From 2292c57e3cbea3f2038a2424263bd8036e3a6488 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 16:17:41 +0800 Subject: [PATCH 001/241] refactor(udf): replace legacy Python service with Arrow runtime --- cmd/mo-service/config.go | 4 +- cmd/mo-service/main.go | 4 +- docs/cn/stream_transport_fast_upload_plan.md | 2 +- .../python-udf-server.toml | 2 +- .../python-udf-server.toml | 2 +- optools/images/pythonserver/Dockerfile | 13 +- pkg/cnservice/options.go | 2 +- pkg/cnservice/server.go | 12 +- pkg/cnservice/server_test.go | 8 +- pkg/cnservice/types.go | 8 +- pkg/config/configuration.go | 2 +- pkg/embed/config.go | 4 +- pkg/frontend/authenticate.go | 54 +- pkg/frontend/clone_database_source.go | 28 +- pkg/sql/compile/Remote_Run_DEV_GUIDE.md | 2 +- pkg/sql/compile/remoterunServer.go | 6 +- pkg/sql/compile/sql_executor.go | 4 +- pkg/sql/plan/function/list_builtIn.go | 2 +- pkg/sql/plan/function/python_udf.go | 290 ++++- pkg/sql/plan/function/udf.go | 710 +---------- pkg/udf/Makefile | 26 - pkg/udf/protocol/protocol.go | 614 ++++++++++ pkg/udf/protocol/protocol_test.go | 175 +++ pkg/udf/pythonruntime/arrow.go | 771 ++++++++++++ pkg/udf/pythonruntime/arrow_test.go | 75 ++ pkg/udf/pythonruntime/config.go | 56 + pkg/udf/pythonruntime/gateway.go | 536 +++++++++ .../pythonruntime/pyserver/requirements.txt | 3 + pkg/udf/pythonruntime/pyserver/test_worker.py | 87 ++ pkg/udf/pythonruntime/pyserver/worker.py | 642 ++++++++++ pkg/udf/pythonruntime/supervisor.go | 113 ++ pkg/udf/pythonservice/cfg.go | 50 - pkg/udf/pythonservice/client.go | 160 --- pkg/udf/pythonservice/demo/README.md | 295 ----- pkg/udf/pythonservice/demo/README_CN.md | 293 ----- pkg/udf/pythonservice/demo/credit/__init__.py | 3 - .../pythonservice/demo/credit/detection.py | 62 - .../demo/credit/model_with_scaler | Bin 1497 -> 0 bytes pkg/udf/pythonservice/demo/ddl.sql | 1006 ---------------- .../demo/dist/detect-1.0.0-py3-none-any.whl | Bin 4152 -> 0 bytes pkg/udf/pythonservice/demo/setup.py | 12 - .../pyserver/requirements/base.txt | 12 - .../pyserver/requirements/pytorch.txt | 5 - pkg/udf/pythonservice/pyserver/server.py | 417 ------- pkg/udf/pythonservice/pyserver/udf_pb2.py | 49 - pkg/udf/pythonservice/pyserver/udf_pb2.pyi | 173 --- .../pythonservice/pyserver/udf_pb2_grpc.py | 72 -- pkg/udf/pythonservice/service.go | 122 -- pkg/udf/pythonservice/types.go | 20 - pkg/udf/runtime.go | 104 ++ pkg/udf/service.go | 50 - pkg/udf/types.go | 40 - pkg/udf/udf.pb.go | 1068 ----------------- pkg/udf/udf.proto | 126 -- pkg/udf/udf_grpc.pb.go | 137 --- pkg/vm/engine/disttae/types.go | 2 +- pkg/vm/process/process2.go | 2 +- pkg/vm/process/process_codec.go | 4 +- pkg/vm/process/types.go | 2 +- 59 files changed, 3534 insertions(+), 5009 deletions(-) delete mode 100644 pkg/udf/Makefile create mode 100644 pkg/udf/protocol/protocol.go create mode 100644 pkg/udf/protocol/protocol_test.go create mode 100644 pkg/udf/pythonruntime/arrow.go create mode 100644 pkg/udf/pythonruntime/arrow_test.go create mode 100644 pkg/udf/pythonruntime/config.go create mode 100644 pkg/udf/pythonruntime/gateway.go create mode 100644 pkg/udf/pythonruntime/pyserver/requirements.txt create mode 100644 pkg/udf/pythonruntime/pyserver/test_worker.py create mode 100644 pkg/udf/pythonruntime/pyserver/worker.py create mode 100644 pkg/udf/pythonruntime/supervisor.go delete mode 100644 pkg/udf/pythonservice/cfg.go delete mode 100644 pkg/udf/pythonservice/client.go delete mode 100644 pkg/udf/pythonservice/demo/README.md delete mode 100644 pkg/udf/pythonservice/demo/README_CN.md delete mode 100644 pkg/udf/pythonservice/demo/credit/__init__.py delete mode 100644 pkg/udf/pythonservice/demo/credit/detection.py delete mode 100644 pkg/udf/pythonservice/demo/credit/model_with_scaler delete mode 100644 pkg/udf/pythonservice/demo/ddl.sql delete mode 100644 pkg/udf/pythonservice/demo/dist/detect-1.0.0-py3-none-any.whl delete mode 100644 pkg/udf/pythonservice/demo/setup.py delete mode 100644 pkg/udf/pythonservice/pyserver/requirements/base.txt delete mode 100644 pkg/udf/pythonservice/pyserver/requirements/pytorch.txt delete mode 100644 pkg/udf/pythonservice/pyserver/server.py delete mode 100644 pkg/udf/pythonservice/pyserver/udf_pb2.py delete mode 100644 pkg/udf/pythonservice/pyserver/udf_pb2.pyi delete mode 100644 pkg/udf/pythonservice/pyserver/udf_pb2_grpc.py delete mode 100644 pkg/udf/pythonservice/service.go delete mode 100644 pkg/udf/pythonservice/types.go create mode 100644 pkg/udf/runtime.go delete mode 100644 pkg/udf/service.go delete mode 100644 pkg/udf/types.go delete mode 100644 pkg/udf/udf.pb.go delete mode 100644 pkg/udf/udf.proto delete mode 100644 pkg/udf/udf_grpc.pb.go diff --git a/cmd/mo-service/config.go b/cmd/mo-service/config.go index b6551bb1ce8cb..bc75566af25c1 100644 --- a/cmd/mo-service/config.go +++ b/cmd/mo-service/config.go @@ -45,7 +45,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/perfcounter" "github.com/matrixorigin/matrixone/pkg/proxy" "github.com/matrixorigin/matrixone/pkg/tnservice" - "github.com/matrixorigin/matrixone/pkg/udf/pythonservice" + "github.com/matrixorigin/matrixone/pkg/udf/pythonruntime" "github.com/matrixorigin/matrixone/pkg/util/debug/goroutine" tomlutil "github.com/matrixorigin/matrixone/pkg/util/toml" "github.com/matrixorigin/matrixone/pkg/version" @@ -119,7 +119,7 @@ type Config struct { // ProxyConfig is the config of proxy. ProxyConfig proxy.Config `toml:"proxy"` // PythonUdfServerConfig is the config of python udf server - PythonUdfServerConfig pythonservice.Config `toml:"python-udf-server"` + PythonUdfServerConfig pythonruntime.Config `toml:"python-udf-server"` // Observability parameters for the metric/trace Observability config.ObservabilityParameters `toml:"observability"` diff --git a/cmd/mo-service/main.go b/cmd/mo-service/main.go index 1ec29e45043dd..f2f647a76054f 100644 --- a/cmd/mo-service/main.go +++ b/cmd/mo-service/main.go @@ -52,7 +52,7 @@ import ( qclient "github.com/matrixorigin/matrixone/pkg/queryservice/client" "github.com/matrixorigin/matrixone/pkg/sql/compile" "github.com/matrixorigin/matrixone/pkg/tnservice" - "github.com/matrixorigin/matrixone/pkg/udf/pythonservice" + "github.com/matrixorigin/matrixone/pkg/udf/pythonruntime" "github.com/matrixorigin/matrixone/pkg/util/debug/goroutine" "github.com/matrixorigin/matrixone/pkg/util/export" "github.com/matrixorigin/matrixone/pkg/util/export/table" @@ -760,7 +760,7 @@ func startPythonUdfService(cfg *Config, stopper *stopper.Stopper) error { defer func() { finishTask(closeErr) }() roleCtx, cancelRole := serviceLifecycle.roleContext(ctx, serviceRolePython) defer cancelRole() - s, err := pythonservice.NewService(cfg.PythonUdfServerConfig) + s, err := pythonruntime.NewSupervisor(cfg.PythonUdfServerConfig) if err != nil { panic(err) } diff --git a/docs/cn/stream_transport_fast_upload_plan.md b/docs/cn/stream_transport_fast_upload_plan.md index 8e3bdb6ff4bb4..cc7227e17f513 100644 --- a/docs/cn/stream_transport_fast_upload_plan.md +++ b/docs/cn/stream_transport_fast_upload_plan.md @@ -20,7 +20,7 @@ Phase 0 — Protobuf / gRPC contract New file `proto/datastream/v1/datastream.proto` (proto3, **not** gogoproto — this proto is shared with Java, so use standard `protoc-gen-go` + -`protoc-gen-go-grpc`, same toolchain as `pkg/udf/udf.proto`, which is the +`protoc-gen-go-grpc`, using the repository's current protobuf toolchain, which is the existing real-gRPC precedent in the repo; the main `proto/*.proto` files are gogo-generated and Java-hostile). diff --git a/etc/launch-with-python-udf-server/python-udf-server.toml b/etc/launch-with-python-udf-server/python-udf-server.toml index d1a7b10adb498..53726382e8222 100644 --- a/etc/launch-with-python-udf-server/python-udf-server.toml +++ b/etc/launch-with-python-udf-server/python-udf-server.toml @@ -3,4 +3,4 @@ service-type = "PYTHON_UDF" [python-udf-server] uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41b2" address = "127.0.0.1:50051" -path = "pkg/udf/pythonservice/pyserver" +path = "pkg/udf/pythonruntime/pyserver" diff --git a/etc/v1/launch-with-python-udf-server/python-udf-server.toml b/etc/v1/launch-with-python-udf-server/python-udf-server.toml index d1a7b10adb498..53726382e8222 100644 --- a/etc/v1/launch-with-python-udf-server/python-udf-server.toml +++ b/etc/v1/launch-with-python-udf-server/python-udf-server.toml @@ -3,4 +3,4 @@ service-type = "PYTHON_UDF" [python-udf-server] uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41b2" address = "127.0.0.1:50051" -path = "pkg/udf/pythonservice/pyserver" +path = "pkg/udf/pythonruntime/pyserver" diff --git a/optools/images/pythonserver/Dockerfile b/optools/images/pythonserver/Dockerfile index f729b5f7718df..8871edc0006c1 100644 --- a/optools/images/pythonserver/Dockerfile +++ b/optools/images/pythonserver/Dockerfile @@ -1,8 +1,8 @@ # run from root path for debug: -# docker build -t mo-python-udf-server -f ./optools/images/pythonserver/Dockerfile ./pkg/udf/pythonservice/pyserver/ -# docker run -d --network host mo-python-udf-server +# docker build -t mo-python-udf-runtime -f ./optools/images/pythonserver/Dockerfile ./pkg/udf/pythonruntime/pyserver/ +# docker run -d --network host mo-python-udf-runtime -FROM python:3.9-bookworm +FROM python:3.12-bookworm RUN useradd -m -s /bin/bash mo @@ -14,13 +14,12 @@ WORKDIR /home/mo # && apt-get update \ # && apt-get install -y vim -COPY . . +COPY requirements.txt worker.py ./ -RUN pip install -r requirements/base.txt -RUN pip install -r requirements/pytorch.txt +RUN pip install --no-cache-dir -r requirements.txt USER mo EXPOSE 50051 -CMD [ "/bin/bash", "-c", "python -u server.py >> server.log 2>&1" ] \ No newline at end of file +CMD [ "python", "-u", "worker.py", "--address=grpc://0.0.0.0:50051" ] diff --git a/pkg/cnservice/options.go b/pkg/cnservice/options.go index 0a4302e95bb04..2e30a98fe0adc 100644 --- a/pkg/cnservice/options.go +++ b/pkg/cnservice/options.go @@ -77,7 +77,7 @@ func WithMessageHandle(f func(ctx context.Context, lockService lockservice.LockService, queryClient qclient.QueryClient, hakeeper logservice.CNHAKeeperClient, - udfService udf.Service, + udfService udf.Runtime, cli client.TxnClient, aicm *defines.AutoIncrCacheManager, mAcquirer func() morpc.Message) error) Option { diff --git a/pkg/cnservice/server.go b/pkg/cnservice/server.go index 62939823bbf16..bb3ff387f1648 100644 --- a/pkg/cnservice/server.go +++ b/pkg/cnservice/server.go @@ -69,7 +69,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/txn/clock" "github.com/matrixorigin/matrixone/pkg/txn/rpc" "github.com/matrixorigin/matrixone/pkg/udf" - "github.com/matrixorigin/matrixone/pkg/udf/pythonservice" + "github.com/matrixorigin/matrixone/pkg/udf/pythonruntime" "github.com/matrixorigin/matrixone/pkg/util/address" "github.com/matrixorigin/matrixone/pkg/util/executor" v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2" @@ -192,7 +192,7 @@ func NewService( lockService lockservice.LockService, queryClient qclient.QueryClient, hakeeper logservice.CNHAKeeperClient, - udfService udf.Service, + udfService udf.Runtime, cli client.TxnClient, aicm *defines.AutoIncrCacheManager, messageAcquirer func() morpc.Message) error { @@ -252,17 +252,17 @@ func NewService( } // init UdfService - var udfServices []udf.Service + var udfServices []udf.Runtime // add python client to handle python udf if srv.cfg.PythonUdfClient.ServerAddress != "" { - var pc *pythonservice.Client - pc, err = pythonservice.NewClient(srv.cfg.PythonUdfClient) + var pc *pythonruntime.Gateway + pc, err = pythonruntime.NewGateway(srv.cfg.PythonUdfClient) if err != nil { return nil, err } udfServices = append(udfServices, pc) } - srv.udfService, err = udf.NewService(udfServices...) + srv.udfService, err = udf.NewRuntime(udfServices...) if err != nil { return nil, err } diff --git a/pkg/cnservice/server_test.go b/pkg/cnservice/server_test.go index 7f75e856edcd7..6b3be01f00b33 100644 --- a/pkg/cnservice/server_test.go +++ b/pkg/cnservice/server_test.go @@ -458,7 +458,7 @@ func Test_InitServer(t *testing.T) { lockService lockservice.LockService, queryClient qclient.QueryClient, hakeeper logservice.CNHAKeeperClient, - udfService udf.Service, + udfService udf.Runtime, cli client.TxnClient, aicm *defines.AutoIncrCacheManager, mAcquirer func() morpc.Message) error { @@ -1060,7 +1060,7 @@ func TestPipelineAdmissionRejectsRequestAlreadyReadDuringClose(t *testing.T) { lockservice.LockService, qclient.QueryClient, logservice.CNHAKeeperClient, - udf.Service, + udf.Runtime, client.TxnClient, *defines.AutoIncrCacheManager, func() morpc.Message, @@ -1160,7 +1160,7 @@ func TestFragmentedPipelineCacheSurvivesHandlerRelease(t *testing.T) { _ lockservice.LockService, _ qclient.QueryClient, _ logservice.CNHAKeeperClient, - _ udf.Service, + _ udf.Runtime, _ client.TxnClient, _ *defines.AutoIncrCacheManager, _ func() morpc.Message, @@ -1286,7 +1286,7 @@ func TestServiceCloseCancelsAdmittedPipeline(t *testing.T) { _ lockservice.LockService, _ qclient.QueryClient, _ logservice.CNHAKeeperClient, - _ udf.Service, + _ udf.Runtime, _ client.TxnClient, _ *defines.AutoIncrCacheManager, _ func() morpc.Message, diff --git a/pkg/cnservice/types.go b/pkg/cnservice/types.go index d0ec4599580f3..6931b4749425e 100644 --- a/pkg/cnservice/types.go +++ b/pkg/cnservice/types.go @@ -53,7 +53,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/txn/clock" "github.com/matrixorigin/matrixone/pkg/txn/rpc" "github.com/matrixorigin/matrixone/pkg/udf" - "github.com/matrixorigin/matrixone/pkg/udf/pythonservice" + "github.com/matrixorigin/matrixone/pkg/udf/pythonruntime" "github.com/matrixorigin/matrixone/pkg/util" "github.com/matrixorigin/matrixone/pkg/util/address" "github.com/matrixorigin/matrixone/pkg/util/executor" @@ -310,7 +310,7 @@ type Config struct { // "working", "draining" and "drained". InitWorkState string `toml:"init-work-state"` - PythonUdfClient pythonservice.ClientConfig `toml:"python-udf-client"` + PythonUdfClient pythonruntime.ClientConfig `toml:"python-udf-client"` // LogtailUpdateWorkerFactor is the times of CPU number of this node // to start update workers. @@ -709,7 +709,7 @@ type service struct { lockService lockservice.LockService, queryClient qclient.QueryClient, hakeeper logservice.CNHAKeeperClient, - udfService udf.Service, + udfService udf.Runtime, cli client.TxnClient, aicm *defines.AutoIncrCacheManager, messageAcquirer func() morpc.Message) error @@ -742,7 +742,7 @@ type service struct { queryClient qclient.QueryClient queryWork queryWorkLifecycle // udfService is used to handle non-sql udf - udfService udf.Service + udfService udf.Runtime bootstrapMu sync.RWMutex bootstrapService bootstrap.Service diff --git a/pkg/config/configuration.go b/pkg/config/configuration.go index 26ff4fbc32878..0d64846cc0d7c 100644 --- a/pkg/config/configuration.go +++ b/pkg/config/configuration.go @@ -1446,7 +1446,7 @@ type ParameterUnit struct { // QueryClient instance QueryClient qclient.QueryClient - UdfService udf.Service + UdfService udf.Runtime // HAKeeper client, which is used to get connection ID // from HAKeeper currently. diff --git a/pkg/embed/config.go b/pkg/embed/config.go index f39cc8510a845..f4ec3e61feaa4 100644 --- a/pkg/embed/config.go +++ b/pkg/embed/config.go @@ -40,7 +40,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/perfcounter" "github.com/matrixorigin/matrixone/pkg/proxy" "github.com/matrixorigin/matrixone/pkg/tnservice" - "github.com/matrixorigin/matrixone/pkg/udf/pythonservice" + "github.com/matrixorigin/matrixone/pkg/udf/pythonruntime" "github.com/matrixorigin/matrixone/pkg/util" "github.com/matrixorigin/matrixone/pkg/util/debug/goroutine" tomlutil "github.com/matrixorigin/matrixone/pkg/util/toml" @@ -95,7 +95,7 @@ type ServiceConfig struct { // ProxyConfig is the config of proxy. ProxyConfig proxy.Config `toml:"proxy"` // PythonUdfServerConfig is the config of python udf server - PythonUdfServerConfig pythonservice.Config `toml:"python-udf-server"` + PythonUdfServerConfig pythonruntime.Config `toml:"python-udf-server"` // Observability parameters for the metric/trace Observability config.ObservabilityParameters `toml:"observability"` diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index fbbac114b818d..24bfcb872220a 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -68,6 +68,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/stage" "github.com/matrixorigin/matrixone/pkg/stage/stageutil" "github.com/matrixorigin/matrixone/pkg/taskservice" + "github.com/matrixorigin/matrixone/pkg/udf" "github.com/matrixorigin/matrixone/pkg/util/fault" "github.com/matrixorigin/matrixone/pkg/util/metric/mometric" v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2" @@ -4927,7 +4928,6 @@ type rmPkg func(path string) error func doDropFunction(ctx context.Context, ses *Session, df *tree.DropFunction, rm rmPkg) (err error) { var sql string var argstr string - var bodyStr string var checkDatabase string var dbName string var dbExists bool @@ -4998,10 +4998,6 @@ func doDropFunction(ctx context.Context, ses *Session, df *tree.DropFunction, rm if err != nil { return err } - bodyStr, err = erArray[0].GetString(ctx, i, 2) - if err != nil { - return err - } argList := make([]*function.Arg, 0) json.Unmarshal([]byte(argstr), &argList) if len(argList) == len(df.Args) { @@ -5023,11 +5019,6 @@ func doDropFunction(ctx context.Context, ses *Session, df *tree.DropFunction, rm if rtnErr != nil { return rtnErr } - u := &function.NonSqlUdfBody{} - if json.Unmarshal([]byte(bodyStr), u) == nil && u.Import { - rm(u.Body) - } - return rtnErr } err = handleArgMatch() @@ -5050,7 +5041,6 @@ func doDropFunction(ctx context.Context, ses *Session, df *tree.DropFunction, rm func doDropFunctionWithDB(ctx context.Context, ses *Session, stmt tree.Statement, rm rmPkg) (err error) { var sql string - var bodyStr string var funcId int64 var erArray []ExecResult var dbName string @@ -5091,11 +5081,6 @@ func doDropFunctionWithDB(ctx context.Context, ses *Session, stmt tree.Statement if err != nil { return err } - bodyStr, err = erArray[0].GetString(ctx, i, 1) - if err != nil { - return err - } - handleArgMatch := func() (rtnErr error) { sql = fmt.Sprintf(deleteUserDefinedFunctionFormat, funcId) @@ -5104,11 +5089,6 @@ func doDropFunctionWithDB(ctx context.Context, ses *Session, stmt tree.Statement return rtnErr } - u := &function.NonSqlUdfBody{} - if json.Unmarshal([]byte(bodyStr), u) == nil && u.Import { - rm(u.Body) - } - return rtnErr } @@ -11790,31 +11770,17 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C body = cf.Body } else { if cf.Import { - // check - if cf.Language == string(tree.PYTHON) { - if !strings.HasSuffix(cf.Body, ".py") && - !strings.HasSuffix(cf.Body, ".whl") { - return moerr.NewInvalidInput(execCtx.reqCtx, "file '"+cf.Body+"', only support '*.py', '*.whl'") - } - if strings.HasSuffix(cf.Body, ".whl") { - dotIdx := strings.LastIndex(cf.Handler, ".") - if dotIdx < 1 { - return moerr.NewInvalidInput(execCtx.reqCtx, "handler '"+cf.Handler+"', when you import a *.whl, the handler should be in the format of '.'") - } - } - } - // upload - storageDir := string(cf.Name.Name.ObjectName) + "_" + strings.Join(typeList, "-") + "_" - cf.Body, err = Upload(ses, execCtx, cf.Body, storageDir) - if err != nil { - return err - } + return moerr.NewNotSupportedNoCtx("Python artifact import requires the immutable artifact catalog") } - nb := function.NonSqlUdfBody{ - Handler: cf.Handler, - Import: cf.Import, - Body: cf.Body, + nb := function.PythonRoutineBody{ + Handler: cf.Handler, + Source: cf.Body, + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, } var byt []byte byt, err = json.Marshal(nb) diff --git a/pkg/frontend/clone_database_source.go b/pkg/frontend/clone_database_source.go index ed5bf631719fc..021cb35623e2a 100644 --- a/pkg/frontend/clone_database_source.go +++ b/pkg/frontend/clone_database_source.go @@ -31,6 +31,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql" "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + "github.com/matrixorigin/matrixone/pkg/udf" ) type cloneDatabaseSource struct { @@ -688,14 +689,37 @@ func validateCloneUserDefinedFunctions(functions []userDefinedFunctionDefinition continue } - var body function.NonSqlUdfBody - if json.Unmarshal([]byte(definition.body), &body) == nil && body.Import { + var raw map[string]json.RawMessage + if json.Unmarshal([]byte(definition.body), &raw) != nil { + return moerr.NewNotSupportedNoCtxf( + "CREATE DATABASE CLONE with malformed %s function %s is not supported", + definition.lang, + definition.name, + ) + } + var importedBody bool + if value, ok := raw["import"]; ok { + _ = json.Unmarshal(value, &importedBody) + } + if importedBody { return moerr.NewNotSupportedNoCtxf( "CREATE DATABASE CLONE with imported %s function %s is not supported: imported UDF packages are not snapshot-versioned", definition.lang, definition.name, ) } + if strings.EqualFold(definition.lang, string(tree.PYTHON)) { + var body function.PythonRoutineBody + if err := json.Unmarshal([]byte(definition.body), &body); err != nil || + body.Handler == "" || (body.Source == "" && body.ArtifactDigest == "") || + body.ABIContract != udf.PythonABIContract || body.AdapterVersion != udf.PythonAdapterVersion { + return moerr.NewNotSupportedNoCtxf( + "CREATE DATABASE CLONE with incomplete %s function %s is not supported", + definition.lang, + definition.name, + ) + } + } } return nil } diff --git a/pkg/sql/compile/Remote_Run_DEV_GUIDE.md b/pkg/sql/compile/Remote_Run_DEV_GUIDE.md index 5e1571e7fbb1a..6b722e922a37a 100644 --- a/pkg/sql/compile/Remote_Run_DEV_GUIDE.md +++ b/pkg/sql/compile/Remote_Run_DEV_GUIDE.md @@ -166,7 +166,7 @@ func CnServerMessageHandler( lockService lockservice.LockService, queryClient qclient.QueryClient, HaKeeper logservice.CNHAKeeperClient, - udfService udf.Service, + udfService udf.Runtime, txnClient client.TxnClient, autoIncreaseCM *defines.AutoIncrCacheManager, messageAcquirer func() morpc.Message) (err error) { diff --git a/pkg/sql/compile/remoterunServer.go b/pkg/sql/compile/remoterunServer.go index ddc95c6ca77c5..e863496396847 100644 --- a/pkg/sql/compile/remoterunServer.go +++ b/pkg/sql/compile/remoterunServer.go @@ -80,7 +80,7 @@ func CnServerMessageHandler( cs morpc.ClientSession, storageEngine engine.Engine, fileService fileservice.FileService, lockService lockservice.LockService, queryClient qclient.QueryClient, - HaKeeper logservice.CNHAKeeperClient, udfService udf.Service, txnClient client.TxnClient, + HaKeeper logservice.CNHAKeeperClient, udfService udf.Runtime, txnClient client.TxnClient, autoIncreaseCM *defines.AutoIncrCacheManager, messageAcquirer func() morpc.Message) (err error) { @@ -831,7 +831,7 @@ type cnInformation struct { lockService lockservice.LockService queryClient qclient.QueryClient hakeeper logservice.CNHAKeeperClient - udfService udf.Service + udfService udf.Runtime aicm *defines.AutoIncrCacheManager } @@ -914,7 +914,7 @@ func newMessageReceiverOnServer( lockService lockservice.LockService, queryClient qclient.QueryClient, hakeeper logservice.CNHAKeeperClient, - udfService udf.Service, + udfService udf.Runtime, txnClient client.TxnClient, aicm *defines.AutoIncrCacheManager, colexecServer *colexec.Server) (messageReceiverOnServer, error) { diff --git a/pkg/sql/compile/sql_executor.go b/pkg/sql/compile/sql_executor.go index 7ad3de1925acd..cc203ab70e03b 100644 --- a/pkg/sql/compile/sql_executor.go +++ b/pkg/sql/compile/sql_executor.go @@ -61,7 +61,7 @@ type sqlExecutor struct { ls lockservice.LockService qc qclient.QueryClient hakeeper logservice.CNHAKeeperClient - us udf.Service + us udf.Runtime buf *buffer.Buffer taskservice taskservice.TaskService } @@ -122,7 +122,7 @@ func NewSQLExecutor( fs fileservice.FileService, qc qclient.QueryClient, hakeeper logservice.CNHAKeeperClient, - us udf.Service, + us udf.Runtime, taskService taskservice.TaskService, ) executor.SQLExecutor { v, ok := runtime.ServiceRuntime(qc.ServiceID()).GetGlobalVariables(runtime.LockService) diff --git a/pkg/sql/plan/function/list_builtIn.go b/pkg/sql/plan/function/list_builtIn.go index 16b2c8a64c9f2..cb9d4f28c2c3a 100644 --- a/pkg/sql/plan/function/list_builtIn.go +++ b/pkg/sql/plan/function/list_builtIn.go @@ -16899,7 +16899,7 @@ var supportedOthersBuiltIns = []FuncNew{ // function `python_user_defined_function` { functionId: PYTHON_UDF, - class: plan.Function_INTERNAL | plan.Function_STRICT, + class: plan.Function_INTERNAL, layout: STANDARD_FUNCTION, checkFn: checkPythonUdf, Overloads: []overload{ diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index c26bdf63d7375..3e45aafe8c590 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -1,25 +1,25 @@ -// Copyright 2023 Matrix Origin +// Copyright 2026 Matrix Origin // // 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. +// http://www.apache.org/licenses/LICENSE-2.0 package function import ( "encoding/json" + "fmt" + "strconv" + "github.com/google/uuid" + "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/defines" "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/matrixorigin/matrixone/pkg/udf/protocol" "github.com/matrixorigin/matrixone/pkg/vm/process" ) @@ -70,57 +70,253 @@ func pythonUdfRetType(parameters []types.Type) types.Type { // param parameters has two parts: // 1. parameters[0]: const vector udf // 2. parameters[1:]: data vectors +// +// The SQL executor normally applies CASE/selection compaction before this +// function is called. The NULL policy is still enforced here because it is +// part of the persisted Python routine contract and must not be inferred from +// the generic builtin STRICT bit. func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int, selectList *FunctionSelectList) error { - // udf with context - u := &UdfWithContext{} - bytes, _ := vector.GenerateFunctionStrParameter(parameters[0]).GetStrValue(0) - err := json.Unmarshal(bytes, u) + if len(parameters) == 0 || parameters[0] == nil { + return fmt.Errorf("python runtime: missing routine descriptor") + } + if length < 0 { + return fmt.Errorf("python runtime: negative input length %d", length) + } + + routine := &UdfWithContext{} + encoded, isNull := vector.GenerateFunctionStrParameter(parameters[0]).GetStrValue(0) + if isNull { + return fmt.Errorf("python runtime: routine descriptor is NULL") + } + if err := json.Unmarshal(encoded, routine); err != nil { + return fmt.Errorf("python runtime: decode routine descriptor: %w", err) + } + if routine.Udf == nil { + return fmt.Errorf("python runtime: routine descriptor has no function") + } + + body := PythonRoutineBody{} + if err := json.Unmarshal([]byte(routine.Body), &body); err != nil { + return fmt.Errorf("python runtime: decode Python routine body: %w", err) + } + if body.Handler == "" || body.Source == "" { + return fmt.Errorf("python runtime: routine handler and source are required") + } + if body.ABIContract != udf.PythonABIContract || body.AdapterVersion != udf.PythonAdapterVersion { + return fmt.Errorf("python runtime: unsupported Python ABI contract %q/%q", body.ABIContract, body.AdapterVersion) + } + argTypes, err := routineArgumentTypes(routine) if err != nil { return err } + if len(parameters)-1 != len(argTypes) { + return fmt.Errorf("python runtime: routine has %d arguments, received %d", len(argTypes), len(parameters)-1) + } + + if length == 0 { + return result.PreExtendAndReset(0) + } + for index, input := range parameters[1:] { + if input == nil || (!input.IsConst() && input.Length() < length) { + return fmt.Errorf("python runtime: input vector %d is shorter than invocation length", index) + } + } + if selectList != nil && len(selectList.SelectList) < length { + return fmt.Errorf("python runtime: selection list is shorter than invocation length") + } + + selected := make([]int64, 0, length) + for row := 0; row < length; row++ { + if selectList != nil && len(selectList.SelectList) > row && !selectList.SelectList[row] { + continue + } + if body.NullPolicy == udf.NullReturnNull && hasNullInput(parameters[1:], row) { + continue + } + selected = append(selected, int64(row)) + } + if len(selected) == 0 { + if err := result.PreExtendAndReset(length); err != nil { + return err + } + result.GetResultVector().SetAllNulls(length) + result.GetResultVector().SetLength(length) + return nil + } + + inputs := parameters[1:] + var compacted []*vector.Vector + if len(selected) != length { + compacted = make([]*vector.Vector, len(inputs)) + for i, input := range inputs { + if input == nil { + return fmt.Errorf("python runtime: input vector %d is nil", i) + } + compacted[i] = vector.NewOffHeapVecWithType(*input.GetType()) + compacted[i].SetIsBin(input.GetIsBin()) + if err := compacted[i].Union(input, selected, proc.Mp()); err != nil { + freeVectors(compacted, proc.Mp()) + return fmt.Errorf("python runtime: compact input %d: %w", i, err) + } + } + inputs = compacted + defer freeVectors(compacted, proc.Mp()) + } - // request - body := &NonSqlUdfBody{} - err = json.Unmarshal([]byte(u.Body), body) + callResult := result + var temporary vector.FunctionResultWrapper + if len(selected) != length { + temporary = vector.NewFunctionResultWrapper(routine.GetRetType(), proc.Mp()) + callResult = temporary + defer temporary.Free() + } + + accountID, err := defines.GetAccountId(proc.Ctx) if err != nil { - return err + return fmt.Errorf("python runtime: resolve account: %w", err) } - request := &udf.Request{ - Udf: &udf.Udf{ - Handler: body.Handler, - IsImport: body.Import, - Body: body.Body, - RetType: t2DataType[u.GetRetType().Oid], - Language: udf.LanguagePython, - Db: u.Db, - ModifiedTime: u.ModifiedTime, - }, - Vectors: make([]*udf.DataVector, len(parameters)-1), - Length: int64(length), - Type: udf.RequestType_DataRequest, - Context: u.Context, - } - for i := 1; i < len(parameters); i++ { - dataVector, _ := vector2DataVector(parameters[i]) - request.Vectors[i-1] = dataVector - } - - // getPkg - reader := &DefaultPkgReader{ - Proc: proc, - } - - // run - response, err := proc.Base.UdfService.Run(proc.Ctx, request, reader) + tuple, err := invocationTuple(routine.Context, proc.QueryId(), accountID) if err != nil { return err } - - // response - err = writeResponse(response, result) - if err != nil { + invocation := &udf.Invocation{ + Language: udf.LanguagePython, + Handler: body.Handler, + Source: body.Source, + Args: argTypes, + ReturnType: routine.GetRetType(), + Inputs: inputs, + Length: len(selected), + Mode: body.Mode, + NullPolicy: body.NullPolicy, + ABIContract: body.ABIContract, + AdapterVersion: body.AdapterVersion, + SDKVersion: body.SDKVersion, + Context: cloneContext(routine.Context), + Tuple: tuple, + } + if err := proc.Base.UdfService.Execute(proc.Ctx, invocation, callResult, proc.Mp()); err != nil { return err } + if len(selected) == length { + return nil + } + if err := result.PreExtendAndReset(length); err != nil { + return err + } + full := result.GetResultVector() + full.ResetWithSameType() + nullResult := vector.NewConstNull(routine.GetRetType(), 1, proc.Mp()) + defer nullResult.Free(proc.Mp()) + selectedRow := int64(0) + for row := 0; row < length; row++ { + if selectedRow < int64(len(selected)) && selected[selectedRow] == int64(row) { + if err := full.UnionOne(callResult.GetResultVector(), selectedRow, proc.Mp()); err != nil { + return err + } + selectedRow++ + continue + } + if err := full.UnionOne(nullResult, 0, proc.Mp()); err != nil { + return err + } + } return nil } + +func hasNullInput(inputs []*vector.Vector, row int) bool { + for _, input := range inputs { + if input == nil || input.IsNull(uint64(row)) { + return true + } + } + return false +} + +func routineArgumentTypes(routine *UdfWithContext) ([]types.Type, error) { + if len(routine.ArgsType) != 0 || len(routine.Args) == 0 { + return append([]types.Type(nil), routine.ArgsType...), nil + } + args := make([]types.Type, len(routine.Args)) + for i, arg := range routine.Args { + if arg == nil { + return nil, fmt.Errorf("python runtime: routine argument %d is nil", i) + } + typ, ok := types.Types[arg.Type] + if !ok { + return nil, fmt.Errorf("python runtime: unknown routine argument type %q", arg.Type) + } + args[i] = typ.ToType() + } + return args, nil +} + +func cloneContext(input map[string]string) map[string]string { + if len(input) == 0 { + return nil + } + output := make(map[string]string, len(input)) + for key, value := range input { + output[key] = value + } + return output +} + +func freeVectors(vectors []*vector.Vector, mp *mpool.MPool) { + for _, vector := range vectors { + if vector != nil { + vector.Free(mp) + } + } +} + +func invocationTuple(context map[string]string, queryID string, accountID uint32) (protocol.FencingTuple, error) { + statementID := context["statement_id"] + if statementID == "" { + statementID = queryID + } + if statementID == "" { + id, err := uuid.NewV7() + if err != nil { + return protocol.FencingTuple{}, fmt.Errorf("python runtime: create statement fence: %w", err) + } + statementID = id.String() + } + groupID := context["group_id"] + if groupID == "" { + groupID = statementID + "/python" + } + invocationID, err := uuid.NewV7() + if err != nil { + return protocol.FencingTuple{}, fmt.Errorf("python runtime: create invocation fence: %w", err) + } + groupEpoch, err := positiveContextUint(context, "group_epoch", 1) + if err != nil { + return protocol.FencingTuple{}, err + } + leaseEpoch, err := positiveContextUint(context, "lease_epoch", 1) + if err != nil { + return protocol.FencingTuple{}, err + } + return protocol.FencingTuple{ + AccountID: uint64(accountID), + StatementID: statementID, + GroupID: groupID, + GroupEpoch: groupEpoch, + InvocationID: invocationID.String(), + LeaseEpoch: leaseEpoch, + }, nil +} + +func positiveContextUint(context map[string]string, key string, fallback uint64) (uint64, error) { + value := context[key] + if value == "" { + return fallback, nil + } + parsed, err := strconv.ParseUint(value, 10, 64) + if err != nil || parsed == 0 { + return 0, fmt.Errorf("python runtime: invalid %s %q", key, value) + } + return parsed, nil +} diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index feb44e2f46227..2f427b4349005 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -1,62 +1,52 @@ -// Copyright 2023 Matrix Origin +// Copyright 2026 Matrix Origin // // 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. +// http://www.apache.org/licenses/LICENSE-2.0 package function import ( - "context" "encoding/json" - "io" - "time" "github.com/google/uuid" - "github.com/matrixorigin/matrixone/pkg/common/moerr" - "github.com/matrixorigin/matrixone/pkg/container/bytejson" "github.com/matrixorigin/matrixone/pkg/container/types" - "github.com/matrixorigin/matrixone/pkg/container/vector" - "github.com/matrixorigin/matrixone/pkg/fileservice" "github.com/matrixorigin/matrixone/pkg/pb/plan" - "github.com/matrixorigin/matrixone/pkg/udf" - "github.com/matrixorigin/matrixone/pkg/vm/process" - "golang.org/x/sync/errgroup" ) type Udf struct { - // sql string, or json string of NonSqlUdfBody - Body string `json:"body"` - Language string `json:"language"` - RetType string `json:"rettype"` - Args []*Arg `json:"args"` - Db string `json:"db"` - ModifiedTime string `json:"modified_time"` - SQLMode *string `json:"-"` - - ArgsType []types.Type `json:"-"` + Body string `json:"body"` + Language string `json:"language"` + RetType string `json:"rettype"` + Args []*Arg `json:"args"` + Db string `json:"db"` + ModifiedTime string `json:"modified_time"` + SQLMode *string `json:"-"` + ArgsType []types.Type `json:"-"` } type UdfWithContext struct { *Udf `json:"udf"` - Context map[string]string `json:"context"` // context map + Context map[string]string `json:"context"` } -type NonSqlUdfBody struct { - Handler string `json:"handler"` - Import bool `json:"import"` - Body string `json:"body"` +// PythonRoutineBody is the single supported Python routine definition. The +// catalog must persist mode and NULL policy with the source so execution does +// not infer either from a generic SQL function class bit. +type PythonRoutineBody struct { + Handler string `json:"handler"` + Source string `json:"source,omitempty"` + Mode string `json:"mode"` + NullPolicy string `json:"null_policy"` + ABIContract string `json:"abi_contract"` + AdapterVersion string `json:"adapter_version"` + ArtifactDigest string `json:"artifact_digest,omitempty"` + EnvironmentDigest string `json:"environment_digest,omitempty"` + SDKVersion string `json:"sdk_version,omitempty"` } -// Arg of Udf type Arg struct { Name string `json:"name"` Type string `json:"type"` @@ -64,61 +54,28 @@ type Arg struct { func (u *Udf) GetPlanExpr() *plan.Expr { uid, _ := uuid.NewV7() - bytes, _ := json.Marshal(&UdfWithContext{ - Udf: u, - Context: map[string]string{ - "queryId": uid.String(), - }, - }) - return &plan.Expr{ - Typ: *type2PlanType(types.T_text.ToType()), - Expr: &plan.Expr_Lit{ - Lit: &plan.Literal{ - Isnull: false, - Value: &plan.Literal_Sval{ - Sval: string(bytes), - }, - }, - }, - } + data, _ := json.Marshal(&UdfWithContext{Udf: u, Context: map[string]string{"statement_id": uid.String()}}) + return &plan.Expr{Typ: *type2PlanType(types.T_text.ToType()), Expr: &plan.Expr_Lit{Lit: &plan.Literal{Isnull: false, Value: &plan.Literal_Sval{Sval: string(data)}}}} } func (u *Udf) GetArgsPlanType() []*plan.Type { - typ := u.GetArgsType() - ptyp := make([]*plan.Type, len(typ)) - for i, t := range typ { - ptyp[i] = type2PlanType(t) + result := make([]*plan.Type, len(u.ArgsType)) + for i, typ := range u.ArgsType { + result[i] = type2PlanType(typ) } - return ptyp + return result } - -func (u *Udf) GetRetPlanType() *plan.Type { - typ := u.GetRetType() - return type2PlanType(typ) -} - -func (u *Udf) GetArgsType() []types.Type { - return u.ArgsType -} - -func (u *Udf) GetRetType() types.Type { - return types.Types[u.RetType].ToType() -} - +func (u *Udf) GetRetPlanType() *plan.Type { return type2PlanType(u.GetRetType()) } +func (u *Udf) GetArgsType() []types.Type { return u.ArgsType } +func (u *Udf) GetRetType() types.Type { return types.Types[u.RetType].ToType() } func type2PlanType(typ types.Type) *plan.Type { - return &plan.Type{ - Id: int32(typ.Oid), - Width: typ.Width, - Scale: typ.Scale, - Charset: uint32(typ.Charset), - } + return &plan.Type{Id: int32(typ.Oid), Width: typ.Width, Scale: typ.Scale, Charset: uint32(typ.Charset)} } func UdfArgTypeMatch(from []types.Type, to []types.T) (bool, int) { - sta, cost := tryToMatch(from, to) - return sta != matchFailed, cost + status, cost := tryToMatch(from, to) + return status != matchFailed, cost } - func UdfArgTypeCast(from []types.Type, to []types.T) []types.Type { castType := make([]types.Type, len(from)) for i := range castType { @@ -131,598 +88,3 @@ func UdfArgTypeCast(from []types.Type, to []types.T) []types.Type { } return castType } - -func getDataFromDataVector(v *udf.DataVector, i int) *udf.Data { - if v == nil { - return nil - } - if v.Const { - return v.Data[0] - } - return v.Data[i] -} - -func vector2DataVector(v *vector.Vector) (*udf.DataVector, error) { - if v == nil { - return nil, nil - } - dv := &udf.DataVector{ - Const: v.IsConst(), - Length: int64(v.Length()), - Type: t2DataType[v.GetType().Oid], - Scale: v.GetType().Scale, - } - size := v.Length() - if dv.Const { - size = 1 - } - dv.Data = make([]*udf.Data, size) - switch v.GetType().Oid { - case types.T_bool: - p := vector.GenerateFunctionFixedTypeParameter[bool](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_BoolVal{BoolVal: val}} - } - } - case types.T_int8: - p := vector.GenerateFunctionFixedTypeParameter[int8](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_IntVal{IntVal: int32(val)}} - } - } - case types.T_int16: - p := vector.GenerateFunctionFixedTypeParameter[int16](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_IntVal{IntVal: int32(val)}} - } - } - case types.T_int32: - p := vector.GenerateFunctionFixedTypeParameter[int32](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_IntVal{IntVal: val}} - } - } - case types.T_int64: - p := vector.GenerateFunctionFixedTypeParameter[int64](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_Int64Val{Int64Val: val}} - } - } - case types.T_uint8: - p := vector.GenerateFunctionFixedTypeParameter[uint8](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_UintVal{UintVal: uint32(val)}} - } - } - case types.T_uint16: - p := vector.GenerateFunctionFixedTypeParameter[uint16](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_UintVal{UintVal: uint32(val)}} - } - } - case types.T_uint32: - p := vector.GenerateFunctionFixedTypeParameter[uint32](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_UintVal{UintVal: val}} - } - } - case types.T_uint64: - p := vector.GenerateFunctionFixedTypeParameter[uint64](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_Uint64Val{Uint64Val: val}} - } - } - case types.T_float32: - p := vector.GenerateFunctionFixedTypeParameter[float32](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_FloatVal{FloatVal: val}} - } - } - case types.T_float64: - p := vector.GenerateFunctionFixedTypeParameter[float64](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_DoubleVal{DoubleVal: val}} - } - } - case types.T_char, types.T_varchar, types.T_text, types.T_datalink: - p := vector.GenerateFunctionStrParameter(v) - for i := 0; i < size; i++ { - val, isNull := p.GetStrValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_StringVal{StringVal: string(val)}} - } - } - case types.T_json: - p := vector.GenerateFunctionStrParameter(v) - for i := 0; i < size; i++ { - val, isNull := p.GetStrValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_StringVal{StringVal: types.DecodeJson(val).String()}} - } - } - case types.T_uuid: - p := vector.GenerateFunctionFixedTypeParameter[types.Uuid](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_StringVal{StringVal: val.String()}} - } - } - case types.T_time: - p := vector.GenerateFunctionFixedTypeParameter[types.Time](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_StringVal{StringVal: val.String2(v.GetType().Scale)}} - } - } - case types.T_date: - p := vector.GenerateFunctionFixedTypeParameter[types.Date](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_StringVal{StringVal: val.String()}} - } - } - case types.T_datetime: - p := vector.GenerateFunctionFixedTypeParameter[types.Datetime](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_StringVal{StringVal: val.String2(v.GetType().Scale)}} - } - } - case types.T_timestamp: - p := vector.GenerateFunctionFixedTypeParameter[types.Timestamp](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_StringVal{StringVal: val.String2(time.Local, v.GetType().Scale)}} - } - } - case types.T_decimal64: - p := vector.GenerateFunctionFixedTypeParameter[types.Decimal64](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_StringVal{StringVal: val.Format(v.GetType().Scale)}} - } - } - case types.T_decimal128: - p := vector.GenerateFunctionFixedTypeParameter[types.Decimal128](v) - for i := 0; i < size; i++ { - val, isNull := p.GetValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_StringVal{StringVal: val.Format(v.GetType().Scale)}} - } - } - case types.T_binary, types.T_varbinary, types.T_blob: - p := vector.GenerateFunctionStrParameter(v) - for i := 0; i < size; i++ { - val, isNull := p.GetStrValue(uint64(i)) - if !isNull { - dv.Data[i] = &udf.Data{Val: &udf.Data_BytesVal{BytesVal: val}} - } - } - default: - return nil, moerr.NewInvalidArgNoCtx("python udf arg type", v.GetType().String()) - } - return dv, nil -} - -func writeResponse(response *udf.Response, result vector.FunctionResultWrapper) error { - var err error - retType := dataType2T[response.Vector.Type] - length := int(response.Vector.Length) - scale := response.Vector.Scale - - result.GetResultVector().SetTypeScale(scale) - - switch retType { - case types.T_bool: - res := vector.MustFunctionResult[bool](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.Append(false, true) - } else { - err = res.Append(data.GetBoolVal(), false) - } - if err != nil { - return err - } - } - case types.T_int8: - res := vector.MustFunctionResult[int8](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.Append(0, true) - } else { - err = res.Append(int8(data.GetIntVal()), false) - } - if err != nil { - return err - } - } - case types.T_int16: - res := vector.MustFunctionResult[int16](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.Append(0, true) - } else { - err = res.Append(int16(data.GetIntVal()), false) - } - if err != nil { - return err - } - } - case types.T_int32: - res := vector.MustFunctionResult[int32](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.Append(0, true) - } else { - err = res.Append(data.GetIntVal(), false) - } - if err != nil { - return err - } - } - case types.T_int64: - res := vector.MustFunctionResult[int64](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.Append(0, true) - } else { - err = res.Append(data.GetInt64Val(), false) - } - if err != nil { - return err - } - } - case types.T_uint8: - res := vector.MustFunctionResult[uint8](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.Append(0, true) - } else { - err = res.Append(uint8(data.GetUintVal()), false) - } - if err != nil { - return err - } - } - case types.T_uint16: - res := vector.MustFunctionResult[uint16](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.Append(0, true) - } else { - err = res.Append(uint16(data.GetUintVal()), false) - } - if err != nil { - return err - } - } - case types.T_uint32: - res := vector.MustFunctionResult[uint32](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.Append(0, true) - } else { - err = res.Append(data.GetUintVal(), false) - } - if err != nil { - return err - } - } - case types.T_uint64: - res := vector.MustFunctionResult[uint64](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.Append(0, true) - } else { - err = res.Append(data.GetUint64Val(), false) - } - if err != nil { - return err - } - } - case types.T_float32: - res := vector.MustFunctionResult[float32](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.Append(0, true) - } else { - err = res.Append(data.GetFloatVal(), false) - } - if err != nil { - return err - } - } - case types.T_float64: - res := vector.MustFunctionResult[float64](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.Append(0, true) - } else { - err = res.Append(data.GetDoubleVal(), false) - } - if err != nil { - return err - } - } - case types.T_char, types.T_varchar, types.T_text, types.T_datalink: - res := vector.MustFunctionResult[types.Varlena](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.AppendBytes(nil, true) - } else { - err = res.AppendBytes([]byte(data.GetStringVal()), false) - } - if err != nil { - return err - } - } - case types.T_json: - res := vector.MustFunctionResult[types.Varlena](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.AppendBytes(nil, true) - } else { - bytes, err2 := bytejson.ParseJsonByteFromString(data.GetStringVal()) - if err2 != nil { - return err2 - } - err = res.AppendBytes(bytes, false) - } - if err != nil { - return err - } - } - case types.T_uuid: - res := vector.MustFunctionResult[types.Uuid](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.AppendBytes(nil, true) - } else { - uuid, err2 := types.ParseUuid(data.GetStringVal()) - if err2 != nil { - return err2 - } - err = res.Append(uuid, false) - } - if err != nil { - return err - } - } - case types.T_time: - res := vector.MustFunctionResult[types.Time](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.AppendBytes(nil, true) - } else { - t, err2 := types.ParseTime(data.GetStringVal(), scale) - if err2 != nil { - return err2 - } - err = res.Append(t, false) - } - if err != nil { - return err - } - } - case types.T_date: - res := vector.MustFunctionResult[types.Date](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.AppendBytes(nil, true) - } else { - d, err2 := types.ParseDateCast(data.GetStringVal()) - if err2 != nil { - return err2 - } - err = res.Append(d, false) - } - if err != nil { - return err - } - } - case types.T_datetime: - res := vector.MustFunctionResult[types.Datetime](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.AppendBytes(nil, true) - } else { - dt, err2 := types.ParseDatetime(data.GetStringVal(), scale) - if err2 != nil { - return err2 - } - err = res.Append(dt, false) - } - if err != nil { - return err - } - } - case types.T_timestamp: - res := vector.MustFunctionResult[types.Timestamp](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.AppendBytes(nil, true) - } else { - ts, err2 := types.ParseTimestamp(time.Local, data.GetStringVal(), scale) - if err2 != nil { - return err2 - } - err = res.Append(ts, false) - } - if err != nil { - return err - } - } - case types.T_decimal64, types.T_decimal128: - res := vector.MustFunctionResult[types.Decimal128](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.AppendBytes(nil, true) - } else { - decimal, err2 := types.ParseDecimal128(data.GetStringVal(), 38, scale) - if err2 != nil { - return err2 - } - err = res.Append(decimal, false) - } - if err != nil { - return err - } - } - case types.T_binary, types.T_varbinary, types.T_blob: - res := vector.MustFunctionResult[types.Varlena](result) - for i := 0; i < length; i++ { - data := getDataFromDataVector(response.Vector, i) - if data == nil || data.Val == nil { - err = res.AppendBytes(nil, true) - } else { - err = res.AppendBytes(data.GetBytesVal(), false) - } - if err != nil { - return err - } - } - default: - return moerr.NewNotSupportedNoCtxf("python udf return type: %v", retType.String()) - } - - return nil -} - -var ( - t2DataType = map[types.T]udf.DataType{ - types.T_bool: udf.DataType_BOOL, - types.T_int8: udf.DataType_INT8, - types.T_int16: udf.DataType_INT16, - types.T_int32: udf.DataType_INT32, - types.T_int64: udf.DataType_INT64, - types.T_uint8: udf.DataType_UINT8, - types.T_uint16: udf.DataType_UINT16, - types.T_uint32: udf.DataType_UINT32, - types.T_uint64: udf.DataType_UINT64, - types.T_float32: udf.DataType_FLOAT32, - types.T_float64: udf.DataType_FLOAT64, - types.T_char: udf.DataType_CHAR, - types.T_varchar: udf.DataType_VARCHAR, - types.T_text: udf.DataType_TEXT, - types.T_json: udf.DataType_JSON, - types.T_uuid: udf.DataType_UUID, - types.T_time: udf.DataType_TIME, - types.T_date: udf.DataType_DATE, - types.T_datetime: udf.DataType_DATETIME, - types.T_timestamp: udf.DataType_TIMESTAMP, - types.T_decimal64: udf.DataType_DECIMAL64, - types.T_decimal128: udf.DataType_DECIMAL128, - types.T_binary: udf.DataType_BINARY, - types.T_varbinary: udf.DataType_VARBINARY, - types.T_blob: udf.DataType_BLOB, - } - - dataType2T = map[udf.DataType]types.T{ - udf.DataType_BOOL: types.T_bool, - udf.DataType_INT8: types.T_int8, - udf.DataType_INT16: types.T_int16, - udf.DataType_INT32: types.T_int32, - udf.DataType_INT64: types.T_int64, - udf.DataType_UINT8: types.T_uint8, - udf.DataType_UINT16: types.T_uint16, - udf.DataType_UINT32: types.T_uint32, - udf.DataType_UINT64: types.T_uint64, - udf.DataType_FLOAT32: types.T_float32, - udf.DataType_FLOAT64: types.T_float64, - udf.DataType_CHAR: types.T_char, - udf.DataType_VARCHAR: types.T_varchar, - udf.DataType_TEXT: types.T_text, - udf.DataType_JSON: types.T_json, - udf.DataType_UUID: types.T_uuid, - udf.DataType_TIME: types.T_time, - udf.DataType_DATE: types.T_date, - udf.DataType_DATETIME: types.T_datetime, - udf.DataType_TIMESTAMP: types.T_timestamp, - udf.DataType_DECIMAL64: types.T_decimal64, - udf.DataType_DECIMAL128: types.T_decimal128, - udf.DataType_BINARY: types.T_binary, - udf.DataType_VARBINARY: types.T_varbinary, - udf.DataType_BLOB: types.T_blob, - } -) - -type DefaultPkgReader struct { - Proc *process.Process -} - -func (d *DefaultPkgReader) Get(ctx context.Context, path string) (io.ReadCloser, error) { - reader, writer := io.Pipe() - var errGroup *errgroup.Group - defer func() { - if errGroup == nil { - writer.Close() - } - }() - - ioVector := &fileservice.IOVector{ - FilePath: path, - Entries: []fileservice.IOEntry{ - { - Offset: 0, - Size: -1, - WriterForRead: writer, - }, - }, - } - - errGroup = new(errgroup.Group) - errGroup.Go(func() error { - defer writer.Close() - return d.Proc.GetFileService().Read(ctx, ioVector) - }) - - return reader, nil -} diff --git a/pkg/udf/Makefile b/pkg/udf/Makefile deleted file mode 100644 index 21ee463ed71e4..0000000000000 --- a/pkg/udf/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2023 Matrix Origin -# -# 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. - -.PHONY: clean -clean: - rm -f udf.pb.go - rm -f udf_grpc.pb.go - rm -f pythonservice/pyserver/python_udf_pb2.py - rm -f pythonservice/pyserver/python_udf_pb2.pyi - rm -f pythonservice/pyserver/python_udf_pb2_grpc.py - -.PHONY: generate -generate: - protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./udf.proto - @cd pythonservice/pyserver && python -m grpc_tools.protoc -I ../../ --python_out=. --pyi_out=. --grpc_python_out=. ../../udf.proto diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go new file mode 100644 index 0000000000000..226c7bf300802 --- /dev/null +++ b/pkg/udf/protocol/protocol.go @@ -0,0 +1,614 @@ +// Copyright 2026 Matrix Origin +// +// 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 protocol contains the transport-independent contracts shared by the +// Python UDF gateway and its callers. It deliberately does not know about +// gRPC, Arrow, or a particular scheduler implementation. +package protocol + +import ( + "bytes" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "sync" + "time" +) + +const ( + // Version identifies the control envelope understood by this runtime. It is + // a wire compatibility field, not a language or package name. + Version = 1 + + // MaxControlBytes is a trust-boundary ceiling. A runtime may negotiate a + // smaller limit, but a caller must never silently raise it. + MaxControlBytes = 1 << 20 +) + +var ( + ErrProtocol = errors.New("python udf protocol violation") + ErrSequence = errors.New("python udf sequence violation") + ErrGroupClosed = errors.New("python udf execution group is closed") + ErrDuplicate = errors.New("python udf identity is already present") + ErrLedgerFull = errors.New("python udf terminal ledger is full") + ErrUnknownIdentity = errors.New("python udf identity is unknown") +) + +// FencingTuple is carried by every invocation control and data-plane +// application message. IDs are never reused while their fence/tombstone is +// retained. The tuple is a deduplication fence, not an authentication token. +type FencingTuple struct { + AccountID uint64 `json:"account_id"` + StatementID string `json:"statement_id"` + GroupID string `json:"group_id"` + GroupEpoch uint64 `json:"group_epoch"` + InvocationID string `json:"invocation_id"` + LeaseEpoch uint64 `json:"lease_epoch"` +} + +func (t FencingTuple) Validate() error { + if t.AccountID == 0 || t.StatementID == "" || t.GroupID == "" || + t.GroupEpoch == 0 || t.InvocationID == "" || t.LeaseEpoch == 0 { + return fmt.Errorf("%w: incomplete fencing tuple", ErrProtocol) + } + return nil +} + +// Control is the small, canonical application envelope carried in Flight +// app_metadata. Payload is a versioned descriptor or error body owned by the +// message kind; it is bounded before JSON decoding. +type Control struct { + Version int `json:"version"` + Kind string `json:"kind"` + Tuple FencingTuple `json:"tuple"` + Sequence uint64 `json:"sequence,omitempty"` + LastSequence uint64 `json:"last_sequence,omitempty"` + AckSequence uint64 `json:"ack_sequence,omitempty"` + FinishID string `json:"finish_id,omitempty"` + Status string `json:"status,omitempty"` + Reason string `json:"reason,omitempty"` + Payload json.RawMessage `json:"payload,omitempty"` +} + +// MarshalControl produces the byte representation used in the Flight +// application metadata field. Struct-field order is intentional: the same +// bytes are used when a descriptor fingerprint is calculated. +func MarshalControl(control Control) ([]byte, error) { + if control.Version == 0 { + control.Version = Version + } + if control.Version != Version || control.Kind == "" { + return nil, fmt.Errorf("%w: unsupported control version or empty kind", ErrProtocol) + } + if err := control.Tuple.Validate(); err != nil { + return nil, err + } + encoded, err := json.Marshal(control) + if err != nil { + return nil, fmt.Errorf("%w: encode control: %v", ErrProtocol, err) + } + if len(encoded) > MaxControlBytes { + return nil, fmt.Errorf("%w: control is %d bytes, limit is %d", ErrProtocol, len(encoded), MaxControlBytes) + } + return encoded, nil +} + +func UnmarshalControl(data []byte) (Control, error) { + if len(data) == 0 || len(data) > MaxControlBytes { + return Control{}, fmt.Errorf("%w: control size %d is outside the allowed range", ErrProtocol, len(data)) + } + var control Control + decoder := json.NewDecoder(bytes.NewReader(data)) + if err := decoder.Decode(&control); err != nil { + return Control{}, fmt.Errorf("%w: decode control: %v", ErrProtocol, err) + } + if control.Version != Version || control.Kind == "" { + return Control{}, fmt.Errorf("%w: unsupported control version %d", ErrProtocol, control.Version) + } + if err := control.Tuple.Validate(); err != nil { + return Control{}, err + } + return control, nil +} + +// Sequence validates the independent input and result directions of one +// invocation. EndInput is a normal half-close; it does not make results +// terminal until all results have been acknowledged. +type Sequence struct { + mu sync.Mutex + nextInput uint64 + lastInput uint64 + inputEnded bool + nextResult uint64 + lastResult uint64 + ackedResult uint64 +} + +func (s *Sequence) AcceptInput(sequence uint64) error { + s.mu.Lock() + defer s.mu.Unlock() + if s.inputEnded { + return fmt.Errorf("%w: input arrived after EndInput", ErrSequence) + } + if sequence != s.nextInput+1 { + return fmt.Errorf("%w: input sequence %d, expected %d", ErrSequence, sequence, s.nextInput+1) + } + s.nextInput = sequence + s.lastInput = sequence + return nil +} + +func (s *Sequence) EndInput(lastSequence uint64) error { + s.mu.Lock() + defer s.mu.Unlock() + if s.inputEnded { + if s.lastInput == lastSequence { + return nil + } + return fmt.Errorf("%w: EndInput changed from %d to %d", ErrSequence, s.lastInput, lastSequence) + } + if lastSequence != s.lastInput { + return fmt.Errorf("%w: EndInput last sequence %d, observed %d", ErrSequence, lastSequence, s.lastInput) + } + s.inputEnded = true + return nil +} + +func (s *Sequence) AcceptResult(sequence uint64) error { + s.mu.Lock() + defer s.mu.Unlock() + if sequence != s.nextResult+1 || sequence > s.lastInput { + return fmt.Errorf("%w: result sequence %d, expected %d and at most input %d", ErrSequence, sequence, s.nextResult+1, s.lastInput) + } + s.nextResult = sequence + s.lastResult = sequence + return nil +} + +func (s *Sequence) AcknowledgeResults(sequence uint64) error { + s.mu.Lock() + defer s.mu.Unlock() + if sequence < s.ackedResult || sequence > s.lastResult { + return fmt.Errorf("%w: result ACK %d outside [%d,%d]", ErrSequence, sequence, s.ackedResult, s.lastResult) + } + s.ackedResult = sequence + return nil +} + +func (s *Sequence) ReadyToFinish() bool { + s.mu.Lock() + defer s.mu.Unlock() + return s.inputEnded && s.lastResult == s.lastInput && s.ackedResult == s.lastResult +} + +func (s *Sequence) State() (lastInput, lastResult, acked uint64, inputEnded bool) { + s.mu.Lock() + defer s.mu.Unlock() + return s.lastInput, s.lastResult, s.ackedResult, s.inputEnded +} + +// OutputSnapshot is the only representation that may cross the trusted +// validation/publication boundary. Freeze copies the worker-owned bytes +// before validation. The snapshot's backing is private, so later worker +// writes cannot change the bytes validated or published by the caller. +type OutputSnapshot struct { + backing []byte + digest [sha256.Size]byte +} + +func FreezeOutput(source []byte, maxBytes int64) (*OutputSnapshot, error) { + if maxBytes <= 0 || int64(len(source)) > maxBytes { + return nil, fmt.Errorf("%w: output snapshot size %d exceeds limit %d", ErrProtocol, len(source), maxBytes) + } + backing := make([]byte, len(source)) + copy(backing, source) + return &OutputSnapshot{backing: backing, digest: sha256.Sum256(backing)}, nil +} + +func (s *OutputSnapshot) Len() int { + if s == nil { + return 0 + } + return len(s.backing) +} + +func (s *OutputSnapshot) Digest() string { + if s == nil { + return "" + } + return hex.EncodeToString(s.digest[:]) +} + +func (s *OutputSnapshot) Validate(expectedLength int, expectedDigest string) error { + if s == nil || s.backing == nil { + return fmt.Errorf("%w: missing output snapshot", ErrProtocol) + } + if expectedLength >= 0 && len(s.backing) != expectedLength { + return fmt.Errorf("%w: output snapshot length %d, expected %d", ErrProtocol, len(s.backing), expectedLength) + } + if expectedDigest != "" && !equalFoldHex(expectedDigest, s.Digest()) { + return fmt.Errorf("%w: output snapshot digest changed", ErrProtocol) + } + return nil +} + +// Bytes returns a private copy for an API that cannot consume an immutable +// view. Validation and publication in a trusted consumer should operate on +// the same snapshot object, rather than refetching the worker buffer. +func (s *OutputSnapshot) Bytes() []byte { + if s == nil { + return nil + } + return append([]byte(nil), s.backing...) +} + +// TrustedBytes exposes the private frozen backing to a validator/consumer +// that is part of the same trusted boundary. The caller must treat the +// returned slice as read-only. It exists so validation and decoding can use +// exactly the bytes that were frozen, rather than refetching worker memory or +// making a second mutable copy between the two steps. +func (s *OutputSnapshot) TrustedBytes() []byte { + if s == nil { + return nil + } + return s.backing +} + +func equalFoldHex(left, right string) bool { + if len(left) != len(right) { + return false + } + for i := range left { + l, r := left[i], right[i] + if l >= 'A' && l <= 'F' { + l += 'a' - 'A' + } + if r >= 'A' && r <= 'F' { + r += 'a' - 'A' + } + if l != r { + return false + } + } + return true +} + +type GroupState string + +const ( + GroupReserved GroupState = "RESERVED" + GroupOpen GroupState = "OPEN" + GroupDraining GroupState = "DRAINING" + GroupReleased GroupState = "RELEASED" +) + +// CloseReason is deliberately a string so the scheduler can add a reason in +// a newer minor protocol without changing the lifetime rules. +type CloseReason string + +const ( + ReasonInputEOF CloseReason = "INPUT_EOF" + ReasonEmptyInput CloseReason = "EMPTY_INPUT" + ReasonAllNull CloseReason = "ALL_NULL" + ReasonNoSelectedRows CloseReason = "NO_SELECTED_ROWS" + ReasonPartialOpenError CloseReason = "PARTIAL_OPEN_FAILURE" + ReasonCancel CloseReason = "CANCEL" + ReasonIdle CloseReason = "IDLE" +) + +// ExecutionGroup is a one-shot admission cohort. Member terminal cleanup +// only removes that member. The release callback belongs to the group owner +// and runs after close, all members terminal, and all in-flight opens finish. +type ExecutionGroup struct { + mu sync.Mutex + id string + epoch uint64 + maxMembers int + registered int + inFlight int + members map[string]bool + closing bool + releaseBusy bool + released bool + release func() error + reason CloseReason +} + +func NewExecutionGroup(id string, epoch uint64, maxMembers int, release func() error) (*ExecutionGroup, error) { + if id == "" || epoch == 0 || maxMembers <= 0 || release == nil { + return nil, fmt.Errorf("%w: invalid execution group", ErrProtocol) + } + return &ExecutionGroup{ + id: id, epoch: epoch, maxMembers: maxMembers, + members: make(map[string]bool), release: release, + }, nil +} + +// BeginOpen reserves one cumulative member-registration slot. The returned +// token must be committed or aborted exactly once by the Open owner. +func (g *ExecutionGroup) BeginOpen(memberID string) (*OpenToken, error) { + if memberID == "" { + return nil, fmt.Errorf("%w: empty member id", ErrProtocol) + } + g.mu.Lock() + defer g.mu.Unlock() + if g.closing || g.released { + return nil, ErrGroupClosed + } + if g.members[memberID] { + return nil, ErrDuplicate + } + if g.registered+g.inFlight >= g.maxMembers { + return nil, fmt.Errorf("%w: member limit %d reached", ErrLedgerFull, g.maxMembers) + } + g.inFlight++ + return &OpenToken{group: g, memberID: memberID}, nil +} + +type OpenToken struct { + group *ExecutionGroup + memberID string + once sync.Once +} + +func (t *OpenToken) Commit() error { + if t == nil || t.group == nil { + return ErrUnknownIdentity + } + var err error + var release bool + t.once.Do(func() { + g := t.group + g.mu.Lock() + g.inFlight-- + if g.closing || g.released { + err = ErrGroupClosed + release = g.canReleaseLocked() + g.mu.Unlock() + return + } + g.members[t.memberID] = true + g.registered++ + g.mu.Unlock() + }) + if release { + if releaseErr := t.group.releaseIfReady(); err == nil { + err = releaseErr + } + } + return err +} + +func (t *OpenToken) Abort() error { + if t == nil || t.group == nil { + return ErrUnknownIdentity + } + var release bool + t.once.Do(func() { + g := t.group + g.mu.Lock() + g.inFlight-- + release = g.canReleaseLocked() + g.mu.Unlock() + }) + if release { + return t.group.releaseIfReady() + } + return nil +} + +func (g *ExecutionGroup) Close(reason CloseReason) error { + if reason == "" { + return fmt.Errorf("%w: close reason is empty", ErrProtocol) + } + g.mu.Lock() + if g.released { + g.mu.Unlock() + return nil + } + if !g.closing { + g.closing = true + g.reason = reason + } + release := g.canReleaseLocked() + g.mu.Unlock() + if release { + return g.releaseIfReady() + } + return nil +} + +func (g *ExecutionGroup) MemberTerminal(memberID string) error { + g.mu.Lock() + if !g.members[memberID] { + g.mu.Unlock() + return ErrUnknownIdentity + } + delete(g.members, memberID) + release := g.canReleaseLocked() + g.mu.Unlock() + if release { + return g.releaseIfReady() + } + return nil +} + +func (g *ExecutionGroup) canReleaseLocked() bool { + return g.closing && len(g.members) == 0 && g.inFlight == 0 && !g.released && !g.releaseBusy +} + +func (g *ExecutionGroup) releaseIfReady() error { + g.mu.Lock() + if !g.canReleaseLocked() { + g.mu.Unlock() + return nil + } + g.releaseBusy = true + g.mu.Unlock() + err := g.release() + g.mu.Lock() + g.releaseBusy = false + if err == nil { + g.released = true + } + g.mu.Unlock() + return err +} + +func (g *ExecutionGroup) State() GroupState { + g.mu.Lock() + defer g.mu.Unlock() + if g.released { + return GroupReleased + } + if g.closing { + return GroupDraining + } + if g.registered > 0 { + return GroupOpen + } + return GroupReserved +} + +func (g *ExecutionGroup) Reason() CloseReason { + g.mu.Lock() + defer g.mu.Unlock() + return g.reason +} + +func (g *ExecutionGroup) Counts() (registered, active, inFlight int) { + g.mu.Lock() + defer g.mu.Unlock() + return g.registered, len(g.members), g.inFlight +} + +type ledgerEntry struct { + key string + bytes int64 + expiresAt time.Time + tombstone bool +} + +// TerminalLedger is an admission-reserved bounded deduplication ledger. A +// terminal entry is retained until expiry; it is never deleted merely to make +// room for a new invocation. +type TerminalLedger struct { + mu sync.Mutex + maxEntries int + maxBytes int64 + entries map[string]ledgerEntry + reservedN int + reservedB int64 +} + +type LedgerCredit struct { + ledger *TerminalLedger + groupID string + remainingN int + remainingB int64 + closed bool +} + +func NewTerminalLedger(maxEntries int, maxBytes int64) (*TerminalLedger, error) { + if maxEntries <= 0 || maxBytes <= 0 { + return nil, fmt.Errorf("%w: invalid terminal ledger limit", ErrProtocol) + } + return &TerminalLedger{maxEntries: maxEntries, maxBytes: maxBytes, entries: make(map[string]ledgerEntry)}, nil +} + +func (l *TerminalLedger) Reserve(groupID string, entries int, bytes int64) (*LedgerCredit, error) { + if groupID == "" || entries <= 0 || bytes <= 0 { + return nil, fmt.Errorf("%w: invalid terminal ledger reservation", ErrProtocol) + } + l.mu.Lock() + defer l.mu.Unlock() + if l.reservedN > l.maxEntries-entries || l.reservedB > l.maxBytes-bytes { + return nil, ErrLedgerFull + } + l.reservedN += entries + l.reservedB += bytes + return &LedgerCredit{ledger: l, groupID: groupID, remainingN: entries, remainingB: bytes}, nil +} + +func (c *LedgerCredit) Add(key string, bytes int64, expiry time.Time) error { + if c == nil || c.ledger == nil || key == "" || bytes <= 0 || expiry.IsZero() { + return fmt.Errorf("%w: invalid terminal ledger entry", ErrProtocol) + } + c.ledger.mu.Lock() + defer c.ledger.mu.Unlock() + if c.closed || c.remainingN == 0 || c.remainingB < bytes { + return ErrLedgerFull + } + if _, exists := c.ledger.entries[key]; exists { + return ErrDuplicate + } + c.ledger.entries[key] = ledgerEntry{key: key, bytes: bytes, expiresAt: expiry} + c.remainingN-- + c.remainingB -= bytes + return nil +} + +func (c *LedgerCredit) ReleaseUnused() { + if c == nil || c.ledger == nil { + return + } + c.ledger.mu.Lock() + defer c.ledger.mu.Unlock() + if c.closed { + return + } + c.ledger.reservedN -= c.remainingN + c.ledger.reservedB -= c.remainingB + c.remainingN = 0 + c.remainingB = 0 + c.closed = true +} + +func (l *TerminalLedger) Complete(key string) error { + l.mu.Lock() + defer l.mu.Unlock() + entry, ok := l.entries[key] + if !ok { + return ErrUnknownIdentity + } + if entry.tombstone { + return nil + } + entry.tombstone = true + l.entries[key] = entry + return nil +} + +func (l *TerminalLedger) Expire(now time.Time) int { + l.mu.Lock() + defer l.mu.Unlock() + removed := 0 + for key, entry := range l.entries { + if !now.Before(entry.expiresAt) { + delete(l.entries, key) + l.reservedN-- + l.reservedB -= entry.bytes + removed++ + } + } + return removed +} + +func (l *TerminalLedger) Counts() (entries int, bytes int64) { + l.mu.Lock() + defer l.mu.Unlock() + return len(l.entries), l.reservedB +} diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go new file mode 100644 index 0000000000000..8696d59997ec4 --- /dev/null +++ b/pkg/udf/protocol/protocol_test.go @@ -0,0 +1,175 @@ +// Copyright 2026 Matrix Origin +// +// 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 protocol + +import ( + "bytes" + "errors" + "sync/atomic" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func testTuple() FencingTuple { + return FencingTuple{ + AccountID: 1, StatementID: "statement", GroupID: "group", + GroupEpoch: 2, InvocationID: "invocation", LeaseEpoch: 3, + } +} + +func TestControlRoundTripIsBoundedAndVersioned(t *testing.T) { + wire, err := MarshalControl(Control{Kind: "OpenInvocation", Tuple: testTuple(), Payload: []byte(`{"mode":"VECTOR"}`)}) + require.NoError(t, err) + got, err := UnmarshalControl(wire) + require.NoError(t, err) + require.Equal(t, Version, got.Version) + require.Equal(t, "OpenInvocation", got.Kind) + require.JSONEq(t, `{"mode":"VECTOR"}`, string(got.Payload)) + + _, err = UnmarshalControl(bytes.Repeat([]byte{'x'}, MaxControlBytes+1)) + require.ErrorIs(t, err, ErrProtocol) + _, err = MarshalControl(Control{Kind: "", Tuple: testTuple()}) + require.ErrorIs(t, err, ErrProtocol) +} + +func TestSequenceKeepsHalfCloseIndependentFromResults(t *testing.T) { + var sequence Sequence + require.NoError(t, sequence.AcceptInput(1)) + require.NoError(t, sequence.AcceptInput(2)) + require.NoError(t, sequence.EndInput(2)) + require.NoError(t, sequence.AcceptResult(1)) + require.False(t, sequence.ReadyToFinish()) + require.NoError(t, sequence.AcknowledgeResults(1)) + require.NoError(t, sequence.AcceptResult(2)) + require.NoError(t, sequence.AcknowledgeResults(2)) + require.True(t, sequence.ReadyToFinish()) + + require.ErrorIs(t, sequence.AcceptInput(3), ErrSequence) + require.ErrorIs(t, sequence.AcknowledgeResults(3), ErrSequence) + require.NoError(t, sequence.EndInput(2)) +} + +func TestOutputSnapshotFreezesBeforeWorkerCanRewrite(t *testing.T) { + worker := []byte("trusted-before-barrier") + snapshot, err := FreezeOutput(worker, 1024) + require.NoError(t, err) + worker[0] = 'X' + + require.NoError(t, snapshot.Validate(len("trusted-before-barrier"), snapshot.Digest())) + require.Equal(t, "trusted-before-barrier", string(snapshot.Bytes())) + + empty, err := FreezeOutput(nil, 1024) + require.NoError(t, err) + require.NoError(t, empty.Validate(0, empty.Digest())) +} + +func TestExecutionGroupReleasesOnlyAfterCloseAndAllMembersTerminal(t *testing.T) { + var releases atomic.Int32 + group, err := NewExecutionGroup("g", 1, 2, func() error { + releases.Add(1) + return nil + }) + require.NoError(t, err) + a, err := group.BeginOpen("a") + require.NoError(t, err) + require.NoError(t, a.Commit()) + b, err := group.BeginOpen("b") + require.NoError(t, err) + require.NoError(t, b.Commit()) + + require.NoError(t, group.MemberTerminal("a")) + require.NoError(t, group.Close(ReasonInputEOF)) + require.Equal(t, int32(0), releases.Load()) + require.NoError(t, group.MemberTerminal("b")) + require.Equal(t, int32(1), releases.Load()) + require.Equal(t, GroupReleased, group.State()) + + _, err = group.BeginOpen("late") + require.ErrorIs(t, err, ErrGroupClosed) + require.NoError(t, group.Close(ReasonCancel)) + require.Equal(t, int32(1), releases.Load()) +} + +func TestExecutionGroupZeroMemberAndAbortedOpenRelease(t *testing.T) { + var releases atomic.Int32 + group, err := NewExecutionGroup("g", 1, 1, func() error { + releases.Add(1) + return nil + }) + require.NoError(t, err) + open, err := group.BeginOpen("will-abort") + require.NoError(t, err) + require.NoError(t, group.Close(ReasonPartialOpenError)) + require.Equal(t, int32(0), releases.Load()) + require.NoError(t, open.Abort()) + require.Equal(t, int32(1), releases.Load()) + + group, err = NewExecutionGroup("empty", 1, 1, func() error { + releases.Add(1) + return nil + }) + require.NoError(t, err) + require.NoError(t, group.Close(ReasonEmptyInput)) + require.Equal(t, int32(2), releases.Load()) +} + +func TestTerminalLedgerRetainsTombstonesUntilExpiry(t *testing.T) { + ledger, err := NewTerminalLedger(2, 200) + require.NoError(t, err) + now := time.Unix(100, 0) + credit, err := ledger.Reserve("g1", 1, 100) + require.NoError(t, err) + require.NoError(t, credit.Add("i1", 100, now.Add(time.Hour))) + require.NoError(t, ledger.Complete("i1")) + credit.ReleaseUnused() + + second, err := ledger.Reserve("g2", 1, 100) + require.NoError(t, err) + require.NoError(t, second.Add("i2", 100, now.Add(time.Hour))) + second.ReleaseUnused() + _, err = ledger.Reserve("g3", 1, 1) + require.ErrorIs(t, err, ErrLedgerFull) + + require.Equal(t, 2, func() int { n, _ := ledger.Counts(); return n }()) + require.Equal(t, 0, ledger.Expire(now.Add(time.Minute))) + require.Equal(t, 2, func() int { n, _ := ledger.Counts(); return n }()) + require.Equal(t, 2, ledger.Expire(now.Add(2*time.Hour))) + third, err := ledger.Reserve("g3", 1, 1) + require.NoError(t, err) + require.NoError(t, third.Add("i3", 1, now.Add(3*time.Hour))) + + require.ErrorIs(t, ledger.Complete("missing"), ErrUnknownIdentity) + require.NoError(t, ledger.Complete("i3")) + require.NoError(t, ledger.Complete("i3")) +} + +func TestExecutionGroupReleaseErrorCanBeRetried(t *testing.T) { + var attempts atomic.Int32 + group, err := NewExecutionGroup("g", 1, 1, func() error { + if attempts.Add(1) == 1 { + return errors.New("temporary release failure") + } + return nil + }) + require.NoError(t, err) + require.Error(t, group.Close(ReasonCancel)) + require.Equal(t, GroupDraining, group.State()) + // A second close is the scheduler's retry-safe release trigger. + require.NoError(t, group.Close(ReasonCancel)) + require.Equal(t, GroupReleased, group.State()) + require.Equal(t, int32(2), attempts.Load()) +} diff --git a/pkg/udf/pythonruntime/arrow.go b/pkg/udf/pythonruntime/arrow.go new file mode 100644 index 0000000000000..c65bb9aea92f1 --- /dev/null +++ b/pkg/udf/pythonruntime/arrow.go @@ -0,0 +1,771 @@ +// Copyright 2026 Matrix Origin +// +// 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 pythonruntime + +import ( + "bytes" + "context" + "crypto/sha256" + "encoding/binary" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "math" + + "github.com/apache/arrow-go/v18/arrow" + "github.com/apache/arrow-go/v18/arrow/array" + "github.com/apache/arrow-go/v18/arrow/decimal128" + "github.com/apache/arrow-go/v18/arrow/flight" + "github.com/apache/arrow-go/v18/arrow/ipc" + "github.com/apache/arrow-go/v18/arrow/memory" + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/container/arrowipc" + "github.com/matrixorigin/matrixone/pkg/container/bytejson" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" +) + +const ( + TypeMetadataKey = "mo.udf.type" + TypeFingerprintKey = "mo.udf.type_fingerprint" + DefaultMaxBatchBytes = 16 << 20 + DefaultMaxBatchRows = 65536 + DefaultMaxControlBytes = 1 << 20 +) + +type TypeDescriptor struct { + TypeID int32 `json:"type_id"` + Width int32 `json:"width,omitempty"` + Scale int32 `json:"scale,omitempty"` + Charset uint8 `json:"charset,omitempty"` + OffsetWidth int32 `json:"offset_width,omitempty"` + JSONEncoding string `json:"json_encoding,omitempty"` + TemporalEncoding string `json:"temporal_encoding,omitempty"` +} + +func NewTypeDescriptor(typ types.Type) (TypeDescriptor, error) { + d := TypeDescriptor{TypeID: int32(typ.Oid), Width: typ.Width, Scale: typ.Scale, Charset: typ.Charset, OffsetWidth: 32} + switch typ.Oid { + case types.T_json: + d.JSONEncoding = "canonical_text" + case types.T_date, types.T_datetime, types.T_timestamp: + d.TemporalEncoding = "sql_zero_struct" + case types.T_bool, types.T_int8, types.T_int16, types.T_int32, types.T_int64, + types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, + types.T_float32, types.T_float64, types.T_decimal64, types.T_decimal128, + types.T_char, types.T_varchar, types.T_text, types.T_uuid, types.T_time, + types.T_binary, types.T_varbinary, types.T_blob, + types.T_array_float32, types.T_array_float64: + default: + return TypeDescriptor{}, fmt.Errorf("python runtime does not support MatrixOne type %s", typ.String()) + } + if typ.Oid == types.T_array_float32 || typ.Oid == types.T_array_float64 { + if typ.Width <= 0 { + return TypeDescriptor{}, fmt.Errorf("python runtime requires a positive vector dimension for %s", typ.String()) + } + d.OffsetWidth = 0 + } + if typ.Oid == types.T_uuid { + d.OffsetWidth = 0 + } + return d, nil +} + +func (d TypeDescriptor) Type() types.Type { + return types.NewWithCharset(types.T(d.TypeID), d.Width, d.Scale, d.Charset) +} +func (d TypeDescriptor) canonical() ([]byte, error) { return json.Marshal(d) } +func (d TypeDescriptor) Fingerprint() (string, error) { + canonical, err := d.canonical() + if err != nil { + return "", err + } + physical, err := d.arrowType() + if err != nil { + return "", err + } + h := sha256.New() + h.Write([]byte("matrixone-python-udf-type\x00")) + h.Write(canonical) + h.Write([]byte{0}) + h.Write([]byte(physical.Fingerprint())) + return hex.EncodeToString(h.Sum(nil)), nil +} + +func (d TypeDescriptor) arrowType() (arrow.DataType, error) { + switch types.T(d.TypeID) { + case types.T_bool: + return arrow.FixedWidthTypes.Boolean, nil + case types.T_int8: + return arrow.PrimitiveTypes.Int8, nil + case types.T_int16: + return arrow.PrimitiveTypes.Int16, nil + case types.T_int32: + return arrow.PrimitiveTypes.Int32, nil + case types.T_int64: + return arrow.PrimitiveTypes.Int64, nil + case types.T_uint8: + return arrow.PrimitiveTypes.Uint8, nil + case types.T_uint16: + return arrow.PrimitiveTypes.Uint16, nil + case types.T_uint32: + return arrow.PrimitiveTypes.Uint32, nil + case types.T_uint64: + return arrow.PrimitiveTypes.Uint64, nil + case types.T_float32: + return arrow.PrimitiveTypes.Float32, nil + case types.T_float64: + return arrow.PrimitiveTypes.Float64, nil + case types.T_decimal64, types.T_decimal128: + precision := d.Width + if precision == 0 { + precision = 18 + if types.T(d.TypeID) == types.T_decimal128 { + precision = 38 + } + } + if precision < 1 || precision > decimal128.MaxPrecision { + return nil, fmt.Errorf("decimal precision %d is outside Arrow's supported range", precision) + } + return &arrow.Decimal128Type{Precision: precision, Scale: d.Scale}, nil + case types.T_char, types.T_varchar, types.T_text, types.T_json: + if d.OffsetWidth == 64 { + return arrow.BinaryTypes.LargeString, nil + } + return arrow.BinaryTypes.String, nil + case types.T_binary, types.T_varbinary, types.T_blob: + if d.OffsetWidth == 64 { + return arrow.BinaryTypes.LargeBinary, nil + } + return arrow.BinaryTypes.Binary, nil + case types.T_uuid: + return &arrow.FixedSizeBinaryType{ByteWidth: 16}, nil + case types.T_time: + return &arrow.DurationType{Unit: arrow.Microsecond}, nil + case types.T_array_float32: + if d.Width <= 0 { + return nil, fmt.Errorf("invalid vecf32 dimension %d", d.Width) + } + return arrow.FixedSizeListOf(d.Width, arrow.PrimitiveTypes.Float32), nil + case types.T_array_float64: + if d.Width <= 0 { + return nil, fmt.Errorf("invalid vecf64 dimension %d", d.Width) + } + return arrow.FixedSizeListOf(d.Width, arrow.PrimitiveTypes.Float64), nil + case types.T_date: + return sqlTemporalType(arrow.PrimitiveTypes.Date32), nil + case types.T_datetime: + return sqlTemporalType(&arrow.TimestampType{Unit: arrow.Microsecond}), nil + case types.T_timestamp: + return sqlTemporalType(&arrow.TimestampType{Unit: arrow.Microsecond, TimeZone: "UTC"}), nil + default: + return nil, fmt.Errorf("unsupported MatrixOne type id %d", d.TypeID) + } +} +func sqlTemporalType(value arrow.DataType) *arrow.StructType { + return arrow.StructOf(arrow.Field{Name: "is_zero", Type: arrow.FixedWidthTypes.Boolean, Nullable: false}, arrow.Field{Name: "value", Type: value, Nullable: false}) +} +func (d TypeDescriptor) Field(name string) (arrow.Field, error) { + typ, err := d.arrowType() + if err != nil { + return arrow.Field{}, err + } + fingerprint, err := d.Fingerprint() + if err != nil { + return arrow.Field{}, err + } + descriptor, err := d.canonical() + if err != nil { + return arrow.Field{}, err + } + return arrow.Field{Name: name, Type: typ, Nullable: true, Metadata: arrow.NewMetadata([]string{TypeMetadataKey, TypeFingerprintKey}, []string{string(descriptor), fingerprint})}, nil +} +func (d TypeDescriptor) ValidateField(field arrow.Field) error { + want, err := d.Field(field.Name) + if err != nil { + return err + } + if field.Type == nil || field.Type.Fingerprint() != want.Type.Fingerprint() || field.Nullable != want.Nullable { + return fmt.Errorf("TYPE_CONTRACT: Arrow type %s does not match %s", field.Type, want.Type) + } + if !field.Metadata.Equal(want.Metadata) { + return fmt.Errorf("TYPE_CONTRACT: Arrow logical metadata does not match the frozen descriptor") + } + return nil +} + +type ArrowFrame struct { + Header []byte + Body []byte +} + +type encodedRecordBatch struct { + Frames []ArrowFrame + Rows int64 +} + +var errArrowBatchTooLarge = errors.New("Arrow record batch exceeds the configured limit") + +func EncodeRecordBatch(record arrow.RecordBatch, maxBytes int64) ([]ArrowFrame, error) { + if record == nil || record.Schema() == nil || maxBytes <= 0 { + return nil, fmt.Errorf("invalid Arrow record batch") + } + collector := &flightFrameCollector{maxBytes: maxBytes} + writer := flight.NewRecordWriter(collector, ipc.WithSchema(record.Schema()), ipc.WithAllocator(memory.NewGoAllocator())) + if err := writer.Write(record); err != nil { + return nil, fmt.Errorf("encode Arrow record batch: %w", err) + } + if err := writer.Close(); err != nil { + return nil, fmt.Errorf("close Arrow record batch: %w", err) + } + if len(collector.frames) < 2 { + return nil, fmt.Errorf("Arrow stream did not contain schema and record batch") + } + return collector.frames, nil +} + +// flightFrameCollector preserves the exact Flight representation: DataHeader +// is the unframed IPC FlatBuffer and DataBody contains the body plus its IPC +// alignment padding. A stream-file frame cannot be copied directly into +// FlightData because its eight-byte continuation prefix is not part of +// FlightData.DataHeader. +type flightFrameCollector struct { + frames []ArrowFrame + maxBytes int64 + total int64 +} + +func (c *flightFrameCollector) Send(data *flight.FlightData) error { + if data == nil || len(data.DataHeader) == 0 { + return fmt.Errorf("invalid Arrow Flight frame") + } + if data.FlightDescriptor != nil || len(data.AppMetadata) != 0 { + return fmt.Errorf("unexpected metadata on Arrow payload frame") + } + header := append([]byte(nil), data.DataHeader...) + body := append([]byte(nil), data.DataBody...) + c.total += int64(len(header) + len(body)) + if c.total > c.maxBytes { + return fmt.Errorf("%w: stream is %d bytes, limit is %d", errArrowBatchTooLarge, c.total, c.maxBytes) + } + c.frames = append(c.frames, ArrowFrame{Header: header, Body: body}) + return nil +} + +func BuildInputRecord(inputs []*vector.Vector, args []types.Type, length int) (arrow.RecordBatch, *arrow.Schema, error) { + return BuildInputRecordRange(inputs, args, 0, length) +} + +func BuildInputRecordRange(inputs []*vector.Vector, args []types.Type, start, length int) (arrow.RecordBatch, *arrow.Schema, error) { + if start < 0 || length <= 0 || len(inputs) != len(args) { + return nil, nil, fmt.Errorf("invalid Python UDF input shape") + } + fields := make([]arrow.Field, len(args)) + for i, typ := range args { + descriptor, err := NewTypeDescriptor(typ) + if err != nil { + return nil, nil, err + } + fields[i], err = descriptor.Field(fmt.Sprintf("arg_%d", i)) + if err != nil { + return nil, nil, err + } + if inputs[i] == nil || (!inputs[i].IsConst() && inputs[i].Length() < start+length) { + return nil, nil, fmt.Errorf("input column %d is shorter than batch range", i) + } + } + schema := arrow.NewSchema(fields, nil) + if len(fields) == 0 { + return array.NewRecordBatch(schema, nil, int64(length)), schema, nil + } + builder := array.NewRecordBuilder(memory.NewGoAllocator(), schema) + defer builder.Release() + for column, typ := range args { + for row := 0; row < length; row++ { + if err := appendInputValue(builder.Field(column), inputs[column], typ, start, row); err != nil { + return nil, nil, fmt.Errorf("input column %d row %d: %w", column, row, err) + } + } + } + return builder.NewRecordBatch(), schema, nil +} +func sourceRow(v *vector.Vector, start, row int) int { + if v.IsConst() { + return 0 + } + return start + row +} +func appendInputValue(builder array.Builder, v *vector.Vector, typ types.Type, start, row int) error { + index := sourceRow(v, start, row) + null := v.IsNull(uint64(index)) + if typ.Oid == types.T_date || typ.Oid == types.T_datetime || typ.Oid == types.T_timestamp { + return appendTemporalInput(builder.(*array.StructBuilder), v, typ, index, null) + } + if typ.Oid == types.T_time { + b := builder.(*array.DurationBuilder) + if null { + b.AppendNull() + } else { + b.Append(arrow.Duration(vector.GetFixedAtNoTypeCheck[types.Time](v, index))) + } + return nil + } + switch typ.Oid { + case types.T_bool: + b := builder.(*array.BooleanBuilder) + if null { + b.AppendNull() + } else { + b.Append(vector.GetFixedAtNoTypeCheck[bool](v, index)) + } + case types.T_int8: + b := builder.(*array.Int8Builder) + if null { + b.AppendNull() + } else { + b.Append(vector.GetFixedAtNoTypeCheck[int8](v, index)) + } + case types.T_int16: + b := builder.(*array.Int16Builder) + if null { + b.AppendNull() + } else { + b.Append(vector.GetFixedAtNoTypeCheck[int16](v, index)) + } + case types.T_int32: + b := builder.(*array.Int32Builder) + if null { + b.AppendNull() + } else { + b.Append(vector.GetFixedAtNoTypeCheck[int32](v, index)) + } + case types.T_int64: + b := builder.(*array.Int64Builder) + if null { + b.AppendNull() + } else { + b.Append(vector.GetFixedAtNoTypeCheck[int64](v, index)) + } + case types.T_uint8: + b := builder.(*array.Uint8Builder) + if null { + b.AppendNull() + } else { + b.Append(vector.GetFixedAtNoTypeCheck[uint8](v, index)) + } + case types.T_uint16: + b := builder.(*array.Uint16Builder) + if null { + b.AppendNull() + } else { + b.Append(vector.GetFixedAtNoTypeCheck[uint16](v, index)) + } + case types.T_uint32: + b := builder.(*array.Uint32Builder) + if null { + b.AppendNull() + } else { + b.Append(vector.GetFixedAtNoTypeCheck[uint32](v, index)) + } + case types.T_uint64: + b := builder.(*array.Uint64Builder) + if null { + b.AppendNull() + } else { + b.Append(vector.GetFixedAtNoTypeCheck[uint64](v, index)) + } + case types.T_float32: + b := builder.(*array.Float32Builder) + if null { + b.AppendNull() + } else { + b.Append(vector.GetFixedAtNoTypeCheck[float32](v, index)) + } + case types.T_float64: + b := builder.(*array.Float64Builder) + if null { + b.AppendNull() + } else { + b.Append(vector.GetFixedAtNoTypeCheck[float64](v, index)) + } + case types.T_decimal64: + b := builder.(*array.Decimal128Builder) + if null { + b.AppendNull() + } else { + b.Append(decimal64ToArrow(vector.GetFixedAtNoTypeCheck[types.Decimal64](v, index))) + } + case types.T_decimal128: + b := builder.(*array.Decimal128Builder) + if null { + b.AppendNull() + } else { + value := vector.GetFixedAtNoTypeCheck[types.Decimal128](v, index) + b.Append(decimal128.New(int64(value.B64_127), value.B0_63)) + } + case types.T_char, types.T_varchar, types.T_text, types.T_json: + b := builder.(*array.StringBuilder) + if null { + b.AppendNull() + } else { + p := vector.GenerateFunctionStrParameter(v) + value, _ := p.GetStrValue(uint64(index)) + if typ.Oid == types.T_json { + value = []byte(types.DecodeJson(value).String()) + } + b.Append(string(value)) + } + case types.T_binary, types.T_varbinary, types.T_blob: + b := builder.(*array.BinaryBuilder) + if null { + b.AppendNull() + } else { + p := vector.GenerateFunctionStrParameter(v) + value, _ := p.GetStrValue(uint64(index)) + b.Append(value) + } + case types.T_uuid: + b := builder.(*array.FixedSizeBinaryBuilder) + if null { + b.AppendNull() + } else { + value := vector.GetFixedAtNoTypeCheck[types.Uuid](v, index) + b.Append(value[:]) + } + case types.T_array_float32: + b := builder.(*array.FixedSizeListBuilder) + if null { + b.AppendNull() + } else { + b.Append(true) + b.ValueBuilder().(*array.Float32Builder).AppendValues(vector.GetArrayAt[float32](v, index), nil) + } + case types.T_array_float64: + b := builder.(*array.FixedSizeListBuilder) + if null { + b.AppendNull() + } else { + b.Append(true) + b.ValueBuilder().(*array.Float64Builder).AppendValues(vector.GetArrayAt[float64](v, index), nil) + } + default: + return fmt.Errorf("unsupported input type %s", typ.String()) + } + return nil +} +func appendTemporalInput(builder *array.StructBuilder, v *vector.Vector, typ types.Type, index int, null bool) error { + zero := false + var raw int64 + switch typ.Oid { + case types.T_date: + if !null { + value := vector.GetFixedAtNoTypeCheck[types.Date](v, index) + zero = value == types.ZeroDate + if !zero { + raw = int64(value.DaysSinceUnixEpoch()) + } + } + builder.Append(!null) + builder.FieldBuilder(0).(*array.BooleanBuilder).Append(zero) + builder.FieldBuilder(1).(*array.Date32Builder).Append(arrow.Date32(raw)) + case types.T_datetime: + if !null { + value := vector.GetFixedAtNoTypeCheck[types.Datetime](v, index) + zero = value == types.ZeroDatetime + if !zero { + raw = int64(value) - types.GetUnixEpochSecs() + } + } + builder.Append(!null) + builder.FieldBuilder(0).(*array.BooleanBuilder).Append(zero) + builder.FieldBuilder(1).(*array.TimestampBuilder).Append(arrow.Timestamp(raw)) + case types.T_timestamp: + if !null { + value := vector.GetFixedAtNoTypeCheck[types.Timestamp](v, index) + zero = value == types.ZeroTimestamp + if !zero { + raw = int64(value) - types.GetUnixEpochSecs() + } + } + builder.Append(!null) + builder.FieldBuilder(0).(*array.BooleanBuilder).Append(zero) + builder.FieldBuilder(1).(*array.TimestampBuilder).Append(arrow.Timestamp(raw)) + default: + return fmt.Errorf("unsupported temporal type %s", typ.String()) + } + return nil +} +func decimal64ToArrow(value types.Decimal64) decimal128.Num { + if value.Sign() { + return decimal128.New(-1, uint64(value)) + } + return decimal128.New(0, uint64(value)) +} + +func DecodeRecordBatch(schemaFrame, batchFrame ArrowFrame, maxBytes int64) (arrow.RecordBatch, error) { + if len(schemaFrame.Header) == 0 || len(batchFrame.Header) == 0 || maxBytes <= 0 { + return nil, fmt.Errorf("invalid Arrow output frames") + } + if _, err := arrowipc.InspectMessage(context.Background(), schemaFrame.Header, arrowipc.ValidationOptions{MaxMetadataBytes: arrowipc.DefaultMaxMetadataBytes, MaxBodyBytes: 0, BodyEnvelopeBytes: 0, MaxDecodedRecordBytes: 1}); err != nil { + return nil, err + } + if _, err := arrowipc.InspectMessage(context.Background(), batchFrame.Header, arrowipc.ValidationOptions{MaxMetadataBytes: arrowipc.DefaultMaxMetadataBytes, MaxBodyBytes: maxBytes, BodyEnvelopeBytes: int64(len(batchFrame.Body)), Body: batchFrame.Body, ValidateBody: true, MaxDecodedRecordBytes: maxBytes}); err != nil { + return nil, err + } + stream := make([]byte, 0, len(schemaFrame.Header)+len(batchFrame.Header)+len(batchFrame.Body)+32) + stream = appendIPCFrame(stream, schemaFrame.Header, schemaFrame.Body) + stream = appendIPCFrame(stream, batchFrame.Header, batchFrame.Body) + stream = append(stream, 0, 0, 0, 0, 0, 0, 0, 0) + reader, err := ipc.NewReader(bytes.NewReader(stream), ipc.WithAllocator(memory.NewGoAllocator())) + if err != nil { + return nil, fmt.Errorf("decode Arrow output: %w", err) + } + defer reader.Release() + if !reader.Next() { + return nil, fmt.Errorf("decode Arrow output: %v", reader.Err()) + } + record := reader.RecordBatch() + if record == nil { + return nil, fmt.Errorf("decode Arrow output: missing record batch") + } + record.Retain() + return record, nil +} +func appendIPCFrame(dst, header, body []byte) []byte { + metadataLength := (len(header) + 7) &^ 7 + var prefix [8]byte + binary.LittleEndian.PutUint32(prefix[:4], math.MaxUint32) + binary.LittleEndian.PutUint32(prefix[4:], uint32(metadataLength)) + dst = append(dst, prefix[:]...) + dst = append(dst, header...) + for len(dst)%8 != 0 { + dst = append(dst, 0) + } + dst = append(dst, body...) + for len(dst)%8 != 0 { + dst = append(dst, 0) + } + return dst +} + +func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vector.FunctionResultWrapper, mp *mpool.MPool) error { + if input == nil || result == nil || input.Len() == 0 { + return nil + } + if mp == nil { + return fmt.Errorf("python runtime: missing memory pool for Arrow result") + } + if err := validateArrayType(descriptor, input); err != nil { + return err + } + result.GetResultVector().SetTypeScale(descriptor.Scale) + typ := types.T(descriptor.TypeID) + for i := 0; i < input.Len(); i++ { + null := input.IsNull(i) + switch typ { + case types.T_bool: + if err := vector.MustFunctionResult[bool](result).Append(input.(*array.Boolean).Value(i), null); err != nil { + return err + } + case types.T_int8: + if err := vector.MustFunctionResult[int8](result).Append(input.(*array.Int8).Value(i), null); err != nil { + return err + } + case types.T_int16: + if err := vector.MustFunctionResult[int16](result).Append(input.(*array.Int16).Value(i), null); err != nil { + return err + } + case types.T_int32: + if err := vector.MustFunctionResult[int32](result).Append(input.(*array.Int32).Value(i), null); err != nil { + return err + } + case types.T_int64: + if err := vector.MustFunctionResult[int64](result).Append(input.(*array.Int64).Value(i), null); err != nil { + return err + } + case types.T_uint8: + if err := vector.MustFunctionResult[uint8](result).Append(input.(*array.Uint8).Value(i), null); err != nil { + return err + } + case types.T_uint16: + if err := vector.MustFunctionResult[uint16](result).Append(input.(*array.Uint16).Value(i), null); err != nil { + return err + } + case types.T_uint32: + if err := vector.MustFunctionResult[uint32](result).Append(input.(*array.Uint32).Value(i), null); err != nil { + return err + } + case types.T_uint64: + if err := vector.MustFunctionResult[uint64](result).Append(input.(*array.Uint64).Value(i), null); err != nil { + return err + } + case types.T_float32: + if err := vector.MustFunctionResult[float32](result).Append(input.(*array.Float32).Value(i), null); err != nil { + return err + } + case types.T_float64: + if err := vector.MustFunctionResult[float64](result).Append(input.(*array.Float64).Value(i), null); err != nil { + return err + } + case types.T_decimal64: + value, err := decimalFromArray(input.(*array.Decimal128).Value(i), true) + if err != nil { + return err + } + if err = vector.MustFunctionResult[types.Decimal64](result).Append(value.(types.Decimal64), null); err != nil { + return err + } + case types.T_decimal128: + value, err := decimalFromArray(input.(*array.Decimal128).Value(i), false) + if err != nil { + return err + } + if err = vector.MustFunctionResult[types.Decimal128](result).Append(value.(types.Decimal128), null); err != nil { + return err + } + case types.T_char, types.T_varchar, types.T_text: + if err := vector.MustFunctionResult[types.Varlena](result).AppendBytes([]byte(input.(*array.String).Value(i)), null); err != nil { + return err + } + case types.T_json: + if null { + if err := vector.MustFunctionResult[types.Varlena](result).AppendBytes(nil, true); err != nil { + return err + } + continue + } + encoded, err := bytejson.ParseJsonByteFromString(input.(*array.String).Value(i)) + if err != nil { + return fmt.Errorf("TYPE_CONTRACT: invalid JSON result: %w", err) + } + if err = vector.MustFunctionResult[types.Varlena](result).AppendBytes(encoded, false); err != nil { + return err + } + case types.T_binary, types.T_varbinary, types.T_blob: + if err := vector.MustFunctionResult[types.Varlena](result).AppendBytes(input.(*array.Binary).Value(i), null); err != nil { + return err + } + case types.T_uuid: + var value types.Uuid + if !null { + copy(value[:], input.(*array.FixedSizeBinary).Value(i)) + } + if err := vector.MustFunctionResult[types.Uuid](result).Append(value, null); err != nil { + return err + } + case types.T_time: + if err := vector.MustFunctionResult[types.Time](result).Append(types.Time(input.(*array.Duration).Value(i)), null); err != nil { + return err + } + case types.T_array_float32: + if err := appendFloat32ArrayResult(input.(*array.FixedSizeList), i, null, result, mp); err != nil { + return err + } + case types.T_array_float64: + if err := appendFloat64ArrayResult(input.(*array.FixedSizeList), i, null, result, mp); err != nil { + return err + } + case types.T_date, types.T_datetime, types.T_timestamp: + if err := appendTemporalResult(input.(*array.Struct), typ, i, result); err != nil { + return err + } + default: + return fmt.Errorf("unsupported output type %s", typ.String()) + } + } + return nil +} + +func appendFloat32ArrayResult(input *array.FixedSizeList, row int, null bool, result vector.FunctionResultWrapper, mp *mpool.MPool) error { + if null { + return vector.AppendArray[float32](result.GetResultVector(), nil, true, mp) + } + start, end := input.ValueOffsets(row) + values := input.ListValues().(*array.Float32) + items := make([]float32, end-start) + for i := start; i < end; i++ { + items[i-start] = values.Value(int(i)) + } + return vector.AppendArray(result.GetResultVector(), items, false, mp) +} + +func appendFloat64ArrayResult(input *array.FixedSizeList, row int, null bool, result vector.FunctionResultWrapper, mp *mpool.MPool) error { + if null { + return vector.AppendArray[float64](result.GetResultVector(), nil, true, mp) + } + start, end := input.ValueOffsets(row) + values := input.ListValues().(*array.Float64) + items := make([]float64, end-start) + for i := start; i < end; i++ { + items[i-start] = values.Value(int(i)) + } + return vector.AppendArray(result.GetResultVector(), items, false, mp) +} +func validateArrayType(descriptor TypeDescriptor, input arrow.Array) error { + want, err := descriptor.arrowType() + if err != nil { + return err + } + if input.DataType().Fingerprint() != want.Fingerprint() { + return fmt.Errorf("TYPE_CONTRACT: output Arrow type %s does not match %s", input.DataType(), want) + } + return nil +} +func decimalFromArray(value decimal128.Num, narrow bool) (any, error) { + high, low := uint64(value.HighBits()), value.LowBits() + if narrow && high != 0 && high != math.MaxUint64 { + return nil, fmt.Errorf("TYPE_CONTRACT: Decimal128 result does not fit Decimal64") + } + if narrow { + return types.Decimal64(low), nil + } + return types.Decimal128{B0_63: low, B64_127: high}, nil +} +func appendTemporalResult(input *array.Struct, typ types.T, index int, result vector.FunctionResultWrapper) error { + if input.IsNull(index) { + return appendTemporalNull(typ, result) + } + zero := input.Field(0).(*array.Boolean).Value(index) + if typ == types.T_date { + value := types.ZeroDate + if !zero { + value = types.DaysFromUnixEpochToDate(int32(input.Field(1).(*array.Date32).Value(index))) + } + return vector.MustFunctionResult[types.Date](result).Append(value, false) + } + if typ == types.T_datetime { + value := types.ZeroDatetime + if !zero { + value = types.Datetime(input.Field(1).(*array.Timestamp).Value(index)) + types.Datetime(types.GetUnixEpochSecs()) + } + return vector.MustFunctionResult[types.Datetime](result).Append(value, false) + } + value := types.ZeroTimestamp + if !zero { + value = types.Timestamp(input.Field(1).(*array.Timestamp).Value(index)) + types.Timestamp(types.GetUnixEpochSecs()) + } + return vector.MustFunctionResult[types.Timestamp](result).Append(value, false) +} +func appendTemporalNull(typ types.T, result vector.FunctionResultWrapper) error { + switch typ { + case types.T_date: + return vector.MustFunctionResult[types.Date](result).Append(0, true) + case types.T_datetime: + return vector.MustFunctionResult[types.Datetime](result).Append(0, true) + default: + return vector.MustFunctionResult[types.Timestamp](result).Append(0, true) + } +} diff --git a/pkg/udf/pythonruntime/arrow_test.go b/pkg/udf/pythonruntime/arrow_test.go new file mode 100644 index 0000000000000..97ed943333f54 --- /dev/null +++ b/pkg/udf/pythonruntime/arrow_test.go @@ -0,0 +1,75 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package pythonruntime + +import ( + "testing" + + "github.com/apache/arrow-go/v18/arrow" + "github.com/apache/arrow-go/v18/arrow/array" + "github.com/apache/arrow-go/v18/arrow/memory" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/stretchr/testify/require" +) + +func TestArrowFieldMetadataIsExact(t *testing.T) { + descriptor, err := NewTypeDescriptor(types.T_varchar.ToType()) + require.NoError(t, err) + field, err := descriptor.Field("result") + require.NoError(t, err) + require.Equal(t, []string{TypeMetadataKey, TypeFingerprintKey}, field.Metadata.Keys()) + require.NoError(t, descriptor.ValidateField(field)) + + withExtra := field + withExtra.Metadata = arrow.MetadataFrom(map[string]string{ + TypeMetadataKey: field.Metadata.ToMap()[TypeMetadataKey], + TypeFingerprintKey: field.Metadata.ToMap()[TypeFingerprintKey], + "untrusted": "must be rejected", + }) + require.Error(t, descriptor.ValidateField(withExtra)) +} + +func TestEncodeRecordBatchUsesFlightPayloadFrames(t *testing.T) { + descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + field, err := descriptor.Field("arg_0") + require.NoError(t, err) + builder := array.NewInt64Builder(memory.NewGoAllocator()) + builder.AppendValues([]int64{1, 2, 3}, nil) + values := builder.NewInt64Array() + defer values.Release() + record := array.NewRecordBatch(arrow.NewSchema([]arrow.Field{field}, nil), []arrow.Array{values}, 3) + defer record.Release() + + frames, err := EncodeRecordBatch(record, DefaultMaxBatchBytes) + require.NoError(t, err) + require.Len(t, frames, 2) + // FlightData.DataHeader is the raw IPC FlatBuffer, without the stream + // continuation prefix. DecodeRecordBatch adds that prefix back only for + // the local bounded decoder. + require.NotEqual(t, []byte{0xff, 0xff, 0xff, 0xff}, frames[0].Header[:4]) + decoded, err := DecodeRecordBatch(frames[0], frames[1], DefaultMaxBatchBytes) + require.NoError(t, err) + defer decoded.Release() + require.Equal(t, int64(3), decoded.NumRows()) + decodedValues := decoded.Column(0).(*array.Int64) + require.Equal(t, int64(1), decodedValues.Value(0)) + require.Equal(t, int64(2), decodedValues.Value(1)) + require.Equal(t, int64(3), decodedValues.Value(2)) +} + +func TestZeroArgumentRecordPreservesRows(t *testing.T) { + record := array.NewRecordBatch(arrow.NewSchema(nil, nil), nil, 3) + defer record.Release() + frames, err := EncodeRecordBatch(record, DefaultMaxBatchBytes) + require.NoError(t, err) + require.Len(t, frames, 2) + decoded, err := DecodeRecordBatch(frames[0], frames[1], DefaultMaxBatchBytes) + require.NoError(t, err) + defer decoded.Release() + require.Equal(t, int64(3), decoded.NumRows()) + require.Equal(t, int64(0), decoded.NumCols()) +} diff --git a/pkg/udf/pythonruntime/config.go b/pkg/udf/pythonruntime/config.go new file mode 100644 index 0000000000000..c6b6ae301d25b --- /dev/null +++ b/pkg/udf/pythonruntime/config.go @@ -0,0 +1,56 @@ +// Copyright 2026 Matrix Origin +// +// 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 + +package pythonruntime + +import ( + "context" + "time" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" +) + +type Config struct { + UUID string `toml:"uuid"` + Address string `toml:"address"` + Path string `toml:"path"` + Python string `toml:"python"` +} + +func (c *Config) Validate() error { + if c.Address == "" { + return moerr.NewInternalError(context.Background(), "missing python runtime address") + } + if c.Path == "" { + return moerr.NewInternalError(context.Background(), "missing python runtime path") + } + return nil +} + +type ClientConfig struct { + ServerAddress string `toml:"server-address"` + MaxBatchBytes int64 `toml:"max-batch-bytes"` + MaxBatchRows int64 `toml:"max-batch-rows"` + RequestTimeout time.Duration `toml:"request-timeout"` +} + +func (c *ClientConfig) Validate() error { + if c.ServerAddress == "" { + return moerr.NewInternalError(context.Background(), "missing python runtime address") + } + if c.MaxBatchBytes < 0 || c.MaxBatchBytes > 1<<30 { + return moerr.NewInternalError(context.Background(), "invalid python runtime max batch bytes") + } + if c.MaxBatchRows < 0 || c.MaxBatchRows > 1<<30 { + return moerr.NewInternalError(context.Background(), "invalid python runtime max batch rows") + } + if c.RequestTimeout < 0 { + return moerr.NewInternalError(context.Background(), "invalid python runtime request timeout") + } + return nil +} diff --git a/pkg/udf/pythonruntime/gateway.go b/pkg/udf/pythonruntime/gateway.go new file mode 100644 index 0000000000000..433393d1f330e --- /dev/null +++ b/pkg/udf/pythonruntime/gateway.go @@ -0,0 +1,536 @@ +// Copyright 2026 Matrix Origin +// +// 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 + +package pythonruntime + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "sync" + "time" + + "github.com/apache/arrow-go/v18/arrow/flight/gen/flight" + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/matrixorigin/matrixone/pkg/udf/protocol" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +const ( + ModeScalar = "SCALAR" + ModeVector = "VECTOR" + NullCallHandler = "CALLED_ON_NULL_INPUT" + NullReturnNull = "RETURNS_NULL_ON_NULL_INPUT" + statusOK = "OK" +) + +type Gateway struct { + cfg ClientConfig + conn *grpc.ClientConn + flight flight.FlightServiceClient + mu sync.Mutex + lifecycle sync.RWMutex +} + +func NewGateway(cfg ClientConfig) (*Gateway, error) { + if err := cfg.Validate(); err != nil { + return nil, err + } + if cfg.MaxBatchBytes == 0 { + cfg.MaxBatchBytes = DefaultMaxBatchBytes + } + if cfg.MaxBatchRows == 0 { + cfg.MaxBatchRows = DefaultMaxBatchRows + } + if cfg.RequestTimeout == 0 { + cfg.RequestTimeout = 30 * time.Second + } + return &Gateway{cfg: cfg}, nil +} + +func (g *Gateway) Language() string { return udf.LanguagePython } + +func (g *Gateway) connect() error { + g.mu.Lock() + defer g.mu.Unlock() + if g.flight != nil { + return nil + } + conn, err := grpc.NewClient(g.cfg.ServerAddress, + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithDefaultCallOptions( + grpc.MaxCallSendMsgSize(int(g.cfg.MaxBatchBytes)+1<<20), + grpc.MaxCallRecvMsgSize(int(g.cfg.MaxBatchBytes)+1<<20), + ), + ) + if err != nil { + return err + } + g.conn = conn + g.flight = flight.NewFlightServiceClient(conn) + return nil +} + +func (g *Gateway) Close() error { + g.lifecycle.Lock() + defer g.lifecycle.Unlock() + g.mu.Lock() + defer g.mu.Unlock() + if g.conn == nil { + return nil + } + err := g.conn.Close() + g.conn = nil + g.flight = nil + return err +} + +type openPayload struct { + Handler string `json:"handler"` + Source string `json:"source"` + Mode string `json:"mode"` + NullPolicy string `json:"null_policy"` + ABIContract string `json:"abi_contract"` + AdapterVersion string `json:"adapter_version"` + SDKVersion string `json:"sdk_version"` + Context map[string]string `json:"context,omitempty"` + Args []TypeDescriptor `json:"args"` + Return TypeDescriptor `json:"return"` + MaxBatchBytes int64 `json:"max_batch_bytes"` + MaxBatchRows int64 `json:"max_batch_rows"` +} + +func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, result vector.FunctionResultWrapper, mp *mpool.MPool) error { + g.lifecycle.RLock() + defer g.lifecycle.RUnlock() + if ctx == nil { + ctx = context.Background() + } + if invocation == nil || result == nil || mp == nil { + return fmt.Errorf("python runtime: nil invocation, result, or memory pool") + } + if err := validateInvocation(invocation); err != nil { + return err + } + if invocation.Length == 0 { + return result.PreExtendAndReset(0) + } + if err := g.connect(); err != nil { + return err + } + + args := make([]TypeDescriptor, len(invocation.Args)) + for i, typ := range invocation.Args { + var err error + args[i], err = NewTypeDescriptor(typ) + if err != nil { + return err + } + } + returnDescriptor, err := NewTypeDescriptor(invocation.ReturnType) + if err != nil { + return err + } + openBody, err := json.Marshal(openPayload{Handler: invocation.Handler, Source: invocation.Source, Mode: invocation.Mode, NullPolicy: invocation.NullPolicy, ABIContract: invocation.ABIContract, AdapterVersion: invocation.AdapterVersion, SDKVersion: invocation.SDKVersion, Context: cloneMap(invocation.Context), Args: args, Return: returnDescriptor, MaxBatchBytes: g.cfg.MaxBatchBytes, MaxBatchRows: g.cfg.MaxBatchRows}) + if err != nil { + return fmt.Errorf("python runtime: encode open payload: %w", err) + } + open, err := protocol.MarshalControl(protocol.Control{Kind: "OpenInvocation", Tuple: invocation.Tuple, Payload: openBody}) + if err != nil { + return err + } + + stream, err := g.flight.DoExchange(ctx) + if err != nil { + return fmt.Errorf("python runtime: open Arrow Flight exchange: %w", err) + } + // Flight carries the invocation command in the descriptor. The descriptor + // is delivered to the server separately from the Arrow IPC reader; putting + // the JSON command in AppMetadata on this message makes PyArrow try to + // decode it as an IPC message. + if err := stream.Send(&flight.FlightData{FlightDescriptor: &flight.FlightDescriptor{Type: flight.FlightDescriptor_CMD, Cmd: open}}); err != nil { + return err + } + if err := result.PreExtendAndReset(invocation.Length); err != nil { + return err + } + + var sequence protocol.Sequence + var schemaFrame *ArrowFrame + var inputSchema []byte + rows := 0 + var start int64 + var batchIndex uint64 + var lastSequence uint64 + var inputEnded bool + for start < int64(invocation.Length) { + batch, err := encodeInputBatch(invocation.Inputs, invocation.Args, start, int64(invocation.Length)-start, g.cfg.MaxBatchBytes, g.cfg.MaxBatchRows) + if err != nil { + return err + } + if len(batch.Frames) != 2 { + return fmt.Errorf("python runtime: input batch contains %d Arrow frames", len(batch.Frames)) + } + if batchIndex == 0 { + inputSchema = append([]byte(nil), batch.Frames[0].Header...) + if err := stream.Send(&flight.FlightData{DataHeader: batch.Frames[0].Header}); err != nil { + return err + } + } else if !bytes.Equal(inputSchema, batch.Frames[0].Header) { + return fmt.Errorf("python runtime: input batches do not share one Arrow schema") + } + sequenceNumber := batchIndex + 1 + if err := sequence.AcceptInput(sequenceNumber); err != nil { + return err + } + inputControl, err := protocol.MarshalControl(protocol.Control{Kind: "InputBatch", Tuple: invocation.Tuple, Sequence: sequenceNumber}) + if err != nil { + return err + } + if err := stream.Send(&flight.FlightData{DataHeader: batch.Frames[1].Header, DataBody: batch.Frames[1].Body, AppMetadata: inputControl}); err != nil { + return err + } + lastSequence = sequenceNumber + isLastBatch := start+batch.Rows == int64(invocation.Length) + if isLastBatch { + // EndInput is an application-level half-close. Send it before + // waiting for the final result so the runtime must keep its result + // direction alive when that result is delayed on the wire. + endInput, err := protocol.MarshalControl(protocol.Control{Kind: "EndInput", Tuple: invocation.Tuple, LastSequence: lastSequence}) + if err != nil { + return err + } + if err := stream.Send(&flight.FlightData{AppMetadata: endInput}); err != nil { + return err + } + if err := sequence.EndInput(lastSequence); err != nil { + return err + } + if err := stream.CloseSend(); err != nil { + return err + } + inputEnded = true + } + batchRows, err := g.receiveResultBatch(ctx, stream, invocation.Tuple, sequenceNumber, batch.Rows, &schemaFrame, returnDescriptor, result, mp, &sequence) + if err != nil { + return err + } + rows += batchRows + start += batch.Rows + batchIndex++ + if isLastBatch { + break + } + } + if !inputEnded || lastSequence != batchIndex { + return fmt.Errorf("python runtime: input stream did not reach EndInput") + } + return g.receiveFinish(ctx, stream, invocation.Tuple, invocation.Length, rows, &sequence) +} + +func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaining, maxBytes, maxRows int64) (encodedRecordBatch, error) { + if start < 0 || remaining <= 0 { + return encodedRecordBatch{}, fmt.Errorf("invalid Python UDF input batch range") + } + if maxRows <= 0 { + return encodedRecordBatch{}, fmt.Errorf("invalid Python UDF max batch rows") + } + if remaining > maxRows { + remaining = maxRows + } + tryEncode := func(rows int64) ([]ArrowFrame, error) { + record, _, err := BuildInputRecordRange(inputs, args, int(start), int(rows)) + if err != nil { + return nil, err + } + frames, encodeErr := EncodeRecordBatch(record, maxBytes) + record.Release() + return frames, encodeErr + } + best, probe := int64(0), int64(1) + var bestFrames []ArrowFrame + failedAt := int64(0) + for { + frames, err := tryEncode(probe) + if err == nil { + best, bestFrames = probe, frames + if probe == remaining { + return encodedRecordBatch{Frames: bestFrames, Rows: best}, nil + } + if probe > remaining/2 { + probe = remaining + } else { + probe *= 2 + } + continue + } + if !errors.Is(err, errArrowBatchTooLarge) { + return encodedRecordBatch{}, err + } + failedAt = probe + break + } + low, high := best+1, failedAt-1 + for low <= high { + middle := low + (high-low)/2 + frames, err := tryEncode(middle) + if err == nil { + best, bestFrames = middle, frames + low = middle + 1 + continue + } + if !errors.Is(err, errArrowBatchTooLarge) { + return encodedRecordBatch{}, err + } + high = middle - 1 + } + if best == 0 { + return encodedRecordBatch{}, fmt.Errorf("%w: one Arrow row exceeds %d bytes", errArrowBatchTooLarge, maxBytes) + } + return encodedRecordBatch{Frames: bestFrames, Rows: best}, nil +} + +func (g *Gateway) receiveResultBatch( + ctx context.Context, + stream flight.FlightService_DoExchangeClient, + tuple protocol.FencingTuple, + sequenceNumber uint64, + expectedRows int64, + schemaFrame **ArrowFrame, + returnDescriptor TypeDescriptor, + result vector.FunctionResultWrapper, + mp *mpool.MPool, + sequence *protocol.Sequence, +) (int, error) { + for { + data, err := stream.Recv() + if err != nil { + if err == io.EOF { + return 0, fmt.Errorf("python runtime: exchange ended before result sequence %d", sequenceNumber) + } + return 0, fmt.Errorf("python runtime: receive result: %w", err) + } + if data == nil || (len(data.AppMetadata) == 0 && len(data.DataHeader) == 0) { + return 0, fmt.Errorf("python runtime: empty Flight result") + } + if len(data.DataHeader) > 0 { + if *schemaFrame == nil { + if len(data.DataBody) != 0 { + return 0, fmt.Errorf("python runtime: result schema contains a body") + } + *schemaFrame = &ArrowFrame{Header: append([]byte(nil), data.DataHeader...)} + if len(data.AppMetadata) > 0 { + control, err := protocol.UnmarshalControl(data.AppMetadata) + if err != nil || control.Kind != "ResultSchema" { + return 0, fmt.Errorf("python runtime: invalid result schema metadata") + } + } + continue + } + control, err := protocol.UnmarshalControl(data.AppMetadata) + if err != nil { + return 0, err + } + if control.Tuple != tuple || control.Kind != "ResultBatch" || control.Sequence != sequenceNumber { + return 0, fmt.Errorf("python runtime: unexpected result sequence %d", control.Sequence) + } + if err := sequence.AcceptResult(control.Sequence); err != nil { + return 0, err + } + snapshot, err := protocol.FreezeOutput(data.DataBody, g.cfg.MaxBatchBytes) + if err != nil { + return 0, err + } + if err := snapshot.Validate(len(data.DataBody), snapshot.Digest()); err != nil { + return 0, err + } + decoded, err := DecodeRecordBatch(**schemaFrame, ArrowFrame{Header: append([]byte(nil), data.DataHeader...), Body: snapshot.TrustedBytes()}, g.cfg.MaxBatchBytes) + if err != nil { + return 0, fmt.Errorf("python runtime: decode result: %w", err) + } + if decoded.NumCols() != 1 || decoded.NumRows() <= 0 || decoded.NumRows() != expectedRows { + decoded.Release() + return 0, fmt.Errorf("python runtime: result batch row count %d, expected %d", decoded.NumRows(), expectedRows) + } + if decoded.Schema().Field(0).Name != "result" { + decoded.Release() + return 0, fmt.Errorf("python runtime: result field has unexpected name %q", decoded.Schema().Field(0).Name) + } + if err := returnDescriptor.ValidateField(decoded.Schema().Field(0)); err != nil { + decoded.Release() + return 0, err + } + if err := AppendArrowResult(returnDescriptor, decoded.Column(0), result, mp); err != nil { + decoded.Release() + return 0, err + } + decoded.Release() + if err := g.action(ctx, "AcknowledgeResults", protocol.Control{Kind: "AcknowledgeResults", Tuple: tuple, AckSequence: control.Sequence}); err != nil { + return 0, err + } + if err := sequence.AcknowledgeResults(control.Sequence); err != nil { + return 0, err + } + return int(expectedRows), nil + } + control, err := protocol.UnmarshalControl(data.AppMetadata) + if err != nil { + return 0, err + } + if control.Tuple != tuple { + return 0, fmt.Errorf("python runtime: result tuple changed") + } + switch control.Kind { + case "ResultSchema": + continue + case "InputConsumed": + if control.Sequence != sequenceNumber { + return 0, fmt.Errorf("python runtime: input sequence %d was consumed while waiting for result %d", control.Sequence, sequenceNumber) + } + continue + case "Error": + return 0, fmt.Errorf("python runtime: worker error: %s", control.Reason) + case "Finish": + return 0, fmt.Errorf("python runtime: Finish arrived before result sequence %d", sequenceNumber) + default: + return 0, fmt.Errorf("python runtime: unexpected control %q", control.Kind) + } + } +} + +func (g *Gateway) receiveFinish( + ctx context.Context, + stream flight.FlightService_DoExchangeClient, + tuple protocol.FencingTuple, + expectedRows, rows int, + sequence *protocol.Sequence, +) error { + for { + data, err := stream.Recv() + if err != nil { + if err == io.EOF { + return fmt.Errorf("python runtime: exchange ended before Finish") + } + return fmt.Errorf("python runtime: receive Finish: %w", err) + } + if data == nil || len(data.DataHeader) > 0 { + return fmt.Errorf("python runtime: unexpected Arrow data while finishing") + } + control, err := protocol.UnmarshalControl(data.AppMetadata) + if err != nil { + return err + } + if control.Tuple != tuple { + return fmt.Errorf("python runtime: Finish tuple changed") + } + switch control.Kind { + case "InputConsumed", "ResultSchema": + continue + case "Error": + return fmt.Errorf("python runtime: worker error: %s", control.Reason) + case "Finish": + lastInput, lastResult, acked, inputEnded := sequence.State() + if control.Status != statusOK || control.FinishID == "" || rows != expectedRows || + !inputEnded || control.LastSequence != lastInput || lastResult != lastInput || acked != lastInput || !sequence.ReadyToFinish() { + return fmt.Errorf("python runtime: invalid Finish status=%q rows=%d", control.Status, rows) + } + return g.action(ctx, "AcknowledgeFinish", protocol.Control{Kind: "AcknowledgeFinish", Tuple: tuple, FinishID: control.FinishID}) + default: + return fmt.Errorf("python runtime: unexpected control %q", control.Kind) + } + } +} + +func validateInvocation(invocation *udf.Invocation) error { + if invocation.Language != "" && invocation.Language != udf.LanguagePython { + return fmt.Errorf("python runtime: unsupported language %q", invocation.Language) + } + if invocation.Handler == "" || invocation.Source == "" { + return fmt.Errorf("python runtime: handler and source are required") + } + if invocation.Length < 0 || len(invocation.Args) != len(invocation.Inputs) { + return fmt.Errorf("python runtime: invalid input shape") + } + if invocation.Mode == "" { + invocation.Mode = ModeScalar + } + if invocation.Mode != ModeScalar && invocation.Mode != ModeVector { + return fmt.Errorf("python runtime: unsupported mode %q", invocation.Mode) + } + if invocation.NullPolicy == "" { + invocation.NullPolicy = NullCallHandler + } + if invocation.NullPolicy != NullCallHandler && invocation.NullPolicy != NullReturnNull { + return fmt.Errorf("python runtime: unsupported NULL policy %q", invocation.NullPolicy) + } + if invocation.ABIContract == "" { + invocation.ABIContract = udf.PythonABIContract + } + if invocation.AdapterVersion == "" { + invocation.AdapterVersion = udf.PythonAdapterVersion + } + if invocation.SDKVersion == "" { + invocation.SDKVersion = udf.PythonSDKVersion + } + if invocation.ABIContract != udf.PythonABIContract || invocation.AdapterVersion != udf.PythonAdapterVersion { + return fmt.Errorf("python runtime: unsupported Python ABI contract %q/%q", invocation.ABIContract, invocation.AdapterVersion) + } + return invocation.Tuple.Validate() +} + +func (g *Gateway) action(ctx context.Context, kind string, control protocol.Control) error { + body, err := protocol.MarshalControl(control) + if err != nil { + return err + } + actionCtx, cancel := context.WithTimeout(ctx, g.cfg.RequestTimeout) + defer cancel() + stream, err := g.flight.DoAction(actionCtx, &flight.Action{Type: kind, Body: body}) + if err != nil { + return fmt.Errorf("python runtime: %s: %w", kind, err) + } + result, err := stream.Recv() + if err != nil { + return err + } + if result == nil { + return fmt.Errorf("python runtime: empty %s response", kind) + } + ack, err := protocol.UnmarshalControl(result.Body) + if err != nil { + return err + } + if ack.Status != statusOK { + return fmt.Errorf("python runtime: %s rejected: %s", kind, ack.Reason) + } + if _, err := stream.Recv(); err != io.EOF { + if err == nil { + return fmt.Errorf("python runtime: %s returned multiple results", kind) + } + return err + } + return nil +} + +func cloneMap(input map[string]string) map[string]string { + if len(input) == 0 { + return nil + } + out := make(map[string]string, len(input)) + for k, v := range input { + out[k] = v + } + return out +} diff --git a/pkg/udf/pythonruntime/pyserver/requirements.txt b/pkg/udf/pythonruntime/pyserver/requirements.txt new file mode 100644 index 0000000000000..d2a628aab1355 --- /dev/null +++ b/pkg/udf/pythonruntime/pyserver/requirements.txt @@ -0,0 +1,3 @@ +# The worker is a separate sandbox process. The runtime image must pin the +# complete environment lock used when the routine revision was published. +pyarrow==24.0.0 diff --git a/pkg/udf/pythonruntime/pyserver/test_worker.py b/pkg/udf/pythonruntime/pyserver/test_worker.py new file mode 100644 index 0000000000000..147808c6a7db6 --- /dev/null +++ b/pkg/udf/pythonruntime/pyserver/test_worker.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 + +import datetime +import importlib.util +import pathlib +import sys +import unittest + +import pyarrow as pa + + +WORKER_PATH = pathlib.Path(__file__).with_name("worker.py") +spec = importlib.util.spec_from_file_location("matrixone_python_worker", WORKER_PATH) +worker = importlib.util.module_from_spec(spec) +sys.modules[spec.name] = worker +spec.loader.exec_module(worker) + + +class WorkerContractTest(unittest.TestCase): + def test_go_python_fingerprint_vectors(self): + cases = [ + ({"type_id": worker.INT64, "offset_width": 32}, "482d3c55b8a9d662c2b41326b3ca55cbae65153e662c47c4919ba020d006262b"), + ({"type_id": worker.VARCHAR, "width": 65535, "charset": 3, "offset_width": 32}, "e35cb66adb4bce519a6f3ec9cfa8a33adad6202cbe678f5fecffdeb28d65b824"), + ({"type_id": worker.JSON, "offset_width": 32, "json_encoding": "canonical_text"}, "b156af5241a070ff80a287da19c46d1593dabee4fb5429f964452e711cd275eb"), + ({"type_id": worker.DATE, "offset_width": 32, "temporal_encoding": "sql_zero_struct"}, "8c401bde992eb173ca8aedca97dbd9f47453b7a860fae199ae0439307e858b4b"), + ] + for descriptor, expected in cases: + self.assertEqual(expected, worker._fingerprint(descriptor)) + + def test_metadata_is_owned_by_adapter(self): + descriptor = {"type_id": worker.VARCHAR, "width": 65535, "charset": 3, "offset_width": 32} + field = worker._field("result", descriptor) + self.assertEqual(field.metadata, { + worker.TypeMetadataKey: b'{"type_id":61,"width":65535,"charset":3,"offset_width":32}', + worker.TypeFingerprintKey: b"e35cb66adb4bce519a6f3ec9cfa8a33adad6202cbe678f5fecffdeb28d65b824", + }) + with_extra = pa.field("result", field.type, metadata={**field.metadata, b"untrusted": b"1"}) + with self.assertRaisesRegex(ValueError, "logical metadata"): + worker._validate_field(with_extra, "result", descriptor) + with self.assertRaisesRegex(ValueError, "field name"): + worker._validate_field(pa.field("other", field.type, metadata=field.metadata), "result", descriptor) + + def test_zero_temporal_is_distinct_from_null(self): + descriptor = {"type_id": worker.DATE, "offset_width": 32, "temporal_encoding": "sql_zero_struct"} + zero = worker.SqlDate(True, None) + array = worker._output_array([zero, None, worker.SqlDate(False, datetime.date(2024, 1, 2))], descriptor, 3) + self.assertTrue(array[0].is_valid) + self.assertFalse(array[1].is_valid) + self.assertTrue(array[2].is_valid) + self.assertEqual(True, array.field("is_zero")[0].as_py()) + self.assertEqual(datetime.date(1970, 1, 1), array.field("value")[0].as_py()) + + def test_zero_argument_vector_uses_context_rows(self): + descriptor = {"type_id": worker.INT64, "offset_width": 32} + output = pa.array([7, 7, 7], type=pa.int64()) + self.assertEqual(3, len(worker._output_array(output, descriptor, 3))) + with self.assertRaisesRegex(ValueError, "result length"): + worker._output_array(pa.array([7], type=pa.int64()), descriptor, 3) + + def test_terminal_admission_does_not_evict_live_tombstones(self): + old_records = worker.MAX_TERMINAL_RECORDS + old_bytes = worker.MAX_TERMINAL_BYTES + try: + worker.MAX_TERMINAL_RECORDS = 1 + worker.MAX_TERMINAL_BYTES = 1 << 20 + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + first = (1, "statement", "group", 1, "invocation", 1) + state = server._admit(first) + with server._lock: + server._active.pop(first) + server._active_bytes -= state.terminal_bytes + server._remember_terminal_locked(first, state) + with self.assertRaisesRegex(ValueError, "entries are full"): + server._admit((1, "statement", "group", 1, "second", 1)) + self.assertIn(first, server._terminal) + with server._lock: + server._terminal[first] = (0.0, state.terminal_bytes) + server._purge_terminal_locked(1.0) + second = server._admit((1, "statement", "group", 1, "second", 1)) + self.assertIsNotNone(second) + finally: + worker.MAX_TERMINAL_RECORDS = old_records + worker.MAX_TERMINAL_BYTES = old_bytes + + +if __name__ == "__main__": + unittest.main() diff --git a/pkg/udf/pythonruntime/pyserver/worker.py b/pkg/udf/pythonruntime/pyserver/worker.py new file mode 100644 index 0000000000000..ef12c8ea37f30 --- /dev/null +++ b/pkg/udf/pythonruntime/pyserver/worker.py @@ -0,0 +1,642 @@ +# Copyright 2026 Matrix Origin +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. + +"""Arrow Flight worker for the MatrixOne Python routine contract. + +The process is deliberately a small protocol endpoint. It does not install +packages, read SQL data, or interpret user supplied paths. Production +launchers must place it in the sandbox class selected by the routine policy. +""" + +from __future__ import annotations + +import argparse +import datetime as _datetime +import decimal as _decimal +import hashlib +import importlib +import inspect +import json +import logging +import threading +import time +import uuid as _uuid +from collections import OrderedDict +from dataclasses import dataclass +from typing import Any, Dict, Iterable, Optional + +import pyarrow as pa +import pyarrow.flight as flight + +PROTOCOL_VERSION = 1 +MAX_CONTROL_BYTES = 1 << 20 +MAX_TERMINAL_RECORDS = 10000 +MAX_TERMINAL_BYTES = 16 << 20 +TERMINAL_TTL_SECONDS = 300.0 +ACK_TIMEOUT_SECONDS = 60.0 +DEFAULT_MAX_BATCH_ROWS = 65536 + +BOOL = 10 +INT8, INT16, INT32, INT64 = 20, 21, 22, 23 +UINT8, UINT16, UINT32, UINT64 = 25, 26, 27, 28 +FLOAT32, FLOAT64 = 30, 31 +DECIMAL64, DECIMAL128 = 32, 33 +DATE, TIME, DATETIME, TIMESTAMP = 50, 51, 52, 53 +CHAR, VARCHAR, JSON, UUID = 60, 61, 62, 63 +BINARY, VARBINARY = 64, 65 +BLOB, TEXT = 70, 71 +VECF32, VECF64 = 224, 225 + +MODE_SCALAR = "SCALAR" +MODE_VECTOR = "VECTOR" +NULL_CALL = "CALLED_ON_NULL_INPUT" +NULL_RETURN = "RETURNS_NULL_ON_NULL_INPUT" +ABI_CONTRACT = "PYTHON_ARROW" +ADAPTER_VERSION = "2026-09" +SDK_VERSION = "1.0" + +log = logging.getLogger("matrixone.python.runtime") + + +@dataclass(frozen=True, slots=True) +class SqlDate: + is_zero: bool + value: Optional[_datetime.date] + + +@dataclass(frozen=True, slots=True) +class SqlDatetime: + is_zero: bool + value: Optional[_datetime.datetime] + + +@dataclass(frozen=True, slots=True) +class SqlTimestamp: + is_zero: bool + value: Optional[_datetime.datetime] + + +class _CallLogger: + __slots__ = () + + def info(self, message: str, *args: Any) -> None: + log.info("user: " + str(message), *args) + + def warning(self, message: str, *args: Any) -> None: + log.warning("user: " + str(message), *args) + + def error(self, message: str, *args: Any) -> None: + log.error("user: " + str(message), *args) + + +@dataclass(frozen=True, slots=True) +class ScalarContext: + sdk_version: str + logger: _CallLogger + statement: Any = None + + +@dataclass(frozen=True, slots=True) +class VectorContext: + sdk_version: str + logger: _CallLogger + statement: Any = None + num_rows: int = 0 + + +def _tuple_key(value: Dict[str, Any]) -> tuple: + required = ("account_id", "statement_id", "group_id", "group_epoch", "invocation_id", "lease_epoch") + if any(not value.get(k) for k in required): + raise ValueError("PROTOCOL: incomplete fencing tuple") + return tuple(value[k] for k in required) + + +def _decode_control(data: bytes) -> Dict[str, Any]: + if not data or len(data) > MAX_CONTROL_BYTES: + raise ValueError("PROTOCOL: invalid control size") + value = json.loads(bytes(data).decode("utf-8")) + if value.get("version") != PROTOCOL_VERSION or not value.get("kind"): + raise ValueError("PROTOCOL: unsupported control") + _tuple_key(value.get("tuple") or {}) + return value + + +def _encode_control(value: Dict[str, Any]) -> bytes: + value = dict(value) + value.setdefault("version", PROTOCOL_VERSION) + _tuple_key(value["tuple"]) + data = json.dumps(value, separators=(",", ":"), ensure_ascii=True).encode("utf-8") + if len(data) > MAX_CONTROL_BYTES: + raise ValueError("PROTOCOL: control is too large") + return data + + +def _canonical_descriptor(descriptor: Dict[str, Any]) -> bytes: + order = ("type_id", "width", "scale", "charset", "offset_width", "json_encoding", "temporal_encoding") + result = {} + for key in order: + value = descriptor.get(key) + if key == "type_id" or value not in (None, 0, ""): + result[key] = value + return json.dumps(result, separators=(",", ":"), ensure_ascii=True).encode("utf-8") + + +def _physical_fingerprint(descriptor: Dict[str, Any]) -> str: + type_id = int(descriptor["type_id"]) + primitive = { + BOOL: "@B", INT8: "@D", INT16: "@F", INT32: "@H", INT64: "@J", + UINT8: "@C", UINT16: "@E", UINT32: "@G", UINT64: "@I", + FLOAT32: "@L", FLOAT64: "@M", BINARY: "@O", BLOB: "@O", VARBINARY: "@O", + TIME: "@bu", + } + if type_id in primitive: + return primitive[type_id] + if type_id in (CHAR, VARCHAR, TEXT, JSON): + return "@d" if int(descriptor.get("offset_width", 32)) == 64 else "@N" + if type_id == UUID: + return "@P" + if type_id in (DECIMAL64, DECIMAL128): + precision = int(descriptor.get("width") or (18 if type_id == DECIMAL64 else 38)) + return f"@X[128,{precision},{int(descriptor.get('scale') or 0)}]" + if type_id == DATE: + return "@[{FNis_zero{@B};FNvalue{@Q};}" + if type_id == DATETIME: + return "@[{FNis_zero{@B};FNvalue{@Su0:};}" + if type_id == TIMESTAMP: + return "@[{FNis_zero{@B};FNvalue{@Su3:UTC};}" + if type_id == VECF32: + return f"@a[{int(descriptor.get('width') or 0)}]{{@L}}" + if type_id == VECF64: + return f"@a[{int(descriptor.get('width') or 0)}]{{@M}}" + raise ValueError(f"TYPE_CONTRACT: unsupported type id {type_id}") + + +def _fingerprint(descriptor: Dict[str, Any]) -> str: + data = b"matrixone-python-udf-type\x00" + _canonical_descriptor(descriptor) + b"\x00" + _physical_fingerprint(descriptor).encode() + return hashlib.sha256(data).hexdigest() + + +def _arrow_type(descriptor: Dict[str, Any]) -> pa.DataType: + type_id = int(descriptor["type_id"]) + simple = { + BOOL: pa.bool_, INT8: pa.int8, INT16: pa.int16, INT32: pa.int32, INT64: pa.int64, + UINT8: pa.uint8, UINT16: pa.uint16, UINT32: pa.uint32, UINT64: pa.uint64, + FLOAT32: pa.float32, FLOAT64: pa.float64, + } + if type_id in simple: + return simple[type_id]() + if type_id in (DECIMAL64, DECIMAL128): + precision = int(descriptor.get("width") or (18 if type_id == DECIMAL64 else 38)) + return pa.decimal128(precision, int(descriptor.get("scale") or 0)) + if type_id in (CHAR, VARCHAR, TEXT, JSON): + return pa.large_string() if int(descriptor.get("offset_width", 32)) == 64 else pa.string() + if type_id in (BINARY, VARBINARY, BLOB): + return pa.large_binary() if int(descriptor.get("offset_width", 32)) == 64 else pa.binary() + if type_id == UUID: + return pa.binary(16) + if type_id == TIME: + return pa.duration("us") + if type_id in (VECF32, VECF64): + width = int(descriptor.get("width") or 0) + if width <= 0: + raise ValueError("TYPE_CONTRACT: vector dimension must be positive") + return pa.list_(pa.float32() if type_id == VECF32 else pa.float64(), width) + if type_id == DATE: + child = pa.date32() + elif type_id == DATETIME: + child = pa.timestamp("us") + elif type_id == TIMESTAMP: + child = pa.timestamp("us", tz="UTC") + else: + raise ValueError(f"TYPE_CONTRACT: unsupported type id {type_id}") + return pa.struct([pa.field("is_zero", pa.bool_(), nullable=False), pa.field("value", child, nullable=False)]) + + +def _field(name: str, descriptor: Dict[str, Any]) -> pa.Field: + metadata = { + TypeMetadataKey: _canonical_descriptor(descriptor), + TypeFingerprintKey: _fingerprint(descriptor).encode("ascii"), + } + return pa.field(name, _arrow_type(descriptor), nullable=True, metadata=metadata) + + +TypeMetadataKey = b"mo.udf.type" +TypeFingerprintKey = b"mo.udf.type_fingerprint" + + +def _validate_field(field: pa.Field, name: str, descriptor: Dict[str, Any]) -> None: + expected = _field(name, descriptor) + if field.name != name: + raise ValueError(f"TYPE_CONTRACT: Arrow field name {field.name!r} does not match {name!r}") + if field.type != expected.type: + raise ValueError(f"TYPE_CONTRACT: Arrow type {field.type} does not match {expected.type}") + if field.metadata != expected.metadata: + raise ValueError("TYPE_CONTRACT: Arrow logical metadata does not match the frozen descriptor") + + +def _validate_schema(schema: pa.Schema, descriptors: Iterable[Dict[str, Any]]) -> None: + descriptors = list(descriptors) + if len(schema) != len(descriptors): + raise ValueError("TYPE_CONTRACT: input column count does not match the routine signature") + for index, descriptor in enumerate(descriptors): + _validate_field(schema.field(index), f"arg_{index}", descriptor) + + +def _load_handler(source: str, handler: str): + namespace: Dict[str, Any] = {"__name__": "__matrixone_routine__"} + exec(compile(source, "", "exec"), namespace, namespace) + if ":" in handler: + module_name, function_name = handler.split(":", 1) + function = namespace.get(function_name) + if function is None and module_name: + function = getattr(importlib.import_module(module_name), function_name, None) + else: + function = namespace.get(handler) + if not callable(function) or inspect.iscoroutinefunction(function): + raise ValueError("USER_CODE: handler must be a synchronous callable") + return function + + +def _scalar_input(array: pa.Array, row: int, descriptor: Dict[str, Any]): + value = array[row].as_py() + if value is None: + return None + type_id = int(descriptor["type_id"]) + if type_id in (VECF32, VECF64): + # A scalar vector is exposed as read-only bytes. Consumers can use + # memoryview.cast("f"/"d") without receiving a mutable Arrow buffer. + import struct + values = value + fmt = "f" if type_id == VECF32 else "d" + return memoryview(struct.pack("<" + fmt * len(values), *values)) + if type_id in (DATE, DATETIME, TIMESTAMP): + zero = bool(value["is_zero"]) + child = value["value"] + if type_id == DATE: + return SqlDate(zero, None if zero else child) + if type_id == DATETIME: + return SqlDatetime(zero, None if zero else child) + return SqlTimestamp(zero, None if zero else child) + if type_id == UUID: + return _uuid.UUID(bytes=bytes(value)) + return value + + +def _check_json(value: str) -> str: + if not isinstance(value, str): + raise ValueError("TYPE_CONTRACT: JSON result must be canonical text") + try: + parsed = json.loads(value) + except Exception as exc: + raise ValueError("TYPE_CONTRACT: invalid JSON result") from exc + canonical = json.dumps(parsed, ensure_ascii=False, separators=(",", ":")) + if canonical != value: + raise ValueError("TYPE_CONTRACT: JSON result is not canonical text") + return value + + +def _check_scalar(value: Any, descriptor: Dict[str, Any]): + if value is None: + return None + type_id = int(descriptor["type_id"]) + if type_id == BOOL and type(value) is not bool: raise ValueError("TYPE_CONTRACT: expected bool") + if type_id in (INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64) and (type(value) is not int): raise ValueError("TYPE_CONTRACT: expected integer") + if type_id in (FLOAT32, FLOAT64) and type(value) is not float: raise ValueError("TYPE_CONTRACT: expected float") + if type_id in (CHAR, VARCHAR, TEXT) and type(value) is not str: raise ValueError("TYPE_CONTRACT: expected string") + if type_id == JSON: return _check_json(value) + if type_id in (BINARY, VARBINARY, BLOB) and type(value) is not bytes: raise ValueError("TYPE_CONTRACT: expected bytes") + if type_id == UUID: + if not isinstance(value, _uuid.UUID): raise ValueError("TYPE_CONTRACT: expected uuid.UUID") + return value.bytes + if type_id == TIME and not isinstance(value, _datetime.timedelta): raise ValueError("TYPE_CONTRACT: expected datetime.timedelta") + if type_id == DATE: + if not isinstance(value, SqlDate) or (value.is_zero and value.value is not None) or (not value.is_zero and type(value.value) is not _datetime.date): raise ValueError("TYPE_CONTRACT: invalid SqlDate") + return value + if type_id == DATETIME: + if not isinstance(value, SqlDatetime) or (value.is_zero and value.value is not None) or (not value.is_zero and (not isinstance(value.value, _datetime.datetime) or value.value.tzinfo is not None)): raise ValueError("TYPE_CONTRACT: invalid SqlDatetime") + return value + if type_id == TIMESTAMP: + if not isinstance(value, SqlTimestamp) or (value.is_zero and value.value is not None) or (not value.is_zero and (not isinstance(value.value, _datetime.datetime) or value.value.tzinfo is None or value.value.utcoffset() != _datetime.timedelta(0))): raise ValueError("TYPE_CONTRACT: invalid SqlTimestamp") + if not value.is_zero and value.value.tzinfo is not _datetime.timezone.utc: + return SqlTimestamp(False, value.value.astimezone(_datetime.timezone.utc)) + return value + if type_id in (VECF32, VECF64): + if not isinstance(value, memoryview) or not value.readonly: + raise ValueError("TYPE_CONTRACT: vector scalar result must be a read-only memoryview") + width = int(descriptor.get("width") or 0) + fmt = "f" if type_id == VECF32 else "d" + try: + values = list(value.cast(fmt)) + except (TypeError, ValueError) as exc: + raise ValueError("TYPE_CONTRACT: invalid vector memoryview") from exc + if len(values) != width: + raise ValueError("TYPE_CONTRACT: vector dimension mismatch") + return values + if type_id in (DECIMAL64, DECIMAL128): + if not isinstance(value, _decimal.Decimal): raise ValueError("TYPE_CONTRACT: expected decimal.Decimal") + scale = int(descriptor.get("scale") or 0) + if -value.as_tuple().exponent != scale: raise ValueError("TYPE_CONTRACT: decimal scale mismatch") + return value + + +def _temporal_array(values: list, descriptor: Dict[str, Any]) -> pa.Array: + type_id = int(descriptor["type_id"]) + valid = [] + zeroes = [] + child_values = [] + for value in values: + if value is None: + valid.append(False); zeroes.append(False); child_values.append(0); continue + value = _check_scalar(value, descriptor) + valid.append(True); zeroes.append(bool(value.is_zero)); child_values.append(0 if value.is_zero else value.value) + if type_id == DATE: child_type = pa.date32() + elif type_id == DATETIME: child_type = pa.timestamp("us") + else: child_type = pa.timestamp("us", tz="UTC") + children = [pa.array(zeroes, type=pa.bool_()), pa.array(child_values, type=child_type)] + return pa.StructArray.from_arrays(children, names=["is_zero", "value"], mask=pa.array([not item for item in valid])) + + +def _output_array(values: Any, descriptor: Dict[str, Any], rows: int) -> pa.Array: + if isinstance(values, pa.ChunkedArray): + values = values.combine_chunks() + if isinstance(values, pa.Array): + if len(values) != rows: raise ValueError("TYPE_CONTRACT: result length does not match input rows") + if values.type != _arrow_type(descriptor): raise ValueError("TYPE_CONTRACT: result Arrow type does not match the return descriptor") + _validate_array_values(values, descriptor) + return values + if not isinstance(values, (list, tuple)): + raise ValueError("TYPE_CONTRACT: VECTOR handler must return an Arrow Array or ChunkedArray") + if len(values) != rows: raise ValueError("TYPE_CONTRACT: result length does not match input rows") + type_id = int(descriptor["type_id"]) + if type_id in (DATE, DATETIME, TIMESTAMP): return _temporal_array(list(values), descriptor) + if type_id in (VECF32, VECF64): + width = int(descriptor.get("width") or 0) + checked = [] + for value in values: + if value is None: + checked.append(None) + continue + checked.append(_check_scalar(value, descriptor)) + try: + child_type = pa.float32() if type_id == VECF32 else pa.float64() + flat = [item for row in checked if row is not None for item in row] + child = pa.array(flat, type=child_type) + mask = pa.array([row is None for row in checked]) + return pa.FixedSizeListArray.from_arrays(child, width, mask=mask) + except (TypeError, ValueError, pa.ArrowException) as exc: + raise ValueError("TYPE_CONTRACT: vector result is outside the declared SQL domain") from exc + checked = [_check_scalar(value, descriptor) for value in values] + if type_id == UUID: checked = [None if value is None else value.bytes for value in checked] + try: return pa.array(checked, type=_arrow_type(descriptor)) + except (TypeError, ValueError, pa.ArrowException) as exc: raise ValueError("TYPE_CONTRACT: result value is outside the declared SQL domain") from exc + + +def _validate_array_values(array: pa.Array, descriptor: Dict[str, Any]) -> None: + type_id = int(descriptor["type_id"]) + if type_id == JSON: + for index in range(len(array)): + if not array.is_null(index): _check_json(array[index].as_py()) + elif type_id in (DATE, DATETIME, TIMESTAMP): + struct = array + for index in range(len(struct)): + if struct.is_null(index): continue + is_zero = bool(struct.field("is_zero")[index].as_py()) + value = struct.field("value")[index].as_py() + if value is None: raise ValueError("TYPE_CONTRACT: temporal child is null") + if is_zero and ((type_id == DATE and value != _datetime.date(1970, 1, 1)) or (type_id == DATETIME and value != _datetime.datetime(1970, 1, 1)) or (type_id == TIMESTAMP and value != _datetime.datetime(1970, 1, 1, tzinfo=_datetime.timezone.utc))): + raise ValueError("TYPE_CONTRACT: temporal zero placeholder is invalid") + + +class _InvocationState: + def __init__(self, tuple_value: Dict[str, Any], terminal_bytes: int): + self.tuple = tuple_value + self.terminal_bytes = terminal_bytes + self.condition = threading.Condition() + self.last_result = 0 + self.acked_result = 0 + self.finish_id: Optional[str] = None + self.finish_acked = False + + def ack_result(self, sequence: int) -> None: + with self.condition: + if sequence < self.acked_result or sequence > self.last_result: + raise ValueError("PROTOCOL: result ACK is outside the received range") + self.acked_result = sequence + self.condition.notify_all() + + def wait_result_ack(self, sequence: int) -> None: + deadline = time.monotonic() + ACK_TIMEOUT_SECONDS + with self.condition: + while self.acked_result < sequence: + remaining = deadline - time.monotonic() + if remaining <= 0: raise TimeoutError("DEADLINE_EXCEEDED: result ACK timeout") + self.condition.wait(remaining) + + def ack_finish(self, finish_id: str) -> None: + with self.condition: + if not self.finish_id or finish_id != self.finish_id: raise ValueError("PROTOCOL: invalid finish id") + self.finish_acked = True + self.condition.notify_all() + + def wait_finish_ack(self) -> None: + deadline = time.monotonic() + ACK_TIMEOUT_SECONDS + with self.condition: + while not self.finish_acked: + remaining = deadline - time.monotonic() + if remaining <= 0: raise TimeoutError("DEADLINE_EXCEEDED: Finish ACK timeout") + self.condition.wait(remaining) + + +class RoutineFlightServer(flight.FlightServerBase): + def __init__(self, location: str): + super().__init__(location) + self._lock = threading.RLock() + self._active: Dict[tuple, _InvocationState] = {} + self._terminal: OrderedDict[tuple, tuple[float, int]] = OrderedDict() + self._terminal_bytes = 0 + self._active_bytes = 0 + + @staticmethod + def _entry_bytes(key: tuple) -> int: + # The admission estimate is deliberately conservative. The tuple is + # already bounded by MAX_CONTROL_BYTES, and its serialized size is + # stable for the lifetime of the fence. + encoded = json.dumps(key, separators=(",", ":"), ensure_ascii=True).encode("utf-8") + return len(encoded) + 128 + + def _purge_terminal_locked(self, now: float) -> None: + expired = [key for key, (deadline, _) in self._terminal.items() if deadline <= now] + for key in expired: + _, size = self._terminal.pop(key) + self._terminal_bytes -= size + + def _admit(self, key: tuple) -> _InvocationState: + size = self._entry_bytes(key) + with self._lock: + self._purge_terminal_locked(time.monotonic()) + if key in self._terminal: + raise ValueError("PROTOCOL: invocation fence is terminal") + if len(self._active) + len(self._terminal) >= MAX_TERMINAL_RECORDS: + raise ValueError("RESOURCE_EXHAUSTED: terminal ledger entries are full") + if self._active_bytes + self._terminal_bytes + size > MAX_TERMINAL_BYTES: + raise ValueError("RESOURCE_EXHAUSTED: terminal ledger bytes are full") + state = _InvocationState({}, size) + self._active[key] = state + self._active_bytes += size + return state + + def _remember_terminal_locked(self, key: tuple, state: _InvocationState) -> None: + deadline = time.monotonic() + TERMINAL_TTL_SECONDS + self._terminal[key] = (deadline, state.terminal_bytes) + self._terminal.move_to_end(key) + self._terminal_bytes += state.terminal_bytes + + def do_action(self, context, action): + control = _decode_control(action.body) + key = _tuple_key(control["tuple"]) + with self._lock: + self._purge_terminal_locked(time.monotonic()) + state = self._active.get(key) + terminal = key in self._terminal + if state is None: + if terminal: + yield _encode_control({"kind": "Ack", "tuple": control["tuple"], "status": "OK"}) + return + raise ValueError("PROTOCOL: unknown invocation") + if action.type == "AcknowledgeResults": + state.ack_result(int(control.get("ack_sequence", 0))) + elif action.type == "AcknowledgeFinish": + state.ack_finish(str(control.get("finish_id", ""))) + else: + raise ValueError("PROTOCOL: unknown action") + yield _encode_control({"kind": "Ack", "tuple": control["tuple"], "status": "OK", "ack_sequence": control.get("ack_sequence", 0)}) + + def do_exchange(self, context, descriptor, reader, writer): + state = None + key = None + writer_started = False + try: + command = getattr(descriptor, "command", None) + if command is None: + raise ValueError("PROTOCOL: exchange is missing the invocation descriptor") + open_control = _decode_control(command) + if open_control["kind"] != "OpenInvocation": raise ValueError("PROTOCOL: first message must open an invocation") + key = _tuple_key(open_control["tuple"]) + payload = open_control.get("payload") or {} + if isinstance(payload, str): + payload = json.loads(payload) + args = list(payload.get("args", [])); result_descriptor = payload["return"] + mode = payload.get("mode", MODE_SCALAR); null_policy = payload.get("null_policy", NULL_CALL) + abi_contract = payload.get("abi_contract", ABI_CONTRACT) + adapter_version = payload.get("adapter_version", ADAPTER_VERSION) + sdk_version = payload.get("sdk_version", SDK_VERSION) + max_batch_rows = int(payload.get("max_batch_rows", DEFAULT_MAX_BATCH_ROWS)) + if mode not in (MODE_SCALAR, MODE_VECTOR) or null_policy not in (NULL_CALL, NULL_RETURN): raise ValueError("PROTOCOL: unsupported call mode or NULL policy") + if abi_contract != ABI_CONTRACT or adapter_version != ADAPTER_VERSION: raise ValueError("PROTOCOL: unsupported Python ABI contract") + if max_batch_rows <= 0: raise ValueError("PROTOCOL: invalid max batch rows") + state = self._admit(key) + state.tuple = open_control["tuple"] + handler = _load_handler(payload["source"], payload["handler"]) + schema = None + result_field = _field("result", result_descriptor) + result_schema = pa.schema([result_field]) + writer.begin(result_schema) + writer_started = True + writer.write_metadata(_encode_control({"kind": "ResultSchema", "tuple": open_control["tuple"]})) + ended = False + while True: + try: + chunk = reader.read_chunk() + except StopIteration: + break + if chunk.data is not None: + if schema is None: + schema = reader.schema + _validate_schema(schema, args) + control = _decode_control(chunk.app_metadata) + if control["kind"] != "InputBatch": raise ValueError("PROTOCOL: data batch is missing InputBatch") + sequence = int(control.get("sequence", 0)) + if sequence != state.last_result + 1: raise ValueError("PROTOCOL: input sequence is not contiguous") + batch = chunk.data + if batch.num_rows <= 0: raise ValueError("PROTOCOL: empty input batch") + if batch.num_rows > max_batch_rows: raise ValueError("RESOURCE_EXHAUSTED: input batch has too many rows") + if mode == MODE_VECTOR: + call_context = VectorContext(sdk_version, _CallLogger(), None, batch.num_rows) + try: + output = handler(call_context, *[batch.column(index) for index in range(batch.num_columns)]) + except Exception as exc: + raise ValueError("USER_CODE: handler failed") from exc + if not isinstance(output, (pa.Array, pa.ChunkedArray)): + raise ValueError("TYPE_CONTRACT: VECTOR handler must return an Arrow Array or ChunkedArray") + else: + call_context = ScalarContext(sdk_version, _CallLogger(), None) + values = [] + for row in range(batch.num_rows): + params = [_scalar_input(batch.column(index), row, args[index]) for index in range(batch.num_columns)] + if null_policy == NULL_RETURN and any(value is None for value in params): values.append(None) + else: + try: + values.append(handler(call_context, *params)) + except Exception as exc: + raise ValueError("USER_CODE: handler failed") from exc + output = values + output_array = _output_array(output, result_descriptor, batch.num_rows) + output_batch = pa.RecordBatch.from_arrays([output_array], schema=result_schema) + state.last_result = sequence + writer.write_metadata(_encode_control({"kind": "InputConsumed", "tuple": open_control["tuple"], "sequence": sequence})) + writer.write_with_metadata(output_batch, _encode_control({"kind": "ResultBatch", "tuple": open_control["tuple"], "sequence": sequence})) + state.wait_result_ack(sequence) + elif chunk.app_metadata: + control = _decode_control(chunk.app_metadata) + if control["kind"] == "EndInput": + if ended or int(control.get("last_sequence", -1)) != state.last_result: raise ValueError("PROTOCOL: invalid EndInput") + ended = True + elif control["kind"] != "OpenInvocation": + raise ValueError("PROTOCOL: unexpected control without Arrow data") + if not ended: raise ValueError("PROTOCOL: input stream ended before EndInput") + if state.acked_result != state.last_result: raise ValueError("PROTOCOL: result is not acknowledged") + state.finish_id = _uuid.uuid4().hex + writer.write_metadata(_encode_control({"kind": "Finish", "tuple": open_control["tuple"], "status": "OK", "finish_id": state.finish_id, "last_sequence": state.last_result})) + state.wait_finish_ack() + except Exception as exc: + if writer_started and key is not None: + try: + writer.write_metadata(_encode_control({"kind": "Error", "tuple": open_control["tuple"], "status": "ERROR", "reason": _safe_error(exc)})) + except Exception: + pass + raise + finally: + if key is not None: + with self._lock: + current = self._active.pop(key, None) + if current is not None: + self._active_bytes -= current.terminal_bytes + # A started invocation is terminal even when the worker + # reports an error. Retaining the fence prevents a late + # retry from running user code a second time; the caller's + # error path remains responsible for reporting failure. + self._remember_terminal_locked(key, current) + + +def _safe_error(exc: Exception) -> str: + message = str(exc) + categories = ("PROTOCOL:", "TYPE_CONTRACT:", "USER_CODE:", "RESOURCE_EXHAUSTED:", "DEADLINE_EXCEEDED:") + if not message.startswith(categories): + return "USER_CODE: handler or runtime failed" + return message[:512] + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--address", required=True) + args = parser.parse_args() + logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(levelname)s %(message)s") + address = args.address if "://" in args.address else "grpc://" + args.address + server = RoutineFlightServer(address) + server.serve() + + +if __name__ == "__main__": + main() diff --git a/pkg/udf/pythonruntime/supervisor.go b/pkg/udf/pythonruntime/supervisor.go new file mode 100644 index 0000000000000..90c171368a75a --- /dev/null +++ b/pkg/udf/pythonruntime/supervisor.go @@ -0,0 +1,113 @@ +// Copyright 2026 Matrix Origin +// +// 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 + +package pythonruntime + +import ( + "errors" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "strconv" + "sync" + "sync/atomic" + + "github.com/matrixorigin/matrixone/pkg/logutil" +) + +type Supervisor struct { + cfg Config + mu sync.Mutex + cmd *exec.Cmd + log io.WriteCloser +} + +var supervisorNumber atomic.Int32 + +func NewSupervisor(cfg Config) (*Supervisor, error) { + if err := cfg.Validate(); err != nil { + return nil, err + } + return &Supervisor{cfg: cfg}, nil +} + +func (s *Supervisor) Start() error { + s.mu.Lock() + defer s.mu.Unlock() + if s.cmd != nil { + return nil + } + workerPath := s.cfg.Path + if !filepath.IsAbs(workerPath) { + cwd, err := os.Getwd() + if err != nil { + return err + } + workerPath = filepath.Join(cwd, workerPath) + } + workerPath = filepath.Join(workerPath, "worker.py") + if _, err := os.Stat(workerPath); err != nil { + return err + } + executable := s.cfg.Python + if executable == "" { + executable = "python" + } + exePath, err := os.Executable() + if err != nil { + return err + } + logPath := filepath.Join(filepath.Dir(exePath), "python-runtime-"+strconv.Itoa(int(supervisorNumber.Add(1))+0)+".log") + logFile, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) + if err != nil { + return err + } + cmd := exec.Command(executable, "-u", workerPath, "--address="+s.cfg.Address) + cmd.Stdout, cmd.Stderr = logFile, logFile + if err := cmd.Start(); err != nil { + _ = logFile.Close() + return err + } + s.cmd, s.log = cmd, logFile + go s.wait(cmd, logFile) + logutil.Infof("started Python runtime worker: %s", cmd.String()) + return nil +} + +func (s *Supervisor) wait(cmd *exec.Cmd, log io.WriteCloser) { + err := cmd.Wait() + _ = log.Close() + s.mu.Lock() + if s.cmd == cmd { + s.cmd, s.log = nil, nil + } + s.mu.Unlock() + if err != nil { + logutil.Errorf("Python runtime worker exited: %v", err) + } +} + +func (s *Supervisor) Close() error { + s.mu.Lock() + cmd, log := s.cmd, s.log + s.cmd, s.log = nil, nil + s.mu.Unlock() + if cmd == nil { + if log != nil { + return log.Close() + } + return nil + } + if err := cmd.Process.Kill(); err != nil && !errors.Is(err, os.ErrProcessDone) { + return fmt.Errorf("stop Python runtime worker: %w", err) + } + if log != nil { + return log.Close() + } + return nil +} diff --git a/pkg/udf/pythonservice/cfg.go b/pkg/udf/pythonservice/cfg.go deleted file mode 100644 index 30df376f7c0ce..0000000000000 --- a/pkg/udf/pythonservice/cfg.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2023 Matrix Origin -// -// 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 pythonservice - -import ( - "context" - "github.com/matrixorigin/matrixone/pkg/common/moerr" -) - -type Config struct { - UUID string `toml:"uuid"` - Address string `toml:"address"` - // Path code path - Path string `toml:"path"` - // Python is the python executable path, optional, default to 'python' - Python string `toml:"python"` -} - -func (c *Config) Validate() error { - if c.Address == "" { - return moerr.NewInternalError(context.Background(), "missing python udf server address") - } - if c.Path == "" { - return moerr.NewInternalError(context.Background(), "missing python udf server path") - } - return nil -} - -type ClientConfig struct { - ServerAddress string `toml:"server-address"` -} - -func (c *ClientConfig) Validate() error { - if c.ServerAddress == "" { - return moerr.NewInternalError(context.Background(), "missing python udf server address") - } - return nil -} diff --git a/pkg/udf/pythonservice/client.go b/pkg/udf/pythonservice/client.go deleted file mode 100644 index 0abaae0e42bc6..0000000000000 --- a/pkg/udf/pythonservice/client.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2023 Matrix Origin -// -// 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 pythonservice - -import ( - "context" - "io" - "math" - "sync" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - - "github.com/matrixorigin/matrixone/pkg/common/moerr" - "github.com/matrixorigin/matrixone/pkg/udf" -) - -type Client struct { - cfg ClientConfig - sc udf.ServiceClient - mutex sync.Mutex -} - -func NewClient(cfg ClientConfig) (*Client, error) { - err := cfg.Validate() - if err != nil { - return nil, err - } - return &Client{cfg: cfg}, nil -} - -func (c *Client) init() error { - if c.sc == nil { - err := func() error { - c.mutex.Lock() - defer c.mutex.Unlock() - if c.sc == nil { - conn, err := grpc.NewClient(c.cfg.ServerAddress, - grpc.WithTransportCredentials(insecure.NewCredentials()), - grpc.WithDefaultCallOptions( - grpc.MaxCallSendMsgSize(math.MaxInt32), - grpc.MaxCallRecvMsgSize(math.MaxInt32), - ), - ) - if err != nil { - return err - } - c.sc = udf.NewServiceClient(conn) - } - return nil - }() - if err != nil { - return err - } - } - return nil -} - -func (c *Client) Run(ctx context.Context, request *udf.Request, pkgReader udf.PkgReader) (*udf.Response, error) { - if request.Udf.Language != udf.LanguagePython { - return nil, moerr.NewInvalidArg(ctx, "udf language", request.Udf.Language) - } - - if request.Type != udf.RequestType_DataRequest { - return nil, moerr.NewInvalidInput(ctx, "type of the first udf request must be 'DataRequest'") - } - - err := c.init() - if err != nil { - return nil, err - } - - stream, err := c.sc.Run(ctx) - if err != nil { - return nil, err - } - defer stream.CloseSend() - err = stream.Send(request) - if err != nil { - return nil, err - } - response, err := stream.Recv() - if err != nil { - return nil, err - } - switch response.Type { - case udf.ResponseType_DataResponse: - return response, nil - case udf.ResponseType_PkgRequest: - var reader io.ReadCloser - reader, err = pkgReader.Get(ctx, request.Udf.Body) - if reader != nil { - defer reader.Close() - } - if err != nil { - return nil, err - } - - pkgRequest := &udf.Request{ - Udf: request.Udf, - Type: udf.RequestType_PkgResponse, - Context: request.Context, - } - for { - pkg := &udf.Package{} - buffer := make([]byte, 5*1024*1024) - var offset int - for { - var n int - n, err = reader.Read(buffer[offset:]) - if err != nil { - if err == io.EOF { - pkg.Last = true - } else { - return nil, err - } - } - offset += n - - if pkg.Last || len(buffer) == offset { - pkg.Data = buffer[:offset] - break - } - } - - pkgRequest.Udf.ImportPkg = pkg - err = stream.Send(pkgRequest) - if err != nil { - return nil, err - } - - response, err = stream.Recv() - if err != nil { - return nil, err - } - - if pkg.Last { - return response, nil - } - } - default: - return nil, moerr.NewInternalError(ctx, "error udf response type") - } -} - -func (c *Client) Language() string { - return udf.LanguagePython -} diff --git a/pkg/udf/pythonservice/demo/README.md b/pkg/udf/pythonservice/demo/README.md deleted file mode 100644 index c68dce2404808..0000000000000 --- a/pkg/udf/pythonservice/demo/README.md +++ /dev/null @@ -1,295 +0,0 @@ -# MO Python UDF Demo - -This document briefly describes the use of python UDFs in MO, showing the flexibility and convenience of python UDFs. - -## Standalone Deployment - -1. Before the deployment, we need to make sure we have [python3](https://www.python.org/downloads/) locally and install the grpc package in python: - -``` -pip install protobuf -pip install grpcio -``` - -2. Follow the steps in [Getting Started](https://docs.matrixorigin.cn/en/1.0.0-rc1/MatrixOne/Get-Started/install-standalone-matrixone/) to complete the installation, and modify the configuration of mo_ctl by running the following command before starting MO: - -```shell -mo_ctl set_conf MO_CONF_FILE="${MO_PATH}/matrixone/etc/launch-with-python-udf-server/launch.toml" -``` - -3. Launch and connect to MO. - -## "Hello world" - -Let's start with a simple function: a python UDF that adds two numbers together. - -Input the following SQL in the client to create the function: - -```sql -create or replace function py_add(a int, b int) returns int language python as -$$ -def add(a, b): - return a + b -$$ -handler 'add'; -``` - -> Note: currently, matrixone does not perform syntax checking on the python script in UDF body. - -This SQL defines a function called py_add that takes two parameters of type `int` and returns the sum of the two parameters. Python code comes after `as`. `handler` represents the name of the python function that will be called. - -Now we can use the function: - -```sql -select py_add(1,2); -``` - -Output: - -``` -+--------------+ -| py_add(1, 2) | -+--------------+ -| 3 | -+--------------+ -``` - -We can remove the function when we no longer need it: - -```sql -drop function py_add(int, int); -``` - -We now have a basic understanding of how to use python UDFs. - -## Advancement - -In this section, we'll look at some more advanced uses of python UDFs. - -### Imported Python UDF - -In the previous section, the py_add function is written directly in SQL, and the python code is written after the keyword `as`. We call this form **embedded UDF**. However, if the function logic is very complex, writing it directly in SQL is not a good choice. It bloats the SQL statements and makes the code less maintainable. In this case, we can choose another way to create python UDFs: importing python code from an external file, known as **imported UDF**. There are two types of files that are supported: (1) a single python file, and (2) the wheel package. Let's continue with the example of the py_add function from the previous section, and write the python code to a file. - -The code for ./add func.py is as follows: - -```python -def add(a, b): - return a + b -``` - -Input the following SQL in the client to create the function(if you connect to matrixone via `mysql` cli, `--local-infile` flag is required to allow the cli reading local python files): - -```sql -create or replace function py_add(a int, b int) returns int language python import -'./add_func.py' -handler 'add'; -``` - -We use the keyword `import` to import the flie add_func.py from the current working directory. - -Call the function: - -```sql -select py_add(1,2); -``` - -We still get the same output as in the previous section: - -``` -+--------------+ -| py_add(1, 2) | -+--------------+ -| 3 | -+--------------+ -``` - -Importing a wheel package and a single python file share the same syntax, so we won't go into detail here. In the final example, we will create a python UDF by importing a wheel package. - -### Vector Option - -In some scenarios, we may want a python function to receive multiple tuples at once to improve the efficiency. For example, in model inference, we typically process data in batches, where each batch is a vector of tuples. The vector option is designed to handle this situation. We'll continue to use the py_add function as an example to demonstrate the usage of the vector option. - -Input the following SQL in the client to create the function: - -```sql -create or replace function py_add(a int, b int) returns int language python as -$$ -def add(a, b): # a, b are list - return [a[i] + b[i] for i in range(len(a))] -add.vector = True -$$ -handler 'add'; -``` - -We use `add.vector = True` to indicate that the python function add should receive two integer lists (vectors) as input, rather than individual integer values. - -Call the function: - -```sql -select py_add(1,2); -``` - -We still get the same output as in the previous section: - -``` -+--------------+ -| py_add(1, 2) | -+--------------+ -| 3 | -+--------------+ -``` - -With the vector option, we have the freedom to choose how the function processes its input, whether it's one tuple at a time or multiple tuples at once. - -### Type Mapping - -The correspondence between MO types and python types is as follows: - -| MO Types | Python Types | -| -------------------------------------------------------- | --------------------------- | -| bool | bool | -| int8, int16, int32, int64, uint8, uint16, uint32, uint64 | int | -| float32, float64 | float | -| char, varchar, text, uuid | str | -| json | str, int, float, list, dict | -| time | datetime.timedelta | -| date | datetime.date | -| datetime, timestamp | datetime.datetime | -| decimal64, decimal128 | decimal.Decimal | -| binary, varbinary, blob | bytes | - -### Function Overloading and Matching - -Overloading is not supported in MO UDF yet, all function names must be unique across an MO cluster. - -## Example: Credit Card Fraud Detection - -In this section, we use the example "Credit card fraud detection" to illustrate how python UDFs can be used in a machine learning inference pipeline. (Detailed code in [github](https://github.com/matrixorigin/matrixone/tree/main/pkg/udf/pythonservice/demo)) - -We need to ensure that the local python environment has numpy and scikit-learn installed. - -### Background - -It is important that credit card companies are able to recognize fraudulent credit card transactions so that customers are not charged for items that they did not purchase. (Details in kaggle [Credit Card Fraud Detection](https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud)) - -### Data - -The dataset contains transactions made by credit cards in September 2013 by European cardholders. The data format is as follows: - -| Column Name | Type | Explanation | -| ----------- | ------ | ------------------------------------------------------------ | -| Time | int | Number of seconds elapsed between this transaction and the first transaction in the dataset | -| V1 ~ V28 | double | May be result of a PCA Dimensionality reduction to protect user identities and sensitive features | -| Amount | double | Transaction amount | -| Class | int | 1 for fraudulent transactions, 0 otherwise | - -We split the data into training, validation, and test sets in an 8:1:1 ratio. Since the training process is not the focus. we won't go into much detail here. We treat the test set as new data appearing in the production process, and store it in MO. The DDL is as follows: - -```sql -create table credit_card_transaction( - id int auto_increment primary key, - time int, - features json, -- store V1 ~ V28, using json list - amount decimal(20,2) -); -``` - -### Inference - -After the model is trained, we can write the inference function. The core code is as follows: - -```python -import decimal -import os -from typing import List - -import joblib -import numpy as np - -# model path -model_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'model_with_scaler') - - -def detect(featuresList: List[List[int]], amountList: List[decimal.Decimal]) -> List[bool]: - # load model - model_with_scaler = joblib.load(model_path) - - columns_features = np.array(featuresList) - column_amount = np.array(amountList, dtype='float').reshape(-1, 1) - # normalize the amount - column_amount = model_with_scaler['amount_scaler'].transform(column_amount) - data = np.concatenate((columns_features, column_amount), axis=1) - # model inference - predictions = model_with_scaler['model'].predict(data) - return [pred == 1 for pred in predictions.tolist()] - -# enable vector option -detect.vector = True -``` - -Then write setup.py to build the wheel package: - -```python -from setuptools import setup, find_packages - -setup( - name="detect", - version="1.0.0", - packages=find_packages(), - package_data={ - 'credit': ['model_with_scaler'] # 模型 - }, -) -``` - -The project directory structure is as follows: - -``` -|-- demo/ - |-- credit/ - |-- __init__.py - |-- detection.py # inference function - |-- model_with_scaler # model - |-- setup.py -``` - -Build the wheel package detect-1.0.0-py3-none-any.whl with the command `python setup.py bdist_wheel`. - -Create the function: - -```sql -create or replace function py_detect(features json, amount decimal) returns bool language python import --- replace with the directory where the wheel package is located -'your_code_path/detect-1.0.0-py3-none-any.whl' --- the function detect in the module credit -handler 'credit.detect'; -``` - -Call the function: - -```sql -select id, py_detect(features, amount) as is_fraud from credit_card_transaction limit 10; -``` - -Output: - -``` -+---------+----------+ -| id | is_fraud | -+---------+----------+ -| 1 | false | -| 2 | false | -| 3 | true | -| 4 | false | -| 5 | false | -| 6 | false | -| 7 | false | -| 8 | true | -| 9 | false | -| 10 | false | -+---------+----------+ -``` - -Now, we have completed the inference of task credit card fraud detection in MO. - -From this example, it's clear that we can easily use Python UDFs to tackle tasks that SQL alone cannot handle. Python UDFs not only extend the semantics of SQL but also spare us from writing data movement and transformation programs manually, greatly enhancing the development efficiency. diff --git a/pkg/udf/pythonservice/demo/README_CN.md b/pkg/udf/pythonservice/demo/README_CN.md deleted file mode 100644 index 392c90c6d5b67..0000000000000 --- a/pkg/udf/pythonservice/demo/README_CN.md +++ /dev/null @@ -1,293 +0,0 @@ -# MO Python UDF Demo - -本文简述了 MO 中 python UDF 的使用方式,展示了 python UDF 的灵活与便捷。 - -## 单机快速部署 - -1. 在部署之前,我们需要确保本地拥有 [python3](https://www.python.org/downloads/) 环境,并在 python 环境下安装 grpc 相关的 package: - -``` -pip install protobuf -pip install grpcio -``` - -2. 按照[快速开始](https://docs.matrixorigin.cn/1.0.0-rc1/MatrixOne/Get-Started/install-standalone-matrixone/)中的步骤完成相关安装,在启动 MO 之前,执行以下命令修改 mo_ctl 的配置: - -```shell -mo_ctl set_conf MO_CONF_FILE="${MO_PATH}/matrixone/etc/launch-with-python-udf-server/launch.toml" -``` - -3. 启动并连接 MO。 - -## "Hello world" - -我们从一个简单的函数开始说起:用 python UDF 实现两数之和。 - -在客户端中输入以下 SQL 来创建函数: - -```sql -create or replace function py_add(a int, b int) returns int language python as -$$ -def add(a, b): - return a + b -$$ -handler 'add'; -``` - -这段 SQL 定义了一个名为 py_add 的函数,接收两个类型为 `int` 的参数,其功能是返回两个参数的和,具体逻辑在 `as` 后的 python 代码中,`handler` 表示调用的 python 函数名称。 - -> 注意: 当前版本 matrixone 不会在创建 UDF 时检查 python 语法,用户需要自行保证 python 语法的正确性,否则在执行后续执行函数时会报错。 - -现在便可以使用该函数了: - -```sql -select py_add(1,2); -``` - -输出: - -``` -+--------------+ -| py_add(1, 2) | -+--------------+ -| 3 | -+--------------+ -``` - -当我们不再需要该函数时,可以将其删除: - -```sql -drop function py_add(int, int); -``` - -至此,我们已经掌握了 python UDF 的基本用法。 - -## 进阶 - -本节主要介绍 python UDF 的一些进阶用法。 - -### 导入式 python UDF - -在上一节中,py_add 函数是直接写在 SQL 中的,python 代码写在 `as` 关键字之后,我们称这种形式为**嵌入式 UDF**。然而,如果函数逻辑十分复杂,直接写在 SQL 中并不是一个好的选择,这会让 SQL 语句膨胀而且不利于代码的维护。这时,我们可以选择另一种创建 python UDF 的方式:从外部文件中导入 python 代码,即**导入式 UDF**。支持导入的文件有两种:(1) 单个 python 文件,(2) wheel 包。我们仍旧以上一节的 py_add 函数为例,把 python 代码写到文件中。 - -./add_func.py 代码如下: - -```python -def add(a, b): - return a + b -``` - -在客户端中输入以下 SQL 来创建函数(使用 `mysql` 命令行工具连接 matrixone 时,需要添加 `--local-infile` 允许工具读取本地的 Python 文件): - -```sql -create or replace function py_add(a int, b int) returns int language python import -'./add_func.py' -handler 'add'; -``` - -其中,我们使用 `import` 关键字来导入当前工作目录下的 add_func.py 文件。 - -调用函数: - -```sql -select py_add(1,2); -``` - -仍旧可以得到与上一节相同的输出: - -``` -+--------------+ -| py_add(1, 2) | -+--------------+ -| 3 | -+--------------+ -``` - -导入 wheel 包与单个 python 文件具有相同的语法,这里不再赘述。在最后的案例中,我们将会以导入 wheel 包的形式来创建 python UDF。 - -### Vector 选项 - -在某些场景下,我们会希望 python 函数一次性接收多个元组来提高运行效率。如在模型推理时,我们通常是以一个 batch 为单位进行的,这里的 batch 即为元组的 vector。而 vector 选项正是用来处理这种情况的。我们仍旧以 py_add 函数为例,展示 vector 选项的用法。 - -在客户端中输入以下 SQL 来创建函数: - -```sql -create or replace function py_add(a int, b int) returns int language python as -$$ -def add(a, b): # a, b are list - return [a[i] + b[i] for i in range(len(a))] -add.vector = True -$$ -handler 'add'; -``` - -其中,我们使用 `add.vector = True` 来标记 python 函数 add 接收两个 int 列表(vector)而不是 int 值。 - -调用函数: - -```sql -select py_add(1,2); -``` - -仍旧可以得到与上一节相同的输出: - -``` -+--------------+ -| py_add(1, 2) | -+--------------+ -| 3 | -+--------------+ -``` - -有了 vector 选项,我们就可以自由地选择函数的处理形式:一次一元组,或者一次多元组。 - -### 类型映射 - -MO 类型与 python 类型的对应关系如下: - -| MO 类型 | Python 类型 | -| -------------------------------------------------------- | --------------------------- | -| bool | bool | -| int8, int16, int32, int64, uint8, uint16, uint32, uint64 | int | -| float32, float64 | float | -| char, varchar, text, uuid | str | -| json | str, int, float, list, dict | -| time | datetime.timedelta | -| date | datetime.date | -| datetime, timestamp | datetime.datetime | -| decimal64, decimal128 | decimal.Decimal | -| binary, varbinary, blob | bytes | - -### 函数重载与匹配 - -MO UDF 目前不支持重载,函数名在一个 matrixone 集群要求是唯一的。 - -## 案例:信用卡欺诈检测 - -本节以“信用卡欺诈检测”为例,讲述了 python UDF 在机器学习推理流水线中的应用。(相关代码详见 [github](https://github.com/matrixorigin/matrixone/tree/main/pkg/udf/pythonservice/demo)) - -在本节中,我们需要确保本地 python 环境已安装了 numpy 和 scikit-learn。 - -### 背景 - -信用卡公司需要识别欺诈交易,以防止客户的信用卡被他人恶意使用。(详见 kaggle [Credit Card Fraud Detection](https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud)) - -### 数据 - -数据集包含了2013年9月欧洲持卡人使用信用卡进行的交易记录。数据格式如下: - -| 列名 | 类型 | 含义 | -| -------- | ------ | ----------------------------------------------- | -| Time | int | 此交易与数据集中的第一个交易之间经过的秒数 | -| V1 ~ V28 | double | 使用 PCA 提取的特征(以保护用户身份和敏感特征) | -| Amount | double | 交易金额 | -| Class | int | 1:欺诈交易,0:非欺诈交易 | - -我们把数据按照8: 1: 1的比例划分为训练集、验证集和测试集。由于训练过程不是本文的重点,不在此处进行过多的介绍。我们把测试集当作生产过程中新出现的数据存储到 MO 中,DDL 如下: - -```sql -create table credit_card_transaction( - id int auto_increment primary key, - time int, - features json, -- 对应 V1 ~ V28,使用 json list 存储 - amount decimal(20,2) -); -``` - -### 推理 - -训练好模型之后,我们就可以编写推理函数了。其核心代码如下: - -```python -import decimal -import os -from typing import List - -import joblib -import numpy as np - -# 模型路径 -model_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'model_with_scaler') - - -def detect(featuresList: List[List[int]], amountList: List[decimal.Decimal]) -> List[bool]: - # 加载模型 - model_with_scaler = joblib.load(model_path) - - columns_features = np.array(featuresList) - column_amount = np.array(amountList, dtype='float').reshape(-1, 1) - # 对金额进行归一化 - column_amount = model_with_scaler['amount_scaler'].transform(column_amount) - data = np.concatenate((columns_features, column_amount), axis=1) - # 模型推理 - predictions = model_with_scaler['model'].predict(data) - return [pred == 1 for pred in predictions.tolist()] - -# 开启 vector 选项 -detect.vector = True -``` - -然后编写 setup.py 用于构建 wheel 包: - -```python -from setuptools import setup, find_packages - -setup( - name="detect", - version="1.0.0", - packages=find_packages(), - package_data={ - 'credit': ['model_with_scaler'] # 模型 - }, -) -``` - -整个项目的目录结构如下: - -``` -|-- demo/ - |-- credit/ - |-- __init__.py - |-- detection.py # 推理函数 - |-- model_with_scaler # 模型 - |-- setup.py -``` - -使用命令 `python setup.py bdist_wheel` 构建 wheel 包 detect-1.0.0-py3-none-any.whl。 - -创建函数: - -```sql -create or replace function py_detect(features json, amount decimal) returns bool language python import -'your_code_path/detect-1.0.0-py3-none-any.whl' -- 替换为 wheel 包所在目录 -handler 'credit.detect'; -- credit module 下的 detect 函数 -``` - -调用函数: - -```sql -select id, py_detect(features, amount) as is_fraud from credit_card_transaction limit 10; -``` - -输出: - -``` -+---------+----------+ -| id | is_fraud | -+---------+----------+ -| 1 | false | -| 2 | false | -| 3 | true | -| 4 | false | -| 5 | false | -| 6 | false | -| 7 | false | -| 8 | true | -| 9 | false | -| 10 | false | -+---------+----------+ -``` - -至此,我们已经在 MO 中完成了信用卡欺诈检测任务的推理。 - -通过该案例可以看出,我们可以方便地使用 python UDF 来处理 SQL 解决不了的任务。Python UDF 既扩展了 SQL 的语义,又避免了我们手动编写数据移动和转换的程序,极大地提高了开发效率。 diff --git a/pkg/udf/pythonservice/demo/credit/__init__.py b/pkg/udf/pythonservice/demo/credit/__init__.py deleted file mode 100644 index f59e717ed6d0c..0000000000000 --- a/pkg/udf/pythonservice/demo/credit/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# coding = utf-8 -# -*- coding:utf-8 -*- -from .detection import detect diff --git a/pkg/udf/pythonservice/demo/credit/detection.py b/pkg/udf/pythonservice/demo/credit/detection.py deleted file mode 100644 index 4a027ec163dc1..0000000000000 --- a/pkg/udf/pythonservice/demo/credit/detection.py +++ /dev/null @@ -1,62 +0,0 @@ -# coding = utf-8 -# -*- coding:utf-8 -*- -import decimal -import os -from typing import List - -import joblib -import numpy as np - -model_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'model_with_scaler') - - -def detect(featuresList: List[List[int]], amountList: List[decimal.Decimal]) -> List[bool]: - model_with_scaler = joblib.load(model_path) - - columns_features = np.array(featuresList) - column_amount = np.array(amountList, dtype='float').reshape(-1, 1) - column_amount = model_with_scaler['amount_scaler'].transform(column_amount) - data = np.concatenate((columns_features, column_amount), axis=1) - predictions = model_with_scaler['model'].predict(data) - return [pred == 1 for pred in predictions.tolist()] - - -detect.vector = True - -if __name__ == '__main__': - ret = detect( - [ - [-1.39598357648026, 1.07394393065875, 0.213508735697434, -1.00551307370986, 1.187300373936, - -1.07111854041464, 0.753203638755905, 0.30971495602621, -0.983991867539784, -1.70071141514904, - 0.823426013946253, 0.755747784301563, 0.57208601947088, -0.493305378300063, -0.470447091684077, - 0.748161458746014, -0.0446257458090844, 1.15426779428755, -0.580978900127479, -0.04190738904369, - 0.313836892986802, 0.629705007512215, -0.702875042416293, -0.378664198371815, 1.17715716992152, - -0.0670218758532906, -0.108995491056784, -0.0807276510778096], - [-1.99458047217904, -1.63531939810522, 1.00669502032082, -1.43318273761075, 3.25919383016879, - 4.00823861971185, -1.66001967781548, 1.09946561236069, 1.91968533357403, -0.518543946411732, - -1.05471184392788, 0.446539472296582, -0.468234843104227, -1.40433618221015, -1.8103263742068, - -0.277012303056273, -0.290667580529318, -0.608743967003329, -0.218456639889371, -0.677311451910878, - -0.258971403019176, 0.0809710102853903, -0.579907932919128, 0.830053981653551, -0.462078172323048, - 0.437226392974709, -0.170400933244463, 0.0175635565102101], - [-3.0435406239976, -3.15730712090228, 1.08846277997285, 2.2886436183814, 1.35980512966107, - -1.06482252298131, 0.325574266158614, -0.0677936531906277, -0.270952836226548, -0.838586564582682, - -0.414575448285725, -0.503140859566824, 0.676501544635863, -1.69202893305906, 2.00063483909015, - 0.666779695901966, 0.599717413841732, 1.72532100745514, 0.283344830149495, 2.10233879259444, - 0.661695924845707, 0.435477208966341, 1.37596574254306, -0.293803152734021, 0.279798031841214, - -0.145361714815161, -0.252773122530705, 0.0357642251788156], - [-2.30334956758553, 1.759247460267, -0.359744743330052, 2.33024305053917, -0.821628328375422, - -0.0757875706194599, 0.562319782266954, -0.399146578487216, -0.238253367661746, -1.52541162656194, - 2.03291215755072, -6.56012429505962, 0.0229373234890961, -1.47010153611197, -0.698826068579047, - -2.28219382856251, -4.78183085597533, -2.61566494476124, -1.33444106667307, -0.430021867171611, - -0.294166317554753, -0.932391057274991, 0.172726295799422, -0.0873295379700724, -0.156114264651172, - -0.542627889040196, 0.0395659889264757, -0.153028796529788], - ], - [ - decimal.Decimal('2.35'), - decimal.Decimal('17.6'), - decimal.Decimal('529'), - decimal.Decimal('239.93'), - ] - ) - - print(ret) diff --git a/pkg/udf/pythonservice/demo/credit/model_with_scaler b/pkg/udf/pythonservice/demo/credit/model_with_scaler deleted file mode 100644 index ef63da8c1de5bc23b2dc5564becf828fc2acba32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1497 zcma)*Uu+ab9LMjj*WP)w<%&fUOO0X*l(rWOS~0O~O;yArM=VKO9?Up$YZQV@bn8G0j$~0xb(>IjeHrL5m;ZtkOFozA2hDk-HO6w(!Fv zhjt0Rk}vSeYfv1WL1%4o+dDrq^O;< zx`gZEQTOUT3!0{AOR3Hr=<^EU%s;V&vG!2@fR}FbTo;HB0lF>CJB9gNd5gw1)@(Q=S!ZX$lANvDQJD6ijDW_|Da8;nkq%WV&0c&ZVa3AL{haI&&R2HdW7m=8QKrZ~rMf>U{g;p*OD#Uv&PwV=s9f zpO*fZk6&xqIVD|K|M*7@C*PAkS$}Y9X#bDS^s6&E{`I00erDHO{{%8axNDx=-~%(hb`N&e*pIyaDV^+ diff --git a/pkg/udf/pythonservice/demo/ddl.sql b/pkg/udf/pythonservice/demo/ddl.sql deleted file mode 100644 index a840f98c3d498..0000000000000 --- a/pkg/udf/pythonservice/demo/ddl.sql +++ /dev/null @@ -1,1006 +0,0 @@ -drop table if exists credit_card_transaction; -create table credit_card_transaction( - id int auto_increment primary key, - time int, - features json, -- 对应 V1 ~ V28,使用 json list 存储 - amount decimal(20,2) -); -insert into credit_card_transaction (time, features, amount) values (157638, '[-1.39598357648026, 1.07394393065875, 0.213508735697434, -1.00551307370986, 1.187300373936, -1.07111854041464, 0.753203638755905, 0.30971495602621, -0.983991867539784, -1.70071141514904, 0.823426013946253, 0.755747784301563, 0.57208601947088, -0.493305378300063, -0.470447091684077, 0.748161458746014, -0.0446257458090844, 1.15426779428755, -0.580978900127479, -0.04190738904369, 0.313836892986802, 0.629705007512215, -0.702875042416293, -0.378664198371815, 1.17715716992152, -0.0670218758532906, -0.108995491056784, -0.0807276510778096]', 2.35); -insert into credit_card_transaction (time, features, amount) values (157639, '[-1.99458047217904, -1.63531939810522, 1.00669502032082, -1.43318273761075, 3.25919383016879, 4.00823861971185, -1.66001967781548, 1.09946561236069, 1.91968533357403, -0.518543946411732, -1.05471184392788, 0.446539472296582, -0.468234843104227, -1.40433618221015, -1.8103263742068, -0.277012303056273, -0.290667580529318, -0.608743967003329, -0.218456639889371, -0.677311451910878, -0.258971403019176, 0.0809710102853903, -0.579907932919128, 0.830053981653551, -0.462078172323048, 0.437226392974709, -0.170400933244463, 0.0175635565102101]', 17.6); -insert into credit_card_transaction (time, features, amount) values (157639, '[1.91995030623265, -0.5295747029094, -0.291774125621835, 0.644989215446892, -0.76675678904966, -0.384374141379217, -0.616882341317413, -0.0303795762697624, 1.25072392843323, 0.0132744068850985, -1.10026154824521, 0.331734538658172, 0.193348358893277, -0.257782871763926, 0.390828644791368, 0.283302715730695, -0.504784359906921, 0.057997610280608, -0.378145951606318, -0.135899240310776, 0.239401040560321, 0.864998262232592, 0.0783537317280094, -0.109595024583041, -0.197548684246792, 0.455488380685572, -0.0082640199045086, -0.0414176548014362]', 41.94); -insert into credit_card_transaction (time, features, amount) values (157639, '[-0.356158491296727, 1.19140675503969, -0.437619198206388, 1.17389858526241, 0.525367907476951, -0.471524075492547, 0.19921791891019, 0.239205320969324, -0.757000018757229, -0.433462393457057, -0.626163240442246, -0.170415717117371, 0.289081031012259, -0.445256858118694, 1.38237075501963, -0.697927739044338, 1.61687269021561, 0.214470276102167, 2.76077271804357, 0.149752362112721, -0.182841920481592, -0.552937665163497, 0.0335953721199883, 0.614989258141114, -0.986867753602889, 0.524161795846751, -0.0198743916937031, 0.100141172352533]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157639, '[2.02583456089301, -0.0460704553298835, -1.24939316418736, 0.274412261852914, -0.0275606053390044, -1.09971415141943, 0.154687080161978, -0.263754573657412, 0.33531332049879, 0.185334849098208, 1.08210981362046, 1.00130451318474, -0.0654466963955989, 0.69565703650254, 0.0364246570962769, -0.0461271446812628, -0.718075126924868, 0.403463206316367, 0.0230679539589328, -0.241081814272209, 0.302147569082114, 1.00340980337905, -5.88882811997649e-05, 0.11396159664657, 0.224937903068446, -0.133708994176919, -0.0233532686686872, -0.0680550254990753]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157640, '[-1.25788044139779, 0.577768020042278, 0.456236866366804, -1.01285260644017, -1.56884105409177, 0.939294972711302, -2.09066900408235, 1.69062535105188, -1.06172905614274, 0.10065118670415, -0.572698298175859, 0.112910775422312, 0.159424394271634, 0.623588180799913, 0.68303613010055, -0.309407447179201, -0.164418821746834, 2.86081287192568, 0.157059825067622, -0.736265048870775, 0.127880379623038, 0.390366351325565, 0.107342480466096, 0.0309931910367953, -1.12833104910195, 0.685512178738179, -0.39438011099865, -0.0225425710328445]', 7.31); -insert into credit_card_transaction (time, features, amount) values (157641, '[1.98510586726557, 0.398792922511515, -2.45150499127779, 1.46248689674201, 1.03546637873498, -0.846499564070512, 0.679494343853913, -0.305204032502528, 0.198211935930933, -0.363112191003191, -0.798523200163691, -0.274237040248291, -0.662816737354039, -0.917638619957321, -0.260083274524396, -0.145069895449114, 0.953649350221411, 0.156306942085275, -0.361630039377152, -0.184153341133051, -0.0386108447781726, 0.0084067645958914, -0.037845829943511, 0.383466256565816, 0.48272284915951, -0.5115343341548, -0.0099082407947613, -0.0198086265817112]', 38.17); -insert into credit_card_transaction (time, features, amount) values (157641, '[-0.374887370619266, -4.11729339378491, -4.1875224037996, 1.18373794632254, -0.310090131427654, -0.899450472361004, 2.7252532041357, -0.949894054704977, -0.171053824310508, -0.383950298690729, -1.43292386006332, -0.233954787781866, -0.173060967229491, 1.15579858379694, 0.0609922403369292, -0.437634662704189, -0.227380513674285, -0.285718698521211, -0.113894844752243, 2.46723269810961, 1.01510422331704, 0.0863033514135896, -1.42676810402777, -0.596595689077286, 0.204409984529966, 0.927533302336789, -0.39802548901435, 0.125554710154175]', 1336.0); -insert into credit_card_transaction (time, features, amount) values (157642, '[-0.0416732511933412, 0.71244420568974, 0.33535085867153, -0.670760190626758, 0.428872888558093, -0.811847554634009, 0.810955098031995, 0.0078032655071081, -0.190866214880937, -0.223122386109244, 0.766145047980819, 0.468258261730657, -0.861865139996295, 0.474579604584876, -0.976567712386884, 0.0548392794470782, -0.527432188772319, -0.274295661265464, 0.107782136692494, -0.0774532911198698, -0.203471813529004, -0.485264248271819, 0.0890083834450539, -0.0100748971629493, -0.570358006667116, 0.123357366885259, 0.240495687692584, 0.0866455092013529]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157643, '[-0.832503466188826, 0.682723784631944, 1.02218856923446, -0.717397382886135, 0.427838532191477, 1.58550406037139, -0.335734551790415, 1.11338845257033, 0.019252243360449, -1.05141052489124, 0.457362240420781, 0.342512098801101, -1.10803892260668, 0.693400052583313, 0.766083459291204, -0.356980260432214, 0.172193840621312, -0.434130513898625, -0.166894804664431, -0.309253450215673, 1.02093015277999e-05, -0.0325676095011079, -0.0331243170780324, -1.69920795655913, -0.504059406166493, -0.412186968702842, 0.0735610937939236, 0.0523765924198769]', 3.99); -insert into credit_card_transaction (time, features, amount) values (157643, '[2.25420752750295, -1.24481322779075, -1.72863974578842, -1.68526914781163, -0.633272382837569, -1.07473988257085, -0.382061279894191, -0.511529894450943, -1.84369298764842, 1.61314870246791, -1.20851073789814, -0.580659560773602, 1.46325147523553, -0.196419847373187, 0.0428856326032823, -0.486149866833118, 0.160598658923804, -0.303179983132317, 0.137190343227818, -0.223003202600284, -0.303673405745144, -0.567555864976534, 0.138123576608639, -0.671257746323221, -0.0802396437891242, -0.282735378147483, -0.0305796850857915, -0.0499709148950415]', 85.0); -insert into credit_card_transaction (time, features, amount) values (157643, '[0.177244382040837, 0.917210791001869, -0.688700744979568, -0.679315255223694, 1.12326209092676, -0.432961532866439, 0.867039513116872, 0.0248384990656834, 0.182589944278121, -0.806064057014407, -1.40091161071351, -0.968885386690624, -1.14843099452001, -0.797624886028567, -0.0091049245692412, 0.510401354176316, 0.272376089211884, 0.0492453250291156, -0.0623830038520425, -0.0452201113723892, -0.389600056638222, -1.02675925702742, 0.0450413635222858, -0.113254034570941, -0.396547137570523, 0.159356219756419, 0.216028690279438, 0.0750202864404438]', 4.49); -insert into credit_card_transaction (time, features, amount) values (157644, '[-0.897403215679839, 0.699772862540808, 0.80409201072632, 0.635410858336631, 1.05363675650451, -0.818910252944362, 0.802695333475396, -0.150121994229663, -0.428486343256276, -1.06826373992494, -0.46973288624574, 0.347080934734465, 1.04875667172493, -1.46560256644374, 0.0509824543224673, 0.340349019538857, 0.362220016825516, 0.273746339761634, -0.704288412154429, 0.0121626544218576, -0.0603507325616821, -0.173919888747679, -0.323116082374684, -0.18831404209253, 0.984769914817444, -0.556450923893259, -0.202612462787745, -0.0024301912341971]', 50.0); -insert into credit_card_transaction (time, features, amount) values (157644, '[-1.32028971061182, -0.0967140071443226, 2.75444126359053, -2.10382883379794, -1.08911993985864, 1.17039076965806, -0.951504207644949, 0.442544482316705, 0.951322010621573, -0.0946106074903396, -2.0514309395451, -0.348748182659254, 0.446338569120425, -2.25011118237956, -2.33194561730455, 0.865589675341509, 0.291234687426737, -1.0016284014087, 0.454522241322133, 0.193914179861337, 0.200579799638371, 1.10369423135335, -0.545784798376071, 0.557538500117808, 0.706163403205832, -0.0325177396845115, -0.511315211437245, -0.383131262714821]', 9.6); -insert into credit_card_transaction (time, features, amount) values (157644, '[-0.839236815165994, 0.772772938354519, 0.896315790067565, -0.291204774756721, 1.10995788514525, -0.259922685295173, 1.02692579501918, -0.194909979465381, -0.707221666850287, -0.610249324986453, -1.00473075743882, 0.317539398659417, 1.0162701878275, -0.0636537611734492, 0.0062630658661567, -0.576085456788288, -0.0627513392625493, -0.614960936410469, 1.22269613107285, 0.165602349613131, -0.232444304473928, -0.666007271329866, -0.301846328581569, 0.531258279316342, 0.585379090020058, 0.507216145949509, -0.166378809200635, 0.101108142387477]', 31.39); -insert into credit_card_transaction (time, features, amount) values (157645, '[2.03473237043037, -0.438923466039102, -0.666964426144476, -0.0249050094282948, -0.215106953813965, 0.175390728144177, -0.646125813386846, 0.130326350894405, 0.919428287998534, 0.168865611671255, -0.074021206703936, 0.689784879203225, 0.146746265738576, 0.0419583431391672, -0.0793888274891199, 0.956846855573017, -1.14999454649998, 0.431947350122071, 0.623283175304275, -0.152084909882827, -0.237369120539355, -0.598430501807229, 0.278486347413146, -1.10562331840212, -0.526518996006121, 0.32141927610625, -0.0401344861298193, -0.0641254152450784]', 6.99); -insert into credit_card_transaction (time, features, amount) values (157645, '[-0.183479931137426, 0.857937614653596, 0.0807566218636643, 0.412551185793813, 1.03282928618833, -1.07274869321084, 1.40937765576693, -0.266740689201988, -0.487884963951038, -0.508335397186214, -1.26858618466222, -0.427358127869716, -1.09741794115717, 0.547713652967518, -0.825632826803471, -0.661245769623629, -0.181485880516096, -0.438938108956117, -0.425318700589288, -0.215632752764924, 0.0889922590906744, 0.283658660084031, -0.323451201392851, -0.0356676340499028, 0.706606250660853, -0.481030364345376, -0.0327263043071444, -0.035265296126595]', 21.56); -insert into credit_card_transaction (time, features, amount) values (157646, '[-1.03994732344747, 1.97440929932459, -1.4413951020941, -0.296659217416401, 0.5776944419145, -1.75100214096989, 0.51803695000682, 0.561321718994645, -0.47425509408744, -2.33512697140002, -0.445701875227705, -0.728294232624045, -0.884311269891526, -1.84691675181435, 0.60350717072587, 1.00089348707433, 2.06025981589296, 1.50450712172025, -1.01934337751317, -0.399906552122338, 0.299071601393581, 0.626380461177943, -0.295862513568879, -0.250576327442362, -0.0798821861819715, -0.202848250235844, -0.18622360787109, 0.0927429477928861]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157646, '[-2.69353886870738, 3.10044368971283, -2.55889744137267, -0.673985560453876, -0.9599197741292, -1.05020493531582, -0.847844018299585, 2.02481930629227, -0.231623935584156, 0.295327097438162, -0.106038118675719, 1.6857008031583, 0.900093210603649, 1.70460318180633, -0.407768316490628, 0.338110148596447, -0.101297811120048, 0.816532937868269, 0.294764224236611, 0.136757173994931, 0.466567982537171, 1.26862048621514, 0.127235361448291, -0.374555932835656, -0.371099953601298, -0.182618771753876, 0.409186278840597, 0.297486784826629]', 2.69); -insert into credit_card_transaction (time, features, amount) values (157647, '[2.05260047957892, -0.110828707060066, -1.24252955680428, 0.188362507635046, 0.149966334997958, -0.615491388148278, 0.0749179612326886, -0.16005763276635, 0.307527691571433, 0.241426971185178, 0.539575444856533, 0.994490117937812, 0.108495817934143, 0.434396258110717, -0.63063017978852, 0.227930779482464, -0.714481796968903, -0.224519558391214, 0.614696884032326, -0.194597509214057, -0.268227892903336, -0.670642669547294, 0.268215499852199, -0.491410166198354, -0.263485465875815, 0.20782111444266, -0.0749112758380428, -0.0748118791225046]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157647, '[-1.27199882743545, 0.170024393750088, -0.088251722094101, -2.11291307127448, 2.75153062500867, 3.66687082623167, -0.146953385279325, 0.950536072153524, 0.489146197127268, -0.622995755433168, -0.196149436731275, 0.0707399586978106, -0.203820118487718, -0.0268143762172014, 0.719533000167805, 0.41010495628507, -1.06715197027243, -0.140932915582162, -0.918224341480068, -0.253938392801881, -0.0269174966606696, -0.300689448818157, 0.213908698152699, 0.641920715206624, -0.40112906350585, -0.76218027414501, -0.467643723395709, 0.418321624672595]', 1.18); -insert into credit_card_transaction (time, features, amount) values (157648, '[2.11751020965837, 0.0235774478087018, -1.9870043554948, 0.293039239050815, 0.557169624192171, -0.579877938926374, 0.0576564317318973, -0.102645605597837, 0.789471792393416, -0.327531662600769, -1.388329399547, -0.944194688986781, -1.51183387023545, -0.545963751991944, 0.433139290855922, 0.569220418192005, 0.352482971760458, 0.0930677139455327, 0.289491593096733, -0.246063991259267, -0.423721871213864, -1.19176114420418, 0.286955353814581, -0.108455477801213, -0.234985090743966, 0.214397040406983, -0.0743007330473323, -0.0402667266075482]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157648, '[1.2256294168653, -2.05483045588278, 0.581187780359728, 0.992412322822088, -1.98712886707541, 0.801471953821846, -1.23315068801493, 0.387753146721514, 2.27265675996996, -0.326349517961391, 0.0448312599642679, 1.58334135387118, 0.0022237043746793, -1.08403078522063, -2.18352446960988, 0.0524856989296345, -0.103699713770269, 0.410027617945241, 0.385379033868296, 0.447661826986291, 0.322247458766696, 0.750138445722837, -0.10597983595467, 0.19113939238615, -0.548493821296221, 0.679922959833611, -0.0208893379416632, 0.0102587672514416]', 328.0); -insert into credit_card_transaction (time, features, amount) values (157648, '[-0.248509726495573, 1.07946868252229, -0.393704058864527, -0.717591356587321, 0.433266436288412, -0.742173056932365, 0.650636809594189, 0.271991343687211, -0.147823288876947, -0.634919406057096, -1.7640334565014, -0.0047852664362168, 0.104355478852626, 0.40333711619458, -0.376267347676382, 0.253744161776144, -0.508267605605149, -0.450619902765913, 0.194131536965775, -0.11870850845706, -0.265742678361742, -0.729147274943867, 0.0467918131182337, -0.727072224534445, -0.365658411742183, 0.187573122607184, 0.118165813854475, 0.02770642473007]', 9.42); -insert into credit_card_transaction (time, features, amount) values (157649, '[1.97557156420932, 0.257052006508714, -2.30602086566742, 0.710884424036468, 0.692095080411303, -0.652265232920129, 0.0815479580842565, -0.0723374784955656, 0.434517554214779, -0.909660163633121, 1.46953564433281, 0.606872423893538, -0.252219110287855, -2.46321159652085, -1.01268702234767, 0.489980229475144, 1.82543420356317, 1.04599683077151, -0.0550521360391502, -0.103584896278749, 0.0385742696680821, 0.372966181302742, -0.0156695797948929, 0.567601948187327, 0.176486311786696, 0.675621228331706, -0.0423392384959142, -0.0146088068254063]', 12.31); -insert into credit_card_transaction (time, features, amount) values (157649, '[-0.923490195175723, -0.411541403361359, 1.31870999103651, -0.807033963370218, 1.07094881607993, -0.566722373692538, 0.130075177826392, 0.0337314567968639, 0.252200442683106, -0.169607973034594, 0.363178350489606, 0.547406517051136, 0.0437651361614005, -0.180551484396432, -0.560353267086069, 0.613677406482808, -1.12055820949404, 0.304506409314633, 0.26068587480448, 0.416315140021198, -0.149954952111745, -0.454977516408151, 0.243535026473874, -0.512818109939499, -0.825786410745404, 0.153323797882963, 0.164884187285001, 0.0275399485708718]', 40.47); -insert into credit_card_transaction (time, features, amount) values (157649, '[2.00855016015528, -1.00830627696618, -0.317348840213955, -0.0696998055948962, -1.27863546083863, -0.576883570660935, -0.886241531559988, -0.056933909460289, 0.116562119974472, 0.8426102410503, -1.31226379337613, -0.339061579495805, -0.313155831453531, -0.0866695618949391, 0.456310113353515, -0.995510666165627, -0.300401516461393, 1.13850279602969, -0.884743665061387, -0.551588310312965, -0.55429928472897, -1.15899745384567, 0.436957785315452, -0.193691591275635, -0.70936766810153, -0.0159983045075576, -0.0008288727590658, -0.0275011483844943]', 59.4); -insert into credit_card_transaction (time, features, amount) values (157649, '[0.223594544683996, 0.715958414102107, -2.13564557647109, -1.97535185861463, 0.496395482356357, -0.490560608050714, -0.5226307455962, -3.43752318061339, -1.01490684402817, 0.166872296900074, 1.04629208304285, -0.22376177865544, -0.96001081019648, -0.647368337467912, -1.84529756839946, 1.16804781165731, 1.16554201444276, -0.814668252428307, -0.271418265558344, -0.788696677113423, 3.36872714339997, -0.180131599083971, 0.0633492381088427, 0.604496607271027, 0.817962052808668, -0.0646537278128118, 0.223178530922308, 0.20813541732301]', 19.46); -insert into credit_card_transaction (time, features, amount) values (157650, '[2.04260022801273, -0.132571727934578, -1.20797226400629, 0.421332838027051, 0.015662256932516, -0.290900369965955, -0.469889792653869, -0.0631863606594573, 1.33273001135079, -0.642606146036098, -1.42330911291295, 0.0776184721728813, 0.686817593859346, -1.50219536621149, 0.824119868486107, 0.801319377845985, -0.0140382552155231, 1.12448350938074, -0.123450200949616, -0.115296834771437, 0.151440034559825, 0.709881626237922, -0.0839973191934584, -1.06186213184746, 0.120787015914271, -0.0784249578623302, 0.0525212587573732, -0.0203316678171085]', 12.58); -insert into credit_card_transaction (time, features, amount) values (157651, '[-0.131054840467345, 0.892623535809587, -0.482924297493091, -0.186360677836607, 0.803878161265486, -1.23191087867137, 0.751297125173002, -0.231255815536925, -0.138538859354719, -0.574688901380832, 1.20122831247042, 0.147984564660915, -0.69271123910182, -0.666342460960936, 0.0723310883844761, 0.24150976314228, 0.320811665517914, 1.25279506457288, 0.0952951751238245, -0.242764588140141, 0.366922538820285, 1.090995504712, -0.259874269506971, -0.0006046999046569, -0.486225886870085, -0.203213961396791, -0.0903803670810949, 0.105680510684779]', 7.37); -insert into credit_card_transaction (time, features, amount) values (157651, '[-0.210002232493935, 1.50789103972255, -1.86428166573953, -0.51623060411041, 0.751880968406418, -0.638984108486165, -0.126320115866028, -2.58409084090286, -0.819442409091646, -1.07986480071802, -1.32333628597076, 0.640977040282002, 0.257433530731629, 1.03499701651991, -1.00783228749532, -0.263062714568735, -0.0569792761702533, -0.582582294663413, -0.311308997111532, 0.326594219796808, -1.01533216687948, 1.11474741796973, 0.167665203226668, 0.729468154695518, -0.331569304619855, 0.499900829983917, -0.198667100462482, -0.0346444636175124]', 0.76); -insert into credit_card_transaction (time, features, amount) values (157651, '[-2.30131222984748, 1.47011403271157, 0.969135997155183, 2.18320065748936, -0.863390844215648, 1.15195530858573, -2.29451663092486, -4.7762607704627, -1.40541108966046, -1.25200599328173, -0.779001242062094, 0.913414366964245, 0.839656714002994, 1.09018386793027, 1.96595047392444, -0.184044207837079, 0.71272603988305, 0.379455125264061, 1.89719409549571, 1.28788467912956, -2.64102324260032, 0.663854666086816, 0.358991144686073, -0.0392489078526365, -0.024862449689254, -0.377762483156487, 0.213168112797435, -0.199975925427775]', 51.0); -insert into credit_card_transaction (time, features, amount) values (157652, '[0.884763508441952, -3.8156762988978, -1.39965199924788, -1.07414994019818, -2.11764507211758, 0.0562262021216791, -0.575881512021307, -0.240249343504635, -1.02828758751354, 1.22542348314424, -1.22168488615554, -0.845611984500319, 0.992455838261884, -0.533670049811058, 0.559956335227874, 0.0766888284180032, 0.109772507881296, 0.650536918075264, -0.591966248606822, 1.11981291980484, 0.456787832968756, 0.143628838729152, -0.434296991619562, 0.509650570790717, -0.515992421348443, -0.160519556864417, -0.100654882997993, 0.0925007709077297]', 746.5); -insert into credit_card_transaction (time, features, amount) values (157653, '[0.731815773882491, 0.543391502795749, -0.0859453295498783, 1.26866038121961, -0.159981828861613, -0.619255064874644, 0.283255994615255, -0.108725800739492, 0.169950171490531, 0.451790719569398, -1.15817984538723, -1.3323848087332, -2.39520068200804, 0.75274975621883, 1.3251194281676, -1.19737871621193, 0.904446729970673, -0.209928873922578, 2.71798863286453, -0.0391638608249803, -0.193578426863593, -0.480362852922719, 0.168862959676893, -0.115902546091977, -0.827008953700782, 0.651625087736028, -0.154819440325894, -0.0656439642523445]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157653, '[-0.242040291626059, 1.54914595234036, 1.47683333183473, 4.33927115234629, 0.308702290845302, 1.41422764612945, -0.188777403569096, 0.404470258555776, -1.56737273147991, 1.47564283478422, -1.46080551454826, -0.0466398267479782, 1.70359273145409, -0.393949877881024, 0.521185486043533, 0.150451806218905, -0.105424504585828, 0.513143478221745, 1.09606425914925, 0.215796943394874, 0.293115506032373, 1.05999152274052, -0.0976773042211085, 0.523527300220911, -0.89178463188075, 0.329421726372358, -0.133824701440268, -0.0581249766516207]', 0.76); -insert into credit_card_transaction (time, features, amount) values (157654, '[2.02864556574127, 0.390124397604779, -2.51097464221226, 1.26910008229917, 1.16460309329568, -0.417938470651313, 0.460249755768631, -0.0804069495275281, 0.0999638743893789, -0.149746806899267, 0.524412944037156, -0.16077415109147, -1.63969292573602, -0.559080106857778, -0.845525001405328, 0.160838401458979, 0.666700429762474, 0.837262194107146, 0.0371473224590694, -0.298526703002147, -0.035499392468754, 0.0193301415358212, -0.0371677287624363, 0.0600083711771599, 0.466886186083478, -0.506978598611515, -0.0132610376470388, -0.0407528843936862]', 1.91); -insert into credit_card_transaction (time, features, amount) values (157654, '[2.14415001735535, 0.0323729942785834, -2.48038703801522, -0.305775718260858, 1.01461584760383, -0.736586782691403, 0.61602968093617, -0.316018599242666, 0.0389752158700674, 0.196791265489431, 0.416213235107388, 0.469909539025883, -0.478685155427874, 1.04357831397847, -0.192120689854796, -0.216764594182215, -0.732967431993865, 0.241137805611009, 0.648505448182082, -0.209892287114361, 0.147317831783046, 0.482182665992543, -0.0922224335220843, 0.137528052007268, 0.498098720879354, 0.227611828144205, -0.0983984352723302, -0.0892664175038227]', 3.78); -insert into credit_card_transaction (time, features, amount) values (157654, '[-0.139570481420866, 0.986570540500794, -0.352421192173833, -0.623364626928538, 0.618639655181002, -0.691549848922661, 0.879960407436095, -0.0403334258719745, 0.105569639449889, 0.218615667103726, 0.350883965660528, -0.0448306532287092, -1.16732851369709, 0.76285829516748, -0.0341861611004669, -0.177702251619848, -0.731183949857996, 0.79652734944385, 0.356429851713179, 0.04708212875973, 0.362065348150772, 1.30296761613408, -0.156491362883465, -0.390287934492053, -0.779148194860942, -0.20579303693408, 0.608550201729674, 0.365622820007491]', 4.49); -insert into credit_card_transaction (time, features, amount) values (157655, '[-0.130650298013811, 0.391344166392019, -0.331644691033737, -0.914679131632785, 1.38356940698963, 0.893025265018253, 0.479004213082131, 0.316064292401913, -0.0094241345888292, -0.23071615668249, 0.687518444925768, 0.480511468523812, -0.773674725661566, 0.471457820690428, -0.245536895411608, -0.545160760336742, -0.0637737445794801, -1.30513596786077, -0.627754983305407, -0.368571775583073, -0.0781987507884595, -0.1947205650754, 0.231814152107424, -1.6599896006415, -1.05404526517416, 0.155443787188482, -0.207936416520938, 0.0409139679759314]', 1.29); -insert into credit_card_transaction (time, features, amount) values (157656, '[-0.714511714551263, 1.50830994194155, 0.50711822904093, -1.24805680461767, 1.35371701530256, -0.603719964734428, 2.51880797015708, -2.86665068532995, 2.14978087024674, 3.01726208671731, 0.50966761251635, 0.149514548378927, 1.03636642956818, -2.0082960794986, 0.497353337135643, -1.09386434323394, -1.42678343693498, -0.499209413042881, -0.75665693577444, 1.00438014445258, 0.514784736124527, 0.930591811787739, -0.342807675489497, 1.17927051560503, 0.164575056265144, -0.450424307262987, -0.71880343224745, -1.41543862183007]', 42.99); -insert into credit_card_transaction (time, features, amount) values (157656, '[-1.93162261550149, 2.59026458697747, -1.8635646963847, -0.78332639978214, 0.379243940523466, 2.01992521624267, -3.01241825666795, -9.30458305757629, -0.787083562192785, -1.46885648770044, -0.365148521542741, 0.89438014400985, -1.14325014731445, 1.92977715679965, -0.307119593585105, 0.528734748496315, -0.448653051895754, 1.11454285856003, 0.0767803133493333, 1.5493102077872, -1.89057320899291, 1.90035699107097, 0.694374997983098, -0.27225631246636, -0.88546484624186, -0.248580812580304, 0.487251246055333, 0.420299091534414]', 38.64); -insert into credit_card_transaction (time, features, amount) values (157656, '[-0.800762106912369, 0.641563618170274, -0.0542473432852957, -1.0353570227287, 1.05592140175839, 1.07685907759499, 0.404842864611541, 0.770551737727229, -0.309806663592078, -1.19832613584598, 0.703326066909501, 1.38521700403863, 0.259350543174613, 0.504158091478425, -0.868675618133526, -1.34371022300666, 0.571809780605375, -1.10482893317612, -0.515841706785354, -0.249907083791907, 0.423954505602875, 1.39683331985651, -0.270520166105858, -1.32386067169, -0.0799291067324985, 0.330705686921022, 0.0522321466482027, 0.0515707723195421]', 25.0); -insert into credit_card_transaction (time, features, amount) values (157656, '[-1.17972115342466, -0.715127721335505, 1.67847011483334, -2.51098657441316, -1.24320788858571, -0.355373467080695, -0.864014438483664, 0.602989356914037, -2.47130798944278, 0.449604051744373, 0.489932842914422, -0.54730730063812, -0.184492950366788, -0.0405632074931372, -0.789191100339196, -0.0462904298812544, 0.440081558068594, 0.507653898408722, 0.0981222104587931, -0.197840306613389, -0.239980636750593, -0.751914143143501, 0.0160181820558147, -0.0663703562011932, 0.148629349059861, -0.368713114256337, -0.0730746117330672, -0.0699371961925373]', 59.96); -insert into credit_card_transaction (time, features, amount) values (157656, '[-0.69925598832763, -0.352236464281865, 0.0057390750347395, -0.983922604023834, -1.47290368141819, 1.60438496397337, 2.14727671584301, -0.127730161743354, 0.423111261231837, -1.01599018293627, 0.0893037300841674, 0.644260363278789, 0.508249572525891, -0.286350822451644, -0.631106400047552, 0.628145055706801, -1.18271140508126, 1.00884901354628, 0.124126316280315, -0.0118866067613299, 0.328426207501013, 1.15568876565384, 0.358355812487624, 0.254846543156037, -0.809282201023793, -0.0674812107974641, 0.309106848985119, 0.128859987728555]', 500.0); -insert into credit_card_transaction (time, features, amount) values (157657, '[2.06065529120707, 0.0967682056317964, -1.84226514689002, 0.211719824847831, 0.655903660553579, -0.339267947329515, 0.0699097157998885, -0.0619455045999982, 0.26813553873579, -0.20688200725904, 0.780746407568512, 0.682695415456113, -0.0034561093824345, -0.661007033492326, -0.461955681876083, 0.626440722693654, 0.0867145742532093, 0.318225520469863, 0.486963768605476, -0.137470281028489, -0.339135124586196, -0.906144506841237, 0.281518992263576, 0.0982559045615988, -0.238615132433342, 0.178137055100331, -0.0671767366379961, -0.0447616832511111]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157657, '[2.18818042484161, -0.773103238611821, -1.4501833660093, -1.08207684948781, -0.368355221346198, -0.728290645915194, -0.492612969549987, -0.168127631239908, -0.736081705459052, 1.05511923991411, 1.00837446023667, -0.210900880556817, -0.338492584560634, 0.306743550511566, -0.28171069360509, 1.11616365402975, -0.0865683066920131, -0.726171215691844, 0.714158081883484, -0.0217439467718453, 0.476267341474473, 1.2971038383396, 0.0191471334909879, 0.81171806437714, 0.171883774885656, 0.014216218174642, -0.0510154264298121, -0.0691723278268449]', 15.0); -insert into credit_card_transaction (time, features, amount) values (157657, '[2.02442612169502, -0.0457922137781754, -1.43728460562818, 0.137082080800018, 0.335117866082995, -0.54306817915896, 0.117418943478694, -0.164191461024606, 0.256384714142543, 0.154148678368035, 1.1322321838556, 1.19917839679656, 0.41896394774377, 0.592872046790169, 0.0837148882758289, -0.0782461678256967, -0.736411751248883, 0.317841249329, -0.0158626041352688, -0.176989447382873, 0.305489566640198, 0.992712047650541, 0.0251382007297824, 0.75248129260826, 0.251567520522297, -0.160579805414128, -0.0230530651597679, -0.0605606285556164]', 4.99); -insert into credit_card_transaction (time, features, amount) values (157658, '[1.40377169825774, -2.6309976417531, -3.06950406574649, -1.31511593176869, -0.653294210746356, -1.02472723679102, 0.537218955237356, -0.577322920377267, -2.30212136312151, 1.70686405080516, 0.619954822557503, -0.781639459350143, -0.720345309229526, 0.76773377284444, -1.18999428159289, -1.12709492309739, 0.617054629765677, 0.311603378387027, 0.12207349892807, 0.520588679292731, 0.45710051518232, 0.622242865329314, -0.550089665267033, 0.823799289029333, 0.42325250167685, 0.195507946667961, -0.178863067156689, -0.0056633826135274]', 513.5); -insert into credit_card_transaction (time, features, amount) values (157659, '[-0.766915012176013, 1.65810941095098, -2.20100292491025, -0.246884619046052, -0.472517200427092, -1.45627254343434, -0.223736534089503, 1.00315110200219, 0.611621497164623, -2.36505638695177, -0.979797925932203, 0.0818948713568789, -0.879830170176104, -1.30539038393444, -0.136204243327807, -0.0487513144691142, 2.40772721663277, 1.061014723443, 0.24995414382334, -0.575533528285327, 0.21957818327074, 0.50324071851885, 0.015525413458478, -0.202375052408002, -0.150324880057374, -0.607555815736408, -0.503800295003373, -0.176655700919763]', 25.0); -insert into credit_card_transaction (time, features, amount) values (157659, '[-2.86729243066438, 0.607702172395742, -1.54311656498544, 0.71970488741748, -0.482233181388535, 0.204499494885432, -0.430172239036267, 1.67406922039689, -0.969590970810925, -0.853290717655412, -0.292248510897408, 0.987725504776081, -0.0283780201316124, 1.72683865118839, -0.275243807120314, 0.961481825249245, -0.315459373695069, 0.446754440883145, 0.458406229556622, -0.5483134616846, -0.0799156665710331, -1.11372449678703, -0.101893504982621, 0.0705310890160139, -1.16127275795735, -1.30826306705791, -0.541450426343595, -0.253504882654566]', 102.6); -insert into credit_card_transaction (time, features, amount) values (157659, '[-0.538717496528732, 0.497037247301723, 0.678574861145991, -1.66156672531294, 1.35582470242373, -0.824378382058554, 1.54588846887594, -0.533860218763007, 0.114142222333549, -0.413710109051273, 0.410442320047211, -0.232262754628378, -1.35256320792588, 0.275493423859727, -0.801663455465844, 0.310926579720657, -1.49093744802186, 0.552536599983858, -1.12831386911552, -0.255665169044622, 0.252038677323505, 0.99794654015748, -0.408265262271822, -0.403829516815616, 0.231246814594198, -0.387908191550835, -0.363963138761858, -0.33481089709042]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157659, '[1.28868138797952, -1.87745285398862, -0.89979356052631, -0.373122036184729, -1.39458052839306, -0.91918362589843, -0.119944597218343, -0.24001131761432, 1.57950648194834, -0.542047035919234, -0.734635500763708, 0.214412021312011, -0.168677256237429, 0.105188736301048, 1.26772220691624, 0.302431217392923, -0.47286451385324, 0.201804213817699, -0.0565754042736389, 0.608199921604214, 0.411625477866091, 0.45787862405848, -0.159463773342714, 0.127795983631398, -0.498388019500921, 0.661999777707197, -0.114554399600257, 0.0156815597426271]', 400.0); -insert into credit_card_transaction (time, features, amount) values (157659, '[-0.399494835410856, 1.03678213917812, 0.0958452793138646, -0.919340951160011, 1.53262179125972, -0.123531537012885, 1.03494485214295, 0.0125673649789998, -0.777497152791399, -1.09231360828425, 0.581234860664014, 0.565161806922879, 0.520946612139756, -0.879500423824476, -0.928242724237109, 0.596289782032917, -0.0575109390421886, 0.437489196465249, 0.424729097397431, 0.026485214028216, -0.264700237411464, -0.788094069292817, -0.189154496819594, 0.0151889061197037, -0.116856695569056, 0.174762746705519, 0.0539158967715802, 0.140703700454984]', 1.29); -insert into credit_card_transaction (time, features, amount) values (157660, '[-1.9567996593669, -2.61014489166794, 1.33272373896791, -1.01638194532143, 0.49053715865399, -0.609377767688863, 0.071716736356296, -0.0261187425380272, -0.688233454409254, -0.0174830023455464, 0.197270848481793, 0.135105988862823, 0.135958540287801, -0.110333294172564, -0.0261327986481843, -1.13032240766272, -0.934574881359157, 2.64977752159329, -0.839338093193207, 0.677501031001426, 0.229884723910273, 0.29604673555042, 0.724878431810796, -0.426134003251837, 0.142261361839809, -0.597141874309556, -0.142115960786366, -0.0299325237997882]', 321.78); -insert into credit_card_transaction (time, features, amount) values (157660, '[2.09192847571684, -0.0946758072668112, -2.45451002739755, -0.173259692153288, 1.01942073652235, -0.483378422047769, 0.548368189548462, -0.264754665359746, -0.128042967414441, 0.37405293739716, 0.190773391424566, 0.269543868715931, -0.427628256181308, 0.957051225445838, -0.257671975956153, 0.163545488271148, -0.855595560493752, 0.169884936741724, 0.624972171863987, -0.116971736899008, 0.0759643734215985, 0.158294087591208, -0.0657696186901157, -0.0926934922241813, 0.289969275434798, 0.727969117192366, -0.143462014620172, -0.0896026228280068]', 36.7); -insert into credit_card_transaction (time, features, amount) values (157661, '[1.92496176830725, 0.308673497576981, -2.72488000282893, 1.20478745318954, 1.49367033156339, -0.0970418316058132, 0.688096346803086, -0.191729105711688, -0.20027895445151, -0.244098815822883, 0.504211207165045, 0.829453155235187, 0.570107064376773, -0.991268285938651, -1.03823497603221, 0.1954577888838, 0.39177616380819, 0.73100188100781, 0.161882074282815, -0.0059346452102432, 0.0032070607362702, 0.0772601889936939, -0.177371312751213, -0.3073120609512, 0.570127314194052, -0.495001888391882, -0.0131919231316632, -0.0283351288818505]', 72.0); -insert into credit_card_transaction (time, features, amount) values (157661, '[2.04310396825651, -0.0859443838594674, -1.17091417962632, 0.222069200560359, 0.097185342511995, -0.699205323107439, 0.0946682806176633, -0.184407289503525, 0.258221620067478, 0.234019295341422, 0.723036001459005, 1.18190212787914, 0.336335850770012, 0.392804210203451, -0.670174007828493, 0.170237327831798, -0.672222852365139, -0.30703095874152, 0.55423090260773, -0.184710890802614, -0.25542417995737, -0.620554894896932, 0.285097165097284, -0.327772411360968, -0.27546984721082, 0.19733769485619, -0.0729064908898449, -0.0727970843061939]', 1.29); -insert into credit_card_transaction (time, features, amount) values (157662, '[-0.678902755094102, 0.592388492368539, 0.100561205962415, -1.40332108804488, 1.67898871739388, 1.74566201609404, 0.740599839331643, 0.13396285679591, 0.499064022339229, -0.289074302162002, 0.483023610141462, 0.606980436560739, -0.44042658430394, -0.118821931598012, -0.649106157094929, -1.26494395650635, 0.0453481753827441, -0.895894269254039, -0.310048242709214, -0.221182325284272, 0.277358447755035, 1.06572393103763, -0.302255594341194, -0.888293840164624, -0.354553976096486, 0.121208274405332, -0.521254557947981, -0.0645931583109889]', 10.44); -insert into credit_card_transaction (time, features, amount) values (157662, '[-0.155784861380603, -0.014453524776931, 0.648109446414884, -1.04630158196848, 0.514031585861522, 0.298764243143644, 0.345469986911851, 0.210707596451789, 0.199614419128464, -0.809836977320697, 0.537598149506386, 1.20320406735625, 0.933408419800931, -0.153402823057145, -0.448885976553377, 0.512858151528217, -1.05614175203572, 0.273370542841903, 0.176577032873555, 0.149488999169619, -0.0969845931346009, -0.448259430882757, 0.302062651944207, 0.193430129736736, -0.442036587431237, -0.402538634393625, -0.0214182072052525, -0.0131542618320503]', 77.7); -insert into credit_card_transaction (time, features, amount) values (157662, '[2.14364255916549, -0.893865129537971, -0.655476327481577, -0.463836586080127, -0.841514151023904, -0.178681944358383, -0.957572075390224, -0.0693714184127005, -0.0008757656583835, 0.833030353579198, -1.28500043797636, 0.103234640521625, 0.93938707092135, -0.403614458875594, 0.334883657485709, -1.16486027280389, -0.362283847780942, 1.46161290714914, -0.996949775731555, -0.522496056978568, -0.073605417022869, 0.455536053520713, 0.148188823555128, 0.632236642007225, -0.178765618853877, 0.813242635002735, -0.0171298894691852, -0.0436872684495654]', 12.1); -insert into credit_card_transaction (time, features, amount) values (157662, '[-1.90736565426464, 0.67384060201129, -0.152918028105094, -1.5241369471231, 1.68595396552452, 4.28649383843176, -0.03899793397186, 1.26990047620504, 0.0201745479735995, -0.687288009662468, -0.130267154798492, 0.0665532139980587, -0.0349481760360964, 0.274178499755284, 1.47977466989759, 0.163948001003363, -0.460332045625155, 0.0050472781613322, 0.244590625448951, -0.335402788979408, -0.106067870886694, -0.494800653404582, 0.0607691121906984, 0.667957103302721, 0.36208419408435, -0.438986051355533, -0.706788421465791, 0.205657311481346]', 109.22); -insert into credit_card_transaction (time, features, amount) values (157664, '[-0.862387024902042, 1.78470367281811, -1.38775787378779, -1.66026708473102, 1.70641506304972, -0.95413573763879, 1.98703979262836, -0.727195563587107, 0.94144518719367, 1.4911580478853, -1.37360420398336, -0.763227897888498, -0.602794546296498, -0.0215747263190106, 0.0963476394298945, -0.675334286704451, -0.922752038319437, -0.187712852635465, 0.0172104283533561, 0.737292715221469, -0.0642561715728267, 0.642652554241579, -0.31861455430985, 0.0531787821033688, 0.0001807567220916, 0.0656196875104861, 0.585735804463068, 0.121318387442835]', 2.16); -insert into credit_card_transaction (time, features, amount) values (157665, '[2.04817471547879, 0.160891509841538, -1.75975319561615, 0.240847031281068, 0.656705375413303, -0.407588627071841, 0.134090819475397, -0.121984321631118, 0.124731830243019, -0.233330753248871, 1.06997705824216, 1.19995800815063, 0.844771627467875, -0.825597786123648, -0.569307935069556, 0.53989580273333, 0.0935927474354178, 0.160003637859814, 0.42174281232985, -0.0842305360986474, -0.318123549525181, -0.806213849790965, 0.289389090640184, 0.278961984560853, -0.230272669700398, 0.165385894702223, -0.0614547261018728, -0.0411052472494336]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157665, '[1.85870279773918, 0.396051041629609, -0.455366911681645, 3.86098983917909, 0.208507579286698, 0.126162728018291, 0.0131965552961598, 0.0489802730795498, -0.845638070131801, 1.55991100586878, 0.22577243084112, 0.414947272421794, -0.580585720132935, 0.266577297786502, -2.19883837974612, 0.631700207118974, -0.702440354452217, -0.0189354878139345, -1.08856866097233, -0.323787309691886, 0.130189017963616, 0.504362094254044, 0.0845574433770186, 0.0639351766871012, 0.0776383528141651, 0.0730375839484188, -0.032659310900174, -0.0604215347892459]', 7.58); -insert into credit_card_transaction (time, features, amount) values (157666, '[1.95279101351902, -0.443646680213216, -1.64373558608181, 0.157513597855708, 0.319796654027065, -0.200328722480518, 0.0958716466424794, -0.0623234262433549, 0.543482715761223, 0.219799115017581, -0.178400816130077, 0.261489094592664, -0.953867646087732, 0.608799293077844, -0.678692386227105, 0.233118444711131, -0.69303495574473, -0.0104506235005991, 0.797291024078636, -0.123507591532171, -0.231262239014541, -0.717605279304208, 0.104836156578914, -1.10714070345973, -0.161960492044155, 0.322044482786744, -0.0946842408649669, -0.0750659926959481]', 69.64); -insert into credit_card_transaction (time, features, amount) values (157666, '[0.0666260477973693, 0.593815427888797, -0.522878691313413, -0.679975879636316, 0.732897383075077, -1.21219306455882, 1.49501223350433, -0.289458227392707, -0.631534221749399, -0.361204025767523, 0.557276348023702, 0.0202015857971261, -1.46658320951785, 0.895822663843126, -1.35555825630229, -0.392276220018851, -0.342557203264131, -0.0493754067049264, 0.215628991956632, -0.15331249096827, 0.246035914963297, 0.660660434964352, -0.173448608693566, 0.126564700747486, 0.0360134286035453, 0.729353876823891, -0.0760040018886952, 0.0011735561200836]', 49.95); -insert into credit_card_transaction (time, features, amount) values (157667, '[-2.33353507264481, 2.46354962218188, 0.0941195136921072, 4.46483394314277, -0.265535547392461, 0.319256387897496, -0.208615935390274, 0.155277515285382, -2.95938211453577, 1.04504589444477, -1.22265002761061, 0.160343713770289, 1.54656272337205, 1.12680738289013, 0.894257121352872, 0.134212690824433, 0.585336201924697, 0.247568522109529, 1.11462971591331, -0.37267298666156, 1.13845278449457, 0.492590933528634, -0.374825397091449, 0.0436122629170256, 0.633610686193592, 0.67739750885263, -0.582974717540913, -0.165175977580806]', 55.38); -insert into credit_card_transaction (time, features, amount) values (157668, '[2.03804669121107, 0.149228928096936, -1.49356362147525, 0.541991577091293, 0.136141242468747, -1.18376465959481, 0.175941280497561, -0.252148730657828, 0.505357460827131, -0.369960062729377, -0.159077562004647, 0.152705745134623, -0.334666217716109, -0.751982994863708, 0.20138899583308, 0.180483677724108, 0.67865827130496, -0.438075952430741, -0.139525195530629, -0.192007415169572, -0.334124293304863, -0.875054160258706, 0.407086197716554, 1.04365772082047, -0.337475787869709, 0.140677126123062, -0.0640799319838407, -0.0258456228731323]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157669, '[2.30348772822127, -1.1003422751185, -2.6773253235167, -1.63428927304118, -0.0076793156786795, -1.2481723022086, 0.128023315710728, -0.643828712842836, -2.17526438795832, 1.6953077447938, -1.03249807539356, -0.848094200122647, 0.647195121863868, 0.199617782777387, -0.624026683784342, -1.42910298247797, 0.744921928840637, -0.443190944165041, -0.0141116922689533, -0.297007244682514, 0.144357919686483, 0.82706600686136, -0.191150560531695, 0.590109588043703, 0.677329811589187, 0.275917322692467, -0.0807080346350161, -0.0720901555637475]', 75.0); -insert into credit_card_transaction (time, features, amount) values (157669, '[1.91473786768401, -0.0493338141702305, -1.89540357698028, 0.0689704013070788, 1.23065499278398, 1.13876055425523, -0.172044228191091, 0.374879112286872, 0.231875454738994, -0.353585847129736, 1.59432167700619, 1.05129269147745, 0.0388187267979768, -0.588217656042168, 0.334877726145528, -0.351687516401723, 1.01270899353266, -1.17906725069728, -0.707203197243012, -0.235150494224008, -0.242574615962248, -0.509926924150119, 0.386134956007147, -0.821519981542935, -0.481882566963798, 0.268681463861382, -0.0128784758553372, -0.0546758025084535]', 0.99); -insert into credit_card_transaction (time, features, amount) values (157669, '[1.87446856530342, -0.46441843689523, -0.472121973473791, 0.18103869914988, -0.494605836015767, -0.237281592565409, -0.480886140400147, 0.0672599443036567, 1.05899007418193, -0.0889467223184553, 0.75020210451754, 1.14212531307948, 0.124141605150623, 0.263727736684343, 0.425507127067417, 0.449210717218909, -0.967536247730269, 0.509108683604654, 0.187854309406977, -0.126026761734618, -0.0618707295394016, -0.177110991339604, 0.266813923131493, -0.451860693176587, -0.386324119133951, -0.932109986929829, 0.0484066610755568, -0.0323440170864113]', 50.95); -insert into credit_card_transaction (time, features, amount) values (157670, '[2.12279133771394, -1.18741824192205, -0.916483921875039, -1.09236487905358, -0.727711739679387, 0.0764459281895712, -1.08103442973963, 0.0659246517250018, 0.0032208902291789, 0.906362620330379, -0.156255400131866, -0.344783537242717, -0.0507919872810802, -0.270931078890298, -0.405206919807005, 1.68154856766522, -0.483672636320703, -0.25218225156518, 1.13003290229964, 0.0654318639110971, 0.322088813490681, 0.887408335253001, -0.0388214523566199, -1.06834387231041, -0.0628157073385791, -0.0430772833385128, -0.0042268595413406, -0.063204173508402]', 49.99); -insert into credit_card_transaction (time, features, amount) values (157670, '[-2.59576480783823, 2.8840239391573, -2.3126776019042, -0.760320433945951, 0.213651620948756, 1.81649581536989, -3.55896540541555, -8.85262475130317, -0.741416240269013, -1.35215352304068, -0.489738719913259, 1.08574992463212, -1.07560466846554, 2.18203764850392, -0.321870391369415, 0.628842473016798, -0.284181179852542, 1.1275605561027, 0.0483897622914708, 1.53518079653712, -1.88674720866848, 1.85104279840616, 0.664449259513719, -0.268815204921672, -0.831607600369412, -0.242287134379948, 0.498574656340234, 0.372368425344521]', 15.45); -insert into credit_card_transaction (time, features, amount) values (157671, '[-0.0956813316911167, -0.367757271273178, 0.236132981001182, -2.65804257142269, -1.20649595496618, -1.13068285237342, -0.446167242708761, 0.301906524881184, 0.247123113323113, -0.877548922001801, -1.25464054481686, 0.148066269919556, 0.0053011356888609, 0.219864998355756, 0.828511274946982, -1.89657531109896, 0.180259751140201, 1.42362583442616, 0.304961802426908, -0.527425357706104, -0.408399754013747, -0.791635121453671, 0.403884811673834, -0.0966960227895864, -1.13719124258596, -0.610808696584691, 0.0634683348824682, 0.0389644225985704]', 41.06); -insert into credit_card_transaction (time, features, amount) values (157671, '[-1.86488219894914, 1.23613748194336, 1.55203146229971, -0.277503018029693, -1.68020467427744, 0.414109989733868, -1.35741923537803, 1.58293596192924, 0.899501508123272, -1.56880333199636, -1.95541618155083, 1.6023183750899, 1.2427244222821, -0.717529357684178, -2.16123285093702, -0.101621920209923, 0.64694513014031, -0.503990163032675, 0.207679299806106, -0.259278542066298, -0.025948886346506, 0.030922895620315, -0.177984159200742, 0.0824577060844309, 0.612711713176754, 0.696564590661485, -0.432156230597208, -0.188617923395142]', 3.71); -insert into credit_card_transaction (time, features, amount) values (157672, '[2.00553228161842, 0.0070868966527725, -3.65259548241003, -0.203742162034209, 2.88371007913055, 3.06387126009357, -0.407470730758041, 0.787168176369652, 0.573959954868234, -1.0425561174637, 0.458201855114249, -0.123987721389439, -0.470081890499791, -2.42916601060841, 0.0321352652214023, 0.266431399506244, 1.95537235613427, 0.506609128807379, -0.398342592881336, -0.067841254193996, -0.018586847672948, 0.151813633128278, -0.0081306451001703, 0.562138291560673, 0.239086126042579, 0.747061487131281, -0.0184026193243048, -0.0180547635727395]', 12.31); -insert into credit_card_transaction (time, features, amount) values (157672, '[-0.501119701945683, 0.631898598931087, 0.261426345840006, 0.81898535891173, 0.807476569727662, 0.0163751766080137, 1.50818509883941, -0.212048811020143, -0.99179495398615, -0.347735979589194, -0.93995294639717, -0.006084666561543, 0.869016128406528, 0.337219881241216, 0.817204393257627, -0.484879958652308, -0.36580688516666, 0.283787894216577, 0.41421824194594, 0.429927128156805, 0.437560512581943, 1.05161420378429, -0.0122425995554489, 0.54232587914934, 0.293018758630902, -0.293144286742353, 0.112615866328799, 0.173152642655114]', 158.5); -insert into credit_card_transaction (time, features, amount) values (157672, '[0.177812185476632, 1.46402086483703, -2.41533855299721, 0.548454242435985, 0.907647046294263, -1.94616322869331, 0.766631154276994, 0.116071532794883, -0.0094249948102138, -1.75700434669279, 0.0036210606576855, -0.506859554160035, -0.593178329700087, -2.49446747850741, 0.79627149882876, 0.313731670138587, 2.66063662293421, 1.3602437645134, -0.0683051398364217, 0.0029849606116793, 0.0188340227238714, 0.156009308911535, -0.0128163986020703, -0.306026483328676, -0.138182011250051, -0.492175744525951, 0.168295228347058, -0.0357874469552025]', 20.0); -insert into credit_card_transaction (time, features, amount) values (157672, '[-0.984714008596551, 1.56751031976119, -1.34659360423239, 0.932186496465468, 1.5619731259302, -0.202129516421906, 0.964876317929437, 0.303446779651333, -0.989685608936685, -0.441089866550192, 0.537792017461151, 0.349048521469868, -0.0945585411994336, -0.662439489588188, -0.801901696895235, -0.261812157806986, 1.04597684216332, 0.9804587818583, 1.03748134356874, -0.0838336144950998, 0.081395669810669, 0.447138350637323, -0.0206412258029941, 0.108025054320145, 0.155234851373501, -0.407761236733805, 0.0995427684657036, 0.201292004298201]', 16.1); -insert into credit_card_transaction (time, features, amount) values (157673, '[-0.271252199321979, 0.803480528970401, 0.339312365067873, -0.993036392768877, 0.779804591946232, -0.390229098889444, 0.9326941083428, -0.0824337036130174, 0.342150121047779, -0.811070527239764, -1.41191358715847, 0.304282769781088, 0.299826531694597, -0.190595085177309, -0.910852500493808, -0.6199802179378, -0.283804840994717, -0.246043401456233, 0.174958196440685, 0.0212521699194917, 0.120213411956863, 0.712492547992129, -0.301738269516433, 0.649183995098063, -0.0077483684214828, 0.102924365930774, 0.391400113145998, 0.236470496907201]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157673, '[-0.308966639631638, -1.40872178095524, -0.521433406405505, -1.96452516548817, -0.564035272006543, 1.19137991184367, -1.24775422064385, -2.53898718407234, -0.930550087548313, -0.584813358832481, -0.144109497073928, 0.354564613694285, 0.816924593463184, -0.0839757171361925, -1.08355086812859, 2.24730058482718, -0.76715329599421, -0.355362415127438, -0.141825512813973, 1.49539640097667, -0.788734400135575, 0.784697714610051, -0.592602136549449, -0.293926035081469, 1.1089170315443, -0.111220282199828, -0.146147083718468, 0.108102173061073]', 399.0); -insert into credit_card_transaction (time, features, amount) values (157673, '[-0.2383175921796, 0.551722978569067, -0.721888519755237, -2.40560801327523, 0.323621573194478, -0.943134115400195, 0.328054953996721, 0.138674382541974, -1.3751938628724, 0.0109708633360267, -1.20412977253443, -0.24642176715472, 1.40941626022518, -0.0655490438594682, -0.685958598166706, 1.24115934821103, -0.257649430141542, -1.18147828205379, -0.251127628843804, 0.0673948514172616, 0.582465253570036, 1.64412188320386, -0.107894123892428, 0.555038375233325, -0.581955127130999, -0.227846664554553, 0.337196233986138, 0.239471066939677]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157673, '[2.02733083232336, 0.472540119973513, -2.49909513199218, 0.595279769559177, 0.670424724319215, -1.32398899994942, 0.21240769510333, -0.198721762173749, 0.391219659381951, -1.0064326585289, 1.47347467682044, -0.0723978308964411, -0.848235290020886, -2.19794608656666, 0.480786051529934, 1.09826616855598, 1.44843783671005, 1.96794307367733, -0.283040482073196, -0.183546836461205, 0.118972959031012, 0.473359732833711, -0.0899100621352102, -0.572288530117652, 0.243524799222156, -0.0976006654556805, 0.0106651446114544, -0.0072909786351266]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157674, '[-0.309060267470029, 1.40998804346571, -0.674802194830392, -0.826464566512148, 1.27308883545268, -0.444900952041377, 1.22664047897167, -0.357044211671821, 0.416302982399144, 0.0606290087698471, -0.727247656947094, 0.239219136408626, 1.12149426481706, -1.63690077262252, -0.205240668057125, 0.224180893099813, 0.0642954790335486, -0.352067182983902, -0.186528397092605, 0.396806760393592, -0.452377650507409, -0.826049342792934, 0.0277310671309127, 0.0917732201887042, -0.271723828858603, 0.110899403364912, 0.149591080916801, -0.0226316518603748]', 10.76); -insert into credit_card_transaction (time, features, amount) values (157674, '[1.79012266278276, -0.676921329244653, -1.40738218221979, -0.10049693190564, 0.537654789886719, 1.07062950945947, -0.264393915983108, 0.340203741043811, 0.930112260600053, -0.189151878545155, 0.739739623780943, 1.06863004378843, -0.564679386284994, 0.442783800471179, -0.117090281782435, -0.975382654142485, 0.273966009506599, -1.2301065076826, -0.203450383688819, -0.203481730838543, -0.0408136794039017, 0.0483738927955093, 0.157158489169186, -1.62587796029627, -0.264068945587754, 0.0179205357942158, 0.0054895478935852, -0.072756306716618]', 70.0); -insert into credit_card_transaction (time, features, amount) values (157675, '[-0.999120757496684, 0.33152744973671, 2.37847185055143, -0.704231858794303, -0.137632522636944, 1.35792088902069, -0.245055118411236, 0.484115233576339, 1.36945492230933, -1.06648172069811, -2.4246690433919, 0.33485920584977, 0.397434948615654, -1.49925829613848, -1.9101083786839, -0.156274875845579, -0.141511411827937, -0.110376653386028, 0.675050143296975, 0.112131386868392, -0.219962073864621, -0.145418099079366, -0.446534467167365, 0.116279437710557, 0.563633592063988, 0.70855665509494, 0.175310618175618, 0.109633450314114]', 23.27); -insert into credit_card_transaction (time, features, amount) values (157675, '[2.0304377142877, -1.41477713947346, -0.25903707134831, -1.17903472604184, -0.946317219385446, 1.00061424458798, -1.66715848128407, 0.29955333760075, 0.254010524064565, 0.781880588790689, 0.0481709786595812, 0.474727259731515, 1.72594701531832, -0.984881838997233, -0.0765731306232688, 2.14774777302976, -0.833583330444377, 0.0676312102237355, 0.858257028127041, 0.272345802905228, 0.454295899969593, 1.25694910062995, 0.0132059006657339, -0.280174883787165, -0.270952807161646, -0.0892141912019501, 0.0415328397080597, -0.0311625185996005]', 76.0); -insert into credit_card_transaction (time, features, amount) values (157675, '[2.12264482184131, -0.678740227022123, -1.05568228588984, -0.534485241748948, -0.897008993793866, -1.04365353618049, -0.895160818776703, -0.145750317348732, 0.0778511248864166, 0.0763734628989035, -0.303660247551544, -0.791394485163903, 0.0689112455356252, -2.08011692844464, 0.388627944326622, 1.60905088018795, 1.43918498708263, -0.529993883680797, 0.128261484400098, 0.0239760026349763, 0.246097426609964, 0.800440812696472, 0.109213635295877, -0.113855335450338, -0.169836820298458, -0.0848353024173462, 0.030943893607115, -0.0114638765188567]', 21.99); -insert into credit_card_transaction (time, features, amount) values (157675, '[1.25738607770783, -1.29260115196379, -3.22749020870842, 0.315520354300516, 0.671152232786627, -1.1507446947082, 1.68824376778646, -0.777889908238491, -0.0868015817041932, -0.231069023926174, -0.855760992723037, 0.676351025069804, 0.982964320579347, 0.742552658332368, -0.0877854130292076, -0.890234187740606, -0.236943864219838, -0.501607557726412, 0.167703332569304, 0.825103607664235, 0.55628119504328, 0.750961721329793, -0.642426748823071, 0.624327789779637, 0.673763407883049, 0.388715763678561, -0.191759113813372, -0.0007451054957198]', 484.0); -insert into credit_card_transaction (time, features, amount) values (157677, '[2.20105339451337, -0.963279089455179, -2.79248687914929, -1.93965348419363, 1.97958446680884, 3.13262435263015, -0.844146857732279, 0.695954207281895, -0.634243222529645, 0.808695051449459, 0.0648416225096195, -0.413990889130083, -0.0847463254003369, 0.170565689831317, 0.101520462835394, 0.550523496552585, 0.307036072719545, -1.9955337740532, 0.700393138125186, 0.0301484386094088, 0.0261588158206121, -0.0075976667386555, 0.229173154036864, 0.712063278795965, 0.0236787144634407, -0.258540944938817, -0.0213502786505819, -0.0692189199705032]', 15.27); -insert into credit_card_transaction (time, features, amount) values (157677, '[-1.03468314179644, 1.12458635099361, 0.18547384505549, -0.65481970320812, 0.605563910604064, -1.04087157747382, 1.42362613744374, -1.06360088065318, 1.48186258006072, 1.53581185157729, -0.909805106781413, -1.62689023797206, -2.49061273132976, -0.114108911533506, 1.04740100412106, -0.715824957737676, -0.643625714952924, 0.245933609089612, 0.0205159220166089, 0.0044864241323308, 0.25961802057698, 1.14778729624083, -0.206160246789341, -0.0459455336265481, -0.620283460249351, -0.314296758864627, -1.04463567602418, -0.26698846629468]', 5.35); -insert into credit_card_transaction (time, features, amount) values (157677, '[-2.46602084188543, 0.365723836271079, -2.30764260745798, -0.674368364383094, 1.01115842968562, -0.81897883400823, 1.80355231398438, 0.0620849442454661, -1.22065163483867, -0.79602351024818, -1.66869247696958, 0.349921892681564, 1.18920821934105, 0.988393454596161, -0.559883289196942, -0.203888976718025, -0.217321788687955, -0.440729857765989, 0.264828423235882, -0.525086575607077, 0.176500837880444, 0.733180271609274, -1.25388318491376, 0.276956931686362, 0.852186166428873, 1.02716117049555, 0.227956062865521, -0.532015077707887]', 272.06); -insert into credit_card_transaction (time, features, amount) values (157678, '[1.82186028194341, -0.475662654961392, -2.22583472408642, 0.181785080811274, 0.639870312294077, -0.573706321453177, 0.664033577364905, -0.383928673782837, 0.604239078891329, -0.202434955872931, -1.37575162360916, 0.28451823716913, 0.383417799546334, 0.508343291916738, 0.472608268238342, -0.358855882877338, -0.6248861321501, -0.023829956158792, 0.284247492490685, 0.142566118194225, 0.154674094376264, 0.244923812684508, -0.190888394420315, 0.059833210715731, 0.441620969366864, -0.527119234872603, -0.0433197593798314, -0.0300237462207368]', 169.43); -insert into credit_card_transaction (time, features, amount) values (157678, '[2.31202561817784, -1.43008187190908, -1.20891062947418, -1.61985678933988, -1.07513640536755, -0.531039007752024, -1.10615124517161, -0.13871647842916, -1.05917680067469, 1.60326176406705, -1.48243248764555, -1.51490719220309, -0.643148729886864, -0.196704397908706, -0.0335873360107412, -0.461923055781142, 0.45428201030941, 0.118643480079771, -0.0006470356543341, -0.458251153374536, -0.201594624709316, -0.163630838616283, 0.232024347937327, 0.425256114582135, -0.149498661972579, -0.175277515428491, -0.0056173654975395, -0.048045932013292]', 25.0); -insert into credit_card_transaction (time, features, amount) values (157679, '[2.20112909336745, -0.671994779399452, -1.56060650598055, -1.02066990214565, -0.165324456280594, -0.861499661758035, -0.233625889151165, -0.413477930348158, -0.748462267577397, 0.819564035196897, -0.583569100220292, 0.0252543571183071, 1.67915136623939, -0.274034906742261, 0.232529082197224, 0.904766285315661, -0.0303924449195594, -1.36931320807433, 0.494652766574586, 0.146747338706366, 0.445574837917572, 1.2815932381753, -0.0428471427190114, 0.676814548688191, 0.288769753895877, 0.0376195241325399, -0.0399049520300122, -0.0530318451753298]', 40.0); -insert into credit_card_transaction (time, features, amount) values (157679, '[-0.406861632704899, 1.10220169200469, -0.163043851415343, -0.661329325297498, 1.02786186290888, -0.968687671861143, 0.954720798735252, -0.158791795883965, -0.249384945471057, -0.781910763051732, -0.592107956210078, -0.6143390453661, -0.278095878217383, -0.957396974501664, 0.508244372519525, 0.481660377253925, 0.308440184253551, 0.499830392681288, -0.577671483960768, 0.059481737552085, 0.155641381215255, 0.498982403643476, -0.32859453268426, 0.688342290723948, 0.404862498063351, 0.673761844550901, 0.0536463672545795, 0.10084281463515]', 1.5); -insert into credit_card_transaction (time, features, amount) values (157680, '[-0.365258778754858, 1.09728199885184, -0.372540084111885, -1.06162026009461, 0.797928615474386, -0.200416513681132, 0.868955043094719, 0.0573705218747252, 0.238613491055849, 0.385692613538063, -0.251298058189558, 0.162960457538497, -0.489465178570015, 0.222562619918289, -0.927959870474759, 0.408291156254974, -1.0368217693522, 0.141706729388943, 0.555428694950459, 0.220457608847449, -0.34902776292063, -0.750426240223662, -0.0470001451392357, -1.12898625261378, -0.292612186439175, 0.199217963684531, 0.454366054245722, 0.193341298948532]', 11.99); -insert into credit_card_transaction (time, features, amount) values (157680, '[1.98748459885835, -0.434937303357228, -0.43341360311259, -0.0383420335854398, -0.523485718247296, -0.192562136340337, -0.637596396099461, 0.115756207070385, 1.14372335228563, -0.0343432858817313, 0.562351696642149, 0.929150227432415, -0.238828896944658, 0.18321496789006, 0.0899702366987793, 0.480247175915945, -0.821162619106004, 0.299516950287604, 0.403448718212386, -0.226331055578317, -0.169646031086914, -0.366638281020488, 0.342715598198295, -0.501028277311011, -0.502246487965202, -0.271937122006483, 0.0073283650548859, -0.0524708628887952]', 0.85); -insert into credit_card_transaction (time, features, amount) values (157681, '[2.08335683194978, -0.760338518270083, -0.371132090587612, -0.630822813589613, -1.3671809627947, -1.70339374271083, -0.508651960074439, -0.336673061775539, -0.365120189346657, 0.747818588413896, 0.260146545325104, -0.0770551286316976, 0.0642745890328091, -0.0940110683821129, 0.212964182981821, 0.90547226398528, 0.465813899807659, -2.16925578439858, 0.412732159942784, -0.0241646354436584, -0.185053891904558, -0.649661538271287, 0.579829694705514, 0.87068513905863, -0.681755054997547, -0.748243257534186, -0.0151101008788047, -0.0312777487143151]', 31.95); -insert into credit_card_transaction (time, features, amount) values (157682, '[0.0548147668971734, 0.825636497730477, 0.221687065106836, -0.61480115061977, 0.43311391019309, -1.05478616463575, 0.971882266465343, -0.168226855354062, 0.0452097219706133, -0.394859199061759, -1.14789246664647, -0.18925791226864, -0.487394675747123, 0.207573131665409, -0.33511851176873, -0.0257877595878572, -0.432272753596909, -0.636294099209896, -0.0246573610170176, -0.0684436629534681, -0.276508015776315, -0.641373787315523, 0.0566548487015433, -0.131552031704074, -0.487460608298759, 0.149207347522262, 0.243716617644422, 0.094767943885897]', 2.69); -insert into credit_card_transaction (time, features, amount) values (157682, '[1.97815112277616, -0.24728564812647, -2.13688593485985, 0.0920593681792395, 0.891761011954678, -0.0849775237016036, 0.444558484459444, -0.197438271892641, 0.0650292261484287, 0.216567992098539, 0.237830701218962, 1.06522121128682, 0.540828413389754, 0.450929826651405, -1.05398962261634, -0.192009139397746, -0.608695084413949, -0.205417182587548, 0.701731255892005, -0.0079903924132831, 0.0105629178345177, 0.0626463306121614, -0.0546621656227497, -0.034918420975161, 0.253965989808443, 0.552405424313774, -0.11182523678573, -0.0759104676085585]', 69.95); -insert into credit_card_transaction (time, features, amount) values (157682, '[1.98583259518274, -0.259051352902079, -0.692348311932495, 0.361386052723655, -0.430187227578805, -0.941094018329212, -0.108181136733131, -0.291570204601908, 0.69826882035104, 0.0005145104525627, -0.626561186482978, 0.969559024312258, 1.25942662543269, -0.181713860593075, 0.175809847585325, 0.0772102693876024, -0.46290452188066, -0.531296305237457, -0.100887214246555, -0.0762455840461724, 0.0250749381393894, 0.243929235310853, 0.184098376326277, 0.123152522278537, -0.233393907004938, 0.548058544265512, -0.0537910669822665, -0.0496008488653154]', 31.35); -insert into credit_card_transaction (time, features, amount) values (157683, '[-3.16328184013955, 3.30039052844423, -2.77108528214923, -0.774925331364977, -0.12228461688672, 1.72993972423332, -3.94206270118423, -8.40276042188811, -0.722225194451139, -1.26939693037988, -0.617674334146216, 1.25513464917228, -1.01420387800534, 2.42874856807674, -0.349008499899204, 0.725585693395977, -0.123937983598227, 1.15485998360559, 0.0138188905995267, 1.58077264938073, -1.86600751904257, 1.82392818504639, 0.800225135943605, -0.27872286542676, -0.740382785431581, -0.235398596748473, 0.458054920068973, 0.375028578541356]', 0.77); -insert into credit_card_transaction (time, features, amount) values (157683, '[2.15141771776466, -0.572687933540587, -2.19490001110557, -2.27449752038785, 0.235487027659246, -1.14793810822466, 0.205527924172439, -0.407403624405586, 1.92451536766178, -1.18073467514183, -1.01956015373171, 0.645776862256435, 0.38041217529306, 0.484741927744875, 1.63248818661826, -0.892661783497144, -0.497274476588846, 0.385455342637485, 1.12514563405842, -0.092617328475195, 0.241415021656626, 0.884928358638999, -0.14581791913272, 0.147068591709136, 0.552138765196511, -0.605838871616567, 0.0136012174868917, -0.0527951405655972]', 33.54); -insert into credit_card_transaction (time, features, amount) values (157684, '[-0.768054680867553, 0.0544425442061756, 1.11236705232835, -2.31840678155671, -0.717744301700017, -0.0757738689131079, -0.35279141220918, 0.115016295618592, -2.66113341120407, 1.18682487069941, 0.425232653218657, -0.414970093981548, 0.759419015772579, -0.301353667246672, -0.647906344331232, -0.785350288542679, 0.565545413217258, 0.56250487331489, 1.10099706167775, -0.231786203981882, -0.102711243122863, 0.100135871623601, -0.428667642712239, -0.386025736665794, 0.501307542474657, 0.0559295274635997, -0.497363476696936, -0.240561050421874]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157684, '[-0.831138228215365, 1.14852007511413, 0.571786141489337, 0.178836874627494, 1.57174575602333, -1.24903023653625, 1.66338741423807, -0.366841436620378, -1.29988414641891, -0.607598854896702, -0.897159907506269, -0.239456854267468, -0.104188317524345, 0.698709530477251, -0.004005074812894, -0.532818716750015, -0.390070859711166, -0.327872503534486, -0.357254136361973, -0.0332765109940069, 0.153395034330664, 0.343013699027422, -0.597100448017311, -0.076525364097104, 1.27645122145004, -0.342032665942805, -0.0129367764806701, 0.0433930007748864]', 9.9); -insert into credit_card_transaction (time, features, amount) values (157684, '[-0.0250774700344481, 0.851425305288206, -0.946901059815186, -0.0645370016103051, 0.335786276738546, -0.541042636445767, 0.29537895482137, 0.48269266514075, -0.0008526268067678, -0.953783465388788, -0.0052319131367756, -0.472561116629127, -2.14555664892262, -0.375987891069494, -1.20760673911253, 0.179255438421801, 0.894662839785164, 0.994980110131881, 0.567165265951081, -0.326458078516148, 0.21987387570077, 0.666558953715943, -0.152096474022838, -0.535522341965088, -0.444908437928033, 0.69131410042931, -0.0687392946558427, 0.0064094603276568]', 12.36); -insert into credit_card_transaction (time, features, amount) values (157687, '[-0.370194207833387, 1.27909213989218, 0.945288137363863, 2.83067592394674, 1.37941087888421, 1.16744982708709, 0.857187084483609, 0.27411306059047, -1.79202538449822, 0.861824140274844, -0.528946980317489, -0.26900603137309, -0.522116760445392, 0.164956595912568, -2.2372637814448, 0.613902617378961, -0.844956908419263, 0.454526026728535, -0.429974301437446, -0.087295194272989, 0.179749206194917, 0.520532003388364, -0.304826470346445, 0.18575176099613, 0.0110417580682294, 0.118954084264323, 0.117320690806495, 0.151824908667014]', 18.9); -insert into credit_card_transaction (time, features, amount) values (157688, '[1.90351822823552, -0.174347941074012, -1.9565640939925, 0.403944756157283, 0.281224002868475, -0.787302383100343, 0.139341069407735, -0.175846993248174, 1.0817296429073, -0.922491702073184, -0.718960420910587, -0.0596976599110652, -0.529626021162883, -1.51300169992354, -8.66407752302123e-05, 0.141296953794059, 1.12224317650492, 0.246586305806003, 0.171273375756559, -0.0253883487909423, -0.234627900521977, -0.632259699414274, 0.135908874516382, 0.438758782112635, -0.0597170130518357, -0.11831946976014, -0.0267978184381739, -0.0013352219699531]', 82.61); -insert into credit_card_transaction (time, features, amount) values (157688, '[1.87799654523266, -0.473803808836681, -0.66857116800568, 0.298629813234874, -0.278078652370265, -0.121642974434615, -0.373670479726424, -0.102155331636264, 1.03035871665514, -0.184689214484112, -0.848368220097319, 1.0418687554502, 1.76631717017878, -0.331297315294243, 0.901283988764296, 0.337129265866278, -0.89284775594053, 0.251560821698716, -0.28689677835906, 0.0758677742036345, 0.252609760104486, 0.769788906716097, 0.0535174484528977, 0.531526164267654, -0.0583329769790265, -0.274533806722435, 0.0240981308406351, -0.0156128519274166]', 84.25); -insert into credit_card_transaction (time, features, amount) values (157688, '[-0.497431419039788, 0.678158594150144, -1.52093761765639, -1.00057109348182, -0.741601751122412, -0.8880497645695, 0.653593600814509, 0.429175601746033, -2.04751794857141, 0.220195098849719, 0.198467265200732, 0.287960706676123, -0.505580363749793, 1.28022325503367, -1.34127503651789, -1.89669886757904, 0.413207003209608, 1.27917851518974, -0.162331104460548, -0.813198949777903, -0.0048115234563083, 0.276262681274769, 0.0646805409594056, 0.0510604957659754, -0.429059736311705, 0.750026861225639, -0.282958609902457, -0.101002720882118]', 126.0); -insert into credit_card_transaction (time, features, amount) values (157690, '[2.10569868219245, -0.0967341893236175, -1.64637823073991, -0.0712262205681997, 0.753233496880488, 0.162771060999685, 0.0411018812322155, -0.055833507931254, 0.254505475721204, 0.21895283587267, 0.0753605084485017, 1.04057323138976, 0.77393034560624, 0.276187834182368, -0.601383565555542, 0.405819598685524, -0.988483696543147, -0.0579625329510764, 0.84989447180861, -0.109865865366591, -0.30743447433671, -0.794361214071003, 0.223205182004414, -0.335628695742678, -0.146090365282371, 0.209131844522297, -0.0771602400682416, -0.0727125420356728]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157691, '[-3.30902736815795, -0.953121412523735, -0.448618081451785, 3.5023951721798, 2.14139189337699, -1.37620845509008, 0.488301380445685, -0.265554628402911, -0.939523909408261, 1.80528296431614, -1.43812541897342, -0.492360425384969, -0.255901876217212, 0.161015764691412, -1.2096456937157, 0.788597852789847, -0.889976251973906, -0.704400025320373, -1.42680914839219, -1.07671823617417, -0.281753058007557, -0.158238551218931, -0.379411208693719, 0.0446265889886949, -1.26913373260076, -0.572879453061116, -1.16291772745959, -0.0036116114707116]', 13.25); -insert into credit_card_transaction (time, features, amount) values (157691, '[-0.0126004838572641, 0.73265898823155, 0.277481257823411, -0.555236383221767, 0.386345733850758, -1.18033219686887, 0.940785865562634, -0.165603213793502, 0.0611968178410471, -0.390086281953597, -1.03551882213013, -0.217852090642622, -0.669022442977876, 0.251836072596179, -0.326387728710055, -0.0642738287234888, -0.365673685253362, -0.663584046836528, -0.0835716088750195, -0.0525552170138068, -0.258908609117544, -0.629871016249881, 0.105406562237157, 0.019805478196573, -0.508187704649129, 0.139853899653454, 0.238327664123373, 0.0977955842172623]', 8.99); -insert into credit_card_transaction (time, features, amount) values (157691, '[0.0072074549137557, 0.506412857381131, -1.187777952089, -1.7201221079315, 2.95558446318271, 3.384701432179, 0.323179659950747, 0.927407014119902, -0.163996549189058, -0.386041544504147, -0.199912764343157, 0.0340563096040058, -0.373073285963966, 0.355618969599158, 0.0425347460166415, -0.155055439291267, -0.482053766676739, -0.840693748107076, -0.206669805212565, 0.0358000410316673, -0.26221323015063, -0.718377299056042, 0.119794752199664, 0.688138959149158, -0.457919325901241, 0.161878548498329, 0.26346451928513, 0.0910398510019692]', 3.99); -insert into credit_card_transaction (time, features, amount) values (157692, '[-0.183148622511039, 0.422058503815131, -0.516862849799115, -0.383962158478075, 0.151738777463743, -0.822269913840261, 1.65138899283605, -0.276715199828938, 0.211899129402947, -1.75552713758327, -0.737879873289243, -0.0095584536728181, 0.0745717919974543, -1.75412351984956, -0.570204375017391, 0.116325118786952, 0.993393888293093, 0.300789476296047, -0.0874035566704642, 0.294071528076684, -0.073486376957242, -0.332171784408773, 0.354501767760105, -0.25990384183988, -0.208296139769667, -0.162983285771797, 0.0041081635285877, 0.0895003573280478]', 199.84); -insert into credit_card_transaction (time, features, amount) values (157693, '[1.91233520948932, -0.324378484828003, 0.164227910469996, 0.734400107600484, -1.19095366311683, -1.11349783853967, -0.524113727540421, -0.167828630380022, 1.2869620015841, -0.190254858100758, -0.0525446793200477, 1.20689500909608, 0.759856854735814, -0.303850812650683, 0.320556360171216, -0.225328133898422, -0.218471042023068, -0.193916287281662, -0.575815821194575, -0.199342982001773, 0.261943335858652, 1.04885485994248, 0.21988385835477, 0.978375380296514, -0.189089862695267, -0.273237983507367, 0.0481668651611472, -0.0254678895942394]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157693, '[0.125100991330419, 0.950423596874578, -1.17866956423642, -0.172309894546629, 0.327005313828198, -0.908479920173051, 0.537657262722291, 0.304716455930898, -0.292246357853814, -0.95961065030589, 0.625694749541833, 0.0958006427745616, -0.765713934822204, -0.186833306118324, 0.0565127869880954, 0.539591403875453, 0.262691903845127, 1.419044357893, 0.155611662665759, -0.199875566720641, 0.369074488441783, 0.935643468552348, -0.0567391482100247, -0.430663423295707, -0.269341650630469, -0.148048808969989, -0.0892946229079656, -0.0593834545086696]', 42.81); -insert into credit_card_transaction (time, features, amount) values (157694, '[1.8824171634852, 0.28181077542448, -0.658378959822149, 3.77873271941921, 0.289269831813546, 0.33174689991353, -0.0824723599738074, 0.150085705177846, -0.617053992964987, 1.59836123512556, -0.36930754539064, -0.42565261984391, -1.83244552615348, 0.50593257542553, -2.02303895760946, 0.814524675848935, -0.776755179203492, 0.278722612394197, -0.924761156263669, -0.390652969232265, 0.0891931321422175, 0.318661261565337, 0.0474246692619383, -0.385665076256504, 0.0870804730004726, 0.102833912486932, -0.0422883043322641, -0.0670574842254138]', 9.85); -insert into credit_card_transaction (time, features, amount) values (157695, '[-2.80215418212591, -2.7869047683594, 3.05095292866455, 5.77386384485884, 0.543900927419285, 0.991193080329851, -1.06331364091894, 0.337127485308067, 0.211592026075768, 1.36870691945478, -2.00112935232413, -0.515544643619281, -0.163465836607423, -1.43403075730352, -0.880210876288146, -0.35056250383487, 0.518871086612674, 0.574731152620137, 1.63838276079299, 0.25950095398015, 0.0675068180942435, 1.0299061746425, 1.43175029691381, 0.0626079452730134, -0.145390386130068, 0.560129173734992, 0.116706439391599, 0.0672966499526748]', 225.11); -insert into credit_card_transaction (time, features, amount) values (157695, '[-1.20052857055263, 2.06956117066816, 1.54249848003991, 4.06951578807093, 1.25860204261309, 2.03720406920658, 0.552052338677142, -3.01239496262701, -1.31567440802053, 2.3349350253327, -1.34324328146888, -0.645751421787565, 0.628918275042762, -0.762605829356297, -0.0092085669427935, -0.861022299008366, 0.22885864455477, -0.0800248266179748, 1.61102522817546, -0.17411614573861, 2.20908849297382, -0.27551614012747, -0.186757237077152, 0.280788458678256, 0.6167612575981, 0.569937993867196, -0.631744374284451, -0.61848721961052]', 26.47); -insert into credit_card_transaction (time, features, amount) values (157695, '[-0.747566889023111, -0.295613044590678, 0.882569257490564, -0.706035712156273, 0.821425378758939, -0.590230373512158, -0.114434501357268, 0.112892588435563, 0.234506406967808, -0.313818526216938, 0.403412207573683, 0.695627020972726, -0.0336128745771185, 0.0433901711592438, -0.62721702731617, 0.63183043531218, -0.967881890778821, 0.163616578316934, 0.129621126114372, -0.23752482801854, -0.08164455039653, -0.216467221982534, 0.174573672927888, -0.390367704142342, -1.56236256646698, 0.0477902022226219, 0.153212355226033, 0.238237867403128]', 28.98); -insert into credit_card_transaction (time, features, amount) values (157696, '[2.06417245105617, 0.0262741413560445, -1.03884773307114, 0.4079913068747, -0.057143436448956, -1.19535537979282, 0.25232488558759, -0.392823157803556, 0.387873931111568, 0.0440001964101087, -0.560664490661123, 0.979468251405491, 1.07381064942554, 0.0744500547386839, -0.0717344300594716, -0.155365494320654, -0.34265608761729, -0.996828203769396, 0.136225708011739, -0.161735394712951, -0.277599973794466, -0.61413263534856, 0.329974491975154, 0.0739573445065143, -0.265017247208815, 0.192089639971415, -0.0639380514763603, -0.0578317776844607]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157696, '[2.18011199902051, -0.967724081051841, -0.748450150433237, -0.480115308871446, -1.02003401418616, -0.78621548538612, -0.702128549715161, -0.149157424291228, 0.460352447510598, 0.570241443648345, -1.39586858789816, -0.45004450292577, -0.878760249058134, -0.570342484716198, -1.87734640083947, 0.102914335800314, 0.981895667468984, -2.11510668706233, 1.34123896003801, -0.156751045388834, -0.180766077125796, -0.228780803673372, 0.253092159972917, 0.0459570283641028, -0.0770882699502772, -0.322389684373911, -0.0041442743389422, -0.0617400328564477]', 0.2); -insert into credit_card_transaction (time, features, amount) values (157696, '[-1.29366289121131, 0.587144129527716, -1.35042368691883, 0.648442940807596, 1.89618071818851, -1.08198367652383, 1.63132894798224, -0.346551603364527, -0.14479418821806, -0.39343575126975, -0.791160942723461, -0.358248354941365, -0.315744544147362, -1.28862979086232, -0.746758716501068, -0.26220060990532, 0.764263179280418, 0.208719689162283, -0.547925953517981, -0.124505503733382, -0.0166214136605226, 0.540370064764475, 0.357230254063475, 0.540021236971326, -0.25432266022078, -0.741160901511905, -0.23563190886077, -0.0223299672875634]', 63.63); -insert into credit_card_transaction (time, features, amount) values (157696, '[1.93841191654503, -0.0320575662446708, -1.67337056033162, 1.45690097664205, 0.202849628664248, -1.25844508173853, 0.621296659079062, -0.371486643161649, 0.430576415026785, 0.288463450609331, -1.27738247303727, -0.511866166776465, -1.79594635881729, 0.847395927243455, -0.390959755352812, -0.604372103063895, -0.0900317558060284, -0.374819511558848, -0.160802636804536, -0.292130069530574, 0.0574357532573195, 0.1992480283501, -0.0333390889117323, 0.0121749010430797, 0.401185168579891, -0.495352328221495, -0.0374353128509507, -0.0559118612493898]', 59.0); -insert into credit_card_transaction (time, features, amount) values (157696, '[1.33473632275155, -1.58763016713364, -1.02569410650842, 0.25379149555934, -0.60670918266514, 0.418695737500983, -0.323887159554186, 0.112219099472646, 0.830097954281041, 0.0616573781019407, 0.485783072472291, 0.63753336878135, 0.0017892716595311, 0.206937164805428, 0.370246493890324, 0.887087221608036, -1.00079171386902, 0.749801976115915, -0.0851027861020506, 0.552745197711853, 0.405513593254625, 0.450194208084305, -0.134891957970788, 0.283332471483262, -0.451711809042609, 0.595549365392638, -0.10862618303707, 0.0028521698388558]', 352.32); -insert into credit_card_transaction (time, features, amount) values (157696, '[2.04927003795927, 0.0645459871560661, -1.78718097904547, 0.253351380515144, 0.534806548058547, -0.440764642262327, 0.0391582806908901, -0.0434188425893922, 0.333500167462273, -0.19235193646676, 0.834973459983887, 0.467074741710023, -0.533356824572028, -0.551618580822264, -0.418262060509893, 0.604388127883473, 0.172301639328543, 0.328836269841847, 0.431394192637855, -0.174735227201026, -0.334626914625222, -0.918488216701021, 0.306889095554294, 0.241179411844752, -0.27649559602302, 0.170119700673963, -0.070256665391431, -0.0442543947274936]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157697, '[2.24170373812058, -1.52863710501241, -3.4612833931453, -2.5600712995897, 1.81676128890144, 2.91799989848321, -0.781818025309443, 0.494429218049466, -1.97660239439925, 1.66089819522385, -0.231850586381931, -0.820594427585329, 0.104303441874373, 0.250024620372057, -0.353087035685302, -1.36766811713977, 0.720521730222131, -0.58281455413751, -0.089708244745716, -0.271189305390558, -0.0092914716432653, 0.291892348510361, -0.0199695342571815, 0.73671683485852, 0.402799228519784, 0.125049499438836, -0.0375678278414892, -0.0730665772868435]', 73.98); -insert into credit_card_transaction (time, features, amount) values (157697, '[1.86144855003728, -0.501020929125723, 0.0549596879548766, 1.40273427561333, -0.999425755305492, -0.268013523351534, -0.820440233388664, 0.164347168969064, 1.48562432407977, 0.188318603823692, -1.46196729472281, -0.727340119860169, -1.79644608778964, 0.170632510266604, 0.871014666036483, 0.704854834050186, -0.709423486621322, 0.556651276208876, -0.612475852108047, -0.29092200430964, 0.0433333602301394, 0.114506287833258, 0.249650990037826, -0.207080312716461, -0.400872871230871, -0.745224754823563, 0.0580520191097033, -0.018903233862605]', 45.0); -insert into credit_card_transaction (time, features, amount) values (157699, '[2.06595479339357, 0.0258352306608864, -1.04936762856547, 0.402022192854845, -0.0445321214318404, -1.18081073680204, 0.252006807035553, -0.391389697539309, 0.389111429711548, 0.043941196376033, -0.58271399489019, 0.972864564057108, 1.08150507818577, 0.0722835449537861, -0.0702447135701681, -0.148147453356016, -0.352031438005429, -0.98898269971448, 0.145730000014999, -0.160706986392169, -0.27922424291845, -0.618519771489969, 0.326810791699705, 0.0487322437381688, -0.261533481723199, 0.193646095162812, -0.0639498189254104, -0.0580810858959237]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157699, '[-0.961170410577063, 1.46309028803722, 1.55268031820307, 0.706805935270864, 0.0646371213022817, 0.387172836699019, 0.112217299785725, 0.612269678541625, -0.534185124288492, -0.56721604421424, -1.15682279530021, 0.301710940783101, 0.835034758440593, 0.0899018287136239, 0.778124678165192, 0.0454175960602848, -0.207433175509048, 0.161854416392188, 0.750948178679016, 0.135036325322671, -0.207667716509745, -0.553304877168348, -0.190083724179341, 0.531734095918253, 0.422462340667078, -0.663253222126027, 0.234961328071738, 0.0923940242556723]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157699, '[-0.279928388173511, 0.619999449424073, 1.0263955819205, -0.774108084310589, 0.755108665204555, 0.163028610367474, 0.838642625359413, -0.290017832467131, 0.653121895901266, -0.718816860546924, -2.02594691432994, 0.208482450565325, 0.984389432875468, -0.768979064259398, -0.574619970502369, -0.229136135852393, -0.855672775632481, 0.332483267000258, 0.299359255306081, -0.0113001160687074, 0.18462568676788, 0.976093228855646, -0.540673687770616, -0.927323527217863, 0.144865132719321, -0.128357957598767, -0.116259451364477, -0.0727088097768788]', 11.85); -insert into credit_card_transaction (time, features, amount) values (157699, '[2.09160914546749, -1.00995910849633, 0.170358701536119, -0.511143276446138, -1.31283938833623, 0.213132734141014, -1.50670033281606, 0.123578973573852, 0.236397032186797, 0.774325899300191, -0.952294583534851, 0.487494504679989, 1.7394447803671, -0.766720773362034, 1.05419985509144, -0.617592834846138, -0.644177350116239, 1.58405288384592, -1.34422109876055, -0.474510581153769, -0.134397849745711, 0.250838889663636, 0.355760431002774, 0.633134365127095, -0.643505559237741, 0.587137754355221, 0.030688734760933, -0.0222320919878286]', 7.42); -insert into credit_card_transaction (time, features, amount) values (157699, '[0.445502455063417, 0.441206899343513, -1.79335577647796, -1.40354797680064, 2.47354163318364, 3.91100368654346, -1.21346890922391, -1.76790562414076, -0.302014202034587, -0.970749621933665, -0.16486069812016, 0.467767686109843, -0.577183678525144, 0.919730943022661, 0.101808491480805, 0.139439772650569, -0.379625121407643, -0.955146047631811, -0.578596722466404, 0.512102064758497, -1.57179172519841, -0.594307856310312, 0.221080387498554, 0.683637229979168, 0.444506583525832, 0.240451151026066, -0.0241958254843618, 0.132578177675354]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157700, '[-0.778314826642336, 1.72993024502851, -0.258396338933288, -0.194311254990339, -0.235396433746089, -1.46162203083859, 0.280118106071631, -1.5696202959191, -0.292711537286667, -0.400571359085391, -0.0960459829911923, 1.16535437263189, 1.05619839496666, 0.609733662953219, 0.185129994042777, -0.6273019192378, 0.0783806681844065, -0.212377280792267, -0.342990248790862, -0.413938503064859, 2.01081816497982, 1.07253788522846, 0.245392046393652, 0.974014134536094, -0.806681699383522, -0.266518540670567, 0.463797042020522, 0.28760665923028]', 3.98); -insert into credit_card_transaction (time, features, amount) values (157700, '[-0.78919879993444, -0.416736346487244, -0.198520979218314, 0.295601470193659, 1.62379745452543, -1.43349595465227, 0.838249395999532, -0.295617070261255, -0.400770095019371, -0.528221660735976, -0.391921175426066, 0.687325631876845, 0.908058193895269, 0.466426331278157, 0.520970267329246, -1.262946574866, 0.0951342866481577, -0.213945184783983, 0.795968265045825, 0.515790162774528, 0.439677766775589, 0.966468728902323, 0.33650485198642, 1.12358219507074, -0.408354231592567, -0.547478581691296, 0.181221703758972, 0.269179293032383]', 107.82); -insert into credit_card_transaction (time, features, amount) values (157700, '[0.0011514535944527, 0.818830970460008, -0.519976151425248, -0.699751825899174, 1.47175169238694, 0.677274378599747, 0.67065343686339, 0.380221061881251, 0.0491134954626667, -0.956094893359527, -0.116736608730502, -0.224154958305256, -0.757007880549536, -0.786365964447261, 0.656533441434471, -0.575715704100711, 1.29931824790608, -1.57553761614036, -1.37576763279459, -0.125113324344339, -0.260968811700973, -0.527005321306448, 0.199131813851019, -0.46956343661467, -0.676830470551731, 0.21234956953088, 0.270672353221625, 0.0717518660745382]', 3.58); -insert into credit_card_transaction (time, features, amount) values (157702, '[1.43561776429555, -1.3229850129845, -0.755773567009584, 0.581365373818886, -1.03826421150534, -0.639218106554318, -0.17035808527814, -0.133353080917126, 1.49274302682945, -0.311605000441295, -1.08763506331906, -0.0711767339866791, -0.66714000262842, 0.248882390087451, 1.21212917781835, 0.281200129825784, -0.662662353415927, 0.587721112530432, -0.363962529740911, 0.314137403959905, 0.385398648755634, 0.600442790365861, -0.143226882583135, -0.117903415977569, -0.182467443650411, -0.583288776218958, -0.002304274966521, 0.0153667326756732]', 300.0); -insert into credit_card_transaction (time, features, amount) values (157704, '[1.7385205854353, -0.892089846408635, -0.61171539902473, 0.214020009687275, -0.64809072813626, -0.130109607815714, -0.459933969339803, -0.0454743695308479, 1.40011554525562, -0.302020291231469, -0.966504956944146, 0.74423598986218, 0.829572661663642, -0.337060700238174, 0.50280920824159, 0.143860563204753, -0.555491381748058, 0.14197372420986, -0.118810916136672, 0.156232377859632, 0.25915801212865, 0.676207405921907, 0.0247114373201877, 0.730089253803407, -0.16529347165433, 0.0790929660675291, -0.0114539596994003, -0.0099156687582736]', 150.0); -insert into credit_card_transaction (time, features, amount) values (157704, '[1.99804907676376, -0.416684210336494, -0.365259376344715, 0.377805253207431, -0.534316282093149, -0.144293305533666, -0.665363366175666, 0.0025426026534573, 1.16150414882564, -0.0183673557570947, -0.93648091444336, 0.635485381423196, 0.79948513793616, -0.402962625971965, 0.3256125017865, 0.328423299664652, -0.558640380306779, -0.0319153926594563, -0.242588483289539, -0.116674521623804, 0.160746311744555, 0.676485992930321, 0.185419554057296, 0.807383586807175, -0.235660871090008, 0.533024124211108, -0.0203608390533247, -0.0384520533541354]', 11.5); -insert into credit_card_transaction (time, features, amount) values (157704, '[-0.426755527272792, 0.87375703451161, -0.370965525053918, -0.589003899281591, 0.724109827828868, -0.723269029563194, 0.874320693865869, -0.13848863585707, 0.182387427672555, 0.343861184576477, 0.391221322670837, -0.0387654246370595, -1.08177341278863, 0.641555855325174, -0.0087081119607021, -0.22147022619051, -0.783225973136488, 0.773809334859463, 0.412408848820866, -0.125923283487632, 0.34690611903494, 1.38592177108063, -0.0552657054979906, -0.38776313500652, -0.846908272920435, -0.283997506332344, -0.19544936037924, -0.220173256802794]', 0.74); -insert into credit_card_transaction (time, features, amount) values (157704, '[2.0651932618778, -1.1133051640027, -0.758239557258063, -0.603335436981097, -0.83828658474467, 0.201902871002653, -1.10136637624334, 0.181306293096023, -0.0379267757307635, 1.02569626044458, 0.0044176153622693, -0.121250948052904, -0.808075289134137, 0.158309806432348, -0.172617925133499, -0.800373864732649, -0.578523463849313, 2.01955161007762, -0.521029078351097, -0.565877911842106, -0.236844112114906, -0.226516812459746, 0.238495073906172, 0.302224807766046, -0.417963928207025, 0.604016645213068, -0.0377025351992958, -0.0518885790613157]', 36.0); -insert into credit_card_transaction (time, features, amount) values (157704, '[-0.103933265119944, 1.209354932723, -0.184922929079553, -0.372333131208527, 0.459848115677374, -1.58685114955114, 1.19871437637383, -0.450368832499871, -0.0750559885514598, -0.958610109709599, -0.0902023786748899, 0.0879390448586052, 0.259108626471398, -0.98088058817972, 0.389091016453283, 0.0617705455616881, 0.393985628250334, 0.429674156855048, -0.787203815563598, -0.186923315765165, 0.337512051836843, 0.999047912364985, -0.236832940804817, 0.402073846782658, -0.0679695428062781, -0.231883308856569, -0.190325710529559, 0.0610671054534179]', 18.0); -insert into credit_card_transaction (time, features, amount) values (157705, '[-4.31903759961312, -4.70952140601699, 1.12861385827668, 0.165809424471442, 4.34356761635449, -1.10312534185627, -1.32330525494534, 0.129066260018699, 1.13256615166833, -0.750491642893958, -0.29813060910041, 0.0749898227300266, -0.394691095355937, -2.08329138349009, -1.57193690191482, 0.601866778905089, -0.100920505177039, 1.28916411282091, 0.0480174010419019, 0.7866861825676, 0.196861701589146, 0.36435493800736, 0.0714996313938601, -0.362333540144417, 1.1795929661975, 0.7653815873745, -0.79849911820282, 0.471025790525291]', 207.2); -insert into credit_card_transaction (time, features, amount) values (157706, '[-0.172747946874229, -0.686847233914274, 1.0979329031162, -2.7476623710753, -0.710979464903696, 0.0741178072164428, -0.409460945238638, 0.174863203750307, -2.10976277740161, 0.867873859150692, 0.361301831485438, -0.93862112277913, -0.549630150619263, -0.276569335761426, -1.03611097637925, -0.265241679910156, 0.187724736737298, 0.717054061915971, -0.126908933986245, -0.298806242899799, 0.0046350612985474, 0.292609682787268, 0.0099350907963515, 0.657560582393858, -0.425619050528873, -0.266950985248151, 0.147780630978695, 0.157570204601165]', 43.0); -insert into credit_card_transaction (time, features, amount) values (157707, '[-1.15127124158764, 1.66458167394539, 0.0036623437285402, 0.281059733350196, 0.766176110074641, -0.974487004641719, 1.3108231084057, -0.110230358770562, -0.34067950817555, 0.0981539401246805, -1.04580893562627, 0.0807023459056578, -0.177251947197928, 0.279813333502844, -0.71955623944703, -0.741838638083559, -0.106741312707914, -0.592163145852269, -0.330201816277138, -0.0049480675168586, -0.0506040216688384, 0.10542159431311, -0.590988271766406, -0.0094311608269884, 1.4745663927463, -0.377401698361993, -0.309128908701368, -0.324334208567247]', 8.97); -insert into credit_card_transaction (time, features, amount) values (157708, '[1.97527625198455, -0.846033656631418, 0.384854217421799, 0.461664204970547, -1.1624911894556, 0.570286567300143, -1.42871781139834, 0.311990905828702, 2.22191319028075, -0.210037546057482, -1.99492577390665, 0.343047323309382, 0.12381058831076, -0.997185684025171, -0.364299356008724, 0.405655211477404, -0.437684380170837, 0.226548018695815, 0.126005918082996, -0.201311797992715, 0.0826914072643253, 0.677138702809898, 0.136258248725671, -0.641000214449053, -0.389197549764031, 0.738866747537939, 0.0292859102214093, -0.0447056383655524]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157708, '[2.06184246253878, -0.307976232912722, -2.78654770060288, -0.777438171502785, 2.49992452962194, 3.16343650481725, -0.400265931460217, 0.715920455141033, 0.448457069112648, 0.0332289061611847, 0.0620942339066804, 0.284944315835478, -0.144093725987975, 0.69457080684155, 1.16583098500761, -0.286162234455405, -0.586906588784058, -0.180099963058657, -0.35555288268917, -0.171442519139442, 0.241950060121122, 0.745452959879616, 0.0403287392996927, 0.737381238667803, 0.30397657803223, -0.0875596152439227, -0.0006145205229113, -0.0654411548550868]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157709, '[1.39734563916074, -1.49666653917257, -0.926199928524948, 0.525728520799198, -0.850909798735179, -0.138555206704582, -0.26685816855018, -0.023938809782132, 1.17816731927994, -0.0525822713403886, -1.18375816544728, -0.402384860858606, -0.74122517503701, 0.178581124984375, 1.07883934888212, 0.703397934828545, -0.685042233601466, 0.380328547428183, -0.42274061021906, 0.447771864063222, 0.349256391843608, 0.319950582970188, -0.0783430406347819, 0.61035570287275, -0.435303728163138, 0.482615948332673, -0.100702291734328, 0.0131511758867353]', 334.6); -insert into credit_card_transaction (time, features, amount) values (157710, '[2.23340713356783, -1.37192147951363, -0.662185960901715, -1.44407956818064, -1.43500442015814, -0.859502029018155, -1.07227743807364, -0.290630911200932, -1.25809865207345, 1.51204896355531, -0.784033967454927, -0.179726731694636, 1.4968017288422, -0.69797890293753, -0.1939576162424, -0.609519131014492, 0.469094690059027, -0.267291828769043, -0.27401873807399, -0.335068902867859, -0.126926224341511, 0.177992740497453, 0.229271651581459, -0.0028900285861614, -0.240273710372358, -0.180751787218209, 0.0272440540426017, -0.0408419406325964]', 37.5); -insert into credit_card_transaction (time, features, amount) values (157710, '[1.85452083383711, -0.367229672173789, -0.558217212120127, 1.33917841078138, -0.283128657092972, 0.139370569410365, -0.424068366305265, 0.106446578742232, 0.858487586130464, 0.280552945921937, 0.182855318680134, 0.944450381959201, -0.22312532242186, 0.0478652831009078, -0.996492409062232, 0.0758328868565778, -0.663522768999519, 0.576392185708508, -0.0762727275393594, -0.191770733428559, 0.262117485114304, 0.95653564613792, -0.0491150454648378, -0.379492678973047, 0.157120066641214, -0.42739859258935, 0.042324453427808, -0.04737974698263]', 44.9); -insert into credit_card_transaction (time, features, amount) values (157710, '[-0.608063721908058, 0.912658989359966, -1.68698466830791, -0.564921834768725, -0.637321632710033, 0.243791128636799, 2.74647743630849, -0.469374315370517, -0.086448018987414, -1.28725128196881, -1.36157896621658, -0.483980069363268, 0.610044103662388, -1.12179091923494, 0.582617926322752, 0.755898538812674, -0.0710757460065687, 0.987920106520247, -0.260664740090848, -0.413269369007386, 0.0956233176669785, 0.768612521503877, -0.166612682928383, -1.04555472127441, 0.197047268656897, -0.14606771205411, -0.195285666404242, -0.383768351332183]', 413.35); -insert into credit_card_transaction (time, features, amount) values (157711, '[1.79060927605258, -0.824626627039168, -0.865917190186543, 0.0593884655954448, -0.27868277420771, 0.315084217011918, -0.505078132646384, 0.179579729708479, 0.892411692830389, 0.129949155600898, 0.222490317106021, 0.466814111042066, -0.534066282682201, 0.2575576340882, -0.0028567739821765, 0.868357420215412, -0.958437692105656, 0.34433087643255, 0.473005535827133, 0.0623647849020547, -0.196232031434245, -0.834103924999991, 0.292884659055228, 0.0641609509919477, -0.641114450737523, 0.208286826622184, -0.0757212673419488, -0.0342823253482439]', 125.0); -insert into credit_card_transaction (time, features, amount) values (157711, '[1.74875641304087, -0.246317377803323, -1.68177109880674, 1.39865404499842, 0.265813314546957, -0.846160902738432, 0.65625034802818, -0.270986067387164, 0.0234580983533103, 0.390881552808123, 0.689536727549109, 0.690268603022208, -1.00964229258842, 0.895489604908673, -1.13696356557025, -0.520512204403745, -0.304995946477436, -0.0862909072981619, 0.0004766380394439, -0.0932346926990085, 0.171824048462299, 0.384562417920369, -0.101023210021308, 0.0113124810225169, 0.350266467128189, -0.522651514896705, -0.0452836003006522, -0.051998269987168]', 127.95); -insert into credit_card_transaction (time, features, amount) values (157711, '[2.06290940705931, -0.0985073059880559, -1.0746602463899, 0.424728512536093, -0.21086073160664, -1.23633508011534, 0.135467223548292, -0.294969951159633, 0.648673869006551, 0.0945891140263695, -0.854399467747339, 0.063420287986235, -0.648607000104597, 0.417232525936087, 0.117244314898733, -0.0745703815737302, -0.244229578582521, -0.785508254889115, 0.147854764196914, -0.27209158146865, -0.297403599398062, -0.755194705224479, 0.350648591297059, 0.026799041861862, -0.323296181699123, 0.197861583694769, -0.0751979158080538, -0.0615309766170867]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157711, '[2.01469705680187, -0.0822841976412569, -2.06152853530467, -0.0010730450306624, 0.357811866172648, -1.48654202579575, 0.68098509760149, -0.412160117626251, 0.0728540232536272, 0.195227874227898, 1.04494421308875, 0.504948037007703, -1.12521918830388, 1.21392985109342, -0.183097468845714, -0.485913916504491, -0.360351800404257, -0.0518389907986588, 0.286273256842784, -0.240041823051097, 0.219247260541673, 0.638572335051831, -0.0531043384039009, 0.0536513585829779, 0.339733673069798, 0.220614263234906, -0.0983463906170769, -0.0853045674918219]', 34.36); -insert into credit_card_transaction (time, features, amount) values (157711, '[-3.41224398629134, -1.15634281487342, -1.1205957337612, -0.69389202939277, -1.773805847031, -0.94935266737923, -1.32371444761529, 1.38071046304581, -0.953248914776966, -0.547431335206752, -1.68187956043691, -0.267408074185896, -0.191121431983989, 0.778995155445901, -0.452838870960759, 1.36880023809223, 1.15791831104715, -1.5421865482288, 1.23568931295594, -0.801838038511645, -0.0341809209545198, -0.545396052728094, -0.713613503038132, -0.0061310096297611, -1.23002879473872, -0.636972710381375, -0.197637834622837, -0.651053013080145]', 171.88); -insert into credit_card_transaction (time, features, amount) values (157712, '[0.0989804200521075, 0.853935639147031, -0.236748881500504, -1.03244010873371, 1.22347408047963, 0.0052854001696519, 0.947374030212105, -0.0304612684121577, -0.364118609574942, -0.269466042620061, -0.278048124214595, 0.916028378088138, 1.18237770942887, 0.0243347766881615, -1.1153730129135, 0.454286229560289, -1.21473713886705, 0.0682362047219116, 0.714442535680621, 0.0808983492522834, -0.287335225251765, -0.627481003337142, -0.125146296898898, -1.36496809782038, -0.302565519024166, 0.202264965204935, 0.248370739635226, 0.0755224212851905]', 2.69); -insert into credit_card_transaction (time, features, amount) values (157714, '[0.799779680799791, -3.23074821302674, -2.28827118797305, -0.432111858440381, -0.93011288573827, 0.0287034662815749, 0.372309467041956, -0.42399801937249, -0.322418073218563, 0.413262899668769, -1.37974737180012, -0.267197050486103, 1.46891159565811, -0.39543282007967, -0.0222218945499173, 1.07631048062601, -0.0624082406389561, -0.798928566142645, 0.47905229608856, 1.62047576291256, 0.993055037648376, 1.30520536588664, -0.845388765729923, 0.193618863485148, 0.171818739730658, 0.176384445243742, -0.15874447596759, 0.069465861141501]', 770.0); -insert into credit_card_transaction (time, features, amount) values (157715, '[-1.15151070369599, -0.261184827920678, -0.54378669207494, -0.949367828432265, -0.220211373747866, -0.457553307770774, 0.392175117118435, 0.212560057251552, -1.38168995534741, 0.37997212568231, 0.149402385483674, 0.591435861213132, 0.678457976847136, 0.549668547885028, -0.476683180184847, -1.62122837242952, -0.295232680743798, 2.08670492351661, -0.327476871922351, -0.426557273072765, 0.129674271633178, 0.897669401514398, -0.283329037528044, -0.345531298927138, -0.412491704871043, -0.0617587000550677, 0.371075362656271, 0.0273624101654262]', 153.0); -insert into credit_card_transaction (time, features, amount) values (157716, '[2.13960676437663, 0.116314882509173, -2.2819265844949, -0.0810395758204253, 0.780268441848252, -1.2559407469731, 0.748974820294992, -0.496697118637002, 0.191627186788527, 0.0042763925631347, -0.697814341080745, 0.216595363613753, -0.0213330778164765, 0.790909074054887, 0.467679897828941, -0.641676011049803, -0.267535820278356, -0.565824539282567, 0.0917940032598002, -0.210624964856565, 0.141256955030142, 0.524243514598024, -0.017205946916704, 0.662285358564918, 0.460442001483553, 0.216937072860783, -0.0880022269442688, -0.0732120136568121]', 5.39); -insert into credit_card_transaction (time, features, amount) values (157716, '[-0.687395606131064, -0.811675380751586, 1.96335985136443, -2.49551595277461, -1.08395152683164, -0.558470787697042, -0.319757055166589, 0.0239113583875154, -1.9842499166027, 0.514947782574436, -1.30669011925027, -1.68552629451437, -0.523964589558547, -0.502899145340056, -0.0520431138770475, -0.248509036206257, 0.429806543402249, 0.160811730261178, -0.0538654149151179, -0.129093071018592, -0.359877068987999, -0.912692432213343, 0.0477705694209291, -0.125178925383502, 0.199419520983958, -0.344678143816341, 0.0272673024529501, 0.0726550050875739]', 77.58); -insert into credit_card_transaction (time, features, amount) values (157717, '[2.05486050579718, 0.608076882322144, -3.17165341934081, 0.607542320367241, 1.27546110085412, -1.27431158894089, 0.676767124479248, -0.28872995640852, -0.16685232294003, -0.87156134900345, 1.7361261023187, 0.143819087736308, -0.795832813327849, -2.11951531861391, -0.603184155860302, 0.478242839221899, 2.02264315294918, 1.00410596120624, -0.0943829193737678, -0.153632704118881, -0.015600559170337, 0.109013569114515, -0.0383344695606118, 0.521952099439397, 0.335767226064341, 0.666045537228504, -0.085322148836183, -0.0242474384588215]', 0.76); -insert into credit_card_transaction (time, features, amount) values (157718, '[2.16196377374032, -1.4400880269279, -1.32130950188601, -1.6702221988234, -0.979168406378975, -0.725135505574236, -0.744821420680758, -0.218022576862253, -1.76248322081587, 1.74926473957811, 0.609433797135966, -0.245613014986551, 0.21860596828053, 0.0800327582767899, -0.684628808297289, -0.374112064338889, 0.201473937162067, 0.0517300210665242, 0.307962485896333, -0.307618793782886, -0.345554440726133, -0.743668220021808, 0.275319264420758, -0.458215897296709, -0.35406018325631, -0.42570115101492, -0.0229948358790974, -0.0541570166511318]', 81.5); -insert into credit_card_transaction (time, features, amount) values (157719, '[-1.74480963314594, 1.12726528430504, 1.09339226637976, -0.836972192575929, 0.0770859331943493, 0.72414609078766, -0.575297902802208, 0.0673251672315034, 0.0064165241038514, -1.17401423913389, 0.525389633115017, 0.412649204532315, 0.0773802499643181, -1.16002150261714, 0.00369476765225, 1.38484404901185, 0.120386476087222, 1.30701852894999, -0.11005286556072, -0.127813990336697, 0.729634494678331, -0.427830768772551, -0.26300066131953, 0.133098437885287, 0.336508329003728, 0.469959801403511, 0.0852398532309527, 0.0573786524842632]', 27.02); -insert into credit_card_transaction (time, features, amount) values (157719, '[-0.621228353327562, 0.624285992459337, 1.40357257893024, -0.188062673974394, 0.762374543008539, -0.598681506226526, 0.460633794708798, -0.25527526139679, 0.0129298142927818, -0.863764865688883, 0.0524628174940379, 0.547316935854133, 1.42623370880741, -1.87387754478618, 0.453129739791528, 0.343257295132107, 0.427527456785175, 0.0390628398482318, 0.0294508887580651, 0.138188538767803, -0.213793104385074, -0.382271377209789, -0.02378105518954, 1.08981290907663, -0.663834862340947, 0.125313910780929, -0.134568347558121, -0.0230695956062728]', 7.5); -insert into credit_card_transaction (time, features, amount) values (157720, '[1.87534467196814, -0.386283525782356, -1.73251581845083, 0.564615543003386, 0.00078828664008, -1.38584969024051, 0.616833862423922, -0.462968354299756, 0.456580455626643, 0.0760778997072881, -0.976862974506888, 0.0399588558403184, -0.698534820557059, 0.555526913628406, -0.369302212248358, -0.530012881497882, -0.0303145275859608, -0.756133405018857, 0.163803364331775, -0.0529892035259458, 0.0252536741780427, 0.0110866789883752, -0.01139968605374, 0.0974125841804097, 0.117138482703166, 0.548415462399308, -0.121336716684905, -0.0587772356392768]', 114.99); -insert into credit_card_transaction (time, features, amount) values (157720, '[-0.137070397494505, 1.25698306906897, -0.822171092975724, -0.0507160720804286, 0.498625466200844, -1.40223614741898, 0.839519597149465, 0.0057310439489969, -0.53563836934527, -1.30220621077778, -0.376733780561397, 0.71488289694574, 1.6049256330661, -0.89988367398027, 0.478850845857217, 0.114826762717223, 0.600108245416873, 0.598087809678427, -0.207522455345316, -0.0461676360383316, 0.385814581558305, 1.13069404737389, -0.112240056504673, 0.015275852447655, -0.303029101762543, -0.163807832594741, 0.0242145500945038, 0.0630719288032126]', 31.35); -insert into credit_card_transaction (time, features, amount) values (157721, '[-1.63625299258691, 0.18503739257352, 0.630537397018246, 0.342683922397841, 3.05213921295319, 0.944062070973113, 2.13470692271031, -1.04603666123174, -0.232853622191206, 1.65431531065051, 1.40933146862519, -0.429179045224098, -0.88915230197759, -0.164246412962473, 1.04559726919722, -1.76384070132233, -0.232887162383348, -0.885468461010331, 0.323687933577685, -0.0809489242731169, -0.172936767851691, 0.869627246708934, -0.280258508832121, -1.63249946894961, 0.986196885860962, -0.225896634445978, -1.20041479355825, -0.69416222803821]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157721, '[2.35224064673288, -1.24037467615084, -1.3148670520734, -1.75256118002705, -0.621643905937809, -0.16410659540082, -0.976440352585635, -0.223861532002158, -1.40291655909312, 1.52811722297215, -1.37001896173841, -0.324703648573353, 1.86838678825219, -0.704246399702155, -0.226962866015586, -0.520779340370145, 0.226069139015708, -0.143013760719467, 0.0638645446621194, -0.315189119534527, -0.199750330303654, -0.0074321677632379, 0.169072197896752, 0.043259563711516, -0.0250523177470883, -0.152650500287121, 0.0149259061887248, -0.0491188837030023]', 15.0); -insert into credit_card_transaction (time, features, amount) values (157722, '[1.96612703219513, -0.253117465158608, -0.900693154517135, 0.138114281612753, -0.351624445304147, -0.32944868351956, -0.677134280490194, 0.212898699560324, 1.21981683998678, -0.502937296029852, 1.06255855136034, 0.194328068382722, -1.45382274336648, -0.827850694646634, 0.300911725673378, 0.886717056639332, 0.269383643435912, 0.95683251264678, 0.147620682377368, -0.237755602273712, -0.232869634876307, -0.639475941132792, 0.419241966330101, 0.592417743229822, -0.562535830679615, -0.333907151781833, 0.0074331860198138, -0.0157852338409259]', 0.69); -insert into credit_card_transaction (time, features, amount) values (157722, '[1.95375607836766, 0.208453312769648, -1.38612953073745, 0.762022764930532, -0.226580458208283, -1.95441439845862, 0.316022890373539, -0.440065071390843, 0.501610081971117, -0.535540136948992, 0.546542253716424, 0.431528432416829, -0.0236207837854936, -0.798231176974282, 0.877639497850422, -0.0849552462026133, 0.84652490413895, 0.153834193265087, -0.859052061640282, -0.195836123234694, 0.265465312759295, 0.915349515684248, 0.0776750935802523, 0.803664389673934, 0.119128893702822, -0.155292044684752, 0.001039654412365, -0.0172745351522763]', 19.89); -insert into credit_card_transaction (time, features, amount) values (157723, '[1.88306046955227, -0.142990985836102, -0.24634313570694, 1.18354323212451, -0.287394228437906, 0.0042976561488086, -0.405181766596472, 0.0493816253524111, 0.509614968574173, 0.284344795506559, 0.686133511252082, 1.60096000434168, 1.18420653539479, -0.067904883853454, -0.365663834377753, 0.609023892298469, -1.09161337575391, 0.325901154568324, -0.0634538563040106, -0.115409496495687, -0.111626716315311, -0.221475587175289, 0.282086983367242, -0.377408422015035, -0.333193008279494, -0.945847537368155, 0.0569227736079488, -0.0309590263476874]', 30.0); -insert into credit_card_transaction (time, features, amount) values (157724, '[-2.60358387513266, -0.169809858854303, -2.33526433253578, 0.090731200255946, -0.0903069094103162, -0.620193663359932, 2.24707625757752, -0.460744914136078, -0.492196569237174, 0.81591512685564, 1.03441930448471, 0.732297276928022, 0.657380500257113, 0.896921654903982, 0.856432775557493, -1.67446008643761, 0.68919577795076, 0.169969270707623, 3.69560303475718, -0.464350760990591, -0.0381503117327855, 1.50279391273233, 0.416231898221532, -0.183821737121722, 0.64549520214581, 1.53625234150466, 0.154956667416565, 0.851587915478829]', 291.85); -insert into credit_card_transaction (time, features, amount) values (157724, '[0.723360752807003, -2.5006202500231, -1.1272152166997, 0.906035703967983, -1.25003730663717, -0.0107589032435551, 0.154625195446812, -0.0647829644728568, 0.817117518756416, -0.0127280791944832, 0.482318179552464, 0.511091711191271, -0.391017689336516, 0.391254497037432, 0.325454421233024, 0.918887684982675, -0.98758000000924, 0.937779728883236, -0.264996163739257, 1.10162581431703, 0.605630955457955, 0.352784547002129, -0.436919060781049, -0.283796328404269, -0.534874213647396, 0.289655548216429, -0.144085425228715, 0.0543768383394672]', 656.0); -insert into credit_card_transaction (time, features, amount) values (157725, '[1.97245874637588, -0.311235658811216, -1.13765858487174, 0.385527717274655, -0.246557106389888, -0.875436518945476, -0.004623364600778, -0.0730387120821265, 0.599334852411939, 0.266414118645752, 0.674123090070554, 0.183700143770359, -1.99069223219973, 0.829735061147462, -0.675110329327211, -0.0590788516441056, -0.242419820694527, -0.281789626339758, 0.399815628301293, -0.316908337738648, -0.198612595258991, -0.553933597218353, 0.29739483161382, -0.0180660779202193, -0.319900024206561, 0.261274573246603, -0.0890224826893526, -0.074460103514258]', 18.58); -insert into credit_card_transaction (time, features, amount) values (157725, '[-0.363514016478533, 0.177053591125749, 0.0119787509115585, -0.654651934101109, 1.74636972698075, -0.577205226160921, 0.732924569627344, -0.147999997205572, -0.328573023544414, -0.678551327187185, -1.4310647524126, 0.634034242041797, 1.50822815607622, -0.188387541197768, -0.684226452633179, -0.102837961548682, -0.634986148957864, -0.644916980359248, 0.312134555344841, 0.170493961997501, -0.15719425672895, -0.537560578490608, 0.0416626985177572, 0.129975425106479, -0.113123378375355, 0.231346216192709, -0.0254380704660875, 0.0552388238530175]', 19.24); -insert into credit_card_transaction (time, features, amount) values (157726, '[0.878917111334939, -2.03105550284133, -1.0214159002434, 1.84564504009851, -0.889114340972146, 0.367653194121688, 0.220444743696283, 0.125665856615481, 1.1612700663397, -0.0401190716268564, -0.163421181559374, 0.358867873321331, -2.02238933237572, 0.408486005834388, -1.57356771772049, -0.0353815386718897, -0.238734131927209, -0.0330241836447003, 0.396363947137648, 0.681179274924865, -0.188443387922137, -1.56621113018766, -0.0531936586490342, -0.504442290001158, -0.578608602432217, -1.1495294333512, -0.0588114995148, 0.0441367849168055]', 538.34); -insert into credit_card_transaction (time, features, amount) values (157726, '[1.91326975684577, 0.380030166067447, -0.015331785212037, 3.68769972344405, 0.218804311904375, 0.820744149532908, -0.46075938563668, 0.130471223516256, -0.480682277600088, 1.33704065314851, -1.47307500188708, 0.354497904649734, 1.46298044027489, -0.542150052295379, -0.699154114868896, 1.20037593508322, -1.10887513397289, 0.0158273540369675, -1.6223648785, -0.170714747967421, 0.192106576834552, 0.719308000405804, 0.142393587394244, 0.491913339925366, -0.0711378521400837, 0.0524469483587269, 0.0172914589640989, -0.0272715204093887]', 0.0); -insert into credit_card_transaction (time, features, amount) values (157729, '[-0.135079150460308, -0.312016260053282, 0.32433692486917, -1.99219567343341, 0.0253562877594597, -0.638739490716042, -0.304824885852845, 0.217916859014027, -0.58002394823955, -0.592081314606204, 0.413093287112477, -1.47092519501279, -1.71797833081587, -1.76140179604005, -0.844481461544482, 2.33758961879167, 0.749342245065009, 0.477205584569342, -0.0770147909790259, 0.0236968959713333, 0.291533244084363, 0.60327816471401, -0.204558674856077, -0.656885219622128, 0.127082276128294, -0.160031518660253, -0.0348545419555524, -0.0287506589618432]', 29.95); -insert into credit_card_transaction (time, features, amount) values (157729, '[-1.18220190362248, -0.0257817403316293, 3.18345036000015, 0.534384530963497, -1.40506692714005, 1.40711225131491, -0.93655540513724, 0.490005511322857, 0.903806171820324, 0.991590472112133, -1.8486838999968, -0.628378535219499, -1.10835989254774, -1.5796298923857, -1.08481573031768, -2.40679428713002, 0.737113749818529, 1.72873040730758, -0.0377727446071612, -0.0096650774240008, -0.401191505256539, 0.195966139211129, -0.298086923915537, 1.04636675893324, 0.477508551473099, -0.21721721020614, 0.502342147650274, 0.114366489452585]', 33.0); -insert into credit_card_transaction (time, features, amount) values (157729, '[1.86066292512071, -0.060755652031458, -1.15116404660628, 1.10595588795016, 0.597370028072106, 0.484111521979414, -0.0562541298916691, 0.148761300708121, 0.350064269840274, 0.176097055722756, -0.174499668337228, 0.316006448366575, -0.260018955524417, 0.587528898130697, 1.46145696582153, -0.837498533998299, 0.232027835375126, -1.41997535424651, -1.75208375550648, -0.358817633771942, 0.267541085459971, 0.964837804430686, 0.149570845986861, -1.04992465275647, -0.061440261679628, -0.434968541876182, 0.0604239207426233, -0.0565229157493051]', 16.5); -insert into credit_card_transaction (time, features, amount) values (157729, '[0.0430874744276437, 0.539609416337611, -0.206477371587916, 0.626103030723981, 0.0535734494235362, 0.420719466519524, 0.0194679208874651, 0.667442584700973, 0.375197638166617, -0.537318696250242, -0.240778798205031, 0.886039532380885, -0.736713495098328, 0.139043945391565, -2.53904541056196, -0.364136969855616, -0.175893336013086, 0.483131627821184, -0.234845531635576, -0.363992028753882, 0.460313492158909, 1.49047034113996, -0.0307372184666412, 0.733725597282153, -0.251439728448248, -0.461292835372154, -0.0205447788505751, -0.0465251563198618]', 33.72); -insert into credit_card_transaction (time, features, amount) values (157729, '[2.05392096730951, -0.485047366996594, -0.421359083552135, -0.567622981936313, -0.788849048074937, -0.850626070675346, -0.576219174661075, -0.17757858193835, 1.27368729638622, -0.286011765480416, -0.534563377854391, 0.894949803577948, 1.21925877666629, -0.290118178572024, 1.027042043393, 0.262284908789234, -0.557635011113767, -0.176165265043644, -0.0678702266938465, -0.111311705226173, 0.17856957630193, 0.755374978682321, 0.18581094850823, 0.021985553249536, -0.358174437579049, 0.905651567245641, -0.0422885503453461, -0.0541647381111306]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157729, '[1.99046452117127, -1.55935315707384, 0.700413255597818, 0.039152107808816, -1.93450523802281, 0.909402373194253, -2.03394680766219, 0.429783747591807, 1.56562500166477, 0.458970546925944, -2.09209777217274, 0.311779096581483, 0.023306107902371, -1.45718615019637, -1.58093429602757, -1.60340142061484, 0.337737270295003, 1.32106370468724, -0.499558191726185, -0.579002925987237, -0.296019127949799, 0.11348467052891, 0.280493054138748, 0.776709265077171, -0.49041054453738, 0.70745646506897, 0.0592593016328184, -0.0231873729001059]', 22.5); -insert into credit_card_transaction (time, features, amount) values (157729, '[-1.25454842323468, 0.941880830428566, 1.52544457153431, -0.455663961649055, 0.160774639369195, -0.0194390053972152, 0.0742802108485071, 0.461239401103857, -0.212571015686181, -1.17288418247576, -0.94364535973804, 0.829411037380491, 1.4691697707377, -0.112771398277907, 0.565695675474951, 0.0660019687455348, -0.338204514221051, -0.031531892366414, 0.493315191054204, 0.0066155181174142, -0.110423117219574, -0.45272172129073, -0.159572853270231, 0.664744134165357, 0.406529115273121, -0.460189311363227, -0.178883034994962, 0.0134448350286316]', 5.0); -insert into credit_card_transaction (time, features, amount) values (157730, '[0.0839327239416598, 0.683834233418001, -1.67189102298397, -0.699370715900215, 3.44092275887205, 3.45003343802652, 0.91268547303285, 0.752580964206175, -0.657073893458826, -0.417852972972361, -0.474010861608173, -0.0497824462278548, -0.56034955603052, 0.616863925698081, -0.586137546968355, -0.723522687660101, -0.385048316612948, -0.542379653671504, -0.477242003478422, -0.132839107203323, 0.129922194016745, 0.366524131873971, -0.176436163791804, 0.697153406778408, 0.265947243636046, -0.546936375418111, 0.067196823917898, 0.0282515202634015]', 30.0); -insert into credit_card_transaction (time, features, amount) values (157731, '[0.1995078300392, 0.0481512741523652, 1.17324213839455, -0.54029192338214, -0.648228375847309, 0.0184542537667365, -0.56417786027129, -0.578783758329997, 0.638947251460841, -0.454726480564647, 0.500445620656671, 0.203219858451849, -1.46238988012587, 0.275061180240275, -0.469610560114083, 0.590888191075948, -0.619956271325532, 0.584559796668071, -0.451570470637419, -0.345685919619283, 1.0168020784624, 0.493985120670883, -0.240630898609875, 0.0554064859293341, 0.523822333637476, 0.791519563884681, 0.140001719244784, 0.226700364449408]', 17.95); -insert into credit_card_transaction (time, features, amount) values (157731, '[2.0507343376702, -0.364009836098765, -2.54284268573131, -0.729357245980242, 2.38845513580892, 3.318014826674, -0.479137991434965, 0.791558699015965, 0.403373925785878, 0.0932322962383584, 0.0043906366679776, 0.390166351524176, -0.212555237880757, 0.495543631087541, 0.472633049946723, -0.171594983536925, -0.368260801549244, -0.9765716778526, 0.0228694906165437, -0.154977952804284, -0.293362990419633, -0.834801882577702, 0.3817404029926, 0.698179490919462, -0.264798455762679, 0.219274980948542, -0.0521311602761514, -0.0669400159437571]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157731, '[1.53136924224897, -0.310048806894437, -0.287028298184486, 4.1018803345775, -0.276467100656946, 0.477880622857202, -0.137269115972041, 0.177404812366639, -0.360909919670694, 1.42106600905119, -0.111357941324161, 0.128795464003687, -1.33697038752733, 0.135516083601316, -2.5196368719342, 0.616586085476324, -0.534845988771062, 0.159013162523121, -1.05393044119171, -0.0651423817638953, 0.224870428483919, 0.487209990936455, -0.0476636286017667, 0.0621805674558569, -0.0352279747441221, 0.0960941777092523, -0.0439263310190957, -0.0308992979487691]', 160.55); -insert into credit_card_transaction (time, features, amount) values (157734, '[1.53265689060905, -0.835334625878746, -1.33941998281553, 0.773041324756797, -0.302611341229472, -0.98896900195442, 0.569470538780951, -0.39708183007438, 0.41550962555782, -0.047659427057156, -0.62971105879701, 0.709196057718519, 0.547269389829577, 0.26434253095437, 0.0567838681342358, -0.160474675874906, -0.27168188006874, -0.916221387420979, -0.070981231542146, 0.329230836593397, -0.110218889804579, -0.756679478084036, 0.0992391241467011, 0.0024401347059051, -0.356666846853665, -0.0099416276904652, -0.101002089506618, -0.0104919701237508]', 267.32); -insert into credit_card_transaction (time, features, amount) values (157735, '[1.63444532898914, -0.0197332889722868, -3.12483542444803, 0.685038292748997, 0.896015232235635, -1.19555554770097, 0.753084895225058, -0.32752091878664, -0.192446738558224, -1.15091655004252, 2.06903756625235, 0.543792983936332, 0.276692563921989, -2.71468245230332, -0.161956353283861, 1.0419110466672, 1.98903855929372, 1.33303264881618, -0.279098148144303, 0.375653482384625, 0.0550718321301796, -0.188810866533899, -0.129843576750681, 0.568200212000063, 0.0150531596875646, 0.616775933946625, -0.107157415777995, 0.0326259473521055]', 212.5); -insert into credit_card_transaction (time, features, amount) values (157735, '[1.96109203223554, -0.528540137753307, -0.325544351035125, 0.224395381762427, -0.652669097723302, -0.106513722314842, -0.744279728802693, 0.0757925003794997, 0.99019154416596, 0.151985502949062, 0.49836346179682, 1.14690496931221, 0.532910843380806, -0.178796555657022, -0.366146632611469, 0.581938741253262, -0.857587282177263, 0.573283930199769, 0.144008717332649, -0.126042543165891, 0.251555975560306, 0.932609360914507, 0.0708070497223712, -0.249851283209036, -0.232101252490165, 0.739863104208191, -0.0305572209268441, -0.0609666562208546]', 15.99); -insert into credit_card_transaction (time, features, amount) values (157735, '[-0.235250554447461, 0.906977219661731, -1.94102702441792, -1.48449225641093, 2.75372616762362, 3.22248526596363, 0.0538252946420797, 1.24510812037575, -0.325851713944973, -0.483693641675058, -0.331382826136371, 0.0763572678096864, -0.191125772385029, 0.955619825184088, 0.846018111597045, -0.390388122008495, -0.386121326856718, 0.0868194108651453, -0.0898286001610832, -0.0660120592086755, 0.406731389793851, 1.19745494433062, -0.0439231917210208, 0.738458428989925, -0.73324634393742, -0.196474887371765, 0.404481030693308, 0.253279151880028]', 0.81); -insert into credit_card_transaction (time, features, amount) values (157736, '[1.81312385735221, -0.323789478825606, -0.609382898331711, 1.06485127359648, 0.0294101757378602, 0.533087326374859, -0.394093458833934, 0.18524075531703, 0.541328562945295, 0.274353850807245, 0.499172146392197, 1.16182872490071, 0.510330714660039, 0.117324054018575, -0.199994186427157, 0.625323067452073, -1.052620444365, 0.333366185066629, -0.0426189679779955, -0.0432900869287134, -0.148302521511433, -0.508033618773403, 0.29720407996019, 0.153994711429784, -0.360920244871966, -1.00971462654726, 0.0371480590935368, -0.0205512077274272]', 74.4); -insert into credit_card_transaction (time, features, amount) values (157737, '[2.34191332652484, -1.29235434188819, -1.1663059791641, -1.64409219156798, -0.949666254165145, -0.506931627177632, -1.04191844161893, -0.20527747904874, -1.24518596371226, 1.57382420240768, -1.27115821133562, -0.855970489346708, 0.594317678474899, -0.446903717398437, -0.17153902421874, -0.522073955042361, 0.382970217363685, -0.0365801921350226, -0.0042291025315354, -0.409341603008864, -0.196424976896256, -0.0541493273329784, 0.230359988947385, 0.458440405325111, -0.102030196988762, -0.177833530601189, 0.0053239410753613, -0.0479942748179367]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157738, '[0.0418645194958908, 0.92642488095757, 0.312047533160246, -0.602698595487112, 0.514088007938104, -1.02275759922992, 1.04823208390876, -0.227917837461599, -0.16951620507941, -0.441848430369793, -0.73626984921396, 0.594195376622629, 0.826146092782206, -0.0456577888195562, -0.446203737272811, -0.190700467636849, -0.39897925379227, -0.938995428517715, -0.160833898722656, 0.0019267572841458, -0.246776039875847, -0.48019386356188, 0.0607875512709743, 0.0026076814316677, -0.477604907738661, 0.140735178967626, 0.256590546370483, 0.0983938085356448]', 0.99); -insert into credit_card_transaction (time, features, amount) values (157738, '[2.11420225937483, -2.18804432139882, 0.603545538263212, -1.10575212867619, -2.36094882925138, 0.946849439520807, -2.49509350836066, 0.387735712267693, 0.580118177842292, 1.15042903272111, -2.11858105612205, -0.342310050588501, 0.507294307432643, -1.92203685311568, -1.90383067304198, -0.725858196270718, 0.882391049995452, 0.322210072266206, 0.206341972051273, -0.352456535827324, -0.0707520365150876, 0.646794956511348, 0.183200136361677, 0.615049630458998, -0.316643784242375, -0.00382870027308, 0.109398590620118, -0.0168357117620624]', 46.2); -insert into credit_card_transaction (time, features, amount) values (157739, '[-0.345947018532829, 0.221689609855178, 1.68866949367616, -0.881681084033478, -0.0193693793565869, -0.0021479558732642, 0.240629369384862, -0.0974860189554045, 0.852488363208922, -0.479817384954774, -1.65483960293721, -0.586081860084165, -0.293989674328486, -0.597674819896937, 0.433662931191321, 0.753257698300604, -1.05143706003626, 0.411892847152629, -0.207315148877616, -0.0697681503251412, 0.0502553219555294, 0.342093796755629, -0.117140651695368, -0.566784186775397, -0.868227067863053, 0.401627715456505, -0.131879961206479, -0.0371630755784455]', 27.99); -insert into credit_card_transaction (time, features, amount) values (157739, '[1.90355890908553, -1.72086079221897, 0.139063963238674, -0.194423737837215, -1.66098100337126, 0.760001538073809, -1.71104921299269, 0.283424192302374, 1.23407901022462, 0.566179019715467, -2.63631122614157, -0.266874356715388, 0.149689695445292, -1.08147333397146, -0.486787168481125, -0.91032676753664, -0.338034134929352, 1.83555613708758, -0.468569836431988, -0.385395594783029, -0.24407481846269, -0.0703035333086816, 0.0756449551659965, -0.977724624414079, -0.492004296135284, 0.745733241340718, 0.0283172755923351, -0.0241675265688537]', 112.74); -insert into credit_card_transaction (time, features, amount) values (157740, '[1.83846371707358, -1.00789570371663, -0.475508888942729, -1.32241750189768, -1.3575364935935, -1.28861338371384, -0.537460563976151, -0.027337566127183, 2.03862295720513, -0.773385130811969, 1.3799174976278, 0.917158064264836, -1.62565139490795, 0.592932743942844, 0.617070516813047, -0.273747394990348, -0.245000707848843, 0.267194762712138, 0.852888653005438, -0.155358878853214, -0.11243721178139, -0.384967829765341, 0.384549492012338, 0.495076451362179, -0.599735008164689, -0.617085396006646, -0.0001982873753459, -0.0335827192839419]', 77.73); -insert into credit_card_transaction (time, features, amount) values (157740, '[2.06304902165685, -0.687040539353543, -1.07566541064391, -0.541476227587332, -0.783895137294314, -0.882228198054091, -0.82677879116441, -0.161548779248274, -0.109924804690685, 0.0350148975111852, 0.120669987063703, -0.210782213372381, 1.01565898594868, -2.26763046041853, 0.254984057925325, 1.5469928679413, 1.43530834125397, -0.637877975337297, 0.0596527698877201, 0.168821729448001, 0.286460219525427, 0.852281711381202, 0.146902166622929, 1.07279124793666, -0.161508660978008, -0.152964826764879, 0.0243990126920294, 0.0067917277746852]', 49.9); -insert into credit_card_transaction (time, features, amount) values (157740, '[2.03203087028484, -0.484093814216839, -0.646584353768229, 0.174146147077712, -0.308441001330428, 0.001793199991257, -0.592710224077965, -0.068557470292307, 1.19057544389679, -0.0422091194455687, -1.72321280829425, 0.597794654617644, 1.45394737054517, -0.556781851323801, 0.31076062538391, 0.563820111399627, -0.908643305742023, 0.228343469943537, 0.11718609565058, -0.043987799920069, 0.167939082254307, 0.739235374817959, -0.024812900116628, -0.897527829394105, -0.0863666409083893, 0.798311927228787, -0.0253205952498289, -0.0544788653764115]', 27.99); -insert into credit_card_transaction (time, features, amount) values (157740, '[1.87981862142844, -0.535896887213884, -1.70839444438536, 0.217682555348215, 1.90809314874955, 3.98317403315355, -1.07652420881567, 1.04053296138806, 0.738002701842881, 0.224059767541061, -0.153416613926394, 0.291789101906111, 0.019368121995729, 0.195937671029803, 1.19368443162048, 0.389562242192401, -0.878161575454054, 0.223283119984314, -0.898038370048889, -0.0993954220481979, 0.243559039895981, 0.667075332234168, 0.14697623583966, 0.689132283677662, -0.0623642465308243, -0.54464459981507, 0.0701932712231592, -0.0303286742065872]', 40.0); -insert into credit_card_transaction (time, features, amount) values (157742, '[2.12849030125647, -0.747185954583879, -1.5447927961167, -0.615499644492191, -0.193327180236505, -0.270710002960345, -0.43820758834029, -0.0812152822731884, -0.30877312042114, 0.861168178256535, 0.183825371984796, 0.227208364690515, -0.413833453052153, 0.53995742891835, -0.112469672186877, -1.5536603858097, -0.541578198005987, 2.17722981763222, -0.481800030352361, -0.619650883567572, -0.0148642805005191, 0.515364471776275, -0.0201613311500474, 0.32885944613271, 0.304806248191858, -0.366445790617166, 0.0211505264380046, -0.0553336098042886]', 21.4); -insert into credit_card_transaction (time, features, amount) values (157742, '[2.01273222402779, -0.322355556749874, -1.5004392466741, 0.24660282704128, 0.344595674329681, -0.0243476754177271, -0.0361029272935881, -0.0626035717793579, 0.551757787173089, 0.18236156449223, 0.218477613311911, 1.01743034484664, 0.131678020318633, 0.170105776722132, -1.31341047544094, -0.180723904964872, -0.485994215597178, 0.0982299926297986, 0.590988472091311, -0.124208750743618, 0.158227865516044, 0.664813434578162, -0.0520136886658377, 0.377909825948252, 0.253263259708681, 0.696729598701705, -0.0800659004959113, -0.0752443898421573]', 25.75); -insert into credit_card_transaction (time, features, amount) values (157742, '[-0.318071742166367, 1.02745601434487, -0.260435051717774, -0.766340115013417, 0.355795791655387, -0.572323874948388, 0.56294197477809, 0.398685457019097, -0.432997936487005, -0.469724666742441, 0.187955940265917, 0.794956120303546, 0.0102613143156877, 0.609379768082371, -1.10074059300705, 0.368434422171477, -0.66099246645221, -0.0488361268993704, 0.378681775893287, -0.107260525079444, -0.193564244582984, -0.56329531031382, 0.0740159009143445, -0.503168842407909, -0.43029942841597, 0.152743046722348, 0.114140563149223, 0.0199384851920048]', 11.99); -insert into credit_card_transaction (time, features, amount) values (157742, '[2.31429888671426, -1.04338614715792, -2.50423600176869, -1.67635179225787, -0.150439713563213, -1.37344964681271, 0.0752761681906443, -0.616690509065882, -2.43981859914671, 1.88616946629869, 0.572240577176754, -0.0706863960929765, 0.751883137816819, 0.355195051253356, -1.43279667251668, -1.18345696329319, 0.412356820601461, 0.110319025292818, 0.381389523170668, -0.344839579464768, 0.17638753114187, 0.982407266486812, -0.239708766846984, -0.257360899172639, 0.673004377785231, 0.296020567106736, -0.0769356247549224, -0.0936969434992459]', 50.34); -insert into credit_card_transaction (time, features, amount) values (157742, '[2.14277774795616, -0.802705307196821, -1.2032447205099, -0.32762349364375, -0.5009994773843, -0.475825533194848, -0.452286890513846, -0.206864593196201, -0.168463323362039, 0.795645060166528, -1.36769074191324, 0.117501342180503, 0.356005512597422, -0.19190146490817, -0.700827462347246, -1.8838364574366, 0.14223679111842, 0.798231714167276, -0.560141462893536, -0.558892578312831, -0.304805987842465, -0.178735935872318, 0.161754724574926, 0.750326714511842, -0.0197054230873036, 0.719905494998099, -0.0515041600611123, -0.054912525315581]', 22.45); -insert into credit_card_transaction (time, features, amount) values (157743, '[1.90915326979068, 0.381884263482279, -0.653980010932487, 3.85651108274668, 0.15046036460817, -0.250349935297848, 0.0488580822050828, -0.0409825875221328, -0.579401823091845, 1.51659745039793, -1.56805619390379, -1.18557838785057, -1.75435392553198, 0.523729864223883, -0.608844395046113, 0.730330343856242, -0.592790372678641, -0.0777003608436466, -1.70337045808353, -0.405359719438246, 0.275231998581727, 0.822341964597943, 0.0188386894419778, -0.0471152062090989, 0.141006773457772, 0.252459225232092, -0.0425743072171133, -0.0557621330041325]', 10.62); -insert into credit_card_transaction (time, features, amount) values (157743, '[2.04610332332394, -0.0437500638027864, -1.81848571745892, 0.268296048565753, 0.404609011354702, -0.474795335600776, -0.057555746269053, 0.0384949372649159, 0.55244372839079, -0.150364928358203, 0.588251695820762, -0.302360651856953, -1.97999331776155, -0.263434533359907, -0.2593827933381, 0.672399787638286, 0.255012222252439, 0.506568354023475, 0.440814464473537, -0.265214682377994, -0.350601495515078, -1.03755564438747, 0.323294613528108, 0.201622368223623, -0.325850122264503, 0.174851882408524, -0.0799209036058502, -0.0471719334989403]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157743, '[2.06831161827872, 0.0853584659959945, -2.02475176147264, 0.433383049421526, 0.497033458408612, -1.51080109726167, 0.826759722503537, -0.585385438752121, 0.314635194859999, -0.0249038755415932, -0.90372178264667, 0.54142026658436, 0.255035024111003, 0.568638993545291, -0.242669668034902, -0.868153447529269, -0.178154155510276, -0.573743017275659, 0.204830288816604, -0.193983325283011, 0.141583871185518, 0.617302731362218, -0.121423998512596, -0.0467513421837677, 0.585775550442182, -0.0652624726304511, -0.0545523497600951, -0.0708393278458775]', 27.49); -insert into credit_card_transaction (time, features, amount) values (157744, '[2.23571001383584, -0.68403269277342, -1.83367914028272, -0.784598653319528, 0.130118073020245, -0.195954773585233, -0.278490618770863, -0.138349075822692, -0.654243278575267, 1.08316924183954, -0.622011388178176, -0.0526806265667618, -0.248988782715607, 0.457074860284552, -0.700035079331822, -1.10200788540102, -0.680950159881122, 1.50283359586339, 0.218872242457627, -0.60917267879173, -0.601706295127028, -1.19060008887046, 0.158435948878832, -1.42170496138364, -0.140845673410488, 0.508018611708571, -0.0755261717006566, -0.087813075060984]', 7.45); -insert into credit_card_transaction (time, features, amount) values (157745, '[1.65313779544536, -0.711007814982481, -0.925334352603764, 0.743301747943678, -0.498871318330668, -0.87424547442454, 0.200317409990387, -0.337106866934903, 0.604324757490942, -0.0317452379676312, -0.663058534302706, 0.914893511293375, 1.1222509992426, -0.0550347603174709, 0.145678065297836, 0.0492930673370552, -0.463805890579845, -0.49597221845402, -0.20153375313579, 0.23840996740054, 0.0868596244520178, 0.02814092313606, 0.0459056113483164, 0.104573206944879, -0.246952123497116, 0.192894233459285, -0.0680055170817587, -0.0169334563682491]', 198.85); -insert into credit_card_transaction (time, features, amount) values (157746, '[-1.19625512501413, 0.361336493557756, 0.35012187229708, 1.01481725243179, 0.368568691551676, -0.0962190287971712, 0.290258812587897, 0.511279692890145, -0.25481046823163, -0.386163197926171, -1.94513134037998, -0.495976845991979, -0.395877064916596, 0.530389354663688, 0.627041179194693, -0.0819567498954667, -0.210200150495589, 0.522374627354505, 0.730362671711535, 0.373691561757597, 0.182057884893051, 0.252754667651089, -0.0223804859044217, -0.811654668692753, 0.0046797607188867, -0.439189007326529, 0.298907045272588, 0.0684735103026787]', 104.5); -insert into credit_card_transaction (time, features, amount) values (157746, '[-1.55640515826511, 0.277250057131305, 0.279203818863053, -0.905677045540747, -1.83503504320863, 0.792850091318565, -0.485137799379526, -2.26993589950136, -1.62601845120763, -0.699273926701926, 0.0544874981189315, -0.473159046831929, -1.5860735720041, 0.551110079544066, -1.73441789430872, 0.251688377314208, 1.31969700769844, -0.494231562168939, 2.10783667253359, 0.689377165749752, -0.729807312383886, 2.0054679590148, -0.370282168801813, 0.170553984741293, 1.01876690359243, 0.566498491287749, 0.0116801819572213, -0.11427870154068]', 253.0); -insert into credit_card_transaction (time, features, amount) values (157747, '[2.06080364938134, -0.101986941177864, -1.0758824736156, 0.425613927831132, -0.211935740378031, -1.23594282518287, 0.13691363270136, -0.29525286488622, 0.648545482103282, 0.0940814313372673, -0.854383851158043, 0.0634651836914334, -0.648412667688802, 0.417479297592626, 0.117381436305634, -0.0744266165263341, -0.244197263247831, -0.785284927766923, 0.147506628837049, -0.269871839770831, -0.296743134780897, -0.755769994215157, 0.349687865840473, 0.0268549724622407, -0.323696402968748, 0.197745332701712, -0.0754038679838504, -0.0613411882851275]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157748, '[2.00351548108285, 1.29863412519987, -4.31527728207764, 1.97602283621219, 1.75293830820954, -2.24497222694047, 1.11766605069805, -0.36313840741697, -0.348439676032932, -1.56998016249089, 2.0778789671457, -1.63681061226303, -3.43617789447646, -3.77640102690597, -0.14803122963879, 1.12250281454358, 3.97354020868844, 2.62459597355864, -0.894324918438769, -0.328026190143838, 0.0362068634765769, 0.203869854082124, -0.270469316503627, -0.47223785876609, 0.73443359963732, -0.202782516800411, -0.006616185819499, 0.0244298732988913]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157748, '[-0.650930709532351, 0.263964467540254, 3.55770916797245, 4.76773434963167, -0.202304811467762, 2.49383079864348, -0.8192891254114, 0.592894380813968, -0.123213243627121, 1.06620638546009, -2.38147616099625, -0.989561898628565, -0.695760441119307, -1.3300913954694, -0.859409667122229, -0.346072323192032, 0.529398058632442, 0.692845154870888, 1.70370316356604, 0.451397341056591, 0.0709598979063375, 0.612585293657667, -0.250158348977302, 0.491312935145328, 0.13995672748693, 0.613300895030037, -0.0029253736821857, -0.101570815095981]', 50.12); -insert into credit_card_transaction (time, features, amount) values (157748, '[-0.757335255177685, 1.0909000225444, 0.624266126570755, 0.103105894843957, 1.19497463887191, -0.294548440388125, 1.64648205753637, -0.108406552708409, -1.12908028458702, -0.584121598872455, 0.202519779350007, 0.146319758312773, -0.902308278626179, 0.709994096310675, -1.37243994011026, -0.486067169112586, -0.4523417540132, 0.184860614880998, 0.256269589668875, -0.0601424907495721, 0.100984605028546, 0.255919320168421, -0.59146646132216, -0.403009601270806, 1.26426042679079, -0.35045354357559, -0.0092566107235634, 0.0278198448265206]', 46.0); -insert into credit_card_transaction (time, features, amount) values (157748, '[2.04632034459966, -0.0277642367175021, -1.05622536419919, 0.418738870335234, -0.0968716018175335, -1.20027293230247, 0.24104214894528, -0.375617052299735, 0.438960886866, 0.0498748704859101, -0.619280965777002, 0.796633887964169, 0.73095131062767, 0.145069016676394, -0.0327926480248298, -0.138004912521931, -0.322700700765357, -0.952697690981258, 0.135641874176874, -0.165254478974978, -0.27604066894971, -0.647153198594462, 0.326079762381277, 0.0649931406468035, -0.280018002699793, 0.192272426379622, -0.0679113310596779, -0.0569854048983729]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157748, '[2.19091521079005, -0.317362279223724, -1.7662852128836, -0.663390000862614, -0.11971372843457, -1.35958632204678, -0.0895239106883937, -0.426572707816931, -0.746343483478287, 0.248284108086772, 0.178394282251264, 0.0546052685741178, 1.16300457117473, -1.4928431253211, -0.306709604523775, 0.88305621485888, 1.38405602849814, -1.56463468882138, 0.508103691093454, 0.0827774774478032, -0.0072936520044746, 0.044828725293702, 0.236942252731653, 1.08312110937402, -0.0017934804411545, -0.341545119485686, -0.0223368558942935, -0.022303647117555]', 15.0); -insert into credit_card_transaction (time, features, amount) values (157748, '[2.20287935086538, -0.83917755281413, -1.51623822048021, -0.737539644031996, -0.665990096744758, -1.42158411857157, -0.289538545708148, -0.396269099406977, -0.25257585171814, 0.870033660700008, -1.03394556186747, -1.1769294601708, -1.0684426879714, 0.160989790522125, -0.224718238898465, 0.529784456382618, 0.470406278595387, -1.20821519860039, 0.563084909444508, -0.0983967532299143, 0.550626585402461, 1.6480286354807, -0.165041847378357, 0.119959540547246, 0.444186408439166, 0.290681093294727, -0.0537918831560525, -0.0747253897895706]', 27.0); -insert into credit_card_transaction (time, features, amount) values (157749, '[-1.15657377664651, 0.9964339929977, 0.838178465622397, -0.867772681400813, 0.642522043447302, -0.488090907415734, 0.631533367652051, 0.421273319802395, -1.00700572772504, -0.999795566635754, 0.421285870719857, 0.766778146960382, 0.0333212664749036, 0.665431558398277, -0.91050575948488, 0.211177738668658, -0.445418411118552, -0.165153940034023, 0.4651198229711, -0.103477236494009, -0.189673574203013, -0.784538961403902, -0.318408026743572, -0.387255181204249, 0.521605677066274, 0.325484583863894, -0.166371101041145, -0.0714860119645089]', 1.29); -insert into credit_card_transaction (time, features, amount) values (157749, '[-0.578991320013255, 0.176269869115641, 1.72959747436657, -1.05165833444821, 0.123865694886083, -0.767387046780066, 0.761666346221852, -0.168170447961388, 0.455547597365137, -0.793369567202865, -1.14947578586987, -0.72147540237967, -1.28613927867143, -0.135356071790557, -0.0372385716594587, 0.559436931657113, -0.800872143159333, -0.269226802238125, -0.664825037061927, -0.0347064489860529, -0.222606563308873, -0.670341991988361, 0.0996946645491959, -0.0088786388499015, -0.564961672152797, 0.108489709354273, -0.123975908065529, -0.0811182362070439]', 47.49); -insert into credit_card_transaction (time, features, amount) values (157749, '[-1.31218649527957, 1.47794604528064, 0.835260708483131, -0.973668550293296, 0.583924407310809, -0.233249287567359, 0.566023278091484, -2.8751659798451, 0.155457543985153, 0.458986603345045, 0.918786611148297, 0.432169731130655, -0.86575920634809, 0.0642431161311722, -0.945861892243984, -0.13633792796123, -0.557665163671291, -0.204176920851281, 0.294373282180676, -0.405861928525427, 1.9969671851274, -1.27526037649752, 0.165312730640243, 0.0183607371704786, -0.238080822288125, 0.129610418114815, -0.204347970948289, -0.244018252578356]', 3.59); -insert into credit_card_transaction (time, features, amount) values (157750, '[0.37707341751061, -0.785761319816824, 1.55634358016483, -0.848884021971634, -1.34457735242435, 0.657358226915269, -1.31655931351197, 0.153508217919353, -1.84383387865382, 1.47856470797897, -1.00188191922223, -0.772117045497867, 1.66728344900969, -1.00577065799995, 1.26534710137343, -1.2614443156487, 1.22110051287671, 0.670924631931016, 2.35747901502321, 0.166483286792319, 0.008564787294346, 0.613056734357945, 0.21735821930664, 0.628199165157873, -1.26958849953935, 0.0809728039354757, 0.330339839062508, 0.248804047174878]', 34.0); -insert into credit_card_transaction (time, features, amount) values (157750, '[-1.1444852175499, 1.46634408900666, -0.365784503068063, -0.793915880823082, 0.434679597323906, -0.488924822882275, 1.30281343071596, -0.101746728101585, -0.323897576430386, -0.788616361937625, 0.821229290531026, 0.0679061110252029, -0.486895558605613, -0.604478444778123, -0.0255427173172512, 0.441752999679591, 0.0722325252297329, 1.20462834075134, -0.127632979870371, -0.297017271636033, 0.316754219071224, 0.891904945925574, -0.530348541022318, -0.458556915769809, 0.26186228984748, -0.168980246885882, -0.653336386174846, -0.176615450812176]', 89.95); -insert into credit_card_transaction (time, features, amount) values (157750, '[-0.30657833666707, 1.04174718337986, -0.090966703914278, -0.530341836381778, -0.0004691658636179, -1.19600942803246, 0.618016490422182, 0.264137686380941, -0.0911828639183154, -0.615284265736217, -1.2060001223976, -0.135571452693822, -0.74704131854644, 0.592268067299415, -0.352859432943153, 0.0656562981048191, -0.190546542596523, -0.610394694738725, -0.0880134438732053, -0.186913442561252, -0.223257384024339, -0.648286658547223, 0.150784919608977, 0.0153364519812683, -0.491333449163797, 0.142731071980553, 0.114344205630448, 0.0332636525000347]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157751, '[0.995536448723758, 1.8604287052582, -4.89863812941707, 2.04548218978533, 1.47310361810392, -2.24144023999241, 1.22333008906408, 0.129188612508083, -0.520690411302041, -1.50489855497871, 1.80005730340127, -1.6259847497, -3.31685510771455, -3.58410239272137, -0.217957576241076, 0.998067520421887, 4.25638249464842, 2.88418104171532, -0.418596476532229, -0.16591430638907, 0.2210992914627, 0.682204514751018, 0.223213986092436, -0.493809168008279, -0.855078470331945, -0.352004451994275, 0.179849970939297, 0.0192266340873271]', 59.02); -insert into credit_card_transaction (time, features, amount) values (157751, '[1.93574284930168, -1.22394751772485, -1.27473771655157, -0.491858458306682, -0.525888734919106, -0.0525375139868245, -0.517635371114252, -0.132763676164761, -0.165891062908025, 0.781954952045084, -1.69043305006766, -0.180301217109999, 0.620426933067886, -0.147970583197821, 0.254132470196078, -1.12743992287832, -0.421785323641085, 1.23684133396203, -0.613006316566133, -0.266509198998845, -0.332732352487289, -0.666949738268772, 0.127400319468649, 0.092216133515229, -0.309739217214739, 0.550797522229459, -0.0624281922962205, -0.0274398920709259]', 145.72); -insert into credit_card_transaction (time, features, amount) values (157751, '[2.00616333354732, -0.102957997721127, -1.00872363502309, 0.311893178388144, -0.0922913523546295, -0.852106113930458, 0.0697096663335968, -0.168770834380666, 0.270529123777551, 0.233122176556197, 1.08803451066019, 1.1894353773142, -0.0123713796248276, 0.477161435652408, -0.622302488258895, 0.0066721871032153, -0.453360851093921, -0.494180543124355, 0.332054381450122, -0.222234989389338, -0.226317932674189, -0.54482707297985, 0.345302753808434, 0.018631093559939, -0.353597166337901, 0.178367162491684, -0.0709379948780563, -0.069901327375337]', 0.99); -insert into credit_card_transaction (time, features, amount) values (157751, '[-7.21819546147783, -8.96771828144094, 1.50273907674583, 1.85796380927918, 8.99912602103606, -6.57097391729028, -5.14779023684865, 0.644873625992101, 0.469401243435839, -0.181275576912098, -1.35565956782952, 0.467249738500158, -0.281846967894806, 0.434323948713366, -0.516682797275072, -0.818545579208959, 0.196367774095126, -0.156594276196618, 0.108601452575295, 2.43520143919706, 0.925196875291596, -0.0170445588984718, 1.27785279442287, 0.03193065278178, 1.4085126985899, 0.852911369574687, -0.395061133282322, 0.217884998199604]', 57.5); -insert into credit_card_transaction (time, features, amount) values (157751, '[1.89768816736501, -0.4325048790701, -0.238286022657638, 0.553589326356288, -0.746598094038173, -0.579279604091999, -0.449418149578351, -0.155511820550268, 1.25247685356112, -0.22511706333054, -0.740371551341499, 1.23423281811443, 1.51819281578446, -0.466492861783479, 0.32474220132332, 0.0096020134140664, -0.572519465194055, 0.0293176274116009, -0.259668978023597, -0.0510208700828914, 0.234962279960646, 0.913901902739597, 0.0682567360571461, 0.111997459198014, -0.0657023641164369, -0.224722067025397, 0.0433485789588105, -0.0261791630404535]', 50.0); -insert into credit_card_transaction (time, features, amount) values (157752, '[0.0368117672889375, 0.839535024590251, 0.285488093283135, -0.590370231245683, 0.408437057001676, -1.04481259773251, 0.982371471217317, -0.166127010520899, -0.0036327386541445, -0.41177538679722, -0.924264405572009, 0.0072830840230801, -0.275692752978534, 0.173974207688459, -0.325089052220534, -0.138448856284179, -0.336194481283671, -0.802727435216233, -0.154029898467275, -0.0630528251062092, -0.257930872404855, -0.570648997882921, 0.0800862928457901, -0.0278834331507814, -0.513841647897647, 0.144346911921666, 0.248486090529327, 0.0962140465716221]', 3.57); -insert into credit_card_transaction (time, features, amount) values (157752, '[1.89170739500416, -0.535418234207353, -0.649055233453485, 0.160692492875326, -0.229655852274538, 0.340856330051236, -0.605532253459684, 0.219567501257327, 1.09393164260772, -0.016871538841787, 0.443548139481764, 0.830369798386695, -0.293535774962598, 0.214764634703597, 0.125780314135634, 0.51515258968659, -0.902328507273473, 0.454757093599476, 0.315176349262703, -0.116516418227511, -0.137147320123324, -0.425352543363503, 0.313525952982681, 0.165615719482378, -0.423358015771402, -0.645636348660543, 0.0182145704959304, -0.0323859078184513]', 50.0); -insert into credit_card_transaction (time, features, amount) values (157753, '[1.73278263686518, -0.592270260647071, -0.462045902778294, 1.19644582723498, -0.484116556270241, 0.250928230474426, -0.615395716587068, 0.255479023979069, 0.831429075065553, 0.375551689481227, 0.588540625141442, 0.182356444065303, -1.33669613816033, 0.490835719529378, 0.330270556765314, 0.695356248222205, -0.915768513950396, 0.969378411002267, -0.563212595820842, -0.114479139554471, 0.31885667216782, 0.726783492232213, 0.10557350243377, 0.654289050515933, -0.200611209120971, -0.617173807621627, 0.0245607598500652, -0.019838916332728]', 100.0); -insert into credit_card_transaction (time, features, amount) values (157754, '[-1.08437373698997, -0.0412353933328802, -0.165797624743433, -2.19547962682919, 0.191909781395609, -0.969693391039072, 0.389501989851879, 0.329852914326939, -1.26946382957439, -0.270440447911511, -1.30066986172269, -1.19657995857087, -0.953882290809789, 0.342889906964146, -0.859442939984685, 0.958405612856348, 0.349146044454139, -1.62221774675246, 0.097285102745393, 0.230069657182812, 0.15479247526566, 0.0121206326513846, 0.0309908285512829, 0.642558408052816, 0.129755664567465, -0.398887950359597, 0.172752596264637, 0.0639834429117401]', 76.19); -insert into credit_card_transaction (time, features, amount) values (157754, '[-0.945582711723325, -0.799151969050314, 0.644264103232057, -4.05352188828289, 0.381395552695166, -0.0687993504504064, 1.24520247283181, -0.191101683834918, 1.57213210266073, -2.28272915743526, -0.210813469179539, 0.887805747164436, 0.571868901293711, -0.256948330898479, 0.139600225916565, 0.315878658552191, -1.76638697434972, 1.4558766012445, 0.234058703096384, 0.446352683720084, 0.35439702931146, 0.878347311892487, -0.106315024204261, -1.3765006838409, 0.59924746466712, -0.888200056265963, -0.0967348639529727, -0.0993864296509226]', 213.64); -insert into credit_card_transaction (time, features, amount) values (157755, '[1.94745075040267, -0.166135946239098, -2.1789988559468, 0.259675948304535, 0.600266187134912, -0.385792777166616, 0.111954875304485, -0.119851953489704, 1.09993863711154, -0.930524920925639, -1.14133905144436, -0.155739453659387, -0.312837252818048, -1.56701368196073, 0.073052246972743, 0.237006697353214, 0.970423184107843, 0.321068653985394, 0.309033400867493, -0.020293814296173, -0.267960397036744, -0.696340579812742, 0.079140772639746, -0.162074004683936, 0.0058090256302605, -0.0785920908076026, -0.0221786968919089, -0.0084732558167042]', 75.46); -insert into credit_card_transaction (time, features, amount) values (157756, '[2.22937174280281, -0.564662323451588, -1.56304440884967, -1.1327568991883, -0.12369719813225, -0.950634618370871, -0.172291840174059, -0.337928002082741, -1.04225945626249, 1.01046242461322, 0.894189186048819, 0.421124238419084, 0.938854512454626, 0.168420574924453, -0.519795733394962, 1.1469081134977, -0.264848109965856, -1.22501638871071, 1.1313725279866, 0.0286812615289434, 0.0778540199652142, 0.18988439574898, 0.13716523706319, -0.472203387827786, -0.0044498094611528, -0.30689356629706, -0.0466223127278476, -0.0759521611455766]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157756, '[-0.536399250777087, 1.09269093884251, 0.0314068708488752, -0.718972340435008, 0.86351894985858, -1.11813068621713, 1.28231479015933, -0.382034069909047, 0.0097074625160727, -0.436452431732871, 1.16241012433618, -0.135405498674783, -1.08061221308623, -0.758039036086932, -0.143115331017543, 0.278893564734146, -0.0059484932873254, 1.18267790897185, -0.339699527625088, -0.0185012536458631, 0.278959224317972, 1.04513464711954, -0.308366330102825, -0.0130010893263757, -0.151276944374993, -0.246861157028185, -0.0241853849781984, 0.0452097936799999]', 13.32); -insert into credit_card_transaction (time, features, amount) values (157756, '[-2.18880795479537, -0.497743923716989, 1.31560172552563, 4.86630879729476, 1.40941850566254, 0.253830145565313, -0.634590462763959, 0.749229751785257, -2.1148307841804, 1.02267086527344, -1.58850860407147, -0.959609663901933, -0.235106252236773, 0.658680217144038, 0.931018786180936, 0.127629182179435, 0.350181111152167, 0.484112244497463, 1.29947445980354, 0.869868835415983, 0.272937762982112, -0.181974140222543, -0.0962407741040469, 0.561695162292163, 0.289202182753139, 0.432880230335186, -0.0289126039611331, -0.270890277589851]', 88.95); -insert into credit_card_transaction (time, features, amount) values (157756, '[1.95400584549428, 0.655397195128564, -0.800645554137467, 3.71691852853449, 0.45298297826303, -0.483443968354456, 0.341575095868091, -0.233377861442085, -1.13049220745049, 1.54884478647581, -1.15433181399121, -0.38523453330898, 0.0705418460128302, 0.408296538734284, -0.315414160681798, 0.922552807035497, -0.944061897356317, -0.206842979000685, -1.71940675789533, -0.288283970433082, 0.224559510942943, 0.66151409853066, 0.0541920838425218, -0.0346133499052405, 0.134809410587815, 0.13401380020373, -0.0460666971361718, -0.0525580321456387]', 4.58); -insert into credit_card_transaction (time, features, amount) values (157757, '[-0.458621773689576, 0.682699395919958, -0.717700493667341, -2.7412829900963, 0.79994570700212, -0.651982955144735, 0.84297048631917, -0.432881763454238, -0.388895723073424, 1.38716248869094, -1.36141631435332, -0.845326268377232, 0.970517011252105, -0.747652380526367, -0.488045428227949, 1.12751682724628, -0.695389929559789, -1.10286498145696, -0.160340186601634, 0.580389473761996, 0.350170815111158, 1.50218057323091, -0.225763658542937, 0.0927971874095637, -0.43076290248475, -0.215199122019883, 0.606190882808856, 0.299291556796428]', 15.0); -insert into credit_card_transaction (time, features, amount) values (157757, '[-0.729037821210149, 0.639110463060512, 0.0316307195375617, -0.620396638876, 0.487170188648724, -0.175842768907904, 0.471087167016775, 0.500278982513446, -0.388546378299453, -0.816431294178666, 0.150579394898356, 0.484026317539133, -0.900453179060494, 0.627579538526255, -1.67824069490274, -0.254329596249963, -0.121784321136374, 0.182580007309519, 0.249926019906321, -0.178579942704754, 0.344371573679307, 0.899385461601915, -0.199641932441146, 0.776438831980956, -0.111418145282334, 0.6104960266223, -0.0377101235726492, 0.0624342373798584]', 29.56); -insert into credit_card_transaction (time, features, amount) values (157757, '[-5.7748067363417, -4.32227757549895, -1.29937262597976, 1.04887404906239, 4.12690082549974, -2.8397358767187, -2.04707532077296, 0.123781007629177, 0.762231195781618, 0.617482960411276, 0.621354556794564, -0.0458515743778481, -1.4657956555301, -0.307403443610212, 0.198119137378741, 0.837804586557949, 0.41367559863984, 0.379498094551388, 0.965424104963162, -1.48223402012487, -0.966762699248118, -1.50803320720952, -3.62521359507269, 0.596769572394591, -1.0543500073088, 0.217528109401039, 1.92434252218339, -2.05302930063958]', 8.97); -insert into credit_card_transaction (time, features, amount) values (157758, '[2.17084214383082, -0.913143597442236, -3.56163511718779, -1.99265008070707, 2.39205038258576, 2.70454314926379, -0.306117896979413, 0.465751272850535, -1.13777398376195, 0.927655372553512, 0.183075924351834, -0.627282681614006, -0.110632219055303, 0.582352837510263, 0.350668114039655, 0.363132051491306, 0.273091745774191, -1.82478072814313, 0.513075600093103, 0.117849693666259, 0.373891598093233, 0.870959869816497, -0.0701333838731601, 0.769021113031478, 0.469472131277971, 0.0955363493514126, -0.0685508903513939, -0.0793720094232542]', 59.9); -insert into credit_card_transaction (time, features, amount) values (157759, '[-1.30269411219782, -0.0418640727284351, 0.963828036033088, -1.08506627923451, 0.0742958691779834, -0.407220420858539, -0.0977229389862071, 0.617105780011204, -0.137341527112833, -1.01796292832634, 0.0563638067164112, 0.401193677069014, -0.279475281888258, 0.39915021104632, -0.50418464359173, 1.17020342005531, -1.1178191581226, 0.900995151620355, -0.606936051254229, 0.0281600872063651, 0.403782591298034, 0.693021517532399, -0.104615423876459, -0.370779028277872, -0.265745952914952, 0.53962925255222, -0.0571931587943226, -0.023851507204078]', 65.93); -insert into credit_card_transaction (time, features, amount) values (157759, '[-1.5608254226094, -1.06785779081051, 0.138003773072091, 0.780004173790235, 2.45151437918082, -1.1362534046161, 0.0973771954255916, -0.066839990531662, 0.151997929506751, -0.26895512947376, -1.55927588304372, 0.450376703513502, 0.608360569183959, -0.177370648596257, -1.1696379952774, -0.451448883067062, -0.516868903126989, -0.0903405180474666, -0.258703699149118, -0.120842383187683, 0.263528658179447, 0.973515977305121, 0.606723976833951, 0.597607777707733, -0.303055409059802, -0.65947536289348, 0.114351187137116, 0.422444170159428]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157759, '[-0.915149111878821, -0.732103700070389, 1.49069621661704, -0.450923280227081, -0.704878215076738, -0.494060725888955, 0.0237870140553342, -0.801321529221471, 0.163585727916949, -0.973935235585285, 1.39319968260154, 1.10467325534667, -0.423014185587626, 0.414208599710605, -0.156794493042451, 0.351135605962524, -0.479560017678668, 0.033509649172744, -0.2518095821509, 0.441220008946705, 0.726163557561348, -1.30439193978001, -0.964258204639311, 0.555589713594712, 0.988762713663006, -0.187225454717361, 0.0067962712424468, 0.210200157442145]', 360.0); -insert into credit_card_transaction (time, features, amount) values (157760, '[1.99318002048534, -0.558485868603381, -0.682291230278836, 0.162872636222983, -0.276326482085174, 0.394895499457525, -0.784860404581807, 0.219108104691434, 1.39517808299051, 0.01699714643554, -0.339379115077556, 0.439812518642154, -0.526328463447657, 0.0877231197409678, -0.0176908779296751, 0.563341226883815, -1.04489341263432, 1.04929510691301, 0.398211276012977, -0.22320691538389, 0.173279557567715, 0.691856395487233, -0.0149100689340387, -1.15247816715018, -0.0231690647988001, -0.157821234151418, 0.034256502430304, -0.0590990039260461]', 12.99); -insert into credit_card_transaction (time, features, amount) values (157760, '[-0.387016308294202, 0.885546810509896, 0.576911056022643, -0.246196704250171, 1.26220352242242, 0.0357934725830215, 0.537904841618394, 0.12271423549909, -0.98282935093223, -0.82859659698616, 1.06275462327465, 0.473996961307179, 0.809562502699716, -0.905139917757283, 0.680285294166137, 0.747654974068223, 0.187758406700493, 0.659629050222666, 1.40458637656597, 0.28609258449808, -0.501688991089838, -1.64453150156937, -0.0484504877013835, -0.038074699512936, 0.159200464028261, 0.198745385469487, -0.0901895402829525, -0.0293581212943189]', 9.0); -insert into credit_card_transaction (time, features, amount) values (157760, '[-1.67074797375828, 1.82082365145551, -2.52200953466509, -2.6746545795997, 3.74073522355887, 2.70667631305782, 1.62417230504786, -0.0285580020193143, 1.42983393139238, 2.65812801040098, 0.326584457209074, -0.355215597577748, -0.550939707199183, -0.33648457701367, 0.479446702920683, -1.17822281667817, -0.908659786991288, -0.724692013381181, -0.431888271899474, 1.01650279941969, -0.202766425390474, 0.785905869092135, -0.163050436529736, 0.72764151824788, -0.0017167587024862, -0.0022157418584732, 0.129194628697034, -0.531097752272958]', 0.69); -insert into credit_card_transaction (time, features, amount) values (157761, '[1.40694462058248, -2.22964420616156, -1.09278924554608, -0.521431442785045, -1.25080215662766, -0.145204768685222, -0.441124278894459, -0.0812557289632714, 0.211282577839796, 0.468449312292831, -1.05534025997817, -0.667440778259441, -0.490713485359621, -0.309137851540799, -0.241440792750203, 1.00508435713639, 0.418800533413061, -1.70792073070499, 0.78011860545921, 0.730794486274656, 0.0095547290122769, -0.84834440789254, 0.115268189565705, 0.567331085956412, -0.627161900049319, -0.635384902508728, -0.0716444352603119, 0.0290791235794769]', 403.48); -insert into credit_card_transaction (time, features, amount) values (157761, '[-0.401122422432255, -0.645339960165853, 0.0915963509265908, -3.31662642631649, 2.03008831501402, 3.90081139626387, -0.124758562493921, 0.813170426774759, -0.798233272590948, -0.118267596569829, -0.24322379818147, -0.978460792265181, -0.140870122605956, -0.611342374486742, -0.09413022967914, 1.18331663128513, -0.332136026863269, -1.169642821445, -0.324964079485232, 0.327934203295884, 0.385193222800044, 0.983422473423648, -0.107336115640603, 0.724395613925288, 0.02425207045917, -0.193409887623481, -0.0559692497362724, -0.0898981718065926]', 89.0); -insert into credit_card_transaction (time, features, amount) values (157761, '[1.70549287992302, -0.776769851154756, -1.269321913709, 0.193283838194526, -0.18941776641426, -0.411500022692395, 0.140278014498494, -0.142612548607431, 0.790211108372426, -0.131043037576414, 0.561370173341116, 1.35234409712455, 0.205757307188476, 0.254033378410913, -0.927709356641389, -0.273981225749802, -0.425864520181834, -0.148659817772306, 0.642261157640657, 0.11586753552278, -0.0297770086494233, -0.197822780702313, 0.0250761451731495, -0.364332749618645, -0.114156009804988, -0.100753282589354, -0.0535844740592357, -0.0414337906923724]', 164.41); -insert into credit_card_transaction (time, features, amount) values (157764, '[2.1175155782907, -1.11663247596756, -2.2302878588157, -1.98034002010056, 1.60353246599434, 3.34578886250108, -1.17050146507107, 0.837020898369754, -0.463790988167026, 0.760909132933108, 0.230911381352299, -0.3472023221394, 0.0817113559187495, 0.047503131605078, 0.697017465171006, 1.09409654181243, 0.053715276269157, -1.999946168881, 0.622025169270762, 0.101041804799662, -0.240856650468923, -0.943249384387394, 0.501566369683911, 0.641977508817422, -0.527746218925885, -0.670975082353041, 0.0015298525834196, -0.0454870254824985]', 39.95); -insert into credit_card_transaction (time, features, amount) values (157764, '[-1.30989059677414, 1.12980327572915, 0.441725781261312, -0.316067183384615, -0.753078173327791, 0.139722555312353, -0.883371840005158, 0.251249945812242, 0.575485443335261, -1.05559536288271, -1.89117130004564, -0.557081509676945, -1.50534156809895, 0.683612756139346, 0.489841289333537, 0.218167442861782, 0.0287942119084175, 0.84373675120483, 0.191045063431661, -0.571350397854006, 1.16538560368293, 0.695205033807072, -0.0321006105602973, 0.644284207832754, -0.253610962005684, -0.148318943098187, -0.137651443771097, 0.0349502998053518]', 9.95); -insert into credit_card_transaction (time, features, amount) values (157764, '[1.96168886365896, -0.0228905791480068, -1.81956766671407, 0.605365686281901, -0.0054948676190132, -1.5652948499908, 0.245925701512115, -0.327583095814266, 0.800732913460871, -0.493734836383028, -0.557510075341906, -0.723631300420433, -1.45515625526132, -0.531886059536065, 1.07311761562143, 0.307636523447466, 0.564281440561343, 0.730176787626216, -0.456946507715766, -0.198696834567125, 0.203000673387383, 0.583347524573185, -0.0460066359361122, -0.0635872915782479, 0.185293797337547, -0.104233871821745, -0.019703249051687, -0.0234773131254189]', 51.65); -insert into credit_card_transaction (time, features, amount) values (157764, '[-1.24408848958698, 1.19330632520761, -1.19635638526568, -0.168698167981753, 3.20348483542277, 3.62516663905731, 0.43212868247803, 1.23732426531801, -1.17622634555151, -0.30698692682965, -0.421755300569328, -0.0590431987713753, -0.422845756572558, 0.956501653798671, 0.245497178313069, -1.11597558271264, 0.314007277995835, -0.370367867076112, 0.834382394202446, 0.099246194259702, 0.0593075084841779, 0.112485890832437, -0.576128289794068, 0.728286525022359, 1.22087694806438, -0.161937834991758, 0.0745908720937911, -0.0046648865197071]', 19.12); -insert into credit_card_transaction (time, features, amount) values (157765, '[2.21734135992744, -0.988823844878078, -2.60643504663937, -2.02269347283352, 1.81733862530113, 3.16650688706906, -1.07694334578937, 0.732534918485502, -0.611046856597784, 0.881106027037353, 0.161659516476641, -0.57133579392004, 0.0780645293858644, 0.162916827005175, 0.827917211894789, 0.921990505112027, 0.0189876950808539, -1.44369894700329, 0.304113364825286, 0.031259645334043, 0.34595602029342, 0.905648238529103, 0.109967126755195, 0.745062187685227, 0.105037562025788, -0.0157633632639415, -0.009606430433617, -0.0685059262213962]', 5.37); -insert into credit_card_transaction (time, features, amount) values (157765, '[2.02474001199973, -1.04195921618869, 0.240668717474758, -0.417004602762899, -1.55363320107346, -0.340650650908301, -1.30683824786951, -0.059122860943785, 0.0677928111987486, 0.79385286667541, -0.832432824646551, 0.69533042600112, 2.22398524543296, -0.746864357433475, 1.18544880018828, -0.491384534831706, -0.798937860617149, 1.64298213992037, -1.37062654735142, -0.385600953949756, -0.0920158826773632, 0.298817268433962, 0.279405417422832, -0.0692194183538692, -0.662983361241718, 0.599295531685619, 0.0239562682798574, -0.0210275953423005]', 45.9); -insert into credit_card_transaction (time, features, amount) values (157765, '[-2.36249893049779, 2.18652491201584, 0.0330869364420679, -0.952162083735602, 0.598479014534101, 1.49417117857969, -0.820652969460173, -3.70344863256169, 0.195603957686532, -0.0086798130551488, 0.150725825780715, 1.60067612447849, 1.19811076312405, 0.0533424827453554, -0.636337482247557, 0.0262667795701083, -0.461270412659054, 0.112405351075221, 1.1882148974455, -0.914347039579022, 3.45567765074469, -2.38163198521093, 0.494036750132676, -0.311692503509576, -0.17960891565747, -0.793594976492951, -0.491144259234298, -0.129088806269323]', 12.99); -insert into credit_card_transaction (time, features, amount) values (157765, '[-0.228741091321712, 0.694153443914698, -0.791232524212178, -0.929637300935088, 1.88417030489634, 1.21197483188609, 0.567927138447901, 0.478190109588234, -0.147375221399862, -0.67235194853831, 1.06036785686647, 0.443567916522042, -0.344114631006769, -0.747466317874685, -0.0780803212328297, -0.160021125877982, 0.732612868267374, -0.831640211180586, -0.763777512680677, -0.104103868884938, -0.245614316569418, -0.508031449750812, 0.240274235610244, -1.06050131633507, -0.574463794093697, 0.218103156784518, 0.150053421906105, 0.0386370668648158]', 4.86); -insert into credit_card_transaction (time, features, amount) values (157766, '[-0.536936892625797, 1.12873968672868, -2.18683861650872, -2.3947487266753, 3.74597388045451, 2.77304915682203, 1.46934944014706, 0.198257237649481, 0.313032990338939, 0.887241898400141, 0.102475656430612, -0.277539631826574, -0.529640915976931, 0.296937398684015, 0.351415725713019, -0.962592229745583, -0.719892136158157, -0.604207711043482, -0.339360635534281, 0.507733528465347, 0.0436167750436431, 0.789218352956048, -0.224979024632596, 0.743067172153576, -0.163175356615064, 0.0674699471166676, 0.408460422708027, 0.0032633063709663]', 7.7); -insert into credit_card_transaction (time, features, amount) values (157766, '[-1.02152956085945, 0.336425145137876, -0.313553263385373, -2.37574074632575, -1.24365276004966, 0.25072928007119, -0.479263773057312, 0.910717504560184, -0.789249144668004, -0.0861725498597684, -0.572896643127133, -0.363761155508383, -0.0836958283477829, 0.0598091934281915, -1.1521057990177, 2.18782899237745, -0.466857216681224, -0.170132197777258, 0.31677566113259, -0.192849979100279, 0.366116021961412, 0.814691254502319, -0.256614347607256, -1.01829855377451, 0.309920150079677, -0.132524476187797, -0.232437087988535, -0.191173238902927]', 119.97); -insert into credit_card_transaction (time, features, amount) values (157767, '[1.44596827015342, -0.967781351868595, -1.45052837548686, 0.859817986090373, -0.314611724834731, -1.03451471947213, 0.713042867716276, -0.470117187930282, 0.384601111304867, -0.0902765207823949, -0.683802476267424, 0.941012053085625, 0.933540925050364, 0.150203612318974, -0.298497933226988, -0.276476616968022, -0.247571086525235, -0.900238859984641, 0.0389941203971027, 0.457884035586482, -0.0409693487055782, -0.611986036326481, -0.0112993831159174, 0.0914627236314364, -0.241331359081248, 0.0559144286062685, -0.113001746193072, -0.0036653972797491]', 317.5); -insert into credit_card_transaction (time, features, amount) values (157767, '[1.99978188271239, -1.38106930564719, -0.510861091272523, -2.0334754298425, -0.817134643662615, 0.731285945721773, -1.16423827559669, 0.268414131815501, 1.38908881781905, -0.513332926146742, -0.386251771271756, 1.74748777966454, 1.30880640066818, -0.700658610339719, 0.242186558412984, -3.50840044413948, 1.29663521662554, -0.858386689124356, -0.634919772398698, -0.65061098961387, -0.635277574546991, -0.764227923660287, 0.509443120589639, -1.04269213223713, -0.618404149446524, -0.467387544686102, 0.130478795615713, -0.0443650156202587]', 9.15); -insert into credit_card_transaction (time, features, amount) values (157767, '[0.086425106619282, 0.900032642421067, -0.358129728643541, -0.625827628318449, 0.833285800838617, -0.522932863536605, 0.788003376137708, 0.118301220595865, -0.145030997053161, -0.641489464184196, 0.972461060906132, 0.0234535335960295, -1.24452866506912, -0.580632861822568, -0.776102448827641, 0.487809510777499, 0.281032961543489, 0.291091160971207, -0.0494196163843757, -0.0526716531419151, -0.289089643609941, -0.769640915104281, 0.119523023251071, 0.569886482808782, -0.520803820326821, 0.0961276399165735, 0.214281526167865, 0.0723993197254135]', 3.87); -insert into credit_card_transaction (time, features, amount) values (157767, '[-0.528298223645267, -0.731875642714243, 0.0178543165502528, -3.4910795918773, 0.853715479730304, -0.596612102169269, 0.0981282849859685, -0.022334028448117, -0.23732224578101, -0.708153693457288, -0.797961026021, -0.162965234096047, -0.459914517077923, 0.324375749658801, -0.280650827893792, -1.8774694642922, -0.600028323277671, 2.55465599667619, 0.652943761494375, -0.353736123644125, 0.0071644185832811, 0.487273284646131, -0.522417351147492, -1.35478446297144, 0.558119179490178, 0.162605532681229, 0.0954202515621783, 0.102829359269462]', 15.17); -insert into credit_card_transaction (time, features, amount) values (157767, '[1.91063965823867, -1.12820485024079, -0.794145211838559, 0.297596684602411, -1.00485718522828, -0.560816933295807, -0.393137877086222, -0.188708712358157, 0.207397810631509, 0.638946493340846, -1.61061811516296, 0.35464422560531, -0.109596143999008, -0.401732138754131, -1.80422238642467, -2.27700097132786, 0.551392037660403, 0.262110056612717, -0.208856659952647, -0.471477772869692, -0.676112328650823, -1.32260451760321, 0.272120914217736, 0.0228504525002846, -0.293902191779638, 0.0877073042282331, -0.0249263159662662, -0.035345281816463]', 108.9); -insert into credit_card_transaction (time, features, amount) values (157768, '[1.83021175323441, 0.0152069672643427, -2.337987428892, 1.17606911527496, 1.00728618638305, -0.874858328889014, 1.11264192547235, -0.562675866580313, -0.401655965885629, 0.276676251999552, -0.84560550220951, 0.678838781192171, 1.22564592848784, 0.598545546316918, 0.0720918356915171, -0.410685883465121, -0.615007090362719, -0.401477390442439, -0.312609959816499, 0.128320855141149, 0.2494033398132, 0.540885516556525, -0.208752897926926, 0.525472970176081, 0.613520470159627, -0.452394555852107, -0.0621459464856337, -0.0347463364019328]', 150.0); -insert into credit_card_transaction (time, features, amount) values (157768, '[2.07148002858802, -0.643035393459739, -2.59335508082669, -0.398018505419956, 0.267754188032876, -1.23944320818091, 0.551255819226493, -0.466540216859111, -1.03476959056667, 1.04756650721258, 0.226693704045929, -0.124641254042228, -1.23941849872157, 1.19880417453292, -0.759988216402427, -2.2433346505424, -0.078821883309461, 1.50061431277259, -0.342761955659529, -0.595440943188553, -0.0019115227017201, 0.431267975970345, -0.23578935281118, -0.390004613573788, 0.644798870225799, 0.126206360261486, -0.0745242507924395, -0.0840601472188135]', 80.21); -insert into credit_card_transaction (time, features, amount) values (157769, '[-0.654893457602449, -0.504969417750165, 2.08852462863789, -0.692081273411401, -1.99432552649763, 1.03533540953023, -1.03860994444184, -1.7882274597354, -1.53681301435887, 1.4773042682504, -1.24789793325666, -1.01294020173202, 0.621546642790805, -1.22212913002582, 0.327444475381256, -1.76898815726383, 1.76964675353452, 0.239060159131878, 3.0274197236083, -0.384622425125271, 1.00365701809442, -0.950172790165122, -0.352600795956006, -0.0946933663432337, -0.113930247167629, 0.201831976959137, 0.265017235009149, -0.187115088634017]', 176.13); -insert into credit_card_transaction (time, features, amount) values (157769, '[2.10677907595987, -0.119487773947513, -1.65276702993052, -0.0684392716869086, 0.72317054798864, 0.15432681276692, 0.0168147320210374, -0.0360837744269233, 0.306746735743554, 0.229391996511042, 0.0166036273004197, 0.857335218488859, 0.429323797932416, 0.344588115171379, -0.563674618188453, 0.421887614003072, -0.968818851232465, -0.0158399153899857, 0.852440662310147, -0.133342260306259, -0.31181329173802, -0.822209454281445, 0.227948167524799, -0.345095761881023, -0.157492801101496, 0.210359823345141, -0.0792818395388925, -0.0735725230598602]', 1.29); -insert into credit_card_transaction (time, features, amount) values (157769, '[2.31215661584518, -1.40036098579913, -1.09906188853936, -1.67884149524907, -0.966691773178993, -0.350210581537372, -1.08150490735582, -0.247101917064222, -1.17686243079677, 1.52295180968422, -1.77393893238389, -0.573102149496182, 1.62585310802493, -0.754227811090483, -0.158839511812196, -0.244882397804565, 0.0381553547513713, 0.168134925252155, 0.189485022007953, -0.295320135055354, -0.200778942097377, -0.0426424916506479, 0.0932433132652524, -0.994819511082684, -0.0890488350507472, -0.121408565045101, 0.0220127748438834, -0.0506505427129274]', 39.2); -insert into credit_card_transaction (time, features, amount) values (157769, '[-0.98560150441428, 0.0027488429299808, 1.06398763313686, -2.93741998475694, -0.966534532472438, -0.928180918496612, -0.296156196043063, 0.355769372472044, -2.25370181420864, 0.397292158322868, -1.42034818687006, -1.45139916962189, -0.490115405947989, -0.0904981188342745, -0.716188135153326, -0.374637836388364, 0.581737115273459, -0.027376643610651, -0.780769860884393, -0.368406694636751, -0.173621169056687, -0.195741431847051, -0.326487494513507, -0.05778834345978, 0.756139210150513, -0.0963683707021458, 0.134642617991058, 0.0270221470189308]', 15.0); -insert into credit_card_transaction (time, features, amount) values (157769, '[-0.832518298863673, 0.779776243218614, -1.25021769149223, 0.961168379063914, 1.93679892041653, -1.19328782988975, 0.845158865908254, 0.0706803968453716, -1.23824382522858, -0.0062286526330954, -1.16245367190074, 0.490039718266208, 1.25663827558915, 0.914221198488144, 0.180629025683277, -0.775171509715917, -0.146259103831779, -0.0662089028429569, 0.640991832388317, 0.301384998669512, 0.389279156438792, 0.95396381857295, -0.21373248279491, 0.535825596604664, -0.220067889657704, -0.413149049450775, 0.373665734168359, 0.0943797392282521]', 3.6); -insert into credit_card_transaction (time, features, amount) values (157769, '[-2.24225907610366, 0.977886673797831, -1.22136121561303, -1.91164763208369, 2.92000132625384, 3.41693631151189, 0.287434910569005, 0.761615914295969, 0.207793947926626, 0.430248601163945, -0.158192744778151, -0.0103354642255143, -0.320903268512022, 0.120033822318762, 0.209387155372166, -0.214302216025041, -0.463829350602869, -0.89815290716544, 0.0015722748020685, -0.517524715349068, -0.290602901102974, -0.720429751187986, 0.27567779167481, 0.701451965160183, -0.036015299838611, 0.132265813579513, -1.05160084839892, -0.161274287214602]', 4.49); -insert into credit_card_transaction (time, features, amount) values (157769, '[-1.2221713764659, 0.256941101585903, -0.743576255788344, -0.601450809623127, 2.4756253937397, -0.768980289437268, 2.08519893250867, -0.221183811784298, -1.32773901054289, -0.7220193253328, 0.0272323899598352, 0.0693511147515338, -0.830731252709335, 1.02292781258321, -1.90873380604927, -0.122744517207548, -1.0721971135384, 0.264200877792174, -1.14931582354859, 0.14299419329196, 0.50681432700793, 0.98057983240688, -0.311384871205432, 0.229188047898153, 1.30658218342333, -0.391158707195793, -0.059376548670031, 0.0978467781656899]', 137.54); -insert into credit_card_transaction (time, features, amount) values (157770, '[-0.812429320224001, 1.01094065506864, -1.22323553988197, -0.319925505906064, 4.16993705425487, 3.21989130036166, 0.800424413193717, 0.824317820458038, -1.17795923808752, -1.15659480780641, 0.0776764992766642, -0.480303274122247, -0.641185168738057, -0.829568714054231, 0.0508342884666212, -0.516964150269976, 1.08644291843415, 0.19915410528376, 0.0228717890396188, 0.110572089496427, -0.0141152138482455, -0.117176016387318, -0.573328357231758, 0.586956111590302, 1.25379125432594, -0.264792519161459, 0.0505003491334401, 0.0761262644996659]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157771, '[0.124285182683536, 0.621313516802911, 0.350324027154793, -0.998057583130743, 0.520489298431237, -0.353371956029866, 0.469196209606206, -0.891390678398288, -0.307398652962039, -0.621586459245705, 0.587906819480283, 0.931623598798837, -0.0826423948246412, 0.470920781576085, -1.17892410952888, 0.426387123073848, -0.850344724417253, -0.417858245962064, -0.394843256504613, -0.343103939319599, 0.473240431842171, -1.12580857951561, -0.182608034210562, -0.399055991484434, 0.915010313947072, 0.232855311864915, 0.0576369964961767, 0.179180014402578]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157771, '[-0.242990654164359, 0.640742823570124, 1.00165439830479, -0.822652932678954, 0.84558966048581, -0.21138764956955, 0.957826044524522, -0.250031630632065, -0.10575091123484, -0.542821347036603, 0.539499045144091, 0.97056336348757, 0.781834905462046, -0.158656243510937, -0.764025845259596, -0.208713315184926, -0.937673937296159, 0.657149482437415, 0.0542891562586466, -0.0049543680482565, 0.431838598694042, 1.61971093967762, -0.561585227500615, -0.304102255831023, 0.183391913169409, -0.0396757235859728, -0.0062036655976332, -0.0828611499443617]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157772, '[1.31017480351477, -1.34463362363981, -2.13841767197186, 0.610094475184947, -0.412229024092678, -0.755911572302768, 0.279784998895369, -0.0400181586177361, 1.2155656482334, -0.741152491080024, 0.405338330641871, -0.73481892670317, -3.20303846507807, -0.572248959400507, -0.425405982234838, 0.45817094636224, 0.902172376877998, 1.06194764710972, 0.440674580545006, 0.361808133132404, -0.0354075927229494, -0.828468730435045, -0.142090624340617, -0.517739190017701, -0.287125493332519, -0.115937241277087, -0.0983546900626692, 0.0207458635426034]', 365.91); -insert into credit_card_transaction (time, features, amount) values (157773, '[-0.491711818696287, 0.534614466216042, 0.801587359080287, -2.25190653017621, -1.16736521547938, -0.218524878215519, -1.17231908620379, -3.21271110354301, 1.57431297826684, -1.24875448961119, 1.43833237166925, 2.12610554967541, 0.524117103252259, 0.0462122543072184, -0.133160554497505, -0.389566134565573, -0.210055440174481, 0.556853288423154, 0.258460915946185, -0.749468599916947, 3.37960379836302, 0.169932521631683, -0.0133275965242375, 0.604530093223917, 0.819350075028855, -0.0290593306772211, 0.348824864675366, 0.257084004095118]', 30.31); -insert into credit_card_transaction (time, features, amount) values (157773, '[2.0599937503275, 0.0355488102271656, -1.69847308189705, 0.447573486628858, 0.254865658468333, -0.889713872963706, 0.0600810766893002, -0.122942939283161, 0.735524976185817, -0.338016005434688, -0.714079190036607, -0.678416199495559, -1.6034190902689, -0.505481778399181, 0.426328403214653, 0.307532972835965, 0.658180215739715, -0.225415738505961, -0.0430830889905617, -0.27258947427812, -0.372020093494021, -1.03813778904758, 0.378703926164148, 0.533972862782642, -0.341145201602175, 0.176557519300914, -0.0700032604061238, -0.033746549328102]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157773, '[-2.46066235781784, -0.134260617371438, -1.64608133812644, -0.485049444169885, 1.13843816735465, -0.493130984360106, 0.976381643565979, -0.110134773943901, 0.3604456995989, 0.275240349643357, 0.0815082547074308, 0.513358872635824, -0.460554660788366, 0.423908929381195, -1.11279765633499, -0.156506737291257, -0.672055956515526, 0.140807802598068, 0.653163998795033, -1.37758569756536, -0.226354310213918, 0.34222638500683, 0.242484209495559, 0.241107489527039, 0.48952718920409, -0.377624950790441, -1.28852956108261, -0.443494617639548]', 71.99); -insert into credit_card_transaction (time, features, amount) values (157775, '[-1.51787229288128, 1.89601597169539, 1.08803947675864, 0.689745988369079, -0.293459936611964, 0.315342515617058, -0.259726742242229, 1.05150253689085, -0.512157031426186, -0.482111628081265, -1.28214288095566, 0.471790495853741, 0.896301657672484, 0.335454796464131, 0.753107171666111, 0.145411947450018, -0.0475694327752496, 0.183734442637367, 0.715834581137235, 0.154769893602717, -0.194721850894505, -0.585940874906564, -0.123096943110259, 0.526648157153492, 0.498110570224223, -0.656244307470282, 0.21441600250756, 0.0905057901084075]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157775, '[-1.35631757734504, 1.55650247881456, -1.83155808432243, -0.737107497251717, 0.822091233696138, -0.133242338211227, 0.442238408681287, 0.546426023550378, -0.378576140842973, 0.064692793780443, -0.335981643984759, 1.00806295492729, 0.570816779482257, 0.688531898419825, -1.54964789933688, 0.0841975508565132, -0.547707708124814, 0.0903187076919027, 0.57070597718863, -0.388329648903317, 0.138911138179736, 0.179375784011847, -0.0626948032717035, -0.0933471487199331, 0.12408719211319, 0.251553264379651, -0.831383174732354, -0.0689882418601661]', 14.95); -insert into credit_card_transaction (time, features, amount) values (157776, '[-0.483629039672677, 0.862919343428215, 0.241969230306266, -0.785441760986528, 0.427981560738354, -0.787576862182843, 1.06808034766767, -0.206278838255919, 0.351421462401874, 0.599191666340965, 0.89603893745247, 0.351590452139754, -0.950416420246187, 0.130918104595845, -0.896827140899966, -0.0498459459317213, -0.652963902994332, -0.324376971493484, 0.0618234413974431, 0.190307376232285, -0.339269120006709, -0.496306277363497, 0.151789235330665, -0.0185433136120239, -0.472956756917792, 0.109604324311234, 0.318189299839678, -0.0226858177003829]', 21.99); -insert into credit_card_transaction (time, features, amount) values (157776, '[2.12235345137732, -0.590116036627406, -1.35125081044742, -0.330565288598222, -0.467085628600007, -1.29288906259661, 0.0346033821373705, -0.479632204910543, -0.73427294431221, 0.862830726147338, -0.856820268734154, 0.448003786093931, 0.989909143442742, 0.0944840712058948, -0.281778213092926, -1.80481687129195, 0.0073501375003945, 0.39910583600684, -0.610811832591531, -0.508364741113887, -0.49637218815194, -0.858987613790647, 0.265824292385938, 0.0573870872907708, -0.206568543964115, 0.471945846077107, -0.0702951930329385, -0.0567715704560007]', 40.95); -insert into credit_card_transaction (time, features, amount) values (157776, '[2.08494970576506, -0.350520653731993, -0.708783601505585, -0.0709942367123143, -0.249444003029974, -0.222100250449101, -0.494786145421839, -0.0488541750505503, 1.36175685642087, -0.210628763092686, -1.66155916746123, 0.315050183415565, 0.537106050349446, -0.171950001653259, 0.72676082867972, 0.502210335618381, -0.892504925497154, 0.031446896116047, 0.423359658417319, -0.173698078452189, -0.262775165326991, -0.573536093596569, 0.262426807108464, -1.0228692974591, -0.352104585883983, -0.221802570044444, 0.0109086796631646, -0.0470074534292583]', 0.77); -insert into credit_card_transaction (time, features, amount) values (157776, '[2.09390858165358, 0.53401185029948, -2.91531234609916, 0.326214432532907, 1.33883326834842, -0.601534842835176, 0.267619528846932, -0.182491703530762, 0.255959522738661, -1.05337498207531, 0.810535711317133, 0.322869703221466, 0.694755780535056, -2.52670388487826, 0.456073493953549, 1.28414677040754, 1.0426426006074, 2.05689383215808, 0.0343607354792053, -0.0683086403386421, 0.0709972308706514, 0.413801551095538, -0.230228264253773, -1.6445166599445, 0.415637690784945, -0.0314731412132949, 0.0213549677806067, -0.0156481366162287]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157777, '[0.258839065931237, 1.1453971320348, -1.57573269457828, -0.45300092427609, 1.13293192656881, -0.269520574963918, 0.455688213924199, 0.333666102250306, -0.415155350819534, -1.0118162930503, -0.0062858202328939, 0.481708589418944, 0.763384283018362, -0.62344775425611, 0.0396604258591865, 0.75003680173846, -0.0597849403509406, 1.53696423233389, 0.46779224766643, -0.172033539850104, 0.291105530387901, 0.863549010613311, -0.295847639480309, -1.50680307363793, -0.11416885136106, -0.0805547294325712, -0.0629772132992395, -0.0684703785402445]', 1.5); -insert into credit_card_transaction (time, features, amount) values (157778, '[-0.102318316251731, 0.355017385142264, 1.4729474047879, -0.267198469329434, 0.432963313649831, 0.864003581834754, 0.170403656950197, 0.0894079849153625, 0.0681694778015647, -0.13876815989909, 0.390471602207007, 0.544438214826899, 0.521064806462692, -0.399394273993292, -0.0070969403901762, 0.0413247041760433, -0.646901948601163, 0.810754270786257, 1.17321864421709, 0.20274326752777, 0.231805215223454, 0.980055521347744, -0.252267747871963, 0.304314999476033, -0.513289491251356, 0.658486645372563, -0.0088058684746288, -0.060263478647028]', 11.5); -insert into credit_card_transaction (time, features, amount) values (157778, '[1.78885650099444, -0.620721353303257, -1.29683818060075, 0.312485231876388, 0.160377841021539, 0.19213061552681, -0.0826120878409747, -0.0104654682919457, 0.451343753398159, 0.180742863611422, 0.351711310538646, 1.04488788405264, 0.609121115143989, 0.196760470711252, -0.392266646646408, 0.480538783404065, -0.949356935866486, 0.307028283308058, 0.359981850445685, 0.137656758835248, 0.0530947014703609, -0.0287710389485747, 0.046576215739148, 0.130467585542789, -0.158868745309286, 0.196682086122215, -0.0703939656537369, -0.0391379534370372]', 135.87); -insert into credit_card_transaction (time, features, amount) values (157778, '[2.06909916910199, 0.0397052035519738, -1.06398693868696, 0.389424959053613, -0.0036415044140161, -1.14985812850832, 0.265593848041661, -0.400595677414124, 0.360015730537229, 0.0377184852461005, -0.586878624187003, 1.07099011665861, 1.30196708505851, 0.0272995760690688, -0.0902466627413603, -0.144927176995156, -0.380598420791667, -1.00029649221806, 0.161291828303106, -0.145422282146189, -0.279690652576102, -0.609487261059133, 0.31858653504276, 0.0093056222660505, -0.248349374596992, 0.195725014727467, -0.0626385646269889, -0.0580654173897355]', 0.99); -insert into credit_card_transaction (time, features, amount) values (157778, '[-0.280386396725125, 2.05643735762257, 0.534355930918401, 4.18256033813513, 0.914642401455556, 0.715753461101099, 0.538351359728649, 0.338910769066097, -2.75509007784256, 1.24137802040785, -1.24904654255637, -0.247220129209848, 1.55446248616795, 0.546797647532527, 0.838776137080321, -0.0421295629723352, 0.0423417610365934, 0.300246569601367, 1.14222589817074, 0.168664606962584, 0.337966688586995, 0.941663240063254, -0.299339986619958, 0.53320250153497, -0.042557735542329, 0.55670703594055, 0.039420864571738, 0.103543010269652]', 0.76); -insert into credit_card_transaction (time, features, amount) values (157779, '[1.0134097597409, -1.9655360588414, -0.708390208894882, 0.78124302946241, -0.194990511214701, 2.36979931220596, -0.581227199737161, 0.632245206200184, 1.47045899796536, -0.516921847812739, -0.357660982930948, 1.09700220655567, 0.282846558500045, -0.403394496130535, 0.480205938337181, -1.20073431686844, 0.985619728378594, -2.35268009309668, -1.4600415689333, 0.499063633916394, 0.102240451946455, -0.167278676850877, 0.156677992105042, -0.655062378629036, -0.898178946869809, 0.112042163128384, 0.0023162637562903, 0.0225791241904814]', 406.5); -insert into credit_card_transaction (time, features, amount) values (157779, '[2.03677345725835, 0.193002540918551, -1.75160139762415, 0.54922211534906, 0.18191310139789, -1.46146921927532, 0.257708311470463, -0.359733982392946, 0.619170569916506, -0.518355848745698, -0.306505743754919, -0.0562179477206154, -0.238917061163892, -0.780443127329162, 0.981247727886079, 0.188504094327591, 0.546085695896767, 0.484974419641384, -0.520129596065853, -0.213010033011811, 0.196540228077392, 0.728276767612655, -0.017493670483, -0.0917350122553697, 0.228576764241645, -0.0981131052530824, -0.0004629771078641, -0.0289234351047625]', 8.98); -insert into credit_card_transaction (time, features, amount) values (157779, '[-0.953238505615653, 2.01717562940193, -2.16473841210852, -0.590454640775954, 0.450714815121361, -0.684606111148835, -0.422010485683253, -2.1476043732179, -0.893040890683037, -1.05089177491157, -1.47208397708579, 0.775888968278593, 0.306591591088268, 1.30680464378162, -1.03888670278806, -0.202829941659205, 0.117920147436086, -0.538876393285495, -0.286637497058584, 0.366296835496053, -0.982736814549142, 1.13839618665175, 0.198279944588642, 0.728502527744802, -0.326472430753723, 0.503456319711958, -0.154502789382597, 0.0494869112409223]', 0.76); -insert into credit_card_transaction (time, features, amount) values (157780, '[2.06781851306589, 0.104644818473505, -1.88233553368743, 0.186163653052426, 0.719439201649155, -0.276746819297447, 0.0780962269578774, -0.0639645409492846, 0.25229724103368, -0.211215868042542, 0.714489892750947, 0.729101792575819, 0.165676782665825, -0.697226186149773, -0.470997224178535, 0.64937272645024, 0.0406792521941312, 0.333277045739408, 0.524690552764447, -0.124251806292644, -0.34410214116787, -0.912771001091965, 0.266898474215621, -0.0006499218590423, -0.219808198103312, 0.184000484438893, -0.0663427438499875, -0.045463192563996]', 0.99); -insert into credit_card_transaction (time, features, amount) values (157780, '[-1.00095108167436, 0.0926641167751102, 0.993433700312233, -2.37293470003817, -0.828563658732537, 0.447451717943579, -0.0306836712000791, 0.229574327294367, -0.716573063136824, 0.123317126768489, 0.65320676846542, 0.306755402265459, 0.861406145904901, -0.771620096732248, -1.36128080040317, 1.50862175205157, -0.369610905379354, -0.565533709315208, -0.034173917044718, -0.127527282854108, 0.574577495609956, 1.69848764543759, -0.245973485269818, 0.786508030681239, -0.233665344307878, -0.224636046667381, -0.465867239980456, -0.145249429858136]', 99.63); -insert into credit_card_transaction (time, features, amount) values (157780, '[1.80402729010402, -2.04594918249489, -2.03183687980939, -1.50208853905351, -0.896096915629037, -0.971482678299379, -0.117744364374252, -0.529923446606477, -1.76406653919984, 1.52379208510727, -1.37582485362172, -0.953328937904946, 0.834740156702428, -0.011332020539433, 0.151632174441215, -0.405426877640654, 0.184321218702203, -0.151580958715886, 0.0897142959038938, 0.213882804399551, -0.173125159325849, -0.758588070440682, -0.0683581935558691, -0.738910045975062, -0.181430394348902, -0.301734407697735, -0.0795126595948357, -0.0111360382367686]', 319.99); -insert into credit_card_transaction (time, features, amount) values (157781, '[-3.60040535002477, 3.37524390240019, 1.16154086116526, 2.16935186158576, 0.0972442717562901, 3.48277723336278, -3.49208787302232, -8.98538373659828, -1.010034161261, 0.716370984091628, -0.701455945783577, -0.295982297681442, -2.25665180292854, 0.791144257934859, -1.48954231088906, 1.75718070250106, -0.499024229491665, 1.16459520090701, -1.66334581247123, -1.03857031888746, 5.79689883638001, -1.6312361405125, 0.668684566928378, 0.0057695045405777, 0.613965220646946, 0.171247477194366, 0.304495914014083, 0.169033240489043]', 8.31); -insert into credit_card_transaction (time, features, amount) values (157781, '[-0.926530016935426, 0.552819758126288, 1.02101606870697, -0.56145619530983, 0.286978089461931, 0.429921046548355, -0.240833171475264, 0.779094719217207, -0.0889682025711841, -0.949481719104565, 0.129912320302033, 0.519085559886705, -0.369264909172681, 0.492552884286289, 0.0182917238995829, 0.402471482886646, -0.592370314465078, 0.72549363504051, 0.764600577427886, -0.0564104546495315, -0.0324616641790198, -0.342450227274175, -0.0493663571994011, 0.172209458445337, -0.28670858188023, -0.549882533672813, 0.029676237606545, 0.0293976301892023]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157782, '[1.99420007382194, 0.20328209088513, -2.22167546044555, 0.919224564867899, 0.334464973210506, -1.20236454726703, 0.0854832415120591, -0.15169093557666, 0.908378668820332, -1.03308819688495, -0.201889286682662, -0.804728288805386, -1.78826429436411, -2.32900233159897, -0.164745181451475, 0.27107971396419, 2.28493581907534, 0.635223873172831, -0.457834732566073, -0.225464982597318, -0.0094999376291866, 0.192975393388965, 0.0561449983873097, 0.907103269554833, 0.109863848070806, 0.677949478246875, -0.048309398780374, -0.0044567957004425]', 12.31); -insert into credit_card_transaction (time, features, amount) values (157782, '[2.06611903766989, 0.146688440940063, -2.77421847595329, 0.284229499356089, 1.08884530586723, -0.736788000680978, 0.549751660944165, -0.212392867022638, 0.0362142805102205, -0.174926365627297, 0.684277478770633, -0.0661757510162737, -1.30999300941029, -0.321066017856137, -0.660527649495515, 0.114580030676273, 0.589319219530518, 0.514893253061197, 0.337266642486896, -0.194768736004111, 0.0475876530702867, 0.202438262493501, -0.0791494940933178, 0.163797400828135, 0.369052099496389, 0.695610417284528, -0.114180681306726, -0.0643989958084699]', 19.0); -insert into credit_card_transaction (time, features, amount) values (157783, '[-0.979878896179132, 0.522062312058962, 2.01258301551263, -1.18247142890477, -0.0170107201378416, 0.127065921655057, 0.376307500997139, 0.217552591188037, 0.104611886870281, -0.876101264409803, 0.122635490710218, 0.13327557076538, -0.708813119843512, -0.13586137394032, -0.840978782361654, 0.798200430969386, -1.0323014880277, 0.758217704127001, -0.394200712799383, -0.145651159958244, 0.19794762160684, 0.521943775921732, -0.511829845422854, -0.297383447825327, 0.575334423118718, 0.597587947747104, -0.15037960011195, 0.0398573096008523]', 28.75); -insert into credit_card_transaction (time, features, amount) values (157783, '[-2.43447321443071, -1.49630092261442, 0.988123243933406, -0.185585085496054, 1.63736629712212, -1.28897188033997, -1.05892166209401, 0.69146823642827, 0.163342353480053, -1.16002343833251, -1.16989599544257, 0.330159212543466, 0.25895474896615, 0.386305625295146, 0.734111911105668, 0.438046735243131, -0.52953227760122, 0.15030146155238, -0.333336569232114, 0.475120614509924, 0.166263692749722, -0.493615282569969, -0.0437927036812678, 0.579518966227291, -0.295912368361664, -0.660305404762921, 0.0638148727303666, -0.278890680506288]', 1.18); -insert into credit_card_transaction (time, features, amount) values (157783, '[2.07439814554867, -1.20023839307236, -1.00340453983047, -1.15969893963708, -0.473629259057983, 0.497460234902729, -1.06717287054404, 0.123267623806147, -0.152889132789216, 0.856702417553234, 0.193237104707309, 0.142038244838355, 0.769863559805138, -0.430140926075868, -0.41684473448237, 1.55715196616014, -0.427964325276582, -0.466826410708433, 0.984986838831341, 0.175708428553576, 0.356062279085961, 0.948192103751228, 0.0010807285451168, -0.156149082121745, -0.0638014486663824, -0.0890644644358541, -0.0039194555651569, -0.0496404707551375]', 69.0); -insert into credit_card_transaction (time, features, amount) values (157784, '[-6.83494585506618, 6.01149920932796, -3.76166846494157, -2.38438038184422, -0.951454362918691, -0.69396007181302, 0.0287032185130134, 1.11973462385617, 4.66964640367519, 7.81788492428989, 0.19585355042168, 1.12951707766327, 0.461511601028897, -1.17332423240942, -0.695849051709386, 0.0494065408354222, -1.01078774988656, -0.303315732077302, -0.213116414489196, 3.28374639857706, -1.07213122092326, -1.21565617827113, 0.314256724601256, -1.20985429374393, 1.05034170829954, 0.257051456492317, 2.30558304027547, 1.25372599380128]', 10.72); -insert into credit_card_transaction (time, features, amount) values (157784, '[-1.61453549413703, 2.23655506897636, -1.40665957136483, -1.07459976320833, 0.713048441531505, -0.412666008627848, 0.697932203774938, 0.257758782622531, 0.831307090790867, 1.26618973989421, 0.86969423441911, 0.85338194994886, 0.54029910203655, -1.29729730689968, -0.877221954184634, 0.513154755554104, -0.0400221598274527, 0.236200752589882, 0.0124765900635108, 0.773529114025214, -0.486337679659915, -0.863372486405895, 0.121597789108536, 0.166925261406621, -0.0885963882884426, 0.103197289248606, 0.418249661372906, 0.186256617321987]', 9.84); -insert into credit_card_transaction (time, features, amount) values (157788, '[-1.23806870081621, -0.241370910316551, 1.78951666107227, -1.95849788995376, -0.630024063624882, 0.1826377184353, -0.68559739383919, 0.599707185311589, -1.05219984102774, -0.625705991193626, -1.20483792716033, -0.242677147569136, 1.5731595832371, -0.759474973418733, 0.125146765617839, 1.68037468315652, -0.0737421236078771, -0.759565502043703, 0.413325963181539, 0.371066566625343, 0.359032963552828, 0.628953747373009, -0.205918640016089, 0.5177493434165, 0.499011592427931, -0.133753572686875, -0.0696998679487452, -0.0483639740316609]', 66.09); -insert into credit_card_transaction (time, features, amount) values (157788, '[-0.0538441777189786, 0.516663067015787, 0.702899966237766, -0.425265521708626, 0.0466963615380727, 0.151970801546386, 0.0979226019228953, 0.0479308608149707, 0.72430240930352, -0.266566681916688, -1.5719018814677, -0.330003472536231, -0.189827166107374, -0.326443219904772, 0.172896927417679, 0.206757051068396, -0.580001578083732, 0.387909419609355, 0.171883669721597, -0.14041993430956, 0.334035812950463, 1.0387651788967, 0.0387459363526379, 0.525989467303559, -1.37831327929168, 0.398160260245502, -0.007013475458329, 0.268774433185507]', 11.5); -insert into credit_card_transaction (time, features, amount) values (157788, '[1.90483460877212, -0.680000949574439, -0.516134896317598, 0.396361237267193, -0.619690794280313, -0.0645270298795779, -0.680489386135686, 0.0679856103737888, 1.350639076842, -0.0072222218139201, -1.28367658489775, -0.0627387235976184, -0.38349524510082, -0.157458684592997, 0.47762663827315, 0.438326046107281, -0.544215113179838, 0.179753226817695, -0.192474034989205, -0.080835502191962, 0.168845716888357, 0.51953624932574, 0.133577490755637, 0.620046481296115, -0.275699558240373, 0.541108591518084, -0.0386475470016383, -0.0333449831255197]', 64.99); -insert into credit_card_transaction (time, features, amount) values (157788, '[2.02060192477424, -0.113312080659788, -1.18116849832287, 0.230234223145931, 0.0979436411472906, -0.691716504228536, 0.119542569810986, -0.195272326402994, 0.235979527083364, 0.224522743893134, 0.746702427235777, 1.25566787298096, 0.47621521618637, 0.368030445885188, -0.683820453791438, 0.165316884917122, -0.679750102064181, -0.32153937361557, 0.549563712323539, -0.152055810665382, -0.246750499064289, -0.615445049665521, 0.273130862984504, -0.32339939116368, -0.275103485529216, 0.19562810759799, -0.0742163810614929, -0.0704639708833981]', 12.99); -insert into credit_card_transaction (time, features, amount) values (157788, '[1.97681586145809, -0.300227574124501, -0.202509829270536, 0.514450296628804, -0.688378361578636, -0.577494048178286, -0.498154426432531, -0.147607737908881, 1.2479949784983, -0.208564405031669, -0.751244885604305, 1.262623088601, 1.58765070285988, -0.491428774983362, 0.313639531784825, 0.0083111493676174, -0.587018056256389, 0.0205127939159817, -0.237851044829026, -0.127056989823762, 0.20988686289498, 0.936274049867588, 0.0995308658620479, 0.0866056783142172, -0.0451967504276541, -0.21912933157175, 0.0513469735634152, -0.0332469539016636]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157789, '[-2.07189825678866, -2.89725197851471, 0.915629533410171, -1.03671855444872, -0.0615598270327908, -0.856319052934606, -1.86418245203782, 0.98893820487952, 0.0179712896745276, -0.206299713917169, -0.600998459503273, -1.24978947256139, -2.91337643219801, 0.152993940439434, -1.62757341889876, 1.44907395301715, 0.424859254000954, -0.380859073037304, 1.08037602445019, 0.577281686862415, 0.278026934451293, -0.329678654841556, 0.172955274048497, -0.41193745945975, -0.18795114859601, -0.37306535214685, -0.105579519748476, -0.438733444508114]', 101.79); -insert into credit_card_transaction (time, features, amount) values (157790, '[-1.33847170533031, -0.111245308432117, 0.321350739432179, -0.105076259064268, -2.74654469384719, 1.14779886831328, 2.37939175304536, -0.129443494240711, -0.0036474432747553, -0.581719463774343, 0.73225500347074, 0.0065964417418837, -0.668367515770877, 0.154513694170835, 0.229227555569845, 0.888000487683456, -0.842977026522441, 0.908178014533206, 0.0311094077957141, -0.502696107127784, 0.112415724077736, 0.840739034158676, 0.222557740208872, 0.126270742747746, -0.0423189404819935, 0.390042672122973, -0.179813204908807, -0.426970486753851]', 572.9); -insert into credit_card_transaction (time, features, amount) values (157791, '[-2.70324614823207, -0.340501685859222, 0.728988015887111, -0.0787558038947305, -0.214525421514046, -0.16414946891801, -0.0414199275384106, 0.903150308388252, -0.266103449304912, -1.43049553170244, -1.15783365854529, 0.245259202785765, 0.374256667601856, 0.561935615802697, 1.14336551538312, 0.459566952317976, -0.191384396005968, 0.230225487995711, 0.359369728730184, -0.218679023315111, -0.0856197166348758, -0.453883543919644, 0.535629709988353, 0.575731744543518, 0.496849461577905, -0.419972793971856, -0.0157496148585376, -0.59232023806864]', 68.82); -insert into credit_card_transaction (time, features, amount) values (157791, '[1.97054751776093, -0.760623421427038, -1.67157026037189, -0.637687109696004, 1.6652902680225, 3.92653078274165, -1.30440982698839, 1.05872763846903, 1.11058953814946, 0.0237403500193585, -0.216871341471088, 0.371081672934286, -0.0223005581197026, -0.0622073906825891, 0.76694010262227, 0.244276330096594, -0.566969378451654, -0.127845508391831, -0.393274463401349, -0.110734387951164, 0.160351657608665, 0.564189165496309, 0.202586142725311, 0.759792872726705, -0.245286156758252, 0.589136426517134, -0.0002525065755098, -0.0529491958647838]', 11.5); -insert into credit_card_transaction (time, features, amount) values (157791, '[-10.283840326559, 8.73711360390633, -6.25330974661393, -2.45024877678851, -2.56093879594621, -1.33378879234573, -1.25946016721643, 2.73580670425344, 5.88774663796836, 9.67169006809798, 1.30871552526723, 1.94769160921491, 0.548987944031479, -1.91738077821551, -0.547095584663062, 0.237957570618949, 0.704478801108747, -0.299044465112427, -1.17118782944075, 4.12650511602013, -1.28080026741558, -1.41057724201119, 0.720097726241932, 0.460297611367704, 1.44526002111981, 0.125872714560615, 2.09049364024244, 0.856336026652095]', 9.84); -insert into credit_card_transaction (time, features, amount) values (157793, '[1.70426112012253, -1.21723015184258, -2.6590138769852, -0.16962221378476, -0.0995270934332791, -1.65210398193167, 0.970277658633988, -0.768445643973197, -1.22169456048433, 0.897693011540047, -0.918536993788862, -0.0791270371168364, 0.256962111023529, 0.720436402586334, -0.328788215028114, -2.32369095262563, 0.248242692450853, 0.539097376352781, -0.83078590128427, -0.0647737252828582, 0.0743359531383701, 0.242295510706484, -0.333876428269169, 0.0808861447671155, 0.39209091536391, 0.992057881423392, -0.170347997344765, -0.0431583663526275]', 289.99); -insert into credit_card_transaction (time, features, amount) values (157793, '[-0.941075928255147, 1.28633024228262, -1.07687293442658, -1.39046125326578, 1.43061052775681, -1.23053906433383, 1.73407122127421, -0.542389222190825, 0.212248655442623, 0.959118897606692, 0.621014855315113, 0.269938275195855, -0.546320069292819, 0.475047431052903, -0.671344860128032, -0.536315480872384, -0.875355875867887, 0.0920936944304808, 0.185843559174571, 0.195725437872443, 0.089002743620273, 0.964125006335455, -0.12043648313724, -0.427629160702855, -0.137407325198694, 0.0866793615809219, 0.494364656059916, 0.163389410493054]', 2.99); -insert into credit_card_transaction (time, features, amount) values (157793, '[1.40881559177793, -1.55713284586253, -1.13491976241115, 0.345679637936459, -0.654766466863484, 0.006810677876549, -0.188424483665475, -0.0829263009312008, 1.17067106218679, -0.0934368723754421, -1.75493489590746, -0.301603380671381, -0.0141160580170873, 0.0261619745824533, 1.08963463844386, 0.843983925732166, -0.93005246277163, 0.433402569407785, -0.162612788749123, 0.518393435909588, 0.318678698796014, 0.270905737949466, -0.22917623162061, -1.00418347723432, -0.367749434467483, 0.684483858935735, -0.101795841969133, -0.0004027601922978]', 352.32); -insert into credit_card_transaction (time, features, amount) values (157793, '[-1.1899796712283, 1.89133152014838, -1.50382624216855, -0.992897074673071, 0.740751862618331, 0.570557901130913, -0.287722069688846, -2.0111499604055, 0.248511132178709, -1.04981077617008, 0.233052089272971, 1.19617566027916, 0.81630393050234, -1.3566394103766, -1.33717529319061, 0.566678551320692, 0.643196984946578, 0.889065393449315, 0.481156217036166, -0.713867019432395, 2.18901942970767, -1.13963188370464, 0.260885070471903, -0.290936007890761, -0.0941916505802669, -0.179866204141953, -0.377582941100181, -0.0309089405483861]', 29.5); -insert into credit_card_transaction (time, features, amount) values (157793, '[-0.0354484927244249, 0.730175148017973, 0.330132311329335, -0.674381883359044, 0.407005295234552, -0.786659113463449, 0.852747280344624, -0.0035221742108129, -0.215483630309981, -0.233704399734699, 0.789823718839538, 0.538536864697287, -0.723863511660823, 0.44676274091715, -0.992120607045315, 0.0499755865673419, -0.536108856638944, -0.289741615224721, 0.105397280446734, -0.0627986867173875, -0.200565479906558, -0.473075582106466, 0.0954852428414791, -0.0068473172003214, -0.564490397539484, 0.122724199658887, 0.240348445434052, 0.0868966699629609]', 7.16); -insert into credit_card_transaction (time, features, amount) values (157794, '[1.5054188142728, -0.663141131019519, -1.82721902533205, 1.50291579164055, 0.123218519731032, -0.805778420080681, 0.809267781049699, -0.291916324702562, 0.0399271703654445, 0.338321858789789, 0.656092031455265, 0.585527683531508, -1.193889690807, 0.965122231842391, -1.09845048067001, -0.494213906317943, -0.289452788942982, -0.0351413041283715, -0.0383327184291764, 0.149872184084339, 0.245722187709739, 0.301197007932837, -0.209492887345876, 0.0121126993617299, 0.29705294597988, -0.53538427156362, -0.0704194261207085, -0.030524233283834]', 253.83); -insert into credit_card_transaction (time, features, amount) values (157795, '[-1.09524449799202, -2.08486258833577, -1.61282104198312, -1.65028590912733, -0.69943692831602, 0.513547047736151, 2.73329184994019, -0.284772443308236, -1.5750877294259, -0.246401417558659, -0.181472804964862, -1.02655085763717, -0.94510976484046, 0.371276828671496, -1.75649263483503, 0.854378647728466, -0.0874402403379363, -0.579409792095228, 1.06566347983326, 1.50284547037691, 0.750287653327273, 0.839512686258899, 1.44625649225825, 0.0320225941007407, -0.263077226122788, -0.259622976586242, -0.0652480312764561, 0.265176912943714]', 675.0); -insert into credit_card_transaction (time, features, amount) values (157795, '[-1.1000160779094, 0.291211950319425, 0.157204771254036, -0.630805393549851, 0.0453442932722407, 0.370754662351859, 0.988364209672035, 0.476960215105395, -0.688994122996438, -0.996703117078864, 0.175292946428921, 0.742694436065353, 0.354052102776272, 0.474695881146295, -0.864716846831595, 0.534585823528542, -0.78082901526066, 0.50235661240969, 0.131142532676325, 0.320292751086516, 0.247227514668375, 0.179540077546935, 0.319905550315546, 0.35679127720391, -0.126108599448645, 0.151868724601958, -0.097839476874566, 0.0690080900724724]', 209.85); -insert into credit_card_transaction (time, features, amount) values (157798, '[1.88636805509399, -1.69106924878415, 0.172131498017553, -1.03945748508987, -2.10528535901864, -0.479979542022299, -1.48133707242017, 0.0412689582262737, 0.939901653906973, 0.43224136958161, -1.12868754288559, -0.104254024427807, 0.116612533517988, -0.522228783375368, 1.05070826482395, -0.839808201109878, -0.319475822040389, 1.71351266618556, -0.912773601270047, -0.355056414475206, -0.100139912822088, 0.119542699214534, 0.242156321689805, 0.0709727951370877, -0.776636067064766, 0.864146376838571, -0.0119149596761949, -0.0168288622922416]', 120.75); -insert into credit_card_transaction (time, features, amount) values (157798, '[1.89969467743245, -0.683079288017006, -0.43764357746394, 0.454744961831374, -0.749998570682082, -0.285773891366412, -0.639655171261453, 0.0085190773210286, 1.37061128932421, -0.0088333309115908, -1.38817600090682, -0.0496881503828339, -0.341784204535597, -0.155226560725719, 0.491720089117549, 0.408714051724439, -0.537683192278867, 0.115614878232876, -0.201478015447254, -0.109308416806466, 0.167824668261193, 0.566092185530666, 0.0794297783880152, -0.373060634318798, -0.281931873520492, 0.592690630312245, -0.0305438387986692, -0.0429024290883929]', 64.99); -insert into credit_card_transaction (time, features, amount) values (157798, '[-1.56614371337096, -1.10693239810506, 1.77284847898343, -2.28493973369918, -0.264700990447496, -0.161627137716695, 0.127037332024835, -0.0861226204207469, -0.563170732863897, 0.250466538012205, 0.323031405000328, -1.49108959090539, -1.75437162498233, -0.363816133964697, -0.313715336960086, 1.83562204227253, -0.589120866101788, -0.149860091600641, 0.135215891538, -0.119417289762808, 0.324400436745769, 0.981932507551466, -0.262115931098626, -0.403542801772277, 0.658971419543815, -0.0541286457657929, -0.402749386959748, -0.0046031863982481]', 127.75); -insert into credit_card_transaction (time, features, amount) values (157798, '[0.0717710443982317, 0.753516692410123, -0.984974259008293, -1.24756611258667, 1.71319288379423, -0.63812538392805, 1.60438741913532, -0.5405278809027, -0.404328116091301, -0.0401934976728908, 0.616694543219629, 0.377847497308172, -0.172795688280997, 0.553395785357984, -0.595742280806656, -0.406635308584287, -0.881831437583427, 0.121085223740003, 0.300454949134101, -0.16062321024601, 0.204559542765417, 0.728217503866964, -0.263298198562384, 0.270649307683319, 0.228751199132963, 0.0973390325057113, -0.467004343031063, -0.266497894160752]', 7.7); -insert into credit_card_transaction (time, features, amount) values (157798, '[-0.444765598861338, 1.4627002885693, -0.880433959796999, -0.556376131927674, 0.616283347546082, -0.884929262646801, 0.65443010354292, 0.291004051506747, -0.114848220369264, -0.7694764811407, -0.732539713278964, 0.369788145204632, 0.685989688752277, -0.893586952353969, -0.325634003133353, 0.414216351739519, 0.481519585730879, -0.260239286706494, -0.259291156266131, 0.081566767767721, -0.323589916959774, -0.825590009077581, 0.14828898750374, 0.571969365975727, -0.321968248331121, 0.118447678763248, 0.210471038850441, 0.0790120613342076]', 9.42); -insert into credit_card_transaction (time, features, amount) values (157799, '[2.03366408140585, -0.0833393815847641, -1.17305539330393, 0.211189610999452, 0.14959928275766, -0.604363683345264, 0.0938741840653013, -0.169100508228718, 0.228032031805312, 0.219556109328809, 0.79842057185103, 1.30147264544246, 0.526854962992368, 0.359733156346715, -0.643201984182282, 0.105300913566589, -0.630077193524295, -0.416557445454839, 0.484176487231363, -0.176936883853522, -0.247493639344885, -0.583147784274602, 0.287797107760436, -0.381990204604314, -0.283074969671472, 0.202297184485535, -0.0686148773088367, -0.072912980623324]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157799, '[2.00145510449199, -0.3640913493235, -0.505150794759056, 0.219068606484759, -0.456185848574338, -0.369052650094353, -0.487073857691969, -0.015589597393387, 1.02205274237803, -0.0093018226952011, -0.836523616955133, 0.32769854422222, 0.105261622254801, -0.0629508169127828, 0.566749597818622, 0.454491906522139, -0.535872111010472, -0.448028196133696, -0.0081160894693764, -0.144538038084023, -0.267001452049833, -0.725826540128248, 0.465148517872478, 0.719175806945812, -0.626860750943678, 0.19855587433563, -0.046282506461219, -0.0355115776401416]', 16.9); -insert into credit_card_transaction (time, features, amount) values (157799, '[2.13414538455416, -0.661133756271348, -1.62020309454371, -1.80997787279354, -0.493490957186542, -1.65088868752532, 0.0492398231276711, -0.394477536561428, 2.4796692887107, -1.28128021128026, -1.00824035250406, 0.612818792606274, -0.921740936016974, 0.350522934108258, 0.361087432136657, -1.6197206563663, 0.26256794374308, -0.0363243555034819, 1.28656592455884, -0.301006891099887, 0.169722443010636, 0.93537256888383, -0.103470706404273, 0.0331165628042509, 0.550642274269616, -0.551365312090925, 0.0323452695913875, -0.0645029207216555]', 0.23); -insert into credit_card_transaction (time, features, amount) values (157800, '[-4.71915049006679, 1.59252490416968, -2.77258664723401, -0.498435936843101, 0.0862327867792849, -1.28217641634285, 0.110770674355989, 0.621997425154314, 1.78121060829476, 1.89354129619428, -0.89978516738163, -0.049430419132411, -0.256056578737117, -1.12021664474182, 0.136701657768248, 0.646386275540903, 0.509462863953576, -0.276863394154898, -0.144206613551039, -0.840948552959527, -0.969393619172675, -0.848938034479947, 1.01278059333581, 0.478191586938237, 0.169007371363003, 0.0875961383361338, -0.324330891455179, -0.515202678666404]', 8.96); -insert into credit_card_transaction (time, features, amount) values (157800, '[2.12667843180652, 0.133713443950872, -2.42777775999825, -0.096190961163517, 1.24382599776436, -0.371659310695292, 0.626161813595055, -0.288448829506422, -0.092206427167988, 0.191698543086133, 0.388735065111448, 0.954648513131259, 0.551570612664994, 0.822799917368543, -0.207282566708548, -0.194168910125332, -0.892265401023494, 0.182727892336413, 0.557631096372231, -0.155880921197694, 0.111172616944129, 0.420920095209807, -0.0957957580094313, -0.165403955024978, 0.531199584254473, -0.162307976902683, -0.0582324650055861, -0.0812866001290752]', 5.9); -insert into credit_card_transaction (time, features, amount) values (157801, '[0.0887065212412666, 0.671882530527959, -0.328513081669109, -1.05325255415979, 1.12358263889934, 0.196045567863838, 0.716812566827932, 0.192173702280555, -0.0114290786690494, -0.201183642288358, -0.469416836360925, -0.379908560318137, -1.38654065868403, 0.532065928907626, -0.813704804217099, 0.516036796028196, -0.988442457520956, 0.320782290568175, 0.634688866187384, -0.0637802489863149, -0.304158150648714, -0.838992116765941, -0.0266499361434722, -0.399958478397064, -0.408975086103619, 0.158634024864416, 0.227705074155744, 0.0799647221145074]', 0.99); -insert into credit_card_transaction (time, features, amount) values (157801, '[1.9735382184824, -0.147425138707456, -0.599246028867224, 1.08804878544682, 0.0732754100694228, 0.383364645579075, -0.451485731702857, 0.0982676112933362, 0.90663549383973, 0.128761867448397, -1.4651525474147, 0.32735165650902, 0.533903566628463, -0.136347095302895, 0.543279076679071, 0.531401513975966, -0.902928034118601, 0.0022829410542289, -0.258475490943602, -0.162518793580638, -0.204209320059014, -0.500164386275119, 0.308062419687576, -0.0408613540802333, -0.271705466889993, -0.929683420196922, 0.0549855011854161, -0.0217298188919691]', 19.9); -insert into credit_card_transaction (time, features, amount) values (157801, '[2.01830670288122, 0.0931911700577121, -1.60942403841763, 0.348380177241888, 0.358500129930782, -0.669727481531726, 0.0691712544751756, -0.0866844517300812, 0.261000291569162, -0.202013781975235, 1.25386058917496, 0.758184250024602, -0.314348565226374, -0.584543685131868, -0.4802515494999, 0.470483892452355, 0.305771983743395, 0.158658560182585, 0.273490970439248, -0.167240773196018, -0.303477276538758, -0.819197993835738, 0.353464826937627, 0.662657093125669, -0.32213878650529, 0.143428186684445, -0.0680184523112714, -0.039252929058807]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157801, '[1.97560988443601, -0.817668328450572, -0.525335964834477, -0.904969880073108, -0.554565913008623, 0.129656949366575, -0.827775847769124, 0.0236044256365399, 1.69438094609917, -0.521669296698851, -1.20404430539154, 0.978779468346732, 1.75375048894336, -0.637687818930429, 1.01691665173731, 0.551238775272759, -0.879625304752796, 0.159658354835614, 0.40476816657131, 0.0910090554521392, 0.0261771051875942, 0.188393994522829, 0.189203096617308, 0.118325879901473, -0.439152455777008, 0.534854161742983, -0.0207366959673776, -0.0298431563004567]', 60.76); -insert into credit_card_transaction (time, features, amount) values (157801, '[1.91287333121634, -0.416397195209376, -1.83478074831675, 0.355999626944455, 0.166662748657346, -0.905560750342791, 0.404800849619557, -0.234917067784546, 0.361806013944991, 0.286331550014571, 0.271153631848679, 0.131214427717345, -1.64812143327027, 0.908130262815438, -0.948889902075486, -0.198725558743612, -0.348971679440399, -0.0472083879472373, 0.592916702819985, -0.151136198935177, 0.026626676054661, 0.003787006106764, -0.0269927621737257, -0.311536580442517, 0.110858216809369, 0.557599446584875, -0.125910463060418, -0.0794813664768505]', 84.98); -insert into credit_card_transaction (time, features, amount) values (157802, '[2.0579682372007, -0.0684551655947941, -1.09797955689948, 0.39351780275777, -0.0867946578808905, -1.0909706649568, 0.162363103157028, -0.299255940455945, 0.559294751777712, 0.0676338175553091, -0.769976535487005, 0.384450783029092, -0.023187848319652, 0.295945015670599, 0.103064396304832, -0.138724323681403, -0.251828539871413, -0.923799957736315, 0.101375165298171, -0.234150781460144, -0.289005523242351, -0.696373108347065, 0.339215265258751, -0.0863960835613664, -0.307350112052131, 0.205731819147201, -0.0683123157429526, -0.0613843734468539]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157802, '[-0.662579830545148, 0.353075290813157, 1.41182994209554, -0.392374918692448, 0.158478536668967, 0.543043141948079, -0.437423860066864, 0.276350030346687, 1.61112203379215, -1.4217206739337, -2.1439523399203, -0.0207896149251316, 0.456672346458041, -2.43470155534823, -0.638659850456144, 0.644993285478948, 0.156328940462853, 1.27748852679236, 0.0121014679009533, -0.169687510623998, 0.147664043963046, 0.789870322417577, -0.38565441956634, -1.05334016819136, -0.440951870893653, -0.243626478490085, 0.0443777701082882, 0.222243042419404]', 7.7); -insert into credit_card_transaction (time, features, amount) values (157803, '[-1.01015212072886, 0.633830094908954, 1.68437076850686, 0.299068887075505, 0.711967035645827, 0.572947214952501, 0.407069893075968, 0.266185254763064, 0.0115740094057204, -0.554820141501952, 0.401217734016973, 1.15595885756949, -0.0667284508338286, -0.361890919936152, -2.10600352397657, -0.277522586916977, -0.328805007685352, -0.384637047355829, 0.350736881494707, -0.209975958521421, -0.481706181869206, -1.31370812660583, -0.0847678629843969, 0.629921569170175, 0.552263283413985, -1.05212396800231, -0.267668691111145, -0.0188005550464329]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157804, '[0.862941187980347, -1.88749019335918, -2.17087155786798, 0.852340177395539, -0.621354181195796, -0.781277508071769, 0.682628938147886, -0.201053970899531, 0.87937039968048, -0.904076081002724, 1.13762261571622, 0.417394820666489, -1.37793888553869, -0.86467663176151, -0.585048920415896, 0.222538462574613, 1.00530597135217, 0.656441242794341, 0.135987224791507, 0.895278671772378, 0.147433546394276, -0.690343079415677, -0.295426478503889, -0.101920082758047, -0.371265073573484, -0.164802184968382, -0.122705562608091, 0.0653487872328319]', 578.8); -insert into credit_card_transaction (time, features, amount) values (157804, '[0.169367883595559, 0.956147953074134, -0.556427123686125, 0.936963561208608, 0.930524383977687, 0.0636670684875959, 0.41622741991107, -0.0466919099127169, -0.538375101643974, 0.196328088871118, 0.79058152210962, -0.0181310328141218, -0.361565946321907, -0.504925910185467, 0.707689218194274, -0.515066597432359, 1.05275932766738, 0.847558427187433, 3.12387907619402, 0.180782302865973, -0.135378894098173, -0.335589119619996, 0.202964448648445, 0.206551350161792, -1.56237916096899, 0.414619289668535, -0.010551588799948, 0.305325512713878]', 1.29); -insert into credit_card_transaction (time, features, amount) values (157804, '[1.7006940593433, -1.42123237639736, -1.236457695055, -0.451099156233925, -1.20180416536041, -0.810533600090655, -0.789689274938437, -0.0233491361941443, -0.0546303091436498, 0.191947700884504, 1.25585753821169, -0.629191490336688, -1.01847302417451, -1.63492786820819, -0.228735136051851, 1.91095573571045, 1.23038232679234, 0.190069856999646, 0.398541286980192, 0.37380933899007, 0.405629138174191, 0.718489472418009, -0.0597655152051037, -0.0411395882353453, -0.304357932886922, -0.130779229930871, -0.0198535948597151, 0.0119640120314064]', 219.0); -insert into credit_card_transaction (time, features, amount) values (157804, '[1.93023662261023, -0.196151849026805, -0.598748101949689, 1.24976328085023, 0.139448992847324, 0.717800771260176, -0.41239489264628, 0.2553959189401, 0.918409464006159, 0.142431299306595, 0.0358968765579994, 1.31270067658047, -0.0803377023810168, -0.131581267851333, -1.80560602428491, -0.134041026321317, -0.43969189855515, -0.308555520479416, 0.613804168172047, -0.242471693522345, -0.50302574730202, -1.20216131086347, 0.412954529689502, 0.137592601043651, -0.279280342348862, -1.12554099041351, 0.0498527649449709, -0.0387168199646039]', 4.94); -insert into credit_card_transaction (time, features, amount) values (157804, '[1.93023662261023, -0.196151849026805, -0.598748101949689, 1.24976328085023, 0.139448992847324, 0.717800771260176, -0.41239489264628, 0.2553959189401, 0.918409464006159, 0.142431299306595, 0.0358968765579994, 1.31270067658047, -0.0803377023810168, -0.131581267851333, -1.80560602428491, -0.134041026321317, -0.43969189855515, -0.308555520479416, 0.613804168172047, -0.242471693522345, -0.50302574730202, -1.20216131086347, 0.412954529689502, 0.137592601043651, -0.279280342348862, -1.12554099041351, 0.0498527649449709, -0.0387168199646039]', 4.94); -insert into credit_card_transaction (time, features, amount) values (157804, '[1.93014002822133, -0.196311465319916, -0.598804167418757, 1.24980389623073, 0.139399680518361, 0.717818764605702, -0.412328543602562, 0.25538294124622, 0.91840357469867, 0.142408011109847, 0.0358975929153066, 1.31270273601648, -0.0803287880500169, -0.131569948050575, -1.80559973431211, -0.134034431594372, -0.439690416200348, -0.308545276116013, 0.613788198660126, -0.242369870508684, -0.502995450759948, -1.20218770026672, 0.412910459714429, 0.137595166667521, -0.279298701122698, -1.12554632302787, 0.0498433175974572, -0.0387081140778168]', 4.99); -insert into credit_card_transaction (time, features, amount) values (157804, '[1.93014002822133, -0.196311465319916, -0.598804167418757, 1.24980389623073, 0.139399680518361, 0.717818764605702, -0.412328543602562, 0.25538294124622, 0.91840357469867, 0.142408011109847, 0.0358975929153066, 1.31270273601648, -0.0803287880500169, -0.131569948050575, -1.80559973431211, -0.134034431594372, -0.439690416200348, -0.308545276116013, 0.613788198660126, -0.242369870508684, -0.502995450759948, -1.20218770026672, 0.412910459714429, 0.137595166667521, -0.279298701122698, -1.12554632302787, 0.0498433175974572, -0.0387081140778168]', 4.99); -insert into credit_card_transaction (time, features, amount) values (157804, '[2.03293896236003, -0.133499827984758, -0.89097044694298, 0.469413420697929, -0.239498274872574, -0.905814587957579, -0.0608221756817656, -0.293101114214716, 0.897950341445993, -0.107902136797229, -0.726465882732101, 0.901733083294368, 0.977775761845263, -0.0510636643707597, 0.289582133657649, -0.372094322914973, -0.396585488713015, -0.0899310999854533, -0.294323200071065, -0.196368066383948, 0.365756138437933, 1.39092070870144, -0.0637909019249169, 0.0756799428703881, 0.312066658713002, 0.0203421735598049, 0.0157803308645931, -0.0532324129855432]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157805, '[1.98715784052101, 0.135969609181324, -2.75632867292445, 0.972901390868871, 1.40648405286108, -0.453710983919198, 0.979853505673817, -0.331547606140305, -0.447530670756135, 0.537492962382802, 0.176339587035396, 0.323719651741669, -0.696354651086258, 1.17025753255851, -0.845682284316742, -0.479041764873774, -0.638627595659541, 0.254659839309911, 0.167354635807938, -0.158992273661776, 0.343683627668722, 0.970225724655249, -0.321650658135891, 0.0707611653510068, 0.901520460578426, -0.208591996229026, -0.0749462597584223, -0.0794109844745718]', 64.0); -insert into credit_card_transaction (time, features, amount) values (157807, '[0.14328828221439, 1.03347205192401, -0.413954804730453, -0.546000253454251, 0.927088521052604, -0.824445563093275, 0.980871727808579, -0.113080498625127, -0.0551913781455736, -0.836754858765189, -0.702518607586338, -0.0945402718921675, 0.0702091679663794, -1.03012421184268, -0.243739030537978, 0.33615651199416, 0.353881746644832, -0.214583603729398, -0.220268149322069, 0.0273538045715858, -0.341512651035965, -0.834778728151865, 0.0956055015074986, 0.560463369200917, -0.414990455926793, 0.113468812126446, 0.222112471808535, 0.0844250605859257]', 4.46); -insert into credit_card_transaction (time, features, amount) values (157808, '[1.89020976926467, -0.718621455617211, -0.494607816018931, 0.41125257367279, -0.664836358728663, -0.0341650686895274, -0.723185802641591, 0.113822222940725, 1.4102089553693, -0.0029513111663952, -1.23903740947893, -0.250509146300211, -0.839344788770907, -0.0599141230617934, 0.567476418025163, 0.377830180221047, -0.43476284183696, 0.119471329861976, -0.290453776516448, -0.117693369815635, 0.174754378194728, 0.521449562973754, 0.155090705247644, 0.634628275709373, -0.315882989950332, 0.542924745528679, -0.0382390801003175, -0.0340646234220689]', 64.99); -insert into credit_card_transaction (time, features, amount) values (157808, '[2.08484113647936, 0.0153232723818007, -1.32095765528647, 0.30363706764646, 0.320449667392797, -0.679532519123371, 0.239355660538362, -0.309144985942832, 0.392165630475432, 0.0154146291929246, -0.744364814841996, 1.02210715677496, 1.26734856338744, -0.0236232077167782, -0.306773778112924, -0.258168858213166, -0.325246078299231, -0.97113190068104, 0.255659549359951, -0.120214069555673, -0.25017179844612, -0.520295794938215, 0.291670547472232, 0.70955009787486, -0.116828793769917, 0.243480492738206, -0.0699730067167858, -0.0550860593735453]', 1.18); -insert into credit_card_transaction (time, features, amount) values (157808, '[2.20272194782546, -0.783839579807829, -1.4386409678936, -1.05101659983573, -0.469859293163585, -0.94967760996934, -0.452134650379234, -0.233771115500973, -0.6779648342407, 1.06726679220494, 0.685310397860821, -0.360276894457644, -0.437209850146088, 0.328133579657708, -0.284828213386965, 1.19845319670586, -0.183045318178142, -0.629692830783504, 0.836709217242646, -0.0499072046662009, 0.457185805373731, 1.27739833230359, -0.0588538258339816, -0.290948207325745, 0.195626880085859, 0.0708728312446743, -0.047410123274501, -0.0801127492014495]', 15.0); -insert into credit_card_transaction (time, features, amount) values (157808, '[2.10265459972427, -0.974301947985372, -1.17943178479541, -0.807064648785807, -0.840413029339322, -1.04973445657136, -0.489679937276198, -0.131114196078993, -0.316009410432336, 0.964188458030938, 0.685427354188882, -0.660510342424728, -1.9476774145923, 0.444591211282609, -1.0022474381471, 0.854999705174846, 0.343969200464974, -1.22155520937397, 1.15501656588183, -0.115045606390623, 0.0209352790007677, -0.0610606754782581, 0.226101669435722, 0.0312980285661253, -0.191185143054015, -0.349560367261045, -0.0528551377558542, -0.0689431140232731]', 40.0); -insert into credit_card_transaction (time, features, amount) values (157809, '[1.72749825858346, -0.460940688670449, -1.10648329544574, 0.55067129546286, -0.163783824672603, -0.336237705326993, -0.180240691292153, -0.081110999858166, 0.791214209032195, -0.577537884750753, -0.337726488684758, 0.650499645419312, 1.09754995477988, -1.41880756136142, 0.63528400304427, 0.762605823463408, 0.339199479665297, -0.0634259065005024, -0.312694006485262, 0.217658078488462, -0.234254970478256, -0.864549526831725, 0.30834230683611, 0.515998894161786, -0.620018086431606, 0.0773377808843559, -0.0386484696811715, 0.0163597096084855]', 150.0); -insert into credit_card_transaction (time, features, amount) values (157809, '[1.94799262008175, -0.045237038198725, -0.455975703893429, 1.43124399296622, 0.0385352593135862, 0.237105147166421, -0.210081916637175, 0.0112467661869301, 0.95394411441597, -0.066708049639737, -1.14203108587611, 1.44012438494246, 1.27755510901435, -0.572895640717578, -1.27495348576189, -0.488472894711816, -0.145500865222528, -1.07402841693146, 0.190989702384496, -0.175796872667835, -0.516890670781023, -1.14598589288621, 0.448670451783649, 0.55639940519416, -0.24856331810995, -1.13307491699875, 0.0625063089648343, -0.0220802721424277]', 6.49); -insert into credit_card_transaction (time, features, amount) values (157810, '[1.857446099099, -0.546959335002011, -0.45363278102496, 0.277492259171764, -0.495370106695829, 0.0562012445094075, -0.618161061893275, 0.20781873519935, 1.11199973853353, -0.0076445690233954, 0.818138680551881, 0.810064741507163, -0.716242473757146, 0.311031406135812, 0.127532157161612, 0.39006896945034, -0.707323114611947, 0.338559572852083, 0.13531737049558, -0.153857021883862, -0.109265804241523, -0.364034803493023, 0.377332824637121, 0.640375817891629, -0.49928884766645, -0.674471318625301, 0.0166398762373841, -0.0282127279240626]', 49.99); -insert into credit_card_transaction (time, features, amount) values (157810, '[-0.247917116688247, -0.655768904879766, 0.11677152910076, -2.64983844936901, -0.488275194960327, 1.11764833890607, -0.947184257728264, 0.865315283554798, -1.88325495693079, 0.478701126344802, -0.951172724747645, -1.29665431350972, -0.613563920957981, -0.0233874820861105, 0.380776913911904, -1.20181009178415, 1.4235580770564, -1.11568158427419, -1.46981278259855, -0.549178272623337, 0.0451194729197998, 0.412136430443857, 0.242727717729859, -0.404977631617722, -0.641704622729318, -0.16781994916912, 0.0075579600766935, -0.0163945189241929]', 46.0); -insert into credit_card_transaction (time, features, amount) values (157810, '[1.88549683468638, -1.20153555374825, 0.696203433229769, -0.314601472163345, -1.76011788319106, 0.156165304977569, -1.46510675707153, 0.193588945694349, 2.98475414773138, -0.925686714455559, -1.38330250650493, 1.74580023538335, 1.29135053134651, -1.5713346337322, -1.28254485308116, -0.608165647578597, 0.179888563198066, -0.208673785749401, 0.732285609926405, -0.0654036540181713, 0.107793832550697, 0.952347034241795, 0.117622289199077, 0.194246945884365, -0.303082320873311, 0.623667829519586, 0.0573531882575415, -0.0309188039903835]', 33.04); -insert into credit_card_transaction (time, features, amount) values (157811, '[2.03960974435102, 0.0757104311597996, -1.9008910923745, 1.11392897225594, 0.731730634367903, -0.435411066015483, 0.438702510998587, -0.154061725916454, 0.18207149997809, 0.465546657668439, -0.143222193545841, 0.105168923946084, -1.47117971098552, 0.935108495939136, -1.02838087113208, -0.270569056054109, -0.572602029878565, 0.227337964069095, 0.351324886948925, -0.350427644162902, 0.038047120955391, 0.250009126680236, -0.0885182568475055, -0.830053254689188, 0.484104664051276, -0.457074483557609, -0.0273133228961275, -0.0826069572342486]', 6.99); -insert into credit_card_transaction (time, features, amount) values (157811, '[1.9719159070628, -0.388731121104135, -0.624006943055621, 0.17015573536754, -0.277733696648881, -0.191131386335047, -0.40097827954714, -0.0543587408742976, 0.906612703241837, -0.0458665498407903, -0.921401238098533, 0.700679833045854, 1.01543716433756, -0.2440392102851, 0.494478197168139, 0.493074498195497, -0.678565391240785, -0.463829779018159, 0.0758096096619381, -0.0299614617424366, -0.258970150409411, -0.716360744113209, 0.400668459063837, 0.484286742120343, -0.572348252538824, 0.209080917242179, -0.045735406548267, -0.031928751743242]', 41.97); -insert into credit_card_transaction (time, features, amount) values (157812, '[1.95178559994952, -0.409727009211516, -0.444015475328114, 0.125487611536859, -0.486976047716096, -0.0577029616634854, -0.699150214488992, 0.232274347938193, 1.23743810020455, -0.0365047003412201, 0.82261019499935, 0.518472881862301, -1.22851738167275, 0.510042677246535, 0.590608682650595, 0.437274570592855, -0.794885215131684, 0.598339258265772, 0.0809074332997959, -0.289030394758501, -0.0786696716460054, -0.218988266371108, 0.400863418781075, 0.610056507052829, -0.439500751304051, -0.970243130806716, 0.0454609463993414, -0.0327784475264763]', 2.35); -insert into credit_card_transaction (time, features, amount) values (157812, '[-0.422421521095763, 0.658543922031277, -0.542993291613436, -1.91077933609488, 2.55752848754234, 3.67851431842003, -0.183898937905112, 1.12543274032514, 0.467184839533209, -1.20056879741915, 0.196317532303265, -0.0996175290741946, -0.288940846422521, -1.28628731988351, 0.855903906145092, 0.545086615514229, 0.269021030996727, 0.261788803371768, -0.482030433066122, 0.0960908874996435, -0.26443143843773, -0.752090922759935, -0.0086320332130002, 0.561731359228306, -0.145211291283595, -0.245972410243061, 0.168815933695936, 0.100460460840373]', 5.78); -insert into credit_card_transaction (time, features, amount) values (157812, '[0.0024960324417067, 0.788164180599921, -1.25484607760832, -0.82336568428351, 1.70747188308121, 0.619559406227495, 0.671560922026512, 0.217821956147169, 0.562239179129043, -1.22713229708576, -0.43150171228519, -0.0249860060926184, -0.495942732420654, -1.74682180509996, -0.584917494202639, -0.595252253685278, 1.63427367867747, -1.08957455661534, -2.07621588234904, -0.406714901289419, 0.322887103476518, 1.1882984618713, 0.234853074605478, -0.432318258813192, -1.97366146694542, 0.23056355011325, 0.0945152146477225, 0.37637794258061]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157812, '[2.01652460331248, 0.197597603262843, -1.70558625054696, 0.548291330260255, 0.190817636093764, -1.50755986197748, 0.349012810877867, -0.44121785950865, 0.484656779092686, -0.501663018213626, -0.224559439906617, 0.430782072646178, 0.681551107047013, -0.859250949937578, 0.824812492899406, 0.170613393918332, 0.361442475553509, 0.417222682587251, -0.447246309176938, -0.120208967695477, 0.216763843195825, 0.787944084515085, -0.0460610578341789, 0.0023672939038673, 0.2674714614548, -0.108543027645682, -0.001856078329216, -0.0258953665999172]', 24.49); -insert into credit_card_transaction (time, features, amount) values (157813, '[0.0245406853862598, 0.834158696854512, 0.279423515963669, -0.581056858872866, 0.413832824945075, -1.11715639703404, 1.02181159037646, -0.207648220991299, -0.0459097877986485, -0.414935763033553, -0.939626144379386, 0.137872662303856, 0.025706194958167, 0.110417921229033, -0.402328086924192, -0.0881568947645665, -0.415336033575582, -0.741678608888256, -0.0791318668810542, -0.0204920378985217, -0.25672151736005, -0.574843814940882, 0.0843517814733371, 0.0136256383933616, -0.483594183991414, 0.139086611652184, 0.244614495231356, 0.098022680591708]', 9.0); -insert into credit_card_transaction (time, features, amount) values (157813, '[-1.89941235074885, -0.835026396217829, 1.66793132486525, -0.646436489043085, 1.52527136759406, 1.13379438858827, -0.310950049331796, 0.638651130892026, -0.195195301251167, -0.602018053632396, 0.918502152812633, 0.378459805344627, -0.255858020847809, 0.165080231517051, 1.13534214789979, -0.0900824216782614, -0.10831140545711, -0.652537748075668, -0.130096452458055, -0.135957644236223, -0.104949842418508, -0.138522232200461, 0.613932943698787, -1.65136356235412, 0.106802237640361, 0.628331759968377, -0.0047200532136992, 0.0265065304979407]', 25.3); -insert into credit_card_transaction (time, features, amount) values (157814, '[-0.0408645436674328, 0.643505132346518, 0.682483895219545, -0.537851306680335, 0.785663820022569, -0.219362528377173, 0.545235620103251, -0.155021156498491, 0.606893027977926, -1.14690155385672, -0.726292299540116, 0.0127270458053618, 0.605513711344683, -1.77213207624616, 0.34676268617161, 0.370041022616633, 0.116644742572105, 0.895540889827852, -0.657126267725782, 0.0091098227613336, 0.29973447644084, 1.22805640499734, -0.19605763451332, 0.549346072211329, -0.710797168706551, -0.33221154212398, 0.113629117667617, 0.0459507976560507]', 2.49); -insert into credit_card_transaction (time, features, amount) values (157814, '[1.91413522555332, -0.66584263691139, -0.571756504768202, -0.913025199012016, -0.570311477436205, -0.317848716721277, -0.549136756749172, 0.0048753584101016, 1.03215036139995, -0.294236720406826, 1.33056615424238, 1.7792247340108, 1.25076632785714, -0.0399209339802863, 0.379142524285099, 0.453145372958297, -0.82357018985906, 0.0811629568394416, 0.526705137750816, 0.0490124103568653, -0.0831337901014837, -0.258884089061158, 0.380226371330108, 0.80867285876941, -0.639265957036621, 0.268833577781513, -0.049688075238884, -0.0372744770147582]', 57.0); -insert into credit_card_transaction (time, features, amount) values (157814, '[2.06536702630595, -0.185842664413203, -1.10932923221241, 0.373668790959369, -0.279027561019407, -1.22946369548719, 0.0857156000797023, -0.261914967063858, 0.811973016089996, 0.073986754873404, -1.01550221237828, -0.201476239390462, -1.23751330241331, 0.464629116766291, -0.052178453682874, -0.163304074751581, -0.112220188082995, -0.777765299745355, 0.248967369192527, -0.30684345847883, -0.294656869850248, -0.736116650117601, 0.331539811061915, 0.0276121178569083, -0.306344804488189, 0.357923693419442, -0.086919074750387, -0.066287276404903]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157814, '[1.9021008785613, -0.482844154348986, -0.601523633155915, 0.179886971764206, -0.25909496971808, 0.219205258493644, -0.565538099369571, 0.16577228248986, 1.02711701744355, -0.0191377865785395, 0.535331378508032, 1.0588679928049, 0.114062426483948, 0.129832519933771, 0.0262672930768413, 0.530508960416592, -0.953857493848836, 0.465758951057107, 0.355454632729674, -0.0931921046465438, -0.135135632861565, -0.398254373317797, 0.314696620216382, 0.306981137172287, -0.403444488315781, -0.656710585289073, 0.0185440301190065, -0.0307360977269626]', 46.48); -insert into credit_card_transaction (time, features, amount) values (157814, '[-0.309006417742835, 1.69743830986966, -0.334570089891847, 2.52065973486873, 1.83324100755956, 1.24449837402443, 0.023365102972311, -2.32096984629601, -1.85417027631769, 1.13929124043572, -0.330898624029878, 0.393039701634436, 0.0541494658972232, 0.609635506751284, -2.30118885101429, 0.800796913914809, -0.957152785599905, -0.132212089011764, -1.17598131222284, -0.681050820855386, 2.25325709977215, -0.990421283568725, -0.586470236991348, -0.130776394990222, 1.19526883195869, 0.0985717764493531, 0.206530037645392, 0.23280725745383]', 21.18); -insert into credit_card_transaction (time, features, amount) values (157815, '[-0.256069392576177, 0.641016316788403, 1.23599786105643, 1.10967000219345, 0.739315250937195, 0.408433003634605, 0.380705187350078, 0.135026748531129, 0.0498645175526142, -0.487835994233637, -1.34097169353132, 0.809816864589273, 0.880417348629801, -0.489823046627348, -1.02980463783317, -0.943606131881048, 0.206346698570494, -0.716394253633113, 1.20623923845022, 0.0723482312025159, -0.390153119584736, -0.881605479674927, 0.191987178757877, 0.560352244906919, -0.750145770646455, -1.03510609069657, 0.263701914394897, 0.225430223978651]', 5.55); -insert into credit_card_transaction (time, features, amount) values (157816, '[-1.19466168797146, 0.904479617259957, -0.727543282784896, 0.948610388342598, 0.754179739501868, -0.501770345120198, 0.956482175709518, 0.33811944114813, -0.710580137749843, 0.259129942299583, 0.0445229092162285, 0.156054594517973, -1.13606430995869, 1.11066638372623, -0.871198669710597, -0.736082606751366, 0.0279779127761554, 0.393553299816004, 1.14282044030211, 0.0961437774020731, 0.149109517059488, 0.584798720001557, -0.116917287999219, -0.403244916259447, 0.122852144837373, -0.359362507005129, 0.446956737832394, 0.195110981693878]', 76.4); -insert into credit_card_transaction (time, features, amount) values (157817, '[-2.33567210288528, 0.733138221649288, 2.0120099315408, 0.570452636629583, -0.560033894628143, 0.864410513456987, 0.0170526509325223, 0.284058903226262, 1.36797757028668, 1.63002234763906, 0.271161287916639, -0.24497861983797, -0.802494768393077, -0.699874500415324, 0.857624610180712, 0.530786442562383, -1.00186667451541, 1.55474026574662, 0.610348673619972, 0.631512187804047, -0.0912926770852709, 0.713324206954873, -0.451620578010056, -0.523147501320451, 0.68667927757969, -0.252686619350527, 0.663833119056286, 0.675868508138676]', 100.0); -insert into credit_card_transaction (time, features, amount) values (157817, '[2.01225660541128, -0.12090862323187, -1.01133122217169, 0.325476421186976, -0.158659570466063, -0.949621553308758, 0.0633844777917638, -0.176685409638332, 0.321384826339672, 0.250849992567385, 0.989175211706786, 0.996650219727563, -0.340384382288002, 0.538035432510428, -0.633944869222583, 0.0782937932135224, -0.487582582090626, -0.367404249890262, 0.402502545720778, -0.235416238019861, -0.23481479952135, -0.59440583314119, 0.34277598792859, 0.0691624275537647, -0.351271213437363, 0.173690252517699, -0.0764478284820569, -0.0697888491767698]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157817, '[-0.0030630410061332, -0.684657807221811, 0.297792231561736, -3.3466535165441, 0.153821265574126, 0.301944521007295, -0.148805741060795, 0.176905609705918, -1.83221510082318, 0.450191859109921, -0.72430532294448, -0.675000939775357, 0.373065372112177, -0.485818938217281, -0.703747314953181, -1.14945106379088, 0.793464752663303, -1.58607543310855, -2.64946542349511, -0.64826280462242, 0.0875770886152101, 0.798256808757288, 0.18761843034172, -1.06091216151852, -1.27522786620147, -0.456043138582043, 0.295467161130535, 0.240630561325634]', 15.0); -insert into credit_card_transaction (time, features, amount) values (157818, '[-2.36265172021935, 2.24444032102664, -2.41785970342538, 0.791624671803851, -0.076004460222897, 0.16295223379335, -0.688874149737515, 2.01735520530894, -1.33602291698205, -0.689971180803214, -1.1022944104057, 0.448983502356223, -0.992706533888524, 2.30972276728927, -0.892585639219672, -0.0332048747267003, 0.463520645926414, 0.751234593579852, 1.41440509219953, -0.718632830516321, 0.372483320536492, 0.278604871368275, -0.218364088002813, -0.219181241038021, 0.0019911974490226, -0.478007450983075, -0.953881444756312, -0.210779472515315]', 16.89); -insert into credit_card_transaction (time, features, amount) values (157819, '[-0.964045125612063, 0.401958802950009, 2.1977831516738, -0.729470190516652, 0.195106370886337, -0.397534278096216, 0.239500366757542, 0.238780214698133, -0.0068377775341286, -0.9648974451456, 0.701341534165569, 0.434148218466311, -0.798178403269352, 0.201861370393168, -0.257776554436292, 0.348178115392445, -0.728458630145008, 0.51417832786665, 0.172123004385327, -0.0406260900446285, -0.105658283079042, -0.438823990466515, -0.212498998001795, 0.0179382099396533, 0.320945596480672, -0.523091236594453, 0.0420783011102279, 0.0648088152694283]', 4.6); -insert into credit_card_transaction (time, features, amount) values (157820, '[2.00704675985152, -0.279405405346904, -1.28956087290228, 0.100786611413697, 0.156186742923983, -0.440342552080132, 0.0814742665626667, -0.226649935964445, 0.949801853207362, -0.260853903166807, -1.07452115842414, 0.962385050693463, 0.965162274969219, -0.124460783657848, -0.321463255860613, -0.438023978708979, -0.291000561790328, -0.633590345164846, 0.464355644488598, -0.068970173114129, -0.15951091658087, -0.266323232999436, 0.170644556868241, 0.515265340319667, 0.0157499850284986, -0.112843979380258, -0.0299753353603384, -0.0436620922839824]', 40.0); -insert into credit_card_transaction (time, features, amount) values (157820, '[-1.10782746910529, 0.818007001151512, 1.23441133451061, -1.33078828029731, 1.05881250675329, -0.716022442446408, 1.18402602137007, -0.194652589029391, -0.324783546652541, -1.23023561554114, -0.802934841360688, 0.732481356758106, 0.850399254752658, -0.396186122192683, -1.67508080947407, -0.326969899836686, -0.394945247275416, -0.86993893333513, -1.22496458554483, -0.176013488544165, 0.170286296549614, 0.593383379883429, -0.620246922024202, 1.20563069766128, 1.14130427420137, 0.598097375634103, -0.192605467790794, 0.034651388695736]', 3.07); -insert into credit_card_transaction (time, features, amount) values (157820, '[0.0271775324813036, 0.821080821077469, 0.182819999066708, -0.778501091963439, 0.626265555479052, -0.611722792794885, 0.914758999117007, -0.0475013734472113, -0.301344931788006, -0.24575141705346, 0.507308892531776, 0.786300341155683, 0.10528223119812, 0.264853615542356, -1.09416566728214, 0.190699597846666, -0.782707158846096, -0.164111144534707, 0.325160299296116, -0.010412459617805, -0.228765806691467, -0.507309429988439, 0.0155310222655124, -0.339498398397163, -0.472696739737868, 0.140226979307561, 0.243889958184265, 0.0841729877243635]', 3.27); -insert into credit_card_transaction (time, features, amount) values (157821, '[1.88665705922934, -0.360965320950786, -0.297727339493862, 0.46446755871876, -0.604808765772919, -0.508171188799265, -0.383475047512767, -0.0788128803541868, 1.10480129068373, -0.216085071905604, -0.352940380035797, 1.07437593976372, 0.933254840791105, -0.193385705382018, 0.578190435918073, 0.0778374544524609, -0.482862659152504, -0.376732625623661, -0.220424140042421, -0.0658078315218247, -0.126037353687638, -0.305315218837071, 0.405318059829234, 1.12656061129541, -0.444332828399621, -0.688489158115425, 0.0283170630663477, -0.0105742493363594]', 49.99); -insert into credit_card_transaction (time, features, amount) values (157821, '[2.02297796313133, -0.451698797647335, -0.523431233028171, 0.373860239825938, -0.523903322869473, -0.235145877911942, -0.637525594159163, 0.0002517286694999, 1.57312390824529, -0.153479726626306, -1.66880347964446, 0.060374746238083, -0.136066884867294, -0.165343839309445, 0.565061269109967, 0.291475463048405, -0.727039997022602, 0.466614024085402, 0.0288750143179468, -0.22320424240174, 0.144349596930845, 0.661177114183402, 0.0382360573204955, -0.63955439142185, -0.017475740445534, -0.171117731230469, 0.0384218127231883, -0.0440449312862853]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157822, '[1.47213000036966, -1.10965201447505, -0.530079772016693, 1.30211685261894, -0.469214861607331, 0.747243422225682, -0.501553862352727, 0.156071341288157, 1.18891394692465, 0.0034108379361629, -1.60958876428604, 0.212803127547787, 0.557309080691805, -0.283026605536064, 0.821924342590273, 0.803487214498176, -1.03105218868005, 0.531108329437095, -0.554660950355263, 0.350410663691309, 0.191638037473539, 0.11349418416183, -0.0181016987719031, -0.0507676437024086, -0.319582805849277, -0.744618829527683, 0.02989188895939, 0.025596850448959]', 269.0); -insert into credit_card_transaction (time, features, amount) values (157822, '[1.95260941642706, -0.463763496156111, -0.787384780096095, 1.39114631147901, 0.193293893885378, 1.20077942517405, -0.843212462361275, 0.36325570364224, -0.170777712518457, 1.30984483645386, -0.761064455868926, -0.708803351997812, -0.644543464519214, 0.0825555562704867, -0.311669570304863, 2.23122765817023, -1.54486702198862, 0.732286707866648, -0.348632120451662, -0.0385540299102912, 0.0759815094916214, 0.0019616327078082, 0.128106059372384, -0.635350697384354, -0.641170558351484, 2.27263580909368, -0.189125635497311, -0.0765970137726111]', 53.96); -insert into credit_card_transaction (time, features, amount) values (157823, '[1.94486901534407, 0.393022084545182, -0.981243860593355, 3.67363032923613, 0.837687690005821, 0.770438248184241, 0.0458714848508149, 0.0658161152500346, -0.566099758843042, 1.36884214413366, -2.1326432260674, -0.489444585331139, -0.2064169321907, -0.011502791251268, -1.3616144522607, 0.632279967763316, -0.717537153627847, -0.320688816331692, -1.14004217303203, -0.260791705400167, 0.0320644712281213, 0.218062292145084, 0.0325631841399894, 0.0139196239470554, 0.219852720839999, 0.109739818288953, -0.0322666704626435, -0.050269144580269]', 15.12); -insert into credit_card_transaction (time, features, amount) values (157823, '[-3.06761475038232, -2.45757422381283, -2.37781833374031, -2.75327430744293, 0.405270219564038, -0.587300907165915, 0.985344454363531, 0.444995319920586, -1.44856299433554, -0.954020409832174, -0.617750097436486, 0.860476183269492, 1.33205170099883, 0.809959856510232, -1.40672634850991, -0.640053638097413, -0.913410026106095, 1.72412664100913, -0.947931624535411, -0.572463091197429, -0.0876827194099806, -0.156815339512873, 0.589958048172099, -0.268956803656156, -0.213857626134977, 0.430112980760767, 0.132307165833751, -0.722747290729469]', 261.06); -insert into credit_card_transaction (time, features, amount) values (157823, '[-0.191673063048596, 0.821384159145986, 0.787674730152658, -0.0922151874145524, 0.681725373574366, -0.722273978632257, 1.26231684222704, -0.739932271562768, 0.152280334918435, 0.388642660435366, -0.774156086293229, -0.485026817886725, -0.549312350960892, -0.14034120075895, 0.434589447227881, -0.787100501008745, -0.127915916983925, -0.642284630683373, 1.13529016002422, 0.0358413872948787, -0.236158337446056, -0.374780192492369, -0.0119837966207439, -0.0847080906541573, -0.906443609943872, 0.208797558300003, -0.59845703660515, -0.252546698431979]', 1.79); -insert into credit_card_transaction (time, features, amount) values (157824, '[2.14725144561267, -0.911386646510524, -1.70743781131686, -1.08121823771349, -0.123056751918487, -0.526472948782039, -0.294571891453705, -0.242186844703195, -0.406899172991187, 0.779200245089816, -1.33341809792709, -0.92799832254967, -0.0587987196156513, 0.0236448955414936, 0.214033993508898, 1.15067640098965, -0.0281973819969767, -1.50455814329727, 1.02405841178102, 0.122064764920196, -0.0779838009596802, -0.452922814833994, 0.186934782075766, 0.0066968744621801, -0.12824301356534, -0.422302825655525, -0.0545148178467393, -0.0461967776619663]', 78.76); -insert into credit_card_transaction (time, features, amount) values (157824, '[-1.48323702696132, 2.10624752649122, -2.16123474882007, -1.22838859489731, 0.233052200224787, -1.36326729699469, 0.43310605472374, 1.04871855353305, -0.609369507776305, -0.337206237993234, -0.0827354737797539, 0.432264304119711, -1.11153317007751, 1.90577260521751, -0.785213429118827, -0.0455624209302278, -0.193326016872693, 0.354370197799988, 0.164834257011197, -0.203439962648355, 0.332130148034254, 0.83334654767392, -0.10917360155125, -0.449728325179691, -0.160171131847402, 0.118467146575708, 0.222562436856777, 0.185344428381212]', 0.92); -insert into credit_card_transaction (time, features, amount) values (157824, '[1.94385824857617, -0.324216926499365, -0.378751671816814, 0.243042148973371, -0.386030995318921, -0.0200066019164586, -0.576057723689871, 0.124435047076755, 0.938180727889361, -0.0153386791813126, 0.977178748442479, 1.42171305419448, 0.464162303746381, 0.0609745917180072, -0.0555692970560797, 0.385183200248637, -0.829375704497138, 0.27097393308082, 0.208626965098023, -0.153419697371748, -0.125178645056365, -0.267839631504996, 0.392750230913669, 0.730302646638874, -0.430623237868935, -0.679854795300319, 0.0287855482064301, -0.0319837818302215]', 9.98); -insert into credit_card_transaction (time, features, amount) values (157824, '[2.06249030426725, -0.0648454310765915, -1.0650812664132, 0.420367017994954, -0.168214387594192, -1.22471681726083, 0.168718161269045, -0.322472670570973, 0.575602771936041, 0.080237911519834, -0.772147943304741, 0.319930193231773, -0.166258743588161, 0.321343992406884, 0.0643805860927848, -0.0971402553273107, -0.271777142273838, -0.844595885668367, 0.144470872369702, -0.240377265067763, -0.291616211892481, -0.715908440885158, 0.344507283686344, 0.0400238915933294, -0.307124950232525, 0.196202778537347, -0.0721207325752885, -0.0604255538216545]', 1.29); -insert into credit_card_transaction (time, features, amount) values (157826, '[1.52888870056684, -1.96676854409923, -0.664912635773967, -0.557305595239503, -1.56125111879195, -0.642749040643673, -0.629031621413586, -0.233352569887686, -0.0045228312455695, 0.593968700843232, -0.578246524436214, -0.166290706760199, 0.991319476045783, -0.523114973812103, 0.592208550164067, 1.3299480960183, 0.009074238013735, -1.05785885405177, 0.0975332152883663, 0.668302342788377, 0.606375699207481, 1.10871855185019, -0.149626859529165, 0.0589351673001042, -0.31441138802195, -0.0995421601121922, -0.0373538621589966, 0.0124885141114627]', 334.28); -insert into credit_card_transaction (time, features, amount) values (157826, '[-0.551296409572373, 1.50583905262851, 0.514153108628084, 2.42072420626781, 1.66512928232429, 0.463940384200157, 2.27057447197262, -1.05359343127532, -0.562582716083645, 2.55930820895058, -1.33880035562573, -1.36858822142472, -0.800853632259143, -0.742586864441154, -1.07784886470889, 0.38648719370457, -1.32925767874308, -0.611923707768003, -1.37718713089342, 0.0746974523978003, -0.379669295897999, -0.341695726300356, -0.248587197565725, 0.404802531019539, -0.293272599619504, -0.393227629181931, -0.740158693792147, -0.701280472714805]', 86.15); -insert into credit_card_transaction (time, features, amount) values (157828, '[0.0094132298917694, -1.5071776819449, -1.88671933901564, -3.64719484766952, 2.53673608073762, -0.338748956282057, 0.130848644830295, -0.0967668282929549, 0.0185210137290804, -0.284888707522018, 0.787329209712129, 0.650563221330971, -0.279868673012532, 0.869180307172842, 0.894726642338023, -3.74327236595601, 0.430318531798971, 0.777385064737291, 0.0434022369398565, -0.311852013670493, 0.142299576141314, 1.03209694412214, 0.320208704504647, -0.953743428336158, -1.60903702675943, -0.893601388814555, 0.247073030425973, 0.129056000939828]', 11.37); -insert into credit_card_transaction (time, features, amount) values (157828, '[-0.91575425733639, 1.5912851193345, -2.02032190594613, -0.240148772738088, 3.00067127247173, 3.52860342148369, 0.410435665027943, 1.24915376531265, -0.593411389384587, 0.420328443148663, -0.478967948023834, 0.0485772389851593, -0.405192086342592, 0.86586695923979, 0.0514365493960024, -1.14373561685891, 0.204696306460171, -0.390598506121877, 0.637884797230501, 0.262606328344763, 0.0809618975278517, 0.455974620149795, -0.206969355646798, 0.711395683193602, 0.198817419056023, -0.345422922504724, 0.551754430877551, 0.288847270792079]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157829, '[1.93463403830276, -0.222941544714367, -0.332789948576418, 1.11929077754318, -0.370950738860409, 0.138379275970264, -0.694966719371524, 0.222893127365693, 0.758564033189333, 0.414010768123185, 0.640976615783874, 0.461756578586964, -0.787057128821181, 0.350599097792385, 0.207654741374768, 0.71164436622105, -1.00416608987488, 0.965576765616621, -0.46655632058962, -0.275937294065399, 0.259464734957981, 0.803858325074834, 0.181308740558508, 0.724160654791181, -0.130899158891553, -0.614081313846642, 0.0439878082065253, -0.0353870048218169]', 0.0); -insert into credit_card_transaction (time, features, amount) values (157829, '[2.34570314489825, -1.38909737166812, -1.09221934822197, -1.6871127151492, -1.00467205964082, -0.371296931278659, -1.14692852907896, -0.207306614426596, -1.08090141691831, 1.5493612652813, -1.87993568190705, -0.903604337805547, 1.00264490968216, -0.634810691326469, -0.0930212340506033, -0.218117501100234, 0.073067109113477, 0.240604090931093, 0.199292750430603, -0.370890063096231, -0.218572630123933, -0.0841357668647441, 0.116198620246752, -1.0126995996372, -0.103566963076992, -0.117453585049837, 0.0212846900092629, -0.0550467264777384]', 21.6); -insert into credit_card_transaction (time, features, amount) values (157830, '[2.08851206565192, -0.489526696539034, -1.10668908538124, 0.665678158825648, -0.16048498916161, -0.115652656338969, -0.308425897709755, -0.17693717496671, -0.451164184313014, 0.929227532604979, -1.36499582905341, 0.533496210440932, 1.06685420505759, -0.259032857193185, -0.83276036010968, -2.03429229024651, -0.0137131424432421, 0.920494999457383, -1.00033677801498, -0.583494962686243, -0.247506752386339, 0.0474518194247801, 0.0993180659549081, 0.597725798717517, 0.261089616371313, -0.487430972718392, 0.0494598147442813, -0.0359975418316735]', 19.98); -insert into credit_card_transaction (time, features, amount) values (157830, '[-0.447925927972273, -0.172584932009424, 0.0569341138869356, -1.40284384610808, -2.20502462878886, 0.0560163277368336, 0.756950475513314, 0.0430077622008576, -0.916479273185834, -0.102806922331421, -1.01255478601743, -0.417674051501705, 1.19933857798349, -0.418871024632366, 0.213944634942227, 1.3755474737578, 0.0503882581384439, -0.729183993452069, 0.568356471353435, 0.0261563791144963, 0.607656684982254, 1.75503241951108, 0.362728777856288, 0.0458702212168817, -1.20206160102013, -0.197355221958857, 0.185480909057384, 0.124347807162022]', 325.0); -insert into credit_card_transaction (time, features, amount) values (157830, '[-0.198524600413521, 1.07056611697248, 0.210865437832398, -0.63896971205222, 0.453348373731048, -1.14898655562123, 1.03046033510157, -0.240133778605682, 0.0334370374083989, -0.120377506966644, -0.765167289228136, 0.559653885117001, 0.774966736423035, -0.109575083169424, -0.47116797480918, -0.152494552607784, -0.457694608353885, -0.862655827940222, -0.120953560944248, 0.130283385701381, -0.283558228376962, -0.530419173642584, 0.0643493886011424, 0.057564507479873, -0.414701799134791, 0.140122709890796, 0.363297935304445, 0.157527602339208]', 2.69); -insert into credit_card_transaction (time, features, amount) values (157830, '[-1.41637994242257, 2.08581438831372, -1.20812762489462, -0.435652715006095, -0.836699173966815, -0.0757787047767257, -2.00204219158296, -1.34089451588921, -0.346342947706735, -1.98849207010635, -1.04601064829146, 0.745948023749714, 0.789587384068126, -0.30440165784537, 0.602529274210554, 1.76141266795973, 0.569673760996769, 0.785720589100461, -0.982234241197868, 0.198847099619588, -1.08790808796609, 0.405200890137176, 0.644970369212119, 0.534240058657476, -1.38144870584727, 0.0115216224049188, -0.547496784347021, -0.0041537578676155]', 9.8); -insert into credit_card_transaction (time, features, amount) values (157831, '[-0.426382615533359, 0.429368652813297, 1.40631158426411, -0.58929268894478, 0.206332502253387, 0.713655068586189, 0.215282272103876, 0.322875560685921, 0.235229778166525, -0.754793868097043, 0.0693717581290611, 0.299751782010992, -0.360197998290926, -0.0164509199494985, -0.185155491332744, 0.219218321267268, -0.780262196487368, 1.16024794941629, 0.677787668726897, 0.0385416709853648, 0.283305303501857, 0.860771986892383, -0.294678575203266, 0.29815791126435, 0.0522178086006876, -0.146656606508687, 0.14424944156103, 0.135031904463973]', 35.97); -insert into credit_card_transaction (time, features, amount) values (157831, '[1.91761659516388, -1.27989042468339, -0.550512879866041, -0.675503386937241, -1.23135480129488, -0.715860319329705, -0.755444386509895, -0.231467593215809, -0.0488695654291568, 0.64396613210052, -0.582051893581756, 0.141068825560873, 1.34962686603566, -0.675067367142543, 0.110420966351565, 1.05256119777113, 0.133430385368821, -1.3548709396005, 0.324134472209228, 0.28187162439205, 0.415992878265722, 1.07503062012215, 0.0210676667911795, 0.0617928605364573, -0.172640661241608, -0.101567033826545, -0.0021142918020167, -0.0246200169536936]', 134.99); -insert into credit_card_transaction (time, features, amount) values (157832, '[-1.80346507043129, 1.94336351248285, -0.477192108231044, -0.401702597457705, -0.364354050082577, -1.36866894683339, 0.387747076722669, 0.344476113557209, 0.445387497102268, 0.731469924962325, -0.685099722598294, 0.335507199868123, -0.251346974320909, 0.397305842955965, -0.0994221366011376, -0.432827203638135, 0.182755154865333, -0.868298803648426, 0.150896667377805, 0.136729912408897, -0.188720269612872, -0.356520984447129, 0.187783520495935, 0.390557329551228, -0.933427342866825, 0.0844267878051226, -0.0667968389304196, 0.0853278684349329]', 4.95); -insert into credit_card_transaction (time, features, amount) values (157834, '[-4.37223272149791, 4.21387369062807, -3.97500050717615, -0.727923467186792, -1.70898981519024, -1.21635706382299, -1.51576250232597, 2.96065803610176, 0.434915678768808, 0.338122672548367, -1.42546779386574, 1.30812689981799, 0.847538384339796, 0.488138763051702, -0.354454893435288, 0.953268790918532, 1.48251852711152, -0.223059074778375, -0.600471602033495, 0.406914971149439, -0.320077450954875, -1.07793786137694, 0.506073576883736, 0.476447505830663, 0.201744331521787, 0.171836693000445, 0.298014787747813, 0.202332772727528]', 17.99); -insert into credit_card_transaction (time, features, amount) values (157834, '[2.19012899669411, -1.46153591009937, -0.803229671372471, -1.66107890407783, -1.15247172132322, -0.132293613880988, -1.24160020822153, -0.0372063708667921, -1.49851074512902, 1.67789309453922, 0.881536323757477, 0.355461625117194, 1.20325870082014, -0.468643047196173, -0.826559645452109, -0.381824106478064, 0.216441188084143, 0.284603079373507, 0.0178000099483304, -0.299460416591788, -0.0792238528330689, 0.217324469894423, 0.25464672620821, 0.707688528935559, -0.264319048131056, -0.233752008525689, 0.0161476018440291, -0.0434131033766562]', 42.0); -insert into credit_card_transaction (time, features, amount) values (157834, '[-0.637324313396194, -1.57689847025112, 0.917671048143363, -2.83681618149499, -0.838599902326643, -0.115953339092963, 0.436287160180054, -0.198810273679015, -1.59661557388642, 0.621985198992814, -1.67892172728516, -2.21434231290518, -1.17819702725974, -0.561841765249186, -0.52350256779129, -0.149958156740237, 0.0363420997301917, 0.470333103166933, -0.806909986909746, 0.165940258356955, -0.002061610294654, -0.0126027785330679, 0.431931858852278, 0.478634109326586, -0.152987133751504, -0.338863984576134, -0.12514648623781, -0.0540566219742693]', 239.0); -insert into credit_card_transaction (time, features, amount) values (157835, '[-0.402507052578237, 0.985184942134102, 0.782167914865014, 0.65501469914171, 1.01980221604131, 0.162967988863067, 1.30684286163706, -0.544255201902881, 0.553265972609925, 1.35127056602887, 0.194178629796895, 0.0226360633595435, -0.71437628656684, -0.463729726724478, -0.96954692983593, -0.900845681999007, -0.609141226227762, 0.581341873668803, 1.19092769318587, 0.508880555870567, -0.0421708374308417, 0.923073375288087, -0.416535325621101, -0.485350248747449, -0.0445354734478045, -0.407512914278499, 0.193432392494004, -0.296088418703337]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157836, '[2.06600812011579, 0.212733685158645, -1.67667616274652, 0.40715771961777, 0.510978546137638, -0.790015457180319, 0.228000247297557, -0.259959557826988, 0.363375521745164, -0.411214817032647, -0.352558855664839, 0.622301334087091, 0.898382128729849, -1.00503720024482, 0.158401967024696, 0.211361309697192, 0.490323784768256, -0.50776489329618, -0.0334631399351485, -0.109995257111866, -0.34778820722648, -0.847448818941393, 0.339761738276403, 0.531585493776343, -0.247659288106161, 0.172541932655976, -0.0538974367239986, -0.0290450111215878]', 1.29); -insert into credit_card_transaction (time, features, amount) values (157836, '[0.0417576258490837, 0.849666970892494, 0.23128169516166, -0.615711165721009, 0.493059001875554, -1.04411168366748, 1.01420179368104, -0.203190219732137, -0.0486971447772289, -0.4142776289848, -1.04226921328416, 0.140920141067685, 0.133708925595141, 0.0849909491972045, -0.402495913302537, -0.0546273603100446, -0.467683543137562, -0.710936730621702, -0.0294000190500372, -0.0194206134345929, -0.266725840713801, -0.591554247389514, 0.0580324998549543, -0.114944660786308, -0.46480139489786, 0.147047769954302, 0.246367806791632, 0.0965567545530596]', 5.37); -insert into credit_card_transaction (time, features, amount) values (157836, '[1.97465908888964, -0.0223951560658185, -1.41708789062216, 0.648787448766615, -0.114031128747409, -1.20724263274786, 0.0206231328480823, -0.209847329147051, 1.02409979572353, -0.58655098654999, -0.569907075300941, -0.237431690507807, -0.96599306826236, -0.82753312955599, 0.614083941341488, 0.155052361083398, 0.676323649846123, 0.299558425306579, -0.283785985590054, -0.232739726316218, -0.0521000212794944, -0.0193475348600889, 0.138452581639282, -0.138786133224291, -0.0454942656006256, -0.335580434307477, 0.0104167148469378, -0.0205564520783589]', 24.99); -insert into credit_card_transaction (time, features, amount) values (157837, '[-0.387011219770642, 0.494090691748053, 0.961992096965214, -0.611490948924778, 0.919883229892197, -1.15211907325743, 1.10392321468602, -0.397080168441054, -0.132434878390282, -0.4965585330485, -1.0314215493946, -0.407010679765922, -0.694604638725308, 0.11989302211298, -0.222157549874694, -0.207746127831496, -0.422062492404337, -0.61908361178042, 0.155466705472628, -0.0168831621875002, -0.251108179557846, -0.620449103204238, -0.0753213384575987, -0.0388695516359171, -0.367655193695854, 0.158839095708461, -0.110907244005624, -0.0818975687330509]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157837, '[2.03782407479185, -0.16442298678413, -1.22529997810387, 0.205262308720011, 0.0863746951306857, -0.590046990996929, 0.0181986252820673, -0.102478635402143, 0.398393562646139, 0.251768551946654, 0.548966423025011, 0.696793939624909, -0.55404384367956, 0.573074716185609, -0.518102950641522, 0.17713032712586, -0.593218344541852, -0.2594430614813, 0.518112629247304, -0.244698119248414, -0.264695666669397, -0.68565680428439, 0.292209606262834, -0.482487368102455, -0.310662369724611, 0.210329901700057, -0.0758539926565251, -0.0759754232909689]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157837, '[-0.531707408435599, 1.45227755432358, 0.025451742188867, -0.575801075336073, 0.402596786634284, -1.24531875260899, 1.22318857142778, -0.436403220795202, 0.254630048132528, 0.993262139497165, 1.59124577093176, 1.27573391576437, 0.752235053637642, 0.044505244536199, -0.319422116170718, -0.605807466352912, -0.703385056832718, 0.277164199461892, 0.020604482519279, 0.492960320494032, 0.330366686815289, 1.59817069089154, -0.0949656118602944, 0.603040508441781, -0.736443525022912, -0.29290976784478, 0.664431490309938, 0.276975750995135]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157838, '[1.91012764654507, -0.214911460242795, -0.149054703791262, 1.23587509910457, -0.614024091646997, -0.222327147820015, -0.640327487495576, 0.141235652060546, 0.745379305996641, 0.408467254876142, 0.776924880566786, 0.613102707751832, -0.683076204345837, 0.34695027642404, 0.1920990820685, 0.604685794990127, -0.913239041756053, 0.807549535948923, -0.570318211677253, -0.303663272429458, 0.276614316427436, 0.9043343788319, 0.155751838809788, -0.0169447489238734, -0.167111441901268, -0.578380903105959, 0.0529191329244133, -0.0420215725506592]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157839, '[1.96256285463695, 0.19629847035573, -2.00081401799851, 0.617643909717091, 0.478082770385361, -1.44344180426208, 0.672101220623945, -0.509841259818088, 0.372268261545081, -0.625001033223497, -0.348249648813358, 0.845402080653515, 1.11002660882389, -1.0075363431364, 0.0183935235966256, -0.180997038667057, 0.610558728570152, -0.179821284582034, 0.0206455926374934, -0.0279161232273599, -0.130514499886407, -0.235961815726805, 0.0432290091998405, -0.179386744023229, 0.196669418587758, -0.379590227879475, -0.0151225713585166, -0.0214028136966656]', 59.74); -insert into credit_card_transaction (time, features, amount) values (157839, '[2.02722978880361, 0.462557604185985, -2.50196013305768, 0.596618746012089, 0.6581273407066, -1.32726737597522, 0.203059082140186, -0.190893505642236, 0.41208365441355, -1.0023855451196, 1.44997587865354, -0.145681667969982, -0.986028701983297, -2.17052348887086, 0.49590435112659, 1.10472977757573, 1.45631195743283, 1.98484866958775, -0.282110157578382, -0.192375331401661, 0.117388668982725, 0.462074767243637, -0.0882561341894579, -0.576061194329224, 0.238862484462931, -0.0971389099578121, 0.0097643554649189, -0.0075869145497367]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157840, '[-0.289766221469332, 0.628559424479173, 0.943144284726303, -0.389692867287835, 0.560809599404991, -0.0491961641241497, 0.588693955780259, 0.110346030595749, -0.763375402564385, -0.281196127532713, 1.06492894781139, 0.443670878478515, -0.144314638995957, 0.553301548272612, 0.51528607876118, 0.139913017084407, -0.436221209582252, -0.0249041546814199, 1.30047059498911, 0.146298291760619, -0.301832802100491, -1.07255262772272, 0.266429405671112, 0.610975875614744, -0.926387177309548, 0.125821169573456, 0.0838071829234286, 0.16018698855591]', 27.56); -insert into credit_card_transaction (time, features, amount) values (157840, '[1.77258351226467, -0.788988000485366, -0.592611225620543, 0.22580449713795, -0.650874285009313, -0.247781807412575, -0.444965604621342, 0.0654538568418677, 0.879930744083094, 0.137735801635657, 0.471242560725537, 0.621001173219971, -0.541254696136626, 0.274544439610745, -0.072302719445212, 0.765234185927878, -0.847630157838773, 0.219210734096822, 0.369042484467334, 0.0171948669582646, -0.176508775391131, -0.724164406200276, 0.291294998619352, -0.430730860425196, -0.68914217577619, 0.227501640378244, -0.0690895260050541, -0.0395666601470801]', 120.0); -insert into credit_card_transaction (time, features, amount) values (157841, '[-0.555276477106862, 0.855721993047392, 0.0918589883442275, -0.760091342228719, 0.0955813626546279, -0.884911601097234, 0.69803317791985, 0.253334566973163, 0.17967836388236, -1.20377641331705, -1.63385983881794, -0.213543161280976, -1.09950980251242, 0.514944666376774, -0.873934511057197, -0.642116336359251, 0.133597304402471, -0.179060455128908, 0.0757904719549056, -0.324517073813025, 0.286660610399304, 0.903979079926945, -0.284215609380972, -0.0327359491682181, 0.0214474605373953, 0.218645838542426, 0.0029078782304432, 0.0951700228296631]', 20.0); -insert into credit_card_transaction (time, features, amount) values (157842, '[1.87447457125147, -1.92605834951993, 0.462380772373881, -0.553780253603811, -1.76137985895345, 1.42200572201284, -2.15937290954825, 0.590852496654097, 1.41873386665477, 0.488476630788313, -0.346948345993439, 0.463015783122129, -0.100675271030776, -1.51393894342423, -2.35623452105639, 0.988065123384293, 0.382699744529149, -0.513633277351094, 1.24038606625674, 0.141293007651812, 0.361983634352254, 1.27709675697346, 0.0354027462051676, 0.368429912863443, -0.253272111779542, -0.0106380542718407, 0.0720308983438213, -0.0266888704510744]', 92.2); -insert into credit_card_transaction (time, features, amount) values (157842, '[1.89162577093522, -0.35717416722083, 0.667425678294614, 1.76515630006475, -0.755774232959439, 1.00248611929123, -1.34007998469617, 0.408196992336103, -0.023652807642118, 1.14023012053801, 0.7844327245034, 1.16309792796846, 1.50231874819735, -0.782873925069329, -0.798034020530616, 1.8282734867967, -1.10357658763516, 0.106351448949116, -1.00204437285227, -0.0440496325347035, 0.18852040310767, 0.646036076974909, 0.385829138989342, 0.831254282443608, -0.953098909022139, 2.17010738401089, -0.115299821991652, -0.0533127892216617]', 0.0); -insert into credit_card_transaction (time, features, amount) values (157842, '[1.97801371722969, -1.06003704155414, -0.0375962080544792, -0.356999933077957, -1.26337356667985, 0.05145658230032, -1.21134001319506, 0.114724054557106, 0.146326136958788, 0.766527474030122, 0.413861570573846, 1.12890909235027, 1.10433409285051, -0.335595946595136, -0.0383281006369141, -0.852525595496914, -0.800280789107831, 2.07625418689173, -0.657695272378165, -0.479890601607901, -0.255169539606108, -0.162339328066228, 0.268953004531386, -0.374446015247298, -0.481871448033971, -0.439245416646459, 0.0744215342111052, -0.0267779011751512]', 46.66); -insert into credit_card_transaction (time, features, amount) values (157843, '[-0.16476058666961, 0.571057429709443, 0.392732635190925, -0.722876478495109, -0.0043006944316656, 0.486237771544567, -0.312000103369092, 0.711764617945534, 0.377263813522055, -0.887539949180069, -0.0915024469963657, 0.913623951596695, 0.333117455302897, 0.0903995810545895, -0.650510595106977, 0.606132797928513, -0.93443806251958, 1.03779619183735, 0.0366614903365086, -0.229734109188045, 0.315207281265638, 0.903593838959301, -0.10630733505883, 0.214837046813191, -0.220446428834252, -0.304785647216578, -0.0510936813387178, -0.0546688222497397]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157843, '[-1.30590884627008, 1.16343275633271, -0.442157013142903, -0.271323551678816, 0.749967454794187, -0.303754881254632, 0.817414039737156, 0.353370181868569, -0.370981728836364, -1.15070060988245, -1.45977383726823, -1.34859152038967, -1.25696966300599, -0.296333337969729, 1.40422773993092, 0.272468046251167, 0.658451690604524, 1.25877604402342, 0.714697813669478, 0.112372918947992, 0.15349443436303, 0.296697885691122, -0.588842036983424, -0.0546777787648191, 1.089016112025, 0.182222970870572, 0.0399234061789595, 0.0503712947333781]', 81.43); -insert into credit_card_transaction (time, features, amount) values (157843, '[2.03298120480541, -0.519250867766739, -0.755020951694331, 0.229512970384677, -0.225139840441982, 0.328881590905993, -0.755790511466087, 0.16696279533742, 1.66457522598513, -0.150521675280538, -1.85991709700497, -0.344120069654245, -0.736174343122989, -0.0549022323684959, 0.736375549012799, 0.327935590851161, -0.705120023593535, 0.534321382323816, 0.0216223944853121, -0.235608640060191, 0.128614965884603, 0.55178110464381, 0.0726469668071797, -0.0922732879710547, -0.0182358331002292, -0.190102810175813, 0.0322620006240155, -0.0402332748670264]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157843, '[1.48741837869265, -1.32344086118531, -0.798170060422109, 0.302493493566117, -0.742597188599083, -0.0343754304195434, -0.289082446434825, -0.0712278515600484, 1.39908116739226, -0.362185965833303, -1.05135663865608, 0.690611131336777, 0.810579406231439, -0.300588494738193, 0.532178798076625, 0.189200896874319, -0.579502115119682, 0.20438418829632, -0.12852123507699, 0.4263491179056, 0.333483684599355, 0.585397235160658, -0.102529488772589, 0.649220117098237, -0.204640769318829, 0.0704243163493087, -0.0370913349684176, 0.0122615838603845]', 283.09); -insert into credit_card_transaction (time, features, amount) values (157844, '[1.98847926751272, -0.438674011257909, -0.0853955437465157, 0.339162822529171, -0.712007567103061, -0.0219103836659887, -0.890245150236702, 0.124223712050773, 1.55566333698797, -0.179120280159013, -1.00061918408885, 0.426288727247951, 0.283524830289165, -0.291086678837846, 0.958926433354009, 0.485204224850785, -0.748190526941709, 0.334781867920445, -0.26839213221904, -0.187479727437693, 0.0618863200466343, 0.3494765019992, 0.293805171014466, 0.651020057739376, -0.350113351336363, -0.438066533233105, 0.054396555577505, -0.0206531008868494]', 2.29); -insert into credit_card_transaction (time, features, amount) values (157844, '[2.05891199440156, -0.179774461961558, -1.12970484192705, 0.408030616671213, -0.227139560654568, -1.12906424418599, 0.0534076449278054, -0.208948076616949, 0.799359081544365, 0.114683304451371, -1.04022833099562, -0.458358239021822, -1.60800641830317, 0.611058117515671, 0.276787720259479, -0.0645365850016284, -0.161308466894115, -0.729608931888649, 0.112422032348397, -0.337898214973206, -0.307885323414823, -0.825574923642232, 0.35919616209149, -0.129837652594825, -0.36056651051359, 0.211158258365743, -0.0784654387523142, -0.064977424796829]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157844, '[-1.2804131924784, 1.82233396280854, -0.0693940062742576, -1.00979846792662, 0.426852296880116, -1.13599059328136, 1.42991556542049, -0.614385394880862, 1.46929046712057, 2.0517432726412, -0.531295713538944, 0.169108808414783, 0.310969373121468, -0.897334666222061, -0.265542726149647, -0.437431147680413, -0.73406559765094, -0.954282341496572, -0.250579647401289, 0.921442306108557, -0.605066642313551, -0.586242535331929, 0.0192424465724631, 0.0005771814038475, -0.249587598326457, 0.0537393513124151, 0.0973312234037515, -0.473180603798492]', 8.95); -insert into credit_card_transaction (time, features, amount) values (157845, '[-1.04017342964516, 0.478068994061985, 1.26254653096111, -1.77784110314035, -0.284508102016783, 0.346007986891355, -0.287310625711571, 0.623377864022016, -1.15174920832849, -0.263121442448326, -1.95459919552996, -0.363526536476605, 0.749634019000826, -0.191738518222399, 0.139910818313873, -0.747937170382772, -0.413011868328195, 1.36049292428697, -0.598319118240791, -0.296736319363136, -0.622118074869156, -1.42517410458178, -0.10634005038137, -0.0119490791002042, 0.273939050943132, 0.42561643216254, 0.127248590380951, 0.0493072559584417]', 21.0); -insert into credit_card_transaction (time, features, amount) values (157846, '[-1.16998501632616, 0.450392812276972, 1.86993548881047, -1.22240944985834, 0.160216720822717, -0.0700201136657804, 0.100492276009131, 0.354659236748992, 0.360202361660083, -0.568240058415776, 0.0069072836545446, -0.583522980993074, -2.0072168154799, 0.178300966880409, -0.437900452625466, 0.838860810803269, -0.966590537413451, 0.920042823709935, -0.568776764468839, -0.133647107239914, 0.215592166131897, 0.638381882539009, -0.58632569625624, -0.381093332856378, 0.633625722529762, 0.700466445548409, 0.104079898614449, 0.0820819296957852]', 2.77); -insert into credit_card_transaction (time, features, amount) values (157847, '[-1.25936237205995, -0.245868072798358, 0.362838361121548, -1.34375786830269, -0.256033687416538, -0.560010425778525, -0.144129097344281, -1.80519185491725, -1.44904261184901, 0.626208886322148, 0.877302394194352, -0.825970454488623, -1.04263154150753, 0.422574823030625, -0.0287707908931669, 0.876279947115107, 0.347987026493651, -0.400915416221153, 1.48851079444722, -0.595862914429193, 1.93485990558038, 0.93219870281267, -0.451096017674422, 0.14402131723528, 0.189719424833817, 0.237770477575723, 0.44963235365984, -0.006833134629177]', 159.8); -insert into credit_card_transaction (time, features, amount) values (157848, '[1.70101712255528, -0.653911951709174, -1.19885043851807, 0.241982152960315, 0.534503896198341, 1.21156062970239, -0.274383046338503, 0.303670847714445, 0.411365996134159, 0.0579316524007709, 1.05771714372146, 1.49604098097081, 0.840306369121232, 0.227411909894642, 0.290174272435812, -0.438222566629529, -0.11552551201505, -1.11745243468877, -0.715074260002397, -0.0207298651157425, 0.127857039855905, 0.406288381680372, 0.114498315645619, -1.58349984636476, -0.372882132761873, 0.324656715163677, -0.0087143897082049, -0.0607143585767801]', 109.95); -insert into credit_card_transaction (time, features, amount) values (157849, '[-2.0689537918788, -2.67806913519051, -0.704399244439648, -3.72072408996058, -1.64253375492401, 2.59784738931079, 3.22197415324644, 0.352375836843928, 1.42130918110889, -3.17499235007923, 0.564008794547129, 0.195029931505474, -1.365736813362, 0.511969001674109, 1.070918834197, -0.394278112992076, -0.588150511207407, 0.467622902134886, -1.27545557469269, 1.61422117378547, 0.920723225101146, 1.15347683423775, 1.83756159463081, -1.07430103913248, 0.274722706086566, -0.909587618782527, -0.0988205827759531, 0.200475636877625]', 915.71); -insert into credit_card_transaction (time, features, amount) values (157850, '[1.9979595211613, -0.236238202694561, -0.299657024454352, 0.382220683158352, -0.622272150638863, -0.69921522019942, -0.446888471611756, -0.0874257918847648, 1.16027938204007, -0.135330853777436, -0.696472899012873, 0.560858325517991, 0.334576542650276, 0.0108274677307566, 1.00701545551332, 0.285868766692241, -0.637068755041453, -0.186410347953965, -0.23243494339709, -0.225710489377349, -0.138284402123124, -0.257183326029473, 0.372755385286338, -0.125934917026405, -0.443633781884186, -0.607855010509986, 0.0381713352632872, -0.0318873278536854]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157850, '[2.0337549284767, 0.134559064027543, -1.70784396766942, 0.762003346736829, 0.175958487238388, -1.15208225189517, 0.130662628191557, -0.307477388906162, 0.763405022150723, -0.686822353751845, -0.627820949394655, 0.307568570219323, 0.324824038472356, -1.80148364270555, -0.466084469214962, 0.134304715945167, 1.16100782967738, 0.165183677772925, -0.071483074691605, -0.140154529127182, -0.0337851948508485, 0.238191571841133, 0.0096459702594858, -0.165512702652204, 0.124603020028329, 0.643740795109804, -0.0385589476695535, -0.0298154750404508]', 9.11); -insert into credit_card_transaction (time, features, amount) values (157851, '[1.85775908884859, -0.031628155917328, -1.81128960400676, 1.05731771669384, 1.17500541309081, 0.793123282521759, 0.287902315119428, 0.187470889368437, 0.00245578781301, 0.298001298167532, 1.04978303171865, 0.987706737891137, -0.680943255646487, 0.865422745965599, -0.389177453163675, -1.3217602820902, 0.370927126768223, -1.38377230755514, -0.903672981803826, -0.377746986204501, 0.166477914664873, 0.742394227957657, 0.0301588518667023, -1.3481952293484, 0.234932931562616, -0.395908981632443, 0.0272869981967712, -0.0849084209723135]', 18.63); -insert into credit_card_transaction (time, features, amount) values (157851, '[0.133841777275129, 0.91340732317306, -0.586068888298282, -0.752408102671662, 1.09916983386924, -0.279001883907169, 0.812982984656937, 0.111391493274789, -0.149918873336896, -0.641433939672887, 0.470984292055473, -0.02513641809735, -0.848115166541602, -0.678400181419487, -0.814746273681456, 0.696155460703694, 0.0040787440014157, 0.527011768958075, 0.231507646321294, -0.007882666267082, -0.328024520616025, -0.872410982177272, 0.0416231537260778, 0.067256898394634, -0.420720022763395, 0.12474165322144, 0.212056680035392, 0.0679584688667059]', 4.56); -insert into credit_card_transaction (time, features, amount) values (157853, '[-0.418279890450697, 0.81579536323124, 0.368985412027566, -0.637428195883281, 0.850412176076468, 0.0572675513367951, 0.310865439387002, 0.0978606567568951, 0.58870205999343, -1.10848075352022, -1.23894810448455, 0.0652587725700526, 1.12378477233819, -1.80700428143635, 0.45155641578147, 0.694948606653118, -0.0428357439733203, 1.1253942564681, -0.338690994174335, 0.111952288788801, 0.171215003939959, 0.780982657540377, -0.273413739226443, -0.0210120211562227, 0.327827801321158, -0.119782180410774, 0.212917048824943, 0.114382596885579]', 2.49); -insert into credit_card_transaction (time, features, amount) values (157853, '[1.47544036344737, -1.58256845976234, -2.89705666475184, -0.30023943531686, 0.0922802918639253, -0.966930393751996, 0.982769244532117, -0.595733424446083, -1.54815582093274, 1.01063410891185, 0.790592481784231, 0.707077874113169, 0.47990785366851, 0.868639336480863, -1.05122411892755, -2.05003115053192, -0.0829270823298786, 1.13672333431214, -0.505883458584193, 0.213272643794415, 0.183343376120601, 0.247238083150039, -0.408659751586596, 0.869738126179322, 0.361807787372725, 0.920997248054669, -0.200351659289703, -0.0265149795267364]', 394.99); -insert into credit_card_transaction (time, features, amount) values (157853, '[1.92287448702174, -0.554943829608252, -1.63975639957667, -0.44165434257599, 1.60555989801129, 3.87214829745946, -1.58918894332324, 1.16181376627752, 1.09369688167302, -0.403028952943393, 0.374688967611876, 0.0267785971742734, 0.164138842084068, -1.31148323379252, 2.00852008253198, 1.34273225417583, -0.0890269972747848, 0.916779918391951, -1.04710167378957, -0.0406077881672269, 0.186853826891385, 0.520044260158824, 0.26562660330476, 0.621437877059116, -0.510364496039619, 0.324701271059333, 0.0504415899514766, -0.0075721997728669]', 16.26); -insert into credit_card_transaction (time, features, amount) values (157854, '[2.21536640244687, -0.761832351460431, -1.44009502509636, -0.982544007461661, -0.441309728945228, -0.926601129697856, -0.393720326013322, -0.186882566749054, -0.538050863033201, 1.00159439142156, 0.513079455713455, -0.465511856216402, -1.12261178229244, 0.380478446107364, -0.868930711070512, 0.965109852963288, 0.093271830946926, -1.13402915369833, 1.2462731890581, -0.125468256071979, 0.038631357864001, 0.08318456191179, 0.162091625555105, -0.357887959147389, -0.0362178780142174, -0.273892481450678, -0.050224878924179, -0.0805616994704347]', 3.71); -insert into credit_card_transaction (time, features, amount) values (157855, '[2.05111836839243, 0.15740855574506, -1.77858292410485, 1.30581548131097, 0.554152759147043, -0.934726134885325, 0.588798593382001, -0.351999236803142, 0.342446185020113, 0.27932995848784, -1.4621011097146, -0.206990119069699, -0.939526774434236, 0.658990785611951, -0.406651200617979, -0.585834138272509, -0.231079702688799, -0.436103086097665, -0.0668402513658939, -0.3307773289533, 0.0164457752436528, 0.236933609967714, -0.0454524536230938, -0.43373260337407, 0.48577564734282, -0.462149301834284, -0.0206162388502714, -0.0672376011113651]', 11.46); -insert into credit_card_transaction (time, features, amount) values (157855, '[-3.71532525934512, -2.07197333799974, -2.04610422655669, -0.396167587198657, -1.03145282756029, -0.0103205086914879, 0.488058836771038, 0.820881967706672, -1.88922686639007, -0.477766366478084, -0.663032389232418, 0.818952495741138, 1.41412180788548, 1.14596253861254, -0.294753297910607, -0.913476925981963, -0.263414539003976, 2.46725934422878, 0.0130169566719335, -0.416706840325311, 0.208040654412326, 0.318879740222887, -1.09262117812668, -0.897391142591055, 0.137042600655579, 0.0064575342940457, -0.247580678883342, -0.536546546537076]', 334.0); -insert into credit_card_transaction (time, features, amount) values (157855, '[-0.530909875155746, 1.17435827853442, 0.336783716800536, -0.614669457642115, -0.0192581354577398, -0.806302148792159, 0.337612201591243, -1.61704742305679, -0.0850360782366578, -0.08048384622935, 1.12032887671022, 0.699680935363251, -1.03575772016956, 0.558804302624249, -1.08897693923071, -0.0095915894878863, -0.281210448171338, -0.308834647498908, -0.0332952070081408, -0.430407538232863, 1.34410810446113, -0.943107703618564, 0.363276105804988, 0.490827843034998, -0.584133869196096, 0.101312190916888, 0.311724568192207, 0.105158942451035]', 7.18); -insert into credit_card_transaction (time, features, amount) values (157856, '[2.01540437435644, -0.111465787280573, -2.08860495970329, 0.457634705801435, 0.368061511330875, -1.45072604984734, 0.733388380109151, -0.473974788176933, 0.55310744822025, 0.0030824437059599, -1.13350897009547, -0.290800359929977, -1.34187000512968, 0.897001670784938, -0.0164148055050148, -0.846185005698976, -0.032998027637546, -0.459026116964284, 0.139900996870749, -0.256544189397996, 0.14214005213038, 0.496488953738721, -0.116455129676418, -0.148894131920432, 0.509548567209587, -0.0566273144356917, -0.0660938175389855, -0.0710031420590403]', 50.0); -insert into credit_card_transaction (time, features, amount) values (157856, '[2.11410663455505, 0.221262303751733, -1.90895918004813, 0.279334454292127, 0.776150447661988, -0.544063738201821, 0.246480735696864, -0.26240861999487, 0.369526832558714, -0.408771110807906, -0.872743867506429, 0.535175038487399, 1.22828334169484, -1.08973177434185, 0.127805899621275, 0.425140590827894, 0.214414741259754, -0.261083703055955, 0.250943509101405, -0.0697879472999849, -0.388131869207295, -0.957464582459925, 0.25962582353087, 0.0192075506697944, -0.149273411842119, 0.201847314090332, -0.0564306681947466, -0.0336757521987126]', 1.79); -insert into credit_card_transaction (time, features, amount) values (157856, '[2.05534908604041, 0.0841374965825322, -1.29722359923244, 0.33111646993233, 0.153078401225327, -1.12754270891507, 0.29442090303109, -0.403542072735935, 0.374511579862079, -0.0294502273364214, -0.179856858308834, 1.02373714614744, 1.24148684657356, 0.252718846228885, 0.624932005265181, -0.351854302151727, -0.464742147968007, -0.296263238405889, -0.365638899418296, -0.144354978991445, 0.278485159894634, 0.984355184443863, 0.064104682998156, 1.21596852576972, 0.278990261805842, -0.171699129172392, -0.0165538768696907, -0.0449067067384646]', 3.79); -insert into credit_card_transaction (time, features, amount) values (157857, '[2.062958371039, 0.0374118687130256, -1.23238631328565, 0.354402294981913, 0.0255049866263097, -1.23013794186386, 0.249955473863987, -0.412144622270941, 0.504484687246529, -0.021886362923122, -0.503478024728184, 0.774307206790292, 0.933662823360504, 0.291939208034237, 0.727805958460171, -0.27854796170213, -0.513597148924842, -0.216909366100751, -0.332601982233066, -0.196549557490007, 0.274938407751407, 1.01393494641999, -0.0032273479077474, 0.0485636061013697, 0.268049133291928, -0.101561794485043, -0.0072822780080278, -0.0563001426893159]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157858, '[1.18157870250369, -2.26084423770886, 0.328917436013441, 0.359712601878124, -2.46558566741515, -0.623433771763082, -0.817246592064876, -0.164288768593195, 0.385780619264421, 0.38947186814969, -0.124518005204928, 1.21158132789166, 1.86252347165147, -0.690367423879642, 0.747558107269647, -1.20363557096104, -0.246565966172785, 1.53137017520168, -1.72640925552612, 0.303274489442358, 0.212195378393862, 0.415929782511567, 0.0063310035918036, 0.958262657320884, -0.697765868671362, -0.375895419118922, 0.0304260329009418, 0.0674369928222688]', 427.8); -insert into credit_card_transaction (time, features, amount) values (157858, '[-0.285060437222363, 0.398444681342833, -1.63777311632013, -1.25444027336329, 3.52089269019313, 3.04248046652764, 0.343326673841843, 0.818680942487868, -0.39610984935726, -1.04047177138057, 0.185781787589992, -0.344012476237531, -0.298991365523662, -0.538194721490538, 1.13177946103248, -0.0926321684099298, 0.391015259888771, 0.638623515519903, -0.201123728209062, 0.130945753989379, 0.364238611494246, 0.920123282286803, -0.121531199871469, 0.638238398796436, -0.320486640294529, -0.122157560964199, 0.216835034408679, 0.233610744325548]', 31.33); -insert into credit_card_transaction (time, features, amount) values (157859, '[2.25531756741648, -0.728737266335447, -1.61407454275529, -1.04719983638802, -0.255346188428555, -0.855547645554183, -0.394301485905557, -0.295472444662657, -0.458816204961659, 0.885603993615658, -0.990917799826062, -0.991988740209498, -0.154195209329196, 0.0816910672084263, 0.439545317703883, 1.0181100669324, 0.0370028413909377, -1.11427321253212, 0.553885950892409, -0.0191625160524406, 0.402426751515702, 1.12458222329607, -0.0113625780670281, 0.521917148016722, 0.249189228682813, 0.052855380599109, -0.0473898334149382, -0.0623947804171946]', 15.0); -insert into credit_card_transaction (time, features, amount) values (157859, '[-1.76156073693198, 2.24809372244951, -1.62956269742749, -1.61315396238162, 0.795771625258495, -1.40296619787448, 1.52316929236213, -0.207766560200248, 1.02074902604269, 2.08673774061626, 0.469382157875629, -0.203142738431112, -1.64396640553965, 0.573774804015273, -0.583698249471286, -0.504210017428086, -0.790736305530579, 0.24938292184699, 0.0739926413176555, 0.782990121796363, -0.010993774693265, 0.757758644884818, -0.237946347399714, -0.3461125366316, -0.0115550313594168, 0.069825569513537, 0.660851089908105, 0.188171830007109]', 7.69); -insert into credit_card_transaction (time, features, amount) values (157859, '[-1.49690673173603, 1.21086579197235, -0.0045701849654747, -0.258420767092212, -0.0725201006481231, -0.402729968702352, -0.384362184970498, 0.935465162541433, -0.0116594093433838, -1.31028519583209, -0.803422742830355, 0.395364963809889, 0.689080294918112, -1.03297507055313, 0.304272957686309, 1.00151092125707, 0.648408728057791, 0.274869037765567, -0.514391647279716, -0.0982329000933663, -0.162758470401473, -0.732194481053031, 0.0734308530124817, 0.560831525503217, -0.204672591618141, -0.0322806502465715, -0.254617060241025, -0.0232005549027079]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157859, '[0.132328260110561, 0.559162285845658, 0.463002797535602, -0.317521049404263, 0.808976543454281, -0.982835849392863, 1.23199499936075, -0.753896960395423, 0.264605008197533, 0.227898100067521, -0.662527026864023, 0.0057162107925079, 0.0801521555170468, -0.30278503733417, -0.0589371603046416, -0.528320150031622, -0.415717435275568, -0.843314888906276, 0.362569532263927, -0.047478146484045, -0.245992985421662, -0.326829587263855, 0.102511555820814, -0.0073609724267186, -1.02420721871642, 0.0643554156859474, -0.512804210146063, -0.330712800041969]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157860, '[1.77515295239732, -0.991510743470274, -1.96380871022228, -0.883603012511522, 1.71194224603874, 3.70009539285151, -0.910823445845902, 0.962892631161506, 1.09011834416348, -0.238640606497804, 0.019527909849207, 0.556805701145316, -0.0295507095468021, 0.211939250823184, 1.09147637936223, 0.121754209402216, -0.569456967259642, -0.457012463675216, -0.0907126191866462, 0.0955213154367886, -0.174089094668087, -0.73644068780735, 0.34900319133562, 0.67518345755326, -0.514468017508317, -0.316209291717666, 0.0028495279318687, -0.0238627050949399]', 119.0); -insert into credit_card_transaction (time, features, amount) values (157860, '[-0.142051582617379, 1.14096330176463, -0.442775972771893, -0.689439971531945, 0.879699015057055, -0.515459217509872, 0.849827736770779, 0.0695165633625453, -0.110815299190136, -0.363991587525768, 1.17155245741182, 0.582184104103802, -0.210818676307783, -0.85694528816157, -0.873943846180469, 0.419066586515102, 0.212774650613408, 0.148185277579467, -0.0860482474064571, 0.138711262148833, -0.308359558058872, -0.706423117840218, 0.122292249135052, 0.594315940972221, -0.433115110251284, 0.0975585641889865, 0.32854355269546, 0.134657321110325]', 4.97); -insert into credit_card_transaction (time, features, amount) values (157861, '[-2.96357080997129, 2.1650067956824, 0.103935712419153, -0.232358239340725, -1.52231571253481, -0.532397029409427, -1.29355065858134, 1.99123436226992, -0.625109756177384, -1.73787167366151, -1.45388287367673, 1.36329608350479, 1.34786629257774, 1.13657125749964, 0.472572444135707, 0.443900769910772, 0.433047559881013, -0.0106435985743426, 0.379947648506217, -0.586620813757666, 0.106928927356735, -0.447181571140975, -0.0638718333482507, -0.0865347151317248, 0.386370510086327, -0.454903224457373, -1.05082280836792, -0.311628524991711]', 0.12); -insert into credit_card_transaction (time, features, amount) values (157861, '[2.21823721149997, -1.46315018810705, -0.785747596251717, -1.62152252214866, -1.29816006129773, -0.447642348865608, -1.19845341566177, -0.121523105986679, -1.42038775438825, 1.70346303804077, 0.494806859794691, 0.123070103989853, 0.98254284422534, -0.428370958633208, -0.864473775530415, -0.238108251523691, 0.0738189020231212, 0.481722840904335, 0.210614311839494, -0.335280365141519, -0.10672229859758, 0.166967968847933, 0.174978613195283, -0.338981886745532, -0.22986492283471, -0.182060726507927, 0.016310364056674, -0.054457048899242]', 39.2); -insert into credit_card_transaction (time, features, amount) values (157861, '[-0.456886723145933, 1.05737971736289, -0.0166428949712578, -0.867822511754261, 0.553752975439729, -0.541404530688917, 0.848166160282426, -0.0619542776405086, 0.0902244542089866, 0.28671470250161, 0.515820739541806, 0.584191238398215, -0.319280721913853, 0.213434091443719, -0.967656370746243, 0.109949544499459, -0.727922515335695, -0.229542248742426, 0.235348489617812, 0.0528061154988361, -0.223781080349237, -0.545599860580502, 0.0466600665834584, -0.415477587760806, -0.473034983292476, 0.1258925391657, 0.0736249192326495, 0.152394338664803]', 7.14); -insert into credit_card_transaction (time, features, amount) values (157864, '[2.03894121293921, 0.241511138776091, -2.79413442153445, 1.15723274777169, 1.32688267168467, -0.109779510107214, 0.38911098925061, 0.0188212010951561, 0.314203110815138, -0.121782438684363, -0.190421950114032, -0.970514118290818, -2.70138656250686, -0.3582982054163, -0.673517343462302, 0.385869847159292, 0.523906864519133, 1.17171606333828, 0.257701273252827, -0.323399717409358, -0.0776003431449847, -0.190486871599213, -0.107993634449155, -0.54925052392386, 0.498880489443572, -0.468905203526214, -0.0245221037817681, -0.0464512070867046]', 17.18); -insert into credit_card_transaction (time, features, amount) values (157865, '[-0.313323463958786, 0.632376259311107, 0.29512940271073, -0.633751526769824, 0.521940269990254, -0.927914785959757, 0.872894367941366, -0.103640554904512, -0.22899830031809, -0.125025558359861, 0.866704035821042, 0.859562676711219, -0.0711443171864997, 0.271862000867153, -1.08838932474487, 0.0745732129293522, -0.639493412401333, -0.283686108094917, 0.192923938815524, -0.0788723236117352, -0.201694313601081, -0.422014083402148, 0.277153520229165, 0.0661532314380647, -0.492290471915714, 0.110904549820421, 0.139240068148655, 0.0612397718041035]', 7.14); -insert into credit_card_transaction (time, features, amount) values (157865, '[-0.283381145646162, 0.865941939843279, -0.304250232515033, -0.477897404666189, 0.33665478710437, -1.15208798032244, 0.698611426428284, 0.166240510927027, -0.212691520738045, -0.782183846435798, -1.46238731323645, 0.0651593562090485, -0.325187834913675, 0.562219757664704, -0.767158714520289, -0.130305346440044, -0.187905707397729, -0.585587193521494, 0.112876711725679, -0.282981722857364, -0.0363362290512662, -0.160842678520698, 0.191091025307775, -0.104403114298763, -1.22209681434188, 0.0862144881157604, 0.0720594421031196, 0.169780033801031]', 10.74); -insert into credit_card_transaction (time, features, amount) values (157866, '[0.0213854350252852, 0.0779246208762383, 0.758548415858107, -0.42678718817739, -0.336747025765528, -0.524122517788203, 0.543094355937069, -0.017708618858103, 0.605688140202642, -0.764610436739245, -1.03918633964772, -0.0929879626083142, -0.42364553523217, 0.0329404635775625, 0.556115631785696, 0.0101720039707508, -0.388122197905019, -0.121009201269123, 0.272664946939963, 0.0603466582067189, -0.0707435185515384, -0.300752074705935, 0.463839356256913, -0.140340455531774, -1.13261415329168, -0.37629378405746, 0.117633760642754, 0.129313289839772]', 96.85); -insert into credit_card_transaction (time, features, amount) values (157867, '[-0.68779198262862, 0.996084243399009, 1.02123215795639, -0.392809937789044, -0.16316483379291, 0.0301552356689265, -0.0988483202813573, 0.55614497632988, 0.317956847278456, -0.898342596399979, -1.23568736479504, 0.608120812575767, 0.976925263312046, -0.156951160775036, 0.268495717458668, -0.0357724986714881, -0.319629018399072, 0.405532513172817, 0.177933348426048, 0.0292873229780241, 0.268655452237953, 0.977792758049683, -0.201545123771574, 0.759883645495179, -0.129958835774833, -0.18557041036972, 0.325164390155835, 0.176550972309605]', 0.01); -insert into credit_card_transaction (time, features, amount) values (157868, '[-0.364398348967928, 1.59733315853756, 1.75161321849181, 4.29005549101201, 0.264393178921372, 1.36451601362395, 0.0807976973315875, 0.269726675523837, -1.40074952428764, 1.8134334456855, -1.16197755162496, -0.0040626198491432, 1.74467935667803, -0.592694831930135, 0.567361756319281, 0.0406961523874426, -0.0962061966950021, 0.413457025747264, 0.990609721824906, 0.555365594380113, 0.192101834579288, 0.974530389567436, -0.0768549533097639, 0.708801447086545, -0.509850513824215, 0.427342092313316, 0.614883397179661, 0.327002375779003]', 20.0); -insert into credit_card_transaction (time, features, amount) values (157869, '[2.06980685354973, -0.863579693969263, -1.42740541359924, -0.845321005129525, -0.413993431215116, -0.0351673461050645, -1.05471785618858, 0.140981924657615, -0.11025526985459, 0.236675832460463, 0.905396069794825, -0.491467755021709, -0.280190576610429, -1.84597484185882, -0.18998139156363, 1.98741978365491, 1.01975257463699, 0.201878094427111, 0.596009066557203, 0.111845716423449, 0.274006710999891, 0.72708219119874, 0.0567390972955766, 0.109913329663389, -0.142530876045586, -0.109784085979704, 0.0140180672730919, -0.0153263458042373]', 49.0); -insert into credit_card_transaction (time, features, amount) values (157870, '[2.00980304896714, -0.0611619152510945, -0.994514023349943, 0.318080889495356, -0.0803144339766726, -0.927732723415108, 0.126286901259942, -0.227986958836113, 0.185579222933123, 0.22379387547165, 1.14194046649691, 1.47306147454536, 0.555559836925861, 0.360153045072208, -0.732011279476894, 0.0364926847927436, -0.538716634964072, -0.476960754806422, 0.395941218220649, -0.174752319866999, -0.223541365552769, -0.521903295590109, 0.330606403083856, 0.0937673580176166, -0.321557320019921, 0.17051713159915, -0.0708969036195145, -0.067584936177259]', 3.59); -insert into credit_card_transaction (time, features, amount) values (157871, '[1.46500439134067, -1.02205465396596, -0.962494360832829, 0.951331138850521, 0.388866090669564, 2.07794617347438, -0.659606104718875, 0.624189304870921, 0.738709058529508, 0.179711775348874, 0.668109972797724, 0.605067416568192, -0.430424249114796, 0.387392943427837, 1.02383503769648, 0.0668671309150085, -0.449804739256787, -0.129312814604111, -1.32718686161072, 0.0834228851888532, 0.418729406050595, 0.920927985217283, -0.0067786229360114, -0.967583994709863, -0.315062701360656, -0.499281977467194, 0.0559284370542651, -0.0174922161053317]', 203.65); -insert into credit_card_transaction (time, features, amount) values (157872, '[1.99647328097931, -0.0381841365560539, -1.63037686768932, 0.510740886050215, 0.306297274192582, -0.373240479551309, -0.118707476599749, -0.0066143975628803, 0.596754410795014, -0.344505737253383, 1.0215691905776, 0.750525324571754, -0.425349883522695, -1.06072807181574, -1.05617363268476, 0.148392899669498, 0.727410554509579, 0.453266133022171, 0.160628028154977, -0.17994528471532, 0.039707920133854, 0.358452898449485, 0.082079749014033, 0.66443916446072, 0.0546860860072242, 0.589264082461755, -0.0519493845136182, -0.0434301095203548]', 2.0); -insert into credit_card_transaction (time, features, amount) values (157874, '[2.07667621413615, -1.14266363000882, -0.196127468714129, -0.661195101757663, -1.09178595073599, 0.399910473942942, -1.44816337694613, 0.135126214003721, 0.254706538211903, 0.817920535569862, -1.5668839399739, -0.101350586892645, 1.30479553553733, -0.589712907860213, 1.3885558597828, -0.239164211901475, -0.982387371879407, 2.00395351833037, -1.12473022788478, -0.402397001917534, -0.149441799666046, 0.0453216196244074, 0.253415270951199, 0.0431764136687273, -0.599204880379358, 0.605916449990743, 0.0113482288645007, -0.0223315212734847]', 45.9); -insert into credit_card_transaction (time, features, amount) values (157874, '[2.18843802436568, -0.412798189654439, -1.6295927808053, -0.211671821073954, -0.184440128614853, -1.36486559600937, 0.237835818561819, -0.574413031439371, -0.889479299724334, 0.887774784741999, -0.909480538058839, 0.680776627888251, 1.35767112811994, 0.048290968809378, -0.768194125342138, -2.18238506188074, 0.138753144521003, 0.353218149564336, -0.578375843433238, -0.551831265129919, -0.342896043061234, -0.254675497843972, 0.105143081167337, 0.105657412126341, 0.165450240296441, 0.601038343499216, -0.068177613463495, -0.0700240680016269]', 14.0); -insert into credit_card_transaction (time, features, amount) values (157876, '[0.05766828044699, 0.795595532573441, 0.212103643328337, -0.611327658013335, 0.3878452830345, -1.06458305943904, 0.940253876951564, -0.141010009339799, 0.118105158088936, -0.380658366271332, -1.23010504338887, -0.445946319623032, -0.969892946930854, 0.303356897373207, -0.282364792772973, -0.0031631419261157, -0.404746746645889, -0.577389969340814, -0.0213295548251179, -0.101194628914302, -0.282593449988528, -0.680626109535534, 0.0607788818246599, -0.14469382272303, -0.504107662577845, 0.15083550838898, 0.240837185041486, 0.0936294135667924]', 2.28); -insert into credit_card_transaction (time, features, amount) values (157876, '[1.54785715827941, -0.985304866879443, -0.338721628084299, 1.59768003853413, -0.677484352390009, 0.464078604060804, -0.479724304549656, 0.167239802283361, 1.50822093207687, -0.0863835190177967, -1.62791013508354, 0.273970136809261, -0.493270440442393, -0.354579688486155, -0.616648974019689, 0.0470318673341477, -0.323158342674437, -0.106907556534061, -0.0988073573640446, 0.135468914465149, -0.116289824802597, -0.526088358581744, 0.161008144658474, 0.523077344490894, -0.327561547912714, -0.905578537885612, 0.033064247033536, 0.0144412227555499]', 207.97); -insert into credit_card_transaction (time, features, amount) values (157877, '[-0.234077557803502, 1.05382611960802, -0.29533586182078, -0.931633798689611, 0.984728925396521, -0.242332234035449, 0.946296152054668, -0.184674576244223, 0.17194563917938, -0.0957683505043199, -1.56559722765138, -0.0745298580635738, 0.321109682303334, -0.0848462704632371, -0.29970536622435, 0.10814934943764, -0.734561282503127, -0.509340662270577, 0.217451078670974, -0.0174220321554876, -0.259844100523559, -0.755727625854643, 0.0308405743776666, 0.025659380870398, -0.400666345891702, 0.11108107565499, -0.167821624370546, 0.0921694873115362]', 5.99); -insert into credit_card_transaction (time, features, amount) values (157877, '[0.0397928079975763, 0.74938020001181, 0.146912561105988, 1.80354074417267, 0.796011893126402, 0.62870877871757, 0.835704966313316, -0.0601162510144385, -0.712171607054627, 0.193352872838765, -1.52422517913491, -0.477492078900505, 0.28451354668182, 0.358936115673517, 1.33482255639452, -1.17258987588461, 0.313593799999029, 0.559912710790312, 2.49465459614725, 0.411515052395084, 0.288991006705053, 0.920210390402821, -0.129488800757688, 0.0600154896854977, -0.156255769008756, -0.0638682267914006, 0.225413282865286, 0.201849964297183]', 83.5); -insert into credit_card_transaction (time, features, amount) values (157877, '[2.11129378499563, 0.317328116684567, -2.49533074047541, 1.18132367306935, 1.03109789401673, -1.15133128671849, 0.931180264508032, -0.431307889682383, -0.0403003450373583, 0.431813061611664, -1.22131147221688, -0.809473791630871, -1.90150265231977, 1.22799810095014, -0.0648155960119166, -0.79248207213154, -0.117799651163266, -0.292387768620937, -0.306107816557538, -0.392207011700612, 0.277229503225996, 0.897965696195175, -0.169973589842068, 0.651934146411564, 0.839757062608298, -0.215342812256031, -0.0662014272622437, -0.0770319699431879]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157878, '[1.88014049625136, -0.237915221632302, -2.68383509619243, 0.291842672945627, 0.817611167690785, -1.21352252150818, 1.07424358470135, -0.501471875920381, -0.0981340095280535, 0.195731610420852, 0.523539217310717, 0.555860311059213, -0.749224032964665, 1.20601245536685, -0.680564876462848, -0.748008799248941, -0.402836685949778, 0.0955972112171333, 0.425646799639706, -0.0479670438834034, 0.391203211452122, 1.03111629250031, -0.37490208150116, -0.393956676004386, 0.774109915388234, 0.121629744713442, -0.104018722567514, -0.0801718998545801]', 124.33); -insert into credit_card_transaction (time, features, amount) values (157879, '[2.17249892419831, -1.19096549444029, -0.0820010124180848, -1.03231844185029, -1.14909029170875, 0.452251201616478, -1.67737188615546, 0.177969627761094, 0.578871096444642, 0.657675214838819, -1.44792273988426, -0.389860158659066, 1.21203122059043, -1.07071820375731, 0.649993197850087, 1.87199488665078, -0.435020210952003, -0.482944058225307, 0.468778278027942, 0.0873642012900552, 0.379627259603342, 1.19511009675924, 0.128584887597207, 0.0843630768514963, -0.279292267411652, -0.0835766872830982, 0.054316729364895, -0.0298474643347014]', 12.5); -insert into credit_card_transaction (time, features, amount) values (157879, '[2.05274728685734, -0.0921879761644723, -1.07581748328731, 0.413504357792781, -0.152692598186371, -1.13971030557606, 0.139878225827251, -0.283681119701624, 0.608005168768671, 0.0779160657351227, -0.767259767413408, 0.219649199574464, -0.389119867253037, 0.370540731637524, 0.136707508528965, -0.142685842533258, -0.20600912126465, -0.903405584650418, 0.0772074304777765, -0.25908874294004, -0.288438541424859, -0.712356227033048, 0.352169010186753, -0.0255118942847336, -0.328717016970851, 0.202547534660297, -0.0705314864338868, -0.0614292578826149]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157879, '[0.0499921391158288, 0.876540077253547, 0.234221984885402, -0.620767325755901, 0.497596967404754, -1.0297796169993, 1.03939385135476, -0.216264705987973, -0.0812897635797646, -0.422088681926887, -1.00690501267434, 0.249624464111733, 0.340016138971994, 0.043358866927684, -0.425613056898751, -0.0638752124109122, -0.479783771655713, -0.736418897207415, -0.0310561164433962, -0.0082480248844283, -0.26505874450633, -0.57388835489194, 0.0544918040615365, -0.109312303386803, -0.458128631712838, 0.146331532986451, 0.247972565389031, 0.0967836731969802]', 5.99); -insert into credit_card_transaction (time, features, amount) values (157880, '[2.18412950325262, -1.17588049487899, -2.49646100543981, -3.05990952731444, 0.0497895904672459, -0.676950084196004, -0.102980791487013, -0.279683520269764, 0.587137340424869, -0.232910913897533, 0.218496124850071, 0.852689399447933, 0.114945152661132, 0.674168499828891, 0.452429361741913, -2.45808301404821, -0.298995865623851, 1.92353413931694, 0.875548245488397, -0.473957268907759, -0.217498156183065, -0.0575001281047381, -0.0744074632049275, -0.210324042823218, 0.429109206351033, -0.698235426900213, 0.0185080178312527, -0.0615865586600772]', 59.99); -insert into credit_card_transaction (time, features, amount) values (157880, '[-1.06141414204234, 0.728974303142099, 1.08044604195431, -0.53029453873708, -0.385430298477668, -0.485635702052261, 0.0165347810990226, 0.395749255245726, 0.244397134188002, -0.748882156252739, -1.22066208931087, 0.659063861137433, 1.18112203101784, -0.318163036737898, -0.195313630606613, 0.344152256796273, -0.484808107220988, 0.137076343601191, -0.387393530591788, -0.0080358257694072, 0.324178699193292, 1.0769959217569, -0.133239824117183, 0.0721063166568859, -0.265658562316117, 0.589497114652848, 0.140525620305627, 0.149831329425266]', 29.99); -insert into credit_card_transaction (time, features, amount) values (157880, '[-0.19940084273604, 0.612922008795064, -1.21906689030795, -1.76966119605003, 3.4850369490411, 3.41450792570283, 0.962793590572686, 0.0625071342201286, 1.06783712241049, 0.758181154263826, 0.460265311078421, -0.594123157223443, -0.476472059383078, -1.98053908513163, 0.437586324694517, -0.0491812386625616, -0.115456079970591, -0.0363571101002415, -0.661538697121491, 0.542658964373006, -0.261391738675452, 0.204753248298129, -0.0592533914170301, 0.624832210996268, -0.621098875236332, 0.274658083866873, -0.220523290165708, -0.5748785245172]', 13.32); -insert into credit_card_transaction (time, features, amount) values (157880, '[-0.41985234564337, 0.618955524398471, 0.507638907398175, -1.09150550964316, 0.817598217643477, -1.04373945707786, 0.959073952698126, -0.0872551994018337, -0.303732294801804, -0.732927476835559, 0.692179944556287, 0.288896432098005, -0.923384603637609, 0.703249973220436, -0.589076403835129, 0.143202589420198, -0.946366646308019, 0.551598952429705, -0.739042484138003, -0.248954097149514, 0.430508818458542, 1.19171137287465, -0.315690086574632, 0.0305521026729413, -0.0996383991449203, -0.287753956974471, 0.134165628875969, 0.162470442333951]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157881, '[-0.939028004949903, 1.26138096622124, 0.723069981579476, -0.110048815111285, 1.13007185102484, -0.901947848892352, 1.81466311432403, -0.333335789704342, -0.786318984402208, -0.809032920158632, -1.22744283894911, -0.25843558856076, -0.635038510079284, 0.390143033393132, -1.07381130681591, -0.557902140313106, -0.34731126441343, -0.539255518277191, -0.750070846515459, -0.252976166214478, 0.0562515738915695, 0.185962275177467, -0.603705345473185, -0.0412560131521469, 1.32848405878253, -0.459214701431163, -0.132159646216888, 0.0312294103684668]', 28.74); -insert into credit_card_transaction (time, features, amount) values (157881, '[2.11304230886494, 0.530154513613536, -2.81664193554979, 0.527859691099781, 1.04269007921069, -1.13524227705307, 0.318297877090455, -0.300986443269425, 0.62550066218622, -1.19703858237365, -0.743395228863856, -0.722311824109756, -0.152322343729143, -2.52960760843535, 1.22842383686647, 1.03292820979781, 1.46277361250566, 1.56159289500729, -0.373073483521788, -0.146046251954931, 0.030844473814821, 0.290235591132129, -0.166683325800332, -1.28615201751914, 0.372326800865178, -0.0314536687874676, 0.0198887532288243, -0.0040164459182145]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157881, '[-1.13257586532279, -0.878240414827419, -3.36433682323203, 1.45537351412798, -1.19158444676292, 0.264668874952401, 4.15572534209539, -0.210224185199998, -1.0089792070866, -0.490214283065661, -1.61796369469165, -1.17253055092891, -1.68772444390201, 1.62876467981738, -0.113151668758188, -0.950419955938666, 0.176847490290452, 0.38877382340554, 0.276706570500428, 1.58712438193028, 1.02239095805706, 1.60690233967136, 1.98535538806822, 0.557287375867389, -0.782758603481381, -0.406985188241554, 0.175998836780809, 0.407587130052964]', 847.67); -insert into credit_card_transaction (time, features, amount) values (157881, '[2.21854226765637, -1.51776618124299, -0.370169379322724, -1.61668373152127, -1.44618001177003, 0.0739980299342651, -1.60974220899998, 0.0433879464774352, -1.20543494083244, 1.64435907351827, 0.768865512009266, 0.572682191305892, 1.69032513727449, -0.846688981875068, -0.924081503617257, -0.228677729536057, 0.0959709836855245, 0.674474124257206, -0.0599748096083292, -0.309485728629236, 0.112441076739675, 0.913536019091172, 0.173551124535822, 0.810038836595524, -0.184917731097518, -0.0488764379725436, 0.0450803192590963, -0.0416526848595496]', 17.2); -insert into credit_card_transaction (time, features, amount) values (157881, '[1.82456579954111, 0.285269548500017, 0.721219666472839, 3.84627996628275, -0.407771752722293, 0.654994177842359, -0.747951656119178, 0.213241618586786, -0.30370546555363, 1.28570448264253, -0.838475557612555, 0.638621441149359, 1.418532399009, -0.669545064432435, -0.51392676989271, 1.31036460244074, -0.98117578004632, -0.185822807704918, -1.89856788105034, -0.171442513117518, 0.0761419676572011, 0.33092497993392, 0.394075743354188, 1.12578339663129, -0.496763384046174, -0.22215459320539, 0.0403964704519625, -0.0065449801991931]', 5.41); -insert into credit_card_transaction (time, features, amount) values (157882, '[1.23183702604858, -2.3078022901259, -1.46566047318755, -0.120914649468717, -1.04590363843117, -0.126741700326513, -0.040480625007596, -0.260674376550962, -0.274983403741572, 0.604619216280449, -1.2727916342833, 0.160966559348715, 0.983578199102177, -0.128526538470212, 0.244778249089618, -1.19130775237141, -0.298535638461135, 1.13434557497372, -0.872896188152936, 0.456180095676669, -0.105465685527946, -0.793743990144628, -0.123276601661981, 0.505905936216097, -0.502236456307837, 0.469469837392391, -0.12403113641271, 0.039003616767987]', 495.0); -insert into credit_card_transaction (time, features, amount) values (157882, '[-1.2074073866793, -0.693632629991395, 1.21953508532021, -1.92585716825867, 1.3050415283645, -0.87537314165601, 0.342976430480777, -0.170424620383533, -1.70606109434515, 0.246901365806081, 0.615140335756935, -0.134258103399695, -0.177955097810702, 0.175511548311642, -0.645184135638645, -1.1368849200887, -0.77757928605749, 1.75489480925424, -1.26297698678264, -0.13944922453755, -0.0560940438463554, 0.0373952142745269, -0.302662454293229, 0.779572627772124, 0.800720336393893, 0.750291881855443, -0.267820190775824, -0.175181399637481]', 32.0); -insert into credit_card_transaction (time, features, amount) values (157882, '[0.119800421480171, 0.788073645063828, 0.365200372933441, -0.387607948010135, 0.452526275847308, -1.03502750517791, 1.1210342297086, -0.278813741248679, -0.264081156877578, -0.612390949116546, -0.880933733434474, 0.352244037536818, 0.428150073716353, 0.0775234136321686, -0.472085098476475, -0.114799458206887, -0.450837275804333, -0.74537237603181, -0.118907046814831, -0.126732439265967, -0.189770144541781, -0.493129438473522, 0.0888197297521361, 0.0419827537903228, -0.494250829041994, -0.0631196228278945, 0.0146975914765788, 0.040745871605246]', 19.75); -insert into credit_card_transaction (time, features, amount) values (157882, '[2.04325553353614, -0.0709706101781754, -1.16661667802807, 0.220060735880992, 0.115631417930917, -0.694287759068737, 0.108691200062379, -0.196149674300795, 0.22692562752008, 0.227948625227471, 0.758284198709351, 1.29182788348945, 0.543025968713628, 0.351670313659763, -0.692851457223477, 0.160541914302167, -0.684034033449312, -0.332389352607154, 0.552835415865509, -0.17146814839193, -0.253047744884938, -0.603627446511822, 0.282616273178655, -0.32211341504361, -0.268476375071983, 0.196645061609387, -0.0715553071700417, -0.0723531804342788]', 1.29); -insert into credit_card_transaction (time, features, amount) values (157883, '[-1.15873971181859, 0.70325899919763, 1.54610220629851, -1.08340041232099, 1.20845991340509, 2.63648193395707, 0.28264858555381, 0.570527981334167, 0.399324870764302, -0.307130721692404, 0.900324061134677, 0.446975555786788, -0.391625613440374, -0.129585035298459, 1.24788507873968, -0.922136717336832, 0.119427491464606, -1.10374659599658, -0.451841929258245, 0.0144621585395087, -0.132966311302209, -0.0661382497524874, -0.280035365996672, -2.43289635816613, 0.0853859945829929, -0.291643109994768, -0.181032211023036, -0.120684777548576]', 23.42); -insert into credit_card_transaction (time, features, amount) values (157883, '[2.06725387544557, 0.0300951826532658, -1.90371091074055, 0.196124745688249, 0.627307449212471, -0.301370626182012, 0.0078489316468607, -0.0052266615751703, 0.408788982385648, -0.18081594107929, 0.538247473784603, 0.179468895652229, -0.867791635714255, -0.491579343032849, -0.3576225571492, 0.697836604644505, 0.0997321929053881, 0.46004852634077, 0.531699925499393, -0.190669164373386, -0.356044909614171, -0.997355464211032, 0.279391073758909, -0.0289500346935749, -0.254738841249825, 0.187474315901626, -0.0730797677539765, -0.0477001236971459]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157883, '[-0.553637154246517, 1.21389938862376, -0.359671774201268, -0.820613714985574, 0.353400974743767, -0.59014161163548, 0.561825996181848, 0.387409362455909, -0.290824487729718, -0.167423003157977, 0.270549964694574, 0.9898573857443, 0.355775410991013, 0.470274803042924, -1.12093161117634, 0.333805786052442, -0.689613009746339, -0.110766666521385, 0.348006157600673, 0.0203625537091664, -0.226731201940427, -0.559406329794625, 0.0492251612222921, -0.494787794265399, -0.373623993288484, 0.156420833069395, 0.235836878624974, 0.0679559755008272]', 10.28); -insert into credit_card_transaction (time, features, amount) values (157883, '[2.19798276313271, -1.58615272836699, -1.1173872536323, -1.72439481773938, -1.05246030475932, -0.071600589496316, -1.21775824272381, 0.0079993281303919, -1.32949335558517, 1.72459878727408, 0.247030596991558, -0.528296458657413, -0.122653750525107, -0.167458001112183, -0.747549278610277, -0.197636255103138, 0.122837522672345, 0.595521156608868, 0.290476888892315, -0.334810510876988, -0.152303944037387, -0.112013772295834, 0.20649138723979, 0.313267500045442, -0.235181154980195, -0.234744920451181, -0.0056608967489571, -0.0484749320583119]', 60.0); -insert into credit_card_transaction (time, features, amount) values (157883, '[1.98589471424635, 0.903630293991162, -1.61326937640463, 3.49413030231042, 1.29863196619582, -0.347734717657882, 0.89673525355298, -0.336033345619095, -1.98468921250142, 1.73790385951012, 0.486091102613236, 0.77967383115114, 1.02681871009254, 0.702829814471268, -1.5178560305061, 0.709613555899111, -1.17010809272141, -0.153768877280432, -1.08406870959026, -0.217098222537903, 0.182073636741283, 0.555706480199687, -0.0666210603501569, -0.382129610727419, 0.432963752803149, 0.144288870372413, -0.082562071875591, -0.0791433501985024]', 2.73); -insert into credit_card_transaction (time, features, amount) values (157884, '[-0.817271394514991, -0.163029128651324, 1.24480415599954, -3.08176098544972, -1.17504789106182, 0.346712011175051, -1.68980352451094, -2.45047461701233, -2.22539903041487, 0.229526532325601, -0.03440632043014, -0.818319871117663, -0.583682311857783, -0.0239378390487275, -0.951436277240565, 0.545308693100736, -0.216297078845865, 1.2148932386441, -0.851938245102277, 0.185441497729212, -1.15044068178039, 1.04346059582974, -0.162060584547279, -0.380489077429246, -0.171248726852229, -0.154039406505358, 0.113180930810204, 0.141991689109871]', 34.6); -insert into credit_card_transaction (time, features, amount) values (157885, '[2.29474835971221, -1.26796842649129, -1.23807448235125, -1.63360450164355, -1.17992909166558, -1.14541413271088, -0.881508095050717, -0.259722463768442, -1.71942612040821, 1.88549170627129, 0.781681308914434, -0.656584797827918, -0.473477209427936, 0.24943691670009, -0.439981701637185, -0.415335812832912, 0.237622010055678, 0.609449646741765, -0.0766511117066568, -0.496330599236015, 0.116112987340357, 0.761466611628846, 0.0820151942167367, 0.0717760964135275, 0.0234135512209999, 0.0483479863054602, -0.0215447093937162, -0.0726288848855631]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157885, '[2.06889405405631, 0.184193167469339, -1.65314657892988, 0.438584356464676, 0.391986155446804, -0.933348429393487, 0.207225083323461, -0.25987061052302, 0.442194254554936, -0.386790759955339, -0.425216772252428, 0.337957653286203, 0.342054015341905, -0.897214217170686, 0.16515985722717, 0.272427212342383, 0.494018001030447, -0.377702661281999, 0.0122031613563231, -0.141302067952325, -0.354733673740883, -0.901203222014449, 0.349407374885248, 0.646722881905736, -0.261674421643166, 0.164324568461553, -0.0605385943916286, -0.0288538580025564]', 1.29); -insert into credit_card_transaction (time, features, amount) values (157885, '[1.85600394494833, -1.09198857180893, -1.09452599576508, 0.536984316414389, -0.460546864408321, 0.257929760240599, -0.548791010118107, -0.0067318584342177, -0.136464831543382, 0.953864575021698, -2.00699492880703, -0.609613117944753, -0.204192272236451, 0.0363150765498185, 0.317903266841066, -1.06335257707425, -0.57955330004991, 1.69862339527506, -1.00779835134191, -0.356007437504851, -0.29101238164635, -0.599191844879728, 0.0851439804199295, -0.0533491535277418, -0.12722555891233, -0.67490374347964, 0.0296650758442623, -0.0061755116305968]', 156.0); -insert into credit_card_transaction (time, features, amount) values (157885, '[-0.320619269371897, 0.605209835079518, 1.27959785240153, -0.122606532184038, 0.196272125471117, -0.628688169009073, 0.591003640009898, -0.193100826403913, 0.55248086100423, -1.12153121083429, -0.734540102060566, -0.657912052841648, -0.623511178077178, -1.49391293570279, 0.788533961520794, 0.230325382547438, 0.444602184834493, 1.1159653865034, -0.0807412751598658, 0.0727742081825356, 0.246302955526387, 0.987062232491391, -0.335734973749354, -0.034227588355407, -0.0978577793765973, -0.100826259237219, 0.0166484845321075, -0.0392570362947684]', 26.77); -insert into credit_card_transaction (time, features, amount) values (157885, '[0.483280098868548, 0.795439601343825, -0.787744160317465, -0.77142686815956, 1.62362135468515, -0.273073210990403, 1.16077119070475, -0.331007229898111, 0.118464561062453, -0.751754380624121, -1.58918979013476, -0.576608871950142, 0.0711928396996683, -1.19970581592359, -0.230940190534974, 0.526751513073209, -0.127094580160387, 0.123352835631878, 0.172251335948822, -0.0480667848623967, -0.347461892671758, -0.766125074399781, 0.0415310529735597, -0.417390729964411, -0.972197386366985, 0.0290584659413162, -0.0633765164996542, -0.0805398822458552]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157886, '[0.312862549298874, -0.743958604005151, 0.559306442736998, -2.31491459505117, -0.690616264717074, 0.03095845816574, -0.282043849795607, 0.0666929473563158, -1.64248409393381, 0.817090839830718, -0.272797965580411, -0.137186894210367, -0.0438920043070187, -0.790076129259981, -3.17544443480289, -1.1693509999806, 0.765536567619508, -0.191493197410778, 0.716991959901502, -0.407079063325381, -0.407974167768931, -0.531850928873852, 0.0582023203039284, -0.42890224334183, -0.412079547241503, -0.390500422480475, 0.0907146866101243, 0.0278977358144258]', 27.25); -insert into credit_card_transaction (time, features, amount) values (157887, '[1.69354481695103, -0.93352272348415, 0.110547292142508, 1.30452360939845, -0.0342203356701667, 3.0311426200953, -1.54263452733846, 1.00249082852558, 1.98406402390909, -0.146762258712861, -0.165041245376622, 1.39042989753347, -0.38849658401662, -0.803075239996122, -1.6046422502356, -0.834430731671016, 0.372854156108188, -0.734465838337716, -0.472053814670556, -0.280424008213518, 0.0109601422966865, 0.547668653413227, 0.205219540403822, -0.951180525077399, -0.313632647362343, -0.56230188901431, 0.150110799094366, -0.038028802810816]', 35.3); -insert into credit_card_transaction (time, features, amount) values (157887, '[0.135027430350424, 0.920278625154535, -0.583663051473421, -0.753509924737852, 1.10726333133621, -0.278478465931337, 0.815269492379029, 0.107700739220223, -0.160075808549985, -0.642841346782861, 0.482734806645038, 0.0116770900703293, -0.779354441357915, -0.692178665658762, -0.822350430810221, 0.692778505013856, 0.0001973632364672, 0.518285317532906, 0.231213271296817, -0.0049790312859904, -0.32763875025139, -0.866721587512347, 0.0391735349368955, 0.069226084226781, -0.418672829244721, 0.124532788887214, 0.212747275554986, 0.0680562312063862]', 3.87); -insert into credit_card_transaction (time, features, amount) values (157887, '[2.10988271481442, -1.78093153732935, -0.953829775470035, -1.59271108628439, -1.42800109805144, -0.374947423416119, -1.23143406139603, -0.0345887024517971, -1.16956543890746, 1.72317244519138, 0.0772248273219857, -0.794689182879176, -0.612448533457307, -0.0988605027703316, -0.666138600432693, -0.107801727963083, 0.112094221016041, 0.745681782331502, 0.261066816593294, -0.310286815632649, -0.0987222147364173, -0.0278900838648617, 0.121329185559705, -0.537242905064787, -0.286710461923956, -0.173410082273102, -0.0061298239093359, -0.0489005622039551]', 100.37); -insert into credit_card_transaction (time, features, amount) values (157888, '[-2.08715181913104, 0.594585924108475, 2.19073193370848, 4.65141314809625, 0.722306275989519, 0.521332136187854, 0.54503775832058, -0.237098441290528, -1.11072352586371, 2.27297768082269, -0.950129942446287, -0.659912694556202, 0.230523623624335, -0.636668203937824, 0.481824828118569, -0.272821003876924, 0.138479472318522, -0.395195128691066, 1.72235797047574, -0.223231024062605, -0.73138037330872, -0.895055696367621, 0.658519224960902, -0.0144153578355398, 0.070155837783745, -0.0030616055276322, -0.594921655033415, -0.508382033286906]', 18.96); -insert into credit_card_transaction (time, features, amount) values (157889, '[-0.677666306601202, 0.110744746525366, -0.306879494512597, -1.06898574099887, -0.0303695995332362, -0.461027109485463, 0.174475281538574, 0.258792034495589, -1.44446230969727, 0.243078418546412, -0.0126966446653426, 0.329523841637215, 0.247774396740235, 0.638390390702429, -0.477942958571961, -1.62777822765838, -0.291827732396814, 2.16689203345562, -0.241512768047151, -0.643773536293986, 0.162818422764468, 0.946824362808555, 0.0014413512349498, -0.452470295312771, -0.404402450445984, -0.063531492107149, 0.0230944434218155, 0.103892980337779]', 51.34); -insert into credit_card_transaction (time, features, amount) values (157889, '[1.89832533749866, -1.50920037414178, -0.743811571585612, -0.840210417716038, -1.17375244960787, -0.282244172485379, -0.995042019649838, -0.0313071823039281, 0.214075191635019, 0.714255078858815, -1.05289002752096, -0.988559388526399, -0.267175182301721, -0.339013334273561, 0.723691653550387, 1.51366788459664, -0.0780876753099101, -0.743078088641473, 0.323372516792785, 0.274473491894428, 0.460710730993695, 0.976621736748005, 0.0231359798900434, 0.602953667107258, -0.23264225192727, -0.103203442124721, -0.0212740003387244, -0.0151065589080708]', 160.0); -insert into credit_card_transaction (time, features, amount) values (157889, '[1.95966876231186, -0.828504027471752, -1.39050658530932, -0.941804233909333, 1.44708931414929, 3.96280004868419, -1.50330977432456, 1.12702195176584, 1.45673537366681, -0.2061528865365, -0.0845074484335585, 0.511729493811233, 0.0672989827932338, -0.0909342624561307, 1.32603246917828, 0.356977723407008, -0.712068001582958, 0.0457410723398313, -0.330862191108304, -0.11531205683397, 0.0552452696231311, 0.233811887470577, 0.324486562816044, 0.7095618749032, -0.423206101977045, -0.0555100711134175, 0.0513990978232612, -0.0374459161865824]', 8.49); -insert into credit_card_transaction (time, features, amount) values (157889, '[0.124200454762395, 0.961385463800489, -1.22065370215572, -0.156712971783243, 0.335791329590982, -0.928452441102013, 0.534084240774119, 0.31189098323403, -0.275499079615578, -0.997715464436744, 0.633087562237307, 0.0028842216291599, -0.909259088274663, -0.263244998077908, 0.0821858523371013, 0.579309946941751, 0.350550903244017, 1.48130258403016, 0.141096397827299, -0.205660517976569, 0.361826442680131, 0.909013633507647, -0.0567278710658409, -0.443308024596524, -0.273943264791258, -0.147538431744579, -0.0889485518362817, -0.0574033679750877]', 42.81); -insert into credit_card_transaction (time, features, amount) values (157890, '[-0.381967377763217, 0.569619565849526, 0.689143181347447, -1.18691951640229, 1.28858030932289, -0.699361649484901, 1.23611353496332, -0.334581244735284, -0.0327251827347307, -0.695167516152613, -1.66777738795247, -0.603358539317978, -0.6407052516771, 0.0386840741073267, -0.481894171200271, 0.175568244102361, -0.849904449637641, -0.556947081263705, -0.264980756741651, -0.108607157814486, -0.306789395675268, -0.77077544629133, -0.201127985159892, -0.797093352843907, -0.187317767980845, 0.115491985589697, -0.126420214119023, -0.100664223940674]', 0.0); -insert into credit_card_transaction (time, features, amount) values (157890, '[-0.0617282834441294, 1.18210247746459, -1.29807569371835, -0.528633954866264, 1.0324392910159, -0.92275296454125, 1.13589380425663, 0.0577158771232668, -0.851292723437338, -0.506591687736834, -1.3471054926443, -0.339845877015665, -0.314175926086869, 1.06013648217101, 0.0884715904890232, -0.367590665016897, -0.168996827991677, -0.318279922833008, 0.321508232511393, -0.221378357510041, 0.27428672742906, 0.69213355377427, -0.0084564022039689, 0.469134436708823, -0.820371533316482, 0.477782169365201, 0.0372189912326145, 0.180105421031703]', 16.2); -insert into credit_card_transaction (time, features, amount) values (157891, '[-0.79761184988351, 0.0890264281673536, -0.297355996257082, -0.672519014708262, 2.26215957335878, -1.54555949606719, 1.02827726991579, -0.334731493287736, -0.742249673570023, -0.607282103333396, -1.08240579390628, 0.186773289705327, 0.465186993112988, 0.385069701442077, -0.772324410384925, -0.660851439777217, -0.256849610911999, -0.62242517190866, 0.0906999534808683, 0.162904944617692, 0.259202148843272, 0.584549138378743, -0.210682980573219, 0.768047874143922, 0.249427547046301, 0.737383729361696, 0.0008452648953466, 0.15554389046145]', 6.0); -insert into credit_card_transaction (time, features, amount) values (157891, '[-0.21529713964505, 0.655655366022243, 0.465820799990057, -0.645669022634821, 0.348884523446231, 0.0037917485997152, 0.177035958170428, 0.233975497918728, 0.299115785401724, -0.894793011162356, 0.788972426797644, -0.0669656099925482, -0.914533925519109, -1.23018903362898, -0.404244817601481, 0.950536395477052, 0.130238906166253, 1.35474175645286, -0.531856693329135, -0.167360701415443, 0.382150226981118, 1.12546067563067, -0.0525686284305769, 0.637486687098099, -1.09023955654171, 0.413035652651385, 0.086689462116785, 0.257176971635437]', 10.78); -insert into credit_card_transaction (time, features, amount) values (157891, '[2.20412820462168, -0.285749296036878, -2.55387738827129, -1.70072885662244, 0.490468153989234, -1.68100610858093, 0.668865942421141, -0.576324764876292, 1.23437045843367, -0.7480413924731, -1.13102117065232, 0.128575266774618, -0.435326457508107, 0.882100136919085, 1.10931593149754, -0.959382367993489, -0.27389628937389, -0.228101887266599, 1.04494510040716, -0.215852085745831, 0.0671675009353499, 0.374811742063742, -0.121130958918484, -0.722964058804574, 0.513003162531862, -0.0256384117699995, -0.0606470169656779, -0.0841856587340256]', 13.72); -insert into credit_card_transaction (time, features, amount) values (157891, '[0.000747765737877, 1.11258043473596, -0.472999174504701, -0.835378697263397, 1.25833100037577, -0.263414792300138, 1.1267300955721, -0.188293900419061, -0.0369267104743596, -0.167414796216749, 0.906065799959952, 0.68199836534875, 0.542786247626516, -1.23783323290705, -0.932426104829955, 0.502215137468959, -0.159845637322139, 0.279609766389852, 0.162726749666034, 0.276108812109608, -0.389427142446033, -0.734536016790253, 0.0052900648809089, 0.189303903840698, -0.359045659764754, 0.0909492289920093, 0.168152356267895, -0.0936801181472963]', 10.11); -insert into credit_card_transaction (time, features, amount) values (157894, '[-0.0909708413648566, 0.767258537189037, 0.23445132084025, -0.492644222263285, 0.807029961359451, -0.500788323759771, 1.20594889939791, -0.260792231891838, -0.424607203763469, -0.601780033042193, -1.49364096026904, 0.152425183572876, 0.844011032816837, 0.050818922799333, -0.162537601658165, -0.138165159657597, -0.519663623391699, -0.465912722540509, 0.791060542804409, 0.0733000171961986, -0.188137902727651, -0.497838683792118, 0.0276260829840275, -0.693375002885843, -0.643201013833703, 0.22434123740446, 0.119941654930354, 0.183733065973594]', 43.7); -insert into credit_card_transaction (time, features, amount) values (157894, '[-0.980127534041516, 0.334524767225136, -0.775471440271509, -4.05868614407756, 0.493698867524761, 0.223560637089089, 0.446767008689881, 0.33266987755895, -0.195251080158663, -1.29107894209803, -0.403931849182272, 0.558896564335421, 0.265450401515436, 0.648017632065046, 1.43684116275618, -3.73657399858987, 1.14293309060415, -0.0555478780289331, -0.814627514192272, -0.791197286683024, -0.0205511900092023, 0.462587010669406, -0.182166015557391, -0.340585942815003, 0.246240469169606, -0.665176279740618, -0.30475790021127, 0.0504671763727687]', 30.0); -insert into credit_card_transaction (time, features, amount) values (157894, '[-2.03204091182433, -1.06488792677621, 1.02900746725203, -0.707950691745042, 0.921131059237985, -0.77234864813297, -0.867647702078217, 0.843596594834265, 0.0949623344275737, -1.04288654525445, 0.482036228689107, 0.304144667496677, -1.19286413491159, 0.795855206935447, 0.167435868142797, 0.674906847650112, -0.621758240840736, 0.668349841791895, 0.0176207113035838, 0.267229856490416, 0.15267108561428, -0.441585457934236, 0.0531446505084496, 0.655022346858257, -0.447528111827238, -0.338537270276676, 0.0057926074152947, -0.189421873949658]', 23.85); -insert into credit_card_transaction (time, features, amount) values (157895, '[0.874137749654705, -2.2585948557799, -1.53758419552037, 0.305294548961614, 0.0392540004228224, 1.98373419044859, -0.0733113384410723, 0.474959724258854, 0.869009997415201, -0.267781267194504, 0.714247155242689, 0.992399281590358, -0.34522000815664, 0.300383581950972, 0.103198348605188, -0.287871898232923, 0.101774560729862, -1.2766824339752, -0.414501438393064, 0.804052177639246, -0.0357181775517071, -1.1187224497687, 0.0451053007809415, -0.950751522504831, -0.970777039077199, 0.171680070039731, -0.105172879023415, 0.0233110152140974]', 534.34); -insert into credit_card_transaction (time, features, amount) values (157895, '[-2.95145750903908, -8.73573413946963, -3.19142730477141, 2.28958951295271, -3.19028213455878, 0.942239616805806, 2.6483306329096, -0.456285154587222, 1.37406078363675, -1.37141284801514, 0.0219770585922259, 1.00977234527812, -0.572858438392427, 0.479282493500472, -1.07714292909117, 0.243019395645019, -0.233661718597804, 0.518359489946215, 0.179549377710051, 4.89736148889273, 1.16752516858805, -2.13662574484399, -1.89536603613023, -0.316139015785521, -1.35926095720466, -0.578141115222792, -0.469111571143466, 0.387144266192967]', 2547.47); -insert into credit_card_transaction (time, features, amount) values (157895, '[1.99524471543149, 0.0478028354206297, -1.78389631026649, 0.566291262184279, 0.390627709715454, -0.439593497864376, -0.0972031322100111, -0.008939082182975, 0.580598520383246, -0.510669564244049, 1.14367161541455, 0.672875123793974, -0.448265216525295, -1.47141885745689, -1.01457568657872, 0.279720143058648, 1.04356686596404, 0.632343443819284, 0.0998898966523721, -0.169950398648955, 0.0167127569916756, 0.298321317672987, 0.0764676321552158, 0.629316448748177, 0.0552932153004491, 0.589562939923034, -0.0468315097484694, -0.0346069473780067]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157895, '[-0.381916014389752, 0.904582120168873, -0.141546969460458, -0.537496749583165, 0.763007312860442, -0.529913958651372, 0.860120857325146, -0.206775159620225, -0.1701873695429, 0.277578285045535, 0.612721978771451, 1.05399594426673, 0.644246431463654, 0.155585390697352, -0.919692041278245, -0.154930793040093, -0.638860823210908, -0.242201227004461, 0.762955401945503, -0.0537200116866628, -0.0841940078416719, -0.0924552780241062, 0.141017451594184, -0.368833443433274, -1.44413410105477, 0.0414779176896924, 0.0890699726447463, 0.32658336770486]', 17.99); -insert into credit_card_transaction (time, features, amount) values (157896, '[2.15499611722595, -1.6336642382552, -0.911913532218405, -1.86491212066969, -0.688111109642097, 1.20093794276144, -1.61756801083601, 0.406422249064719, -1.2056725611387, 1.60232254488955, 0.684554724030332, -0.218634802186758, 0.0930094051838177, -0.236352664284653, 0.0739279098975766, -0.918477765891507, 0.808858365675431, -0.594233105021545, -0.757435930028644, -0.52720565298939, -0.0578634466504834, 0.430217390450558, 0.259312026867836, -1.66060489541335, -0.45468499426435, -0.0627993097062929, 0.0699963425232515, -0.0727435156063523]', 13.7); -insert into credit_card_transaction (time, features, amount) values (157896, '[2.30676850320387, -1.30544402277144, -0.884869842725682, -1.61545749090099, -1.07619691380622, -0.410873067101839, -1.14073858781718, -0.206782284230105, -1.26625373362318, 1.52023902956032, -1.0214862603368, -0.262823041307623, 1.64365810654171, -0.753288061143543, -0.194312068498528, -0.470152690442343, 0.307750699937535, -0.0900594583797713, -0.106598512380145, -0.327445943540135, -0.163568247276504, 0.0775823326844607, 0.249953596209345, 0.586745946113069, -0.168345671495382, -0.205431612936236, 0.0232755453153838, -0.0387018291035679]', 17.0); -insert into credit_card_transaction (time, features, amount) values (157896, '[0.599062585536189, -2.87642397545265, -0.938185941587078, 1.26624325159145, -1.61356731465813, 0.291096359269465, 0.0068046430870135, 0.0729261293467636, 1.82107574441951, -0.443454710302831, 0.0752076867270332, 0.785705698936285, -1.45568139258644, -0.0039056074544981, -1.60529947612682, -0.454145535411903, 0.021332959933459, 0.622705206907382, 0.186118015368104, 1.02421562322345, 0.689605472870998, 0.896439257457367, -0.619434577662689, 0.097221582502764, -0.106915488698315, -0.0585614518598048, -0.0843976412828654, 0.0581543793712038]', 680.3); -insert into credit_card_transaction (time, features, amount) values (157896, '[-0.537065414805345, -0.436391405163059, 1.97920180154175, -2.2681625856484, -0.488086801026272, -0.0243374073113559, -0.531373467429205, 0.277016609949402, -0.653601613245138, -0.146999956905202, 0.0992599209231778, 0.577345420634845, 1.02564549211825, -0.632632207113674, -0.819813950865385, 0.100690388830211, -1.5079140583366, 2.28593289352485, -2.21626737288044, -0.500515475485959, 0.0242742189580927, 0.458293092387654, -0.0014609892151069, -0.332477668001832, -0.831409923505809, 0.34799265915513, 0.152945955806711, 0.183869935178162]', 21.2); -insert into credit_card_transaction (time, features, amount) values (157897, '[0.084622911456161, 0.0497336642116673, 0.235022065158614, -2.5743832009014, 0.689250369714968, -0.873735137381891, 0.835462806417917, -0.355359498272619, 1.27080607314137, -1.39946764777834, -1.05853907204533, 0.0652953424594523, -0.287463591564612, -0.0590608656504366, 0.599634976273762, -0.721137529430174, -0.46728648182462, 0.050837576778913, 0.771678661662824, -0.0044508951762856, 0.0098029393964264, 0.290247620543975, -0.185970191790329, 0.500470672471646, -0.049905916607372, -0.328566826245707, -0.108169680621951, -0.169769219289147]', 10.47); -insert into credit_card_transaction (time, features, amount) values (157898, '[0.249983446354362, -3.28997149534248, -1.89985683045391, 0.567734891641382, -0.279382544403865, 2.0999999918999, 0.35540964245177, 0.39110305748287, 0.830955648141821, -0.41826027930015, 0.718875969618624, 1.00570653336605, -0.287619166968485, 0.373527606533198, 0.143841636808564, -0.245259410606551, 0.111352944520433, -1.21048745540841, -0.517690036618029, 1.46199176271398, 0.1600459586992, -1.28924021775814, -0.239657250149244, -0.934173487302693, -1.08940409209579, 0.137222849088636, -0.166217859717328, 0.0795649732777415]', 857.42); -insert into credit_card_transaction (time, features, amount) values (157899, '[-8.01482331115438, 7.06255482350825, -6.60054410151113, -1.56961768644062, -1.96823317337275, -1.30580242265623, -1.91254738585737, 3.55887351724071, 1.54153780042878, 3.51910523550793, -0.310078945845208, 1.70228017627906, 0.122048900593556, 0.812923974849694, -1.30596206148944, 0.60784968333206, 1.64837377776102, 0.513783260919317, -0.348658187630747, 1.14407788174426, 0.186234207062, 0.106917799127988, 0.390380028899803, 0.112047885592719, 0.84931575223108, 0.566270499626512, -0.263478408468529, 0.747256758963994]', 2.55); -insert into credit_card_transaction (time, features, amount) values (157900, '[0.0737887856018367, 0.795153712567147, -0.110337248221287, -0.941471202551368, 0.96976346592985, -0.216539312867019, 0.890923219723065, 0.0006700998799452, -0.245552313057108, -0.242328691330827, -0.126860567482349, 0.530713441320792, 0.180656812324312, 0.232442820942043, -1.03763957801116, 0.396802218280224, -1.03432418851456, 0.0699724508962404, 0.589487716098665, 0.0092937964706779, -0.275256012098953, -0.640359765422046, -0.0708344479374029, -1.04178597261983, -0.380898915949113, 0.183812881804712, 0.242684774697795, 0.0770338395992733]', 2.67); -insert into credit_card_transaction (time, features, amount) values (157900, '[0.835191573593701, -2.8578949808554, -2.26582845379784, 0.0084519614756108, -0.993843041083543, -0.537559899793885, 0.697331722824314, -0.39486071271835, -0.823185773502289, 0.768634832349307, 0.245595317638252, 0.256056311382268, -0.366730736338625, 0.70651263164887, -0.710182494158098, -1.33680321462496, -0.285545667357253, 1.33849758707585, -0.371243297505876, 0.762247863441567, -0.0889472786487298, -1.28680630021755, -0.358427737986008, -0.401662520776188, -0.474425709385888, 0.413932352749525, -0.208511736774225, 0.0404490489521142]', 699.0); -insert into credit_card_transaction (time, features, amount) values (157900, '[2.18673115914591, -0.65137035084956, -1.21936289949389, -0.426831404124117, -0.687905141355369, -1.23040952136611, -0.342454819867699, -0.330182618372767, -0.475585490190968, 0.994912922190698, -1.00765374006895, -0.562818152374183, -0.458949771571066, 0.410604467131052, 0.646075357328223, -1.45258338028467, -0.128593402446772, 1.1075089576064, -1.0809696921502, -0.673528987164475, -0.142707317397195, 0.157637210506489, 0.148560404935555, -0.0023299875079604, -0.110416645359042, 0.801492577077862, -0.0624217380014489, -0.0670655990384319]', 2.99); -insert into credit_card_transaction (time, features, amount) values (157900, '[-0.493903185082797, 1.48024304290096, -0.460867342096709, 0.817704257181372, 0.786579133296784, -0.346017270911799, 1.02607370130255, 0.286036551507853, -1.104905623776, -0.0721878333927018, 0.209835127771765, 0.753678252825354, -0.0087216633462644, 0.94060922218128, -1.05818950355916, -0.808935770108734, -0.0203992186404635, 0.251467925973858, 1.15799961647567, 0.0062237131161779, 0.195696889100679, 0.725050858504305, -0.262785766225978, -0.374240225624988, 0.0764665506635068, -0.370815342321736, 0.307725945972628, 0.168930825376137]', 22.4); -insert into credit_card_transaction (time, features, amount) values (157900, '[-0.381217565562118, 0.583593116883996, -0.6116031647165, 0.392167901063612, 0.308642390743848, -1.21689699370856, 0.312991288622845, 0.288781213860821, 0.102971114997442, -1.15577174030823, -1.23470889581905, -0.478156602148045, -1.099423691853, -0.755898134039938, -0.622237070212195, -0.0482957761582344, 1.13419890349787, 0.388192378611406, 0.144331105123874, -0.131533414007584, 0.19261780510878, 0.486821369368834, -0.0275773925489235, -0.0180121172454527, -0.517637181374241, 0.400478218276118, -0.0177141513596138, 0.0010334262797165]', 29.89); -insert into credit_card_transaction (time, features, amount) values (157900, '[-1.91755261697316, 1.33017455482758, 0.042396986871526, -0.419234186100371, -0.758114714975666, -0.179526096022429, -0.709981115280485, 1.32279944762951, -0.07330803555802, -0.93892900978983, -1.3089400501036, 0.775350568166637, 0.822592297930393, 0.473230609007015, 0.146304286898183, 0.723312319860541, -0.146715433712617, -0.231926829091941, -0.327051394185408, -0.294985291265425, -0.049569753753946, -0.542340134411873, 0.236195705569596, 0.661619992444514, -0.173667857384025, -0.0404071249013867, -0.522678304330722, -0.125644985718057]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157901, '[-0.658512660952247, 1.04334176746059, -0.0166830967394197, -0.842387962417706, 0.725381920476646, -0.639462994618298, 0.867608236650307, 0.0736767438617071, 0.0062162473671651, -0.384489774063838, -1.75702069831662, -0.43537894268419, -0.505452948334033, 0.316215343476969, -0.231962922119078, 0.0669014760318342, -0.511063706778201, -0.466199103133965, 0.245638923575681, -0.107831147607011, -0.281945719889646, -0.625309249130629, 0.0465811149370318, -0.796971367459351, -0.530516218757201, 0.152770937066802, -0.0584772396019007, -0.0716419957741303]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157901, '[2.0349323910287, -0.712674693723369, -0.979103212262256, -0.382544655899642, -0.858342592361684, -1.26688783855819, -0.274602223694948, -0.330947970473472, -0.97784037632193, 1.11346689831595, 1.37137792364028, 0.998370993506269, 0.69396395814166, 0.380894093213844, -0.28323105315914, -1.41876712058075, -0.305269237011596, 1.35367295353032, -0.954066258753647, -0.506235517053859, -0.0197954186517223, 0.437240923389281, 0.147126281291046, 0.598042673594229, -0.170892489379524, 0.735138005900876, -0.0677417091212256, -0.0609969483276765]', 43.9); -insert into credit_card_transaction (time, features, amount) values (157901, '[-1.71619744078076, 2.19590069722008, -1.43133986110361, 0.826001188809166, 0.0809214640325466, -0.523320201620366, 0.251037184169182, 1.16411936715498, -1.01633330137333, 0.110172104493274, -0.0704250578982231, 0.99270405150433, -0.0812494106723119, 1.47442938168691, -1.07058596912208, -0.583757163705439, 0.309390186332102, 0.313037614177102, 1.09320727774172, -0.0195425979073825, 0.199890206005182, 0.629591421397521, -0.214343368362719, -0.380159132547274, 0.203338776521147, -0.356621893747678, 0.305434316400816, 0.118843965167719]', 21.82); -insert into credit_card_transaction (time, features, amount) values (157902, '[-0.785322122467692, 0.961483115517616, -1.92215447137287, -2.25379214859201, 3.63205140074275, 2.77544765865689, 1.06789336768814, 0.605739377249651, -0.454833872481111, -0.168550879214234, -0.0555833800674775, -0.16659713584695, -0.481114008226962, 0.804271379305383, 0.400025182901024, -0.77099718131868, -0.442948647755501, -0.531110459917082, -0.198971034096133, 0.140356002520428, 0.157532147291346, 0.547436017700413, -0.378912271650549, 0.755593623838874, 0.473436244817106, 0.228935463942859, 0.293699304408411, 0.27292853275079]', 13.79); -insert into credit_card_transaction (time, features, amount) values (157902, '[-0.649231350061541, 1.28898913178982, -1.13708877120126, -1.66612376719745, 1.60602367924697, -0.828609476026074, 2.1546782608748, -0.833475221302612, 0.893431366057737, 1.60440472319773, -0.071330939352789, -1.00320106825351, -2.13524526236887, 0.317781119890721, -0.441229674090099, -0.40261306843108, -1.26667299149117, 0.525064075793738, 0.445182647564266, 0.525663353383508, -0.0848057714050158, 0.69446935503082, -0.422523743328681, -1.04620806039527, -0.131994015251356, 0.0736582098049211, 0.329804864260251, -0.172873221772078]', 30.05); -insert into credit_card_transaction (time, features, amount) values (157902, '[-1.33559506120005, 0.539863142113922, 0.601209660607156, -0.628999427060293, -0.557872953649539, -0.618379492703623, 1.55312653603153, 0.220532686903824, -0.579231812548526, -1.36822916768202, -1.33243072236119, -0.627569760882967, -1.35277731986473, 0.710444704928356, -0.352577602715176, -0.0259568811120971, 0.0297635357991977, -0.484393066721101, 0.174041202371641, 0.222026247676947, -0.118827557633524, -0.903552034161335, 0.258719943017483, 0.002270339249504, 0.60619085086954, 0.474990545994021, -0.266212284906561, -0.0111088856415367]', 229.41); -insert into credit_card_transaction (time, features, amount) values (157902, '[-0.117021325480892, 0.438512439697097, 0.33625718764148, -0.0538105876965149, 0.632122863666363, -0.757626441193409, 1.49883055414855, -0.604552453069684, -1.74778602208135, 0.551229707525331, -1.21502999923672, -0.260624234451585, 0.391720041016906, 0.0402246504199353, -0.82560137560621, -2.56786644657313, 0.102153392566023, 0.851032810724188, -0.591164816821375, -0.32466052812295, -0.228643010483369, 0.0674866065063492, -0.184743430515323, -0.0376716780976729, 0.126002627109249, -0.488867924247838, -0.0015505696851462, -0.0570840012001833]', 62.95); -insert into credit_card_transaction (time, features, amount) values (157903, '[-1.01895693569342, 0.573433181253949, 0.806061738436092, -0.90562051608275, 0.216796894077958, 0.643680805053632, -0.171086510897476, 0.80431242309621, -0.0131796943757115, -0.733141121111047, -0.178652511630448, 0.550619795933532, 0.128705660648942, 0.118426796199606, -0.65170628130358, 0.692855609208508, -0.802817538525621, 0.864414933655868, 0.111227628789411, 0.104702070849897, 0.295614104529386, 0.80424733658981, -0.239934782738573, 0.0931908163348545, 0.015715681517997, 0.623179386616816, 0.204840217414147, 0.094269198265361]', 34.3); -insert into credit_card_transaction (time, features, amount) values (157903, '[2.11250674460611, 0.124453365564863, -2.48815948601055, 0.320593939176355, 0.889049805139394, -1.13833176480141, 0.796966062689835, -0.381165478141393, -0.260768068822949, 0.469902937431072, 0.723915101344203, 0.182422991632372, -1.41394249440071, 1.25447120089002, -0.806249882919377, -0.543653217828135, -0.300349862713011, -0.0315710926320397, 0.298066252560275, -0.297376700865476, 0.300420853055377, 0.941334195588568, -0.138177245356098, 0.834716891972212, 0.629566386284558, 0.671163374349601, -0.139195997549872, -0.0986853729154215]', 0.0); -insert into credit_card_transaction (time, features, amount) values (157903, '[0.245458649760057, 1.06542020571345, -1.46650845140007, -0.252925553679658, 0.75862951975372, -0.753788439277694, 0.570667673876605, 0.20926954423767, -0.0495699752016178, -1.1314106169566, -1.59114110895577, -0.54887613648666, -0.07395135895906, -0.520545442976051, 0.802776870326066, 0.469823178668022, 0.278727117758228, 1.00434179940077, 0.0707913842822678, -0.208481502534964, 0.268542741878845, 0.753951158705625, -0.183038658877185, -1.14199807087522, -0.14920671987347, -0.0812299246007023, -0.0727396636679443, -0.0576412845557827]', 21.75); -insert into credit_card_transaction (time, features, amount) values (157903, '[-1.56117308741516, 1.64990103489131, -1.16256107048878, -0.803774238594438, 0.198197452056755, -0.409049821905381, -0.142759543233837, -0.24593674464463, -0.24879054174963, -0.19866395879008, 0.699638635500335, 1.30250140877807, 0.529999734258827, 0.877815546237471, -0.400597621683801, 0.151565009014956, -0.512720316843324, 0.469426157330296, -0.227981875872939, -0.734471750018317, 1.28374654881286, 0.845108478223971, 0.107712061009612, 0.73104144487092, 0.0595796084275727, -0.292639139864585, -0.973545660286161, -0.138012663241048]', 3.49); -insert into credit_card_transaction (time, features, amount) values (157904, '[-2.25703474764583, -2.452066486735, -0.952998791848426, 0.689593231867508, 4.56921498529072, 2.64676856927825, -0.895836003994044, 0.916504135325729, -0.517579058722481, 0.388894323189424, 0.100947883275083, -0.0553359506868724, 0.0875441404530024, 0.528294027463233, 1.88135595237381, -1.22045162364543, 0.550988509182496, -0.394821120746533, 2.96309373574462, 0.0825354145041859, -0.291520376442678, -0.321498871608976, 2.03403196225141, 0.700295746018922, -0.321293600937591, 0.68342797032638, 0.266453219757414, 0.101977896714882]', 4.47); -insert into credit_card_transaction (time, features, amount) values (157904, '[-0.980911170983152, 1.37121012118107, -0.559525112034686, -0.550990041471289, -0.0463310330961797, -1.16101399545253, 0.383224959502767, 0.613515412348663, -0.275316848960592, -0.778752087659786, -1.5606500434433, 0.201408672782287, -0.27826762746971, 0.794198461237844, -0.748719796481105, -0.0154493167152493, -0.0132394393918369, -0.573763458656846, 0.0869651585900584, -0.280637287993738, -0.0693480758469666, -0.305566138030473, 0.144366834523028, -0.107082592256806, -0.785703155543112, 0.153121773333652, 0.0139600775815906, 0.119783998280052]', 6.48); -insert into credit_card_transaction (time, features, amount) values (157905, '[-0.254038986112246, -0.150368410161423, -0.38415410346338, -0.930157156013426, -1.30222271559157, -0.645647368229031, 1.34086792948199, -0.494491463326635, -1.24404062286028, 0.8237262368369, 1.12030559072902, -0.962106496776634, -1.88481725306932, 0.360155215525693, -0.912561789425541, 0.115748489947065, 0.869571731892819, -1.13739692101667, 1.90406045091532, -0.283630185679304, 0.211310138416589, 0.764197801992011, -0.127018977972646, 0.580006029754394, 0.261898153975394, 0.0679359153045664, -0.333060788963968, -0.103230700439352]', 238.0); -insert into credit_card_transaction (time, features, amount) values (157905, '[1.97999336554606, -0.142044948535131, -0.703849781227801, 1.34345121368236, 0.158572533861169, 0.331878234956497, -0.199008369791474, 0.0060108194440058, 1.12184362928976, -0.0449915160102269, -2.05189365373729, 0.850441438260074, 0.801719391694577, -0.487676042620765, -1.1828602401452, -0.217452384437668, -0.419751095203964, -0.732192108229198, 0.526117340526063, -0.193106806878799, -0.571728070667003, -1.31492180434125, 0.296523228838472, -1.12473755996578, -0.169760500752762, -1.04098692168015, 0.0600951513983694, -0.0377968242276434]', 17.87); -insert into credit_card_transaction (time, features, amount) values (157905, '[-0.0516352638968041, 0.98050290589871, -2.27477364037747, -0.532868040044273, 0.949273408797316, -1.11834903705716, 1.56498170085685, 0.0839099515100263, -0.80827030136609, -0.0852607048162529, 0.214571835651573, 0.0448990005906746, -1.46489610801555, 1.51398107985028, -1.52859233736862, -0.449187891811337, -0.345523466333364, 0.222036585485296, -0.0027806810655068, -0.11884690761192, 0.591864478964928, 1.62604788111902, 0.204959343085669, 0.817311778977049, -1.16485461322391, 0.335357324996459, 0.334548097294036, 0.321496487977308]', 88.21); -insert into credit_card_transaction (time, features, amount) values (157905, '[-0.585138574634772, 0.554392797846965, -0.533852624863726, 0.152928746715669, 2.0517956790642, 4.57433519490335, -0.177844862220581, 1.56702391162216, -0.153262839347354, -0.742601713873033, -0.82778006764288, 0.417979090672179, -0.359725465815216, 0.258317361925088, -0.632132314125478, -0.824807511083985, 0.355036177820579, -0.626668377868553, 1.07352996770334, 0.0597885070590277, -0.325538016716953, -1.04380728227758, 0.423007943933086, 0.619722085246048, -0.723452126711582, -0.987658492063803, 0.131846603450899, 0.150504208891102]', 89.4); -insert into credit_card_transaction (time, features, amount) values (157906, '[0.0465931987457306, 0.885543809065956, 0.271404015853055, -0.614044460656422, 0.500334810654438, -0.995489108580857, 1.00960491918688, -0.192576617686994, -0.0825707902631356, -0.425735144346444, -0.891728643704836, 0.282676887161694, 0.296401226597962, 0.0579836432229254, -0.38158442492019, -0.144746526559487, -0.393608818194222, -0.849543088109048, -0.130594302914531, -0.0307394276951737, -0.257699801885398, -0.537556222389651, 0.0583491706256812, -0.0827868174337551, -0.486584202937646, 0.146924064540632, 0.252989399340288, 0.096507833349973]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157906, '[2.01390375331608, 0.0827776541425267, -2.10430779002471, 0.39780737967145, 0.559252419012978, -0.999448147451114, 0.328952259605552, -0.350386143413494, 0.589149768178417, -0.550796847357519, -0.89925134354605, -0.033535800935122, 0.413198410553575, -0.918931053995973, 0.985744562636534, 0.391661587847706, 0.241392602529502, 0.678598975780997, -0.249491068783377, -0.0745737561188518, 0.176491501605903, 0.609064519323158, -0.152753553596954, -0.837791091597327, 0.33284171041776, -0.0568820407150537, -0.0056292950502836, -0.0286165182927772]', 48.75); -insert into credit_card_transaction (time, features, amount) values (157906, '[1.13797666981808, -1.69344624399708, -1.09067182058295, 1.35595681014061, -0.55215539585825, 0.60490969933164, -0.0994259144511083, 0.190002739783328, 0.969441322934145, 0.175525796279448, -0.460429269359792, -0.22031243001196, -1.62805353933732, 0.584155864826226, 0.120235445140114, 0.970238933912401, -1.13066305708445, 0.941754580081028, 0.0448603287374758, 0.540912032776538, 0.0561830879830368, -0.801958021126795, -0.129766475313135, -1.26068484036493, -0.497367357776644, -0.926388566398691, -0.0377187998129315, 0.0252369570474452]', 438.0); -insert into credit_card_transaction (time, features, amount) values (157907, '[0.0247705606032034, 1.09097958001963, -0.528967932008397, -0.605520807628633, 1.02890270141006, -0.707369624669997, 0.989771564310705, -0.152346114348203, -0.0086363886519808, -0.733513882828902, -0.823778851166164, -0.0354061215341754, 0.337785215169639, -1.12423299976171, -0.24647426636738, 0.369449482882631, 0.264252339235132, -0.188641832553441, -0.145504473084704, 0.0256222258437457, -0.336562644950979, -0.848612460962225, 0.0955877022829466, 0.376690305251935, -0.388507719895016, 0.112511254005237, 0.0916862327139131, 0.077890608279672]', 5.49); -insert into credit_card_transaction (time, features, amount) values (157908, '[-2.42765447777068, 2.30887834156243, -1.29472055152809, -0.49192177545785, 0.34129639487533, -0.42506860103783, 0.0609060051655076, 1.09704104437298, -1.05140079101845, -1.63900965993603, -1.32666148942587, 0.663720001185731, 1.88986714769002, -0.258809432019079, 0.780034642769215, 0.520700225331663, 0.734846299552925, 0.893135989976126, 0.366015593703541, -0.311140729671428, 0.328644142901115, 0.531112322474409, -0.661398635144403, 0.0312696916656398, 1.15118947030638, 0.035724955713893, -1.11011498388287, -0.473302418468432]', 25.0); -insert into credit_card_transaction (time, features, amount) values (157908, '[0.0926357201473769, 1.24502659579819, -1.32996795922569, 0.0162000757520552, 0.881710593584294, -0.243087876272779, -0.426771099182833, -2.76779067460179, -0.166681792207206, -2.24643613704431, -0.578056093020906, -0.148209488146708, -0.581185345290101, -2.19342043502059, -0.662685601756719, 0.586875430226292, 2.04227132520997, 0.663702830144735, -0.780632966414863, 0.586372262257694, -1.27882194169557, 0.536998872601288, -0.264142204116178, 0.456993611287235, 0.893745113546679, 0.731997964039419, 0.0860093874833085, 0.324464391838056]', 12.31); -insert into credit_card_transaction (time, features, amount) values (157908, '[1.99324833203318, -0.83319912010525, -2.68769780748939, -0.369608362338447, 0.186569506050947, -1.48068293354212, 0.748629385505938, -0.679114881138996, -1.10250175989748, 0.975818606981075, -1.36787389593569, -0.483666560715026, -0.19495642539827, 0.764836450181156, -0.261422163946881, -2.19995350949636, 0.125469277514611, 0.70480493868789, -0.631609819621673, -0.358546973689111, -0.0398415642938354, 0.198095705248245, -0.258970463341371, -0.345437776889043, 0.478851486383427, 1.0332507476481, -0.148630033752764, -0.0718456343220761]', 154.98); -insert into credit_card_transaction (time, features, amount) values (157908, '[-0.25080783252098, 1.07246180826257, -0.873690545826931, -0.151194103426197, 0.273120150895431, -1.05780137900395, 0.558517846599771, 0.256869034454488, -0.34560288207957, -0.897386537832912, 1.03803808108836, 0.253692091136194, -0.7765158281827, -0.188952254036643, 0.0753340571846981, 0.313864801674154, 0.46639741027085, 1.19456704633898, 0.0093102442504786, -0.307477743381429, 0.407393820533666, 1.10717297727466, -0.0195888452209443, -0.0676259598157408, -0.408615198007465, -0.17906945006243, -0.118683052997159, 0.0079366148534008]', 29.18); -insert into credit_card_transaction (time, features, amount) values (157909, '[-0.0947391909592723, 0.375172534723615, 1.24680005456955, -0.195607113359925, -0.153787639501474, -0.457432176308868, 0.179266175082623, 0.0340459979987299, 0.701563939674269, -0.720415346832911, -1.32736972550344, -0.111173961760158, -0.304984083930414, -0.163316268766993, 0.29430112621322, -0.1181198013219, -0.433636407590132, 0.494517554519687, 0.140064425456671, -0.109058163407614, 0.331100771425887, 1.14184928527388, -0.0870346754838411, -0.0032903403959216, -0.830756209934015, -0.269584981811816, 0.270869434257416, 0.238445158218471]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157909, '[2.13594297883431, -0.0004015969276476, -1.47783967272336, 0.161963278578655, 0.458716579522584, -0.593329307546439, 0.23590393813479, -0.329735834085398, 0.44950568363661, 0.0430689063464959, -1.4869529095715, 0.668967887294012, 1.32425266224343, -0.0014529232428345, -0.002248691477363, 0.147395166233377, -0.727551244947571, -0.662741491954791, 0.530555422274653, -0.12127426577678, -0.345102006055858, -0.802317115185071, 0.198618879646868, -0.974142969559776, -0.123251323607733, 0.256761877496172, -0.0650824806319844, -0.0681305970956919]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157909, '[1.99469208315303, 0.336003820218472, -1.54330430092413, 1.27080614832155, 0.313781509756749, -1.51172076884198, 0.70880536285969, -0.407782017595857, -0.398269940354268, 0.555721220112759, 1.38814040080625, 0.859398105678084, -0.640914719390795, 1.10846021273329, -0.524689089065201, -0.366261164020548, -0.464614005399254, -0.0712609541476403, -0.30372901102756, -0.323066353087508, 0.203998944889394, 0.658310826604845, 0.05093690518782, 0.539239907299545, 0.358090224890124, -0.537288169666052, -0.0366296700876039, -0.0691747883797682]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157910, '[1.77247027069035, -0.439409688459886, -1.84459850519985, 0.352019683927497, 0.100150031056696, -0.500590546853668, -0.010740575037245, 0.0356881143434952, 0.969075825741137, -0.687168719048782, 1.01167659471481, 0.183333884318202, -1.71845411001624, -0.930393156517682, -0.562986990470135, 0.219635324291018, 0.962479424289317, 0.652316535065338, 0.319939712853861, -0.0344384266060296, -0.146370970177332, -0.53718995005491, 0.145167736881368, 0.551771519521099, -0.184263721389302, -0.144994843560502, -0.0420902455317882, -0.0095115280963436]', 115.36); -insert into credit_card_transaction (time, features, amount) values (157910, '[-0.657531455719813, 1.39973864909325, -0.425651200869176, -0.287011476856892, 0.529657440979324, -1.09706836262121, 0.690547761082501, 0.254158968786737, -0.134009358843976, -1.48376798697574, -1.01556634581355, 0.0528000428356162, 0.205399860468476, -1.58427434761282, -0.940263713599507, 0.207665179725233, 1.24256466406546, 0.372761739266948, -0.20294651667422, -0.0390709726029234, 0.0645482040580051, 0.428463629146299, -0.265972285428651, -0.169294895830524, -0.129878069924786, 0.588831963203196, 0.258116027570852, 0.192858204681211]', 4.74); -insert into credit_card_transaction (time, features, amount) values (157912, '[0.211131284422336, 0.286675685766003, 0.0627090090937991, -1.88897655137908, 0.0633350820659715, -1.15404286427866, 0.604951089749858, -0.425154905151124, -1.32637468946505, 0.266804134201603, -0.653672270888109, -0.395185926813384, 1.18042111203098, -0.339730459160403, -0.17790111927084, 0.804348776440014, -0.0054832817301665, -1.37502408904382, 0.178865706371488, 0.0334164029520285, 0.532915014563483, 1.52217277363081, -0.28529728601461, 0.0014425489403848, -0.0286294926824956, -0.014257600977176, -0.0836128641165237, 0.0243603678246047]', 15.0); -insert into credit_card_transaction (time, features, amount) values (157912, '[0.0197874103213681, 1.30621737962263, -0.81197185216138, -0.0874597716901431, 0.458784793550026, -1.33311873394097, 0.67514398179196, 0.0827573678323825, -0.376122901940923, -1.20335807844291, -0.488359432384472, 0.354392365742054, 0.830973026365255, -0.653366328511352, 0.597686388817002, 0.0684912877349065, 0.613308869388673, 0.540309298210897, -0.266879867386791, -0.198053942608, 0.357228200169644, 1.09518069874693, -0.152568891454972, -0.0550575896138856, -0.330932413592807, -0.152717490463572, 0.0083527485961637, 0.0395816766884335]', 1.5); -insert into credit_card_transaction (time, features, amount) values (157913, '[1.91066126162459, -0.211159238566408, -0.528439855371583, 0.979040826479544, -0.0110939115680447, 0.465083511553869, -0.535637622860092, 0.203841985114149, 0.582293313531761, 0.344121502099147, 0.393468961284806, 0.880351764181356, 0.275166470433681, 0.182067909767296, 0.140468161598655, 0.898058819091774, -1.25602942439591, 0.675330411934491, -0.0855681488377849, -0.133652281124354, -0.0903288336337876, -0.292904086229648, 0.297358275889729, 0.122598194707521, -0.336875554665426, -0.948067664208927, 0.0432490617214345, -0.0272122038307616]', 31.0); -insert into credit_card_transaction (time, features, amount) values (157913, '[1.79225832698467, -0.0849760704575839, -1.95970148529606, 1.36185163991992, 0.431960880304172, -1.37463637986497, 0.983158255406124, -0.53694791270602, -0.136749052862529, 0.309013907912058, -0.741518976703376, 0.0752642666322282, -0.314208931214831, 0.89186980199522, 0.269010953586832, -0.443688593783608, -0.365164040989799, -0.457252889660962, -0.499139910365335, -0.0231352174738422, 0.209158832699302, 0.40013374941257, -0.127093396910719, -0.0120829018603704, 0.399993131958951, -0.49539645335707, -0.0566006465537482, -0.0401141192067391]', 144.0); -insert into credit_card_transaction (time, features, amount) values (157913, '[0.94216456027253, -1.79992339818104, -2.40273944625159, 0.740017248261139, -0.33933215380822, -0.538472437740158, 0.643437851418059, -0.160503872502217, 0.92095826997913, -0.948998183305172, 0.735444899300075, 0.189370656023334, -1.38094644573399, -1.0294960514447, -0.529687943281462, 0.41040836774365, 0.945202783414781, 0.881937170295514, 0.304679432272243, 0.861499829155589, 0.0923205937190821, -0.794328805016838, -0.335409139091891, -0.601652322434349, -0.300420312178591, -0.131953148870835, -0.117550815061413, 0.0592940295343889]', 554.8); -insert into credit_card_transaction (time, features, amount) values (157914, '[1.33955399554668, -1.57009902692414, -0.736502129989807, 0.58064038521, -1.17958785297662, -0.56575375497292, -0.204163927508693, -0.114901819941184, 1.18538447595711, -0.0790128327249399, -0.972340417482769, -0.265959559841319, -0.725192191260264, 0.19225159442834, 1.07735270662446, 0.58411020319591, -0.543699684376732, 0.18057838709201, -0.527540956582624, 0.452119040508396, 0.376768473567353, 0.406788253940842, -0.101811522002397, -0.0395474071137182, -0.516522562974818, 0.625650187892035, -0.104042929177585, 0.0083551164989929]', 352.32); -insert into credit_card_transaction (time, features, amount) values (157914, '[-0.297960415038452, 1.72596629591149, -0.586200685572207, 3.19595486162759, 1.04206429765504, -0.688006075746141, 1.12231290877593, 0.14132723035833, -1.97230618978181, 0.961474058720724, -1.83953404836843, -1.13671157175163, -1.38444086389626, 1.02815320061198, -1.37918673772152, 0.241865804025122, -0.266971574155994, -0.33600812567418, -1.05456642448721, -0.422516830755513, 0.272682124344865, 0.581673074901658, -0.142270982893622, -0.0530857165943762, -0.245326696296474, 0.111658227514345, -0.20147868455937, 0.0236174975751608]', 7.02); -insert into credit_card_transaction (time, features, amount) values (157915, '[-1.25411039501246, -0.0649692910440273, -0.701484926917165, -2.0137089669258, 3.91257117737602, 3.0084350491042, 0.317902205279048, 0.631811715004565, 0.0796131568708577, -0.187705811660144, -0.230528196910831, -0.0486252227695603, -0.501636393505328, 0.0379061536368099, -0.402998046344604, -0.242755884930695, -0.663790464917861, -0.971644772332455, -0.534067215422928, -0.13102200029208, -0.310168123391017, -0.634984691782627, -0.273068506205573, 0.729149660763609, -0.0950745162621681, 0.162974959299789, -0.0490179350343842, 0.0073919212221497]', 13.35); -insert into credit_card_transaction (time, features, amount) values (157915, '[2.07314050495194, 0.160444533888299, -1.92773981403612, 0.463771784916458, 0.452010631212701, -1.07165320911927, 0.289097027096728, -0.265643615317733, 0.480442465197333, -0.373277032869777, -0.575307344560624, -0.23564207659069, -0.662466926432632, -0.719435986571659, 0.203848788235053, 0.219958539336777, 0.666670663070596, -0.192796974171176, -0.0076825016110446, -0.195157443255181, -0.270750900837503, -0.698427563731026, 0.263745395503125, 0.633327298257517, -0.129101270497182, 0.294110340159281, -0.0772520743222654, -0.0341864203657847]', 5.94); -insert into credit_card_transaction (time, features, amount) values (157916, '[1.9897483178861, -0.223330504600318, -1.04491162019632, 0.331111915571817, -0.217006469308533, -0.880371750891401, -0.0084863098212759, -0.0964788283521086, 0.467794787379438, 0.267843642464905, 0.864910545243809, 0.493568434878492, -1.31998250030777, 0.739487281883822, -0.477672246443677, 0.0691316291020421, -0.378319527459128, -0.331938283830813, 0.338337342243589, -0.28981400913784, -0.23652124140144, -0.656256550604291, 0.353963873281439, -0.016798716630704, -0.400826560364293, 0.181900621423771, -0.0810070673723202, -0.0713197766781938]', 8.99); -insert into credit_card_transaction (time, features, amount) values (157916, '[1.56062905603918, -0.716724649050804, -1.82197651429573, 0.592674213883093, -0.286196644253949, -1.02625855477543, 0.222704049916073, -0.128578787229013, 0.935391202205827, -0.784466686853299, 1.11212858932586, 0.292280905200238, -1.57122910201697, -1.07148191194073, -0.649688231404452, 0.283744027659032, 1.06063654114159, 0.747910067762574, 0.297911804491932, 0.169550971911224, -0.0838371998722528, -0.555272928223719, 0.0132387961735952, -0.0765468985238263, -0.230231921303395, -0.131869871524722, -0.0573828158375352, 0.0066724989919832]', 221.3); -insert into credit_card_transaction (time, features, amount) values (157916, '[2.00047993671758, -0.121883269346704, -1.11192409826635, 0.238849362300104, 0.117110730008115, 0.0610137947047535, -0.534223473268728, 0.158218895397177, 0.723379207723015, -0.304064935245308, 0.781764833705914, 0.668316513646892, 0.101123908745036, -1.09368976154752, 0.0043578023505527, 1.1619110379149, -0.0647448170286013, 0.741493049892432, 0.25422219765741, -0.107685118270648, -0.31370866711294, -0.852833437382745, 0.377936192955871, 0.0733888448462453, -0.560395101943095, 0.098532375664288, -0.0251509086342257, -0.0245952961988179]', 5.5); -insert into credit_card_transaction (time, features, amount) values (157916, '[2.06744234907365, 0.180664572524214, -1.81408279048141, 1.26178223504015, 0.638117857640997, -0.769467932568533, 0.527781532476666, -0.287250068673222, 0.340185903898516, 0.289371450333883, -1.30622006713612, -0.271229657284828, -1.14680752510323, 0.689518362231553, -0.411823821434058, -0.575497632807276, -0.198110208043693, -0.383588248893993, -0.0863699877141649, -0.332918812285031, 0.015966793058212, 0.198756619411277, 0.0290265846303137, 0.640953044200207, 0.478791639732923, -0.517606673028781, -0.0278839615022978, -0.0586915594560799]', 2.48); -insert into credit_card_transaction (time, features, amount) values (157917, '[-1.3811801670671, -0.0110199570090237, 1.6187258326839, -0.789666963552105, 1.75572953441951, 1.11029397124941, 0.521056442426509, 0.288928458325404, -0.438860244480903, -0.555567676392488, 1.33844299885313, 0.895514146501095, 0.0942530042715619, 0.0346926867792677, 0.211127686494395, -0.622843429443675, -0.0105354554558779, -1.57012871041032, -0.537415763506381, 0.0162029388516364, -0.379769697713028, -1.00975114510212, 0.0447805992393896, -1.46136013684093, -0.0212727913427164, -0.054734924590897, -0.29572457100272, -0.0787510504711053]', 32.5); -insert into credit_card_transaction (time, features, amount) values (157918, '[1.90834206460806, -1.74202025372547, -1.23501217970743, -2.20059012917225, -1.09521156185242, -0.497750772699442, -0.698003889949556, -0.144100917330474, 1.1888409238861, -0.215154540491498, -1.76412617679087, -0.0336870769428297, 0.0670911911982854, -0.0285279905038496, 1.23092512837873, -1.59816069013561, -0.323164742123862, 1.44743613353295, 0.299701357477478, -0.261284069498962, -0.555165891807501, -1.31279071130434, 0.187838635043034, -1.127406407645, -0.481465675897489, -0.506746764482113, 0.0188074774386466, -0.0162776564189558]', 176.11); -insert into credit_card_transaction (time, features, amount) values (157918, '[2.08429755832433, 0.103235162466998, -1.61361555890563, 0.485971291788574, 0.264824231190334, -1.41185653162505, 0.598777333538508, -0.504130253158685, 0.496313007988332, -0.0788293085333469, -0.784750615478738, 0.783872174148628, 0.424062917113364, 0.35956500549993, -0.384584739945419, -0.843042744261262, -0.117171998634464, -0.71984337622377, 0.226709340552929, -0.23967285370069, 0.0020007712082624, 0.29396484734589, 0.0296908966250725, 0.0905369947593913, 0.38323670117106, -0.224995693625922, -0.0312610900509016, -0.0657430711526309]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157919, '[-0.26959871730005, 1.00204601186873, 0.353983119582744, -0.524324689068921, 0.195451095588173, -1.37294833640204, 1.07074845419106, -0.259101703364395, 0.0423116891689439, -0.123173436746835, -0.438670575873667, 0.554314605572607, 0.447463335944319, -0.0338829236437851, -0.469034604365884, -0.254854134946186, -0.295459358150351, -0.961104566821315, -0.27532016019649, 0.11314411278435, -0.257930502730128, -0.474437897055473, 0.161304648570382, 0.462782454030735, -0.467900470489219, 0.116095262676174, 0.360871923068357, 0.167584895059721]', 16.84); -insert into credit_card_transaction (time, features, amount) values (157919, '[2.09197169136571, 0.0687219450774321, -3.8188375150935, -0.652842000157968, 3.14274578217089, 2.63383431381525, 0.139801174064295, 0.53522830440046, -0.196245790875915, -0.239075344722302, 0.473904382455054, -0.0718214917982835, -0.325591434711489, -0.248767140037801, 0.815179843740933, -0.0375959810913961, 0.528569745432951, -0.280729046744247, -0.338025403835938, -0.111579824373858, 0.0123578893869716, 0.0263296010496553, 0.0550755644958474, 0.66103493935876, 0.271985819138783, 0.636178815286168, -0.083020013827179, -0.0604894970669956]', 7.5); -insert into credit_card_transaction (time, features, amount) values (157920, '[1.62483403246282, -2.24269797395034, -2.82386739165679, -1.17351838422963, -0.838943532483226, -1.78340421968327, 0.58913379142438, -0.810782632237686, -2.06130494180128, 1.58184664513257, -1.03518416701662, -1.28397525989883, -0.374307944265847, 0.503858184859234, -0.576524952121808, -1.37015604972209, 0.863043538542929, -0.267593956372813, -0.140826509408091, 0.302040095349845, 0.354444651285977, 0.637110120692926, -0.49520294973277, 0.110386315691532, 0.483409140673369, 0.258089300649623, -0.149933100959815, -0.0189630836004605]', 417.0); -insert into credit_card_transaction (time, features, amount) values (157920, '[-1.32974466339768, -1.4508295166275, 2.18600925993499, -1.82624161451296, 0.451298905998421, 1.08660586997725, -1.18945840609869, 0.614540247518562, -0.261847050172193, -0.372205095453535, -0.74079450700664, 0.0993901203691936, 0.722639145458476, -1.36804070025507, -2.17309050851372, 1.25990733608638, -0.115023249708138, -0.335576326065161, 1.55720387641174, 0.589540958165436, 0.223916754100598, 0.427397538252894, -0.199027786387784, -0.302409062568658, 0.697672589540845, -0.046943915672199, 0.0278676827698158, 0.0745410246254846]', 70.34); -insert into credit_card_transaction (time, features, amount) values (157920, '[2.08133949677623, -0.761712376602396, -0.858707345032282, -0.0374845362501132, -0.84299267684175, -0.892698700724695, -0.463015834331284, -0.319803279023863, -0.348509267104929, 0.896894591549453, -1.0544663244373, 0.329699652559688, 1.04416168263655, -0.200348195745272, -0.0203110902126511, -1.5713502021745, -0.183547090235792, 1.21848062108527, -1.08939192477731, -0.513842752573541, -0.0063431778331387, 0.649222366426924, 0.0187114313492941, 0.109604300807661, 0.047182392895006, 0.613509827906607, -0.0174451581753065, -0.0491872826849357]', 39.96); -insert into credit_card_transaction (time, features, amount) values (157921, '[-2.37570629382808, -1.04995863193441, 2.07604531045681, -0.807229985379467, 1.08474989966145, -1.0960588121922, 0.493954715192259, -0.318310909199382, 0.273134776809935, -0.61459747117965, -0.610760381329007, 0.140840810078379, 0.655169145397799, -0.626378873556277, 0.441671901985843, 0.670600034263735, -0.994564066909666, -0.403395298258754, -0.651618397975362, -0.49852969328415, -0.368564851607881, -0.35590977213292, 0.81138039220605, -0.0084219094805577, 0.482435792051295, 0.335093259566536, -0.240414267605951, -0.155891831117611]', 32.0); -insert into credit_card_transaction (time, features, amount) values (157921, '[1.38834229189561, -0.388268819883058, -0.401905090977022, 4.24114276500166, -0.119271577596902, 0.38792100919243, 0.25364013450123, -0.111083582731924, -0.50288165969927, 1.12245784571971, -1.39644097799082, 0.821426950025301, 1.38728501374022, -0.558687497890179, -2.03926870637376, 0.279001420849993, -0.40790763529645, -0.695422717220419, -1.42850628482773, 0.283336656765931, 0.261126085557606, 0.544270143098555, -0.15599877337842, 0.0478875801794117, 0.045308984122726, 0.105473464231047, -0.0381406711443492, 0.0001012789782845]', 256.59); -insert into credit_card_transaction (time, features, amount) values (157921, '[-0.502112973235413, 1.35186603328416, -0.412836920357391, -0.2615558778689, 0.467122897046593, -1.23791813112278, 1.16580854006253, 0.0446847769772345, -0.444110246444329, -0.7393545570311, -1.127309041561, 0.512542557742862, 0.360845245890352, 0.609044759599614, -0.592587851281732, -0.949769044025727, 0.135711529408129, -0.448722187933098, 0.56145111836586, -0.0468475951403699, 0.12007664745922, 0.543318160639334, -0.183263483858848, 0.0909354118908938, -0.0115440124805144, -0.219742904983597, 0.283016279869387, 0.181147342922975]', 19.99); -insert into credit_card_transaction (time, features, amount) values (157921, '[2.14977318513032, 0.0918546589971934, -2.48539435685465, 0.011082315857333, 1.20234423792827, -0.485703100158384, 0.696580403794684, -0.37595348220969, 0.0849770975413368, 0.144088582594547, -0.233900185769754, 1.02298046458883, 0.750042246861589, 0.614021397682603, -0.896903161861583, -0.335743698856402, -0.894274044783687, 0.270438328350434, 0.958145900928726, -0.159903610467402, 0.105323062181276, 0.54569712210562, -0.2717591164204, -1.31324847552732, 0.738292679928578, -0.0061735505435438, -0.0538232332469688, -0.0960391310016814]', 7.74); -insert into credit_card_transaction (time, features, amount) values (157923, '[0.144854668144045, 0.942795884614655, -0.616418344695841, -0.781397453720165, 1.19497757998435, -0.219874196555399, 0.81984880343284, 0.0991589007847242, -0.195286383124, -0.648184510692283, 0.439947920968067, 0.132401190305614, -0.472892716264366, -0.755977814134993, -0.846583646033655, 0.708518590146123, -0.0534080723981094, 0.515331742586739, 0.268809084576554, 0.0112938211942947, -0.332538187196344, -0.862024914655354, 0.0166797699176292, -0.0255676789916286, -0.396233036781039, 0.130041264196013, 0.215407740467439, 0.0674893382702629]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157923, '[1.76794676949225, -1.3317884743186, -1.81390309537759, -0.778302902112833, -0.36067864548818, -0.12158355832951, -0.513622636667698, -0.017555021146143, -0.401912016961426, 0.320425716721317, 0.894189184261683, -0.250111873563193, -0.0412585705092759, -1.29250076137025, -0.440902737498159, 1.66897950273209, 0.826840167764128, -0.28890062993788, 0.772643032446014, 0.452530429634523, 0.243860284072686, 0.237728354398629, -0.0429106778502691, 0.140346897973324, -0.173091873199418, -0.244046219434171, -0.041094952254558, 0.0009445960115419]', 218.35); -insert into credit_card_transaction (time, features, amount) values (157925, '[2.06612409234861, 0.149124262884596, -1.69485014591972, 0.415536143517643, 0.431440051287345, -0.811468848112239, 0.166703470687372, -0.208972068821107, 0.499038603910471, -0.384722274298209, -0.505306774608129, 0.145939917620932, 0.0026536363261812, -0.826880873628236, 0.256620594620613, 0.253322010510034, 0.541493710627918, -0.39796047478566, -0.0272882746234939, -0.168195058334121, -0.358328464876924, -0.920589980050934, 0.350864829724375, 0.507042651410159, -0.277817463850434, 0.175586004307004, -0.0596769873963704, -0.0310382416608503]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157925, '[-0.469927368026209, 0.681071126186689, -1.21057057165811, -1.64019103503306, -0.0452686023708123, -1.13371102044959, 0.243489695007196, -3.59311561575316, 0.0704217064755982, 1.50230778198256, -0.585439928322057, -0.540175022475834, -0.515417190945755, 0.424215596731098, 2.00601585834365, -3.90967508691696, 1.05942396178825, 1.43159240382367, 2.68701634861656, -0.88618933102057, 2.15417831768358, -0.151035698785869, 0.279019326375889, 0.0465086732777118, -1.268932962529, 0.0616609012282296, -0.530081562099901, -0.103633299281977]', 22.18); -insert into credit_card_transaction (time, features, amount) values (157925, '[2.03798409859368, -0.107904287351189, -2.2134741931746, 0.284251169697136, 0.861885585767768, 0.105492458142275, 0.0152618285931339, -0.0266753694179184, 0.562015102087528, -0.315493098591407, 0.0470049034370809, 0.523385053513287, 0.0328599834904463, -1.07213506524223, -1.13083891487648, 0.389608705876798, 0.262801718585189, 0.842614443417707, 0.624837980719691, -0.0716681060532197, 0.0532330445778965, 0.363661241709029, -0.143960173513846, -0.309169799901015, 0.325451888604953, 0.733226556750844, -0.0674276729432825, -0.0537980248281564]', 28.75); -insert into credit_card_transaction (time, features, amount) values (157926, '[-0.149720031210442, -1.29947671081083, 2.02159688784832, -2.51844685789081, -1.04558831530504, 1.90806545577602, -1.61774428375973, 0.624424924848313, -0.638222959495195, 0.496819186791492, -1.27469442222772, 0.204533175024581, 1.47255254524403, -2.06406183073973, -3.12707780329266, -0.349028465809798, 0.149612869201718, 1.14652588975338, 0.682683957223623, -0.177374548345525, 0.0366306720757109, 0.911385983475427, -0.178041636891683, -0.288273405218505, -0.469451968225097, -0.0448956568338422, 0.277215773089255, 0.191103641067075]', 31.8); -insert into credit_card_transaction (time, features, amount) values (157926, '[1.9795778736571, -0.0628243311654117, -0.801145033525763, 0.429915507498614, -0.331972236085698, -1.20402428218077, 0.116049582576774, -0.242515096543534, 0.194024894151914, 0.231712898076633, 1.51719058007952, 1.4860179666106, 0.205326508986029, 0.44125888752274, -0.737272159311528, -0.0884109523365345, -0.352401335637593, -0.598001143221396, 0.220898416506869, -0.210420842369034, -0.196652433595654, -0.456300566777828, 0.39340865192979, 0.557670916520259, -0.39282097127563, 0.142403130544455, -0.0717247944041733, -0.06366750739952]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157926, '[1.67225192237509, -1.67184066639985, -0.78690565921556, -0.71283191897065, -1.07475689136153, -0.149468662167204, -0.602240865497721, -0.0581022270524489, -0.220055242376447, 0.676282310115501, 0.724108066847037, 0.751219767809571, 0.84039135057236, -0.429802304306782, -1.14830086393876, 1.14431773520427, 0.0334859208353034, -1.3913084441712, 1.17342778428317, 0.489415862483088, -0.024771797436085, -0.515639856585539, 0.16354849555215, -0.398703372753287, -0.543406467511388, -0.594296156357309, -0.0317175746725137, -0.0144454796375164]', 246.42); -insert into credit_card_transaction (time, features, amount) values (157926, '[2.06327052064031, 0.6332167225651, -3.16169090593985, 0.614965472820401, 1.25925880130661, -1.3590697924574, 0.70652267672436, -0.327700599453414, -0.199335992216013, -0.869560880333858, 1.7312478121582, 0.244128501610669, -0.572848671895177, -2.16855584459408, -0.67542427667193, 0.523879433659684, 1.95689558843626, 1.06305703240325, -0.0273398567463443, -0.133516068658077, -0.0183601373573682, 0.105097181497664, -0.0466043617170252, 0.587523290926874, 0.35710594172373, 0.659627191027381, -0.0870417683732725, -0.0231235931601989]', 0.76); -insert into credit_card_transaction (time, features, amount) values (157926, '[1.89249428551278, -0.126636355157507, -0.269777503092203, 1.59414794585428, -0.346948353572951, -0.262272167246693, -0.157656720106602, -0.0709524219453199, 1.02794768206607, -0.0539594756059052, -1.09023926843527, 1.27120612926327, 0.759433012836665, -0.45104598593821, -1.27398935659502, -0.528824285411609, -0.0464234198283567, -1.08995304056593, 0.127766751761212, -0.203585489958346, -0.496868851816582, -1.11414829401264, 0.418152845346167, -0.0705564610178097, -0.307551134633643, -1.10722847425256, 0.0610376203425599, -0.0256228531566949]', 25.0); -insert into credit_card_transaction (time, features, amount) values (157927, '[-1.49950278065785, 0.198544987027778, 1.24902345373812, -0.228124591498957, -1.28602824063477, 0.175765469678459, 1.32019922670457, 0.359833114676594, -0.334021624874887, -1.52211713677469, -0.957003189839956, 0.0888477030312176, 0.298160977009357, 0.300753694659534, 1.02372674417847, 0.241951134912847, -0.304956838512993, 0.213557377093191, 0.197082971472968, 0.613954136944857, 0.105898619377152, -0.394461650590835, 0.57259484395786, -0.157633209706208, 0.444455062193257, -0.410752007972983, -0.163469144579092, 0.0364531341705004]', 340.0); -insert into credit_card_transaction (time, features, amount) values (157927, '[2.00999773155784, 0.0780338456022838, -1.61652155075309, 0.339618048335816, 0.386999813090905, -0.581690901989414, 0.0487643151932074, -0.0555420652167005, 0.272619965813547, -0.208061364054128, 1.28223767750235, 0.731158673223781, -0.399539294696636, -0.562925756847489, -0.423129728284929, 0.418383688994817, 0.36364542753353, 0.0828018930751454, 0.205517583317011, -0.178528913716366, -0.299133408303439, -0.803996640628812, 0.360080791148288, 0.600858565849764, -0.338815187405455, 0.1493847773877, -0.0653980436276464, -0.0400808384428196]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157927, '[2.07242834951376, 0.170784467937744, -1.68610985974446, 0.423844711265842, 0.414162742968445, -0.895834796696281, 0.197905432085552, -0.248225625592589, 0.466426547731218, -0.38322948831772, -0.510169448179327, 0.246294227200491, 0.225832110174649, -0.875674627951868, 0.184517595215887, 0.299102369995215, 0.475778461449691, -0.338786076466451, 0.0394066526440644, -0.145858681175497, -0.36042757844679, -0.925081656658464, 0.341634212111376, 0.572669773498015, -0.256878969460669, 0.169051407112824, -0.0616025591092564, -0.0297246080302685]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157928, '[1.22668843949932, -2.44462223269125, -0.893435787102717, -0.647262341835603, -1.09395247475253, 0.851845331530816, -0.783713700846096, 0.200736534870435, 0.059334956177401, 0.432998865157126, -0.0574662532598882, -0.210869192014289, 0.424701382728348, -0.314012591159239, 1.43569115866562, 0.496097419483148, 0.86516185477645, -2.31918846005751, -0.9936610104215, 0.724262791781626, 0.734734972051411, 1.35268564644745, -0.141984034597083, -0.97126974001279, -0.578356232595922, -0.0124460184139842, -0.0078255562590056, 0.016010141695998]', 425.0); -insert into credit_card_transaction (time, features, amount) values (157928, '[2.30177519907839, -1.25629502042441, -1.08308622456662, -1.61083860571318, -0.926888538614509, -0.497754813926663, -0.971889813375486, -0.250068274408717, -1.41090337045908, 1.53118295388869, -0.88988163800387, -0.246967156747601, 1.55576017518623, -0.626213276958146, -0.245237573021508, -0.678501193569506, 0.448204858123719, -0.304258605922677, -0.153860201316035, -0.337322004793529, -0.161210061954408, 0.0788369253966963, 0.238571415146495, 0.615831920613947, -0.111112415612536, -0.188268182255441, 0.0133491261760834, -0.0428505536525869]', 20.0); -insert into credit_card_transaction (time, features, amount) values (157929, '[-0.996633663542127, -1.53229451325185, 1.62348838460276, -2.63569910929782, -0.209817581830176, -1.10360305331492, -0.644968275106295, -0.0210492973107727, -1.94672763390834, 0.480837015985327, -1.04008182540377, -0.599111544266612, 1.14441585333425, -0.82533057089345, -0.65210905684967, -0.17732662692614, 0.133720385012858, -0.204826628163015, -0.852801296886538, 0.0284644717629053, -0.210680180576877, -0.598114124687074, 0.361205503811889, -0.0802641885349423, -0.364965441564858, -0.574159276451151, 0.0914888529202736, 0.166600535479948]', 79.95); -insert into credit_card_transaction (time, features, amount) values (157930, '[1.88667080042368, -0.337838076250316, -0.543728986890066, 1.05161430647845, -0.17983096641759, 0.396881738709101, -0.628385290693623, 0.220266513283861, 0.732336098545478, 0.386322363202457, 0.328422780778863, 0.502116781623136, -0.37866923712037, 0.269425124734399, 0.206780981821633, 0.821881907666493, -1.17185177836571, 1.06809811152382, -0.325963303513875, -0.160025368211387, 0.260342100363387, 0.733663635780487, 0.0910736279044898, 0.321768392159181, -0.0793627923311834, -0.593850042078899, 0.0380393160990945, -0.0319022611131042]', 40.0); -insert into credit_card_transaction (time, features, amount) values (157930, '[-0.748864800183258, 1.21581870775893, 0.705935748097067, -1.08183091938693, 1.24553069749271, -0.588250921000645, 1.34620588621373, -0.120517533308124, -0.680443752040808, -1.58025959317457, -0.613394596538767, 0.0006792452833486, 0.416059829725375, -1.08656005646751, -0.401013749240097, 0.393404291661908, 0.295977691832879, -0.374662895282829, -0.576872091533141, -0.0202856534745011, -0.34510109111359, -1.04574096880025, -0.303818005533999, 0.520637078608609, 0.615090837935169, 0.211693664237025, -0.0505382067459184, 0.0673700622401467]', 11.28); -insert into credit_card_transaction (time, features, amount) values (157930, '[-1.21657246910893, 0.568843673348446, 1.64876509383322, -0.557792472045414, -0.273298988445341, 1.78012172857568, -0.314914711962459, 1.02305282145287, 0.548210456703622, -1.1787380420447, -0.681266913112478, 1.05521178688015, 0.70408647872069, -0.515858965926757, -1.13395623276089, 0.165666011204449, -0.463233693722475, 0.945998889103085, 1.19095111017846, 0.275452775193575, 0.0029476309373415, 0.141420541878362, -0.258955781536889, -0.333517955042215, 0.694632028148933, -0.128919900332844, 0.208011628336672, 0.0701955704622153]', 83.57); -insert into credit_card_transaction (time, features, amount) values (157931, '[-1.58155892330988, -2.77860440658372, -0.510734456627402, 0.603838683866386, 3.89006771657355, 0.0235024593207987, -0.812579162743547, 0.403818636148781, 0.104050386646725, 0.166804211343967, 1.24375204069339, 1.54249834202393, 0.531271557425058, 0.252255191565789, -0.33017965465238, -1.95937488442042, 0.750646956754927, -1.76834461224154, -0.420762944125979, 0.765336181770929, 0.584801954267739, 1.33307390203306, 1.03633300114502, -1.63511855907707, -2.0942093176399, 0.200851894259616, 0.125664788857475, 0.167508926127598]', 111.75); -insert into credit_card_transaction (time, features, amount) values (157931, '[-0.999705470695706, 0.661781016640732, 1.01828728393128, -0.805451545376523, -0.755428099574746, -0.493924324642999, 0.0950675491652153, 0.362861604732441, 0.703607190076796, -1.03793544696967, -1.44266150499005, -0.183107631747373, -0.651545299893335, 0.0643111205055434, 0.118615058128725, 0.215812897625593, -0.366418166689673, 0.447597698769094, -0.272673444317152, -0.398274096834139, 0.359274398785639, 1.0693916355755, -0.0893035191721659, 0.0816305850691395, -0.2779978596893, 0.114368958483053, -0.17717216923088, 0.0730964430666244]', 49.94); -insert into credit_card_transaction (time, features, amount) values (157931, '[0.100148282414153, 0.676166286838082, 1.04349439642276, 0.962489552506196, 0.365100836667361, -0.261914242227575, 1.47077152220227, -0.639380199211605, 0.544084425402585, -0.0411579775358732, -0.923983833654127, 0.888923002165709, 0.552844354748019, -0.902308723167735, -2.07147922941979, -1.45113845494642, 0.124450560151414, -1.07566358426091, 0.37047770840819, -0.0508854197968171, -0.210678083560212, 0.155222398984881, 0.108502729656684, 0.402514909981623, -1.15401443881916, -1.04309538805417, -0.107650934684726, -0.176566228168035]', 55.0); -insert into credit_card_transaction (time, features, amount) values (157931, '[-2.36984159154914, -2.06708959177853, -1.672846441851, 0.207226862282187, 2.09357274384398, -1.92823856607067, -0.0183104403338608, 0.286660233107773, 0.720045768536136, -1.33038276403666, -1.0858394197759, -0.0851601176976521, -0.545261412278518, -1.15329237694464, -0.569572615417847, 0.222130835308653, 0.978158714747765, 0.342694602056529, -0.0428267414226355, -0.617810009419051, -0.0987121863144065, 0.340048359096145, 2.43002557793095, 0.5041642980143, -1.43884015852876, -0.40594440083711, 0.425397261169659, 0.0821332529257892]', 59.15); -insert into credit_card_transaction (time, features, amount) values (157931, '[1.56316419522887, -1.92237851048437, -0.286649942076551, -0.289824700789892, -1.6573304828314, 0.0923729497343368, -1.06135356222741, 0.123180954115099, 0.105007234380892, 0.858124473367227, 0.242249897991142, 0.382766851217087, 0.0108929719067542, -0.118073309622936, 0.028971629509992, -0.504475324346855, -0.706804464266619, 2.04814054847755, -0.730959283968476, -0.0638560757163427, -0.164109422940277, -0.502639121143212, 0.135547486134662, -0.355356367384818, -0.813823143364726, 0.439412438879461, -0.0449778542810493, -0.0024370835543427]', 270.0); -insert into credit_card_transaction (time, features, amount) values (157932, '[-0.160297074648054, 0.709094115878877, 0.148480596231733, -0.516943573360998, 0.311319747315188, -0.965599269386475, 1.06040374899812, -0.279752378143138, 0.15143058394144, -0.399156586790789, -1.12079995666747, -0.359456328175633, -1.00125455513815, 0.232275012925142, -0.49926874390349, -0.265317902442354, -0.215536334494666, -0.751266053430272, -0.0432339711763388, -0.326989621419416, -0.160986762101509, -0.439158590079785, 0.109031352133516, -0.0284253278190202, -0.499343484232979, 0.186041583443561, -0.240397385572595, 0.005166309357732]', 28.29); -insert into credit_card_transaction (time, features, amount) values (157932, '[1.99399610750816, -0.441073379295851, -0.550121635450938, 0.17594495130319, -0.40664065146016, -0.162611661834131, -0.556174657533116, 0.0240606336825749, 1.10933758232747, -0.0185502218286165, -1.09789316881293, 0.221083335413362, 0.132876082197357, -0.120905585088131, 0.610275311059643, 0.565137812534681, -0.643151468420928, -0.276170973023189, 0.0482427268632735, -0.114947435540659, -0.231593211683458, -0.635637013098799, 0.403971896481946, 0.46582289294961, -0.587699144423881, 0.254587372305099, -0.0440856276239011, -0.0354787063757335]', 27.5); -insert into credit_card_transaction (time, features, amount) values (157932, '[-0.923743711077661, -0.0815436012816398, 1.01890830747789, -0.631155831821731, 0.728647896683211, -0.545908250536857, -0.0939054900012241, 0.0480129080617804, 0.405543215330192, -0.343967733273209, 0.413113050146179, 0.803599670305774, 0.377403376991828, -0.0429060416387811, -0.157090461258343, 0.504934899689507, -1.1877927210154, 0.995809183479603, -0.0581101183273862, -0.241519417589196, 0.378695637017941, 1.18094221007507, -0.0907052791267418, -0.30363944506113, -0.741254881426649, -0.391510645595408, -0.0277062511770515, 0.348112927089877]', 0.01); -insert into credit_card_transaction (time, features, amount) values (157933, '[2.01048079100994, -0.163105237744151, -1.02358735609447, 0.331409065401812, -0.208549339987795, -0.962479551905495, 0.0269321823599938, -0.145556666765375, 0.404757178299718, 0.26670775381077, 0.895190191312959, 0.70354411542486, -0.891431446637449, 0.64788656446437, -0.573382353222288, 0.104241874415154, -0.456065049761307, -0.299636396288245, 0.405997076630764, -0.269284330987692, -0.240721748817081, -0.639920425027522, 0.348765906065566, 0.0541082025664383, -0.370181167062733, 0.175461551385254, -0.0801851374028922, -0.070848969242833]', 2.69); -insert into credit_card_transaction (time, features, amount) values (157933, '[-3.21445000084446, 2.91673744080652, -1.8096405745232, -1.02585432790887, -1.27548416232014, -0.547802031402771, -1.37006921340876, 2.08578685226851, 0.707730213691018, -0.96840079874447, -2.1415280814966, 0.347935421516118, 0.331449363036786, -0.313308457981825, 0.40258689024827, 1.42739849619037, 0.766457367589872, 0.835274228448777, -0.0676473357997088, -0.198901135849425, -0.148731851764974, -0.949253091373133, 0.129468696040402, -1.16027957012113, 0.179760019683015, -0.23109155793543, -0.713593054679059, -0.0136291798134445]', 15.33); -insert into credit_card_transaction (time, features, amount) values (157933, '[1.94031432169939, -0.544233624273246, -0.49048247028825, 0.421451359399117, -0.572816447416609, -0.127636909255188, -0.656312416187755, 0.0523169392621075, 1.53107533206318, -0.169331051888316, -1.19524283021061, 0.179578229085371, -0.234706939293981, -0.141673839022606, 0.573752806042991, 0.145934777337158, -0.542353763513583, 0.383136279159721, -0.212045315922458, -0.15593370018846, 0.247900267122131, 0.862970103588059, 0.0837531939331197, 0.686706300720079, -0.0359092549126385, -0.184701218054395, 0.0287115852983715, -0.0275239764750578]', 37.78); -insert into credit_card_transaction (time, features, amount) values (157933, '[1.49409021870911, -2.71278067203835, -0.834707535825328, -1.39735154620108, -1.84857565145707, 0.067364911155527, -1.1105904628073, -0.0455454425153687, -1.32691992068007, 1.54581476644946, 0.843089267257774, 0.140911334245054, 1.15913838191924, -0.470123964905989, -0.250684384426538, 0.109188499842649, -0.0477974859861319, 0.916211583361146, -0.32269850765727, 0.43095587827675, 0.323305498570045, 0.534731173237921, -0.10025923838944, 0.792810112691794, -0.450799514016043, -0.163215685259759, -0.0354466759780227, 0.0256698237320813]', 396.5); -insert into credit_card_transaction (time, features, amount) values (157934, '[2.05051487153934, -0.045836353913454, -1.65988411541739, 0.512492674387287, 0.1312427574889, -1.43688696506041, 0.53251091544426, -0.434171636489779, 0.692519774103628, -0.0482950603998944, -1.00774577985129, 0.0883755183090037, -0.881945406855815, 0.623926151907753, -0.238823561021906, -0.779397570357765, -0.0418641476062158, -0.555759180390315, 0.230120983103104, -0.288944095592865, -0.0027552192544852, 0.177790555018511, 0.0304282345799942, 0.0555684837406786, 0.332706399608959, -0.222421038755834, -0.0430287956281118, -0.0655962020111639]', 17.99); -insert into credit_card_transaction (time, features, amount) values (157934, '[-0.852475802121942, 0.590264681919447, 0.871489937947575, -0.308073286188237, -0.207866690565924, -0.0318295487406609, -0.19742958178507, 0.631285062995786, 0.541966296567461, -0.862467179835533, -1.52030087729121, -0.100929432409838, -0.299295041043022, 0.108546750818018, 0.414708459726021, 0.0343875692949917, -0.266055585255675, 0.655586153914652, 0.157511855513372, 0.0673548312953131, 0.347247701556557, 1.0317434120918, -0.142737614428176, 0.686748511239331, -0.169087002484128, -0.133578656190316, 0.317826877483763, 0.150153259257448]', 29.96); -insert into credit_card_transaction (time, features, amount) values (157934, '[-1.64937504465849, 0.912264588784204, 1.25975654945296, 3.02071593705283, 0.434721587872998, 0.137396270373949, -0.290408942202668, 0.42950993834176, -0.970614790780346, 0.870068741642854, -1.61961161665048, -0.105361275079481, 0.560566436468923, -0.273708808065161, -0.972386978305047, 1.24352826411273, -0.854588187637739, 0.0165976480759262, -1.9511340864707, -0.607226772013721, 0.290573653321462, 0.727866317439068, -0.619974484563451, -0.0428794870960244, -0.211598561201863, 0.0072911947834407, -0.400901041151647, -0.23138405620086]', 8.27); -insert into credit_card_transaction (time, features, amount) values (157935, '[2.00676454566572, -0.710237833925383, -0.755293639141048, -1.62640302113185, -0.625136090845934, -0.546715596537143, -0.572969286306591, 0.0222630902156835, 1.81197066995996, -0.801281967783048, 1.17818691204433, 1.60266326364236, 0.17779544035028, 0.193881783687797, 0.50573184799523, -0.179786831224149, -0.560710817796427, 0.254741303998895, 1.07250517903783, -0.124507887887863, -0.170966816749237, -0.367460029516793, 0.389125186637656, 0.752546762498424, -0.430053917412824, -0.617594779104801, 0.0169297836474716, -0.0390176525159983]', 15.88); -insert into credit_card_transaction (time, features, amount) values (157935, '[1.8152957925141, -0.678746107553952, -2.4025418562889, -1.43217797689056, 0.189442851410343, -1.79984882565986, 0.966507796699274, -0.687095186406237, 0.879442466848056, -0.88253682092583, 0.128477328269856, 1.32638365201651, 1.04606747098471, 0.648284921621648, 0.914678732102231, -1.31133661582044, 0.0192164467973231, -0.721059530122926, 0.572362750797546, 0.22209128467019, 0.254297739029505, 0.56845770814564, -0.11372004482326, 1.19104973989717, 0.376835687297965, -0.152228177039608, -0.0850118732729521, -0.03333362981648]', 180.29); -insert into credit_card_transaction (time, features, amount) values (157935, '[1.40763673596149, -1.15439092717661, -0.708486205639558, 1.34639535383586, -0.682613754301022, 0.108297439154889, -0.281614886873305, 0.095803598225612, 0.801085416968342, 0.294608217861467, 0.173787872122009, 0.246645864162601, -0.856057353747963, 0.43704032539123, 0.257295442992941, 0.879562777910484, -1.14625461407603, 1.17766454346156, -0.376059919468366, 0.280278052594373, 0.402834049353601, 0.600409279993243, -0.167526867690392, -0.521844412501431, -0.192937035480397, -0.578062878500199, -0.0069689442486937, 0.0017792140438377]', 286.0); -insert into credit_card_transaction (time, features, amount) values (157936, '[-1.99960160045057, -1.03097007345002, 0.868237358401827, 0.159978909198401, 1.17580569884783, -0.990404086795604, -0.685854705757231, 0.514693219225114, 0.056373920060499, -1.07163812635335, -1.50081370185409, 0.595907505912696, 1.29591216281519, 0.243759142194074, 1.18529877612739, 0.144926263315029, -0.504452084329012, 0.494566931743183, 0.912768704477751, 0.59130621640204, 0.133479871242145, -0.35503856343963, -0.0808384568878395, -0.723466007608803, -0.169443315890385, -0.760528326090835, 0.0952557361345498, -0.206094254441784]', 42.69); -insert into credit_card_transaction (time, features, amount) values (157936, '[2.12568821011582, -2.03436515358675, 0.900202268696414, -0.968166346990035, -2.6112160839556, 0.422304123376147, -2.38345416590547, 0.220293158533413, 0.414358841966527, 1.13416758777087, -1.7220770903612, 0.352467934575303, 1.54098711939885, -2.11660112855519, -2.08647577744429, -0.870003571468066, 0.92170646437955, 0.0775580207928043, 0.111972634866761, -0.357992637821618, -0.0495320504133747, 0.842973027979845, 0.17722166441416, 0.115382047613715, -0.320203625457979, 0.015381260417291, 0.125359724286661, -0.0226058418312986]', 27.5); -insert into credit_card_transaction (time, features, amount) values (157936, '[-2.36520761815987, 1.96212555829729, -1.0475985119509, -0.225612525608671, -1.0468606891665, -0.377309573552944, -0.930375761538982, 1.72723574494781, -0.0404905057234974, -1.33488885852872, -1.04455162856296, 0.726296637077188, 0.82939946816477, -0.539656098018437, 0.258189525507556, 1.26277629478531, 0.947665603120058, 0.310601639128592, -0.585832049133921, -0.302597616939814, -0.13703350222999, -0.794172260731257, 0.273110299296714, 0.553542125236304, -0.0545949643094026, -0.0293110286785042, -0.541870079163803, -0.173437350956433]', 35.0); -insert into credit_card_transaction (time, features, amount) values (157937, '[2.07073180799526, 0.227550669120164, -1.31574927009334, 1.7266136652626, 0.600045853741118, -0.313731494787029, 0.271924383258325, -0.241764100953671, -0.879137142565208, 1.14052757613183, -1.1357505243856, -0.0246882636798341, 0.703436711202168, 0.0737396200929519, -0.81072903270696, 0.825323047645772, -0.556323780519571, -1.25861827629337, -0.508339505980047, -0.103105497707805, -0.251511327456123, -0.729932964108987, 0.326644059692305, 0.560588901806596, -0.442805340472907, 2.04715086625208, -0.223480358423593, -0.0800168737441402]', 8.63); -insert into credit_card_transaction (time, features, amount) values (157937, '[0.0358113165050554, 0.740719159308204, 0.0944803876090328, -0.804778045505724, 0.608162459433124, -0.543976232764819, 0.847261450713584, 0.0196422143850203, -0.137734274500655, -0.216900516730717, 0.194597805908088, 0.195452382433387, -0.880324521923666, 0.45721000670016, -0.971497775211918, 0.284121323720517, -0.781786981714732, 0.0117086063544979, 0.390657152543995, -0.0677282260485649, -0.250026015762826, -0.619151811566777, 0.0111216423588114, -0.524065779205352, -0.485622877828517, 0.153284567765541, 0.23665543092961, 0.0804886050444655]', 4.49); -insert into credit_card_transaction (time, features, amount) values (157937, '[-0.476661841557924, 0.815895421808081, 0.678821390969839, -0.773410961827341, -0.656031551252051, -0.720742936161877, 0.0194006714821521, 0.34139181427534, 0.642837592119663, -0.891209223898404, -1.16651077440555, 0.153350383618923, -0.28678857807104, 0.13576682716239, 0.248841608411489, 0.351327041714304, -0.440560201340703, -0.0763517143944299, -0.16485121004736, -0.354658954760584, -0.0511691387550822, -0.295775297330079, 0.200184229821621, 0.0039487510590451, -0.765040643508011, -0.384960260404724, -0.302855669408198, -0.0165209291067946]', 19.95); -insert into credit_card_transaction (time, features, amount) values (157938, '[1.93484338219189, -0.389694760094884, -1.44706099169778, 0.0081580551269274, 0.654437771578433, 0.877317935558023, -0.283677918179636, 0.371407993418918, 0.575884941463277, 0.159969186058513, 0.731405267405812, 0.252166929923869, -1.67358051629264, 0.857794902005322, 0.338035963070511, -0.515780456701549, 0.155230586091055, -1.30115197132758, -0.381920279310698, -0.396723132694109, -0.21795942486648, -0.505271720674369, 0.354032768254475, -1.67830397851102, -0.516607247183201, 0.315750393161434, -0.0368376229698279, -0.0909043683195387]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157938, '[2.06253949386552, -0.0822292638845887, -1.13743899601745, 0.375135616510582, -0.0569003504536342, -1.04451125851927, 0.152887861239511, -0.286738147441077, 0.584283724077538, 0.0711448717282764, -0.868474100617354, 0.288731855052136, -0.134677609621868, 0.316160479489972, 0.123341061964316, -0.107611065615564, -0.275826598985267, -0.880057623368549, 0.134407694463371, -0.23801453525169, -0.295679061276576, -0.722962455760098, 0.329472155146491, -0.175943785007295, -0.300425549242861, 0.211411610435611, -0.0693891777777187, -0.062403053465718]', 2.7); -insert into credit_card_transaction (time, features, amount) values (157938, '[1.91797632096915, -0.101480181368795, -1.88891369173568, 0.219718858249453, 0.485723915735256, -0.445284860351535, 0.133246981730833, -0.142217479149238, 0.6567373613872, -0.728637586332209, 0.78093714116065, 1.31836526330095, 0.914956352571586, -1.47653195752055, -0.836017995056432, 0.28794654937039, 0.564584930214796, 0.542679419618553, 0.593760076707005, 0.015706653401832, -0.192899092760535, -0.385347462359433, 0.0308762411111002, -0.886188461346622, 0.0029976297248518, -0.0666178805549832, -0.011731425286745, -0.0278809193377484]', 63.35); -insert into credit_card_transaction (time, features, amount) values (157938, '[-0.379371239477643, 1.42202910728327, 0.555737702645311, 2.65069604526932, 1.82774672661635, -0.826461077005383, 1.86598897579944, -0.495449616913309, -2.16549802584117, 1.01202000210432, -1.29621767841865, -1.18180443670675, -0.857239426525845, 0.563673244455897, -1.01374778800874, 0.44347054819045, -0.896588812741444, -0.425102964327577, -1.63692782825568, -0.122771351962183, 0.149774019942872, 0.40317545822151, -0.289864964219639, 0.0104582479333766, 0.0495879528771649, -0.0128977106344409, -0.102305218786961, -0.0675495373159021]', 13.72); -insert into credit_card_transaction (time, features, amount) values (157940, '[-0.0973246006848609, 0.592255028709971, -0.0593528667094778, -0.999360298185324, 1.34393876660967, 0.972694936639742, 0.598442885728545, 0.433777452146986, -0.188697472685601, -0.354892657515838, 0.750370890438897, 0.592604956044477, -0.526043600274106, 0.456610998569303, -0.236193949937416, -0.561329838420221, -0.0332325350564239, -1.32745966807357, -0.619219806360956, -0.132283383013645, -0.174622051990059, -0.280580073186863, 0.0691620640734305, -1.65217111766122, -0.666513702622147, 0.254181093996747, 0.288765340549955, 0.0693795945108346]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157941, '[1.66346628332977, 0.0161565033823855, -3.07944715005947, 0.963218641136904, 0.563971985156584, -1.90183911484916, 0.850783612408749, -0.448028586100193, 0.649786689981896, -1.53742228341976, 0.11071062410117, -0.820379309597694, -1.42190781779088, -2.48126093499951, 0.926818814135502, 0.483620732209474, 2.39707423193273, 1.25805342436726, -0.580975052675977, 0.148274702822015, 0.0344739992572245, -0.168687215772104, -0.18997868982085, -0.309280568531209, 0.248661464461843, -0.531051579455465, -0.0093241156849915, 0.0457075792705235]', 200.24); -insert into credit_card_transaction (time, features, amount) values (157941, '[0.135284262260185, 1.04293772891261, -0.416184305175535, -0.558121056674973, 0.978586839717608, -0.723364610572361, 0.991677983344454, -0.102323404973826, -0.0966378332773202, -0.854621436384597, -0.615363971553324, 0.0609620225525676, 0.329660925254782, -1.07707145820707, -0.224448681588369, 0.268308657069071, 0.391878960842543, -0.332201804502183, -0.290976293642326, 0.0405190764221664, -0.332610248695567, -0.791248653198165, 0.100974025454756, 0.507926277898433, -0.419543953441283, 0.118221122502486, 0.226584727952845, 0.0843743373490887]', 5.99); -insert into credit_card_transaction (time, features, amount) values (157942, '[1.97490836803606, 0.393454453047863, -2.41811749805605, 1.48453125920707, 0.990454022478434, -0.895208127169753, 0.683416138108996, -0.310635893075828, 0.193750090274313, -0.363908216620832, -0.72348345756227, -0.25168414960463, -0.688610488281047, -0.909783993477505, -0.264881854143427, -0.169342326113957, 0.985606320752739, 0.1300561812146, -0.394645700129386, -0.183293805900527, -0.0317886345857304, 0.0222016725534007, -0.0289695944596609, 0.46938804748557, 0.470085849727597, -0.517057395486755, -0.010272556184309, -0.018587905753234]', 40.31); -insert into credit_card_transaction (time, features, amount) values (157942, '[1.72709379859789, -1.01136616711475, -0.747801514904899, -0.797741731916275, -0.633602209930809, -0.19572117697175, -0.424757716464845, 0.0378939284983705, 1.14748749498058, -0.359052658044124, 1.19424267713631, 1.52570547620699, 0.56033600530047, 0.081696641711565, 0.165045661037726, 0.265515219958242, -0.600558439255539, -0.0876576340650845, 0.583289876599488, 0.180549874235881, -0.11807198142173, -0.562324397426176, 0.333897501956626, 0.731700219345021, -0.700264284981191, 0.219022163514518, -0.0703824020252954, -0.0248764219847886]', 149.0); -insert into credit_card_transaction (time, features, amount) values (157943, '[2.06256465300189, -0.113800312255569, -1.07906987892629, 0.426818207976473, -0.229405431683488, -1.24121665746299, 0.121577002191013, -0.283253521750122, 0.67995808293897, 0.100613207746825, -0.88964623228307, -0.046501348752039, -0.855279289386214, 0.458389062081293, 0.139934344239305, -0.0648617785902098, -0.232415432788744, -0.760129372296675, 0.149218311915294, -0.285130677852012, -0.29971944138635, -0.772174932416073, 0.353041343265542, 0.021145176792245, -0.330326371385632, 0.198543551712851, -0.0765679942228843, -0.0619574687154276]', 0.99); -insert into credit_card_transaction (time, features, amount) values (157943, '[-1.00298903988335, 0.448279245453895, 0.363189892687094, -1.11913961953647, 0.0746410757383499, 0.826992641139967, 0.225250396939471, 0.195542176646352, -0.625701615546153, 0.337394336729985, -0.569133572553786, 0.854696114843583, 0.50249519787009, -0.451760679167143, -2.41962636921048, -2.35598949395017, 0.159175299773122, 1.26834020851451, 0.899528515021976, -0.601018693779465, -0.594246112531821, -1.02125511451609, -0.157182992757536, 0.0687629632825386, -0.106747921894385, -0.525962391932538, -0.62686298493347, -0.139486810535574]', 41.47); -insert into credit_card_transaction (time, features, amount) values (157943, '[2.035978765894, -0.139826291843228, -1.17926292158945, 0.477305222606146, -0.387395038548044, -1.56998722096494, 0.114790812664978, -0.292384620741237, 0.872958808373716, 0.0659956478481336, -0.61968559757071, -0.620533016547673, -2.03117327131294, 0.920031668107667, 0.979279036220855, -0.300974116881926, -0.181015951699458, -0.0409106241044171, -0.445349442843656, -0.396402736873195, 0.254432267665787, 0.810429066219608, 0.0825417299561031, 0.382230677710144, 0.129997938573399, -0.124265498722336, -0.0289474352578498, -0.0594777282540789]', 0.85); -insert into credit_card_transaction (time, features, amount) values (157944, '[0.788862936884592, -3.04565148607129, -3.39551671570616, -0.482369484962375, -0.598364148176146, -1.12007271042563, 1.3323266198968, -0.658607050266915, -1.19469017018191, 0.806631125091535, 0.29598207068673, -0.304522907977219, -1.19973554188776, 1.27035457607765, -0.725079557234848, -1.85953981174207, 0.0565422537298613, 1.28198069724227, -0.363226343805397, 0.862955734283772, 0.351615251353681, -0.16012130109623, -0.760862009229204, -0.284160038152073, 0.0445157762607068, 1.56899718527254, -0.322092913734916, 0.0135365458158489]', 767.42); -insert into credit_card_transaction (time, features, amount) values (157944, '[2.2247339060952, -0.547757734233112, -2.1876093230173, -1.08099387281946, 0.158683403528739, -1.28431658845409, 0.223246873894394, -0.494699838214966, -1.26559358718774, 1.08394834699888, 0.828088341186577, 0.108196337468257, 0.38558685467575, 0.480652090502045, -0.784113081226796, 0.724452198781507, -0.0539360213942737, -1.13092079134102, 1.08075385437449, 0.0269009463208562, 0.388756782939088, 1.08279926971293, -0.14894357746658, -0.330636426748462, 0.476938941938762, 0.0812935262547588, -0.0842732720707869, -0.0911736507510116]', 31.0); -insert into credit_card_transaction (time, features, amount) values (157944, '[0.105594051612785, 0.703077089454517, -0.328690847034737, -0.682187079645388, -0.0861378796993685, -0.313565198905864, -0.183136736480975, 0.628059185903104, 0.386986591404143, -1.29363774431946, 0.900224828758362, 0.763906945607677, -0.210321236195683, -0.893366097248943, -0.407593744762373, 1.02207620774566, 0.188579028076001, 0.964624918268661, -0.19199331175244, -0.24644719675246, -0.0603887340285353, -0.293264608984256, 0.406177975164764, 0.612798137079515, -1.20682641480751, -0.507086803089229, -0.0384005111085055, -0.005160054617516]', 19.95); -insert into credit_card_transaction (time, features, amount) values (157944, '[2.15882107276873, 0.0672033902971921, -2.46745610957006, -0.286997913078949, 0.987287139411816, -0.925136528460553, 0.704506589363936, -0.419539556456763, -0.0060082426456556, 0.188074732557845, 0.186389684363328, 0.679733592925371, 0.120249946394557, 0.925744525543234, -0.269037696793083, -0.158688303474839, -0.879099015902365, 0.261972000266964, 0.776480272122734, -0.190316941159601, 0.135103021022454, 0.513434259404438, -0.183041943693169, -0.973979138027272, 0.548543844484155, 0.283543870034046, -0.0905307651193947, -0.0987909008606479]', 4.99); -insert into credit_card_transaction (time, features, amount) values (157945, '[-0.378964511848937, 0.826849377938675, -0.683916714340929, -1.74996169087068, 1.85603070551767, -0.483341574532047, 1.66067194888337, -0.170798784997141, -0.778342401148782, -0.81830346188037, -0.011086770877865, -0.139930258272346, -0.971479480849696, 0.991653123975052, -0.829308733069321, -0.0352480560805225, -0.994535364203421, 0.354237020103077, -0.0074373443191504, -0.148893695903613, 0.231692108956715, 0.536859567938602, -0.475605140891819, -0.0847553463209244, 0.536033739382578, 0.130203141173249, 0.012593976191889, 0.102923599818434]', 24.6); -insert into credit_card_transaction (time, features, amount) values (157945, '[-0.313217955594952, 0.73747532025499, 0.45966750648723, -0.340453267413719, 0.59865698394617, -0.956593916617101, 1.02301582668903, -0.300513051001248, -0.274660334685805, -0.434122820760681, -1.04733175980579, 0.0321632366816343, 0.114594309367895, 0.172399395131392, -0.11931600673934, -0.294355305389584, -0.270491634474764, -0.610391943020039, 0.585111184091816, -0.109356005005994, -0.171266819503274, -0.443359488337592, 0.0140958882189854, -0.0958245961127248, -0.77365117926379, 0.179071073955915, 0.0205661989546631, 0.179934830072784]', 26.99); -insert into credit_card_transaction (time, features, amount) values (157946, '[2.10658433499552, -0.899434286531931, -0.877984999888084, -1.03265077789218, -0.724032863863578, -0.602462192582267, -0.672341208515899, -0.0639997775455318, -0.482232422855861, 0.919249073841108, 0.848649182371891, 0.0143281499956217, -0.21296551615959, 0.116553905808525, -0.305879426040542, 1.41899864306025, -0.149151050417918, -1.31387141470207, 1.0914498227478, 0.0055989985215785, -0.209032647860257, -0.774348324618356, 0.423174130265085, -0.466670353837505, -0.579679277076974, -0.684108963916703, -0.02103524243581, -0.0543011098382413]', 37.47); -insert into credit_card_transaction (time, features, amount) values (157947, '[-0.886016715016289, 1.37676521094932, -0.967773147172531, -0.904033884025408, 0.322858772695137, -0.269374647688134, 0.132164386455579, 0.902942499970542, -0.356171419899533, -0.38480796604756, -0.393523952634104, 0.764554241551988, 0.0866108210986516, 0.845551573490893, -1.02410273463972, 0.578351120336471, -0.640543464134904, 0.0717209241285589, 0.481366328710058, -0.0927208518264027, -0.21618508964891, -0.687300522260755, 0.0449990537437834, -1.1109991324545, -0.305811756696405, 0.198852461770972, 0.106255680250153, -0.0027566255583733]', 8.99); -insert into credit_card_transaction (time, features, amount) values (157947, '[-3.04079644739058, -2.236770540545, 0.221671143534587, -0.0223217929811176, 3.36689327699981, -1.52448292942163, 1.65245264676324, -1.70586190070209, 1.07314411119735, 0.794209586086788, -0.168956074815494, -0.547423030918042, 0.341870228912209, -2.44462270380443, 0.265810903169252, 0.133944121257501, -0.376111227882183, -0.436333649630669, 0.474778301666447, -2.0942098833859, -1.27759556866483, -0.195109489005391, 1.68154120174616, 0.557845376761826, -0.156721250881129, 0.078611137865343, -0.258690439189911, -1.45710991217636]', 1.79); -insert into credit_card_transaction (time, features, amount) values (157947, '[1.8607942516299, -0.540762000644369, -1.78069408615946, 0.476085632546504, 2.06270874946893, 4.16965961371771, -0.845752554916739, 1.07479626766169, 1.01977291183612, -0.0071215774271098, -0.541614402276259, 0.746139305286182, -0.370388649394624, -0.0621618996325374, -0.792569331100199, -0.494367868934238, -0.133430100928321, -0.999469298942959, 0.0775175617555802, -0.153063237494011, -0.507833864657946, -1.35164933118721, 0.450330143050021, 0.618057630715561, -0.293384462976927, -1.08770027024535, 0.0680708084576619, -0.0313558716761439]', 38.78); -insert into credit_card_transaction (time, features, amount) values (157948, '[2.09948742710708, -0.0723304809880295, -2.08452148675059, -0.520152956159295, 0.596570568297551, -1.02271375857664, 0.512217819561838, -0.354910915775572, -0.216298732010906, 0.271063819155825, 1.24351245140305, 0.984810216881798, 0.191941620162796, 0.817835823376287, -0.312040765470398, -0.160812422555638, -0.439005920473822, -0.458838054389003, 0.412550065172733, -0.125723367880543, 0.109359660080548, 0.348307565097075, 0.095340788520112, 0.815200867628221, 0.05608979192927, 1.29720130956434, -0.176303261775073, -0.0936412265282741]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157948, '[-0.558444816726526, 1.02516109411149, 0.11585061564408, -0.641842931385032, 0.402920192709823, -1.03338293601231, 1.0365551230057, -0.314423869004569, 0.283755428912727, 0.113365296509313, -0.805620334099738, 0.16398871231851, 0.0857674997778871, -0.107885804488577, -0.308866429747884, -0.226577245095246, -0.419994285110336, -0.883678609482764, -0.133281839548949, -0.0958132770093471, -0.279363621856357, -0.493078638216871, 0.153631437270877, -0.0214390210804245, -0.54254505191404, 0.0544298113000256, -0.597997409807539, -0.406484082294649]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157949, '[1.77401029907377, -0.964541473301166, 0.471470389702876, 1.66119607871983, -1.01594689476908, 1.26782693096402, -1.35782671154769, 0.408293153893965, 2.4357518644739, -0.221120039690317, -2.76182225870542, 0.63773448994186, 0.407277779996956, -1.36646829462487, -1.55528102709713, 0.0716012595424843, -0.433852312127229, 0.493508941781845, 0.216290013899203, -0.0823922580907394, 0.0957696866487306, 0.727275421454148, -0.0727016677224375, -0.965205684093965, -0.0064972251142685, -0.420145574707014, 0.122265786307215, -0.0150236979468001]', 79.5); -insert into credit_card_transaction (time, features, amount) values (157950, '[-0.423520377918017, 0.827751763827349, 0.948301268576159, -1.20928507363995, 0.320333829310019, -0.0444008599529219, 0.406071163704863, 0.0098824855236115, 0.712587553372695, -0.621659039475971, -1.74973522159798, 0.118643627542081, 0.764636326825837, -0.474384134273564, 0.320929265933132, 0.479082881079385, -1.01556340238723, 0.0956355901290112, 0.216058885550763, 0.0422920732578327, -0.236627688890152, -0.581785389944286, -0.161793290786122, -1.02145993254389, -0.0358385006275781, -0.220274198166634, -0.0008060829022785, 0.0663980010078263]', 0.77); -insert into credit_card_transaction (time, features, amount) values (157951, '[0.496037026629713, 0.65944480111628, 0.22668038602162, 1.05837304294214, -0.162900031337561, 0.631368206594806, -0.757595651202159, -1.48091716673546, -0.236372645807891, 0.522093629394776, 0.961021609917019, 0.337796040866756, -0.808596924758335, 0.803022455486797, 1.03773155684655, -0.780132452285254, 0.547147392967212, 0.438028027649036, 2.62941151283694, -0.131786434079001, 1.55033451739738, -0.349278574787741, -0.0217778029763379, 0.740996443917679, 0.274548606407144, 0.915365458808303, 0.233196440969967, 0.260685844148833]', 1.18); -insert into credit_card_transaction (time, features, amount) values (157952, '[0.0417179464419774, 0.991665811300549, -0.315676676833978, -0.589918417564405, 1.1703273966254, -0.748375845411038, 1.07304584806938, -0.169409496686861, -0.274405125870813, -1.0565427914781, -0.735179755577625, -0.0076517233896974, 0.25461376404232, -0.959900525227061, -0.32929290469182, 0.198832868820715, 0.385929856406705, -0.266800149892477, -0.190746182526778, -0.10223891267919, -0.194172906451181, -0.488502645051792, 0.158430944209381, 0.517364179975973, -1.17174831563608, -0.0031964190520522, 0.193261241754412, 0.267822880912105]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157953, '[2.06406885643051, 0.150635885588552, -1.69463987261267, 0.415752070586226, 0.436513734322261, -0.809437405166869, 0.172824186322012, -0.213169110813451, 0.488478219491403, -0.387253513691962, -0.493541758935384, 0.182626731862901, 0.0717446747231818, -0.840345400819593, 0.249198566229186, 0.250233971047554, 0.537588965601217, -0.406189945618679, -0.0281015722307661, -0.161561069166073, -0.356875855235615, -0.915522786246576, 0.349077140294913, 0.508984914116324, -0.275886527740446, 0.175238875565013, -0.0594325449988992, -0.030700485371586]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157953, '[0.714940572199113, -3.14668263623907, -1.34434487660362, 0.217049747142615, -1.56005133529814, 0.301011658371958, -0.0488747600953272, 0.0439457304276764, 0.126920201375223, 0.465165165688082, 0.321647290647655, 0.194042720768047, -1.35226912355935, 0.463556765165538, -0.545864333206366, -1.35919762120867, -0.107326869757454, 1.50118620927985, -0.496764743355698, 0.687190515731497, -0.302260626621068, -1.92147881169346, -0.0435509802378034, 0.590779965747819, -0.870201179977087, -0.867746078635534, -0.0945408734752064, 0.0839035920931845]', 700.4); -insert into credit_card_transaction (time, features, amount) values (157954, '[0.155418307516308, 1.06706434723187, -0.48481027577188, -0.595345271948942, 1.05995324376574, -0.69618112444826, 1.02719156490691, -0.134820316180118, -0.130704881846982, -0.855978375030594, -0.773260307513653, 0.148318348731243, 0.679235782005899, -1.15591524647323, -0.293050756379983, 0.36486091932644, 0.252055949109237, -0.222681079951058, -0.153624697657035, 0.0749240763359663, -0.346126150982433, -0.8223736016878, 0.0705879624032651, 0.386768119529358, -0.369429957544625, 0.123170670555335, 0.224879452927972, 0.083855946494632]', 6.99); -insert into credit_card_transaction (time, features, amount) values (157954, '[-0.196502757734091, 1.16898915678427, -0.849597998100463, -0.509445858436981, 0.511294864528861, -0.85440863008484, 0.541155971886057, 0.399803873512338, -0.0019894003933657, -1.02216226206132, -1.17181220211394, -0.726982413256965, -1.28736000983712, -0.433439881473624, -0.118932597226696, 0.551503052980536, 0.572686532779407, 0.0294828625111178, -0.184168060374324, -0.160983721261086, -0.318611723597352, -0.979355941307693, 0.168741647778025, 0.433562019792299, -0.425941530016154, 0.125898939143942, 0.0856947812225393, 0.0178164666878912]', 10.06); -insert into credit_card_transaction (time, features, amount) values (157956, '[0.0377772803522289, 0.70962218327457, 0.0864418754332224, -0.800975092723469, 0.569095784878146, -0.557730600670006, 0.809661890486252, 0.0474975725899271, -0.064148208054088, -0.201476531495999, 0.112354291836447, -0.0606904076434513, -1.36287933759573, 0.553051806748703, -0.918675698124949, 0.306447342008864, -0.754113779140093, 0.0703189871241063, 0.394262288253137, -0.101714862122309, -0.256401448714307, -0.65855332774574, 0.0135945303269278, -0.537100794157204, -0.502521253462503, 0.154945695942483, 0.233993514328793, 0.0793502352551405]', 3.08); -insert into credit_card_transaction (time, features, amount) values (157957, '[-1.1533613827591, 0.932987101708906, 0.48045437717297, -0.870664604454561, 1.15532047793528, -0.272714026478393, 0.653182141793233, 0.341698259938587, -0.832812406520562, -1.1585319859078, -1.60089314184079, 0.237305386151913, 0.896601615072072, 0.30486901147015, -0.198617376087359, 0.160272508089655, -0.431583996078477, -0.464461210289953, 0.497237386445524, 0.035288240450506, -0.258800648208347, -1.00785916201138, -0.330518975359237, 0.0592199476554792, 0.652257881414818, 0.33950538883829, -0.162612073504426, -0.0771535111803993]', 3.59); -insert into credit_card_transaction (time, features, amount) values (157957, '[2.2180935602798, -1.53035153822686, -0.317128421398909, -1.46561865678762, -1.75563905259586, -0.690470025280416, -1.40183164203569, -0.13050866808013, -0.892344207175662, 1.5027266981516, -1.10143004252507, -0.737906927183276, 0.53962226703376, -0.649660619510824, 0.0979250652193446, -0.17015743484654, 0.313826503900443, -0.0380751087507016, -0.133131167343187, -0.377336804247485, -0.351987830707386, -0.578394351495228, 0.405817594026537, -0.173512728876944, -0.591207504129514, -0.438335884957371, 0.0377173735606557, -0.0308092751175787]', 40.0); -insert into credit_card_transaction (time, features, amount) values (157957, '[-1.82881711077753, 2.11312659067489, -2.70565184336161, -0.54153561530829, 0.731924581784389, -0.374141156646679, 0.15535042930654, 0.927011680491262, -0.527661852500732, -0.551689726799319, -0.107838426519603, 0.934997174046555, 0.567860760022302, -0.265117418402258, -1.45447591940341, 0.591221396737469, 0.564917860578733, 0.658942234065919, 0.383968912323998, -0.478203261993345, 0.130738242552403, -0.018221886983316, -0.0412233035868095, -0.199102001432269, 0.132807536795369, 0.240592185964573, -1.07951201656348, -0.106838544641023]', 14.95); -insert into credit_card_transaction (time, features, amount) values (157958, '[-4.02657350667, -5.13560536462968, -1.5864618861875, 0.0941755372627182, 0.974338929331611, -0.966912739299797, 0.244006478523435, 0.528526651618191, -1.30475522306458, -0.0350002009185114, -0.385043193117391, -0.0986670882749319, -0.317581123418741, 1.07350350509879, -0.195445048951483, -1.34910305933578, -0.329507186230072, 2.77815919288323, -0.354919578805565, 1.95093331041854, 0.780323837289314, 0.346111473754255, 1.22927528135008, 0.14114986513322, -0.151104723972879, -0.12736453442329, 0.199719304433133, -0.342208805188658]', 622.0); -insert into credit_card_transaction (time, features, amount) values (157959, '[1.91953715091255, -0.471146959708282, -0.320106645181777, 0.601097301413454, -0.835077125809063, -0.734047928354754, -0.518424895960432, -0.0957156123104241, 1.07059091091028, 0.0907413834248014, -0.868845943698411, 0.100389024563389, -0.106496000192297, 0.0037175001806409, 0.885153359040691, 0.529199247915558, -0.656365226688879, 0.16559305974002, -0.486358526050581, -0.136452357176805, 0.210846112570921, 0.652100651225731, 0.148336542646621, 0.0772832556770693, -0.312687840507206, 0.350449133613549, -0.0224136341360181, -0.0373309252509812]', 47.2); -insert into credit_card_transaction (time, features, amount) values (157960, '[-0.0167360401228981, 0.810738944735208, 0.355029310089414, -0.676065908875726, 0.440162878835009, -0.857533498939415, 0.916115351854028, -0.0736257898032115, -0.330993667562361, -0.246225940656005, 0.879015707445893, 0.932000089670094, 0.0494625929457461, 0.28743401008896, -1.12529848962295, 0.069387888935094, -0.633282014640039, -0.2996954348626, 0.169315109125263, -0.0152865792779525, -0.19921028254512, -0.431198443657408, 0.0727977822393492, 0.0741640559815099, -0.525949544897579, 0.114541701178317, 0.243445371604533, 0.0888514582812736]', 4.49); -insert into credit_card_transaction (time, features, amount) values (157961, '[-0.288430758943871, 1.1761184792378, -0.274976284059367, -0.487969202837398, 0.380054252799194, -0.996524999108536, 0.820886750713392, -0.0051980429193138, -0.266273361801721, -0.0182501803760934, 0.832854461447437, 0.846211681348274, 0.13430664824925, 0.659119532552508, -0.276540910368016, -0.25971396022472, -0.642692576994192, 0.602162377021445, 0.292947547820401, -0.0566156281481256, 0.438254825919884, 1.50260277667472, -0.121849611352243, 0.121701483434302, -0.842153712356565, -0.28523646197213, 0.0813906084501782, 0.0266894948907803]', 0.99); -insert into credit_card_transaction (time, features, amount) values (157961, '[2.09290324082901, -0.730497275359928, -1.50531614308008, -0.543655223555024, -0.269337145186302, -0.592985462827389, -0.214852690835621, -0.165536108814146, -0.817315789199893, 1.06254472540993, 0.63240086627314, 0.433252390015448, -0.338430538278368, 0.527780119751134, -0.801942781219551, -1.52964058287603, -0.186471294628776, 1.07624581460366, -0.309604254558122, -0.554345241954112, -0.465126769858491, -0.900308326429664, 0.310258392841819, 0.739283254021243, -0.262809067567763, 0.423214015772059, -0.0867210143559728, -0.0628768414644909]', 37.9); -insert into credit_card_transaction (time, features, amount) values (157961, '[1.98651690903976, -0.139920953249173, -1.22167073159544, 1.10572731956866, 0.380750700607988, 0.159883856957599, -0.121391119674426, -0.0291394706956704, 0.740649189462826, 0.204143454685721, -1.67260884543788, -0.0618065517600697, -0.033166497338101, 0.145482938341498, 0.326379639625274, 0.183373879224712, -0.756952042628467, 0.201046317285517, -0.284100890073826, -0.173399734571779, 0.120733016065792, 0.449711546875324, 0.0016483431145024, -0.0361652431070216, 0.227096215905187, -0.511281513506969, 0.0211840151418421, -0.0386575984148595]', 35.0); -insert into credit_card_transaction (time, features, amount) values (157963, '[1.92586657185659, -0.529199897825763, -0.145934081922038, 0.407499013270104, -0.852249746320965, -0.253461272631271, -0.783740706196698, 0.121908830054698, 1.04034849985091, 0.175818146958595, 0.796274705305816, 0.950495068631654, -0.235514764413005, 0.0016555673681376, -0.282653116738965, 0.441921138342107, -0.628450030537591, 0.405241925340875, -0.0812666600594878, -0.204680555384908, 0.222583252125102, 0.820361857130425, 0.171198417328548, 0.0689213514847251, -0.348035094063476, 0.549624539782602, -0.0217428139219938, -0.0568157268137682]', 11.5); -insert into credit_card_transaction (time, features, amount) values (157963, '[2.00197341186197, -0.0172307442925724, -1.64275823561917, 0.366268061048751, 0.2460725341237, -0.694711143797763, 0.0003371610921903, -0.0222232977718137, 0.437400782277952, -0.171344087115177, 1.05423556519694, 0.135601556549636, -1.4841644910807, -0.349638172636094, -0.35073834928678, 0.526481044376817, 0.372939483126367, 0.303997272438385, 0.278840412835517, -0.225970933401332, -0.312090235909307, -0.919347783750754, 0.360463204469865, 0.631000460271372, -0.364709537527224, 0.146498823595791, -0.0771886251285026, -0.0403737012696964]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157963, '[2.23329085170967, -1.69144957004062, -2.38852352523168, -2.57775518701614, 1.14357603227901, 3.44120524904476, -1.59216074049841, 0.792470005925062, -1.40654405612625, 1.58306681617355, -0.219105097606072, -0.72149325368834, 0.319497581175934, -0.199904882985085, 0.190592814035743, -0.705043949806864, 0.436370723424263, -0.28236885133011, -0.267079526457362, -0.307510351202207, -0.153174906605346, -0.0879417958761224, 0.24366905982448, 0.688319130860332, -0.138447433908701, -0.143262405698555, 0.0234166575446106, -0.0528976874640977]', 42.76); -insert into credit_card_transaction (time, features, amount) values (157963, '[2.06061496870053, -0.156284236095448, -1.09142693069339, 0.432823959876221, -0.279383963397353, -1.25404226803778, 0.0852441350379371, -0.25214813872615, 0.763319834145534, 0.116429050236064, -0.983629963233745, -0.339603746069908, -1.40631030793986, 0.568260569676601, 0.200508182190628, -0.0389018268800775, -0.200895232220781, -0.692343078840531, 0.152684097703824, -0.318815489395252, -0.305571856906352, -0.817737025228242, 0.358951935447387, 0.0060955699278855, -0.349269370803907, 0.200305251874558, -0.0803223083692439, -0.0630019181852741]', 1.79); -insert into credit_card_transaction (time, features, amount) values (157964, '[-0.683709087568444, 0.296121340959055, -0.0955113777931461, -1.2550420516208, 1.7980614388856, -1.07052776194258, 0.723038003165735, 0.0645548494880929, -0.304991075599898, -1.19891304728934, 0.864145353564404, 0.429619901952159, -0.673540572341577, -0.668428435856265, -1.6088100795599, 0.828233303204743, -0.190711716532288, 0.137954253253225, -1.12743751521058, -0.132893476778697, -0.117760205640354, -0.584333003295222, 0.20305618239447, 0.58267152100511, -0.875528720569339, -0.18218308689086, 0.103228961477245, 0.236036279574716]', 0.99); -insert into credit_card_transaction (time, features, amount) values (157964, '[2.02130568911583, -0.106107709910944, -1.20084756442329, 0.281772587584589, -0.121881897198451, -1.07775051389328, 0.0659526767523445, -0.21512396209524, 0.457800287680914, 0.1975893681161, 0.98272077547269, 0.708544100597675, -0.602225929242185, 0.774793782408752, 0.131014026070172, 0.0167631777718205, -0.70461822143883, 0.513506321629264, 0.0033918647002959, -0.274404744385071, 0.310342814099609, 1.00210823602601, 0.0063998012102415, 0.0998522895067879, 0.191878317094332, -0.125108888402155, -0.0235576952413561, -0.0680629970014868]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157964, '[1.94366108760167, 0.0703544863727542, -0.234683907704162, 1.213840155994, -0.273840024699517, -0.388226066015964, -0.298323876406533, -0.0644292612161531, 0.484245148416809, 0.185720446368747, -0.192325810062568, 0.973848991690798, 1.1882329159931, -0.0289223593377505, 0.947882302676674, 0.410145675180216, -0.755566268841414, -0.338091720088588, -0.824687681992613, -0.167115353117578, -0.102525251501971, -0.232049153569127, 0.459978035806903, 1.03121996132453, -0.423349117850612, -1.0229454956366, 0.0552017116479644, -0.0114940290400824]', 5.0); -insert into credit_card_transaction (time, features, amount) values (157965, '[0.0618368245157055, 0.4483744464616, 1.04829352135028, -0.689349628492269, 0.027718517500259, -0.139601613945344, 0.256464318295674, 0.176728361401527, 0.386447036418693, -0.666355004345517, 0.340995702239376, 0.60887760941688, -0.346742018435612, 0.0838006682968273, -0.438480531382187, 0.518189637476565, -1.00700481776491, 0.577671547860521, 0.139963577180324, -0.188523239862826, -0.0775430078048705, -0.188789911476871, 0.0603362051988515, -0.394962657111677, -0.679616108439498, -0.695610561994836, 0.102996861051272, 0.0501463876644225]', 6.95); -insert into credit_card_transaction (time, features, amount) values (157966, '[-8.20861607046392, 7.37438337575459, -7.27861422233577, -1.58731815284072, -2.54426450916029, -1.46068366809213, -2.4790315506221, 4.01317742453994, 1.67973389284029, 3.77148782546918, -0.208375008960203, 1.8976982770544, 0.349559564072912, 1.10875832305077, -0.679037513878558, 1.18956829557332, 1.49829449008219, 0.584858967553385, -0.657513312446231, 1.1255989106054, 0.0926279389971332, -0.322768577173434, 0.729107876787504, 0.0616525555932529, 0.431632698418571, 0.315398120433926, -0.317099171194962, 0.671549730637482]', 9.91); -insert into credit_card_transaction (time, features, amount) values (157966, '[2.03074519293165, -1.82421226674575, -0.842893521766777, -1.3591542575788, -1.64055091794564, -0.816550692012471, -1.0341445802757, -0.228270578295579, -1.03773647555012, 1.50661258175424, -1.10245293885893, -0.999853874525731, 0.0215815259605607, -0.378167815989221, -0.0100557220788719, -0.504199364188025, 0.532745175777142, -0.0375582081079738, -0.271434439059458, -0.211618019875968, -0.0841071148614551, -0.0147917204142604, 0.144424327215541, -0.109219880883719, -0.321099113164504, -0.182734933012596, -0.0028958577287816, -0.0261790050932126]', 144.4); -insert into credit_card_transaction (time, features, amount) values (157967, '[-1.3784842823001, 0.836253834230049, 1.63717317041987, -1.20071491939441, 0.527644893227459, -1.77579789806105, 1.25498691340279, -0.354095145686627, -0.402204168980457, -1.02661290907531, -0.153022395433992, 0.446609211033295, -0.0676794093851433, 0.0222814426804166, -0.969469984042873, 0.0121020226413929, -0.43827060073736, -1.19207121977984, -1.32918557326521, -0.322040407099317, -0.22033880481446, -0.734717698602182, -0.180544963056035, 0.932185359473056, 0.535121113540519, 0.0597898872485901, -0.333964586234657, 0.0766867456795813]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157968, '[-1.24653037207163, 1.61597217458955, 0.244828166687947, -1.13583620890234, 0.290600998547033, -0.277997466652597, 0.208438651740384, 0.437277772839563, 0.553872373950403, -1.11505185844921, -1.53997855517165, 0.0067690854324076, 0.740821830023757, -1.42730475314938, 0.413160125865243, 0.91978816710802, 0.115996718396721, 0.686650231945729, 0.0798408241824044, 0.12430123539442, -0.264394638855443, -0.719232726523527, -0.166029629130133, -1.12622350196224, -0.0570402514170426, -0.217427583838379, 0.0832706734666287, 0.209989193164973]', 0.77); -insert into credit_card_transaction (time, features, amount) values (157968, '[-2.80578689320652, 3.18227555712877, -1.47614502675081, -1.53660983322885, 0.141134715594812, -2.47624569791166, 1.81158285016513, -0.621928403233836, 2.20391805995782, 3.65204796924155, 0.156020230434811, -0.219408848739783, -1.21050585621525, -0.225078188425433, 0.0632504934267331, -1.27663910838827, -0.278438787722901, -0.82023297146283, -0.825669868224927, 1.50573809404652, -0.168393595649716, 0.832980234782807, -0.0583151977485832, 0.91537600363269, 0.107405315360701, 0.0036909808853293, 1.02379478709671, 0.292022168207763]', 0.77); -insert into credit_card_transaction (time, features, amount) values (157968, '[-3.32785612880507, 3.74284510416295, 0.102989548867145, 3.97111691483664, -0.728104965006497, 3.79597592120345, -4.29874619762918, -8.58254391834837, -1.09042034656957, 1.79912538035272, -0.594137276188149, -0.15270804588819, -1.85649493482985, 1.23201794284558, 0.0014976443443785, 0.765055733710974, 0.656003827904937, 1.53779613655893, 1.07317578536359, -0.704741094863117, 5.90984726047862, -1.15689810111434, 1.16848513492925, 0.0298377843500019, -0.567869957203603, 0.468192279368689, 0.484931877775832, 0.294533594512196]', 7.75); -insert into credit_card_transaction (time, features, amount) values (157969, '[1.83888766917069, -0.0764128151632818, -1.91552240711566, 0.589749279799011, 0.251281511505436, -1.30615268042018, 0.474585548635681, -0.441664967747948, 0.447131099126887, -0.601661262658675, -0.253432849433953, 0.493651440339286, 0.930408803323264, -0.988655718223063, 0.883178547264484, 0.19578891969138, 0.42828357631568, 0.420531050493752, -0.503419484606504, 0.0850612676544874, 0.264941175479925, 0.734106150308426, -0.145991179407594, -0.212111048038646, 0.247577074495147, -0.103751822866401, -0.0138415781165598, -0.0091967906204431]', 117.54); -insert into credit_card_transaction (time, features, amount) values (157970, '[1.99906299189977, -0.182999504001492, -1.41118544263677, 0.17129269748625, 0.142312903104677, -0.618549789669981, 0.0267283870013384, -0.115330456666407, 0.45939086039813, 0.183746195372574, 0.898934223749624, 0.604277946676819, -0.650047353156469, 0.777154534868393, 0.191082906139417, 0.0677892325764169, -0.74495448692418, 0.582858789277018, 0.0318782089146311, -0.208511029149992, 0.311209711200393, 0.917589129172324, 0.019334819169837, 0.783955514081871, 0.208751363202549, -0.157442177067247, -0.0327373137870122, -0.0584867539139868]', 19.95); -insert into credit_card_transaction (time, features, amount) values (157973, '[-0.964697326988786, 1.41240741952048, 0.317744622511331, 0.640112635012405, 0.672533533660404, 0.0832064691547012, 0.922455970627585, -0.103988682643461, 0.577303800940569, 1.43903553953967, 0.0691064181769118, 0.194498194238766, -0.652630172459585, -0.217654061733043, -0.993600691000042, -0.800421001015771, -0.448893335028301, 0.601793037202568, 1.1559904295511, 0.523317155288731, -0.0308664772711088, 0.888297928902851, -0.366397755654084, -0.489442935283755, 0.0277478050148657, -0.401094304549291, 0.17191200784603, -0.297837266020055]', 5.0); -insert into credit_card_transaction (time, features, amount) values (157973, '[0.896239917425564, -2.3524076549197, -1.09776116060742, -0.0536660982707264, -1.32098979070395, -0.512299813897651, 0.277680586957759, -0.169480141078878, 1.11208257624998, -0.471410049385005, 0.982463638752311, 1.4066503863401, 0.0216716761713687, 0.191734635425939, -0.595136392285055, 0.129464931569796, -0.32928816935155, -0.313355953724628, 0.691015763444587, 0.974251588541518, -0.0388073775816171, -1.2387639008878, -0.0153672863972512, 0.112121008085071, -0.916627170365452, 0.308516962925865, -0.17090229324426, 0.0369939533772284]', 572.84); -insert into credit_card_transaction (time, features, amount) values (157973, '[-0.773645036856289, 1.14187839052569, -2.00940865038627, -1.87509281164653, 3.26322750501122, 3.13732617124828, 0.876309721177129, 0.375236025125563, 0.765330580112903, 0.921625349615873, 0.48336524899578, -0.597282768638666, -0.369529597464575, -1.48685750262332, 0.870007051112978, 0.117532727040786, -0.0878655833859465, 0.192498517247581, -0.899118828825117, 0.552102325160159, -0.0467304889982395, 0.724459417401952, -0.192384890643433, 0.651937193841015, -0.270887785737543, 0.493429791322173, -0.25446941428238, -0.599785151013234]', 28.21); -insert into credit_card_transaction (time, features, amount) values (157973, '[2.03536273310752, -0.943719083880541, -1.6543236034095, -1.12360489314325, -0.369077687889891, -0.896880377877599, -0.0853312327084431, -0.306179388538316, -0.967566809935332, 0.998889513736933, 0.666910758864691, 0.549159250972956, 0.385138853715296, 0.546512740454178, -0.18584784488346, -1.20046824382935, -0.422553520043883, 0.980838397363322, -0.212556147899113, -0.385025651205767, -0.473531876927823, -1.07479683932682, 0.25306790939445, -0.455122496945265, -0.48017084553966, 1.02592757733018, -0.137747205086342, -0.070883453110854]', 93.0); -insert into credit_card_transaction (time, features, amount) values (157973, '[-1.2231026879908, 0.747107929053307, 2.80214650407355, 3.99627623969058, 0.357225429950914, 2.1725594914511, -0.390945064091217, 0.405706616293283, -0.491755197952139, 2.65627889114601, -0.186385481189706, -1.60905952691208, -1.63618327367767, -0.484837363250144, 1.12867741863864, 0.878685400346291, -0.749518725460162, 1.79198609953037, 1.39285173420542, 0.50646901803822, -0.0762430850511763, 0.611070310549528, -0.0051384965965158, 0.0282711363089857, 0.152619508290004, 0.531819296340161, 0.391843575457727, -0.233223744015689]', 18.15); -insert into credit_card_transaction (time, features, amount) values (157974, '[-0.688928417572515, 0.52099901390324, 0.395567619354803, -0.331300364117948, 1.39362783310617, -0.622543630287477, 0.565202622116405, 0.130661531453614, -0.61684536408945, -0.878499649972557, 0.997136930107938, -0.085437364104921, -1.21433079640909, -0.449622649788725, -0.404991670390028, 0.208240284489818, 0.549792261933334, 0.413011220123731, 0.658948663453891, 0.0734436553507974, -0.205214246670432, -0.793544288280305, -0.0106664964016563, 0.588260901841865, -0.245564503640268, 0.243204839633853, 0.0371667603083719, 0.146906238567966]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157976, '[2.05255860617653, -0.146485271082057, -1.0913619403651, 0.42071438983787, -0.220140821205693, -1.15780974843096, 0.0882087281638287, -0.240576393541553, 0.722779520810923, 0.100263684633919, -0.89650587948911, -0.183419730186877, -1.1470175075041, 0.521322003721498, 0.219834254413959, -0.107161052887001, -0.1627070902376, -0.810463735724028, 0.0823848993445511, -0.308032392564461, -0.297267263550314, -0.774323258046133, 0.361433079793668, -0.0462712968190888, -0.354289984806009, 0.205107453833142, -0.0754499268192803, -0.0630899877827614]', 1.79); -insert into credit_card_transaction (time, features, amount) values (157976, '[1.95902759736612, -0.133766212551384, -0.869202857218849, 0.111340955201187, -0.157188983100066, -0.197125238276084, -0.57122878629977, 0.13833885858806, 0.949763158412604, -0.563658170249103, 1.40817056111254, 1.15663758717233, 0.321211851585402, -1.17641972357424, 0.153946566289958, 0.747368682978227, 0.220958829236181, 0.652766691730082, 0.0670623633560689, -0.129696144276046, -0.20708937652179, -0.471969775505063, 0.403459391312989, 0.581554287808335, -0.516300356368384, -0.334192792482777, 0.0221991324256461, -0.0126040789588429]', 0.77); -insert into credit_card_transaction (time, features, amount) values (157976, '[-2.66383205908704, 0.174647496723316, 2.11245438541986, 4.51203303814439, -0.520728886617058, 1.50565562360304, 0.0284231801402955, 0.368720147951529, -0.260473043667203, 2.52234222111307, -1.76959789252947, -1.66403270284149, -0.564439767882363, -0.661016234185204, 1.78953233942014, 0.869842683271945, -0.42794206813361, 1.1634192063946, 1.13521894413423, -0.0003465240527101, -0.322476804007028, 0.670453093518308, 0.502409326852764, -0.601407228296095, 0.428083813958631, 0.628127647596657, 0.661857951182953, -0.275026934135342]', 174.6); -insert into credit_card_transaction (time, features, amount) values (157977, '[-0.745517800584415, 1.48280525331285, -0.987091490228214, -1.28141472894969, 0.865436916990643, -1.5046921777319, 1.4916251334676, -0.235320134468621, 0.103140170151472, 0.647988136404069, 0.757329236023915, -0.0617024406297733, -1.71943731917457, 0.984448574219067, -0.649475788029373, -0.555900121039057, -0.513164650122404, 0.109545096436624, -0.0303703315452879, 0.218888229966171, 0.203379493314934, 0.906310389151378, -0.182634344980966, 0.0231816475550947, -0.253059055927106, 0.0871014257313095, 0.700361236264471, 0.442312947133834]', 0.15); -insert into credit_card_transaction (time, features, amount) values (157977, '[-2.99301653467851, 2.29490924392415, 1.98918498607115, 3.83052499870375, -0.392687116576311, 1.50772049443603, -0.483294472730568, 0.434057551711502, 0.924517829992485, 4.62133005658301, -1.22245913790506, -1.47827211800812, -0.622738361654396, -1.21444578536491, 1.80050666717643, 0.415035298030138, -0.383297527182699, 0.900670634466261, 0.687245561219846, 1.38455285253594, -0.310005896107521, 0.425598385458306, -0.531065600998571, 0.543647263529668, 0.36163297872204, 0.499858522066366, 0.789114965482187, 0.0533434675252892]', 18.15); -insert into credit_card_transaction (time, features, amount) values (157977, '[-0.661593711822078, 0.652793423475606, 0.7673908873748, -0.606041778157361, 1.40739059966363, -1.2556945740505, 1.96355758509504, -2.56736973479898, 1.16884489287547, 0.677118757460659, 0.406201562086944, -0.896522251183681, -0.841017956570658, -2.16037242723745, 0.816026837925164, -0.43528020829686, -0.0744183346191714, 0.26507889395609, -0.810455329336394, -0.129294645207376, 0.73764004562111, 0.681506765324107, -0.314302195307962, 0.302195877665518, 0.281824623896969, -0.339694125950599, -1.70572620737748, -1.09107489559943]', 8.6); -insert into credit_card_transaction (time, features, amount) values (157977, '[-0.890719367974028, 1.37084429023364, -0.296669602897132, -0.993757582426446, 0.368370299867898, -0.686870802913754, 0.766229821121271, 0.0826705604294247, 0.685632517923621, 1.03123275061918, 0.290090616041666, 0.0360645619834591, -1.31930082364347, 0.264438250192654, -0.86949543196661, 0.195337341623331, -0.7624748554422, -0.0283915466226299, 0.242330694479769, 0.410957294622519, -0.371288575262615, -0.724627709889998, 0.0907228117984926, -0.466184143965356, -0.29930323241112, 0.16799226402743, 0.64474601567674, 0.349551873089223]', 2.69); -insert into credit_card_transaction (time, features, amount) values (157977, '[1.82325499195386, 0.19622352726535, -0.11935235707208, 3.62620320746891, 0.573495535185885, 1.79681532344717, -0.501690293526354, 0.394622872162896, -0.459783497446441, 1.29552595513065, -0.446200520787739, 1.36698946963065, 1.51713164579045, -0.672789746850831, -2.62440287030406, 1.00977208070635, -1.05743830841439, -0.272972863692372, -0.521953696778539, -0.106977397750954, -0.369304399521242, -0.889433673932337, 0.327546338061398, -0.248345886348167, -0.348104763227304, -0.412827696020526, 0.0207524755124976, -0.0336437819003199]', 26.47); -insert into credit_card_transaction (time, features, amount) values (157978, '[-0.666067754181954, 1.18819791522328, 0.311066547972187, -0.374017287707467, 0.516044074148531, -0.301691499397619, 0.80992397446302, 0.0482586188691898, -0.156417828254936, 0.28019302509348, 0.6889287221767, -0.406857836977868, -1.70949565200734, 0.847823975052059, 0.58010173439227, -0.436476684801031, -0.319676483862379, 0.929367317338259, 1.07758737140569, 0.191012188096813, 0.277619435010711, 0.90350995007144, -0.375449413549478, 0.7636470160597, 0.316156815676701, 0.0403100759112164, 0.318440459403248, 0.241267991241012]', 7.99); -insert into credit_card_transaction (time, features, amount) values (157978, '[-0.462584526224977, 0.74980261149664, -1.01508453157879, 0.0471592679975883, 0.918350659413925, -0.846999475015829, 0.4355738020709, 0.16722179466712, -0.0780622681935225, -1.08599154534344, -1.43280450884057, 0.250677382842168, 0.782693910771039, -1.1629523038356, -0.76490146091398, -0.0950920608610851, 0.89819571376613, 0.239944985049191, 0.386180275585579, -0.161847461013527, 0.202388589803986, 0.753929336889137, -0.0711966664037763, -0.635777010745609, -0.287629921024362, 0.704843516717623, -0.140024528649442, 0.0270525121906098]', 5.69); -insert into credit_card_transaction (time, features, amount) values (157979, '[2.00442329518763, -0.103757942606191, -2.02206078759673, 0.493910355657102, 0.296153933286302, -1.53910924067694, 0.740031396852728, -0.486761152292382, 0.535016096820338, 0.001424060861036, -0.985286725012501, -0.213285685381904, -1.32059707246963, 0.89669973267183, -0.0331943825254506, -0.894092036588173, 0.0210925545466615, -0.516037751233991, 0.0806101229238717, -0.258495155808709, 0.152985422284505, 0.529285106239231, -0.0977007381687096, 0.0091200322090107, 0.490317362656807, -0.0664916908535324, -0.0655705897062785, -0.0693121098769825]', 50.0); -insert into credit_card_transaction (time, features, amount) values (157979, '[1.92666675492338, -0.195582478342884, -1.17826293848127, 0.238473764956231, 0.508606096230559, 0.350103136695233, -0.0557243483417705, 0.107414532314776, 0.505204557931785, -0.0752001297508144, -0.0480394705165628, 0.794246688733908, 0.199331878944025, 0.326012387379621, 0.840272043822156, -1.04344266830493, 0.580458884801121, -2.32702012885371, -0.992919471009605, -0.312833762940224, -0.201582849105492, -0.324585991677623, 0.425714010351967, -1.02830422375004, -0.519722026843405, 0.295394250122115, -0.0162052054596585, -0.0711881360104416]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157980, '[-1.61297691007714, 1.56104420562487, 0.748769507905986, -0.993980974046741, 0.126316760589102, 0.283377439558068, -0.162779713371469, -0.913077734158791, -0.458297961851394, -0.627040582657327, 0.46751348110298, 0.312584660367103, -1.09484198169594, 0.758289258416562, -0.617531945652306, 0.287521058187268, -0.223316086482307, 0.29843455483529, 0.131557372829886, -0.391505520770848, 1.53766889713242, -0.57742478319376, -0.118904999269506, 0.686669242741798, 0.679646169784791, 0.557079975757182, 0.145107669563328, 0.051238754166178]', 3.59); -insert into credit_card_transaction (time, features, amount) values (157980, '[1.94575336427642, -1.10746611063971, -0.38161402794336, -0.266821928565136, -1.32610828898409, -0.749354577663574, -0.745672665731535, -0.144669424091363, -0.0129254778314704, 0.773805669913565, -1.01501425895293, 0.0320462724809392, 0.260857726053945, -0.15606274123976, 0.388821724832114, -1.07884244765892, -0.224936714930868, 0.871012493723425, -0.827646651099286, -0.430201391688745, -0.573028442322667, -1.28328081191214, 0.45058302463433, -0.0089054532443411, -0.796885802682008, 0.222794674116536, -0.0309006496499365, -0.0237329612937065]', 96.0); -insert into credit_card_transaction (time, features, amount) values (157980, '[1.87184930947792, -0.259915838579638, -2.54104246908075, 0.177836240074178, 0.778426112810201, -0.535660063214527, 0.419192095398964, -0.178353484440636, 0.132389738566986, -0.221411927841926, 0.634866606916482, 0.0643745711098544, -0.727815293623028, -0.437267074972362, -0.203059123566239, 0.61236047665476, 0.198037174417328, 0.768672979084602, 0.323025256602774, 0.0734234274875721, 0.0562649931241585, -0.0553143629936731, -0.0853529003818045, 0.0359183772413752, 0.0954082854036176, 0.671223854473251, -0.124085298098747, -0.0384948090849152]', 122.0); -insert into credit_card_transaction (time, features, amount) values (157980, '[-0.297038125811158, 0.762610438101774, 0.730339890280684, -0.596276261475649, 0.615714601295896, -1.12566428119967, 1.03930759137958, -0.227584485706682, -0.317098420128097, -0.702442833356434, -1.00172687761946, -0.0750492055055783, -0.273768606535085, 0.247807207178697, -0.338469149433701, -0.158404063215292, -0.333861519089508, -0.668446522429342, 0.100800293527853, -0.120964948204753, -0.188363961228007, -0.535614912774125, -0.0176234596026, 0.0428371776117388, -0.516012917906981, 0.150407374551543, 0.0842337861392922, 0.159141028830275]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157981, '[1.86926884946311, 0.413058711140049, -0.572303743423866, 3.7604492874234, 0.218277694004166, -0.0405909268757412, 0.0284560119484586, 0.0190435833520761, -0.991206135710436, 1.66524869677438, 0.329371574217789, 0.0311256547437708, -0.878857968792483, 0.526688978922034, -1.4702065703776, 0.912528325484498, -0.921608557841306, 0.356867398453975, -1.38365728980941, -0.328716244875331, 0.338361480774963, 1.00800215203024, -0.0004779004906996, 0.0701951008988325, 0.146426465546607, 0.220831410102284, -0.0430859143860707, -0.062346108810627]', 10.62); -insert into credit_card_transaction (time, features, amount) values (157981, '[0.206060594953811, 0.807815773425009, 0.769807708980104, 2.41107272681782, -0.0917582319751275, -0.776406818271336, 0.572877006997071, -0.18775055589271, -0.358332025591123, 0.307231218582176, -0.477880868581443, -0.138682849846432, -0.877309754605858, 0.450803643362897, 0.44343798106244, -1.99696931449746, 1.18821908834196, -0.0708335785398571, 2.06098119594949, 0.0750030647814684, 0.389942538651507, 1.47005256021261, -0.0715339655219718, 0.91708637455169, -0.753174959470877, -0.116267216186615, 0.315513952991209, 0.252121847375306]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157981, '[2.02436237603537, -0.293730788550126, -2.08411219154586, 0.121534138179134, 0.670296415672217, -0.227201023315928, 0.271028793534234, -0.0844098921308814, 0.363953056051184, 0.289564356796266, 0.0238461231945178, 0.0394588634398212, -1.5069048219135, 0.854261674667014, -0.84714069480227, -0.143876083822952, -0.441334312016314, -0.0116841999157678, 0.669983520000323, -0.203029062441929, -0.0212187036159191, -0.0598477695060261, 0.0140094625483717, 0.0543326869656147, 0.177283920207652, 0.553323077445849, -0.119150398247176, -0.0839871028600665]', 39.95); -insert into credit_card_transaction (time, features, amount) values (157982, '[1.03454846822727, 0.915873955029731, -0.778864844472036, 1.166481929245, 0.827127599192127, -0.273605125167718, 0.731468634595371, -0.474851711119359, -0.184661164380683, 0.230231303659996, -0.404474446770238, 0.129227567034488, 1.18580843506561, -1.22244286123264, 1.23599123409444, -0.796675003349985, 1.12357016816963, 0.0541532284841868, 2.60387364690589, 0.302229671207166, -0.257466115784235, -0.35618742097819, 0.287616617200605, 0.429186323516502, -1.50328057885806, 0.382681936043292, -0.154550355993643, -0.1224949312475]', 5.99); -insert into credit_card_transaction (time, features, amount) values (157983, '[-0.130366442031847, 0.712577670059276, -0.297719730900554, -1.0054853332461, 1.22166908103954, -0.0659941373862591, 0.849569199725631, -0.0177541513489372, -0.161807880520032, -0.12806524967738, -0.409825401339099, 0.477956091357462, 0.366440037390018, 0.14942209065554, -1.00892632704129, 0.48565073238296, -1.17801356454006, 0.166181143543691, 0.735403726729126, -0.0084641466526045, -0.289105858444239, -0.68323603186344, 0.013317154422042, -1.39079583478784, -0.311320000147051, 0.197458816019289, 0.124741613879059, 0.0568751015590167]', 0.99); -insert into credit_card_transaction (time, features, amount) values (157984, '[2.05269311103296, 0.0832291750212749, -1.29963681382918, 0.319329160730435, 0.190586891271607, -1.03891055540037, 0.274840025695008, -0.375561108243263, 0.376040836425049, -0.0361706507085913, -0.139771919621809, 1.03323404059433, 1.22467579188652, 0.259968927221364, 0.674129858259793, -0.407568804281939, -0.410891741117796, -0.381166876545931, -0.433151217096556, -0.157134606833929, 0.281863973713935, 1.00672960583387, 0.0724497417901615, 1.15590752441511, 0.265709827167777, -0.165664124585168, -0.0129351274570088, -0.046091589598825]', 0.89); -insert into credit_card_transaction (time, features, amount) values (157984, '[0.81583530027683, -0.135741872269979, 0.410949138436555, -1.80124886333432, -0.974179003182342, -0.915719732679837, -0.295548566414395, -0.936574701573116, 1.2708519660587, -1.14499402886989, 1.77626595190362, 2.23927946535372, 0.946650207071043, 0.125260831791892, 0.237268823166167, -0.432256428436072, -0.335418471019247, -0.0157564977461659, 0.842744825885943, -0.160982196995703, 0.659120484482723, -0.419533642855097, 0.320547791407024, 0.557733796674746, -0.0336864066761128, -0.553766936135689, 0.172173027814975, 0.168069916805165]', 32.74); -insert into credit_card_transaction (time, features, amount) values (157984, '[-1.1499923777044, 0.59625694895982, 1.74801909207187, 1.05768707484915, 0.490737741281965, 0.473117785397453, 0.44844040725259, 0.25666885341858, 0.209536022831864, -0.370252654103923, -1.43731632747189, -0.154487374945779, -0.809666313030499, -0.262462484169826, -0.616880806821511, -0.893279132813805, 0.401463388114945, -0.550878637613737, 1.31146800622303, 0.114973040826894, -0.568831258861779, -1.36939612294812, 0.10587011625502, 0.58298796794886, 0.433680213662218, -0.813375616852775, 0.235455766292334, 0.162920778082918]', 34.96); -insert into credit_card_transaction (time, features, amount) values (157985, '[-1.038324774473, -1.04420226793028, -1.68550813350863, -1.98020284108057, 1.30026242196773, 1.52857894655716, 2.24569625500273, 0.266297135236602, -0.488183289920301, -1.23386295035756, 1.17415300662843, -0.126389608625717, -1.78268755461073, 1.36742723965976, 0.727297107708839, -1.52428315117596, 0.599308925335549, -1.40121348069582, -0.815527972818355, 0.656271834043813, 0.645011675347473, 1.12862593403377, 0.86919482378899, -1.06325491003779, -0.459294682096277, 0.82408723326341, -0.0195542401536002, 0.187682143489534]', 415.6); -insert into credit_card_transaction (time, features, amount) values (157985, '[2.0377230312721, -0.174405502571658, -1.22816497916937, 0.206601285172922, 0.074077311518071, -0.593325367022731, 0.0088500123189233, -0.0946503788706294, 0.419257557677737, 0.255815665355955, 0.525467624858113, 0.623510102551369, -0.691837255641971, 0.600497313881401, -0.502984651044866, 0.183593936145614, -0.585344223819071, -0.242537465570877, 0.519042953742118, -0.25352661418887, -0.266279956717685, -0.696941769874464, 0.293863534208587, -0.486260032314027, -0.315324684483836, 0.210791657197925, -0.0767547818030606, -0.076271359205579]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157985, '[2.33711541867659, -1.32241285641572, -1.5076316497485, -1.93901752550013, -0.414174669647993, 0.269720384779131, -1.05899156802788, -0.0808658994993204, -1.617465734983, 1.71725026880438, -0.104273546944298, 0.0941080483826006, 1.63945724094246, -0.483336059308375, -0.944640291093014, -0.181981381030383, -0.194555936984752, 0.630365977235737, 0.545655194623276, -0.288842100983413, -0.122488349226662, 0.162934022046668, 0.0594114496811898, -0.326713086903993, 0.0665098816809244, -0.0883627524016086, 0.0029763057924077, -0.0639523456880933]', 20.45); -insert into credit_card_transaction (time, features, amount) values (157985, '[0.272183044850092, 0.804097011214754, -0.236366736323444, -0.262365483658319, 1.16912262938236, -0.678473710241877, 1.12331938626959, -0.317212171216718, -0.152698317271657, -0.734420029626425, 1.0381150524124, 0.702601803491696, 0.23333273080958, -1.06398771710766, -0.561929474229747, 0.0087268526745382, 0.25282793348098, 0.520090073955388, 0.605443161418944, 0.0167722477592292, -0.211633701238631, -0.33743240145056, 0.024118167848894, -0.523397041819117, -0.766463522219622, -0.662480266592223, -0.0143824717134726, -0.0961654418816045]', 9.99); -insert into credit_card_transaction (time, features, amount) values (157985, '[-0.141331897398899, -0.205877050453299, -2.73231436952907, -1.33800297970994, 3.85317203835303, 2.54885158789366, 0.0039433333060001, -0.267734900098729, -0.661319767070645, -0.858174576856784, 0.381171445672259, -0.140006854855413, -0.482621300868651, -0.116694741736131, 0.547170237186007, 0.0943155603040334, 0.547478157470998, -0.283419381095407, -0.810195930667418, 0.238404045325131, 0.923845311542132, -0.635754497915462, -1.63346067045926, 0.733959578965911, 0.633797618105617, 0.739604654364438, 0.114416244960481, 0.319937286330274]', 252.9); -insert into credit_card_transaction (time, features, amount) values (157986, '[0.147051840027449, 1.0830396660897, -0.402870389789097, -0.553268602776946, 0.97253869603613, -0.803215528516796, 1.03177008707257, -0.149294644474044, -0.150102084846622, -0.85660535615362, -0.596710198204915, 0.234367756322204, 0.690211237125984, -1.15373282921449, -0.311969388429648, 0.307477317658837, 0.318226280880149, -0.29043368300994, -0.224784459518234, 0.0675472943503132, -0.334343624340973, -0.78363297823318, 0.0893149404561686, 0.577336269654958, -0.393884221899291, 0.11135399453266, 0.226049670491634, 0.085689181091412]', 5.55); -insert into credit_card_transaction (time, features, amount) values (157987, '[2.11236262467254, 0.654754740525139, -2.81924754830598, 0.476959073914732, 1.27080918013566, -0.932040025725309, 0.390901979939392, -0.341114630529116, 0.350278023810418, -1.24376005266223, -0.269915077847392, 0.170098147999943, 1.42912959605036, -2.85236305446325, 1.02703319295645, 0.956498495682944, 1.39874219383979, 1.39191006984878, -0.412732080257681, -0.0156889288911087, 0.0572854712568602, 0.396408456467406, -0.119900536060807, -0.148248625557752, 0.420761880114656, -0.0947176854940052, 0.0226409426344049, 0.0100758634306431]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157987, '[2.04109782099017, 0.350940189056597, -2.10090814768339, 1.08312542190863, 1.04431954194898, -0.866813357501284, 0.887324124816537, -0.499160372491717, -0.327876686419373, 0.318842067036512, -0.846729877011878, 0.657916710982758, 1.15757045599222, 0.547625404122294, 0.12020511562162, -0.347763444754248, -0.642043189599288, -0.426426187636703, -0.274215912853205, -0.103771952899864, 0.128494173257471, 0.434767724325055, -0.0586906490835362, 0.506267126674545, 0.562184550941427, -0.508893151213243, -0.0357005330978196, -0.0512525870505582]', 36.92); -insert into credit_card_transaction (time, features, amount) values (157987, '[-0.394788448107399, -0.894404876691071, 0.979298291075818, -2.53714149861398, -0.483413827960082, -0.840846478443589, -0.245646929680381, -0.0436200901853771, -2.3458008188704, 0.921203537073684, 0.48372448980412, -0.654391319780736, -0.192391706438135, -0.177761989410496, -1.31899854386112, -0.470671553570291, 0.243554912097002, 0.542999885746448, -0.0071167943493756, -0.205083088356636, 0.0201852017064449, 0.277830546908711, 0.0185608934538624, 0.0447062630395892, -0.291131078889448, -0.22834421975755, 0.120528098915956, 0.152882165428069]', 50.0); -insert into credit_card_transaction (time, features, amount) values (157988, '[2.04712004532606, -0.0178533596278358, -2.30606043977286, 0.12799513631335, 0.968767552806877, -0.510501224883777, 0.623160392803822, -0.277374653477536, 0.112727612633072, 0.137937194438245, 0.493305890164093, 0.927393102116149, -0.0937839584347398, 0.804422500414814, -0.791809467196635, -0.596497685073425, -0.490340506852817, 0.0114111308590317, 0.553261186536863, -0.168578834552216, 0.169514320625628, 0.611486035994919, -0.12613908189907, 0.273767721234261, 0.589176448678518, -0.0915406984112753, -0.0629072823343511, -0.0782769675353617]', 28.16); -insert into credit_card_transaction (time, features, amount) values (157989, '[1.80864033170131, 0.0383821145193868, -2.10464260599799, 1.32557117246225, 0.679213923068398, -1.38480715246024, 1.18298160916691, -0.677137221825468, -0.420948059601586, 0.279909812451714, -0.660041306284505, 0.847408958726595, 1.31442093840839, 0.595582894060089, 0.0007835281641163, -0.491826764589974, -0.539881906722786, -0.507336674768713, -0.386302958973705, 0.101245975785915, 0.267422876895862, 0.63890420341079, -0.226338950259919, -0.0530879289663113, 0.577839269028708, -0.428649055843689, -0.0560485764108666, -0.0398602234387406]', 150.0); -insert into credit_card_transaction (time, features, amount) values (157990, '[-0.854089720396774, 0.802951390473658, -1.01687286859822, 1.11067043625121, 1.60872665710188, -1.70323665346098, 0.915498549602817, -0.0437809583997831, -1.25753591894454, -0.0029950921809338, -0.976889475975735, 0.658609895800632, 1.34541328550971, 0.911258546231316, 0.109320718155876, -0.85631239084077, -0.0711339201918452, -0.172068187169231, 0.567298833231111, 0.274310119314279, 0.407298693521455, 1.05198250542721, -0.231318535127903, -0.0427353025377282, -0.255749090788623, -0.389403549442357, 0.379763104243126, 0.0892658521914443]', 3.6); -insert into credit_card_transaction (time, features, amount) values (157990, '[1.83886779621712, -1.26584212554491, -0.713061595464002, -0.344034471235008, -0.773010627780886, 0.386865708550394, -0.887792599528705, 0.0665193044653516, -0.419159788590151, 0.979460795527683, 0.383055652385181, 0.952046783923038, 1.43898769303676, -0.215104118489459, -0.0110305587787033, -0.662098721303236, -0.908310963582548, 2.06090999612596, -0.813681582319438, -0.205022834033805, -0.0611147386381165, 0.0968051302793067, 0.0949946174797474, 0.304822366746747, -0.368648957472589, 0.314097076469585, -0.0166541633355801, -0.0203895822173477]', 147.0); -insert into credit_card_transaction (time, features, amount) values (157990, '[1.93090892696115, -0.480163126614668, -0.850093142552679, 0.107091373620853, -0.131368959289603, 0.0223979395098992, -0.402617937018541, 0.0103154252520142, 1.32766637867618, -0.266015098899084, -1.38553406656163, 0.276500735832294, 0.354160197554477, 0.0168838879056778, 1.15126696307505, 0.462141538725997, -0.952514217800872, 0.27471647162802, 0.134714480553858, -0.0464755268238872, -0.14137610620748, -0.45383383126495, 0.239722571272779, -0.0235600514082925, -0.271392155578471, -0.92997705778748, 0.0403439789231055, -0.0155516589263575]', 69.24); -insert into credit_card_transaction (time, features, amount) values (157990, '[0.143560596001966, 0.587314009216495, -0.0358333786338847, -0.869775533398348, 1.48280698016015, -0.007579073573562, 1.25983492837551, -0.521463698895298, 0.112014393995214, 0.168550814434153, -0.380956644934996, -0.417639703496914, -0.606826944035918, 0.226212668865572, 0.0974728408286391, 0.0484235646200726, -1.37795844984772, 1.17687285786284, 0.914286199545073, 0.0059582263924113, 0.265857825739496, 1.13844429340141, -0.469287571340013, -1.36081072102547, -0.416918454332601, -0.163319329918721, -0.254136657921484, -0.251555960560955]', 5.55); -insert into credit_card_transaction (time, features, amount) values (157991, '[0.259173746741467, 1.21386157141849, -1.45677103146647, -0.309308665209166, 1.01141101130299, -0.564735445666399, 0.612991719993012, 0.171974000960478, -0.321304504666245, -1.17031859600834, -1.1176468120284, 0.345709791087465, 1.50577618664901, -0.84415287766274, 0.600815481283695, 0.391552779300015, 0.2154017809313, 0.831188730963809, 0.0332985675473074, -0.0972804972681595, 0.289830437479287, 0.860718920941663, -0.156833013547339, -0.0030439976012819, -0.10437263161415, -0.144214785685948, -0.066941447769097, -0.0441856406478188]', 13.0); -insert into credit_card_transaction (time, features, amount) values (157991, '[0.0526809203754026, -0.190089867648071, 1.16208526769314, -1.43366348623236, -0.0801315553798603, 0.25010675315447, 0.0718004188821336, -0.198956884811732, -0.736003702781692, 0.39457143822218, -1.71664956559432, -1.35836540867604, 0.379508741991065, -0.766917053915528, 0.583058223186984, 0.843678275913349, 0.0619489268911854, -0.617608384467588, 1.81773342259392, 0.380878279362272, 0.306566709153659, 1.07361667105095, -0.341761480134881, -1.01211296537181, -0.156709849468961, 0.115647155119122, -0.0008530734809258, -0.0792043979122315]', 39.9); -insert into credit_card_transaction (time, features, amount) values (157993, '[1.85288475952639, 0.473710003884223, 0.310970769467465, 3.81760877567988, -0.125462595975344, 0.129680799942635, -0.248698938000325, -0.0166052221847358, -0.701846642724368, 1.32082671729537, -0.925746094513927, 0.744912574080614, 1.73230665990834, -0.437725567136392, -0.590151872929491, 1.23354929136605, -1.05131375888487, -0.561850926201894, -1.60242488288064, -0.159511743907691, -0.174755285657351, -0.432877685499437, 0.412669118182352, -0.0008895695501572, -0.517112847841033, -0.389886619043593, 0.0188498459005466, -0.0196453401288847]', 13.99); -insert into credit_card_transaction (time, features, amount) values (157993, '[-0.188385880285044, 0.213025385938357, 0.78071255521591, -1.37766341933504, -0.493586682173149, -0.0939470703203497, -0.318464839691432, -0.158508131738335, -0.592652387483716, 0.808193806973832, -0.82214943402255, -0.68537288238289, 0.805566419124682, -0.680552987090326, 0.722933748676302, 0.977471777736693, 0.150010963232088, -1.03705837254047, 1.49019012883415, 0.0752863788038008, 0.244302949786818, 0.55967743528884, 0.156345833461641, 0.672306340526743, -1.47409896473772, -0.495173717129364, -0.213566937468262, 0.239556787718746]', 24.15); -insert into credit_card_transaction (time, features, amount) values (157994, '[2.05167392990316, 0.272887523213804, -1.57395460342605, 1.39371941781976, 0.40762053361259, -1.23997685023916, 0.656515123923081, -0.45037159663884, 0.187040071335283, 0.26691239792518, -0.996227869510808, 0.365150932324821, -0.152766039228104, 0.50519378601389, -0.579675718953309, -0.689585294556884, -0.18624073605008, -0.58957012403175, -0.153441896914621, -0.304302826092369, 0.0413032450335258, 0.365279323191869, -0.0020650531763521, 0.0544707478920734, 0.478429123340327, -0.494707561537863, -0.0156669199767425, -0.0624594589471261]', 1.0); -insert into credit_card_transaction (time, features, amount) values (157994, '[-1.42147860971256, 2.21360707933308, -1.85054206422684, -1.67631304380085, 1.35780249285282, -1.03240924232746, 1.60596892880081, -0.286426300030681, 0.964090810678693, 1.57745524909955, -1.49921721436163, -0.59217689062349, -0.541604865101477, 0.224648757261934, 0.071242482005685, -0.576106969027422, -0.762409271701829, -0.165780929679948, -0.0181828757511213, 0.760434519614119, -0.0500193611678655, 0.608940100226333, -0.254804956349742, 0.0481006932642992, 0.0748600603920638, 0.0723379210297193, 0.563302480702816, 0.120452282676504]', 0.77); -insert into credit_card_transaction (time, features, amount) values (157994, '[-0.389578141229863, 0.965798289868215, 1.06405285907439, 1.12011687424355, 0.627132063843454, 0.188575024004209, 0.786271785520629, 0.0250913248703534, 0.0554194135958932, -0.366664888836034, -1.69891931248837, 0.660891202826879, 0.679885960339591, -0.490851304205345, -1.51273988200752, -1.30982957197075, 0.378128000333287, -0.676583540883496, 1.39176799240482, 0.167438521860015, -0.309836716429563, -0.379238572723551, -0.194083477413766, -0.413646925559684, 0.0752375390139664, -0.612144503906447, 0.449281857159036, 0.217958986364404]', 10.78); -insert into credit_card_transaction (time, features, amount) values (157994, '[-1.03834629001417, 0.980823096831625, 1.13169386902647, -0.965596494322759, 0.977842027054246, -0.554693848572675, 0.99023266502701, -0.0615763088584925, -0.718198697228029, -0.456005664710077, 0.649272018854922, 0.900761122073184, 0.537575177052452, 0.151056722133844, -0.965661561623348, 0.102450898101333, -0.71373745664673, -0.213664917369033, 0.511309133552619, 0.0842441648458802, -0.289983643887679, -0.761898723191137, -0.397129864457753, -0.311402125020374, 0.581507724734275, 0.323495541398553, 0.0872730595077866, 0.0833171739683947]', 1.78); -insert into credit_card_transaction (time, features, amount) values (157994, '[-2.18655778922673, 2.55338991628287, -4.05731999713177, -1.22917092542734, 1.5410592698886, 2.85245864086152, -1.47630610751728, 2.8507407794835, -0.5190090362882, -1.1609868002415, -0.428427490095631, 0.493050112478783, 0.0100472096973589, 0.640308697444481, 0.971030816304602, 0.522734621982998, 1.24385878671091, 0.76951887452415, -0.380507516641941, -0.378266202672716, 0.506290602255772, 0.784137868585688, 0.145798851350069, 0.612597581596902, -0.167759567091009, -0.153299530316839, -0.663251731511976, -0.0723573504426223]', 2.58); -insert into credit_card_transaction (time, features, amount) values (157995, '[-3.24087328373638, -3.04250014375305, -1.52905280617537, -1.54341703522962, 1.75569789099543, -1.42438211500702, -0.224384618618197, 0.240723645552957, -1.16172489175815, 0.205560279822645, -0.259810707826992, -0.546038513640202, -0.863699060298001, 0.604588956066458, -1.80197983685328, 1.23191819343331, -0.0385130490162624, -0.906240308679344, 0.736034445375585, -0.0603431288503041, 0.248804759089803, 0.377166624157001, -1.11842850205233, 0.232663664758924, -0.13663541370527, -0.241819312812789, 0.674763536286375, -0.669739164955096]', 219.0); -insert into credit_card_transaction (time, features, amount) values (157995, '[2.02410564755048, -0.239977221069602, -1.17552969284413, 0.546774190209576, -0.136380867800517, -0.829512139643842, 0.0355426306707878, -0.232416679923116, 0.826196917864315, 0.031921019907592, -0.831811809453729, 0.354451700025848, -0.382637426253395, 0.109604038786624, -0.624148423976021, -0.594347279076859, 0.0854363644874066, -0.609000878785836, 0.0028679005035407, -0.218079905313213, 0.146532568407121, 0.671720718941477, 0.0780787130449502, 1.23109509337488, 0.164595435721947, 0.6668067861417, -0.0756149114581401, -0.0601502729104189]', 12.31); -insert into credit_card_transaction (time, features, amount) values (157995, '[1.96531979162672, -0.604376981009271, -1.73674372868077, -0.678321855171807, 1.81561788620994, 3.77925610393906, -1.09947973164136, 1.02682028217507, 1.1205364396116, -0.14822086025553, -0.0410258631561172, 0.553902400274783, -0.0455777581470326, 0.157776530378819, 1.06905477711207, 0.119232218242606, -0.629752334109814, -0.318907944379756, -0.201247779928948, -0.142166209012562, -0.180360210617679, -0.490728830618942, 0.409368393747652, 0.657382492668504, -0.391700640161588, -0.60176744559643, 0.0539876134028559, -0.0366980694787675]', 10.0); -insert into credit_card_transaction (time, features, amount) values (157995, '[0.153383664773214, 1.13745490472237, -0.386275232320806, -0.56152742735665, 1.0334692725835, -0.791439789543417, 1.06601991271845, -0.183836682480236, -0.243090973724566, -0.87261561561599, -0.490942401876628, 0.564639350036639, 1.30967196749328, -1.27748556035014, -0.380253988916206, 0.277878452396739, 0.282970449360879, -0.367631373813257, -0.228324854474877, 0.100855389972614, -0.3289660062317, -0.732542521944843, 0.075163675853285, 0.594642778470109, -0.374099619013697, 0.109360979469292, 0.231111886956425, 0.0867836173839464]', 2.87); -insert into credit_card_transaction (time, features, amount) values (157997, '[-0.336239426170053, 0.958429815680492, -0.24889173869767, -0.746848195911093, 0.274269650318516, -0.546923737773364, 0.503795181688903, 0.463445249433104, -0.322065352417541, -0.4571219134258, 0.173844886916435, 0.42347874366809, -0.789677612021243, 0.775675564117922, -0.972964608233147, 0.324518306892487, -0.532016283436993, -0.0660608356153877, 0.282532810174294, -0.161811043129225, -0.190438410833539, -0.589730387075449, 0.104367282564373, -0.498258864252165, -0.481315563369098, 0.155649782478461, 0.111600822557173, 0.0186245286382775]', 13.99); -insert into credit_card_transaction (time, features, amount) values (157997, '[2.07227678423414, 0.155810694256452, -1.69040736134271, 0.425853175945209, 0.395716667549523, -0.900752360734983, 0.183882512640836, -0.236483240795318, 0.497722540278616, -0.377158818203769, -0.545417645429673, 0.136368471590181, 0.019141992231033, -0.834540731408179, 0.207195044610871, 0.308797783524846, 0.487589642533864, -0.313427682600817, 0.0408021393862854, -0.159101423586181, -0.362804013519222, -0.942009105043574, 0.344115104030004, 0.567010777180656, -0.263872441599506, 0.169744040359626, -0.0629537428290597, -0.0301685119021836]', 1.98); -insert into credit_card_transaction (time, features, amount) values (157997, '[1.89142394167909, 0.461925233243559, -0.74498642849913, 3.60437892143354, 0.523475632235626, 0.23278700238057, 0.112270521822615, 0.103716691947064, -1.01752051307632, 1.63106591073464, 0.0118734508196438, -0.235196702459739, -1.33029764070338, 0.709285044875633, -1.36882642356874, 1.09084761541496, -0.985950338437737, -0.125841497872216, -0.95488056362038, -0.356430951462129, -0.254410668869074, -0.825294015065832, 0.313420004207921, -0.583386295319196, -0.294627049217404, -0.328505470675697, -0.0471442294175663, -0.0596523887074605]', 9.85); -insert into credit_card_transaction (time, features, amount) values (157997, '[1.95581549901846, 0.0064200337213412, -2.63556579695858, 0.0458810376539879, 1.5554127316891, 0.198887846133665, 0.742241558151422, -0.0905190989182302, -0.202215426164499, 0.0905837486484391, 1.31443995868746, 1.18110135867995, -0.132397172420877, 1.12959218828524, -0.0021701535247633, -1.68622804870277, 0.4026567302194, -1.38025858756923, -0.637270442447588, -0.318025060572124, 0.418556274317098, 1.49322107311686, -0.199073001579511, -1.33003623239184, 0.615005377374104, 0.221316570880241, -0.0289957001045035, -0.107714970044056]', 17.35); -insert into credit_card_transaction (time, features, amount) values (157997, '[1.72986506814428, 0.37174933012196, -1.61297138354966, 3.7959286431451, 0.769966836114099, -0.748735049608872, 1.01194750424307, -0.413043568570005, -1.46281207666999, 1.53791798356379, -1.25782145683423, -0.664832404867863, -0.505758065995271, 0.836359792172352, -0.584720931689256, 0.61175336738986, -0.761991805660756, -0.510663749344267, -1.49740032747962, -0.049354581416787, 0.161755965916549, 0.120367296777598, -0.0797963948768653, -0.134588628952614, 0.233421470219938, 0.068273542838009, -0.110208180292015, -0.0420379583817925]', 144.12); -insert into credit_card_transaction (time, features, amount) values (157998, '[-0.0640958562133124, 0.663898024301168, -0.760477066502158, -0.922439695087993, 1.84110396284019, 1.2280774707675, 0.581541966751942, 0.525113793607584, -0.202841666650212, -0.788730243186031, 1.02623748963988, 0.372535496055676, -0.488542777952157, -0.675080252364888, -0.0763698193630831, -0.147262441497555, 0.752348722389591, -0.804238380819083, -0.781884659841249, -0.0228732512448712, -0.23864346591827, -0.538224598375529, 0.147990662418589, -1.06297512853967, -0.59258266054486, 0.225142908524695, 0.256604536177576, 0.0591223459757539]', 16.99); -insert into credit_card_transaction (time, features, amount) values (157999, '[-1.02574938375413, 1.15776291744236, -0.033327477821379, -0.442243813863839, 0.393003389774765, -1.19693665319056, 1.0989318096207, -0.371292483490231, 0.338062078062157, 0.418121441759003, -0.668703480545418, 0.106382715853071, 0.358559522590487, 0.0683863671740823, 0.693155822516832, -0.452353661315082, -0.465190389979203, 0.0241815230822891, 0.0434485216146917, 0.150053624184731, 0.170571854526715, 0.91016263242133, -0.292805521683459, 0.0921582959904475, 0.511682271103957, -0.0324269308502219, 0.239172073534195, 0.286926278190003]', 38.09); -insert into credit_card_transaction (time, features, amount) values (157999, '[2.05603140576344, 0.342600840903561, -1.81955947683389, 1.24637060988893, 0.572197989525541, -1.41054327263024, 0.798174184572388, -0.496394436217941, -0.109103043389559, 0.37415468472009, -0.777261214118751, 0.0264318227166965, -0.399594005572001, 0.872706235560097, 0.26099638167988, -0.451128923564884, -0.374623663124239, -0.468745496691316, -0.445848364176961, -0.302746528084032, 0.124553959218894, 0.461693303591412, -0.0098771048358922, -0.0461543591706105, 0.450949421727211, -0.479142804179872, -0.0314340442411572, -0.0641287250516018]', 8.36); -insert into credit_card_transaction (time, features, amount) values (157999, '[-1.42656259993647, -2.36732850168801, -2.1491077454988, -2.85642449287857, -1.33558729099318, 0.67084246937659, 3.92924406221627, -0.650406479028878, -3.42991822394087, 0.153531209322498, -0.838723151709099, -1.66398574297931, -0.264681323464446, 0.475410635409852, -1.89291189835722, -0.474357040668973, -0.242155089010834, 1.02470967746216, -0.0377785154810256, 1.41999492602488, 0.632862819046121, 0.713253419575556, 1.2247375972255, -1.44879582442195, 1.29660721484043, 0.252188828697769, -0.271000932427871, 0.125407173302402]', 857.55); -insert into credit_card_transaction (time, features, amount) values (157999, '[2.01102378066906, -0.624258780548357, -2.07613122346912, -0.268794071745131, 0.253604296813077, -0.646627503228843, 0.329745824921249, -0.384418114296321, -1.35704233085159, 1.08694744094524, 0.850578581032546, 1.18835482670936, 1.12220661786516, 0.449006919426211, -1.22143952013622, -2.04755549121025, -0.118250700942601, 0.929476645845765, -0.507935782020169, -0.383266167731841, -0.137817695259622, 0.0699408663907496, -0.0127426989762834, 0.767071428464348, 0.279433698780856, 0.470825965126254, -0.0884967725903225, -0.0634472867099299]', 89.44); -insert into credit_card_transaction (time, features, amount) values (157999, '[2.29899706749088, -1.3459062126824, -0.563147550902457, -1.71377958314276, -1.33590068528017, -0.393882056259288, -1.40187624254848, -0.0626831870150649, -1.15675184430066, 1.57568781032651, -0.848992992853496, -0.843739454096345, 0.657899532899061, -0.463988023154065, 0.738780145102113, 0.0043906068621889, 0.160528140633593, -0.0235764467531043, -0.346203611862752, -0.408380227731442, -0.348380201969361, -0.616430363616836, 0.500609454683835, 0.526165859287702, -0.619592133825937, -0.500084928398665, 0.03254746173764, -0.0296132921820711]', 6.7); -insert into credit_card_transaction (time, features, amount) values (158001, '[2.0804458012968, 0.157797221564784, -1.72497222941489, 0.40466173647078, 0.439693464897851, -0.851665937379694, 0.181354048303846, -0.231323911793502, 0.502060710477959, -0.376851844717831, -0.620442344527644, 0.113858829102904, 0.0451229441090357, -0.842157642072063, 0.212125713658569, 0.33320870345553, 0.455663801453384, -0.286961790098674, 0.0734824403881914, -0.157822675531815, -0.368989996328157, -0.956358190469169, 0.334313399069626, 0.481142864362185, -0.251620976418148, 0.175155116790014, -0.0627878217372978, -0.0312064091081313]', 0.89); -insert into credit_card_transaction (time, features, amount) values (158002, '[-0.549098556120708, 0.766195858129804, 1.01909289642756, -1.07510196402487, -0.129909471934689, 0.126445190701562, -0.104323067052091, 0.680171682259812, -0.0127904295950648, -1.10224461713379, 0.705173783476582, 1.12638195017102, 0.265629205980796, 0.258916255338938, -0.392073865317991, 0.505319582445916, -0.64616793178304, 0.290283934207098, 0.0693128702455883, -0.201792112756794, -0.0654568866809415, -0.319780426971331, 0.0443886396399804, 0.681193508833636, -0.229043111350763, -0.320790261779217, -0.10031657898665, -0.0461826232346844]', 3.7); -insert into credit_card_transaction (time, features, amount) values (158004, '[2.06550290251705, 0.162821106221004, -1.69100116807402, 0.413852601882327, 0.449491628074564, -0.806407337309328, 0.181257182481838, -0.220818275169419, 0.467695496903158, -0.390979249986143, -0.470052846499326, 0.255882148719389, 0.209415068917796, -0.867924211765855, 0.233993465007978, 0.243679354795962, 0.529694388382164, -0.423236913744068, -0.0288115174610784, -0.154137731814145, -0.355709657467918, -0.903873646891761, 0.348031378005165, 0.512722172718482, -0.270970861902284, 0.174850710145318, -0.058401382456676, -0.0305246906946382]', 1.29); -insert into credit_card_transaction (time, features, amount) values (158004, '[0.109324109169265, -0.341359999690875, -0.184801742480943, -2.34348578412266, -0.724844167576597, -0.394404191913993, -0.437892621320415, 0.101288947662588, -1.69032272176358, 1.21765313336653, -1.85018687214858, -2.01620345223279, -1.05993224039229, -0.0826300686653481, -0.284471370283958, -0.632545908880372, 0.562731195431606, 0.400662124109114, 0.314626330728009, -0.504081803445869, -0.0419308672436013, 0.321584296839844, 0.175852729743953, 0.417841022498596, -1.28200230406287, -0.338280669456561, -0.131838307432044, -0.0284202718310015]', 20.0); -insert into credit_card_transaction (time, features, amount) values (158004, '[-1.15506028408787, 2.4189020055203, 0.917719176127805, 4.34800584015966, 0.0286157856885355, 0.553499890025478, 0.479632581514223, 0.725492752682277, -3.05477649771925, 0.866651919786396, -0.686530212856898, 0.221366203142337, 1.42214479836464, 0.819436764218728, 0.634016613620267, -0.114883441465671, 0.598338924424487, -0.421850268280038, 1.28734383701138, 0.0908511058084369, -0.112713270597994, -0.644786218760235, -0.0045105816774112, 1.12899939306351, 0.18643712593013, 0.138407088167937, -0.291010968855825, -0.0449216077722927]', 56.69); -insert into credit_card_transaction (time, features, amount) values (158004, '[-1.15506028408787, 2.4189020055203, 0.917719176127805, 4.34800584015966, 0.0286157856885355, 0.553499890025478, 0.479632581514223, 0.725492752682277, -3.05477649771925, 0.866651919786396, -0.686530212856898, 0.221366203142337, 1.42214479836464, 0.819436764218728, 0.634016613620267, -0.114883441465671, 0.598338924424487, -0.421850268280038, 1.28734383701138, 0.0908511058084369, -0.112713270597994, -0.644786218760235, -0.0045105816774112, 1.12899939306351, 0.18643712593013, 0.138407088167937, -0.291010968855825, -0.0449216077722927]', 56.69); -insert into credit_card_transaction (time, features, amount) values (158004, '[-1.21856080377954, 2.3188899092973, 0.962124579511793, 4.37257807777186, 0.254430020526787, 0.399950438575389, 0.268947913997004, 0.768127780257851, -3.04230859762087, 0.892319101728426, -0.69453243044046, 0.242375499576354, 1.42125658230275, 0.834256083331126, 0.631472523161664, -0.132702840500678, 0.608662777267431, -0.417839058065723, 1.2830589929023, 0.173004066676641, -0.0828315589305315, -0.662974331983671, -0.022599086032618, 1.12577946680195, 0.178329541926154, 0.131827203077857, -0.349199246859752, -0.0203315741999646]', 6.01); -insert into credit_card_transaction (time, features, amount) values (158004, '[-1.21856080377954, 2.3188899092973, 0.962124579511793, 4.37257807777186, 0.254430020526787, 0.399950438575389, 0.268947913997004, 0.768127780257851, -3.04230859762087, 0.892319101728426, -0.69453243044046, 0.242375499576354, 1.42125658230275, 0.834256083331126, 0.631472523161664, -0.132702840500678, 0.608662777267431, -0.417839058065723, 1.2830589929023, 0.173004066676641, -0.0828315589305315, -0.662974331983671, -0.022599086032618, 1.12577946680195, 0.178329541926154, 0.131827203077857, -0.349199246859752, -0.0203315741999646]', 6.01); -insert into credit_card_transaction (time, features, amount) values (158005, '[-1.32810970955363, 0.107338014270061, 1.73762146291356, -0.331052776733906, 0.986896555632258, 0.510835874288767, 0.445982754162208, 0.340067045879952, -0.438485084066442, -0.82268729994518, 0.0904337560501687, 0.371077421739853, 0.180131863029724, 0.0033190296924099, -0.430258921904993, 1.00371254724598, -1.47809191533409, 1.17085240148857, -0.821312878215421, 0.233601153819319, 0.331077019310538, 0.572049383968115, -0.256214299632852, 0.167230162790563, 0.908312883877749, -0.546693084577415, 0.00781965182604, 0.0744328428619158]', 95.0); -insert into credit_card_transaction (time, features, amount) values (158005, '[1.95863121859227, -0.270358858428833, -0.361758061353839, 0.232941035614787, -0.341751857602434, -0.01286687699886, -0.557950971549502, 0.10289433602546, 0.876470961056475, -0.0239914475363933, 1.04756783261856, 1.64125606189957, 0.876207172849847, -0.0229889075230185, -0.101866433770536, 0.364804483093047, -0.853220123414868, 0.218722539711737, 0.208228224499259, -0.142187299996863, -0.124964196913852, -0.230031602129102, 0.394390129342312, 0.741236308817778, -0.413886149270631, -0.680441236162737, 0.0329031283035746, -0.0324001159271016]', 2.49); -insert into credit_card_transaction (time, features, amount) values (158006, '[1.96807082007987, -0.473547486337158, -0.224402524425328, 0.388142689028991, -0.790983742207614, -0.404441367273001, -0.69333792227015, -0.0120263556123078, 1.20784562090276, -0.0215718960470008, -0.626773151403427, 0.580835533992384, 0.404442051912913, -0.326718394006489, 0.341163082442498, 0.219212502839639, -0.376442449141442, -0.0947754607243288, -0.389843707015761, -0.137925129929002, 0.237008128981077, 0.880059040207286, 0.205791671246351, 1.22810530739388, -0.277807655716904, 0.681254716110786, -0.0313862405242558, -0.0372369502682329]', 14.99); -insert into credit_card_transaction (time, features, amount) values (158007, '[-0.174917483310695, -0.3802532173463, 0.425592259603839, -1.60065326921161, -1.79280612435935, 0.269107756756679, 1.4934269467715, -0.383368658178788, -0.762060463385778, -0.232361892163579, -0.81829070606579, -0.0287198029042257, 1.32830763279617, -0.949920527356444, -0.938435376070552, 0.967722921045715, 0.1632538044246, -1.90953822667882, 0.629253080361338, 0.0985351199276307, -0.128633755803298, -0.259236286080482, 0.402771704425359, -0.0815274099926616, -0.652753682019415, -0.65023886510379, 0.107371044334943, -0.0367400964881512]', 357.4); -insert into credit_card_transaction (time, features, amount) values (158008, '[2.12824860039992, -1.37484398762585, -1.70766623468932, -1.85208377750572, 1.13351130900808, 3.84281520229695, -1.82825993170034, 1.02281227216907, 0.186772577126798, 0.72245308449633, -0.15763866001492, -0.405617405802214, 0.140457860683641, -0.47816376057519, 0.471718261364598, 1.08269133281213, 0.0640828220124807, -1.11484502193072, 0.269356364811938, 0.0566471381801107, 0.431020544885627, 1.26910275923978, 0.114499845078129, 0.761774542353535, -0.0696130410945029, 0.0444011539559604, 0.04322762241014, -0.0520447600128112]', 14.95); -insert into credit_card_transaction (time, features, amount) values (158008, '[2.06696679914538, -0.0586455101676325, -1.28892839968384, 0.350483457381838, -0.0561656764195863, -1.22073881355422, 0.160256995636037, -0.333780364647096, 0.706142210634753, 0.0163967498086748, -0.788180370804549, 0.0597027453624339, -0.35392610125504, 0.546414664416819, 0.875582441395916, -0.197023134613227, -0.464927118858226, -0.0344365882615781, -0.297270353474904, -0.277553535295582, 0.255359945354464, 0.894498478025095, 0.0036660425132795, -0.0575925537141293, 0.233468261099952, -0.0928364440237184, -0.0158725770755196, -0.0598064892288759]', 1.0); -insert into credit_card_transaction (time, features, amount) values (158008, '[-1.33284248995339, 2.03119003550903, -0.720939425737272, -0.487277891938185, -0.308116808038665, -0.180411271129577, -1.68137885135292, -4.94871354211716, -0.711354391180041, -1.61145321731141, -1.25576550413049, 0.764544520372453, -0.42883323502723, 1.25129923642293, -0.602596501061529, 0.358616297603198, 0.0431355847483786, -0.62057891106073, -0.420707862018223, 1.10795399788182, -2.72715468874493, 0.217475512910371, 0.571787386257881, -0.0043502116861516, -0.607924730244165, 0.106827705284383, 0.0495643883022036, 0.10757800505176]', 1.98); -insert into credit_card_transaction (time, features, amount) values (158008, '[-0.298673843353843, 0.183739852526517, 0.647865001229045, -0.579165559700988, -0.480181607968308, 0.395464748465713, -0.985381660681913, -2.5118133667157, -0.11385244582456, -1.1114961500072, 0.405144750230186, 0.815051661879033, -0.61666004527177, 0.670727717013591, -0.466202706326449, 0.99276738290918, -0.819217516807982, 0.205792765178059, -0.178956660036883, 0.767749613593986, -1.44020998875816, -0.46315404139436, -0.025509281700941, -0.357899501214852, 0.236179176597933, 0.287736425353656, 0.0214301897309842, 0.26461403946828]', 130.0); -insert into credit_card_transaction (time, features, amount) values (158009, '[-0.187065738562102, 0.938949796372722, 0.158719491986008, -0.635957028283626, 0.267082977201802, -1.08421006871295, 0.90458768576091, -0.0974889838836657, 0.343124081719593, -0.0737261282824574, -1.07776962765302, -0.533308770675161, -1.30940543824619, 0.30919167449721, -0.19663321750018, -0.11058920508987, -0.286106658185972, -0.692350235470158, -0.177221975014794, -0.0036473758111797, -0.300598304711216, -0.677266238419372, 0.10110312439087, -0.0598839760112864, -0.497809069737035, 0.152464734696248, 0.348868155923537, 0.153910093277228]', 4.49); -insert into credit_card_transaction (time, features, amount) values (158009, '[1.77605423354843, -0.643944145159802, -1.16405697582766, 0.546213485659379, -0.175210218972686, -0.389591746147173, 0.0051497998833683, -0.153794950607152, 0.77260234122879, 0.0232261679929539, -1.06528075396715, 0.173686120412681, 0.0086044950463042, 0.150746727001186, 0.345403216716222, 0.188709383093358, -0.506428144770819, -0.251381530104047, -0.0921158114932612, 0.0996194116509905, 0.0305268134628971, -0.118706296972696, 0.108339322874396, 0.599722082980315, -0.21176556296923, 0.188068516027917, -0.0724443369684532, -0.0236568974723718]', 148.75); -insert into credit_card_transaction (time, features, amount) values (158009, '[-0.961235578939082, 1.33817544647597, 0.657262789394844, -0.497486396693, -0.730714410453866, 0.722049906975452, -1.60756288287889, -4.78567532423441, 0.828029747227186, -0.319231028145593, -0.933227880147206, 1.16983614590807, 1.16989282968414, -0.312015090251343, -0.108449106648623, 0.326413109547181, -0.255271208278592, -0.0871572715591543, -0.764758183230007, -1.04888230191168, 4.79202047276388, -0.720301638569118, 0.218132920417395, -0.0470787182790086, 0.763649384130085, 0.735270054982837, 0.36915484211879, 0.273405387017759]', 29.99); -insert into credit_card_transaction (time, features, amount) values (158010, '[-0.359846842014646, -1.72306592785694, 1.04928893390916, -2.31785954793245, -0.932436687283213, -0.135419624087709, -1.19918557691809, 0.18223634351014, -1.01464488811998, 1.00168115114308, -1.50766584860569, -1.58777813764519, -0.312910934496231, -0.853604094235265, 0.0756591824448081, 0.0901607754723302, 0.118832783990921, 0.616825711553791, -0.597274273125863, -0.448238221523313, -0.0215206771846747, 0.371009154709892, 0.637866626028848, 0.534466539068606, -1.04342233194524, -0.38195944404197, 0.0955265517133887, 0.152541512702937]', 67.0); -insert into credit_card_transaction (time, features, amount) values (158010, '[-1.2542814057946, 1.20096307133381, -0.627200807531874, 0.671479997644877, 2.30684078562474, 1.47195996916669, 0.980373130511881, 0.596089708960187, -1.14954783298045, -0.871663207720353, 0.876826509380834, -0.301796587205867, -1.27869630236082, -0.53208179407442, 0.268003910341743, -1.02942905140882, 1.79907100553185, -0.0706723660211838, 0.297031260110904, -0.148100374181437, 0.0220516010513153, 0.304048937035024, -0.308586510007307, -1.08225409006223, 1.01559518865203, -0.12965653868741, -0.278113051461387, -0.267037202557645]', 30.21); -insert into credit_card_transaction (time, features, amount) values (158011, '[2.10114312153406, -0.131633889284133, -2.09444043711982, 0.202531844329187, 0.736451528296812, -0.501846626088548, 0.413759428167791, -0.274836296105806, 0.49347684412016, 0.10139639854721, -1.57536354832683, -0.191761002854347, -0.516013680327826, 0.471888064322938, -0.24276731060148, -0.36696166759536, -0.264130483177789, -0.600831418464043, 0.401751198253923, -0.185175887839243, -0.0756203432825797, -0.101839504363857, 0.0214987019545058, 0.0714925771207879, 0.25129259337617, 0.573086957506978, -0.106701465881401, -0.0751004318541749]', 24.94); -insert into credit_card_transaction (time, features, amount) values (158011, '[2.13568645962781, -0.0495722266166086, -2.42561905467689, -0.250896037581784, 0.80652073476973, -0.877499997940161, 0.525600500430951, -0.251580495866916, 0.228290445740574, 0.237081672505878, 0.357697356019724, -0.177064565613102, -1.84575614751461, 1.31960087365334, -0.0600074678519535, -0.209694419357159, -0.588194831094848, 0.342498404005647, 0.587283682180758, -0.307577557991362, 0.142580642397469, 0.409347190412612, -0.0502162249690347, 0.290028895538371, 0.428879347821436, 0.220688853255967, -0.106299269096564, -0.0907389372021451]', 0.77); -insert into credit_card_transaction (time, features, amount) values (158012, '[-0.356112107485342, -0.176792234424064, 0.667073479330746, -0.832209868478933, 0.708046902364393, -0.556373890222478, 0.84391850402528, -0.140145781725371, 0.396220800911885, -0.598178788054038, 0.164846278986967, 0.0477260492905488, -1.50444726395879, 0.202073972005627, -1.1673127114867, -0.200155807497776, -0.593045242449931, 0.228665426373271, 0.559031887936197, 0.076144266555552, -0.103606206643723, -0.289182382264244, -0.0357451605996312, -0.370219303277823, 0.18072485751449, -0.108404918136018, -0.239703048695415, -0.257559850365974]', 68.45); -insert into credit_card_transaction (time, features, amount) values (158012, '[-0.115623294131462, 0.232952497287794, 1.54391073546632, 0.74175325796478, -0.408977914119821, 0.875809943582535, 0.524788492741967, -0.067408140031601, -0.510123806832224, 0.233755923793785, 1.2133921555289, 0.591021490450145, 0.943774719526892, -0.138164975040216, 1.45782503054464, -0.47189508525955, -0.0484905554283102, 1.01933839962322, 2.65449992273842, 0.727916336802697, 0.334267314456189, 1.06185604724004, 0.0773724916852188, 0.858019182195634, -0.523388914381481, 1.01915778703403, -0.0535869079019798, -0.0628129239951077]', 139.0); -insert into credit_card_transaction (time, features, amount) values (158012, '[-1.36319602377002, 1.46744250567976, -1.80801440252905, 0.758068498733319, 1.91363288695622, 1.26347372708645, 0.534051079649939, 0.971553749657575, -0.831576539740343, -0.551426446125783, 0.665632218797952, -0.0221423444694377, -1.1769746116895, -0.263322643684293, 0.0524271682594856, -0.905754215946917, 1.86084049587924, -0.0554157576697577, 0.128724314473812, -0.276268762354191, 0.1178831286758, 0.62066415939755, -0.080968923661723, -1.07924656287613, -0.0869949100703554, -0.332134232365957, -0.12029706944578, -0.146111970160301]', 32.79); -insert into credit_card_transaction (time, features, amount) values (158012, '[2.06804013207811, -0.854566234202144, -1.48438270459897, -0.952948646598933, -0.293969763362184, -0.761562206676964, -0.172659366138343, -0.29596589214731, -0.858394409898638, 0.898922909951742, 0.906730502052593, 0.646359344803653, 0.940969290991741, -0.006479051868868, -1.03698810719985, 0.822421675294992, 0.0312538227132215, -1.45701291092015, 1.14063774461727, 0.148278489067593, 0.111625309179023, 0.234895744286238, 0.0789322648857008, -0.357476182162683, -0.0073477595872901, -0.282854187904493, -0.0473919080405555, -0.0641320545480188]', 76.48); -insert into credit_card_transaction (time, features, amount) values (158013, '[2.0298433000459, -0.0880601458885333, -0.902333329835496, 0.522586204628432, -0.406609334198378, -1.46985201784382, 0.152797528570979, -0.32675532491943, 0.607351021649553, 0.0905275170575396, -0.470746065389009, 0.244645641298072, -0.636108789216364, 0.425669978145497, 0.0780593327541418, -0.198645989990932, -0.0989181095164906, -0.930120634541996, -0.008975555400264, -0.275783044998366, -0.26801840623418, -0.673364996689796, 0.398815001102551, 0.442669552427606, -0.376303691551718, 0.171754984141973, -0.0745017228674723, -0.0567975559072154]', 2.99); -insert into credit_card_transaction (time, features, amount) values (158014, '[2.19059184936535, -0.667482517987159, -1.42159182025015, -1.10895976920009, -0.20580177735733, -0.607630452654572, -0.421494377090815, -0.217884168919408, -0.942945048297514, 1.00890578671234, 1.28341729358577, 0.53134788831271, 1.02225607847444, 0.0392922229142589, -0.383960015434374, 0.995536083170316, -0.111521365971314, -0.98056107619905, 0.638013238757741, 0.0494848082164501, 0.494216601009636, 1.43343627056651, 0.0128038517785256, 0.789275948935685, 0.205997556340949, 0.0158576375863187, -0.0379919969562041, -0.0677634987861634]', 10.0); -insert into credit_card_transaction (time, features, amount) values (158014, '[2.15772500725235, -0.565010808070048, -2.25210028245371, -0.656838100190328, 0.417949337253706, -0.540404973914572, 0.221306383120983, -0.358830724316406, -1.22462923514464, 1.08842683843672, 0.348654895460532, 0.82697007233589, 0.874521347191276, 0.451709193508456, -1.17860675540703, -1.8235023524484, -0.292778023880146, 1.13519833862308, -0.146309785478595, -0.464203163115534, -0.219075435481153, -0.0801340219061155, -0.0188162703987775, 0.347536337871168, 0.299916502243819, 0.796660422332797, -0.108067714557822, -0.0812456414352052]', 42.13); -insert into credit_card_transaction (time, features, amount) values (158015, '[-3.36075457165147, 3.61812371452389, -1.94380003937942, -1.55487797308058, -0.232721270330603, -2.53741807883311, 1.45757625128927, -0.183662836138109, 2.22376282070789, 3.73364101164388, 0.0306710420874961, -0.0515998645066788, -1.14900357586303, 0.019489090941739, 0.0378903246767697, -1.17582778113969, -0.119461564605101, -0.796937153800969, -0.860334658983379, 1.52647615757724, -0.155660517363271, 0.803622552577433, 0.03170527728366, 0.90911506442161, 0.18856085901733, 0.0112478529725959, 1.00255268080285, 0.289222071208658]', 1.54); -insert into credit_card_transaction (time, features, amount) values (158015, '[1.3286221109967, -3.0036285044689, -2.17104255519545, -1.20034493691271, -1.45192935372842, -0.685638827183179, -0.165426013547936, -0.360504694585152, -1.56723281385972, 1.6220540043684, 0.11072479290007, -0.991455493328809, -0.93758475467081, 0.342389105533479, -0.966093536062319, -0.60627681384665, 0.383972832245193, 0.867719706872176, 0.0571431139179858, 0.520741209728053, 0.518875265687279, 0.844124527807451, -0.573745259072927, -0.286280404572821, 0.156454063926388, 0.242699655877684, -0.127925786452998, 0.0030608193830294]', 527.0); -insert into credit_card_transaction (time, features, amount) values (158016, '[2.05188001302592, 0.0348865835982961, -1.82489028521084, 0.240945123039728, 0.538142561529563, -0.408024626839614, 0.0163465023580155, -0.0201352944127314, 0.388981338726039, -0.182906300289172, 0.714778317665099, 0.265502035502147, -0.856197533034902, -0.488854536653689, -0.376176553343842, 0.640811456881494, 0.165885139670378, 0.393193203430254, 0.459865414572454, -0.191719998725591, -0.342454882066987, -0.959505214956084, 0.301244264898468, 0.161487832110637, -0.278840486170047, 0.175496511657153, -0.0727473926089709, -0.0454994015328238]', 1.98); -insert into credit_card_transaction (time, features, amount) values (158017, '[-0.932059273777712, -0.134426462911196, 0.772692057775689, -0.747332254458257, 1.19363988055783, -0.754138038330834, 0.631763782720432, -0.0203658352550088, -0.080884974934663, -0.888336491273951, -1.22232470732149, 0.0678166073914077, 0.232688959664018, -0.0374107628237998, -0.458266111392729, 0.300523120014312, -0.789381105832364, -0.211169653621913, -0.750798062898426, 0.169673219492678, 0.140619500448844, 0.104309922915188, 0.144435330750445, 0.673637250217338, -0.228817445798648, 0.0526938306279889, 0.050418939379092, 0.183032605262705]', 70.9); -insert into credit_card_transaction (time, features, amount) values (158018, '[-2.89215053450099, -1.39625746956052, 1.53102495742112, 0.822701727139747, 3.16967084037415, -1.54518216175689, -1.1539309234839, 0.214378508190957, -0.221002770060266, -0.708907597819677, 0.703805330201808, 0.662673290680547, 0.373053554687829, -1.2312832915632, -0.261327853556574, 1.05033507632874, -0.148900721263542, 1.00884113579705, -0.0149744683411427, -0.452646117639742, -0.38385290241954, -0.89687542010848, -0.730306754353318, -0.579237341308403, 0.384479012881505, -0.832912674670711, 0.361005313543467, -0.0674958404769695]', 34.95); -insert into credit_card_transaction (time, features, amount) values (158019, '[-0.692113938530945, 1.31322905999001, -0.521201209439012, -0.483767039913747, 0.67528577528705, -0.341005212892133, 0.531521123077797, 0.544426676252537, -0.324382576289273, -1.32184205551676, 0.756413946595868, 0.412216372909969, -0.566762992698048, -1.25437059857952, -1.4893040650211, 0.356076111939148, 1.12360142067351, 0.844035830406707, -0.0358623447215515, -0.0457538598457172, 0.121183903330983, 0.488303121618516, -0.183195340392929, 0.624329253229232, -0.197622719380915, 0.533996954477075, 0.244057268454374, 0.197915897790865]', 14.39); -insert into credit_card_transaction (time, features, amount) values (158020, '[-1.12200628366799, -0.457950088985587, 1.67237441053119, -0.466082206773037, 1.0509684781632, 5.62615888306642, -1.64109782647114, 1.65423636512179, 0.273081740198956, 0.462746963666576, -1.34905623067453, -0.0081170819182522, -0.0293042269574189, -1.34096663940576, -0.899291556406563, -2.29331780809303, 0.536157017254091, 1.6854308044934, 0.0458828036695601, -0.0109095521174638, -0.314833804457018, 0.120776261416867, -0.287328935456076, 0.696121200950272, 0.580222236646483, -0.123866190255205, 0.585458586983351, 0.254846368895795]', 50.0); -insert into credit_card_transaction (time, features, amount) values (158020, '[1.69234571013859, -0.105039263484382, -1.91526204863659, 1.19088481394566, 1.18460904173727, 1.57559755895921, -0.42723589515588, 0.562465879341146, 0.522988426717505, -0.681035776184852, 1.30158377716841, 0.372918968991889, -0.495313231239861, -1.78386619476624, 0.711942108589096, 0.425689857371131, 1.42515544808223, 0.392682245258996, -1.35049741039887, -0.0994592504385012, 0.0480323632818154, 0.174183546075954, 0.107162479626003, -1.1691702782335, -0.232120048291807, -0.597588176590653, 0.0913160732796459, 0.0047357337573496]', 84.0); -insert into credit_card_transaction (time, features, amount) values (158020, '[2.27111082192535, -1.28664547506791, -1.28222705350878, -1.65792731670975, -0.834495361397583, -0.42737892521792, -0.90080684881993, -0.105961962166683, -1.62191843396148, 1.72129681576365, 0.706430219452338, -0.134978372766328, -0.0003340866483964, -0.0520930181934239, -1.24007007633913, -0.740913234887491, 0.51370308298751, -0.114014316456132, 0.356540648380577, -0.442595728371339, -0.342447581123677, -0.533457228659934, 0.345727790021545, 0.657011162039137, -0.224177716487093, -0.375518392670327, -0.0132068316186918, -0.0593780392408658]', 14.4); -insert into credit_card_transaction (time, features, amount) values (158021, '[-0.702790428181329, 0.720406636512539, 0.9342701622712, -1.14531501058955, 0.818452719276262, -0.946817662562218, 1.1817011012598, -0.273955036034273, -0.144021027767585, -0.201863325800114, 0.766480234566862, 0.345900909890859, -0.888688645175973, 0.209018387790344, -1.2726555744136, 0.171937737654069, -0.859793134888601, -0.273147939101213, -0.251707212339735, -0.0685826156312848, -0.25784613905826, -0.538555366533331, -0.153338765103057, 0.0576671923723828, -0.302110249263983, 0.0421762436224188, 0.0132382102031736, -0.0540165180394867]', 8.7); -insert into credit_card_transaction (time, features, amount) values (158023, '[2.07386596664826, -0.0574474764833047, -1.32266276285972, 0.378656051692918, -0.117837413212535, -1.39583096601079, 0.200316364078324, -0.358865810237295, 0.725053004880719, 0.0406563940631472, -0.831944067758982, -0.151727503312774, -0.786835606155431, 0.657393598233784, 0.833119699354609, -0.179442218962579, -0.451064184733163, 0.0363218537704614, -0.229172122366579, -0.301798890214492, 0.235533016070261, 0.80813268884773, 0.0117178195227804, 0.0603417932928446, 0.238485379956948, -0.108280379250893, -0.025032459774617, -0.0604760194003316]', 1.0); -insert into credit_card_transaction (time, features, amount) values (158024, '[1.3812998852291, -1.6855638790775, -1.08201980232882, -0.768956734741289, -0.343957063833239, 1.0631943685801, -0.569929512753637, 0.335112250965508, 1.55728818689712, -0.644782790504745, -0.131422013604171, 0.469188663830721, -0.0807469103033629, 0.123956521667, 2.11002619275931, -0.600274914180664, 0.346997049869918, -1.21251173073995, -1.12261428814145, 0.323980394680132, 0.421475242229477, 0.816282520366422, 0.0515997744700914, -0.268750315521372, -0.653431458245139, 0.743398326844738, -0.0446368027267562, -0.0085561300393639]', 289.8); -insert into credit_card_transaction (time, features, amount) values (158025, '[0.376337000790453, 2.34401765468442, -0.576319562992614, 4.9045885987752, 1.0852926797056, -0.317089445118758, 0.824636000873547, -0.112581024954758, -1.86334386252492, 0.989373105390264, 0.0655255369114273, -0.288828616498574, 1.40109531595254, -2.85582001679919, 0.469506442302996, 0.561961800837084, 2.24822993276018, 0.632002797602366, 0.71821352973162, 0.507300542421562, -0.422439867129738, -0.851232057797204, 0.157989934594824, -0.217006902765562, -0.623896764547443, 0.0459039196578555, 0.425447231332348, 0.147727991755193]', 2.5); -insert into credit_card_transaction (time, features, amount) values (158026, '[-8.96971251912099, 7.53597195525541, -6.72151102801756, -1.51089577092286, -3.46695390039357, -0.948142590776108, -3.5320288922753, 4.72719293847749, 2.28413423822467, 3.67262139954074, -0.524159638289884, 2.1812120584612, 0.483838812579013, 0.822944498549129, -0.795942554609621, 1.52218941426229, 1.66586784234829, 0.871112553522731, -0.705198513309069, 1.18506615693331, 0.0955160015746943, -0.329154839461986, 0.744203148916278, 0.0583801618215842, 0.580245760318318, 0.353083252758906, -0.336489738492317, 0.651645091340483]', 5.09); -insert into credit_card_transaction (time, features, amount) values (158026, '[-0.0411362706306996, -0.220560148922629, 1.01235482098296, 1.11926344898811, -0.191347078861543, -0.293937627356436, -0.315027408081702, 0.174625180849426, -0.0948211408189453, 0.351563338187937, 0.838693633451771, 0.150544230236316, -0.814295047056348, 0.496159370442463, 1.03577209695395, -0.492802671998233, 0.269642775324203, 0.62934993386594, 2.87077127932348, 0.395722073464704, 0.0301042715185565, -0.0356016327614129, 0.569941764458777, 0.064809932666515, -1.9540522843997, 0.474514196656517, 0.249768333200403, 0.282966840241029]', 59.9); -insert into credit_card_transaction (time, features, amount) values (158026, '[1.8845408705184, -1.57198622407464, -2.25834829501493, -2.73018100845195, -0.588552889794093, -1.25244283080556, 0.0726867763310602, -0.375652965145536, 0.568206332600148, -0.273289832238356, 0.928453011429209, 0.939874123010966, -0.399409675738461, 0.827767322163664, 0.395219513341256, -2.63354758679693, 0.0046985048432499, 1.78449470472491, 0.56281535280024, -0.2652998474271, -0.0908898959612222, -0.0091651937167342, -0.0738109272361255, 0.758319483504186, 0.262225115533907, -0.772610466459783, -0.009741585541382, -0.0305728896846595]', 185.96); -insert into credit_card_transaction (time, features, amount) values (158026, '[-1.40186451573321, 0.574414179400537, -0.699218351415311, -1.6998275291308, 2.89966487009745, 3.47599109876195, 0.167104800364399, 1.29806857954787, -0.776928707942542, -1.03902118088366, -0.379846397582771, 0.0569042573111709, -0.390457880345495, 0.666057129070605, -0.0462687491159509, -0.255127371692401, -0.0959822346000761, -0.792042207035525, 0.113453649669977, -0.0557637264872856, -0.17485256670988, -0.858522868763138, -0.258559338410444, 0.720468300050424, 0.646053055551408, 0.413605380465705, -0.290968039114206, -0.038218878870042]', 29.87); -insert into credit_card_transaction (time, features, amount) values (158027, '[1.98334362190362, -1.07499759743561, -1.23808722499258, -0.638798384443381, -0.369728599694053, 0.182272906699272, -0.594504544950383, -0.0131013261854548, -0.518791494926067, 0.966542363373287, 0.123198938808012, 0.679302664092877, 0.771246526746198, 0.0291464366636196, -0.528324940289719, -1.0063492969552, -0.645043921748145, 1.58412516262599, -0.287481492210106, -0.337297625911408, -0.352038911253586, -0.649017700078523, 0.181594043650614, 0.0971591189742047, -0.33270292384924, 0.49130019440509, -0.0597336253818767, -0.0453469733843929]', 99.0); -insert into credit_card_transaction (time, features, amount) values (158027, '[-0.479561088303501, 2.09727296588127, -1.83172350683907, 0.803337039943055, 0.864218865013255, -1.59468961077119, 1.03345438393617, 0.290785266154311, -1.35233075259922, -0.977477489635804, -0.687076195962851, 0.354528577870922, 0.696307980295894, -0.0219360327428018, -0.0845441177817256, -0.13141615423882, 0.923423744674992, 0.20292233394646, -0.386314441592495, -0.362055153651599, 0.334092880653461, 0.807311684264609, -0.166293985290652, -0.0853953199903552, -0.0303548168950653, -0.477985353791553, -0.252130120765253, -0.0055098425400003]', 3.99); -insert into credit_card_transaction (time, features, amount) values (158027, '[-2.26937494863406, 2.46896387958507, -0.552642600075627, -0.988644659117133, 0.160638344611072, 0.236830491934834, -0.922422071570921, -4.4312266201294, 0.149168549443, -0.227034492872218, -1.82019661818979, 0.158328577270348, -0.35385758462076, 0.630045288321782, -0.409353791676874, 0.201282263236349, -0.0468619105025272, -0.327261322718866, 0.208884307203662, -1.09095008228502, 4.34236306228897, -2.30014012987148, 0.592053677644645, -0.752815715798393, -0.145816859928819, 0.249402378844361, 0.261954109699018, 0.179065190459022]', 1.29); -insert into credit_card_transaction (time, features, amount) values (158028, '[0.218982140449111, 1.09790666776565, -1.74492772602432, -0.946471343041764, 1.698527879749, -0.906198693069468, 1.47825586101997, -0.182782704675715, -0.668852024240003, -0.519143300728539, 0.534119705382849, -0.407273312819681, -1.12592269750011, -0.275903173647229, -0.71293008682192, 0.431733235906333, 0.100543417670423, 0.789486965485517, 0.0046360903011481, -0.0180003806083725, 0.137315102116296, 0.455681217692153, -0.185570914500965, 0.13173064984024, -0.311413742189966, 0.633974270852576, 0.257281702739795, 0.161364179377333]', 15.5); -insert into credit_card_transaction (time, features, amount) values (158028, '[-1.37985804980739, 0.793973966478004, -2.1841182593307, -1.58662976300357, 2.17592277366205, 3.43477240992112, 0.0423904108320659, 1.61455694935254, -0.402392264638262, -0.711041771121262, -0.612084855682658, 0.334480768591291, -0.267668714270779, 0.927676030968783, -0.316998046893873, -0.100010013617603, -0.0788829651085887, -0.761822095513528, -0.093670397730602, -0.227448774184604, -0.0631493809295078, -0.402987665249253, 0.249758537636261, 0.716907766776778, -0.758521617301839, 0.154248383742078, -0.0614147152215703, 0.0987632617967819]', 83.14); -insert into credit_card_transaction (time, features, amount) values (158029, '[-0.362211311239705, 0.429058175354956, 1.45910877608664, -0.415063083819598, 0.376753437707893, 0.247101576037765, 0.463892835130038, -0.168525855002821, 0.60254735519351, -0.549286374314341, -1.00851993805448, 0.371509925091531, 0.969895138476047, -0.696979819763335, 0.383786008987526, -0.289351076966226, -0.572426595982439, 0.322956910629434, 0.136455979419392, 0.0475111121403775, 0.300434754479481, 1.23722991434846, -0.30200509706785, 0.673191650282243, -0.268942091685096, -0.189464925216867, -0.0615280978292815, -0.041777109568563]', 29.95); -insert into credit_card_transaction (time, features, amount) values (158031, '[-1.17359609832539, 1.31219367933074, -3.45825634278, -0.619697079736893, 2.66309870331589, 2.91628165771074, -0.0232599555609482, 1.82143301701985, -1.21791988415161, -0.649555761964068, -0.67266631753441, 0.328805727364899, -0.219406734016554, 1.78852807794834, 0.0005214058168281, -0.0687095149492227, -0.202580910778195, -0.295119678913572, -0.759983936367472, -0.657311385180601, 0.365553495274159, 0.61929703867544, 0.188888054422954, 0.697252809401397, -0.199772198646894, -0.645708812586734, -0.407238142613834, -0.268139018826796]', 27.0); -insert into credit_card_transaction (time, features, amount) values (158031, '[2.10703262019669, -1.11519976824871, -0.405904513230341, -0.835567684152946, -1.35262247270329, -0.631244740815227, -1.16879948577003, 0.0554114562586086, 0.0750603357167312, 0.949686885904241, 0.726186662830209, -0.479265705127159, -1.24110687068457, -0.0137108318703954, -0.388079653768245, 1.38052206022577, -0.0020924332498371, -0.522249754710248, 0.705432581462696, -0.10657250734388, 0.366803408279533, 1.04190123558376, 0.14886721567695, 0.078629065065693, -0.239717780927028, -0.108852687044709, -0.002471993601708, -0.0594965189145242]', 14.99); -insert into credit_card_transaction (time, features, amount) values (158031, '[2.03536201944366, -0.154987712698983, -2.9587481513792, -0.576317086765721, 2.60688279192775, 3.1435447970342, -0.413552119246551, 0.783741468086949, 0.35960673565204, -0.352244168884697, 0.329686844837848, 0.183611504312773, -0.272471045586356, -0.596868411176443, 0.584212566926748, 0.17900689176916, 0.473972692508747, -0.498335531622195, -0.140900354260615, -0.11560251899467, -0.350812914111748, -0.998261522870848, 0.361272593229977, 0.604955364070343, -0.265481196698076, 0.219402950201712, -0.0396837084348813, -0.0423499198869141]', 4.49); -insert into credit_card_transaction (time, features, amount) values (158032, '[-1.05024221264022, 0.0025401599929001, -0.85418081044805, -2.48765266834124, 0.219093791364313, -0.603868852709712, 0.293886967238672, 0.305268281916422, -1.23659347166536, 0.416070428206051, -0.27696033239687, -0.436862379417214, 0.213481272883072, 0.25674137351867, -1.08280971519994, 1.73422355424759, -0.674230652189816, -0.297489644820476, 0.285521398692345, 0.216416453083641, 0.535336523504374, 1.44054410815674, -0.317221551372596, -0.978726662973967, -0.155548364571756, -0.0847672490390446, 0.428207540143884, 0.192653197490518]', 92.8); -insert into credit_card_transaction (time, features, amount) values (158032, '[1.90167182036578, -0.0647195001622905, -1.63861508134985, 1.43640591990439, 0.261252439525088, -1.07592324896262, 0.61446466869174, -0.355135298819051, 0.383589825877924, 0.248684797271174, -1.19628967061793, -0.213227125200212, -1.22287295610631, 0.716743752258148, -0.35906352334014, -0.61338219693596, -0.111828183856228, -0.508697174021479, -0.210014328323246, -0.228711088928778, 0.0387730037056437, 0.13760484705351, -0.0228478330306491, -0.109929886045315, 0.348948123430657, -0.534909903086685, -0.0298987755607366, -0.0512705504925316]', 73.91); -insert into credit_card_transaction (time, features, amount) values (158033, '[-1.6449835220238, 0.676857125738824, -0.641803229754665, -0.979810092173884, 2.13515893526295, 1.54144440260202, 0.668270006419728, -2.04957136291005, 0.897611610687022, 1.43824335174584, 1.44553893561281, 0.675702938312644, 0.0612233185862741, -0.240336194394959, 0.813795754964867, -1.29579082087597, -0.286346784597244, -0.766463811282719, -0.604375934118076, -0.544029249675438, 1.74304874744952, 1.29832922272758, 0.451478315058192, -0.713430341074749, -0.885625926989528, -0.255318895472629, -0.394642415030952, -0.0821596998051062]', 2.21); -insert into credit_card_transaction (time, features, amount) values (158033, '[2.0570677358863, -0.973300264074425, -1.54151461408459, -1.14665295726593, -0.19470576155852, -0.312563887359672, -0.412593350862231, -0.189196216674687, -0.842893009744399, 0.958963045754405, 0.830056670552292, 0.393755910846297, 1.16428631465264, -0.0372803419834995, -0.302300341671561, 1.31838452480115, -0.380857623001207, -0.736159049996304, 0.864286623153643, 0.248723554463887, 0.429156000647478, 1.03119374123013, -0.0511204869894362, 0.351594557933091, 0.113794501239562, -0.0750378095262471, -0.0492702168473531, -0.0520609687206832]', 95.0); -insert into credit_card_transaction (time, features, amount) values (158035, '[1.59584958501531, -2.35921708123694, 0.483229406165788, -0.335229768345118, -2.16421323035442, 1.13455323929928, -1.98493022637826, 0.525184293765458, 1.43379378232765, 0.445542841269327, -0.0837875030561063, 0.38353532505258, -0.53076877397851, -1.38772587152528, -2.37556323741882, 0.959248718006741, 0.505523951697418, -0.487885396684577, 1.11334643248188, 0.38075929272823, 0.460185925483974, 1.22933945583353, -0.0320707110079302, 0.837740490895204, -0.356425902314491, -0.0548470026180815, 0.0417136861389353, 0.0005329629137676]', 225.5); -insert into credit_card_transaction (time, features, amount) values (158035, '[0.0566021745191798, 0.951098353437786, -0.324917580352524, -0.615017590159592, 0.963199567285392, -0.609298195137936, 0.869264722914242, 0.0165292763594911, -0.351598965802727, -0.671140867571411, 1.16686148455664, 0.750322686533213, 0.152092828571542, -0.86037437195677, -0.974831883207936, 0.477710990373779, 0.149119160237306, 0.208631321480512, 0.0096100439429732, 0.0605345008608042, -0.272931553934858, -0.680832370963663, 0.112028300919858, 0.667083758743021, -0.456710585780856, 0.0857316915837108, 0.217644616221604, 0.0772180147410612]', 5.99); -insert into credit_card_transaction (time, features, amount) values (158036, '[1.37166443259712, -1.11021453135428, -2.12965919689448, 0.577863463863569, -0.189423993257986, -0.669839314585188, 0.317641621828778, -0.0826023233275789, 1.00660845749559, -0.831872204858817, 0.723187944050703, -0.0213423674863225, -1.85589857447857, -0.992139459844658, -0.51679684880317, 0.379995787423229, 0.988287183417761, 0.864674461658353, 0.352855632853052, 0.373842235715342, -0.0442693053525782, -0.697175702504967, -0.123269472388493, -0.554202338304981, -0.241485533441161, -0.11090445837269, -0.0776978691668765, 0.019915980712503]', 329.75); -insert into credit_card_transaction (time, features, amount) values (158036, '[-0.848132112847811, -1.37741691535354, -0.483287887917608, -2.8677557216457, 0.160810180395217, -1.35355120274205, 0.955147119570841, -0.33043950181277, -2.45035025166664, 0.64430088257854, -2.1846429107193, -3.11501515284984, -2.56219291840295, 0.639089315121884, -0.469331325840908, -0.461257390784567, 0.232887105661091, 0.398929582677185, -0.486526548409494, 0.0068392871085084, 0.0776555965243466, -0.0950931954148426, 0.134249179747713, -0.756083218207173, 0.596374994164938, -0.0176637952921578, -0.0671055523432867, 0.107939417872924]', 212.0); -insert into credit_card_transaction (time, features, amount) values (158036, '[-3.05661614363048, -0.925224110668674, -0.0263192523562169, -0.786261554545787, -0.107190115723014, -0.755997836327521, 0.35656638166816, 0.935692834050907, 0.0134966500442507, -1.56590009666917, -0.543473301292723, -0.61088280554071, -3.18765283312174, 1.39810193041292, -1.14833698987461, 0.463934357611409, -0.193650888427685, 0.548328515952565, 0.244120941268683, -0.402671632722606, -0.0613502519687377, -0.687308147826808, 0.0312355883625691, -0.38691925716432, 0.833368448478289, -0.0444888432940726, -0.184565333095616, -0.600208999178454]', 120.75); -insert into credit_card_transaction (time, features, amount) values (158037, '[-0.0739888344128354, 1.4086829888292, -0.714582542706148, 0.997097935627811, 0.476138902435877, -1.32199346330527, 1.10559822160598, 0.0665682378070395, -1.34542812726404, 0.0300651504594178, 1.03830567842148, 0.624854959132702, -0.613251955221646, 1.44707453390369, -0.504046184324323, -0.699419998362678, -0.0366453172997912, 0.283501885756301, 0.605847345023067, -0.256643935477219, 0.437758138153104, 1.20560255392758, 0.0314273144179835, 0.549898660497841, -0.918290936224458, -0.583786191478743, 0.152652206651162, 0.206205322688217]', 13.56); -insert into credit_card_transaction (time, features, amount) values (158039, '[0.0027886393703686, -0.246172130247548, 0.432182731679725, -2.19237956717741, 0.321394057013514, 0.594958072348222, -0.16572393463533, -0.147374491780634, -0.493200471846075, 0.775866716544824, 0.188588081878574, -0.043540043924062, 1.07454308236404, -0.979852863359727, -0.844954857473175, 1.46500106484545, -0.705396584600766, -0.46431381343931, 0.797086909295227, 0.0664926982253571, 0.366367093987032, 1.15076631765794, -0.263078949164154, -0.14935882692341, -0.311047239134237, -0.222004127980555, -0.495862493857952, -0.212741970218743]', 24.99); -insert into credit_card_transaction (time, features, amount) values (158039, '[2.16419493082148, -2.00104284658433, 0.37760078887389, -1.47306988582828, -2.03670395092928, 1.03648682131037, -2.46071020717002, 0.454148486037529, -0.0892711512372141, 1.46798399922231, -0.225823228621129, 0.0726147480521411, 0.559564067320394, -1.37269953202828, -1.55722493210918, -0.0699723044720499, 0.216558915704659, 1.05860125324494, 0.26704623134624, -0.37299309833219, 0.0114172849385955, 0.743688007541658, 0.204592219008939, 0.368546668543463, -0.390333943608661, -0.0559280122208667, 0.093931236134012, -0.0327800085965102]', 18.95); -insert into credit_card_transaction (time, features, amount) values (158039, '[-1.42571176165928, -0.761333263622105, -1.66947983257245, -2.51419912602983, 3.50558649833876, 2.40104651024928, -0.427789419682642, 1.16632274532313, -1.93349121646105, -0.244198425191946, -0.440168854260717, -0.199515450211599, -0.0258042250628068, 1.07450571891906, 0.403130376925301, -1.92707807057653, -0.0249710598933956, 0.888529135329965, -0.895422608450692, -0.230184592841364, -0.138303207387573, -0.594791209485464, -0.226214123717853, 0.698407015559469, 0.267324663082692, 0.0742725849543881, -0.0150263606499974, -0.1504438264428]', 0.95); -insert into credit_card_transaction (time, features, amount) values (158039, '[2.13248934754282, 0.185056806998615, -2.13576503203818, 0.291459747202838, 0.65576440856261, -0.933549359540901, 0.245727499169464, -0.325141942179795, 0.674203962620894, -0.4675105621698, -1.29217289433744, -0.32037648033182, 0.101098181372744, -0.775868465336214, 0.982090739679764, 0.5090970742339, 0.0231045264026084, 0.847991634117938, -0.0399279883164512, -0.179944322138216, 0.125704534431823, 0.544289216361839, -0.147053448049202, -1.06955894178303, 0.389778295805663, -0.0386269905933658, -0.0040235625872427, -0.0420075917906744]', 2.39); -insert into credit_card_transaction (time, features, amount) values (158040, '[1.93071818096019, -2.1262985915603, -0.562190042262186, -1.4455218532364, -1.82450252361202, -0.124037055005639, -1.45575427286702, 0.0155392181642128, -0.957051580803472, 1.62432324368829, 0.213048359491319, -0.303107164840523, 0.241484681918027, -0.515757461364103, -0.756392570310974, -0.0611778675400904, 0.0828598299394405, 0.971968833215396, 0.0220578874096559, -0.108266497907202, 0.172035792111545, 0.698651196919579, -0.0254000635636389, -0.322349843871649, -0.265073476103063, -0.0042389602053724, 0.0102038961761064, -0.0283918397818033]', 173.19); -insert into credit_card_transaction (time, features, amount) values (158040, '[0.162509218802761, 1.08802975471127, -0.479260243527288, -0.599334149389565, 1.07314605318904, -0.692843559943088, 1.03308275381776, -0.142439804949978, -0.151174590384665, -0.858677568184693, -0.74971150340878, 0.221683454733099, 0.816425535030794, -1.18375945087461, -0.308493788149635, 0.358094766225378, 0.244251032482099, -0.240543305875597, -0.154092859470752, 0.077918170415628, -0.346172244771247, -0.810638330925273, 0.0631315141210395, 0.390804827771353, -0.365837069660957, 0.122772471859586, 0.226677785884346, 0.0838988207694406]', 4.95); -insert into credit_card_transaction (time, features, amount) values (158040, '[-1.46807680106721, 0.467623126420621, 2.45083236371981, 3.20817626336865, 1.56031755775091, -0.929101125469001, 0.790742331611271, -0.208926196557915, -1.6909262621155, 0.637981618249925, -0.688561439677695, -0.0625944634063719, 0.0782913373552517, -0.322584496777146, -1.86626015516544, 0.022072553466161, -0.308665818393793, -0.716260989603198, -1.68950103181656, 0.199631019272556, 0.178867090541067, 0.441549696551428, -0.277427413056125, 0.939775631601582, 0.854239509749194, 0.131670153407918, -0.200910210928901, -0.142277778306537]', 18.96); -insert into credit_card_transaction (time, features, amount) values (158040, '[-0.554663867441918, 1.69598933859823, -1.11751215491975, 1.02949087125493, 0.177269366320355, -1.39145947157606, 0.711667832128233, 0.45522170735753, -1.43940361356781, -0.0763629328989788, 0.89993116461054, 0.789421333501349, -0.546852991522995, 1.72789128520947, -0.531925837041507, -0.587260606350829, 0.125424636881326, 0.309455955225973, 0.606178578326564, -0.405067450045686, 0.490366604813421, 1.18907777001833, 0.0497586618628577, 0.552244794856709, -0.91496791959085, -0.59421363851772, -0.091770616237237, 0.123215519009794]', 11.92); -insert into credit_card_transaction (time, features, amount) values (158041, '[-1.76293392713379, -0.0420766603235875, -0.585828673472461, 0.419884423094998, 1.45235514549013, -1.07393606458466, 0.378920224620948, 0.157588740953506, -0.49489869800209, -0.770181841878987, -0.739469022666234, 0.195870829186762, 0.842697240381394, -0.786023912161699, 0.419795631327136, 0.0091587169612489, 0.850120653607785, -0.0105339190085261, 1.21130647772201, -0.349613764650356, -0.314036678559929, -0.492210717579355, 1.20930297670168, 0.494998852989626, -0.410117916050452, 0.298732601406856, -0.13987742712738, 0.227970504647912]', 1.98); -insert into credit_card_transaction (time, features, amount) values (158041, '[-0.0441639798911216, 1.09760257862115, -0.926787159178486, -0.0654949702765529, 0.260679461168122, -1.25691893862939, 0.728401977120678, 0.147748308551425, -0.190933239023631, -1.20196357405327, -0.773128563327046, -0.370485092284141, -0.448474787024962, -0.394868511957962, 0.748157441057619, 0.158706252858903, 0.658645386224814, 0.739165590316672, -0.241773195410174, -0.188618207477022, 0.361979211952857, 0.972935637098266, -0.0485278626837927, -0.166174166003259, -0.348512492892967, -0.145310073569738, -0.0146182766926823, 0.0390811186475384]', 42.81); -insert into credit_card_transaction (time, features, amount) values (158041, '[-0.824361656394776, 0.738153775557966, 0.877998518925298, -1.40715195623649, 0.346294930358104, 0.458448638273054, 0.553576376107043, -0.0527763649874379, 0.981085546524477, 0.17871846817522, -0.0439714728804402, 0.313895261533906, -0.0903441662407898, -0.448423124156698, -0.174655441094708, 0.576735499437365, -1.31456583384812, 0.557798182305857, 0.443348021724407, 0.103890871339873, -0.288169801469596, -0.507147311558589, -0.161148185186428, -1.19487435638729, -0.0739794417946125, -0.258828922296431, -0.158334102168078, -0.109956373101282]', 38.52); -insert into credit_card_transaction (time, features, amount) values (158041, '[1.96625483088915, -1.53752348140964, 0.0243053303304094, -0.822982318869676, -1.60397314416749, 0.144384982394338, -1.63053698969458, 0.187319170048801, 0.708983410720329, 0.651032277238713, -1.16052174914491, -0.830562476265344, -0.0403551176648998, -0.78516558576119, 0.749786415317184, 1.77989603443373, -0.167855432634068, -0.498686097418137, 0.244213521840766, 0.170775184372445, 0.454294206283303, 1.15351758828884, 0.13360739886429, 0.601060331973767, -0.423266284386191, -0.122578046037241, 0.0310195519724147, -0.0117926489430764]', 99.0); -insert into credit_card_transaction (time, features, amount) values (158042, '[1.99629600233142, 0.0351417045860207, -1.75608476523766, 0.561395464021629, 0.05403683856977, -1.46016650143182, 0.214359028075343, -0.30973308887363, 0.766861742785519, -0.457655169974517, -0.501588071716564, -0.548707260035861, -1.19397518439081, -0.479896337484598, 1.07916284788365, 0.203264208736131, 0.521842251297097, 0.562263593416986, -0.504878930275455, -0.235087375541727, 0.203838501122883, 0.653543328575067, -0.0227829135917265, -0.108194162621486, 0.188169175317524, -0.0971691365269092, -0.0119832473075463, -0.0296145365046353]', 29.98); -insert into credit_card_transaction (time, features, amount) values (158043, '[-0.457777589303788, 0.798486572321378, -0.57750546940168, -0.747448840222225, 2.10762988654929, 1.05723194085689, 1.02837833793358, 0.405471526952467, -0.384498732900626, -1.34184348350663, -0.177522764625974, -0.799508659531795, -1.84487697413551, -0.45616078819072, 0.593325848387299, -1.38026916518166, 2.0117863066503, -1.83451224024327, -1.4970597069453, -0.275185231506541, 0.0827588213761465, 0.38856542006845, -0.144280108382553, -0.766350530839447, -0.2640333501296, 0.637221123841715, 0.116934620305455, 0.145000633495933]', 12.99); -insert into credit_card_transaction (time, features, amount) values (158043, '[2.04927596201142, -0.0490032104957632, -1.32290356639624, 0.382513045283908, -0.0691618382140238, -1.37476441471411, 0.264296910452165, -0.401378697764927, 0.619202987636985, 0.014370553501562, -0.714263967296096, 0.215226723532476, -0.0955526031496355, 0.523221493991925, 0.759162336303115, -0.210046954001096, -0.490049672569432, -0.0455446401694726, -0.237972624037573, -0.231202796562971, 0.251325507941943, 0.857701549835788, -0.0080011997298862, 0.079871663432282, 0.257027344310482, -0.111974569951064, -0.0229829349259743, -0.0567345504399878]', 13.99); -insert into credit_card_transaction (time, features, amount) values (158044, '[1.96174359236974, 0.007208771153347, -1.84440280072034, 0.250383138783817, 0.677941074473482, -0.263530471153249, 0.169870672522184, -0.0980095268189798, 0.134735092773077, -0.259575306826791, 1.03750659363432, 1.1562959489835, 0.788697494550978, -0.800281786954105, -0.502622842489987, 0.513588924794929, 0.126607196026686, 0.114828788842056, 0.366525997111099, -0.0050637961386726, -0.292246302737941, -0.825941956542132, 0.249277137229631, 0.149054557132857, -0.253030169833617, 0.171094043764246, -0.0669937279248558, -0.0351393081699311]', 44.99); -insert into credit_card_transaction (time, features, amount) values (158044, '[0.0369544338564517, 0.928230745931255, 0.278472478307022, -0.6181713562497, 0.552089585121511, -0.962948636926338, 1.09179132781791, -0.242033601750856, -0.210762353668994, -0.456567184108027, -0.750728493546413, 0.720437166366282, 1.12448339638087, -0.105948757158573, -0.471907240253493, -0.181979237867702, -0.441466642457278, -0.948212500306135, -0.137955858214439, 0.0372664862704724, -0.244174050641105, -0.470204602245057, 0.0647634158430095, -0.0609980753713009, -0.455773018004239, 0.143925761934615, 0.255991249852423, 0.0987592388082234]', 8.01); -insert into credit_card_transaction (time, features, amount) values (158045, '[-0.309247483098739, 1.00180543151555, -0.268309483740652, -0.764525748135804, 0.30736749719437, -0.584977839035211, 0.52192956943199, 0.430220407997166, -0.349112661676105, -0.451880996120532, 0.0940258508189762, 0.501754560402765, -0.541727087117274, 0.718390767281084, -1.04075934202735, 0.393813694690724, -0.629476587820414, 0.017703039556694, 0.383052416101266, -0.149658251674726, -0.201894687053612, -0.607547921314458, 0.0755701453189772, -0.518071279415494, -0.449754933102611, 0.154741641550326, 0.111154019729223, 0.0198264595129384]', 9.81); -insert into credit_card_transaction (time, features, amount) values (158045, '[-0.861206293696744, 1.03840094345116, -0.0331518723369128, -0.227256311042534, 0.769609492432418, -1.28917532680993, 1.08322060697039, -0.262949962431265, 0.0191922594439277, -0.771674877911098, -0.568950376387317, -0.927775252572413, -1.11075281664584, -0.794593032513192, 1.01384092783818, -0.0120384563152488, 0.685024783604102, 0.787607003775575, -0.0814872069408404, -0.11698872077387, 0.199215877877277, 0.815216801855523, -0.203098080565496, -0.10876863759699, 0.261067269158557, -0.0240388438237309, 0.17339120067972, 0.198801141968144]', 20.33); -insert into credit_card_transaction (time, features, amount) values (158045, '[-0.241626849940373, 1.28959858180472, -0.675589653785654, -0.593099148127863, 0.650708632277234, -0.633474241596401, 0.549143106783324, 0.422089887184249, -0.573524333475638, -0.904355130127726, 1.07846894840802, 1.09184884458219, 0.556076384963949, -0.615621009992703, -1.05386681770079, 0.583516991260149, 0.297428484314067, 0.201185829310297, 0.0033033562518628, -0.0490551327529463, -0.233169533810241, -0.66051166144719, 0.143389430904265, 0.676353174484033, -0.424787340651846, 0.0871579523421106, 0.0978955170621409, 0.0137272179804553]', 1.98); -insert into credit_card_transaction (time, features, amount) values (158045, '[-0.360654838129332, 0.860239140077136, 0.833754660217246, -0.813738756419872, 0.174019334423401, -1.78717448907624, 1.28810029926903, -0.394136592612964, -0.166884145380937, -1.02443143989489, -0.0930819371778737, 0.276586912712384, -0.220502040222885, 0.482987242076331, 0.365797234073995, -0.669498693569452, -0.236544429575547, -0.114863857577038, -0.550372372572943, -0.152980827438772, 0.410894791332264, 1.24272994902686, -0.277647658458909, 0.963613843902349, 0.113509161216559, -0.454053889841847, 0.140073907812585, 0.160139791806169]', 17.49); -insert into credit_card_transaction (time, features, amount) values (158045, '[-3.53061264689577, -2.88036025067832, 2.48195109539194, 0.303782237096385, 0.106190848692327, 1.59604326223454, -0.65241274174616, -0.071531605664762, 1.0583663740712, 1.13919412381556, -0.725774724313279, 0.229251375990574, 0.0095391553411392, -2.09053091334511, -2.18587516878431, -1.43005759226523, -0.589997329663525, 2.25432865405336, -0.169066252644082, -1.21209790907249, -0.667016139235043, 0.202018602813361, -0.576249320925147, 0.250359610108243, 0.568988161594735, -0.511194775072067, -1.25501508515865, -0.177785734716368]', 120.0); -insert into credit_card_transaction (time, features, amount) values (158045, '[-7.04967734500612, 6.22346067143712, -3.16210885614043, -2.93078263669895, 0.819725256439663, 0.907167432014108, 1.40949515131412, -0.316346097659255, 6.97153568748172, 11.2507301329479, 2.2539836102297, 0.286961107779601, -0.59256113251204, -2.82900272905902, 1.36281708448014, -2.26253952911196, -0.893503406472064, -1.25592328826542, -1.60373299502508, 4.58795856941289, -0.881544079669902, 1.20504394844206, 0.0899640482110283, -0.840246947557245, 0.43855777180815, -0.311546096646831, 1.71309115838051, -0.41100974427325]', 0.79); -insert into credit_card_transaction (time, features, amount) values (158046, '[2.03280521148798, -0.168190765778752, -1.19740790236069, 0.222570910849199, 0.0450715220504348, -0.632229879564578, 0.0144109738785781, -0.10256032771085, 0.4053759895739, 0.253956573307866, 0.598680787432403, 0.678560030317362, -0.644389038688123, 0.592825236760949, -0.514696437610703, 0.160241590234497, -0.563147167380652, -0.272859880216248, 0.492084245437282, -0.251979090847398, -0.26096010475533, -0.679069991790227, 0.301855495299331, -0.414057850402678, -0.322704645124882, 0.206222106217416, -0.0762715850543882, -0.0754284358975098]', 1.98); -insert into credit_card_transaction (time, features, amount) values (158046, '[-0.167328708744615, 0.502076965985162, -0.709248280147804, 2.25579829433559, 3.6076305178543, 4.32442509830559, 0.0167230489635649, 1.11206742536693, -1.45782426171965, 0.923083977421996, -0.93825461579807, -0.458739710733163, -0.398904425311608, 0.152294141167741, -1.30553933866091, 0.200734665852775, -0.538628486484938, -0.419112797255344, -1.20236012728672, -0.0119454230980116, 0.227399764661435, 0.539107130658707, 0.0571044265359236, 0.69271393766991, -0.450046241716516, 0.0627919859708296, 0.120056861862893, 0.111686189344893]', 23.18); -insert into credit_card_transaction (time, features, amount) values (158046, '[-0.93680125297717, 0.859082963929476, 1.72689963450359, -0.0290095443872069, -0.637650877659658, 0.390964874060823, -0.349630542134048, 0.652628937018306, -1.87298405265036, 0.438414407580365, 0.300511483751131, 0.622764293069369, 1.08783249743318, 0.190976536834424, 0.225631470433147, -1.09033863337755, -0.343087110161399, 2.16838063655658, 0.167883088615166, -0.238110339353733, -0.432455351083333, -0.797510216120741, -0.148756224400264, -0.421963063761307, 0.273705990076248, -0.601171207492508, 0.257915205607349, 0.0774009332947655]', 17.0); -insert into credit_card_transaction (time, features, amount) values (158046, '[2.22127820372406, -0.606952121788273, -1.08163741102949, -0.812094985770578, -0.605064504217847, -1.27659776047806, -0.285841705864116, -0.405988683176092, -0.491704396296431, 0.747800729002468, -0.566780159868413, 0.0276296278021145, 0.898440698637403, -0.267750013754306, -0.327325580132385, 0.718004819829924, 0.299590474079629, -1.99125619691934, 0.839432489506881, -0.0143138408481991, -0.0674357498789766, -0.11256806132735, 0.279088617023285, 0.0316343741291712, -0.147783149954189, -0.408919015437785, -0.0227827353980988, -0.0567106255960488]', 4.95); -insert into credit_card_transaction (time, features, amount) values (158047, '[0.140334742414108, 0.988536716225315, -0.39913377609429, -0.523617346642668, 0.826930136581668, -0.878958297900041, 0.937666113612492, -0.0782640919640309, 0.0453708461548768, -0.816716583438785, -0.758515857628307, -0.442860148532183, -0.640343034449782, -0.887126737244217, -0.172433734618616, 0.34844984073013, 0.419316581874039, -0.152017683604469, -0.242147742294824, -0.0205571594334353, -0.345192008527678, -0.878755970715596, 0.112053935430627, 0.611925790189547, -0.448163343997131, 0.111436880051032, 0.217763378815883, 0.0835685400772794]', 4.49); -insert into credit_card_transaction (time, features, amount) values (158047, '[1.98741635856846, 0.128297718328412, -2.17222660211076, 1.11094384247555, 0.884337849263309, -0.814837086085613, 0.770939534850372, -0.368249160134696, -0.0372762477405685, 0.356820413544879, -1.13526019154846, -0.357502387260932, -0.783769965767086, 0.944605702525518, 0.384289692996234, -0.309600368849068, -0.477193755203672, -0.269389977986895, -0.336905628926395, -0.187854210092217, 0.125253230408802, 0.285599029948867, -0.0498249382483703, 0.394706530777852, 0.474202643432056, -0.499132400391359, -0.0495449894196223, -0.0521092292615957]', 59.7); -insert into credit_card_transaction (time, features, amount) values (158048, '[-0.300214503768063, -0.162933334967322, 1.32280376377343, -2.1491562582558, 0.381065863994089, 0.420695885651061, 0.219582064290766, 0.0225290248874589, -0.986105706442055, 0.181843257650334, -0.0621327705881322, 0.125501422241847, 0.364053736803903, -0.409741505762836, -0.970637702110409, -0.596337336482429, -1.14063895094659, 1.64412959112626, -0.899804032264457, -0.381196919135105, -0.575682127897389, -1.15056464537517, 0.0713363197876743, 0.0299455931663197, -0.705442277995971, 0.0704700906509997, -0.0692445110013047, -0.07111458521595]', 21.95); -insert into credit_card_transaction (time, features, amount) values (158049, '[2.09644507153469, -0.97628501915331, -1.46967099413564, -0.933683538460257, -0.487283459784679, -0.822467214792926, -0.36957442003371, -0.195519694443509, -0.29032898064024, 0.801543153267885, -0.908640949075622, -1.26695290798688, -1.23151808465943, 0.277169586233122, 0.332156084126636, 0.960644268401542, 0.314319576797943, -1.66619766296907, 0.725841466824367, 0.0250899189457903, -0.0442838792750437, -0.401111799441588, 0.284259300269653, 0.548560319077711, -0.261505852847418, -0.451968848527957, -0.0572070505788601, -0.0429688784613449]', 77.44); -insert into credit_card_transaction (time, features, amount) values (158050, '[-2.59067914020312, -2.35241895396614, -1.7619579783047, 1.51625524879955, 4.53203680261981, -2.30853748647356, -0.965623926731461, -1.31056649496078, 0.243869709406191, 1.55446584399786, 0.138538627788593, -0.810841745165796, -2.80156387027333, 1.18790756444083, -0.277481165236819, -0.685625513197026, -0.354364602696192, 0.430311388125896, 0.87935192358108, -1.70295753996574, 0.713315849279896, 0.712502154921543, -1.28165113119589, 0.401344074019227, 0.0172723168803012, -0.237773722664883, -0.277590496289562, 0.487405951462239]', 1.0); -insert into credit_card_transaction (time, features, amount) values (158050, '[-0.513597802594165, -0.900232839465239, 0.948939260084391, -2.99525546951477, -0.410127710515561, -0.233223606751585, -0.0610858069325511, 0.0590393167763066, -2.32183656275408, 0.664965989769748, 0.410524041434846, -0.571771712453661, 0.0659077712868453, -0.343547555643415, -1.54247591534139, -0.157607814718721, -0.0308884208053827, 0.538091076306178, -0.502213441166136, -0.150921299869733, -0.0128573233440718, 0.0798718559156074, 0.102609192659194, 0.719569923844345, -0.110603106604199, -0.359399596808665, 0.0799190816076589, 0.143022081784996]', 91.6); -insert into credit_card_transaction (time, features, amount) values (158051, '[-2.13023270905677, -1.5787610410514, -3.18169207767389, 1.58934127730561, 2.34468346679763, -1.22881617450677, 0.56420619447076, -1.06631556579953, 0.179431262640725, 1.38374889535392, -0.0690767390556154, -0.819164044414501, -2.65579886961081, 1.36685207688252, -0.415556780821799, -0.564754087769728, -0.308750130676465, 0.640065275555576, 1.06815107645791, -1.97138383146265, 0.792487847206179, 1.52070117244493, 1.87644932367662, 0.259372910667783, -0.514925411724223, -0.35050775745542, -0.442688880779016, 0.420591471807596]', 1.0); -insert into credit_card_transaction (time, features, amount) values (158051, '[2.25128933702913, -1.56747961665041, -1.1070598754971, -1.78379937635581, -1.0040913843179, 0.0232423583873219, -1.28339247667621, -0.0007860213519153, -1.23932920190308, 1.72031788081058, -0.240128720740062, -0.563022207333322, 0.2154570346622, -0.287643782320593, -0.667349709543604, -0.047801968736155, -0.0766481917969821, 0.733799510311714, 0.410680159250432, -0.367735088827374, -0.155355252890769, -0.0146831024915894, 0.101382290890269, -1.12367561552489, -0.181764454384488, -0.130404525197396, 0.012031764639004, -0.0634510771239426]', 43.0); -insert into credit_card_transaction (time, features, amount) values (158052, '[-0.34115724595417, 0.964644552473398, -0.218134661888991, -0.730878570234816, 0.24526386085088, -0.585828250315211, 0.509356143248557, 0.455535300592884, -0.335946920521378, -0.458981005473889, 0.247058049490724, 0.478528671434084, -0.742229395067395, 0.76800348699747, -0.984676394798984, 0.30116596098137, -0.509819226998575, -0.0963832502607585, 0.255574101869458, -0.160263519787752, -0.185118558871185, -0.571858608991212, 0.112359243655117, -0.426056682340816, -0.488695524010144, 0.151080231497952, 0.112084019305846, 0.0194674519463468]', 13.99); -insert into credit_card_transaction (time, features, amount) values (158052, '[-0.119789318628698, 1.06133329649585, -0.603303593353997, 0.0259494895005489, 1.7279710086789, -1.73570033401657, 1.36606629010028, -0.794981045981071, 0.113322269027701, -1.18145363212693, 0.0783111965234852, -0.900299646256578, -0.319989168432693, -2.98287980655373, 0.958912337451257, 0.399436759779982, 1.61168549559879, 1.47471792424704, -0.300211695540034, 0.0238040231780335, 0.12766158215869, 0.857785088548046, -0.425815139879602, -0.227174403446773, -0.555734458726766, -0.224835852779666, -0.162686508077223, -0.183632786561089]', 1.0); -insert into credit_card_transaction (time, features, amount) values (158052, '[2.36926716042377, -1.24609902495935, -2.17382021749752, -1.84850321222334, -0.149322087315866, -0.329846187341586, -0.521771353353859, -0.288142582932259, -1.77465044320002, 1.77356208363264, -0.563013273032314, -0.468343011404381, 0.496816147126186, -0.0320190736121438, -1.49347090499992, -0.626719522782918, 0.0694869130661255, 0.395437286676759, 0.926968070919673, -0.37836931823471, -0.20718148422151, -0.0732488462453094, -0.0921750665800468, -1.37413090758979, 0.338942565013294, 0.0217975539250091, -0.0367176045092703, -0.0903231506057273]', 29.9); -insert into credit_card_transaction (time, features, amount) values (158052, '[2.0963637444315, -0.978955904771515, -0.379211111571828, -0.77742130947897, -1.20045750269603, -0.828603717892373, -0.867580597075723, -0.176196392995108, 0.0071312609131175, 0.681277843756132, -0.680377929643361, -0.125414108550753, 0.752852365944866, -0.544928384025883, 0.166535667978341, 1.25307051954704, 0.07382959889101, -1.5550449940279, 0.628577477890057, 0.068995989408971, -0.0213429643283343, -0.0941116585998622, 0.343448406248042, -0.0358042594702178, -0.485729513290804, -0.48864291418283, 0.0095653100134527, -0.0335264656714153]', 45.0); -insert into credit_card_transaction (time, features, amount) values (158053, '[-3.14198314601995, -0.795747772990656, -3.22872410771548, 1.38515758391949, 1.94493796528915, -1.09048597715142, 0.564201149815337, -0.6840797584683, -0.0635237340593889, 1.30770870918202, -0.246503874820104, -0.760471640699039, -2.62596286208287, 1.66760940504194, -0.446721804837327, -0.549807923718244, -0.117407677681424, 0.70025020216097, 1.21216567392072, -2.08886258992153, 0.795509070343903, 1.65601578542278, 1.69612661033994, 0.280425838319691, -0.65924286915628, -0.348070025252755, -0.19979202404733, 0.62481946422239]', 20.0); -insert into credit_card_transaction (time, features, amount) values (158053, '[1.78848211880527, -0.351577290238326, -0.285186406391459, 1.39775584209901, -0.616029821188238, -0.505693978321213, -0.300441301143996, -0.133206128840839, 0.779853952625029, 0.161292991484048, -0.810229646947379, 0.656901182838524, 0.909853966274774, -0.132602841182037, 0.703080536966557, 0.439654799071828, -0.83667925945936, 0.272857685597335, -0.78995335027845, -0.0196046254298708, 0.286271113531241, 0.820474202985322, 0.0485314358039791, 0.03118923011929, -0.0932808679886006, -0.574754094903624, 0.0452801628693278, -0.0127810764367538]', 95.0); -insert into credit_card_transaction (time, features, amount) values (158053, '[1.96968336046084, -0.0964962250022813, -0.710070699281692, 1.30421340111195, 0.304598537857831, 0.569519045247275, -0.213703634641616, 0.0492712198067681, 1.00191685868978, -0.0685682023356797, -1.66895410745299, 1.21642940014383, 1.31723175726522, -0.592735171005588, -1.22458160561029, -0.315873103242682, -0.351449862334455, -0.875942097212711, 0.40585131572622, -0.141201729848692, -0.549637802082017, -1.26263090270532, 0.369443191798886, -0.0229593685904975, -0.177258375063635, -1.0981111113625, 0.0594869852898803, -0.0263652727104336]', 16.28); -insert into credit_card_transaction (time, features, amount) values (158054, '[0.018341766123318, 0.727123659597603, 0.156352441826882, -0.776670951115936, 0.567948774391502, -0.5571198064077, 0.80772482580987, 0.0474891874312141, -0.121445590483331, -0.216823082825509, 0.347652735291864, 0.17402196719854, -1.08252320043251, 0.50584355611331, -0.916061024947777, 0.189681001620597, -0.661553281171852, -0.105519382949307, 0.265261373748907, -0.0961708359053289, -0.238069028621332, -0.5825375987544, 0.0307865328597195, -0.431211539235901, -0.527421246713587, 0.14995507065977, 0.23994518841151, 0.0809090456634147]', 0.89); -insert into credit_card_transaction (time, features, amount) values (158054, '[-1.01267295348477, 0.4682509695406, -1.02986952527514, -0.398862739545357, 1.98892162336445, -1.16420592840461, 0.623420039709719, -0.0217103407875031, 0.543361210122182, -1.48821877937244, -1.78226040854642, -1.87683133103201, -2.29543278829302, -2.43758977392769, -0.598346139188743, 0.756892243380234, 1.62278982462605, 1.23721813155852, -0.340814767872601, -0.175754753631895, -0.0700599332267562, 0.0716661135428761, -0.545344261056474, -1.24491362176541, 0.0679041714645703, 0.699314925456353, 0.305419867918879, 0.243688356985179]', 29.56); -insert into credit_card_transaction (time, features, amount) values (158054, '[1.52080142915274, -0.77820140092093, -2.33515777704217, 0.415627654807271, 0.472697155083894, -0.328008502571347, 0.541534652446861, -0.306690027602327, 0.806618660709988, -1.02148643126813, -0.915990997275203, 0.824147158203123, 1.54318501257345, -1.73477787851352, -0.159348204685902, 0.191607828026595, 0.708843071553992, 0.16848678962857, 0.31470047402869, 0.558102939924943, -0.107399848638681, -0.668475244865543, -0.145380535231515, -0.0290789200772619, -0.0024418139805457, -0.114532648235638, -0.0580588562981461, 0.0322838287423411]', 301.84); -insert into credit_card_transaction (time, features, amount) values (158054, '[1.87614518394264, 0.585367206769706, -0.693006909770134, 3.58682140007763, 0.687824651650574, 0.36097388059056, 0.19477600225076, 0.051334862224966, -1.31009188811732, 1.58139678231463, 0.614799679320102, 0.729202748739479, 0.279466933339481, 0.384981246767101, -1.58539088098162, 0.973020679561193, -1.00381206025566, -0.345296589289656, -1.04656984314445, -0.221730095974606, -0.216898472520202, -0.691472344504252, 0.373913158281579, 0.69114381887658, -0.263427253334316, -0.40058947549215, -0.044381451930199, -0.0436186223175986]', 12.51); -insert into credit_card_transaction (time, features, amount) values (158055, '[1.80888580120365, -0.699901907453964, -1.41192659426633, -0.101255637515896, 0.479881645809919, 1.04899977221234, -0.329081096024142, 0.385854690743167, 1.04604209477172, -0.162235115444438, 0.610352962401577, 0.6651570526803, -1.32432601827821, 0.591344127646303, -0.0351976285595531, -0.941151749922794, 0.316977202521436, -1.13917460285594, -0.195139696583259, -0.272403055743338, -0.0555865830838366, -0.0084155373014661, 0.175069087885377, -1.64714073823403, -0.286039921996293, 0.0215267139045696, 0.0024246770903611, -0.0761251316043972]', 60.0); -insert into credit_card_transaction (time, features, amount) values (158055, '[2.00736633378888, 0.197605490107496, -2.31292767230526, 1.01068461374767, 1.18453116200442, -0.560293343350268, 0.855922216171058, -0.417799102964725, -0.206546422783952, 0.317477735664009, -1.26250777273801, 0.200762021983395, 0.575368638578868, 0.665491142647104, 0.271658486354423, -0.256295239005763, -0.691988437367095, -0.300106202806184, -0.200621409248385, -0.0837983790833267, 0.117171975793909, 0.317473732195776, -0.117129341848675, 0.0412893239555221, 0.568106602898064, -0.479833437225246, -0.0424349490636987, -0.0525243288229536]', 64.02); -insert into credit_card_transaction (time, features, amount) values (158055, '[1.94395372643321, -1.66526597629775, -0.160880656915558, -0.650764232756074, -1.27218776786536, 0.825805683241033, -1.54479923020897, 0.233190415799586, 1.06182590455868, 0.398137307327396, -1.9860487793936, -0.0694452487071388, 0.825185005314729, -1.45179724494334, -1.23351732279866, 1.02952045707233, 0.261188656245176, -1.12018048572968, 1.13093310692688, 0.249748720111618, 0.142528963631199, 0.508749001765518, 0.0689424769735744, 0.0915231880054894, -0.22785765814095, -0.181669889198793, 0.042885410709068, -0.0170944627421974]', 116.43); -insert into credit_card_transaction (time, features, amount) values (158056, '[-0.913222756375777, -0.510744913327451, 1.27929140325769, -2.82017773729711, 1.31111267119318, 4.72016057949832, -0.411020771708426, 1.00301961695429, -0.326959949696871, -0.284111492030938, -0.517665514849398, -0.440042813876752, 0.140448639739117, -0.758424656728543, 0.779337500016846, -0.895773707612941, -0.919148299692307, 1.86279131492079, -1.90481348258028, -0.391045563574394, -0.168519199521533, 0.0904561733189935, -0.238458982635033, 0.666540047732917, 0.430271781181312, -0.24519088338482, -0.124393824530429, -0.177661275531115]', 112.7); -insert into credit_card_transaction (time, features, amount) values (158056, '[1.0708531479055, -1.75410024912809, -2.0721382931966, 0.548071494560761, -0.296132616690594, -0.711412209990822, 0.877419896822178, -0.470178538313481, 0.270720998143061, -0.0967304851571395, -0.677405440108196, 0.364450705523664, 0.675799371290164, 0.430161777139185, 0.690577100014718, 0.132336723466881, -0.533521141748383, -0.17964920225141, -0.364182532350579, 0.943922454178608, 0.527668292118363, 0.417766437467591, -0.401101369370746, 0.823041813051571, -0.0940491035346733, 0.696898546170088, -0.19268318358273, 0.0298726965962113]', 538.0); -insert into credit_card_transaction (time, features, amount) values (158056, '[2.11366540972298, -0.0625313670485518, -1.37761680582221, 0.239114892693589, 0.234679690120205, -0.779785813488236, 0.179683970482505, -0.295334897237603, 0.570966597658399, 0.0697200461409319, -1.38894221713175, 0.267747679856097, 0.341220675691468, 0.20158958437351, 0.0791675373234989, 0.107418734809747, -0.569733970464571, -0.641929306966707, 0.428297921497103, -0.188928828401778, -0.336504854106543, -0.826149148836059, 0.244729441383997, -0.711774224843256, -0.193430124019134, 0.241988913356279, -0.0709360557128, -0.0670972116220714]', 2.68); -insert into credit_card_transaction (time, features, amount) values (158056, '[2.17748950437641, -0.736223118899005, -1.26581931845296, -0.898160562192686, -0.576158295092153, -1.06449012422919, -0.375654755733691, -0.206660144809882, -0.619716142993168, 0.982149912261311, 0.983832872210899, -0.128171684071749, -0.851120292490032, 0.341596987056181, -0.889000964077639, 0.772553435713818, 0.276721634874781, -1.39710640084506, 1.01968024670217, -0.121797876029927, 0.0753031805703097, 0.209314721577517, 0.214219930869322, 0.0055294797093293, -0.0936291470680254, -0.295017703202381, -0.0443388735571768, -0.0762088661540979]', 4.13); -insert into credit_card_transaction (time, features, amount) values (158057, '[1.55662218761062, -0.943101169547192, -1.6440226162826, 0.273656608242931, -0.311297015730152, -1.08585405552726, 0.539228810860325, -0.2902085829919, 0.525913776016586, -0.0270908697932851, 0.871407119825074, 0.670776196540878, -1.11794847948101, 0.88940814684043, -0.473580664871551, -0.249273005358224, -0.352611506546353, -0.0707406827157482, 0.458629282352921, 0.201190725903527, 0.0527787623877599, -0.309905402533756, -0.0161881089425985, 0.0747400754226593, -0.136448051652766, -0.126490659219331, -0.10688022896079, -0.0314186477557069]', 249.0); -insert into credit_card_transaction (time, features, amount) values (158057, '[1.83604359298373, 0.361213698697015, -0.655592756317554, 3.73259504183759, 0.56033733833686, 0.6867672362945, -0.0094747917690079, 0.145688293058722, -0.925862324135712, 1.52360143185409, 0.276052399683832, 0.613274231957642, -0.0942139231736152, 0.166282664241039, -2.15016435455197, 0.601032023902391, -0.720450860719725, -0.102303684852575, -1.13101251168902, -0.237293879797034, 0.140196254777488, 0.487858669812262, 0.100059137871992, 0.703019309900319, 0.1002290400241, 0.044993597551924, -0.0344375238442478, -0.0510118427526211]', 22.68); -insert into credit_card_transaction (time, features, amount) values (158057, '[2.07213838086927, -0.0747559805958977, -1.1323991419929, 0.384651860390274, -0.0969873196893065, -1.13608531826296, 0.162990761328786, -0.309865398631069, 0.593612850892599, 0.0815749172496382, -0.920360302656867, 0.242443938900753, -0.187408658480414, 0.321802143770461, 0.0812469647377727, -0.0491422172062759, -0.325847267961774, -0.787442879183695, 0.203541367052077, -0.237021141068522, -0.302043489766016, -0.74906876715041, 0.325144726522631, -0.117954866926699, -0.288147096758683, 0.205993564877014, -0.0727743338036832, -0.0619964447660501]', 1.98); -insert into credit_card_transaction (time, features, amount) values (158057, '[1.98859021571532, -0.462435002608779, -0.587557230924636, 0.11017123090759, -0.117172508641378, 0.616844724306851, -0.767758002745185, 0.190371909919723, 0.878871498545837, 0.130784657849819, 0.349101127865736, 1.3660354858958, 1.22693772158787, -0.318401736341083, -0.328976516550753, 0.62099013357787, -0.993467394838053, 0.518741133882817, 0.197178081450755, -0.0661589877002234, 0.183824942046755, 0.736386058590645, 0.100992558019131, 0.117090970567576, -0.187269627297211, 0.556315857716198, -0.0190973181804629, -0.0543573824058145]', 11.5); -insert into credit_card_transaction (time, features, amount) values (158058, '[-0.765962670291498, 1.53491809806818, -0.868302627406612, -0.930869604809474, 0.780307847797014, -0.331711301740271, 0.811608847633188, 0.0645062745036926, 0.64882673174714, 1.13787882635058, 0.266847934858503, -0.0408876551033626, -0.976929475114732, 0.495991378236091, -0.0023198067971015, -0.128953415183282, -0.889554091869874, 0.895297132480328, 0.392475696785222, 0.490764814004673, 0.257964406088212, 1.14669726595361, -0.108220757836914, 0.275280807377137, -0.570435216468638, -0.224848989302734, 0.914426309723186, 0.552461059934263]', 2.69); -insert into credit_card_transaction (time, features, amount) values (158058, '[-0.245899782509229, -0.0827620938579728, 1.21420928337861, 0.287399623540103, -1.57178725891245, 1.0741216709421, -1.35279799970126, 0.771873177463041, -0.641025094870666, 0.63282187978159, 0.485118569179367, 0.571774518284022, 0.709486244611973, 0.0496629865314147, 1.49834619529287, -1.88355984025355, 0.382591003833595, 2.97505797957449, 1.69411614050303, -0.26789931266379, 0.16462551505184, 1.00510898765884, 0.209462737583158, 0.697287078574199, -1.44870822571487, -0.341444893716906, 0.182026131180365, 0.201904513138414]', 62.85); -insert into credit_card_transaction (time, features, amount) values (158058, '[1.91698236752409, -0.623713912063827, -0.577232823699824, 0.366288295344461, -0.469307786772858, -0.0456202979662577, -0.561924202810063, -0.0449573694570374, 1.20875443245996, -0.0437298815327138, -1.50245897451322, 0.502459563158338, 1.00901514846953, -0.43862546121085, 0.376987553939646, 0.441316037009794, -0.74125092120754, 0.132597874519823, -0.106590822227025, -0.0050327428122797, 0.217536387989648, 0.773685050414691, -0.0211668749904259, -0.684280116678274, -0.1427207964521, 0.668831911840868, -0.0236013138704864, -0.0439777340677026]', 69.99); -insert into credit_card_transaction (time, features, amount) values (158059, '[1.94798365241909, -0.266252073363287, -1.69035458571125, 0.534072776862618, 0.0378711580201823, -1.39938068607612, 0.566939381547449, -0.453209128501882, 0.461009214858657, 0.0935906236616408, -0.977401675201871, 0.0384101599545751, -0.705238397468891, 0.547014423457886, -0.374032271789174, -0.534972116160354, -0.0314292583972938, -0.763837166298141, 0.175812437295928, -0.129560109799346, 0.0024706745400765, 0.0309315102264677, 0.02174093520098, 0.0954832350297339, 0.130944280627825, 0.552425588398322, -0.114232311354674, -0.0653240625031898]', 77.39); -insert into credit_card_transaction (time, features, amount) values (158059, '[2.1106679202672, -0.0642292754328239, -1.35288875262305, 0.253614204403093, 0.198800901987926, -0.816760867435516, 0.174848032722424, -0.294696812142355, 0.578496004849875, 0.0722119549318383, -1.34751478425621, 0.247006058377405, 0.253639000630061, 0.220368367261592, 0.0830451977836086, 0.0931471667437671, -0.543202848135033, -0.652544515840614, 0.406060814585815, -0.197249280159364, -0.333803158951552, -0.820839719829356, 0.253804726054176, -0.6528495780223, -0.203907647075743, 0.238540033774892, -0.0712258024889534, -0.0667656915036206]', 1.98); -insert into credit_card_transaction (time, features, amount) values (158059, '[2.03858190118996, -0.08955411837767, -1.20381247011261, 0.195219985323175, 0.178605072225296, -0.565459170803417, 0.0883132225056465, -0.161190559388497, 0.241913599909149, 0.221415201376897, 0.72520740927674, 1.24642271767646, 0.479406746038521, 0.367405233467167, -0.631490197616445, 0.128653259477706, -0.652274249962714, -0.386235030809468, 0.511135195536199, -0.178484407194994, -0.25281349130724, -0.601019562358839, 0.279805146669692, -0.454192386515664, -0.275695009030426, 0.206866735466045, -0.069098074057509, -0.0737559039313933]', 1.98); -insert into credit_card_transaction (time, features, amount) values (158060, '[1.80177445180494, 0.392900146650338, -0.764728756168735, 3.65117947615325, 0.62361486211524, 0.485783941645229, 0.16928057973791, 0.118861011346272, -1.13431680009952, 1.55885926903576, 0.44707433228444, 0.366778481764997, -0.530725938020933, 0.496382585451187, -1.68792662937989, 0.836182813663618, -0.819173081929585, -0.362880374319654, -1.0591322778914, -0.215820446157879, -0.187039833837802, -0.6716725808213, 0.328963596879575, 0.621648001150195, -0.25515828386024, -0.351783951244471, -0.0518704877629955, -0.0420217892639217]', 45.38); -insert into credit_card_transaction (time, features, amount) values (158060, '[-0.397301829938534, 0.937969128694766, 0.19260164696609, -0.447221668743905, 0.763687410290789, -1.22371604276296, 1.41308353320128, -0.350034773814132, -0.323134838637991, -0.544366180893735, -1.30680428146014, -0.667290392605218, -1.38903101562744, 0.533267581613254, -0.73779222116137, -0.583628554593284, -0.102225363787679, -0.50798479494302, 0.0805805951811145, -0.254050466861325, 0.0582550960812433, 0.19986997785849, -0.31617354426051, 0.0701338211751449, 0.0519364843360323, 0.334074414529849, -0.071607107490044, 0.127574872131995]', 13.4); -insert into credit_card_transaction (time, features, amount) values (158060, '[2.06469236749068, 0.193408694015494, -2.76101478000716, 0.278346924701658, 1.14934597735104, -0.720036253641448, 0.597821706634258, -0.251793703557811, -0.0682234807975602, -0.195627696608758, 0.801785796751263, 0.300284623071794, -0.620847662978237, -0.457952610319925, -0.735993348022924, 0.0823938801163987, 0.549978263012657, 0.43057016077715, 0.332295629774418, -0.148589801028603, 0.0561150341531602, 0.258335302379025, -0.0883005333235351, 0.182712034363408, 0.391996497815793, 0.693194987507978, -0.109865682524321, -0.0627451984996771]', 20.0); -insert into credit_card_transaction (time, features, amount) values (158062, '[-1.42370397819228, 0.572465457584779, 1.09822708350118, -0.774047164402353, 1.09377763731995, 1.29415399308902, 0.204210977388848, 0.556054069929106, 0.231303860868837, -0.320949405870751, 0.768519073282095, -0.228708504845823, -2.04109709353267, 0.584103697229902, 0.822126111875452, -0.952882123879487, 0.341498131629051, -0.632408542276245, -0.206573077950201, -0.203519389899039, 0.0507363947725749, 0.253125237298422, -0.417934861266197, -1.54279990752579, 0.425507457955472, -0.0815234616494057, -0.0752547263517826, 0.163206416254446]', 9.83); -insert into credit_card_transaction (time, features, amount) values (158062, '[1.98845313775173, 0.0155463785550837, -2.05446862423836, 0.307062427764176, 0.482226554682777, -0.871033238214819, 0.270083021873564, -0.150762185734681, 0.222280835617012, -0.230374981805227, 1.15404728632482, 0.303632083267801, -1.06481994610466, -0.472607323584188, -0.541608360213101, 0.334733683039823, 0.551883735050448, 0.314664717040862, 0.27859282243093, -0.150125268137629, -0.151170981428364, -0.445142444705659, 0.190413040587063, 0.674193311206083, -0.108955445695942, 0.463384737267867, -0.101600061491616, -0.0443616975130006]', 30.95); -insert into credit_card_transaction (time, features, amount) values (158062, '[-0.090258092684463, 1.14139039856269, -0.638816930492043, -0.795632925050198, 1.06888714359649, -0.33206393095434, 0.84108370763587, 0.0825098789077009, -0.0572781518477523, -0.350121192504979, 0.674263778390358, 0.336462026838403, -0.255058276464882, -0.865091270593329, -0.873234947528042, 0.621130256041031, -0.0082325993800895, 0.40733973503873, 0.165414535188785, 0.150704167252117, -0.346932075109601, -0.827931366051785, 0.0534278827694109, 0.166250725681542, -0.360467649257552, 0.122152712203135, 0.323381732011365, 0.129386280724004]', 2.69); -insert into credit_card_transaction (time, features, amount) values (158062, '[1.78393840767865, -0.190894371893229, -1.06989673977674, 1.76946048833352, -0.118343566898157, -0.206228223305486, -0.194602220264359, 0.0343387299776153, 0.902740599165868, -0.307545997657614, 0.655545797908997, 1.07348912312364, -0.33565060708333, -1.3443237652253, -1.9374670387508, -0.225069983946257, 0.804970598945215, 0.754039698224413, -0.141720615895689, -0.144712320557656, 0.279606828890742, 1.14032378579156, -0.173734321596993, -0.0253093151548956, 0.397831435388674, -0.271393142154207, 0.0498101941227625, -0.0230016886453852]', 62.58); -insert into credit_card_transaction (time, features, amount) values (158063, '[1.82781261500287, -0.834576905584231, -0.621645544756949, 0.16909041609066, -0.660666282262516, -0.122512148342058, -0.593528596264158, 0.0333186916722233, 1.57636098632024, -0.249583361989633, -1.23012765564523, 0.133708837155878, -0.254354817711652, -0.134898284339224, 0.623351119138974, 0.214386707898909, -0.5256815903896, 0.294995114956702, -0.0651426791653565, 0.0005168862027209, 0.214600181948143, 0.593962087605712, 0.0655213087825487, 0.611863865125332, -0.174768612579088, 0.0927212099813462, -0.0104811116188821, -0.0207053864539358]', 106.5); -insert into credit_card_transaction (time, features, amount) values (158063, '[-0.208471673121375, 0.765746531432683, -2.43969216049611, -0.510489315057049, 1.59345592155506, 0.259208779185712, 1.42664875534026, 0.380298244346266, -0.79833639199878, -0.3393056050257, 0.851408499599706, 1.03116905210376, -0.12992712774525, 1.42114026616392, -0.461100156271367, -1.76148787938286, 0.52445934133305, -1.06760294003354, -0.492754264682229, -0.0470819988630124, 0.722246689473042, 2.20751418768393, 0.211029943326324, -1.34368487580256, -1.22555093758533, -0.0442763383692967, 0.457259147355167, 0.298485093693931]', 106.07); -insert into credit_card_transaction (time, features, amount) values (158063, '[1.9685750052288, -0.503187605694809, -0.186967160575634, 0.29692013050899, -0.608110998506472, 0.177803938604807, -0.90062500722356, 0.166651359270377, 1.58544636024093, -0.189579567560013, -1.1485729326818, 0.313805005133515, 0.189228879354687, -0.269033068560807, 1.03635841116761, 0.49197041691924, -0.75605615645576, 0.328640749985723, -0.268989696142519, -0.169288048191564, 0.0610989552812056, 0.31945968456597, 0.266263607045252, 0.399499985843925, -0.347813876971312, -0.421621004214798, 0.0540468896903258, -0.0212510488442206]', 15.16); -insert into credit_card_transaction (time, features, amount) values (158063, '[2.0421643018548, -0.349952391977515, -1.79074160699123, 0.395536913114032, 0.229197672466133, -0.707037798969294, 0.277954114644534, -0.347905142354436, -1.43480805202343, 1.28713879464262, 0.505586637786463, 0.727090373221375, 0.662904726803939, 0.694210139191587, -0.55268002082255, -1.55977061151737, -0.590340582084389, 1.39443525732114, -0.794836091535283, -0.531325754453925, -0.25375492460605, -0.289369065379604, 0.0395283232949813, -0.512523696355468, 0.222686158605791, -0.589403963487044, -0.0055160621338437, -0.0576773706489091]', 58.8); -insert into credit_card_transaction (time, features, amount) values (158064, '[-0.0307276060395299, 0.876928609719564, -0.859382625797533, -0.0627757362236442, 0.514044629885717, -1.32224687914059, 1.08011991984497, -0.43249730701895, 0.306170850395402, -0.482532125877761, -0.523779170219644, -0.348308141918262, -0.116448035449065, -1.00437643432236, 0.764250406646827, 0.0712868989842776, 0.336916405415481, 0.677530937479771, -0.189737276243736, -0.257430504093161, 0.206011154390673, 1.00345028088615, 0.0032128536867709, -0.0953780211001562, -0.293453871503418, -0.218245211970163, -0.589215794727545, -0.54663140666535]', 42.81); -insert into credit_card_transaction (time, features, amount) values (158066, '[-0.25478041067097, 1.10524619985592, -0.5041980143308, -0.31638040561217, 0.0819042645406688, -1.30576703194993, 0.720781474538327, 0.164112699387785, -0.0569017129101983, -0.493393326564251, -1.22545213563873, -0.365084245716588, -0.830087780528719, 0.920310175716388, 0.514557899274165, -0.279633324440794, -0.251826654196782, 0.310848000960627, 0.0318047703994647, -0.15437778167266, 0.411610383379771, 1.25883065929227, -0.0274290109519171, 0.0591158901778585, -0.790844169762277, -0.217807560500606, 0.373386201368361, 0.259639857981223]', 19.99); -insert into credit_card_transaction (time, features, amount) values (158066, '[2.0694111124574, -0.0944565161602246, -1.89463696576991, 0.0333005463213146, 0.552174164354481, -0.554415897363521, 0.254390621332373, -0.137200720847121, 0.553618938654337, 0.0842019321579898, 0.41046765719381, 0.333264020715734, -1.21659894502071, 0.97278022368361, -0.119789745118491, -0.225798825351016, -0.664271103213415, 0.491002510592234, 0.495878432087348, -0.284287436872967, 0.114826476814383, 0.396209068273423, 0.0045715343401154, 0.331236501786823, 0.374232304679169, -0.54531726230948, -0.0248717439015936, -0.0681164080490862]', 5.0); -insert into credit_card_transaction (time, features, amount) values (158066, '[1.92735618586021, -0.0320639091326363, -1.36972351849436, 1.07445917969652, 0.346600915782068, -0.341138405522301, 0.126181722807939, -0.0628143989569896, 0.0709944348559103, 0.495481881522249, 0.82366872738408, 0.465617792954891, -0.758408801833574, 0.842605102860724, -0.0027271488203465, 0.158410886047471, -0.787686662501673, 0.523570494051303, -0.400355259322564, -0.217466696982898, 0.321507040308478, 0.889613100159995, 0.0072119869514688, 0.693271132477487, 0.253799410151988, -0.477652488325716, -0.0135646390466795, -0.0510600274123866]', 35.5); -insert into credit_card_transaction (time, features, amount) values (158067, '[2.16114266476253, -0.854060029930769, -1.22422292720539, -0.755991920097876, -0.225583767532568, 0.208141568471526, -0.690957575795242, -0.0456654080011426, -0.45340033873382, 0.995486125308165, -0.462429821423128, 0.67711357509785, 1.27488392911981, -0.135983046893044, -0.52952782834414, -0.809933413618608, -0.933493430017945, 1.80881437328479, -0.0489505322286981, -0.465241130752253, -0.384093423101951, -0.503541853432988, 0.0935468918116679, -1.36470949389581, -0.202806044100518, 0.619664509245038, -0.0352184736221549, -0.0708506934753829]', 26.2); -insert into credit_card_transaction (time, features, amount) values (158069, '[-0.638750327733038, 1.16379757576115, -1.06638605171706, -0.738521186552809, 4.16902485877022, 3.31734792244742, 1.24586922992769, 0.584440792328399, -0.990152789182, -1.11964181485828, 0.113218483163353, -0.573182957050857, -0.737492764826597, -1.08083879630009, -0.237173110355923, -0.389626388984832, 0.77971922075232, 0.102585895454119, -0.506880070036051, 0.0503806091341384, -0.0886119424821012, -0.114731513291954, -0.671233043014259, 0.581011832384235, 1.28659545749539, -0.376848877928385, -0.120629980274248, -0.156792428479784]', 1.0); -insert into credit_card_transaction (time, features, amount) values (158069, '[1.52011867589579, -0.814491196215313, -1.69389648892886, 0.760903870377673, -0.0591250834615059, -1.09519862443895, 0.837516059259168, -0.533962953651456, 0.192359873345928, -0.0367122909388949, -0.72170418976513, 0.93513768610503, 1.18830936872834, 0.229681241210634, -0.157729244777629, -0.258794490953418, -0.359128436135173, -0.824553440898034, 0.0319933362507131, 0.430454126709364, 0.0254389537284521, -0.376030651530863, -0.0775235410776442, -0.0476972733639176, -0.0898828548764882, 0.156176611097369, -0.11902760346036, -0.0135240795679878]', 293.9); -insert into credit_card_transaction (time, features, amount) values (158070, '[2.08418395137894, 0.303908521995735, -2.98154514900366, 0.142018048669677, 1.37375102175253, -1.07533452220695, 0.955685956751364, -0.57587323352673, -0.277849590624981, -0.351621067503912, -0.701548425374395, 0.421199001457474, 1.52572019036536, -0.815979727463438, 0.290003317186343, 0.160865859035089, 0.307766856026333, -0.0557114593722326, 0.0818417065144045, 0.071418576700575, 0.0525267997822637, 0.197623751689773, -0.149178734450972, 0.0493895756270135, 0.453386015104436, 0.798005231408597, -0.121284959648873, -0.0464489281458786]', 58.0); -insert into credit_card_transaction (time, features, amount) values (158070, '[-0.343731551410044, 0.720867903950207, 0.459598122969709, -0.571910013492466, 0.771714901891993, -1.09997983358582, 1.02608611814309, -0.304518713012099, -0.275976038499654, -0.540643284882029, -0.830411287002669, 0.448358829680354, 0.626856135685181, 0.0464331210729753, -0.441222051332081, -0.259514363693083, -0.374452166012208, -0.866936769643486, -0.008213954349943, -0.134927240608947, -0.128718353942374, -0.310205112947141, 0.159531270113385, 0.004758201745015, -0.887340975274899, 0.0716782780087929, 0.0095292541970001, 0.222699848849322]', 0.89); -insert into credit_card_transaction (time, features, amount) values (158072, '[2.00016959883351, 0.766128039256629, -1.87039526394277, 3.53350417145155, 1.57286743145024, 0.174578087654259, 0.848128074497978, -0.282346483776415, -1.4621501632082, 1.48323505388731, -1.69599978968366, -0.0810134852943552, 0.827041786527786, 0.356109222849145, -1.22241275006295, 0.362259678641628, -0.794762423877421, -0.664584385582423, -1.15606939783326, -0.182054802131374, 0.0890507823409251, 0.32018157466165, -0.0846731790870023, 0.0516898867832329, 0.541006046331634, 0.180406004228705, -0.0789793657516306, -0.063674129496317]', 22.69); -insert into credit_card_transaction (time, features, amount) values (158072, '[1.88150027085014, 0.273816112432466, -2.60402128251999, 1.44802207078666, 1.09693138228262, -0.971803461812934, 0.960368734316088, -0.442158676032975, -0.101192741630322, -0.251601201601777, -0.613569203676707, 0.126107895882707, 0.0943376381598297, -0.626439463326391, -0.224659104293593, -0.316860960561607, 0.700827091061394, -0.0093983856381431, -0.450862367048816, -0.0207693115617597, 0.129221670511681, 0.366761198841948, -0.163769301175009, 0.531805799474019, 0.610572001205469, -0.420042708008352, -0.033006231301453, -0.0180038541198166]', 100.0); -insert into credit_card_transaction (time, features, amount) values (158072, '[-1.97814595416767, 2.64635049402622, -2.31529335583235, -1.6934941590907, 0.998281714705924, -1.10323942055503, 1.23622345402664, 0.153035173749095, 0.985647782188868, 1.66191523226598, -1.62466237781549, -0.422458941754717, -0.480340536985045, 0.470140914997481, 0.0460411152679054, -0.476200480815713, -0.602633337229558, -0.143433243743065, -0.0532807904455965, 0.781890858909877, -0.0365929267987142, 0.576927879032573, -0.181862881930305, 0.0426483217350015, 0.151830428737418, 0.0794291250441214, 0.5419842410313, 0.118671334779544]', 0.77); -insert into credit_card_transaction (time, features, amount) values (158072, '[1.91913455184454, -0.213459991046471, -1.29897589824821, 1.30483076904466, 0.175382146084449, -0.242623831918883, 0.0732764315539103, -0.0620597292290035, 0.5718617525157, 0.360673329287559, -0.0872083753252122, 0.491637975341428, -0.998848267287836, 0.474534681160918, -1.32646294288266, -0.212724882459056, -0.545179281644989, 0.465986841273086, 0.242646491713901, -0.24327106785197, 0.204190637063395, 0.75462977338881, -0.144758718493471, -0.483972030793564, 0.432671542928282, -0.365060270669454, -0.0018003018270572, -0.0646560560494987]', 43.89); -insert into credit_card_transaction (time, features, amount) values (158072, '[1.97043653588596, 0.0232671897061891, -1.57889189507548, 1.33066416293783, 0.223783578160951, -1.00691567359934, 0.435916090049396, -0.195043194787799, 0.233549103466842, 0.489086092842113, 0.424581774145237, -0.0201149032113373, -2.32217014896317, 1.12297448777842, -1.05686235643686, -0.418412247729906, -0.287418121287991, 0.135885378776211, 0.113196004865995, -0.396217498103411, 0.0843971342700311, 0.315080050368324, 0.0067090079020514, 0.0296902205643354, 0.361065183087688, -0.512155346309828, -0.0359444573779361, -0.0734515648845868]', 16.98); -insert into credit_card_transaction (time, features, amount) values (158073, '[1.8703414374326, 0.421265426411168, -0.523970931317917, 3.95531508819241, 0.254851417215812, -0.0437141511002858, 0.151889361530053, -0.0971800236987923, -0.654692521237274, 1.36169942980138, -1.42470061372104, -0.0316516480124279, -0.0065462432417887, -0.0208846651672863, -1.49430997243393, 0.383635170938346, -0.455850690431738, -0.62790386431443, -1.42289538635865, -0.276838485035133, 0.0928865521419743, 0.429187500573849, 0.0731369594422189, -0.0129837459169884, 0.115602913715351, 0.0981990511536669, -0.0255557429282221, -0.0480888658281339]', 22.75); -insert into credit_card_transaction (time, features, amount) values (158073, '[-0.243050688451976, 1.40789375870162, 1.50611478005943, 4.28067568232745, 0.985938562843297, 1.05146027138761, 0.669648609317906, 0.0889721494610659, -2.30187124816434, 1.25793456662633, -1.08240898120638, -0.0242207706812204, 1.62127712468875, -0.0545595966274106, 0.517243082801085, -0.0211377009360716, -0.0224980643624611, -0.40099231883392, 1.58519159637501, 0.444234359177754, -0.391641649438725, -1.22105025553885, 0.264886021441823, 0.411839545020749, -0.692307047366379, -0.193484821393766, 0.160741111803187, 0.183927157667793]', 46.9); -insert into credit_card_transaction (time, features, amount) values (158073, '[-0.0883906696269832, 1.0457325897812, -0.703413615304326, -0.802783837805217, 0.994594745702955, -0.308077915207444, 0.763648874495042, 0.156553735102884, 0.13425396978603, -0.315291542416744, 0.388011205225123, -0.346180582074604, -1.46851520304134, -0.62593342224556, -0.731689613945576, 0.704744590810923, 0.0303386309075489, 0.586521127271906, 0.206203366823669, 0.0743541965947302, -0.367136894899187, -0.943967800912328, 0.0618545021742439, 0.0464609637696135, -0.3895541474266, 0.131772696794208, 0.31657972699435, 0.124739613247839]', 4.49); -insert into credit_card_transaction (time, features, amount) values (158075, '[2.1165195274224, -0.060824070946816, -1.59491954141603, -0.0311329714902188, 0.675114162028371, -0.080999692209259, 0.124207479264702, -0.16030811165515, 0.215602891262901, 0.213127238952929, -0.0857668796331095, 1.23779664779035, 1.27563973429416, 0.179654670094019, -0.676353988908631, 0.440602125509111, -1.09650610509599, -0.057593109967187, 0.944097434637234, -0.101308798725368, -0.31536226117377, -0.752003151824819, 0.145991938746094, -1.35703967873107, -0.11017571628235, 0.259764079741058, -0.0694354956121309, -0.0817189536084626]', 1.79); -insert into credit_card_transaction (time, features, amount) values (158076, '[-0.297797045258832, 0.908675905559729, -0.314027921639516, -0.880273125101702, 1.68567934063896, -0.300726760338133, 1.2749065617148, -0.23921972170733, -0.369280654454933, -0.652169598075945, 0.376737695129232, -0.492210325985142, -1.26615698604864, -0.765064903838997, -0.818380932972477, 0.42673380767152, 0.0577295086447829, 0.691376745131895, 0.43605503811391, -0.0606303064950935, -0.175582969518696, -0.43264404855109, -0.255331958667567, -0.0115791058952027, -0.287894346560759, 0.262798076181858, -0.228093532681901, -0.0501784306677713]', 5.87); -insert into credit_card_transaction (time, features, amount) values (158076, '[-2.6602074511247, 1.8936211706316, -1.29260377955572, -3.38408034817405, -1.02316069888704, -0.657291959032157, -1.08973688801533, 1.90157454288868, 0.711239768530032, -2.71582721739333, -2.10997949575661, 1.62089995588236, 1.47057941860962, 0.996047820814807, -0.127820270233685, 0.774403128642233, -0.371125034994948, 0.0682067767622025, -0.214434082831887, -0.771323929651732, 0.112696894014598, -0.501869296098083, 0.168446636222551, 0.0290380643673965, -0.252142454911719, -0.847440858536893, -1.15541013660752, -0.158711687418066]', 9.85); -insert into credit_card_transaction (time, features, amount) values (158077, '[-0.265969438077506, 0.906718581276279, -1.82266370491374, -1.60895604663072, 3.11120817025141, 3.17050054404624, 0.313669688109596, 0.895223997339977, 0.10309419996328, -0.378379842304796, 0.168465923596973, -0.145475534840891, -0.424501219311756, -0.85875304093318, 0.181240747075413, 0.182828159042802, 0.335994641364543, -0.399791927265376, -0.422706284088929, 0.150024489293798, -0.351020705071461, -0.928440494534973, 0.144588705603171, 0.588682307504071, -0.379282074993107, 0.156865587563356, 0.217273441936228, 0.135748289526853]', 1.29); -insert into credit_card_transaction (time, features, amount) values (158077, '[1.55511747553783, -2.03532233318157, -2.22530657582974, -1.09876359849239, 1.09358606277707, 3.91484244215921, -1.15030983155469, 0.894398897319769, 0.0642651585179147, 0.582680805128733, -0.407682345636573, 0.128119077495033, 0.293379831260656, 0.0423498599023209, 0.897102511659099, -1.51683906365488, -0.346855717470443, 1.57853658310192, -1.2977198694016, 0.016532780104685, 0.142422277162276, 0.382624341664947, -0.111227147305119, 0.721073965123793, -0.0949422908509532, -0.0662146927717048, 0.0218665949151095, 0.0039704643905569]', 287.94); -insert into credit_card_transaction (time, features, amount) values (158077, '[-0.221261638764708, -0.103304153828853, 2.20542754773743, -1.12218827926237, -1.09267219125482, -0.0903064941492987, -0.471941550428012, 0.0721799600464207, -0.754543535878988, 0.0859490568391077, -1.02097872806516, 0.168427594790715, 1.72406017388393, -0.816449678763223, 0.813874879619495, -0.857463465109312, -0.522431136623004, 1.81671006312581, -0.929585623798286, -0.287392453056418, -0.0210638136205978, 0.505404435123536, 0.0070878667240081, 0.0857237645986269, -0.82712709270363, 0.648192267383244, 0.185237867923584, 0.185278236661975]', 29.89); -insert into credit_card_transaction (time, features, amount) values (158078, '[2.08402094416765, 0.789079638479605, -3.01718047834247, 0.795187108140692, 1.15987374997072, -1.84032321026247, 0.906778832378184, -0.5714474436963, -0.163618773274032, -1.07797829518101, 0.553297642647569, 0.371488367456094, 0.784767795239195, -2.61022113128385, -0.144966727305513, 0.169243128733897, 2.25104066877001, 0.297266560685705, -0.449659267664362, -0.0699977612270718, -0.0331642536405961, 0.162090670975431, -0.0095222703956224, 1.0062505607374, 0.388392087951558, 0.652258575487315, -0.0740953565804871, -0.0067569278284233]', 0.76); -insert into credit_card_transaction (time, features, amount) values (158078, '[1.99838560018673, 0.129986208297545, -1.64931100825586, 0.792388306861566, 0.161079372199674, -1.13954206370383, 0.156197342357292, -0.314807152984846, 0.693342533350202, -0.710619337071993, -0.380603727284313, 0.578258459535896, 0.675798348086938, -1.86051560741299, -0.470030344424595, 0.0160251202290032, 1.24960090085785, -0.0166639673022884, -0.204246738466864, -0.109638968119896, -0.0087047927811704, 0.315568331528921, 0.0225802743682575, -0.0575439433555003, 0.0995687108104761, 0.637543331506091, -0.0343152138519227, -0.02658802609948]', 17.59); -insert into credit_card_transaction (time, features, amount) values (158078, '[2.25976613595617, -1.47062749804758, -1.76727811214294, -1.8755881625177, -0.629435402687654, -0.293176926530501, -0.902011090475073, -0.118126255936916, -1.65728848385508, 1.86168826791702, 0.0767373089456427, -1.04510715235444, -0.517837924013802, 0.242347988403254, -0.313713833092114, -0.15857239143508, -0.039297671491883, 0.919154773701658, 0.196057687326123, -0.353099462234909, 0.0902240288026091, 0.526966788356112, -0.0140674327621695, 0.0810120330396643, 0.114534781799811, 0.0547860003552184, -0.038255241777681, -0.064719948751202]', 60.0); -insert into credit_card_transaction (time, features, amount) values (158079, '[-0.545212398316568, 0.491961263810459, 1.2245020289817, -0.347667522942493, 0.211771284121254, 0.33272698266724, 0.397083139847578, 0.194546122755747, 0.538195781139998, -1.60139881848552, -1.33765801215261, -0.0918011458980561, 0.0918307416066358, -2.00899752954312, -1.07420365607947, 0.177373735538439, 0.741228180955831, 0.543247690028306, -0.13400975214764, 0.0987896564955963, 0.13123878238793, 0.578831795655899, -0.460271252770885, 0.577854293320336, 0.976243116080739, 0.873923657778245, -0.0836754640305318, -0.0372597441362773]', 54.95); -insert into credit_card_transaction (time, features, amount) values (158079, '[-0.0008328572451291, 0.888961854898189, 0.372249860341718, -0.689232099351591, 0.494920556445377, -0.830088688313869, 0.975007535745541, -0.117785847499354, -0.446620811082917, -0.268802585677266, 1.00842668372035, 1.33393298770981, 0.806313977910539, 0.135673436601211, -1.20922589467188, 0.0339658565903343, -0.676804343775477, -0.393800746772186, 0.164423332039843, 0.0251051969422241, -0.192908302687729, -0.367926142102051, 0.0565732292012525, 0.0951637003831646, -0.501745069841462, 0.112045143118432, 0.249591320647151, 0.0899986122328242]', 2.97); -insert into credit_card_transaction (time, features, amount) values (158080, '[2.2583215130857, -1.34833411064532, -0.953865411782146, -1.61666133000974, -1.07946743349742, -0.627391155843994, -0.924967770849296, -0.273676714205855, -1.31159929281736, 1.48582189684475, -1.34701686789439, -0.397738911540485, 1.42243897106487, -0.607554671730647, -0.212843837572286, -0.293257978634325, 0.202675156242394, -0.460574134810278, 0.32422423267761, -0.289554492702726, -0.64625848559179, -1.45958472786715, 0.429094624499299, -0.729472130497656, -0.538527342702467, -0.639309157327278, 0.0150640406131446, -0.0374173325297163]', 52.95); -insert into credit_card_transaction (time, features, amount) values (158081, '[1.88270978276207, -0.203215603343795, -1.43003350113993, 0.491799248504603, 0.0694321963626393, -0.638357338202461, -0.0132510104773134, -0.082357905032932, 0.761526372827605, -0.488805909914426, -0.538535782427391, -0.152671488216229, -0.603813733709077, -0.901787142223031, 0.547011316250756, 0.600411416644901, 0.560009514153027, -0.331867502266493, -0.0357466366417133, -0.0372225662242964, -0.545341601500347, -1.72293844054031, 0.489095317382395, 0.436285184517016, -0.687529931590287, -0.116639320969008, -0.0584642948198295, -0.0038387702189186]', 81.0); -insert into credit_card_transaction (time, features, amount) values (158082, '[2.2039336854423, -0.747797057211488, -1.43918339058904, -0.994530400254695, -0.371544446983618, -0.826442473626299, -0.379018554350413, -0.183606275075657, -0.599667186469029, 0.980543537327192, 0.623728126488045, -0.235969863563173, -0.725204653978271, 0.306524795283782, -0.864496499423267, 0.890624428106622, 0.123639216980209, -1.26868660940973, 1.17446876377488, -0.10219103580892, 0.0496109167829102, 0.136933276167255, 0.161332322853014, -0.40638979922345, -0.0372370931151909, -0.269744009106936, -0.0447918127381696, -0.0800404212289757]', 5.51); -insert into credit_card_transaction (time, features, amount) values (158082, '[2.07432126412485, 0.14389739720641, -2.05346938698305, 0.362237265782979, 0.521694220635563, -1.08337985450324, 0.339651669920655, -0.293159185617915, 0.447426178736587, -0.406858354032851, -0.595006445323535, -0.202282673748731, -0.512597423293254, -0.780991692294195, 0.175817754080364, 0.212145726062603, 0.697601501036405, -0.187807040765836, 0.0441634374939348, -0.163964045824354, -0.246453351188729, -0.630256214714182, 0.222933119945107, 0.576435318904607, -0.0890735156663121, 0.451587233586819, -0.0890503053245467, -0.0361410535144938]', 12.7); -insert into credit_card_transaction (time, features, amount) values (158083, '[-0.548143851180123, 0.822260253758586, -0.380725156211691, -0.682493347641176, 0.503978106908539, -1.34706401890499, 0.761621572994474, -0.342549564947644, 1.26698005213032, 1.05502280950522, -1.20314655853046, -0.855941272632263, -1.78943689137258, -0.0142708841722056, -0.163404957666389, -0.0430205210036624, -0.560831109808515, -0.605741094524832, -0.226660389533922, 0.083310601085726, -0.455610981057382, -0.752369861696202, 0.0765051728663474, -0.167718863728392, -0.704190643707102, 0.0645098258752825, 0.30764451080339, -0.0031405174135306]', 8.99); -insert into credit_card_transaction (time, features, amount) values (158084, '[-0.407301501389798, 0.599187496319106, 0.67014941968811, -0.236033023222735, 0.797438884695857, -1.06932663520237, 1.07532557870956, -0.30724107859846, -0.541546651686777, -0.644759885572147, -0.803582917792047, 0.666352269529717, 1.11119947206464, -0.0240481612471989, -0.48261291388063, -0.551613881843007, -0.141960115790906, -0.796515933601656, 0.59561054762285, 0.130111707736977, -0.101881060031207, -0.255756487387776, 0.0141964899946217, 0.097553341006981, -0.370973367667514, 0.299048898807788, 0.0839627756264165, 0.16489980398556]', 30.79); -insert into credit_card_transaction (time, features, amount) values (158084, '[-0.237072882987776, 0.597910832266842, -0.172596091390882, -0.606132166698665, 1.67357890769623, -0.929743957599525, 1.40736556776356, -0.747654791675128, 0.150455311198472, -0.374031785970019, -0.494571992489758, 0.116972511950436, 0.789700774113428, -1.57591091457866, -0.392035642928224, 0.0756915077459882, 0.0382627569813209, -0.322707594717668, -0.150661570295444, -0.0489648439377985, -0.28326946069883, -0.349862651198065, 0.324385183627055, 0.589434932039139, -1.30042191590005, -0.118187287630564, -0.364489361775515, -0.12876546121133]', 0.99); -insert into credit_card_transaction (time, features, amount) values (158084, '[2.09824945538098, 0.228234723328982, -2.16714040318854, 0.245655702719036, 0.868877702880564, -0.645849790913187, 0.291724262842977, -0.317915728773504, 0.461236833290222, -0.516188816332361, -0.848877257139733, 0.362331304334737, 1.2551828906387, -1.00551992440391, 0.877245510935354, 0.398432894544184, 0.0370154867566652, 0.647367372876822, -0.14936707062255, -0.0565945810103014, 0.160369420076634, 0.630621443369791, -0.100925183783467, -0.0022217541687746, 0.405129936588162, -0.0961601084484463, -0.003347910900897, -0.0272299481118484]', 15.33); -insert into credit_card_transaction (time, features, amount) values (158084, '[-0.387600347784762, 0.175436361873595, 0.345720488165518, -0.634227690451022, 1.287967898755, -0.913605260526702, 0.651514658233317, -0.1074617050902, -0.153378237427606, -0.674477593947801, -1.51776112899619, -0.179975316044408, -0.0575058802032664, 0.155591225932977, -0.216837950599842, 0.080193421082645, -0.565630783915332, -0.570894103737566, 0.136256232065958, 0.0125142187678312, -0.252416753156908, -0.874697327263612, -0.0207816826802341, -0.726277594346789, 0.0591533396491715, 0.250699878065437, -0.0949525735234002, -0.0310354979088665]', 10.99); -insert into credit_card_transaction (time, features, amount) values (158085, '[-1.24768990124209, 0.258574818653987, 0.664601588398163, -0.706924067292257, 0.62724172827434, -1.06361941360236, 0.559785144542227, 0.0601835690905438, 0.258546847187433, -0.966875767056081, -1.26764806683635, 0.110571436150021, -0.433278256365815, 0.161993867279446, -0.567670691421919, -0.525199549629115, -0.0591756436558982, -0.513929503159043, 0.211420875090599, -0.0966974159226946, -0.0652445868956963, -0.193173736444832, -0.254527014630197, -0.0670897576134426, 0.0358721855019896, -0.125803706387639, -0.352185941632468, -0.166473857351358]', 10.0); -insert into credit_card_transaction (time, features, amount) values (158085, '[1.09005817592847, -1.61517462149508, -0.711285400444173, 1.711553924973, -1.12510981628332, -0.42838785782095, 0.0700808431066272, -0.138054034929766, 0.976149382964895, 0.0402187791408546, -1.05325854902609, -0.164431316827223, -0.618281516854788, 0.2664261075669, 0.920739069953, 0.554250295836756, -0.72607856618264, 0.533185951016063, -0.90373939641835, 0.610964972796443, 0.487811150016614, 0.505080531497447, -0.246588513068335, 0.0315011843227289, -0.282564424824381, -0.609395185264343, -0.0330880469647394, 0.0467473536239455]', 455.0); -insert into credit_card_transaction (time, features, amount) values (158085, '[1.94517387006848, -0.241569175062956, -0.246097421368926, 0.457002592176409, -0.577646756759342, -0.63147775701274, -0.34280872823463, -0.153340451065074, 1.0525046454637, -0.221808596889395, -0.507017816242199, 1.33657557323354, 1.57133815042497, -0.320969427532141, 0.538119804326634, 0.0657169606370537, -0.56950401100442, -0.463025217706063, -0.162884649896958, -0.106763572602661, -0.147477931271728, -0.227991247391173, 0.347586933704342, -0.0166408111847024, -0.399470291541983, -0.625793538646539, 0.0450018407042757, -0.0252246140384243]', 23.24); -insert into credit_card_transaction (time, features, amount) values (158085, '[-0.176098329170012, 1.15046129671737, -0.15812831391767, 0.756227431753437, 1.22377334394024, -0.265806068705763, 1.28243795759551, -0.101030561181443, -0.858309542063943, 0.17577875023774, 0.149867593381854, 0.339391446164429, -0.435790394360737, 0.695769257534579, -0.96250561109521, -0.869890683401475, -0.221390506695121, 0.31123458859643, 1.22686901128535, 0.094042016136484, 0.138920777072542, 0.671516801536024, -0.341435481249146, -0.539935988797998, 0.058850427388073, -0.362016657506103, 0.431183689553437, 0.229091353584809]', 13.27); -insert into credit_card_transaction (time, features, amount) values (158086, '[2.03415287317897, -0.0563999721090738, -0.892816077470864, 0.517532917514887, -0.373794757350399, -1.46241179829141, 0.173382401142653, -0.345780903105248, 0.55543838498511, 0.0813878377976955, -0.412029156978667, 0.427768737669155, -0.291999661212327, 0.356638052274153, 0.0399994049051681, -0.215081991071998, -0.118665670225141, -0.972814887580991, -0.0106306471366415, -0.257988374221006, -0.265330135880475, -0.644044227778443, 0.396531120191226, 0.451993456753972, -0.363876836152545, 0.170824565200438, -0.0718529614055622, -0.0564233633657493]', 0.89); -insert into credit_card_transaction (time, features, amount) values (158087, '[-1.67347859224627, 2.09736441055119, -1.15218250364996, -0.677685201245432, 0.984340414172702, -1.07562266222881, 1.05655515569714, 0.576071087840273, -1.10565562242107, -1.33014217241647, -0.889691880621656, -0.0532001770339381, 0.0978200420671897, -0.351065480929806, -0.440178978538398, -0.0761450901418398, 1.21090066505197, -0.0447371829138738, -0.12006948406886, 0.0681471398743792, 0.0359491468679062, 0.0651283022173351, -0.569491164576101, 0.582832254352365, 1.36086012745298, 0.84488460334357, 0.0365064488336446, 0.0246598386572959]', 16.43); -insert into credit_card_transaction (time, features, amount) values (158088, '[2.04898285988623, -0.809157412263293, -1.19863065081856, -0.707368616270271, -0.683809072666342, -0.514626119253209, -0.950765730680637, 0.0007066637476348, -0.201098871251505, 0.22521234099967, 1.14492711769896, -0.0748373523805822, 0.300909258462651, -1.94747469079178, -0.312168923631464, 1.89304740953025, 1.05531734065522, 0.0471170297000639, 0.530942430854705, 0.118985910066886, 0.296080882700273, 0.858451639569599, 0.0284410005525877, -0.487760730585029, -0.157783588388586, -0.0857620726217122, 0.0230679318613714, -0.0195537234091875]', 49.98); -insert into credit_card_transaction (time, features, amount) values (158089, '[-1.16198629433283, -0.487939610289333, 0.904127925716778, -2.22301250157102, 1.38003811967009, -1.16433447448122, 0.280990577022542, -0.104294490043446, -1.53165603409977, -0.323412650519439, -0.968318252230365, -0.784159614612916, 0.152972323596845, -0.188819828172465, -0.80056586662978, 0.765583228731952, 0.171859054565474, -1.79014479266086, 0.277835752558299, 0.300254554501421, 0.0910332076619541, -0.140182209560325, -0.252457996905965, 0.610698495978681, 0.93019298021847, -0.26327404898223, -0.0645582105115289, 0.0548755703683155]', 12.55); -insert into credit_card_transaction (time, features, amount) values (158089, '[-0.433889077243946, 0.800554457693849, -0.305057486031491, -0.970588032953791, 1.01851606966106, -0.262851475986909, 0.833047888990124, -0.0180597856725609, 0.0644846972925898, 0.193718585024979, -0.178957026390183, 0.416089939296449, 0.0095756058837613, 0.153093968542073, -0.972174670074616, 0.404863444829806, -1.06875207180648, 0.0912901858579476, 0.607229444378598, 0.0387884814494773, -0.323018518986299, -0.672736826166993, 0.0807835559952665, -1.11258777438451, -0.30034589338388, 0.1885896803278, 0.252166149381054, 0.116147280603481]', 7.23); -insert into credit_card_transaction (time, features, amount) values (158089, '[2.0972824569959, -0.122837377581949, -1.49433508003744, 0.0453884386749687, 0.446506575346497, -0.269671173220791, 0.0611900357318454, -0.121577760337433, 0.347684260640149, 0.242547157747946, 0.000471490289366, 0.799868619863082, 0.223425783169, 0.396046242933982, -0.587579889438837, 0.403646467333126, -0.934799205605278, -0.0286559466527968, 0.842816120488545, -0.17663594525776, -0.308526743594896, -0.780633207367095, 0.194339703658428, -1.0966393660842, -0.182098193310612, 0.245392637009632, -0.0754371501457788, -0.081112124469335]', 0.89); -insert into credit_card_transaction (time, features, amount) values (158090, '[2.04022698036619, 0.658167032476465, -2.3487897119355, 0.760713881935295, 0.654877582400217, -1.70245314609606, 0.434325669809334, -0.446553374295066, 0.344668574926125, -1.23910966579679, 0.429646187388238, 0.357713724979096, 1.04426080147407, -2.74139513460311, 1.00033307392637, 0.662443419583762, 1.76502281758142, 1.05022075325544, -0.777519740340114, -0.0915884423184959, 0.115642016200398, 0.596336920673733, -0.0536546823590322, -0.19838279863096, 0.27911496096633, -0.101090590032899, 0.0302855162472742, 0.0095794889283817]', 1.0); -insert into credit_card_transaction (time, features, amount) values (158091, '[1.99373726003452, -0.128551236105866, -1.21210779884686, 0.277867324408519, -0.072599845457297, -0.977883338490194, 0.0823197767094163, -0.206173711074434, 0.416070334233448, 0.176719786770898, 1.06998956339337, 0.865144122556398, -0.341132433944465, 0.730141816206901, 0.151610672797818, -0.050163913392258, -0.666130643785583, 0.397455026153235, -0.0701331750669008, -0.243053398794669, 0.324767308954143, 1.0401913437532, -2.11894081769692e-05, 0.0480036787816706, 0.183149230777361, -0.12138387454437, -0.0205936778891407, -0.0663924774679762]', 11.1); -insert into credit_card_transaction (time, features, amount) values (158091, '[-11.6373442487818, 9.0848328835584, -10.0612756405108, -1.09557785929482, -5.55419239170499, -0.0561926905982396, -8.49487653967082, -0.1933009134856, -1.9676981611826, -1.98497239267709, -2.5323207435467, 4.0255418758943, 0.411374104930579, 6.88131039796648, -1.5039953417143, 1.93370903532687, 3.11611940879729, 0.990513274007641, 0.0652677529649987, -4.23828977636867, 9.05864041259056, -1.99644529309411, 1.79782625063198, 0.111193497118115, 0.0961089492494726, -0.0714180539927687, -4.28261248876486, -1.05808292112014]', 38.52); -insert into credit_card_transaction (time, features, amount) values (158091, '[-1.06892760141129, 0.679531804648469, 0.496769394920854, -1.10897952955767, 1.78120525080318, 1.42859514307248, 0.565155374231507, 0.488640447428433, -0.442491627784629, -0.36558883735647, 1.45487714890164, 1.16339016572397, 0.223867215645962, 0.304549993892942, 0.0805396832700647, -1.1533923770563, 0.433267526309248, -2.09889428723114, -1.03189287730293, -0.143834738902689, -0.101692991122473, -0.0732590155041425, -0.0778990427242523, -1.73826612603025, -0.466285170297431, 0.324106203458366, 0.106841904127213, 0.183326479889934]', 3.57); -insert into credit_card_transaction (time, features, amount) values (158091, '[1.98983911549471, -0.167762601128678, -0.220172748471614, 0.438222040230277, -0.554844735846896, -0.639797879983998, -0.373488526050164, -0.147339565414892, 1.05522786124679, -0.211040134713208, -0.507349059861029, 1.33562329001869, 1.56721616377068, -0.32620370340295, 0.535211320906856, 0.0626675588977888, -0.570189451865006, -0.467762211343751, -0.155500347584958, -0.153846534119709, -0.161487052325711, -0.215788787332005, 0.367964890177989, -0.0178271556624584, -0.390981194520225, -0.623327737766295, 0.0493702941945669, -0.0292502160887878]', 0.12); -insert into credit_card_transaction (time, features, amount) values (158092, '[-0.945571368518438, 0.345248661102196, -0.104713006087022, -0.375220681723907, 1.29294656348924, 1.5020201731981, -0.268593298222835, 0.897182453812541, -0.578976354767741, -0.452630233812574, 0.969874257297121, 1.04823606402067, 0.41313439818138, 0.621214788828823, 0.565115248463854, -0.921622321105943, 0.577927384066225, -0.987319320929827, 0.288758252417057, -0.16256167796487, 0.250844899541348, 0.721966946636435, -0.131584611825962, -0.643500804193784, -0.963155428449924, 0.697784785409688, 0.0226496159612859, -0.0186477525200934]', 10.0); -insert into credit_card_transaction (time, features, amount) values (158092, '[-0.209248039182748, 1.21046148850354, -0.622695514067446, -0.902893326213596, 1.18818944175993, -0.281837134425201, 0.996983919657194, -0.0990396653633745, 0.337140466220848, 0.181288498260055, 0.652507690444982, 0.0486284040640577, -0.604548129186652, -1.08134386226685, -0.785732542280408, 0.556438402618319, -0.131996816515832, 0.433140761214962, 0.173297280670453, 0.335195668110087, -0.436383202740261, -0.867710038422543, 0.0157292701385595, 0.0668860011035545, -0.336403674983663, 0.104436032475606, 0.26002898699554, -0.032387403453054]', 0.99); -insert into credit_card_transaction (time, features, amount) values (158092, '[2.12688561612748, -1.12033650643079, 0.0412171574653195, -0.520921338665569, -1.43041239998944, 0.0318491089562395, -1.53857563764103, 0.119997478410251, 0.504754086055302, 0.83086289711949, -1.78090165980089, -0.440107733713972, 0.433077761028875, -0.515802819316194, 1.16190874333842, -0.338854218444129, -0.822684668921011, 2.01228175000271, -1.04100016339986, -0.56189718643089, -0.189582605382326, 0.053209387922822, 0.250125297174141, -0.7224056769836, -0.612606122269372, 0.659214522437881, 0.021935615860717, -0.0374890291062133]', 10.6); -insert into credit_card_transaction (time, features, amount) values (158092, '[1.96935560368262, -0.389883230467109, -0.860295217933778, -0.0691540389844665, 0.135502656346451, 0.569185284517156, -0.570246987805748, 0.128296357910764, 0.968137439068462, -0.0965435611373025, 0.354805148800534, 1.51083945074064, 1.54646829219618, -0.106936781341768, 0.382057082656561, 0.523140069573143, -1.28349787732976, 0.946080774368326, 0.215247563958677, -0.0353247654014468, 0.250311428018148, 0.866260100202517, 0.0072383603202719, -0.170872031855957, 0.063280242421168, -0.562632724884825, 0.0564978371889291, -0.0380977033897141]', 30.0); -insert into credit_card_transaction (time, features, amount) values (158093, '[0.144284134251589, 1.09701381060509, -1.27984817797986, -0.248399162918321, 0.506294047342374, -1.26029698830937, 0.969009356706899, 0.0716723841132748, -0.486967991748855, -1.19718257169359, -0.302282031039785, 0.677959653353355, 0.931052162282815, -0.820926142919542, -0.612156053806736, 0.177681206447504, 0.7250286079839, -0.354932607331892, -0.512536008426331, -0.12969062150067, -0.0199763616884816, -0.147434002706866, 0.349884271557535, 1.08153178203605, -0.746222866277082, 0.135989146805322, -0.133632375042151, -0.0189512121768577]', 52.9); -insert into credit_card_transaction (time, features, amount) values (158093, '[-0.902479634210226, 1.06456754642278, 1.73902148032602, -0.480557081508535, 0.0314875589730367, -0.363817899495278, 0.781053376846971, -0.439609582800063, 0.607835262754474, -0.0817150309896642, -0.602260850649336, 0.566248284545627, 1.14575037981274, -0.777811370224999, 0.525559254174712, -0.27114738682877, -0.64226912850371, -0.191716059596236, 0.382167300429845, 0.0241779080986937, -0.158733980848731, -0.0930980463870523, -0.112271607997907, 0.0392800682048323, -0.383921818964599, -0.669129153950408, -0.981054582144627, -0.593218626625402]', 10.0); -insert into credit_card_transaction (time, features, amount) values (158093, '[-2.3082093081445, 0.516493102417341, -0.465689627415325, -0.361627055738481, 1.20385129752107, -1.69198013493389, 0.831126471614565, -0.220078299250809, 0.133947881463859, -0.45390238400603, -0.321428030253902, 0.278990305672809, 0.870206623696915, -1.09812131966602, 0.584610964931516, 0.13356764643819, 0.33816186420952, 0.403840288740456, -0.623775450638294, -0.10110594924905, 0.144765254720549, 0.846619836996749, -0.57427240524202, -0.0222217951323605, 0.384077794559862, -0.160721315925312, -0.221768432854791, 0.23606970982294]', 21.71); -insert into credit_card_transaction (time, features, amount) values (158094, '[-1.67552857998417, 0.789513581650327, -0.144200820367981, -0.177578885583882, 0.367189376223954, -1.63713296563304, 0.618681684342823, 0.0472270149307917, 0.0309280894020112, -0.0555025112303673, -0.550045375047246, 0.188680932587619, -0.0345510673779806, 0.578769003699882, 0.66328298375021, -0.484036855709808, -0.0959406586240212, -0.0627669500446129, -0.0382383674992371, -0.432645476035113, 0.226635517892696, 1.27325858221429, 0.364075160135979, 0.440989083181606, 0.0390955556747681, -0.0957686566466375, 0.35789741608757, 0.107298306242012]', 0.89); -insert into credit_card_transaction (time, features, amount) values (158094, '[-0.0728698912035648, 0.794483211035932, 0.554977612465192, -0.557569649482135, 0.248454464677606, -1.14635090102269, 0.908535971754675, -0.105277483184297, -0.372240093731409, -0.246169446628157, 1.31273959452789, 1.13093504214468, 0.0452788551300183, 0.301762261814226, -1.16693675415454, -0.0722654900478796, -0.465999033855831, -0.461733859289495, -0.0082963914979424, -0.0169258088447094, -0.164664198163728, -0.340209712214373, 0.136421982557808, 0.547460822469341, -0.584690323268993, 0.0851112834151908, 0.243376587885302, 0.0944527549640905]', 4.49); -insert into credit_card_transaction (time, features, amount) values (158094, '[0.0076762342675182, 0.602594305469068, -0.346944258362736, -0.630931423287438, 0.537102720279461, -0.639662617786215, 0.953878169041618, 0.008705010827957, 0.240763866096902, -1.36100304416301, 0.521679806275906, -0.069937066555374, -1.418475364914, -1.15305078755537, -1.12579890375648, 0.353552293399419, 0.660586113180797, 0.908240870549429, 0.332585135742902, -0.0856111947097896, -0.122386560819535, -0.337306762812071, 0.0158253349827007, -0.495349777803418, -0.320215450071142, -0.160658216895598, 0.0369745959354867, 0.0614416220363263]', 61.16); -insert into credit_card_transaction (time, features, amount) values (158094, '[2.15929692637919, -0.920283439608135, -0.637066089279967, -0.912802464072116, -0.787560956950413, -0.261056085866641, -0.964008885733249, -0.100728899683998, -0.0489112509454606, 0.688319090935912, -0.705723104940489, 0.0861596228425579, 1.43715871889795, -0.736503236179224, 0.142668314499269, 1.0995716356906, 0.0551134679616648, -1.30800729622118, 0.420979136030512, 0.0865952466864251, 0.332727685032672, 1.06028550637764, 0.141628550941401, 0.67247754066917, -0.0921963402278394, -0.115733064794957, 0.0148910784904178, -0.0387728287144674]', 19.95); -insert into credit_card_transaction (time, features, amount) values (158096, '[-0.760820454007006, 0.771373118508915, -1.18205937887548, -0.840363740520401, 0.899014319077187, -1.84189477764295, 1.40246651726575, -0.0703127636718442, -0.614653352231739, -0.758855184747824, -0.963621443258745, 0.216288463779397, 0.0667266735314359, 1.02384298191477, -0.178536956902159, -0.601902716048616, -0.186093646034804, -0.430376500503685, -0.235896501288051, 0.082547212738367, 0.372180077851166, 0.918660692502304, -0.0422342629547716, 0.043406045696035, -0.269458277180909, 0.0864687733086281, 0.260017702307211, 0.14680080513015]', 68.8); -insert into credit_card_transaction (time, features, amount) values (158096, '[1.97897161253861, -0.12271942589058, -0.818335039918767, 0.437949366216083, -0.405756537761386, -1.22369453833558, 0.0599579047979109, -0.195545557354451, 0.319208864341505, 0.255995578532438, 1.37619779107814, 1.04631494416936, -0.621433962788435, 0.605794473697494, -0.64656236173159, -0.0496292982180108, -0.305156611300904, -0.496567567758861, 0.226480363475753, -0.26339181201177, -0.20615817388538, -0.524010360318269, 0.403332219604305, 0.535034931250825, -0.420794859830978, 0.145173663531665, -0.0771295292833862, -0.0654431228871805]', 1.98); -insert into credit_card_transaction (time, features, amount) values (158097, '[1.93684448474331, -0.459957053368673, -0.436654368362665, 0.266731859007182, -0.531146053282273, -0.135797893216158, -0.619705804906207, 0.154217241718442, 1.17721755098334, 0.0187772005945139, 0.433166713154755, 0.641003868045781, -0.799038135535103, 0.319363937084133, 0.12466749101519, 0.488390322821929, -0.830853302875314, 0.450556069140534, 0.294263149302829, -0.242283824119552, -0.151658903364968, -0.379608174808109, 0.317836324793646, -0.534196990416578, -0.454452184667279, -0.610169811420252, 0.0260697326757262, -0.0452457544574447]', 18.99); -insert into credit_card_transaction (time, features, amount) values (158097, '[2.13724038835429, -0.0767820880380639, -1.49953745402167, 0.171789674906908, 0.361412519393058, -0.619948570685321, 0.159668625276571, -0.2668268681067, 0.616546030792667, 0.0759534963100051, -1.67495891149597, 0.0826522950004897, 0.221711034128348, 0.217681086666965, 0.118560583888986, 0.198960273344012, -0.664590594500009, -0.527720051793603, 0.53834615359303, -0.194121966998247, -0.358436791059324, -0.89202155091498, 0.212811028669473, -1.00438021385273, -0.160149620411906, 0.260572172472175, -0.0720828416284717, -0.0706878727445317]', 0.89); -insert into credit_card_transaction (time, features, amount) values (158099, '[2.04387672336769, -0.0846674535145838, -1.17046565587378, 0.221744277516308, 0.0975798411436982, -0.699349269871648, 0.0941374882679135, -0.184303467952483, 0.258268734527393, 0.234205600915405, 0.723030270600547, 1.181885652391, 0.336264536122014, 0.392713651797382, -0.670224327610842, 0.17018457001624, -0.672234711203558, -0.307112913648747, 0.554358658703094, -0.185525474911905, -0.255666552293944, -0.620343779670996, 0.285449724897866, -0.327792936351933, -0.275322977020132, 0.197380355771073, -0.0728309121097359, -0.0728667314004909]', 0.89); -insert into credit_card_transaction (time, features, amount) values (158099, '[2.11661697421739, 0.13988800206923, -1.95384656993448, 0.277856936910916, 0.703663218772156, -0.540145171684285, 0.171286196442692, -0.19686759770259, 0.538975465110964, -0.376604706201481, -1.10632820495494, -0.0647437483990968, 0.141881405729279, -0.874788152684911, 0.251856817102947, 0.491800875002354, 0.25802583842177, -0.109576109857345, 0.2779795637991, -0.137902310275977, -0.404049926017248, -1.05691684611398, 0.266147493008966, -0.0631275766619684, -0.179437534902895, 0.208739723439506, -0.0636972154647032, -0.0365257073002679]', 1.98); -insert into credit_card_transaction (time, features, amount) values (158100, '[0.342793110429886, -0.287261030687008, -0.0933252341703406, -1.98418595427963, -0.439231421928649, -1.30291887895992, 0.953927075161979, -0.725135954950892, -0.24768179211501, -0.200636040787097, -0.604255406676331, -0.286895491866822, -0.101875221684159, 0.483180366917527, 2.2764595567812, -4.07312753230281, 1.1296607636659, 1.7207327520418, 3.05152389374649, 0.042896461353378, -0.139282440121017, 0.425724045137724, -0.0981341315100914, 0.0641253377323846, -0.189590036827337, -0.33438345492012, 0.0804654432333014, -0.0350896019737029]', 84.98); -insert into credit_card_transaction (time, features, amount) values (158100, '[-0.0193845230578541, 0.0813437116183215, -0.123084684200039, -1.58005600867001, 0.93049143996304, -0.103879633803591, 1.14701778970959, -0.320478472201595, -1.5751004504366, 0.500310713256511, 0.0489999403243191, -0.0850124452179171, -0.321662537639655, 0.216845786602834, -1.57096092005955, -1.89677815738097, -0.35518412949643, 1.26978681811476, -0.295770640168619, -0.375383949353751, -0.285242347633549, -0.204706377164344, -0.0997544452359128, 0.294668911114002, -0.346887294312847, 0.419339624073865, -0.0716772597504023, -0.0581369955977684]', 47.61); -insert into credit_card_transaction (time, features, amount) values (158100, '[0.077338945991989, 0.78043299830265, -0.640003489208689, -0.143651965877503, -0.0497355010155829, -1.02703426150194, 0.8402653211067, 0.050636154370072, -0.308546339817244, -0.747207653142655, -0.772159076419779, 0.74030875278531, 1.20104953565085, 0.463585501741128, 0.457891359104055, -0.26833922711374, -0.340616230476837, -0.0014976789631764, -0.172396361044441, -0.0498765453656851, 0.455633963603872, 1.23155707232782, 0.0981427884553025, 0.0398010447751219, -0.216981162458766, -0.15344982684261, -0.0987349005751729, -0.0655036905744334]', 85.25); -insert into credit_card_transaction (time, features, amount) values (158100, '[1.93948896381013, -0.469871527616659, -0.355205262153049, 0.312484966808565, -0.530844012474013, 0.102405750625639, -0.761942355112931, 0.179919771659607, 1.20508337731698, -0.0021177589180198, 0.713071855093997, 1.10803333132093, -0.0234264573552982, -0.000430513415361, -0.177394465297379, 0.289598893202039, -0.755625472908917, 0.724243366446333, 0.0547387499636053, -0.185511685032334, 0.241436059282215, 0.875160788592062, 0.147748254005445, 0.786338120445995, -0.115365554239363, -0.268819395548443, 0.0325550531980302, -0.0391637294338968]', 9.99); -insert into credit_card_transaction (time, features, amount) values (158101, '[-0.265021807974238, 0.697274956114369, -0.688388679669962, -0.869974136845275, 1.64982583027218, -1.17166941315847, 1.11046674296122, -0.162572723194628, -0.153901002016783, -1.22908199068775, -1.1797801547767, -0.824489707332643, -1.09346658575399, -0.84617004621226, -0.619360685699456, 0.476813991349286, 0.348184745220955, 0.0947197243395556, -0.648285495929034, -0.152868525317181, -0.0981157713555551, -0.38299439991256, 0.0410077863271335, 0.354661677272148, -0.745871456918168, 0.104786055970378, 0.124732442157054, 0.246742116830861]', 7.32); -insert into credit_card_transaction (time, features, amount) values (158101, '[-1.53465908150274, 1.83862678673387, -0.225463045383317, 0.627528112515424, 0.0814690901189145, 0.158890236656975, 0.778377446016933, 0.292274706503078, 0.587254266549266, 1.48982586201722, -0.0474177881095055, 0.347026558632778, -0.582561172291179, 0.018768806241311, -1.00934320804571, -0.67532281831666, -0.299188674044467, 0.622987891314272, 1.11996841402817, 0.492633683372837, -0.0403318229394232, 0.861166426769615, -0.302101170870214, -0.489750077901004, 0.105817068631284, -0.391771931245495, 0.190892164946714, -0.32077338487077]', 50.0); -insert into credit_card_transaction (time, features, amount) values (158101, '[2.09053781353743, -0.547143517118784, -3.29258777410779, -0.537067214986212, 2.5665972963547, 3.09317919064836, -0.188776529132601, 0.555901723556236, -1.36214212417098, 1.18274884948291, -0.223201049388393, -0.12555819244218, 0.0041256952931892, 0.868090946799658, 0.454891850807344, -1.9839575136078, -0.266557366563513, 0.809412645089907, -1.28246339681873, -0.533037281324756, -0.218750585962745, -0.255323010400983, 0.0725633230485925, 0.659471849256448, 0.384969116239264, -0.466116121958146, 0.0054405674281493, -0.0582073378255668]', 45.2); -insert into credit_card_transaction (time, features, amount) values (158101, '[2.06360645255844, -0.0080988959583393, -2.1840391122884, 0.253442875798909, 0.981182324095781, 0.206991589632901, 0.0280561470070728, -0.0380252177049686, 0.450482617226158, -0.337788933248111, 0.216127637494887, 0.935351993727404, 0.771354281599726, -1.21895805439434, -1.16659693185526, 0.296451667504787, 0.27291902563184, 0.661789895473593, 0.556792128241113, -0.0651142166440278, 0.0566303460881829, 0.455676732574935, -0.132063635577595, -0.349217482142836, 0.343083153233551, 0.738252366421223, -0.0561431944882507, -0.0558538496660642]', 11.5); -insert into credit_card_transaction (time, features, amount) values (158102, '[-1.27296375104223, 1.88699037994696, -0.756176621991244, 0.957220735304354, 0.385955420695301, -0.805606952243749, 1.00840441500542, 0.145876223297351, -0.634180010522493, 0.187680483544885, -1.23468672343011, 0.338744163777208, 0.319722725289077, 0.664042348234363, -0.365579616732331, -1.08212770506513, 0.338923039821917, -0.386382316018162, 0.799782946402919, -0.228475712430853, 0.177829637118788, 0.707880143356651, -0.142214885799575, -0.0535052591581526, 0.0497312265199262, -0.44020018233763, -0.463285623672708, -0.137061202222681]', 28.4); -insert into credit_card_transaction (time, features, amount) values (158103, '[2.08843181991689, -0.597663861725287, -1.60705924591156, -0.525817581719043, -0.141958731875097, -0.82804042526325, -0.0067765119945119, -0.295739523510996, -0.859592029815763, 0.951878959883511, 0.46821198409591, 0.650193689374901, 0.364914501521249, 0.632864186690209, -0.169142137730976, -1.41299775757809, -0.616786348629523, 1.45928476554466, -0.296017349636417, -0.530784952308861, -0.449200137458304, -0.870255972295054, 0.195789250071528, -0.557604037544169, -0.0947448225683981, -0.485496188727246, -0.0158361016860141, -0.0568455100591142]', 49.6); -insert into credit_card_transaction (time, features, amount) values (158104, '[-1.39764319371123, 0.682598729893661, 0.919836071529467, -1.71342789904981, -0.587311399409774, 0.322204267331025, -0.651363349910599, 0.959821384620919, -1.36961163945888, -0.570251734356641, -2.10664646002848, -0.211185450556423, 0.818009377711385, 0.122351819547098, 0.104790088977273, -0.62483644112955, -0.249740803889989, 1.39273780442764, -0.565480027598169, -0.601613790850221, -0.526418710070052, -1.42073393434623, -0.113685596832628, -0.005276844422918, 0.210579362064958, 0.397052768195102, -0.361447905737923, -0.0898720733709888]', 18.0); diff --git a/pkg/udf/pythonservice/demo/dist/detect-1.0.0-py3-none-any.whl b/pkg/udf/pythonservice/demo/dist/detect-1.0.0-py3-none-any.whl deleted file mode 100644 index 9e78c923f4ebb68700ea6bfd29e77908e6147dab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4152 zcmai%cT`i`w#EZUZ_|iUBDh z6hW#~=~4v*9^Uib!|OecyZ4x5jrGU;eRGVxzcts?ff8Jz2LJ#h009G8L!Ih{JM!l{ z$a&D7hqZ^T4Z=&r!UExf@UpNFc6)f&0Ni&6^AT$JMxRdzf~%QXfEx@94@Sfohju98 zH<}_qhjnEBz!L5f40r0`L$cI5!b1=@*=0O)VSvv6YyI$(HGDPHo#9Lb08CQ?0CX2x zHnv{2)?Nr#mvga*6sRjFhBo3L`NuWQ6~gaiDdJqyLWi&IWP8SH1ofP^oYj>$_@+}& z4|YI2KA$P`P(MO$h_mx*r}G7`WOfeQowaP_{FR!yxwGC|v~j9X;CY+$FJjzs$hxiV#(Fex&n2B+5an{x!L70ta- zRCv}k`2)RxL=THn3S||!pGj)1Dk$z8_AdzCRxdO|Pp9F~j>b`Q{xuI@Nza{nDU|rD ziQA*=A{C|;UPr&#Y+lxwM624%B~-9C^qw{?1+l)Hk!<-ZpdbRCd#2c;zW(W2SBm$- zn&&%H{>fzMo{WjGFWRofwC{EcVf&F*u}{8*MNnh8>!$OjCf`^DeV{b$R~6R;fhh)i zs}DfITew*7*7a;?1<$;kaQEzDkKM;mjOGZWJ_f?;xuaoQu9siWm#XEN<4 zv2lDkFIh3E3FRUj39;{^|H37j0i`v{q1{4$;w!zMLn^*05=#U!E^)I$IdsDuTUEA6 ziTgfXUeyI#i5qnACVEmX#(MJ9z9?xgPRit-I|NGGxx(w8BnP0d{sY^7JA1T-kJE2T zcGzqRD23+3`OV*cc~E$*$n;5-iqAs8Fr(YTP=k>$T6VQMwvMD0CsA=j6T$<~e8Y*V z(^f|_i%f013q-V8wFmlO>}t45UO0iJliNUb%U8at$zwl1M;MA#-KyqEp$(|wX&<4d zKtd9%-h`;#`{wSBLBZ*1vf6o^)Az;eXPn%*=b-tt1MNm(p;vY_O5=U|>_VMrHs{y< zNh3^lqfzh0N{I{MsTvAVQonyrL{V#J`WgCEmht5e)7 zN_hM!zj%*jK?sNzTL~cKXLxKv5}BdL<`oyV&vWFLuL&e1V5JmiluNzi-Y_z zvi{DoJt*zhs$7&v{oL(MR)XhuXud;B`V6?~7}#c2LL!z(v0r_44_zd!R!O;u?&p@& z4Q`v?@0lQrzfWW2S-|_)0o+O_#bs?TCKe~W5E9@~qUmJA&XKGVsXE%3P2yapV%T-> zsMMQ1gOJ|H5Br>1%H6Jd`G+3B_L2Zeo4JtE+meLBPl<}X?1kd0{~ zDJsa4C*cQ#4~HR>H)nEemo=4k(~gKp zdP!H>^d7gh3gm=mt6HV$Gw$A!YyMhksy|Op>z_`svWQSyCuY-Fy`J;HJ}+$p=0y_N zN3y}flLGwMO1`pRMav1u<1XgEUl&5^zpRG5YGlkOZ^$`2a9yNW@@cWaV}uGkou5sz z)X3N@qtwyT3Gy04IgWmyZsSd0+Lxf6Ra~v=Bwc*;O~C^%7J%BK&lXJ1tg}i|<}?U< z3(K|H8R0X@Kw#e+q!@;m?T(t$y=x14LM0Sxn?uS%yXaL@)hEyV;Nb`TFY)=soe0D6 zw!En}oCT--Xa0ET&{507T(F@ zQAGvZ$?o*~03uA=n#(tGfwZIVjsoI`H8h_>XNViR_P5s+W6|-!c8l`)9^2Fx-RZi8 ztYKp1`}Jc20AP#|0ARl8PR_12woVql2rmZdzbWx(|D-3SkIxtXkM8c8|CSxh~SUxmP9E` z03r1_UjajMS{;TaqB%r|Ub-kv4!{Q_ZKbZz;X(lFS5P$Bg`x3N2DeU$94FCisd66T z%DMQV-Rce>%wFE;ojw7=`giJ-86+-W?g=U6E8~RveTC~whUQu~TdRCHSoRo(?*<4K zu!t5Kz5MWAR4Ef{+;!Eh8yoUhct0XxGzU4CDD&oo>)1%dB(XSWs>?_`HK6cA)G^qP zB+*~x+ac>gx6{k4JiIQxO5Y_aSX(u{rxeIc`&)y=_)D+kXL1F{l-a8?QxZ1Da54g% zjRTPKR)rhIt!AxDwOQf5BEh3i-r}IH)T%T?;K0-?Y`F`uCs@(ne&VCIe##8g^GV4OwFW~hQ6qr%*mqivG{Jx zY}R5q)4Q}5>N?fE`DrWuim7oseP=5#dr6qjX;#lyQK}0h|_w^ zoM(4>g;ROmS+)?ka_IzfxnnDyMX@rLFmw$y;l#=zGL9UApb$bHk%ByaB> zi%)Yx6=}hkXXDd~O`GfFX#4e+&2dC?bR2nbFRyToa|Uf+dC+#^GL|~L-(WL?b^HXW zaB}n{CP>jSD$c3$grRRduu>kohhEm5-745;C?YD1XnT~z9#NU+D|hw@b|~B+EnT%e zxmBW4Tpq=)ZkBA*aY}G;V2C}GH5Ab|UJ*Y(C}hs#+Ijqaj};OV7CnD$5T0H_2p2n7 z5g15MSxs3_c?Tv0(Sis0Mx+`J*2D-3 zM~e`b=njYuNT3EJu=8Zy{UX>s!4XP6Au5k~$a} z-FJ$^T7Zqk_aep0QrrB1JOh)_UjvStE8~Qmn`U&FtdeFVGvQ%v8dUo4y;HX+WB3v# zc-H}@j=BLV-1={I%1c_nZlWKZ0tRoT`MHe;54Af1!*tV3dkdLvdu~VBzu36$WGNdb zX3_{mL=YEl)Czz>3luzIHiu+YU}VEOUa6FerTKHUH^S%0B&r~vFXl7y zVQBfMWMT+x1zt@sn`9*#;|nz93w`Bc*R07RGL7|^mQ>RD^H#(ahY^ap@S)n{V% z-x`t8AVWZDag9Ql8>@b9qSEqMVe{WI)e2K}A%yNxbLN)&%A>)%ZEJMnin{U7lyUhJQV Ze|t*@N_ak{|MWC5;P~8-yi`AT{{u=1Lk<7{ diff --git a/pkg/udf/pythonservice/demo/setup.py b/pkg/udf/pythonservice/demo/setup.py deleted file mode 100644 index 8db958bbbf793..0000000000000 --- a/pkg/udf/pythonservice/demo/setup.py +++ /dev/null @@ -1,12 +0,0 @@ -# coding = utf-8 -# -*- coding:utf-8 -*- -from setuptools import setup, find_packages - -setup( - name="detect", - version="1.0.0", - packages=find_packages(), - package_data={ - 'credit': ['model_with_scaler'] - }, -) diff --git a/pkg/udf/pythonservice/pyserver/requirements/base.txt b/pkg/udf/pythonservice/pyserver/requirements/base.txt deleted file mode 100644 index c3d724172e0cd..0000000000000 --- a/pkg/udf/pythonservice/pyserver/requirements/base.txt +++ /dev/null @@ -1,12 +0,0 @@ -#-i https://pypi.org/simple --i https://mirrors.aliyun.com/pypi/simple - -grpcio==1.59.0 -protobuf==4.24.4 - -numpy==1.26.0 -scipy==1.11.3 -pandas==2.1.1 -scikit-learn==1.3.1 -tensorflow-cpu==2.14.0 -onnx==1.14.1 diff --git a/pkg/udf/pythonservice/pyserver/requirements/pytorch.txt b/pkg/udf/pythonservice/pyserver/requirements/pytorch.txt deleted file mode 100644 index d23b156a670c2..0000000000000 --- a/pkg/udf/pythonservice/pyserver/requirements/pytorch.txt +++ /dev/null @@ -1,5 +0,0 @@ --i https://download.pytorch.org/whl/cpu - -torch==2.1.0 -torchvision==0.16.0 -torchaudio==2.1.0 \ No newline at end of file diff --git a/pkg/udf/pythonservice/pyserver/server.py b/pkg/udf/pythonservice/pyserver/server.py deleted file mode 100644 index 262df4861f08f..0000000000000 --- a/pkg/udf/pythonservice/pyserver/server.py +++ /dev/null @@ -1,417 +0,0 @@ -# coding = utf-8 -# -*- coding:utf-8 -*- -# Copyright 2023 Matrix Origin -# -# 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. -import argparse -import datetime -import decimal -import enum -import importlib -import json -import logging -import os -import shutil -import subprocess -import threading -from concurrent import futures -from typing import Any, Callable, Optional, Iterator, Dict - -import grpc - -import udf_pb2 as pb2 -import udf_pb2_grpc as pb2_grpc - -DEFAULT_DECIMAL_SCALE = 16 - -DATE_FORMAT = '%Y-%m-%d' -DATETIME_FORMAT = '%Y-%m-%d %H:%M:%S' -DATETIME_FORMAT_WITH_PRECISION = '%Y-%m-%d %H:%M:%S.%f' - -ROOT_PATH = os.path.dirname(os.path.abspath(__file__)) -INSTALLED_LABEL = 'installed' - -OPTION_VECTOR = 'vector' -OPTION_DECIMAL_PRECISION = 'decimal_precision' - -logging.basicConfig( - level=logging.INFO, - format='[%(asctime)s] - [%(name)s] - [%(levelname)s] - [%(threadName)s] : %(message)s' -) -log = logging.getLogger('Server') - - -class Server(pb2_grpc.ServiceServicer): - - def run(self, requestIterator: Iterator[pb2.Request], context) -> pb2.Response: - firstRequest: Optional[pb2.Request] = None - path: Optional[str] = None - filename: Optional[str] = None - item: Optional[InstallingItem] = None - - firstBlock = True - lastBlock = False - - try: - for request in requestIterator: - # check - checkUdf(request.udf) - - # the first request - if request.type == pb2.DataRequest: - log.info('receive data') - - if request.udf.isImport: - path, filename, item, status = functionStatus(request.udf) - - if status == FunctionStatus.NotExist: - firstRequest = request - yield pb2.Response(type=pb2.PkgRequest) - - elif status == FunctionStatus.Installing: - with item.condition: - # block and waiting - if not item.installed: - log.info('waiting') - item.condition.wait() - log.info('finish waiting') - yield self.calculate(request, path, filename) - - else: - yield self.calculate(request, path, filename) - - else: - yield self.calculate(request, "", "") - - # the second request (optional) - # var firstRequest, path, filename and item are not null - elif request.type == pb2.PkgResponse: - log.info('receive pkg') - - # install pkg, do not need write lock - absPath = os.path.join(ROOT_PATH, path) - lastBlock = request.udf.importPkg.last - try: - if firstBlock: - if os.path.exists(absPath): - shutil.rmtree(absPath) - os.makedirs(absPath, exist_ok=True) - firstBlock = False - - file = os.path.join(absPath, filename) - - with open(file, 'ab+') as f: - f.write(request.udf.importPkg.data) - - if lastBlock: - if request.udf.body.endswith('.whl'): - subprocess.check_call(['pip', 'install', '--no-index', file, '-t', absPath]) - os.remove(file) - - # mark the pkg is installed without error - open(os.path.join(absPath, INSTALLED_LABEL), 'w').close() - - except Exception as e: - shutil.rmtree(absPath, ignore_errors=True) - raise e - - finally: - if lastBlock: - with item.condition: - item.installed = True - item.condition.notifyAll() - - with INSTALLING_MAP_LOCK: - INSTALLING_MAP[path] = None - - if not lastBlock: - yield pb2.Response(type=pb2.PkgRequest) - else: - yield self.calculate(firstRequest, path, filename) - - else: - raise Exception('error udf request type') - # notify all - finally: - if item is None: - with INSTALLING_MAP_LOCK: - item = INSTALLING_MAP.get(path) - - if item is not None: - with item.condition: - item.installed = True - item.condition.notifyAll() - - with INSTALLING_MAP_LOCK: - INSTALLING_MAP[path] = None - - def calculate(self, request: pb2.Request, filepath: str, filename: str) -> pb2.Response: - log.info('calculating') - - # load function - func = loadFunction(request.udf, filepath, filename) - - # set precision - if hasattr(func, OPTION_DECIMAL_PRECISION): - prec = getattr(func, OPTION_DECIMAL_PRECISION) - if type(prec) is int and prec >= 0: - decimal.getcontext().prec = prec - else: - decimal.getcontext().prec = DEFAULT_DECIMAL_SCALE - else: - decimal.getcontext().prec = DEFAULT_DECIMAL_SCALE - - # scalar or vector - vector = False - if hasattr(func, OPTION_VECTOR): - vector = getattr(func, OPTION_VECTOR) is True - - # init result - result = pb2.DataVector( - const=False, - data=[], - length=request.length, - type=request.udf.retType, - scale=defaultScale(request.udf.retType) - ) - - # calculate - if vector: - params = [] - for i in range(len(request.vectors)): - params.append([getValueFromDataVector(request.vectors[i], j) for j in range(request.length)]) - values = func(*params) - assert len(values) == request.length, f'request length {request.length} is not same with result length {len(values)}' - for value in values: - data = value2Data(value, result.type) - result.data.append(data) - else: - for i in range(request.length): - params = [getValueFromDataVector(request.vectors[j], i) for j in range(len(request.vectors))] - value = func(*params) - data = value2Data(value, result.type) - result.data.append(data) - log.info('finish calculating') - return pb2.Response(vector=result, type=pb2.DataResponse) - - -def checkUdf(udf: pb2.Udf): - assert udf.handler != "", "udf handler should not be null" - assert udf.body != "", "udf body should not be null" - assert udf.language == "python", "udf language should be python" - assert udf.modifiedTime != "", "udf modifiedTime should not be null" - assert udf.db != "", "udf db should not be null" - - -class FunctionStatus(enum.Enum): - NotExist = 0 - Installing = 1 - Installed = 2 - - -class InstallingItem: - condition = threading.Condition() - installed = False - - -# key: db/func/modified_time, value: InstallingItem -INSTALLING_MAP: Dict[str, Optional[InstallingItem]] = {} -INSTALLING_MAP_LOCK = threading.RLock() - - -def functionStatus(udf: pb2.Udf) -> (str, str, Optional[InstallingItem], FunctionStatus): - with INSTALLING_MAP_LOCK: - filepath, filename = os.path.split(udf.body) - path = os.path.join('udf', udf.db, filepath[filepath.rfind('/') + 1:], udf.modifiedTime) - item = INSTALLING_MAP.get(path) - if item is None: - if os.path.isfile(os.path.join(ROOT_PATH, path, INSTALLED_LABEL)): - return path, filename, item, FunctionStatus.Installed - else: - item = InstallingItem() - item.installed = False - INSTALLING_MAP[path] = item - return path, filename, item, FunctionStatus.NotExist - else: - if item.installed: - return path, filename, item, FunctionStatus.Installed - else: - return path, filename, item, FunctionStatus.Installing - - -def loadFunction(udf: pb2.Udf, filepath: str, filename: str) -> Callable: - # load function - if not udf.isImport: - exec(udf.body, locals()) - # get function object - return locals()[udf.handler] - else: - if udf.body.endswith('.py'): - file = importlib.import_module(f'.{filename[:-3]}', package=filepath.replace("/", ".")) - return getattr(file, udf.handler) - elif udf.body.endswith('.whl'): - i = udf.handler.rfind('.') - if i < 1: - raise Exception( - "when you import a *.whl, the handler should be in the format of '.'") - file = importlib.import_module(f'.{udf.handler[:i]}', package=filepath.replace("/", ".")) - return getattr(file, udf.handler[i + 1:]) - - -def getDataFromDataVector(v: pb2.DataVector, i: int) -> pb2.Data: - if v is None: - return pb2.Data() - if v.const: - return v.data[0] - return v.data[i] - - -def getValueFromDataVector(v: pb2.DataVector, i: int) -> Any: - data = getDataFromDataVector(v, i) - - if data.WhichOneof("val") is None: - return None - - if v.type == pb2.BOOL: - return data.boolVal - if v.type in [pb2.INT8, pb2.INT16, pb2.INT32]: - return data.intVal - if v.type == pb2.INT64: - return data.int64Val - if v.type in [pb2.UINT8, pb2.INT16, pb2.INT32]: - return data.uintVal - if v.type == pb2.UINT64: - return data.uint64Val - if v.type == pb2.FLOAT32: - return data.floatVal - if v.type == pb2.FLOAT64: - return data.doubleVal - if v.type in [pb2.CHAR, pb2.VARCHAR, pb2.TEXT, pb2.UUID]: - return data.stringVal - if v.type == pb2.JSON: - return json.loads(data.stringVal) - if v.type == pb2.TIME: - sign = 1 if data.stringVal[0] == '-' else 0 - h, m, s = data.stringVal[sign:].split(':') - if sign == 0: - return datetime.timedelta(hours=int(h), minutes=int(m), seconds=float(s)) - return datetime.timedelta(hours=-int(h), minutes=-int(m), seconds=-float(s)) - if v.type == pb2.DATE: - return datetime.datetime.strptime(data.stringVal, DATE_FORMAT).date() - if v.type in [pb2.DATETIME, pb2.TIMESTAMP]: - formatStr = DATETIME_FORMAT if v.scale == 0 else DATETIME_FORMAT_WITH_PRECISION - return datetime.datetime.strptime(data.stringVal, formatStr) - if v.type in [pb2.DECIMAL64, pb2.DECIMAL128]: - return decimal.Decimal(data.stringVal) - if v.type in [pb2.BINARY, pb2.VARBINARY, pb2.BLOB]: - return data.bytesVal - else: - raise Exception("vector type error") - - -def defaultScale(typ: pb2.DataType, scale: Optional[int] = None) -> int: - if scale is not None: - return scale - if typ in [pb2.FLOAT32, pb2.FLOAT64]: - return -1 - if typ in [pb2.DECIMAL64, pb2.DECIMAL128]: - return decimal.getcontext().prec - if typ in [pb2.TIME, pb2.DATETIME, pb2.TIMESTAMP]: - return 6 - return 0 - - -def value2Data(value: Any, typ: pb2.DataType) -> pb2.Data: - if value is None: - return pb2.Data() - - if typ == pb2.BOOL: - assert type(value) is bool, f'return type error, required {bool}, received {type(value)}' - return pb2.Data(boolVal=value) - if typ in [pb2.INT8, pb2.INT16, pb2.INT32]: - assert type(value) is int, f'return type error, required {int}, received {type(value)}' - return pb2.Data(intVal=value) - if typ == pb2.INT64: - assert type(value) is int, f'return type error, required {int}, received {type(value)}' - return pb2.Data(int64Val=value) - if typ in [pb2.UINT8, pb2.INT16, pb2.INT32]: - assert type(value) is int, f'return type error, required {int}, received {type(value)}' - return pb2.Data(uintVal=value) - if typ == pb2.UINT64: - assert type(value) is int, f'return type error, required {int}, received {type(value)}' - return pb2.Data(uint64Val=value) - if typ == pb2.FLOAT32: - assert type(value) is float, f'return type error, required {float}, received {type(value)}' - return pb2.Data(floatVal=value) - if typ == pb2.FLOAT64: - assert type(value) is float, f'return type error, required {float}, received {type(value)}' - return pb2.Data(doubleVal=value) - if typ in [pb2.CHAR, pb2.VARCHAR, pb2.TEXT, pb2.UUID]: - assert type(value) is str, f'return type error, required {str}, received {type(value)}' - return pb2.Data(stringVal=value) - if typ == pb2.JSON: - return pb2.Data(stringVal=json.dumps(value, ensure_ascii=False)) - if typ == pb2.TIME: - assert type( - value) is datetime.timedelta, f'return type error, required {datetime.timedelta}, received {type(value)}' - r = '' - t: datetime.timedelta = value - if t.days < 0: - t = t * -1 - r += '-' - h = t.days * 24 + t.seconds // 3600 - m = t.seconds % 3600 // 60 - s = t.seconds % 3600 % 60 - r += f'{h:02d}:{m:02d}:{s:02d}.{t.microseconds:06d}' - return pb2.Data(stringVal=str(r)) - if typ == pb2.DATE: - assert type(value) is datetime.date, f'return type error, required {datetime.date}, received {type(value)}' - return pb2.Data(stringVal=str(value)) - if typ in [pb2.DATETIME, pb2.TIMESTAMP]: - assert type( - value) is datetime.datetime, f'return type error, required {datetime.datetime}, received {type(value)}' - return pb2.Data(stringVal=str(value)) - if typ in [pb2.DECIMAL64, pb2.DECIMAL128]: - assert type(value) is decimal.Decimal, f'return type error, required {decimal.Decimal}, received {type(value)}' - return pb2.Data(stringVal=str(value)) - if typ in [pb2.BINARY, pb2.VARBINARY, pb2.BLOB]: - assert type(value) is bytes, f'return type error, required {bytes}, received {type(value)}' - return pb2.Data(bytesVal=value) - else: - raise Exception(f'unsupported return type: {type(value)}') - - -def run(): - server = grpc.server(futures.ThreadPoolExecutor(), options=[ - ('grpc.max_send_message_length', 0x7fffffff), - ('grpc.max_receive_message_length', 0x7fffffff) - ]) - pb2_grpc.add_ServiceServicer_to_server(Server(), server) - server.add_insecure_port(ARGS.address) - server.start() - server.wait_for_termination() - - -ARGS = None - -if __name__ == '__main__': - parser = argparse.ArgumentParser( - prog='python udf server', - epilog='Copyright(r), 2023' - ) - parser.add_argument('--address', default='[::]:50051', help='address') - ARGS = parser.parse_args() - - log.info('python server start') - - run() diff --git a/pkg/udf/pythonservice/pyserver/udf_pb2.py b/pkg/udf/pythonservice/pyserver/udf_pb2.py deleted file mode 100644 index 52e791a8a7ff0..0000000000000 --- a/pkg/udf/pythonservice/pyserver/udf_pb2.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by the protocol buffer compiler. DO NOT EDIT! -# source: udf.proto -"""Generated protocol buffer code.""" -from google.protobuf import descriptor as _descriptor -from google.protobuf import descriptor_pool as _descriptor_pool -from google.protobuf import symbol_database as _symbol_database -from google.protobuf.internal import builder as _builder -# @@protoc_insertion_point(imports) - -_sym_db = _symbol_database.Default() - - - - -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\tudf.proto\x12\x03udf\"\xce\x01\n\x07Request\x12\x15\n\x03udf\x18\x01 \x01(\x0b\x32\x08.udf.Udf\x12 \n\x07vectors\x18\x02 \x03(\x0b\x32\x0f.udf.DataVector\x12\x0e\n\x06length\x18\x03 \x01(\x03\x12\x1e\n\x04type\x18\x04 \x01(\x0e\x32\x10.udf.RequestType\x12*\n\x07\x63ontext\x18\x05 \x03(\x0b\x32\x19.udf.Request.ContextEntry\x1a.\n\x0c\x43ontextEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"L\n\x08Response\x12\x1f\n\x06vector\x18\x01 \x01(\x0b\x32\x0f.udf.DataVector\x12\x1f\n\x04type\x18\x02 \x01(\x0e\x32\x11.udf.ResponseType\"\xab\x01\n\x03Udf\x12\x0f\n\x07handler\x18\x01 \x01(\t\x12\x10\n\x08isImport\x18\x02 \x01(\x08\x12\x0c\n\x04\x62ody\x18\x03 \x01(\t\x12\x1f\n\timportPkg\x18\x04 \x01(\x0b\x32\x0c.udf.Package\x12\x1e\n\x07retType\x18\x05 \x01(\x0e\x32\r.udf.DataType\x12\x10\n\x08language\x18\x06 \x01(\t\x12\x14\n\x0cmodifiedTime\x18\x07 \x01(\t\x12\n\n\x02\x64\x62\x18\x08 \x01(\t\"%\n\x07Package\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\x12\x0c\n\x04last\x18\x02 \x01(\x08\"p\n\nDataVector\x12\x17\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\t.udf.Data\x12\r\n\x05\x63onst\x18\x02 \x01(\x08\x12\x0e\n\x06length\x18\x03 \x01(\x03\x12\x1b\n\x04type\x18\x04 \x01(\x0e\x32\r.udf.DataType\x12\r\n\x05scale\x18\x05 \x01(\x05\"\xc0\x01\n\x04\x44\x61ta\x12\x11\n\x07\x62oolVal\x18\x01 \x01(\x08H\x00\x12\x10\n\x06intVal\x18\x02 \x01(\x11H\x00\x12\x12\n\x08int64Val\x18\x03 \x01(\x12H\x00\x12\x11\n\x07uintVal\x18\x04 \x01(\rH\x00\x12\x13\n\tuint64Val\x18\x05 \x01(\x04H\x00\x12\x12\n\x08\x66loatVal\x18\x06 \x01(\x02H\x00\x12\x13\n\tdoubleVal\x18\x07 \x01(\x01H\x00\x12\x13\n\tstringVal\x18\x08 \x01(\tH\x00\x12\x12\n\x08\x62ytesVal\x18\t \x01(\x0cH\x00\x42\x05\n\x03val*C\n\x0bRequestType\x12\x12\n\x0eUnknownRequest\x10\x00\x12\x0f\n\x0b\x44\x61taRequest\x10\x01\x12\x0f\n\x0bPkgResponse\x10\x02*E\n\x0cResponseType\x12\x13\n\x0fUnknownResponse\x10\x00\x12\x10\n\x0c\x44\x61taResponse\x10\x01\x12\x0e\n\nPkgRequest\x10\x02*\xbf\x02\n\x08\x44\x61taType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04\x42OOL\x10\n\x12\x08\n\x04INT8\x10\x14\x12\t\n\x05INT16\x10\x15\x12\t\n\x05INT32\x10\x16\x12\t\n\x05INT64\x10\x17\x12\t\n\x05UINT8\x10\x1e\x12\n\n\x06UINT16\x10\x1f\x12\n\n\x06UINT32\x10 \x12\n\n\x06UINT64\x10!\x12\x0b\n\x07\x46LOAT32\x10(\x12\x0b\n\x07\x46LOAT64\x10)\x12\x08\n\x04\x43HAR\x10\x32\x12\x0b\n\x07VARCHAR\x10\x33\x12\x08\n\x04TEXT\x10\x34\x12\x08\n\x04JSON\x10\x35\x12\x08\n\x04UUID\x10\x36\x12\x08\n\x04TIME\x10<\x12\x08\n\x04\x44\x41TE\x10=\x12\x0c\n\x08\x44\x41TETIME\x10>\x12\r\n\tTIMESTAMP\x10?\x12\r\n\tDECIMAL64\x10\x46\x12\x0e\n\nDECIMAL128\x10G\x12\n\n\x06\x42INARY\x10P\x12\r\n\tVARBINARY\x10Q\x12\x08\n\x04\x42LOB\x10R23\n\x07Service\x12(\n\x03run\x12\x0c.udf.Request\x1a\r.udf.Response\"\x00(\x01\x30\x01\x42+Z)github.com/matrixorigin/matrixone/pkg/udfb\x06proto3') - -_globals = globals() -_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) -_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'udf_pb2', _globals) -if _descriptor._USE_C_DESCRIPTORS == False: - - DESCRIPTOR._options = None - DESCRIPTOR._serialized_options = b'Z)github.com/matrixorigin/matrixone/pkg/udf' - _REQUEST_CONTEXTENTRY._options = None - _REQUEST_CONTEXTENTRY._serialized_options = b'8\001' - _globals['_REQUESTTYPE']._serialized_start=827 - _globals['_REQUESTTYPE']._serialized_end=894 - _globals['_RESPONSETYPE']._serialized_start=896 - _globals['_RESPONSETYPE']._serialized_end=965 - _globals['_DATATYPE']._serialized_start=968 - _globals['_DATATYPE']._serialized_end=1287 - _globals['_REQUEST']._serialized_start=19 - _globals['_REQUEST']._serialized_end=225 - _globals['_REQUEST_CONTEXTENTRY']._serialized_start=179 - _globals['_REQUEST_CONTEXTENTRY']._serialized_end=225 - _globals['_RESPONSE']._serialized_start=227 - _globals['_RESPONSE']._serialized_end=303 - _globals['_UDF']._serialized_start=306 - _globals['_UDF']._serialized_end=477 - _globals['_PACKAGE']._serialized_start=479 - _globals['_PACKAGE']._serialized_end=516 - _globals['_DATAVECTOR']._serialized_start=518 - _globals['_DATAVECTOR']._serialized_end=630 - _globals['_DATA']._serialized_start=633 - _globals['_DATA']._serialized_end=825 - _globals['_SERVICE']._serialized_start=1289 - _globals['_SERVICE']._serialized_end=1340 -# @@protoc_insertion_point(module_scope) diff --git a/pkg/udf/pythonservice/pyserver/udf_pb2.pyi b/pkg/udf/pythonservice/pyserver/udf_pb2.pyi deleted file mode 100644 index b3438382c2537..0000000000000 --- a/pkg/udf/pythonservice/pyserver/udf_pb2.pyi +++ /dev/null @@ -1,173 +0,0 @@ -from google.protobuf.internal import containers as _containers -from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper -from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union - -DESCRIPTOR: _descriptor.FileDescriptor - -class RequestType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - UnknownRequest: _ClassVar[RequestType] - DataRequest: _ClassVar[RequestType] - PkgResponse: _ClassVar[RequestType] - -class ResponseType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - UnknownResponse: _ClassVar[ResponseType] - DataResponse: _ClassVar[ResponseType] - PkgRequest: _ClassVar[ResponseType] - -class DataType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): - __slots__ = [] - UNKNOWN: _ClassVar[DataType] - BOOL: _ClassVar[DataType] - INT8: _ClassVar[DataType] - INT16: _ClassVar[DataType] - INT32: _ClassVar[DataType] - INT64: _ClassVar[DataType] - UINT8: _ClassVar[DataType] - UINT16: _ClassVar[DataType] - UINT32: _ClassVar[DataType] - UINT64: _ClassVar[DataType] - FLOAT32: _ClassVar[DataType] - FLOAT64: _ClassVar[DataType] - CHAR: _ClassVar[DataType] - VARCHAR: _ClassVar[DataType] - TEXT: _ClassVar[DataType] - JSON: _ClassVar[DataType] - UUID: _ClassVar[DataType] - TIME: _ClassVar[DataType] - DATE: _ClassVar[DataType] - DATETIME: _ClassVar[DataType] - TIMESTAMP: _ClassVar[DataType] - DECIMAL64: _ClassVar[DataType] - DECIMAL128: _ClassVar[DataType] - BINARY: _ClassVar[DataType] - VARBINARY: _ClassVar[DataType] - BLOB: _ClassVar[DataType] -UnknownRequest: RequestType -DataRequest: RequestType -PkgResponse: RequestType -UnknownResponse: ResponseType -DataResponse: ResponseType -PkgRequest: ResponseType -UNKNOWN: DataType -BOOL: DataType -INT8: DataType -INT16: DataType -INT32: DataType -INT64: DataType -UINT8: DataType -UINT16: DataType -UINT32: DataType -UINT64: DataType -FLOAT32: DataType -FLOAT64: DataType -CHAR: DataType -VARCHAR: DataType -TEXT: DataType -JSON: DataType -UUID: DataType -TIME: DataType -DATE: DataType -DATETIME: DataType -TIMESTAMP: DataType -DECIMAL64: DataType -DECIMAL128: DataType -BINARY: DataType -VARBINARY: DataType -BLOB: DataType - -class Request(_message.Message): - __slots__ = ["udf", "vectors", "length", "type", "context"] - class ContextEntry(_message.Message): - __slots__ = ["key", "value"] - KEY_FIELD_NUMBER: _ClassVar[int] - VALUE_FIELD_NUMBER: _ClassVar[int] - key: str - value: str - def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... - UDF_FIELD_NUMBER: _ClassVar[int] - VECTORS_FIELD_NUMBER: _ClassVar[int] - LENGTH_FIELD_NUMBER: _ClassVar[int] - TYPE_FIELD_NUMBER: _ClassVar[int] - CONTEXT_FIELD_NUMBER: _ClassVar[int] - udf: Udf - vectors: _containers.RepeatedCompositeFieldContainer[DataVector] - length: int - type: RequestType - context: _containers.ScalarMap[str, str] - def __init__(self, udf: _Optional[_Union[Udf, _Mapping]] = ..., vectors: _Optional[_Iterable[_Union[DataVector, _Mapping]]] = ..., length: _Optional[int] = ..., type: _Optional[_Union[RequestType, str]] = ..., context: _Optional[_Mapping[str, str]] = ...) -> None: ... - -class Response(_message.Message): - __slots__ = ["vector", "type"] - VECTOR_FIELD_NUMBER: _ClassVar[int] - TYPE_FIELD_NUMBER: _ClassVar[int] - vector: DataVector - type: ResponseType - def __init__(self, vector: _Optional[_Union[DataVector, _Mapping]] = ..., type: _Optional[_Union[ResponseType, str]] = ...) -> None: ... - -class Udf(_message.Message): - __slots__ = ["handler", "isImport", "body", "importPkg", "retType", "language", "modifiedTime", "db"] - HANDLER_FIELD_NUMBER: _ClassVar[int] - ISIMPORT_FIELD_NUMBER: _ClassVar[int] - BODY_FIELD_NUMBER: _ClassVar[int] - IMPORTPKG_FIELD_NUMBER: _ClassVar[int] - RETTYPE_FIELD_NUMBER: _ClassVar[int] - LANGUAGE_FIELD_NUMBER: _ClassVar[int] - MODIFIEDTIME_FIELD_NUMBER: _ClassVar[int] - DB_FIELD_NUMBER: _ClassVar[int] - handler: str - isImport: bool - body: str - importPkg: Package - retType: DataType - language: str - modifiedTime: str - db: str - def __init__(self, handler: _Optional[str] = ..., isImport: bool = ..., body: _Optional[str] = ..., importPkg: _Optional[_Union[Package, _Mapping]] = ..., retType: _Optional[_Union[DataType, str]] = ..., language: _Optional[str] = ..., modifiedTime: _Optional[str] = ..., db: _Optional[str] = ...) -> None: ... - -class Package(_message.Message): - __slots__ = ["data", "last"] - DATA_FIELD_NUMBER: _ClassVar[int] - LAST_FIELD_NUMBER: _ClassVar[int] - data: bytes - last: bool - def __init__(self, data: _Optional[bytes] = ..., last: bool = ...) -> None: ... - -class DataVector(_message.Message): - __slots__ = ["data", "const", "length", "type", "scale"] - DATA_FIELD_NUMBER: _ClassVar[int] - CONST_FIELD_NUMBER: _ClassVar[int] - LENGTH_FIELD_NUMBER: _ClassVar[int] - TYPE_FIELD_NUMBER: _ClassVar[int] - SCALE_FIELD_NUMBER: _ClassVar[int] - data: _containers.RepeatedCompositeFieldContainer[Data] - const: bool - length: int - type: DataType - scale: int - def __init__(self, data: _Optional[_Iterable[_Union[Data, _Mapping]]] = ..., const: bool = ..., length: _Optional[int] = ..., type: _Optional[_Union[DataType, str]] = ..., scale: _Optional[int] = ...) -> None: ... - -class Data(_message.Message): - __slots__ = ["boolVal", "intVal", "int64Val", "uintVal", "uint64Val", "floatVal", "doubleVal", "stringVal", "bytesVal"] - BOOLVAL_FIELD_NUMBER: _ClassVar[int] - INTVAL_FIELD_NUMBER: _ClassVar[int] - INT64VAL_FIELD_NUMBER: _ClassVar[int] - UINTVAL_FIELD_NUMBER: _ClassVar[int] - UINT64VAL_FIELD_NUMBER: _ClassVar[int] - FLOATVAL_FIELD_NUMBER: _ClassVar[int] - DOUBLEVAL_FIELD_NUMBER: _ClassVar[int] - STRINGVAL_FIELD_NUMBER: _ClassVar[int] - BYTESVAL_FIELD_NUMBER: _ClassVar[int] - boolVal: bool - intVal: int - int64Val: int - uintVal: int - uint64Val: int - floatVal: float - doubleVal: float - stringVal: str - bytesVal: bytes - def __init__(self, boolVal: bool = ..., intVal: _Optional[int] = ..., int64Val: _Optional[int] = ..., uintVal: _Optional[int] = ..., uint64Val: _Optional[int] = ..., floatVal: _Optional[float] = ..., doubleVal: _Optional[float] = ..., stringVal: _Optional[str] = ..., bytesVal: _Optional[bytes] = ...) -> None: ... diff --git a/pkg/udf/pythonservice/pyserver/udf_pb2_grpc.py b/pkg/udf/pythonservice/pyserver/udf_pb2_grpc.py deleted file mode 100644 index 2707b06019282..0000000000000 --- a/pkg/udf/pythonservice/pyserver/udf_pb2_grpc.py +++ /dev/null @@ -1,72 +0,0 @@ -# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! -"""Client and server classes corresponding to protobuf-defined services.""" -import grpc - -import udf_pb2 as udf__pb2 - - -class ServiceStub(object): - """protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./udf.proto - - """ - - def __init__(self, channel): - """Constructor. - - Args: - channel: A grpc.Channel. - """ - self.run = channel.stream_stream( - '/udf.Service/run', - request_serializer=udf__pb2.Request.SerializeToString, - response_deserializer=udf__pb2.Response.FromString, - ) - - -class ServiceServicer(object): - """protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./udf.proto - - """ - - def run(self, request_iterator, context): - """Missing associated documentation comment in .proto file.""" - context.set_code(grpc.StatusCode.UNIMPLEMENTED) - context.set_details('Method not implemented!') - raise NotImplementedError('Method not implemented!') - - -def add_ServiceServicer_to_server(servicer, server): - rpc_method_handlers = { - 'run': grpc.stream_stream_rpc_method_handler( - servicer.run, - request_deserializer=udf__pb2.Request.FromString, - response_serializer=udf__pb2.Response.SerializeToString, - ), - } - generic_handler = grpc.method_handlers_generic_handler( - 'udf.Service', rpc_method_handlers) - server.add_generic_rpc_handlers((generic_handler,)) - - - # This class is part of an EXPERIMENTAL API. -class Service(object): - """protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./udf.proto - - """ - - @staticmethod - def run(request_iterator, - target, - options=(), - channel_credentials=None, - call_credentials=None, - insecure=False, - compression=None, - wait_for_ready=None, - timeout=None, - metadata=None): - return grpc.experimental.stream_stream(request_iterator, target, '/udf.Service/run', - udf__pb2.Request.SerializeToString, - udf__pb2.Response.FromString, - options, channel_credentials, - insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/pkg/udf/pythonservice/service.go b/pkg/udf/pythonservice/service.go deleted file mode 100644 index c0d990d00ff60..0000000000000 --- a/pkg/udf/pythonservice/service.go +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2023 Matrix Origin -// -// 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 pythonservice - -import ( - "fmt" - "github.com/matrixorigin/matrixone/pkg/logutil" - "io" - "os" - "os/exec" - "path" - "path/filepath" - "strconv" - "sync" - "sync/atomic" -) - -type service struct { - cfg Config - process *os.Process - log io.WriteCloser - mutex sync.Mutex -} - -func NewService(cfg Config) (PythonUdfServer, error) { - err := cfg.Validate() - if err != nil { - return nil, err - } - return &service{cfg: cfg}, nil -} - -var severNo int32 = 0 - -func (s *service) Start() error { - s.mutex.Lock() - defer s.mutex.Unlock() - - if s.process == nil { - var err error - var file string - - ex, err := os.Executable() - if err != nil { - return err - } - exePath := filepath.Dir(ex) - - if path.IsAbs(file) { - file = path.Join(s.cfg.Path, "server.py") - } else { - file = path.Join(exePath, s.cfg.Path, "server.py") - } - _, err = os.Stat(file) - if err != nil { - return err - } - - no := strconv.Itoa(int(atomic.AddInt32(&severNo, 1))) - s.log, err = os.OpenFile(path.Join(exePath, "pyserver"+no+".log"), os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) - if err != nil { - return err - } - defer func() { - if err != nil { - s.log.Close() - } - }() - executable := s.cfg.Python - if executable == "" { - executable = "python" - } - - cmd := exec.Command(executable, "-u", file, "--address="+s.cfg.Address) - cmd.Stdout = s.log - cmd.Stderr = s.log - go func(cmd *exec.Cmd) { - logutil.Infof("start python server process, command: %s", cmd.String()) - err := cmd.Run() - // panic the launch process if python server exit with an error - if err != nil { - panic(fmt.Sprintf("python server exit with error: %v", err)) - } - }(cmd) - - s.process = cmd.Process - } - - return nil -} - -func (s *service) Close() error { - s.mutex.Lock() - defer func() { - s.mutex.Unlock() - if s.log != nil { - s.log.Close() - } - }() - - if s.process != nil { - err := s.process.Kill() - if err != nil { - return err - } - s.process = nil - } - - return nil -} diff --git a/pkg/udf/pythonservice/types.go b/pkg/udf/pythonservice/types.go deleted file mode 100644 index 541418c2b0616..0000000000000 --- a/pkg/udf/pythonservice/types.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2023 Matrix Origin -// -// 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 pythonservice - -type PythonUdfServer interface { - Start() error - Close() error -} diff --git a/pkg/udf/runtime.go b/pkg/udf/runtime.go new file mode 100644 index 0000000000000..33b2b90280ecf --- /dev/null +++ b/pkg/udf/runtime.go @@ -0,0 +1,104 @@ +// Copyright 2026 Matrix Origin +// +// 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 udf contains the execution contract shared by SQL routine binders, +// CN operators, and language runtimes. Wire formats and language-specific +// adapters live below this package; the SQL engine depends only on this +// contract. +package udf + +import ( + "context" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/udf/protocol" +) + +const ( + LanguagePython = "python" + PythonABIContract = "PYTHON_ARROW" + PythonAdapterVersion = "2026-09" + PythonSDKVersion = "1.0" + NullCallHandler = "CALLED_ON_NULL_INPUT" + NullReturnNull = "RETURNS_NULL_ON_NULL_INPUT" +) + +// Invocation is the language-neutral routine call handed to an admitted +// runtime. The runtime owns transport, worker lifecycle, and Arrow +// conversion; CN owns the SQL vectors, result wrapper, and fencing identity. +type Invocation struct { + Language string + Handler string + Source string + Args []types.Type + ReturnType types.Type + Inputs []*vector.Vector + Length int + Mode string + NullPolicy string + ABIContract string + AdapterVersion string + SDKVersion string + Context map[string]string + Tuple protocol.FencingTuple +} + +// Runtime executes one invocation. Implementations must not retain the +// vectors or result after Execute returns. +type Runtime interface { + Language() string + Execute(context.Context, *Invocation, vector.FunctionResultWrapper, *mpool.MPool) error +} + +// Registry dispatches to the one runtime selected by a routine's language. +// A registry is immutable after construction, so plan execution cannot race +// service registration or observe a partially initialized adapter. +func NewRuntime(runtimes ...Runtime) (Runtime, error) { + registry := &runtimeRegistry{byLanguage: make(map[string]Runtime, len(runtimes))} + for _, runtime := range runtimes { + if runtime == nil || runtime.Language() == "" { + return nil, moerr.NewInternalErrorNoCtx("invalid udf runtime") + } + if _, exists := registry.byLanguage[runtime.Language()]; exists { + return nil, moerr.NewInternalErrorNoCtx("too many " + runtime.Language() + " runtimes") + } + registry.byLanguage[runtime.Language()] = runtime + } + return registry, nil +} + +type runtimeRegistry struct { + byLanguage map[string]Runtime +} + +func (r *runtimeRegistry) Language() string { return "multiple" } + +func (r *runtimeRegistry) Execute( + ctx context.Context, + invocation *Invocation, + result vector.FunctionResultWrapper, + mp *mpool.MPool, +) error { + if invocation == nil { + return moerr.NewInternalError(ctx, "nil udf invocation") + } + runtime := r.byLanguage[invocation.Language] + if runtime == nil { + return moerr.NewInternalError(ctx, "missing "+invocation.Language+" udf runtime") + } + return runtime.Execute(ctx, invocation, result, mp) +} diff --git a/pkg/udf/service.go b/pkg/udf/service.go deleted file mode 100644 index 0342bf9340a9e..0000000000000 --- a/pkg/udf/service.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2023 Matrix Origin -// -// 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 udf - -import ( - "context" - - "github.com/matrixorigin/matrixone/pkg/common/moerr" -) - -func NewService(services ...Service) (Service, error) { - srv := &service{} - srv.mapping = make(map[string]Service, len(services)) - for _, s := range services { - if srv.mapping[s.Language()] == nil { - srv.mapping[s.Language()] = s - } else { - return nil, moerr.NewInternalErrorNoCtx("too many " + s.Language() + " udf service") - } - } - return srv, nil -} - -type service struct { - mapping map[string]Service -} - -func (s *service) Language() string { - return "multiple" -} - -func (s *service) Run(ctx context.Context, request *Request, pkgReader PkgReader) (*Response, error) { - srv := s.mapping[request.Udf.Language] - if srv == nil { - return nil, moerr.NewInternalError(ctx, "missing "+request.Udf.Language+" udf service") - } - return srv.Run(ctx, request, pkgReader) -} diff --git a/pkg/udf/types.go b/pkg/udf/types.go deleted file mode 100644 index 7adc0833377fb..0000000000000 --- a/pkg/udf/types.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2023 Matrix Origin -// -// 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 udf - -import ( - "context" - "io" -) - -const ( - LanguagePython = "python" -) - -// Service handle non-sql udf in cn -type Service interface { - Language() string - Run(ctx context.Context, request *Request, pkgReader PkgReader) (*Response, error) -} - -// PkgReader read udf package from storage -type PkgReader interface { - Get(ctx context.Context, path string) (reader io.ReadCloser, err error) -} - -// PkgUploader upload udf package to storage -type PkgUploader interface { - Upload(ctx context.Context, localPath string, storageDir string) (storagePath string, err error) -} diff --git a/pkg/udf/udf.pb.go b/pkg/udf/udf.pb.go deleted file mode 100644 index 4db1253b016ca..0000000000000 --- a/pkg/udf/udf.pb.go +++ /dev/null @@ -1,1068 +0,0 @@ -// Copyright 2023 Matrix Origin -// -// 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. - -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.28.1 -// protoc v3.17.0 -// source: udf.proto - -package udf - -import ( - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -type RequestType int32 - -const ( - RequestType_UnknownRequest RequestType = 0 - RequestType_DataRequest RequestType = 1 // request with data for function result - RequestType_PkgResponse RequestType = 2 // response with package -) - -// Enum value maps for RequestType. -var ( - RequestType_name = map[int32]string{ - 0: "UnknownRequest", - 1: "DataRequest", - 2: "PkgResponse", - } - RequestType_value = map[string]int32{ - "UnknownRequest": 0, - "DataRequest": 1, - "PkgResponse": 2, - } -) - -func (x RequestType) Enum() *RequestType { - p := new(RequestType) - *p = x - return p -} - -func (x RequestType) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (RequestType) Descriptor() protoreflect.EnumDescriptor { - return file_udf_proto_enumTypes[0].Descriptor() -} - -func (RequestType) Type() protoreflect.EnumType { - return &file_udf_proto_enumTypes[0] -} - -func (x RequestType) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use RequestType.Descriptor instead. -func (RequestType) EnumDescriptor() ([]byte, []int) { - return file_udf_proto_rawDescGZIP(), []int{0} -} - -type ResponseType int32 - -const ( - ResponseType_UnknownResponse ResponseType = 0 - ResponseType_DataResponse ResponseType = 1 // response with function result - ResponseType_PkgRequest ResponseType = 2 // request for package -) - -// Enum value maps for ResponseType. -var ( - ResponseType_name = map[int32]string{ - 0: "UnknownResponse", - 1: "DataResponse", - 2: "PkgRequest", - } - ResponseType_value = map[string]int32{ - "UnknownResponse": 0, - "DataResponse": 1, - "PkgRequest": 2, - } -) - -func (x ResponseType) Enum() *ResponseType { - p := new(ResponseType) - *p = x - return p -} - -func (x ResponseType) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (ResponseType) Descriptor() protoreflect.EnumDescriptor { - return file_udf_proto_enumTypes[1].Descriptor() -} - -func (ResponseType) Type() protoreflect.EnumType { - return &file_udf_proto_enumTypes[1] -} - -func (x ResponseType) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use ResponseType.Descriptor instead. -func (ResponseType) EnumDescriptor() ([]byte, []int) { - return file_udf_proto_rawDescGZIP(), []int{1} -} - -type DataType int32 - -const ( - DataType_UNKNOWN DataType = 0 - DataType_BOOL DataType = 10 - DataType_INT8 DataType = 20 - DataType_INT16 DataType = 21 - DataType_INT32 DataType = 22 - DataType_INT64 DataType = 23 - DataType_UINT8 DataType = 30 - DataType_UINT16 DataType = 31 - DataType_UINT32 DataType = 32 - DataType_UINT64 DataType = 33 - DataType_FLOAT32 DataType = 40 - DataType_FLOAT64 DataType = 41 - DataType_CHAR DataType = 50 - DataType_VARCHAR DataType = 51 - DataType_TEXT DataType = 52 - DataType_JSON DataType = 53 - DataType_UUID DataType = 54 - DataType_TIME DataType = 60 - DataType_DATE DataType = 61 - DataType_DATETIME DataType = 62 - DataType_TIMESTAMP DataType = 63 - DataType_DECIMAL64 DataType = 70 - DataType_DECIMAL128 DataType = 71 - DataType_BINARY DataType = 80 - DataType_VARBINARY DataType = 81 - DataType_BLOB DataType = 82 -) - -// Enum value maps for DataType. -var ( - DataType_name = map[int32]string{ - 0: "UNKNOWN", - 10: "BOOL", - 20: "INT8", - 21: "INT16", - 22: "INT32", - 23: "INT64", - 30: "UINT8", - 31: "UINT16", - 32: "UINT32", - 33: "UINT64", - 40: "FLOAT32", - 41: "FLOAT64", - 50: "CHAR", - 51: "VARCHAR", - 52: "TEXT", - 53: "JSON", - 54: "UUID", - 60: "TIME", - 61: "DATE", - 62: "DATETIME", - 63: "TIMESTAMP", - 70: "DECIMAL64", - 71: "DECIMAL128", - 80: "BINARY", - 81: "VARBINARY", - 82: "BLOB", - } - DataType_value = map[string]int32{ - "UNKNOWN": 0, - "BOOL": 10, - "INT8": 20, - "INT16": 21, - "INT32": 22, - "INT64": 23, - "UINT8": 30, - "UINT16": 31, - "UINT32": 32, - "UINT64": 33, - "FLOAT32": 40, - "FLOAT64": 41, - "CHAR": 50, - "VARCHAR": 51, - "TEXT": 52, - "JSON": 53, - "UUID": 54, - "TIME": 60, - "DATE": 61, - "DATETIME": 62, - "TIMESTAMP": 63, - "DECIMAL64": 70, - "DECIMAL128": 71, - "BINARY": 80, - "VARBINARY": 81, - "BLOB": 82, - } -) - -func (x DataType) Enum() *DataType { - p := new(DataType) - *p = x - return p -} - -func (x DataType) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (DataType) Descriptor() protoreflect.EnumDescriptor { - return file_udf_proto_enumTypes[2].Descriptor() -} - -func (DataType) Type() protoreflect.EnumType { - return &file_udf_proto_enumTypes[2] -} - -func (x DataType) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Use DataType.Descriptor instead. -func (DataType) EnumDescriptor() ([]byte, []int) { - return file_udf_proto_rawDescGZIP(), []int{2} -} - -type Request struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Udf *Udf `protobuf:"bytes,1,opt,name=udf,proto3" json:"udf,omitempty"` - Vectors []*DataVector `protobuf:"bytes,2,rep,name=vectors,proto3" json:"vectors,omitempty"` - Length int64 `protobuf:"varint,3,opt,name=length,proto3" json:"length,omitempty"` - Type RequestType `protobuf:"varint,4,opt,name=type,proto3,enum=udf.RequestType" json:"type,omitempty"` - Context map[string]string `protobuf:"bytes,5,rep,name=context,proto3" json:"context,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // currently just transfer, not used -} - -func (x *Request) Reset() { - *x = Request{} - if protoimpl.UnsafeEnabled { - mi := &file_udf_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Request) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Request) ProtoMessage() {} - -func (x *Request) ProtoReflect() protoreflect.Message { - mi := &file_udf_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Request.ProtoReflect.Descriptor instead. -func (*Request) Descriptor() ([]byte, []int) { - return file_udf_proto_rawDescGZIP(), []int{0} -} - -func (x *Request) GetUdf() *Udf { - if x != nil { - return x.Udf - } - return nil -} - -func (x *Request) GetVectors() []*DataVector { - if x != nil { - return x.Vectors - } - return nil -} - -func (x *Request) GetLength() int64 { - if x != nil { - return x.Length - } - return 0 -} - -func (x *Request) GetType() RequestType { - if x != nil { - return x.Type - } - return RequestType_UnknownRequest -} - -func (x *Request) GetContext() map[string]string { - if x != nil { - return x.Context - } - return nil -} - -type Response struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Vector *DataVector `protobuf:"bytes,1,opt,name=vector,proto3" json:"vector,omitempty"` - Type ResponseType `protobuf:"varint,2,opt,name=type,proto3,enum=udf.ResponseType" json:"type,omitempty"` -} - -func (x *Response) Reset() { - *x = Response{} - if protoimpl.UnsafeEnabled { - mi := &file_udf_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Response) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Response) ProtoMessage() {} - -func (x *Response) ProtoReflect() protoreflect.Message { - mi := &file_udf_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Response.ProtoReflect.Descriptor instead. -func (*Response) Descriptor() ([]byte, []int) { - return file_udf_proto_rawDescGZIP(), []int{1} -} - -func (x *Response) GetVector() *DataVector { - if x != nil { - return x.Vector - } - return nil -} - -func (x *Response) GetType() ResponseType { - if x != nil { - return x.Type - } - return ResponseType_UnknownResponse -} - -type Udf struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Handler string `protobuf:"bytes,1,opt,name=handler,proto3" json:"handler,omitempty"` - IsImport bool `protobuf:"varint,2,opt,name=isImport,proto3" json:"isImport,omitempty"` - Body string `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` - ImportPkg *Package `protobuf:"bytes,4,opt,name=importPkg,proto3" json:"importPkg,omitempty"` - RetType DataType `protobuf:"varint,5,opt,name=retType,proto3,enum=udf.DataType" json:"retType,omitempty"` - Language string `protobuf:"bytes,6,opt,name=language,proto3" json:"language,omitempty"` - ModifiedTime string `protobuf:"bytes,7,opt,name=modifiedTime,proto3" json:"modifiedTime,omitempty"` - Db string `protobuf:"bytes,8,opt,name=db,proto3" json:"db,omitempty"` -} - -func (x *Udf) Reset() { - *x = Udf{} - if protoimpl.UnsafeEnabled { - mi := &file_udf_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Udf) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Udf) ProtoMessage() {} - -func (x *Udf) ProtoReflect() protoreflect.Message { - mi := &file_udf_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Udf.ProtoReflect.Descriptor instead. -func (*Udf) Descriptor() ([]byte, []int) { - return file_udf_proto_rawDescGZIP(), []int{2} -} - -func (x *Udf) GetHandler() string { - if x != nil { - return x.Handler - } - return "" -} - -func (x *Udf) GetIsImport() bool { - if x != nil { - return x.IsImport - } - return false -} - -func (x *Udf) GetBody() string { - if x != nil { - return x.Body - } - return "" -} - -func (x *Udf) GetImportPkg() *Package { - if x != nil { - return x.ImportPkg - } - return nil -} - -func (x *Udf) GetRetType() DataType { - if x != nil { - return x.RetType - } - return DataType_UNKNOWN -} - -func (x *Udf) GetLanguage() string { - if x != nil { - return x.Language - } - return "" -} - -func (x *Udf) GetModifiedTime() string { - if x != nil { - return x.ModifiedTime - } - return "" -} - -func (x *Udf) GetDb() string { - if x != nil { - return x.Db - } - return "" -} - -type Package struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` - Last bool `protobuf:"varint,2,opt,name=last,proto3" json:"last,omitempty"` -} - -func (x *Package) Reset() { - *x = Package{} - if protoimpl.UnsafeEnabled { - mi := &file_udf_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Package) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Package) ProtoMessage() {} - -func (x *Package) ProtoReflect() protoreflect.Message { - mi := &file_udf_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Package.ProtoReflect.Descriptor instead. -func (*Package) Descriptor() ([]byte, []int) { - return file_udf_proto_rawDescGZIP(), []int{3} -} - -func (x *Package) GetData() []byte { - if x != nil { - return x.Data - } - return nil -} - -func (x *Package) GetLast() bool { - if x != nil { - return x.Last - } - return false -} - -type DataVector struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Data []*Data `protobuf:"bytes,1,rep,name=data,proto3" json:"data,omitempty"` - Const bool `protobuf:"varint,2,opt,name=const,proto3" json:"const,omitempty"` - Length int64 `protobuf:"varint,3,opt,name=length,proto3" json:"length,omitempty"` - Type DataType `protobuf:"varint,4,opt,name=type,proto3,enum=udf.DataType" json:"type,omitempty"` - Scale int32 `protobuf:"varint,5,opt,name=scale,proto3" json:"scale,omitempty"` -} - -func (x *DataVector) Reset() { - *x = DataVector{} - if protoimpl.UnsafeEnabled { - mi := &file_udf_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *DataVector) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*DataVector) ProtoMessage() {} - -func (x *DataVector) ProtoReflect() protoreflect.Message { - mi := &file_udf_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use DataVector.ProtoReflect.Descriptor instead. -func (*DataVector) Descriptor() ([]byte, []int) { - return file_udf_proto_rawDescGZIP(), []int{4} -} - -func (x *DataVector) GetData() []*Data { - if x != nil { - return x.Data - } - return nil -} - -func (x *DataVector) GetConst() bool { - if x != nil { - return x.Const - } - return false -} - -func (x *DataVector) GetLength() int64 { - if x != nil { - return x.Length - } - return 0 -} - -func (x *DataVector) GetType() DataType { - if x != nil { - return x.Type - } - return DataType_UNKNOWN -} - -func (x *DataVector) GetScale() int32 { - if x != nil { - return x.Scale - } - return 0 -} - -type Data struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Val: - // - // *Data_BoolVal - // *Data_IntVal - // *Data_Int64Val - // *Data_UintVal - // *Data_Uint64Val - // *Data_FloatVal - // *Data_DoubleVal - // *Data_StringVal - // *Data_BytesVal - Val isData_Val `protobuf_oneof:"val"` -} - -func (x *Data) Reset() { - *x = Data{} - if protoimpl.UnsafeEnabled { - mi := &file_udf_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Data) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Data) ProtoMessage() {} - -func (x *Data) ProtoReflect() protoreflect.Message { - mi := &file_udf_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Data.ProtoReflect.Descriptor instead. -func (*Data) Descriptor() ([]byte, []int) { - return file_udf_proto_rawDescGZIP(), []int{5} -} - -func (m *Data) GetVal() isData_Val { - if m != nil { - return m.Val - } - return nil -} - -func (x *Data) GetBoolVal() bool { - if x, ok := x.GetVal().(*Data_BoolVal); ok { - return x.BoolVal - } - return false -} - -func (x *Data) GetIntVal() int32 { - if x, ok := x.GetVal().(*Data_IntVal); ok { - return x.IntVal - } - return 0 -} - -func (x *Data) GetInt64Val() int64 { - if x, ok := x.GetVal().(*Data_Int64Val); ok { - return x.Int64Val - } - return 0 -} - -func (x *Data) GetUintVal() uint32 { - if x, ok := x.GetVal().(*Data_UintVal); ok { - return x.UintVal - } - return 0 -} - -func (x *Data) GetUint64Val() uint64 { - if x, ok := x.GetVal().(*Data_Uint64Val); ok { - return x.Uint64Val - } - return 0 -} - -func (x *Data) GetFloatVal() float32 { - if x, ok := x.GetVal().(*Data_FloatVal); ok { - return x.FloatVal - } - return 0 -} - -func (x *Data) GetDoubleVal() float64 { - if x, ok := x.GetVal().(*Data_DoubleVal); ok { - return x.DoubleVal - } - return 0 -} - -func (x *Data) GetStringVal() string { - if x, ok := x.GetVal().(*Data_StringVal); ok { - return x.StringVal - } - return "" -} - -func (x *Data) GetBytesVal() []byte { - if x, ok := x.GetVal().(*Data_BytesVal); ok { - return x.BytesVal - } - return nil -} - -type isData_Val interface { - isData_Val() -} - -type Data_BoolVal struct { - BoolVal bool `protobuf:"varint,1,opt,name=boolVal,proto3,oneof"` // bool -} - -type Data_IntVal struct { - IntVal int32 `protobuf:"zigzag32,2,opt,name=intVal,proto3,oneof"` // int8, int16, int32 -} - -type Data_Int64Val struct { - Int64Val int64 `protobuf:"zigzag64,3,opt,name=int64Val,proto3,oneof"` // int64 -} - -type Data_UintVal struct { - UintVal uint32 `protobuf:"varint,4,opt,name=uintVal,proto3,oneof"` // uint8, uint16, uint32 -} - -type Data_Uint64Val struct { - Uint64Val uint64 `protobuf:"varint,5,opt,name=uint64Val,proto3,oneof"` // uint64 -} - -type Data_FloatVal struct { - FloatVal float32 `protobuf:"fixed32,6,opt,name=floatVal,proto3,oneof"` // float32 -} - -type Data_DoubleVal struct { - DoubleVal float64 `protobuf:"fixed64,7,opt,name=doubleVal,proto3,oneof"` // float64 -} - -type Data_StringVal struct { - StringVal string `protobuf:"bytes,8,opt,name=stringVal,proto3,oneof"` // char, varchar, text, json, uuid | time, date, datetime, timestamp | Decimal64, Decimal128 -} - -type Data_BytesVal struct { - BytesVal []byte `protobuf:"bytes,9,opt,name=bytesVal,proto3,oneof"` // binary, varbinary, blob -} - -func (*Data_BoolVal) isData_Val() {} - -func (*Data_IntVal) isData_Val() {} - -func (*Data_Int64Val) isData_Val() {} - -func (*Data_UintVal) isData_Val() {} - -func (*Data_Uint64Val) isData_Val() {} - -func (*Data_FloatVal) isData_Val() {} - -func (*Data_DoubleVal) isData_Val() {} - -func (*Data_StringVal) isData_Val() {} - -func (*Data_BytesVal) isData_Val() {} - -var File_udf_proto protoreflect.FileDescriptor - -var file_udf_proto_rawDesc = []byte{ - 0x0a, 0x09, 0x75, 0x64, 0x66, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x03, 0x75, 0x64, 0x66, - 0x22, 0xff, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03, - 0x75, 0x64, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x75, 0x64, 0x66, 0x2e, - 0x55, 0x64, 0x66, 0x52, 0x03, 0x75, 0x64, 0x66, 0x12, 0x29, 0x0a, 0x07, 0x76, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x75, 0x64, 0x66, 0x2e, - 0x44, 0x61, 0x74, 0x61, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x76, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x04, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x75, 0x64, 0x66, 0x2e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x12, 0x33, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x18, 0x05, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x75, 0x64, 0x66, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x63, - 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x1a, 0x3a, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, - 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0x5a, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, - 0x0a, 0x06, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, - 0x2e, 0x75, 0x64, 0x66, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x52, - 0x06, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x25, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x75, 0x64, 0x66, 0x2e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xf4, - 0x01, 0x0a, 0x03, 0x55, 0x64, 0x66, 0x12, 0x18, 0x0a, 0x07, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, - 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, - 0x62, 0x6f, 0x64, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, - 0x12, 0x2a, 0x0a, 0x09, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x6b, 0x67, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x75, 0x64, 0x66, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x52, 0x09, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x6b, 0x67, 0x12, 0x27, 0x0a, 0x07, - 0x72, 0x65, 0x74, 0x54, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0d, 0x2e, - 0x75, 0x64, 0x66, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x72, 0x65, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, - 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, - 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d, - 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, - 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x64, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x64, 0x62, 0x22, 0x31, 0x0a, 0x07, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, - 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, - 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x61, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x04, 0x6c, 0x61, 0x73, 0x74, 0x22, 0x92, 0x01, 0x0a, 0x0a, 0x44, 0x61, 0x74, - 0x61, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x75, 0x64, 0x66, 0x2e, 0x44, 0x61, 0x74, 0x61, - 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, - 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x6c, 0x65, - 0x6e, 0x67, 0x74, 0x68, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x0d, 0x2e, 0x75, 0x64, 0x66, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, 0x70, - 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x61, 0x6c, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x22, 0x99, 0x02, - 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x07, 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, - 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x07, 0x62, 0x6f, 0x6f, 0x6c, 0x56, - 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x06, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x11, 0x48, 0x00, 0x52, 0x06, 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x08, - 0x69, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x12, 0x48, 0x00, - 0x52, 0x08, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x12, 0x1a, 0x0a, 0x07, 0x75, 0x69, - 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x07, 0x75, - 0x69, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x12, 0x1e, 0x0a, 0x09, 0x75, 0x69, 0x6e, 0x74, 0x36, 0x34, - 0x56, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x09, 0x75, 0x69, 0x6e, - 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x08, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x56, - 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x48, 0x00, 0x52, 0x08, 0x66, 0x6c, 0x6f, 0x61, - 0x74, 0x56, 0x61, 0x6c, 0x12, 0x1e, 0x0a, 0x09, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, - 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x09, 0x64, 0x6f, 0x75, 0x62, 0x6c, - 0x65, 0x56, 0x61, 0x6c, 0x12, 0x1e, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, - 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x09, 0x73, 0x74, 0x72, 0x69, 0x6e, - 0x67, 0x56, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x08, 0x62, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x08, 0x62, 0x79, 0x74, 0x65, 0x73, 0x56, - 0x61, 0x6c, 0x42, 0x05, 0x0a, 0x03, 0x76, 0x61, 0x6c, 0x2a, 0x43, 0x0a, 0x0b, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x6e, 0x6b, 0x6e, - 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, - 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x10, 0x01, 0x12, 0x0f, 0x0a, - 0x0b, 0x50, 0x6b, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x10, 0x02, 0x2a, 0x45, - 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x13, - 0x0a, 0x0f, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x10, 0x00, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x6b, 0x67, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x10, 0x02, 0x2a, 0xbf, 0x02, 0x0a, 0x08, 0x44, 0x61, 0x74, 0x61, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, - 0x08, 0x0a, 0x04, 0x42, 0x4f, 0x4f, 0x4c, 0x10, 0x0a, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x54, - 0x38, 0x10, 0x14, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x31, 0x36, 0x10, 0x15, 0x12, 0x09, - 0x0a, 0x05, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x16, 0x12, 0x09, 0x0a, 0x05, 0x49, 0x4e, 0x54, - 0x36, 0x34, 0x10, 0x17, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x49, 0x4e, 0x54, 0x38, 0x10, 0x1e, 0x12, - 0x0a, 0x0a, 0x06, 0x55, 0x49, 0x4e, 0x54, 0x31, 0x36, 0x10, 0x1f, 0x12, 0x0a, 0x0a, 0x06, 0x55, - 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x20, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x49, 0x4e, 0x54, 0x36, - 0x34, 0x10, 0x21, 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x33, 0x32, 0x10, 0x28, - 0x12, 0x0b, 0x0a, 0x07, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x36, 0x34, 0x10, 0x29, 0x12, 0x08, 0x0a, - 0x04, 0x43, 0x48, 0x41, 0x52, 0x10, 0x32, 0x12, 0x0b, 0x0a, 0x07, 0x56, 0x41, 0x52, 0x43, 0x48, - 0x41, 0x52, 0x10, 0x33, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x45, 0x58, 0x54, 0x10, 0x34, 0x12, 0x08, - 0x0a, 0x04, 0x4a, 0x53, 0x4f, 0x4e, 0x10, 0x35, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x55, 0x49, 0x44, - 0x10, 0x36, 0x12, 0x08, 0x0a, 0x04, 0x54, 0x49, 0x4d, 0x45, 0x10, 0x3c, 0x12, 0x08, 0x0a, 0x04, - 0x44, 0x41, 0x54, 0x45, 0x10, 0x3d, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x41, 0x54, 0x45, 0x54, 0x49, - 0x4d, 0x45, 0x10, 0x3e, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x49, 0x4d, 0x45, 0x53, 0x54, 0x41, 0x4d, - 0x50, 0x10, 0x3f, 0x12, 0x0d, 0x0a, 0x09, 0x44, 0x45, 0x43, 0x49, 0x4d, 0x41, 0x4c, 0x36, 0x34, - 0x10, 0x46, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x45, 0x43, 0x49, 0x4d, 0x41, 0x4c, 0x31, 0x32, 0x38, - 0x10, 0x47, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x50, 0x12, 0x0d, - 0x0a, 0x09, 0x56, 0x41, 0x52, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x51, 0x12, 0x08, 0x0a, - 0x04, 0x42, 0x4c, 0x4f, 0x42, 0x10, 0x52, 0x32, 0x33, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x12, 0x28, 0x0a, 0x03, 0x72, 0x75, 0x6e, 0x12, 0x0c, 0x2e, 0x75, 0x64, 0x66, 0x2e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0d, 0x2e, 0x75, 0x64, 0x66, 0x2e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x2b, 0x5a, 0x29, - 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6d, 0x61, 0x74, 0x72, 0x69, - 0x78, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x2f, 0x6d, 0x61, 0x74, 0x72, 0x69, 0x78, 0x6f, 0x6e, - 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x75, 0x64, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, -} - -var ( - file_udf_proto_rawDescOnce sync.Once - file_udf_proto_rawDescData = file_udf_proto_rawDesc -) - -func file_udf_proto_rawDescGZIP() []byte { - file_udf_proto_rawDescOnce.Do(func() { - file_udf_proto_rawDescData = protoimpl.X.CompressGZIP(file_udf_proto_rawDescData) - }) - return file_udf_proto_rawDescData -} - -var file_udf_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_udf_proto_msgTypes = make([]protoimpl.MessageInfo, 7) -var file_udf_proto_goTypes = []interface{}{ - (RequestType)(0), // 0: udf.RequestType - (ResponseType)(0), // 1: udf.ResponseType - (DataType)(0), // 2: udf.DataType - (*Request)(nil), // 3: udf.Request - (*Response)(nil), // 4: udf.Response - (*Udf)(nil), // 5: udf.Udf - (*Package)(nil), // 6: udf.Package - (*DataVector)(nil), // 7: udf.DataVector - (*Data)(nil), // 8: udf.Data - nil, // 9: udf.Request.ContextEntry -} -var file_udf_proto_depIdxs = []int32{ - 5, // 0: udf.Request.udf:type_name -> udf.Udf - 7, // 1: udf.Request.vectors:type_name -> udf.DataVector - 0, // 2: udf.Request.type:type_name -> udf.RequestType - 9, // 3: udf.Request.context:type_name -> udf.Request.ContextEntry - 7, // 4: udf.Response.vector:type_name -> udf.DataVector - 1, // 5: udf.Response.type:type_name -> udf.ResponseType - 6, // 6: udf.Udf.importPkg:type_name -> udf.Package - 2, // 7: udf.Udf.retType:type_name -> udf.DataType - 8, // 8: udf.DataVector.data:type_name -> udf.Data - 2, // 9: udf.DataVector.type:type_name -> udf.DataType - 3, // 10: udf.Service.run:input_type -> udf.Request - 4, // 11: udf.Service.run:output_type -> udf.Response - 11, // [11:12] is the sub-list for method output_type - 10, // [10:11] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name -} - -func init() { file_udf_proto_init() } -func file_udf_proto_init() { - if File_udf_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_udf_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Request); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_udf_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Response); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_udf_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Udf); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_udf_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Package); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_udf_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DataVector); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_udf_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Data); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_udf_proto_msgTypes[5].OneofWrappers = []interface{}{ - (*Data_BoolVal)(nil), - (*Data_IntVal)(nil), - (*Data_Int64Val)(nil), - (*Data_UintVal)(nil), - (*Data_Uint64Val)(nil), - (*Data_FloatVal)(nil), - (*Data_DoubleVal)(nil), - (*Data_StringVal)(nil), - (*Data_BytesVal)(nil), - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_udf_proto_rawDesc, - NumEnums: 3, - NumMessages: 7, - NumExtensions: 0, - NumServices: 1, - }, - GoTypes: file_udf_proto_goTypes, - DependencyIndexes: file_udf_proto_depIdxs, - EnumInfos: file_udf_proto_enumTypes, - MessageInfos: file_udf_proto_msgTypes, - }.Build() - File_udf_proto = out.File - file_udf_proto_rawDesc = nil - file_udf_proto_goTypes = nil - file_udf_proto_depIdxs = nil -} diff --git a/pkg/udf/udf.proto b/pkg/udf/udf.proto deleted file mode 100644 index e21c500fab7f6..0000000000000 --- a/pkg/udf/udf.proto +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2023 Matrix Origin -// -// 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. - -syntax = "proto3"; - -package udf; - -option go_package = "github.com/matrixorigin/matrixone/pkg/udf"; - -// protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./udf.proto - -service Service { - rpc run(stream Request) returns (stream Response) {} -} - -enum RequestType { - UnknownRequest = 0; - DataRequest = 1; // request with data for function result - PkgResponse = 2; // response with package -} - -message Request { - Udf udf = 1; - repeated DataVector vectors = 2; - int64 length = 3; - RequestType type = 4; - map context = 5; // currently just transfer, not used -} - -enum ResponseType { - UnknownResponse = 0; - DataResponse = 1; // response with function result - PkgRequest = 2; // request for package -} - -message Response { - DataVector vector = 1; - ResponseType type = 2; -} - -message Udf { - string handler = 1; - bool isImport = 2; - string body = 3; - Package importPkg = 4; - DataType retType = 5; - string language = 6; - string modifiedTime = 7; - string db = 8; -} - -message Package { - bytes data = 1; - bool last = 2; -} - -message DataVector { - repeated Data data = 1; - bool const = 2; - int64 length = 3; - DataType type = 4; - int32 scale = 5; -} - -enum DataType { - UNKNOWN = 0; - - BOOL = 10; - - INT8 = 20; - INT16 = 21; - INT32 = 22; - INT64 = 23; - - UINT8 = 30; - UINT16 = 31; - UINT32 = 32; - UINT64 = 33; - - FLOAT32 = 40; - FLOAT64 = 41; - - CHAR = 50; - VARCHAR = 51; - TEXT = 52; - JSON = 53; - UUID = 54; - - TIME = 60; - DATE = 61; - DATETIME = 62; - TIMESTAMP = 63; - - DECIMAL64 = 70; - DECIMAL128 = 71; - - - BINARY = 80; - VARBINARY = 81; - BLOB = 82; -} - -message Data { - oneof val { - bool boolVal = 1; // bool - sint32 intVal = 2; // int8, int16, int32 - sint64 int64Val = 3; // int64 - uint32 uintVal = 4; // uint8, uint16, uint32 - uint64 uint64Val = 5; // uint64 - float floatVal = 6; // float32 - double doubleVal = 7; // float64 - string stringVal = 8; // char, varchar, text, json, uuid | time, date, datetime, timestamp | Decimal64, Decimal128 - bytes bytesVal = 9; // binary, varbinary, blob - } -} \ No newline at end of file diff --git a/pkg/udf/udf_grpc.pb.go b/pkg/udf/udf_grpc.pb.go deleted file mode 100644 index 5e863134bba82..0000000000000 --- a/pkg/udf/udf_grpc.pb.go +++ /dev/null @@ -1,137 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v3.17.0 -// source: udf.proto - -package udf - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// ServiceClient is the client API for Service service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type ServiceClient interface { - Run(ctx context.Context, opts ...grpc.CallOption) (Service_RunClient, error) -} - -type serviceClient struct { - cc grpc.ClientConnInterface -} - -func NewServiceClient(cc grpc.ClientConnInterface) ServiceClient { - return &serviceClient{cc} -} - -func (c *serviceClient) Run(ctx context.Context, opts ...grpc.CallOption) (Service_RunClient, error) { - stream, err := c.cc.NewStream(ctx, &Service_ServiceDesc.Streams[0], "/udf.Service/run", opts...) - if err != nil { - return nil, err - } - x := &serviceRunClient{stream} - return x, nil -} - -type Service_RunClient interface { - Send(*Request) error - Recv() (*Response, error) - grpc.ClientStream -} - -type serviceRunClient struct { - grpc.ClientStream -} - -func (x *serviceRunClient) Send(m *Request) error { - return x.ClientStream.SendMsg(m) -} - -func (x *serviceRunClient) Recv() (*Response, error) { - m := new(Response) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// ServiceServer is the server API for Service service. -// All implementations must embed UnimplementedServiceServer -// for forward compatibility -type ServiceServer interface { - Run(Service_RunServer) error - mustEmbedUnimplementedServiceServer() -} - -// UnimplementedServiceServer must be embedded to have forward compatible implementations. -type UnimplementedServiceServer struct { -} - -func (UnimplementedServiceServer) Run(Service_RunServer) error { - return status.Errorf(codes.Unimplemented, "method Run not implemented") -} -func (UnimplementedServiceServer) mustEmbedUnimplementedServiceServer() {} - -// UnsafeServiceServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to ServiceServer will -// result in compilation errors. -type UnsafeServiceServer interface { - mustEmbedUnimplementedServiceServer() -} - -func RegisterServiceServer(s grpc.ServiceRegistrar, srv ServiceServer) { - s.RegisterService(&Service_ServiceDesc, srv) -} - -func _Service_Run_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(ServiceServer).Run(&serviceRunServer{stream}) -} - -type Service_RunServer interface { - Send(*Response) error - Recv() (*Request, error) - grpc.ServerStream -} - -type serviceRunServer struct { - grpc.ServerStream -} - -func (x *serviceRunServer) Send(m *Response) error { - return x.ServerStream.SendMsg(m) -} - -func (x *serviceRunServer) Recv() (*Request, error) { - m := new(Request) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// Service_ServiceDesc is the grpc.ServiceDesc for Service service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var Service_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "udf.Service", - HandlerType: (*ServiceServer)(nil), - Methods: []grpc.MethodDesc{}, - Streams: []grpc.StreamDesc{ - { - StreamName: "run", - Handler: _Service_Run_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "udf.proto", -} diff --git a/pkg/vm/engine/disttae/types.go b/pkg/vm/engine/disttae/types.go index 700055a837937..4bcbee73a2661 100644 --- a/pkg/vm/engine/disttae/types.go +++ b/pkg/vm/engine/disttae/types.go @@ -262,7 +262,7 @@ type Engine struct { ls lockservice.LockService qc qclient.QueryClient hakeeper logservice.CNHAKeeperClient - us udf.Service + us udf.Runtime cli client.TxnClient idGen IDGenerator tnID string diff --git a/pkg/vm/process/process2.go b/pkg/vm/process/process2.go index cea6422496152..8ed62d772ac89 100644 --- a/pkg/vm/process/process2.go +++ b/pkg/vm/process/process2.go @@ -57,7 +57,7 @@ func NewTopProcess( fileService fileservice.FileService, lockService lockservice.LockService, queryClient qclient.QueryClient, HAKeeper logservice.CNHAKeeperClient, - udfService udf.Service, + udfService udf.Runtime, autoIncrease *defines.AutoIncrCacheManager, taskService taskservice.TaskService) *Process { diff --git a/pkg/vm/process/process_codec.go b/pkg/vm/process/process_codec.go index 3f4e2340257a3..315b35d755b0f 100644 --- a/pkg/vm/process/process_codec.go +++ b/pkg/vm/process/process_codec.go @@ -229,7 +229,7 @@ func NewCodecService( partitionService partitionservice.PartitionService, queryClient qclient.QueryClient, hakeeper logservice.CNHAKeeperClient, - udfService udf.Service, + udfService udf.Runtime, engine engine.Engine, ) ProcessCodecService { mp, err := mpool.NewMPool("codec", 1<<40, mpool.NoFixed) @@ -256,7 +256,7 @@ type codecService struct { partitionService partitionservice.PartitionService queryClient qclient.QueryClient hakeeper logservice.CNHAKeeperClient - udfService udf.Service + udfService udf.Runtime mp *mpool.MPool engine engine.Engine } diff --git a/pkg/vm/process/types.go b/pkg/vm/process/types.go index 7b77b1c809b76..75431b5bb9e2b 100644 --- a/pkg/vm/process/types.go +++ b/pkg/vm/process/types.go @@ -485,7 +485,7 @@ type BaseProcess struct { prepareParamsOwned bool QueryClient qclient.QueryClient Hakeeper logservice.CNHAKeeperClient - UdfService udf.Service + UdfService udf.Runtime WaitPolicy lock.WaitPolicy messageBoard *message.MessageBoard executionResourceBudgetBorrowed bool From 4420d3d557df1cc7da020d052e9b836640f1970c Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 16:23:19 +0800 Subject: [PATCH 002/241] fix(udf): tighten runtime naming and lifecycle --- .../python-udf-server.toml | 2 +- .../python-udf-server.toml | 2 +- optools/images/pythonserver/Dockerfile | 2 +- pkg/cnservice/server.go | 3 + pkg/udf/protocol/protocol.go | 4 +- pkg/udf/protocol/protocol_test.go | 2 + pkg/udf/pythonruntime/gateway.go | 8 +- .../{pyserver => worker}/requirements.txt | 0 .../{pyserver => worker}/test_worker.py | 33 +++++ .../{pyserver => worker}/worker.py | 119 +++++++++++++++++- pkg/udf/runtime.go | 29 +++++ pkg/udf/runtime_test.go | 48 +++++++ 12 files changed, 239 insertions(+), 13 deletions(-) rename pkg/udf/pythonruntime/{pyserver => worker}/requirements.txt (100%) rename pkg/udf/pythonruntime/{pyserver => worker}/test_worker.py (73%) rename pkg/udf/pythonruntime/{pyserver => worker}/worker.py (86%) create mode 100644 pkg/udf/runtime_test.go diff --git a/etc/launch-with-python-udf-server/python-udf-server.toml b/etc/launch-with-python-udf-server/python-udf-server.toml index 53726382e8222..4c351d3d923c5 100644 --- a/etc/launch-with-python-udf-server/python-udf-server.toml +++ b/etc/launch-with-python-udf-server/python-udf-server.toml @@ -3,4 +3,4 @@ service-type = "PYTHON_UDF" [python-udf-server] uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41b2" address = "127.0.0.1:50051" -path = "pkg/udf/pythonruntime/pyserver" +path = "pkg/udf/pythonruntime/worker" diff --git a/etc/v1/launch-with-python-udf-server/python-udf-server.toml b/etc/v1/launch-with-python-udf-server/python-udf-server.toml index 53726382e8222..4c351d3d923c5 100644 --- a/etc/v1/launch-with-python-udf-server/python-udf-server.toml +++ b/etc/v1/launch-with-python-udf-server/python-udf-server.toml @@ -3,4 +3,4 @@ service-type = "PYTHON_UDF" [python-udf-server] uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41b2" address = "127.0.0.1:50051" -path = "pkg/udf/pythonruntime/pyserver" +path = "pkg/udf/pythonruntime/worker" diff --git a/optools/images/pythonserver/Dockerfile b/optools/images/pythonserver/Dockerfile index 8871edc0006c1..cf1b3844f391f 100644 --- a/optools/images/pythonserver/Dockerfile +++ b/optools/images/pythonserver/Dockerfile @@ -1,5 +1,5 @@ # run from root path for debug: -# docker build -t mo-python-udf-runtime -f ./optools/images/pythonserver/Dockerfile ./pkg/udf/pythonruntime/pyserver/ +# docker build -t mo-python-udf-runtime -f ./optools/images/pythonserver/Dockerfile ./pkg/udf/pythonruntime/worker/ # docker run -d --network host mo-python-udf-runtime FROM python:3.12-bookworm diff --git a/pkg/cnservice/server.go b/pkg/cnservice/server.go index bb3ff387f1648..8d4cd1bed5882 100644 --- a/pkg/cnservice/server.go +++ b/pkg/cnservice/server.go @@ -847,6 +847,9 @@ func (s *service) stopRPCs() error { if s.queryClient != nil { err = errors.Join(err, s.queryClient.Close()) } + if closer, ok := s.udfService.(udf.RuntimeCloser); ok { + err = errors.Join(err, closer.Close()) + } if s.timestampWaiter != nil { s.timestampWaiter.Close() } diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 226c7bf300802..047b23ea6ad6a 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -18,7 +18,6 @@ package protocol import ( - "bytes" "crypto/sha256" "encoding/hex" "encoding/json" @@ -111,8 +110,7 @@ func UnmarshalControl(data []byte) (Control, error) { return Control{}, fmt.Errorf("%w: control size %d is outside the allowed range", ErrProtocol, len(data)) } var control Control - decoder := json.NewDecoder(bytes.NewReader(data)) - if err := decoder.Decode(&control); err != nil { + if err := json.Unmarshal(data, &control); err != nil { return Control{}, fmt.Errorf("%w: decode control: %v", ErrProtocol, err) } if control.Version != Version || control.Kind == "" { diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index 8696d59997ec4..33938086ad5c4 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -42,6 +42,8 @@ func TestControlRoundTripIsBoundedAndVersioned(t *testing.T) { _, err = UnmarshalControl(bytes.Repeat([]byte{'x'}, MaxControlBytes+1)) require.ErrorIs(t, err, ErrProtocol) + _, err = UnmarshalControl(append(wire, []byte(" trailing")...)) + require.ErrorIs(t, err, ErrProtocol) _, err = MarshalControl(Control{Kind: "", Tuple: testTuple()}) require.ErrorIs(t, err, ErrProtocol) } diff --git a/pkg/udf/pythonruntime/gateway.go b/pkg/udf/pythonruntime/gateway.go index 433393d1f330e..6cbcd829a5535 100644 --- a/pkg/udf/pythonruntime/gateway.go +++ b/pkg/udf/pythonruntime/gateway.go @@ -118,6 +118,8 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if ctx == nil { ctx = context.Background() } + streamCtx, cancel := context.WithTimeout(ctx, g.cfg.RequestTimeout) + defer cancel() if invocation == nil || result == nil || mp == nil { return fmt.Errorf("python runtime: nil invocation, result, or memory pool") } @@ -152,7 +154,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return err } - stream, err := g.flight.DoExchange(ctx) + stream, err := g.flight.DoExchange(streamCtx) if err != nil { return fmt.Errorf("python runtime: open Arrow Flight exchange: %w", err) } @@ -223,7 +225,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul } inputEnded = true } - batchRows, err := g.receiveResultBatch(ctx, stream, invocation.Tuple, sequenceNumber, batch.Rows, &schemaFrame, returnDescriptor, result, mp, &sequence) + batchRows, err := g.receiveResultBatch(streamCtx, stream, invocation.Tuple, sequenceNumber, batch.Rows, &schemaFrame, returnDescriptor, result, mp, &sequence) if err != nil { return err } @@ -237,7 +239,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if !inputEnded || lastSequence != batchIndex { return fmt.Errorf("python runtime: input stream did not reach EndInput") } - return g.receiveFinish(ctx, stream, invocation.Tuple, invocation.Length, rows, &sequence) + return g.receiveFinish(streamCtx, stream, invocation.Tuple, invocation.Length, rows, &sequence) } func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaining, maxBytes, maxRows int64) (encodedRecordBatch, error) { diff --git a/pkg/udf/pythonruntime/pyserver/requirements.txt b/pkg/udf/pythonruntime/worker/requirements.txt similarity index 100% rename from pkg/udf/pythonruntime/pyserver/requirements.txt rename to pkg/udf/pythonruntime/worker/requirements.txt diff --git a/pkg/udf/pythonruntime/pyserver/test_worker.py b/pkg/udf/pythonruntime/worker/test_worker.py similarity index 73% rename from pkg/udf/pythonruntime/pyserver/test_worker.py rename to pkg/udf/pythonruntime/worker/test_worker.py index 147808c6a7db6..ef15c3643a7b0 100644 --- a/pkg/udf/pythonruntime/pyserver/test_worker.py +++ b/pkg/udf/pythonruntime/worker/test_worker.py @@ -57,6 +57,39 @@ def test_zero_argument_vector_uses_context_rows(self): with self.assertRaisesRegex(ValueError, "result length"): worker._output_array(pa.array([7], type=pa.int64()), descriptor, 3) + def test_statement_context_is_whitelisted_and_frozen(self): + context = worker._statement_context( + { + "statement_id": "fence-only", + "statement_timestamp_utc": "1704067200123456", + "session_timezone_kind": "FIXED_OFFSET", + "session_timezone_offset_minutes": "+510", + "sql_mode": '["ANSI", "STRICT"]', + "current_database": "app", + "current_user": "alice", + "current_role": "writer", + "connection_collation": "utf8mb4_bin", + } + ) + self.assertIsInstance(context, worker.StatementContext) + self.assertEqual(510, context.session_timezone.offset_minutes) + self.assertEqual(("ANSI", "STRICT"), context.sql_mode) + self.assertEqual("alice", context.current_user) + self.assertIsNone(worker._statement_context({"statement_id": "fence-only"})) + with self.assertRaisesRegex(ValueError, "unsupported statement context"): + worker._statement_context({"unexpected": "value"}) + with self.assertRaisesRegex(ValueError, "not canonical"): + worker._statement_context( + { + "statement_timestamp_utc": "1704067200000000", + "session_timezone_kind": "FIXED_OFFSET", + "session_timezone_offset_minutes": "0", + "sql_mode": '["STRICT", "ANSI"]', + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + ) + def test_terminal_admission_does_not_evict_live_tombstones(self): old_records = worker.MAX_TERMINAL_RECORDS old_bytes = worker.MAX_TERMINAL_BYTES diff --git a/pkg/udf/pythonruntime/pyserver/worker.py b/pkg/udf/pythonruntime/worker/worker.py similarity index 86% rename from pkg/udf/pythonruntime/pyserver/worker.py rename to pkg/udf/pythonruntime/worker/worker.py index ef12c8ea37f30..1eb732105fab5 100644 --- a/pkg/udf/pythonruntime/pyserver/worker.py +++ b/pkg/udf/pythonruntime/worker/worker.py @@ -78,6 +78,25 @@ class SqlTimestamp: value: Optional[_datetime.datetime] +@dataclass(frozen=True, slots=True) +class TimezoneContext: + kind: str + name: Optional[str] = None + offset_minutes: Optional[int] = None + tzdb_version: Optional[str] = None + + +@dataclass(frozen=True, slots=True) +class StatementContext: + statement_timestamp_utc: _datetime.datetime + session_timezone: TimezoneContext + sql_mode: tuple[str, ...] + current_database: Optional[str] + current_user: str + current_role: Optional[str] + connection_collation: str + + class _CallLogger: __slots__ = () @@ -95,17 +114,108 @@ def error(self, message: str, *args: Any) -> None: class ScalarContext: sdk_version: str logger: _CallLogger - statement: Any = None + statement: Optional[StatementContext] = None @dataclass(frozen=True, slots=True) class VectorContext: sdk_version: str logger: _CallLogger - statement: Any = None + statement: Optional[StatementContext] = None num_rows: int = 0 +_FENCING_CONTEXT_KEYS = frozenset( + {"account_id", "statement_id", "group_id", "group_epoch", "invocation_id", "lease_epoch"} +) +_STATEMENT_CONTEXT_KEYS = frozenset( + { + "statement_timestamp_utc", + "session_timezone_kind", + "session_timezone_name", + "session_timezone_offset_minutes", + "session_timezone_tzdb_version", + "sql_mode", + "current_database", + "current_user", + "current_role", + "connection_collation", + } +) + + +def _required_context_value(context: Dict[str, Any], key: str) -> str: + value = context.get(key) + if not isinstance(value, str) or not value: + raise ValueError(f"PROTOCOL: missing statement context field {key}") + return value + + +def _statement_context(raw: Any) -> Optional[StatementContext]: + if raw is None: + return None + if not isinstance(raw, dict): + raise ValueError("PROTOCOL: statement context must be an object") + unknown = set(raw) - _FENCING_CONTEXT_KEYS - _STATEMENT_CONTEXT_KEYS + if unknown: + raise ValueError("PROTOCOL: unsupported statement context field") + if not (set(raw) & _STATEMENT_CONTEXT_KEYS): + # The fencing fields are transport identity, not user-visible context. + return None + + timestamp_text = _required_context_value(raw, "statement_timestamp_utc") + try: + timestamp_micros = int(timestamp_text, 10) + seconds, micros = divmod(timestamp_micros, 1_000_000) + timestamp = _datetime.datetime(1970, 1, 1, tzinfo=_datetime.timezone.utc) + _datetime.timedelta(seconds=seconds, microseconds=micros) + except (TypeError, ValueError, OverflowError) as exc: + raise ValueError("PROTOCOL: invalid statement_timestamp_utc") from exc + + timezone_kind = _required_context_value(raw, "session_timezone_kind").upper() + if timezone_kind == "IANA": + timezone_name = _required_context_value(raw, "session_timezone_name") + tzdb_version = _required_context_value(raw, "session_timezone_tzdb_version") + if raw.get("session_timezone_offset_minutes"): + raise ValueError("PROTOCOL: IANA timezone cannot carry a fixed offset") + timezone = TimezoneContext("IANA", name=timezone_name, tzdb_version=tzdb_version) + elif timezone_kind == "FIXED_OFFSET": + offset_text = _required_context_value(raw, "session_timezone_offset_minutes") + try: + offset_minutes = int(offset_text, 10) + except (TypeError, ValueError) as exc: + raise ValueError("PROTOCOL: invalid fixed timezone offset") from exc + if offset_minutes < -839 or offset_minutes > 840: + raise ValueError("PROTOCOL: fixed timezone offset is outside SQL range") + if raw.get("session_timezone_name") or raw.get("session_timezone_tzdb_version"): + raise ValueError("PROTOCOL: fixed timezone cannot carry IANA identity") + timezone = TimezoneContext("FIXED_OFFSET", offset_minutes=offset_minutes) + else: + raise ValueError("PROTOCOL: unsupported timezone kind") + + sql_mode_text = _required_context_value(raw, "sql_mode") + try: + sql_mode_value = json.loads(sql_mode_text) + except (TypeError, ValueError) as exc: + raise ValueError("PROTOCOL: sql_mode must be canonical JSON array") from exc + if not isinstance(sql_mode_value, list) or any(not isinstance(item, str) for item in sql_mode_value): + raise ValueError("PROTOCOL: sql_mode must be an array of strings") + sql_mode = tuple(sorted(set(sql_mode_value))) + if list(sql_mode) != sql_mode_value: + raise ValueError("PROTOCOL: sql_mode is not canonical") + + current_user = _required_context_value(raw, "current_user") + connection_collation = _required_context_value(raw, "connection_collation") + return StatementContext( + statement_timestamp_utc=timestamp, + session_timezone=timezone, + sql_mode=sql_mode, + current_database=raw.get("current_database") or None, + current_user=current_user, + current_role=raw.get("current_role") or None, + connection_collation=connection_collation, + ) + + def _tuple_key(value: Dict[str, Any]) -> tuple: required = ("account_id", "statement_id", "group_id", "group_epoch", "invocation_id", "lease_epoch") if any(not value.get(k) for k in required): @@ -528,6 +638,7 @@ def do_exchange(self, context, descriptor, reader, writer): if isinstance(payload, str): payload = json.loads(payload) args = list(payload.get("args", [])); result_descriptor = payload["return"] + statement_context = _statement_context(payload.get("context")) mode = payload.get("mode", MODE_SCALAR); null_policy = payload.get("null_policy", NULL_CALL) abi_contract = payload.get("abi_contract", ABI_CONTRACT) adapter_version = payload.get("adapter_version", ADAPTER_VERSION) @@ -563,7 +674,7 @@ def do_exchange(self, context, descriptor, reader, writer): if batch.num_rows <= 0: raise ValueError("PROTOCOL: empty input batch") if batch.num_rows > max_batch_rows: raise ValueError("RESOURCE_EXHAUSTED: input batch has too many rows") if mode == MODE_VECTOR: - call_context = VectorContext(sdk_version, _CallLogger(), None, batch.num_rows) + call_context = VectorContext(sdk_version, _CallLogger(), statement_context, batch.num_rows) try: output = handler(call_context, *[batch.column(index) for index in range(batch.num_columns)]) except Exception as exc: @@ -571,7 +682,7 @@ def do_exchange(self, context, descriptor, reader, writer): if not isinstance(output, (pa.Array, pa.ChunkedArray)): raise ValueError("TYPE_CONTRACT: VECTOR handler must return an Arrow Array or ChunkedArray") else: - call_context = ScalarContext(sdk_version, _CallLogger(), None) + call_context = ScalarContext(sdk_version, _CallLogger(), statement_context) values = [] for row in range(batch.num_rows): params = [_scalar_input(batch.column(index), row, args[index]) for index in range(batch.num_columns)] diff --git a/pkg/udf/runtime.go b/pkg/udf/runtime.go index 33b2b90280ecf..5df11f7a374de 100644 --- a/pkg/udf/runtime.go +++ b/pkg/udf/runtime.go @@ -20,6 +20,9 @@ package udf import ( "context" + "errors" + "sort" + "sync" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" @@ -64,6 +67,14 @@ type Runtime interface { Execute(context.Context, *Invocation, vector.FunctionResultWrapper, *mpool.MPool) error } +// RuntimeCloser is an optional lifecycle contract for runtimes that own a +// transport connection or a worker process. Execution callers only need +// Runtime; service shutdown uses this interface to close such resources. +type RuntimeCloser interface { + Runtime + Close() error +} + // Registry dispatches to the one runtime selected by a routine's language. // A registry is immutable after construction, so plan execution cannot race // service registration or observe a partially initialized adapter. @@ -83,6 +94,8 @@ func NewRuntime(runtimes ...Runtime) (Runtime, error) { type runtimeRegistry struct { byLanguage map[string]Runtime + closeOnce sync.Once + closeErr error } func (r *runtimeRegistry) Language() string { return "multiple" } @@ -102,3 +115,19 @@ func (r *runtimeRegistry) Execute( } return runtime.Execute(ctx, invocation, result, mp) } + +func (r *runtimeRegistry) Close() error { + r.closeOnce.Do(func() { + languages := make([]string, 0, len(r.byLanguage)) + for language := range r.byLanguage { + languages = append(languages, language) + } + sort.Strings(languages) + for _, language := range languages { + if closer, ok := r.byLanguage[language].(RuntimeCloser); ok { + r.closeErr = errors.Join(r.closeErr, closer.Close()) + } + } + }) + return r.closeErr +} diff --git a/pkg/udf/runtime_test.go b/pkg/udf/runtime_test.go new file mode 100644 index 0000000000000..908d7764f225b --- /dev/null +++ b/pkg/udf/runtime_test.go @@ -0,0 +1,48 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package udf + +import ( + "context" + "sync/atomic" + "testing" + + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/stretchr/testify/require" +) + +type closableRuntime struct { + language string + closed atomic.Int32 +} + +func (r *closableRuntime) Language() string { return r.language } + +func (r *closableRuntime) Execute( + context.Context, + *Invocation, + vector.FunctionResultWrapper, + *mpool.MPool, +) error { + return nil +} + +func (r *closableRuntime) Close() error { + r.closed.Add(1) + return nil +} + +func TestRuntimeRegistryClosesOwnedRuntimesOnce(t *testing.T) { + python := &closableRuntime{language: LanguagePython} + runtime, err := NewRuntime(python) + require.NoError(t, err) + closer, ok := runtime.(RuntimeCloser) + require.True(t, ok) + require.NoError(t, closer.Close()) + require.NoError(t, closer.Close()) + require.Equal(t, int32(1), python.closed.Load()) +} From 8ae711693725c2fe7a00828dcc36ba304aab7fb4 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 16:31:11 +0800 Subject: [PATCH 003/241] fix(udf): rename Python adapter and fence duplicate calls --- cmd/mo-service/config.go | 4 +- cmd/mo-service/main.go | 4 +- .../python-udf-server.toml | 2 +- .../python-udf-server.toml | 2 +- optools/images/pythonserver/Dockerfile | 2 +- pkg/cnservice/server.go | 6 +-- pkg/cnservice/types.go | 4 +- pkg/embed/config.go | 4 +- pkg/udf/protocol/protocol.go | 38 ++++++++-------- pkg/udf/protocol/protocol_test.go | 14 ++++++ pkg/udf/{pythonruntime => python}/arrow.go | 2 +- .../{pythonruntime => python}/arrow_test.go | 2 +- pkg/udf/{pythonruntime => python}/config.go | 2 +- pkg/udf/{pythonruntime => python}/gateway.go | 2 +- .../{pythonruntime => python}/supervisor.go | 2 +- .../worker/requirements.txt | 0 .../worker/test_worker.py | 12 ++++++ .../worker/worker.py | 43 ++++++++++++++++--- 18 files changed, 102 insertions(+), 43 deletions(-) rename pkg/udf/{pythonruntime => python}/arrow.go (99%) rename pkg/udf/{pythonruntime => python}/arrow_test.go (99%) rename pkg/udf/{pythonruntime => python}/config.go (98%) rename pkg/udf/{pythonruntime => python}/gateway.go (99%) rename pkg/udf/{pythonruntime => python}/supervisor.go (99%) rename pkg/udf/{pythonruntime => python}/worker/requirements.txt (100%) rename pkg/udf/{pythonruntime => python}/worker/test_worker.py (89%) rename pkg/udf/{pythonruntime => python}/worker/worker.py (95%) diff --git a/cmd/mo-service/config.go b/cmd/mo-service/config.go index bc75566af25c1..1314bb73218e7 100644 --- a/cmd/mo-service/config.go +++ b/cmd/mo-service/config.go @@ -45,7 +45,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/perfcounter" "github.com/matrixorigin/matrixone/pkg/proxy" "github.com/matrixorigin/matrixone/pkg/tnservice" - "github.com/matrixorigin/matrixone/pkg/udf/pythonruntime" + "github.com/matrixorigin/matrixone/pkg/udf/python" "github.com/matrixorigin/matrixone/pkg/util/debug/goroutine" tomlutil "github.com/matrixorigin/matrixone/pkg/util/toml" "github.com/matrixorigin/matrixone/pkg/version" @@ -119,7 +119,7 @@ type Config struct { // ProxyConfig is the config of proxy. ProxyConfig proxy.Config `toml:"proxy"` // PythonUdfServerConfig is the config of python udf server - PythonUdfServerConfig pythonruntime.Config `toml:"python-udf-server"` + PythonUdfServerConfig python.Config `toml:"python-udf-server"` // Observability parameters for the metric/trace Observability config.ObservabilityParameters `toml:"observability"` diff --git a/cmd/mo-service/main.go b/cmd/mo-service/main.go index f2f647a76054f..f0a4497bf209d 100644 --- a/cmd/mo-service/main.go +++ b/cmd/mo-service/main.go @@ -52,7 +52,7 @@ import ( qclient "github.com/matrixorigin/matrixone/pkg/queryservice/client" "github.com/matrixorigin/matrixone/pkg/sql/compile" "github.com/matrixorigin/matrixone/pkg/tnservice" - "github.com/matrixorigin/matrixone/pkg/udf/pythonruntime" + "github.com/matrixorigin/matrixone/pkg/udf/python" "github.com/matrixorigin/matrixone/pkg/util/debug/goroutine" "github.com/matrixorigin/matrixone/pkg/util/export" "github.com/matrixorigin/matrixone/pkg/util/export/table" @@ -760,7 +760,7 @@ func startPythonUdfService(cfg *Config, stopper *stopper.Stopper) error { defer func() { finishTask(closeErr) }() roleCtx, cancelRole := serviceLifecycle.roleContext(ctx, serviceRolePython) defer cancelRole() - s, err := pythonruntime.NewSupervisor(cfg.PythonUdfServerConfig) + s, err := python.NewSupervisor(cfg.PythonUdfServerConfig) if err != nil { panic(err) } diff --git a/etc/launch-with-python-udf-server/python-udf-server.toml b/etc/launch-with-python-udf-server/python-udf-server.toml index 4c351d3d923c5..37efe868191bc 100644 --- a/etc/launch-with-python-udf-server/python-udf-server.toml +++ b/etc/launch-with-python-udf-server/python-udf-server.toml @@ -3,4 +3,4 @@ service-type = "PYTHON_UDF" [python-udf-server] uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41b2" address = "127.0.0.1:50051" -path = "pkg/udf/pythonruntime/worker" +path = "pkg/udf/python/worker" diff --git a/etc/v1/launch-with-python-udf-server/python-udf-server.toml b/etc/v1/launch-with-python-udf-server/python-udf-server.toml index 4c351d3d923c5..37efe868191bc 100644 --- a/etc/v1/launch-with-python-udf-server/python-udf-server.toml +++ b/etc/v1/launch-with-python-udf-server/python-udf-server.toml @@ -3,4 +3,4 @@ service-type = "PYTHON_UDF" [python-udf-server] uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41b2" address = "127.0.0.1:50051" -path = "pkg/udf/pythonruntime/worker" +path = "pkg/udf/python/worker" diff --git a/optools/images/pythonserver/Dockerfile b/optools/images/pythonserver/Dockerfile index cf1b3844f391f..88022f7fafd1f 100644 --- a/optools/images/pythonserver/Dockerfile +++ b/optools/images/pythonserver/Dockerfile @@ -1,5 +1,5 @@ # run from root path for debug: -# docker build -t mo-python-udf-runtime -f ./optools/images/pythonserver/Dockerfile ./pkg/udf/pythonruntime/worker/ +# docker build -t mo-python-udf-runtime -f ./optools/images/pythonserver/Dockerfile ./pkg/udf/python/worker/ # docker run -d --network host mo-python-udf-runtime FROM python:3.12-bookworm diff --git a/pkg/cnservice/server.go b/pkg/cnservice/server.go index 8d4cd1bed5882..d40fd5d698342 100644 --- a/pkg/cnservice/server.go +++ b/pkg/cnservice/server.go @@ -69,7 +69,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/txn/clock" "github.com/matrixorigin/matrixone/pkg/txn/rpc" "github.com/matrixorigin/matrixone/pkg/udf" - "github.com/matrixorigin/matrixone/pkg/udf/pythonruntime" + "github.com/matrixorigin/matrixone/pkg/udf/python" "github.com/matrixorigin/matrixone/pkg/util/address" "github.com/matrixorigin/matrixone/pkg/util/executor" v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2" @@ -255,8 +255,8 @@ func NewService( var udfServices []udf.Runtime // add python client to handle python udf if srv.cfg.PythonUdfClient.ServerAddress != "" { - var pc *pythonruntime.Gateway - pc, err = pythonruntime.NewGateway(srv.cfg.PythonUdfClient) + var pc *python.Gateway + pc, err = python.NewGateway(srv.cfg.PythonUdfClient) if err != nil { return nil, err } diff --git a/pkg/cnservice/types.go b/pkg/cnservice/types.go index 6931b4749425e..b2a4706efa922 100644 --- a/pkg/cnservice/types.go +++ b/pkg/cnservice/types.go @@ -53,7 +53,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/txn/clock" "github.com/matrixorigin/matrixone/pkg/txn/rpc" "github.com/matrixorigin/matrixone/pkg/udf" - "github.com/matrixorigin/matrixone/pkg/udf/pythonruntime" + "github.com/matrixorigin/matrixone/pkg/udf/python" "github.com/matrixorigin/matrixone/pkg/util" "github.com/matrixorigin/matrixone/pkg/util/address" "github.com/matrixorigin/matrixone/pkg/util/executor" @@ -310,7 +310,7 @@ type Config struct { // "working", "draining" and "drained". InitWorkState string `toml:"init-work-state"` - PythonUdfClient pythonruntime.ClientConfig `toml:"python-udf-client"` + PythonUdfClient python.ClientConfig `toml:"python-udf-client"` // LogtailUpdateWorkerFactor is the times of CPU number of this node // to start update workers. diff --git a/pkg/embed/config.go b/pkg/embed/config.go index f4ec3e61feaa4..1007a9f0a9ad6 100644 --- a/pkg/embed/config.go +++ b/pkg/embed/config.go @@ -40,7 +40,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/perfcounter" "github.com/matrixorigin/matrixone/pkg/proxy" "github.com/matrixorigin/matrixone/pkg/tnservice" - "github.com/matrixorigin/matrixone/pkg/udf/pythonruntime" + "github.com/matrixorigin/matrixone/pkg/udf/python" "github.com/matrixorigin/matrixone/pkg/util" "github.com/matrixorigin/matrixone/pkg/util/debug/goroutine" tomlutil "github.com/matrixorigin/matrixone/pkg/util/toml" @@ -95,7 +95,7 @@ type ServiceConfig struct { // ProxyConfig is the config of proxy. ProxyConfig proxy.Config `toml:"proxy"` // PythonUdfServerConfig is the config of python udf server - PythonUdfServerConfig pythonruntime.Config `toml:"python-udf-server"` + PythonUdfServerConfig python.Config `toml:"python-udf-server"` // Observability parameters for the metric/trace Observability config.ObservabilityParameters `toml:"observability"` diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 047b23ea6ad6a..ea7a61941cb00 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -318,6 +318,7 @@ type ExecutionGroup struct { registered int inFlight int members map[string]bool + terminal map[string]bool closing bool releaseBusy bool released bool @@ -331,7 +332,7 @@ func NewExecutionGroup(id string, epoch uint64, maxMembers int, release func() e } return &ExecutionGroup{ id: id, epoch: epoch, maxMembers: maxMembers, - members: make(map[string]bool), release: release, + members: make(map[string]bool), terminal: make(map[string]bool), release: release, }, nil } @@ -346,7 +347,7 @@ func (g *ExecutionGroup) BeginOpen(memberID string) (*OpenToken, error) { if g.closing || g.released { return nil, ErrGroupClosed } - if g.members[memberID] { + if g.members[memberID] || g.terminal[memberID] { return nil, ErrDuplicate } if g.registered+g.inFlight >= g.maxMembers { @@ -360,52 +361,48 @@ type OpenToken struct { group *ExecutionGroup memberID string once sync.Once + result error } func (t *OpenToken) Commit() error { if t == nil || t.group == nil { return ErrUnknownIdentity } - var err error - var release bool t.once.Do(func() { g := t.group g.mu.Lock() g.inFlight-- if g.closing || g.released { - err = ErrGroupClosed - release = g.canReleaseLocked() + t.result = ErrGroupClosed + release := g.canReleaseLocked() g.mu.Unlock() + if release { + _ = t.group.releaseIfReady() + } return } g.members[t.memberID] = true g.registered++ g.mu.Unlock() }) - if release { - if releaseErr := t.group.releaseIfReady(); err == nil { - err = releaseErr - } - } - return err + return t.result } func (t *OpenToken) Abort() error { if t == nil || t.group == nil { return ErrUnknownIdentity } - var release bool t.once.Do(func() { g := t.group g.mu.Lock() g.inFlight-- - release = g.canReleaseLocked() + release := g.canReleaseLocked() g.mu.Unlock() + if release { + t.result = t.group.releaseIfReady() + } }) - if release { - return t.group.releaseIfReady() - } - return nil + return t.result } func (g *ExecutionGroup) Close(reason CloseReason) error { @@ -431,11 +428,16 @@ func (g *ExecutionGroup) Close(reason CloseReason) error { func (g *ExecutionGroup) MemberTerminal(memberID string) error { g.mu.Lock() + if g.terminal[memberID] { + g.mu.Unlock() + return nil + } if !g.members[memberID] { g.mu.Unlock() return ErrUnknownIdentity } delete(g.members, memberID) + g.terminal[memberID] = true release := g.canReleaseLocked() g.mu.Unlock() if release { diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index 33938086ad5c4..f535bf43df98f 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -94,6 +94,9 @@ func TestExecutionGroupReleasesOnlyAfterCloseAndAllMembersTerminal(t *testing.T) require.NoError(t, b.Commit()) require.NoError(t, group.MemberTerminal("a")) + require.NoError(t, group.MemberTerminal("a")) + _, err = group.BeginOpen("a") + require.ErrorIs(t, err, ErrDuplicate) require.NoError(t, group.Close(ReasonInputEOF)) require.Equal(t, int32(0), releases.Load()) require.NoError(t, group.MemberTerminal("b")) @@ -127,6 +130,17 @@ func TestExecutionGroupZeroMemberAndAbortedOpenRelease(t *testing.T) { require.NoError(t, err) require.NoError(t, group.Close(ReasonEmptyInput)) require.Equal(t, int32(2), releases.Load()) + + group, err = NewExecutionGroup("late", 1, 1, func() error { + releases.Add(1) + return nil + }) + require.NoError(t, err) + open, err = group.BeginOpen("late-member") + require.NoError(t, err) + require.NoError(t, group.Close(ReasonCancel)) + require.ErrorIs(t, open.Commit(), ErrGroupClosed) + require.ErrorIs(t, open.Commit(), ErrGroupClosed) } func TestTerminalLedgerRetainsTombstonesUntilExpiry(t *testing.T) { diff --git a/pkg/udf/pythonruntime/arrow.go b/pkg/udf/python/arrow.go similarity index 99% rename from pkg/udf/pythonruntime/arrow.go rename to pkg/udf/python/arrow.go index c65bb9aea92f1..65a66dec35d61 100644 --- a/pkg/udf/pythonruntime/arrow.go +++ b/pkg/udf/python/arrow.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package pythonruntime +package python import ( "bytes" diff --git a/pkg/udf/pythonruntime/arrow_test.go b/pkg/udf/python/arrow_test.go similarity index 99% rename from pkg/udf/pythonruntime/arrow_test.go rename to pkg/udf/python/arrow_test.go index 97ed943333f54..f4ed3027bd689 100644 --- a/pkg/udf/pythonruntime/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -3,7 +3,7 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. -package pythonruntime +package python import ( "testing" diff --git a/pkg/udf/pythonruntime/config.go b/pkg/udf/python/config.go similarity index 98% rename from pkg/udf/pythonruntime/config.go rename to pkg/udf/python/config.go index c6b6ae301d25b..4c4d191639fe0 100644 --- a/pkg/udf/pythonruntime/config.go +++ b/pkg/udf/python/config.go @@ -6,7 +6,7 @@ // // http://www.apache.org/licenses/LICENSE-2.0 -package pythonruntime +package python import ( "context" diff --git a/pkg/udf/pythonruntime/gateway.go b/pkg/udf/python/gateway.go similarity index 99% rename from pkg/udf/pythonruntime/gateway.go rename to pkg/udf/python/gateway.go index 6cbcd829a5535..00442d64eafed 100644 --- a/pkg/udf/pythonruntime/gateway.go +++ b/pkg/udf/python/gateway.go @@ -6,7 +6,7 @@ // // http://www.apache.org/licenses/LICENSE-2.0 -package pythonruntime +package python import ( "bytes" diff --git a/pkg/udf/pythonruntime/supervisor.go b/pkg/udf/python/supervisor.go similarity index 99% rename from pkg/udf/pythonruntime/supervisor.go rename to pkg/udf/python/supervisor.go index 90c171368a75a..901aa8bdc0526 100644 --- a/pkg/udf/pythonruntime/supervisor.go +++ b/pkg/udf/python/supervisor.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -package pythonruntime +package python import ( "errors" diff --git a/pkg/udf/pythonruntime/worker/requirements.txt b/pkg/udf/python/worker/requirements.txt similarity index 100% rename from pkg/udf/pythonruntime/worker/requirements.txt rename to pkg/udf/python/worker/requirements.txt diff --git a/pkg/udf/pythonruntime/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py similarity index 89% rename from pkg/udf/pythonruntime/worker/test_worker.py rename to pkg/udf/python/worker/test_worker.py index ef15c3643a7b0..af802a9ae7fff 100644 --- a/pkg/udf/pythonruntime/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -115,6 +115,18 @@ def test_terminal_admission_does_not_evict_live_tombstones(self): worker.MAX_TERMINAL_RECORDS = old_records worker.MAX_TERMINAL_BYTES = old_bytes + def test_active_fence_cannot_be_admitted_twice(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + key = (1, "statement", "group", 1, "invocation", 1) + server._admit(key) + with self.assertRaisesRegex(ValueError, "fence is active"): + server._admit(key) + with self.assertRaisesRegex(ValueError, "fencing tuple changed"): + worker._require_tuple( + {"account_id": 1, "statement_id": "other", "group_id": "group", "group_epoch": 1, "invocation_id": "invocation", "lease_epoch": 1}, + {"account_id": 1, "statement_id": "statement", "group_id": "group", "group_epoch": 1, "invocation_id": "invocation", "lease_epoch": 1}, + ) + if __name__ == "__main__": unittest.main() diff --git a/pkg/udf/pythonruntime/worker/worker.py b/pkg/udf/python/worker/worker.py similarity index 95% rename from pkg/udf/pythonruntime/worker/worker.py rename to pkg/udf/python/worker/worker.py index 1eb732105fab5..3a24237de18e3 100644 --- a/pkg/udf/pythonruntime/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -217,22 +217,43 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: def _tuple_key(value: Dict[str, Any]) -> tuple: - required = ("account_id", "statement_id", "group_id", "group_epoch", "invocation_id", "lease_epoch") - if any(not value.get(k) for k in required): + string_fields = ("statement_id", "group_id", "invocation_id") + numeric_fields = ("account_id", "group_epoch", "lease_epoch") + if not isinstance(value, dict) or any(not isinstance(value.get(k), str) or not value[k] for k in string_fields): raise ValueError("PROTOCOL: incomplete fencing tuple") - return tuple(value[k] for k in required) + if any( + isinstance(value.get(k), bool) + or not isinstance(value.get(k), int) + or value[k] <= 0 + or value[k] > (1 << 64) - 1 + for k in numeric_fields + ): + raise ValueError("PROTOCOL: incomplete fencing tuple") + return ( + value["account_id"], + value["statement_id"], + value["group_id"], + value["group_epoch"], + value["invocation_id"], + value["lease_epoch"], + ) def _decode_control(data: bytes) -> Dict[str, Any]: if not data or len(data) > MAX_CONTROL_BYTES: raise ValueError("PROTOCOL: invalid control size") value = json.loads(bytes(data).decode("utf-8")) - if value.get("version") != PROTOCOL_VERSION or not value.get("kind"): + if not isinstance(value, dict) or value.get("version") != PROTOCOL_VERSION or not isinstance(value.get("kind"), str) or not value["kind"]: raise ValueError("PROTOCOL: unsupported control") _tuple_key(value.get("tuple") or {}) return value +def _require_tuple(value: Dict[str, Any], expected: Dict[str, Any]) -> None: + if _tuple_key(value) != _tuple_key(expected): + raise ValueError("PROTOCOL: fencing tuple changed") + + def _encode_control(value: Dict[str, Any]) -> bytes: value = dict(value) value.setdefault("version", PROTOCOL_VERSION) @@ -586,6 +607,8 @@ def _admit(self, key: tuple) -> _InvocationState: size = self._entry_bytes(key) with self._lock: self._purge_terminal_locked(time.monotonic()) + if key in self._active: + raise ValueError("PROTOCOL: invocation fence is active") if key in self._terminal: raise ValueError("PROTOCOL: invocation fence is terminal") if len(self._active) + len(self._terminal) >= MAX_TERMINAL_RECORDS: @@ -606,6 +629,10 @@ def _remember_terminal_locked(self, key: tuple, state: _InvocationState) -> None def do_action(self, context, action): control = _decode_control(action.body) key = _tuple_key(control["tuple"]) + if action.type not in ("AcknowledgeResults", "AcknowledgeFinish"): + raise ValueError("PROTOCOL: unknown action") + if control["kind"] != action.type: + raise ValueError("PROTOCOL: action kind does not match action type") with self._lock: self._purge_terminal_locked(time.monotonic()) state = self._active.get(key) @@ -619,8 +646,6 @@ def do_action(self, context, action): state.ack_result(int(control.get("ack_sequence", 0))) elif action.type == "AcknowledgeFinish": state.ack_finish(str(control.get("finish_id", ""))) - else: - raise ValueError("PROTOCOL: unknown action") yield _encode_control({"kind": "Ack", "tuple": control["tuple"], "status": "OK", "ack_sequence": control.get("ack_sequence", 0)}) def do_exchange(self, context, descriptor, reader, writer): @@ -633,10 +658,14 @@ def do_exchange(self, context, descriptor, reader, writer): raise ValueError("PROTOCOL: exchange is missing the invocation descriptor") open_control = _decode_control(command) if open_control["kind"] != "OpenInvocation": raise ValueError("PROTOCOL: first message must open an invocation") + if not isinstance(open_control.get("payload"), (dict, str)): + raise ValueError("PROTOCOL: invocation payload must be an object") key = _tuple_key(open_control["tuple"]) payload = open_control.get("payload") or {} if isinstance(payload, str): payload = json.loads(payload) + if not isinstance(payload, dict): + raise ValueError("PROTOCOL: invocation payload must be an object") args = list(payload.get("args", [])); result_descriptor = payload["return"] statement_context = _statement_context(payload.get("context")) mode = payload.get("mode", MODE_SCALAR); null_policy = payload.get("null_policy", NULL_CALL) @@ -667,6 +696,7 @@ def do_exchange(self, context, descriptor, reader, writer): schema = reader.schema _validate_schema(schema, args) control = _decode_control(chunk.app_metadata) + _require_tuple(control["tuple"], open_control["tuple"]) if control["kind"] != "InputBatch": raise ValueError("PROTOCOL: data batch is missing InputBatch") sequence = int(control.get("sequence", 0)) if sequence != state.last_result + 1: raise ValueError("PROTOCOL: input sequence is not contiguous") @@ -701,6 +731,7 @@ def do_exchange(self, context, descriptor, reader, writer): state.wait_result_ack(sequence) elif chunk.app_metadata: control = _decode_control(chunk.app_metadata) + _require_tuple(control["tuple"], open_control["tuple"]) if control["kind"] == "EndInput": if ended or int(control.get("last_sequence", -1)) != state.last_result: raise ValueError("PROTOCOL: invalid EndInput") ended = True From 2f05365cba3dc726ceef9d6092169cc5acc464e1 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 16:59:27 +0800 Subject: [PATCH 004/241] fix(udf): close remaining Python worker contracts --- cmd/mo-service/config.go | 6 +- cmd/mo-service/main.go | 12 +- .../cn.toml | 0 .../launch.toml | 5 +- .../python-udf-worker.toml} | 2 +- .../cn.toml | 0 .../launch.toml | 4 +- .../python-udf-worker.toml} | 2 +- .../{pythonserver => pythonworker}/Dockerfile | 4 +- pkg/embed/config.go | 4 +- pkg/frontend/clone_database_source.go | 7 +- pkg/sql/plan/function/python_udf.go | 47 +++--- pkg/udf/protocol/protocol.go | 10 +- pkg/udf/protocol/protocol_test.go | 31 ++++ pkg/udf/python/arrow.go | 103 +++++++++++- pkg/udf/python/arrow_test.go | 17 ++ pkg/udf/python/config.go | 12 +- pkg/udf/python/gateway.go | 99 ++++++------ pkg/udf/python/gateway_test.go | 60 +++++++ pkg/udf/python/supervisor.go | 9 +- pkg/udf/python/worker/test_worker.py | 25 ++- pkg/udf/python/worker/worker.py | 150 ++++++++++++++---- 22 files changed, 464 insertions(+), 145 deletions(-) rename etc/{launch-with-python-udf-server => launch-with-python-udf-worker}/cn.toml (100%) rename etc/{launch-with-python-udf-server => launch-with-python-udf-worker}/launch.toml (54%) rename etc/{launch-with-python-udf-server/python-udf-server.toml => launch-with-python-udf-worker/python-udf-worker.toml} (87%) rename etc/v1/{launch-with-python-udf-server => launch-with-python-udf-worker}/cn.toml (100%) rename etc/v1/{launch-with-python-udf-server => launch-with-python-udf-worker}/launch.toml (55%) rename etc/v1/{launch-with-python-udf-server/python-udf-server.toml => launch-with-python-udf-worker/python-udf-worker.toml} (87%) rename optools/images/{pythonserver => pythonworker}/Dockerfile (77%) create mode 100644 pkg/udf/python/gateway_test.go diff --git a/cmd/mo-service/config.go b/cmd/mo-service/config.go index 1314bb73218e7..548433db15719 100644 --- a/cmd/mo-service/config.go +++ b/cmd/mo-service/config.go @@ -118,8 +118,8 @@ type Config struct { CN cnservice.Config `toml:"cn"` // ProxyConfig is the config of proxy. ProxyConfig proxy.Config `toml:"proxy"` - // PythonUdfServerConfig is the config of python udf server - PythonUdfServerConfig python.Config `toml:"python-udf-server"` + // PythonUdfWorkerConfig is the config of the Python UDF worker. + PythonUdfWorkerConfig python.Config `toml:"python-udf-worker"` // Observability parameters for the metric/trace Observability config.ObservabilityParameters `toml:"observability"` @@ -594,7 +594,7 @@ func (c *Config) mustGetServiceUUID() string { case metadata.ServiceType_PROXY: return c.ProxyConfig.UUID case metadata.ServiceType_PYTHON_UDF: - return c.PythonUdfServerConfig.UUID + return c.PythonUdfWorkerConfig.UUID } panic("impossible") } diff --git a/cmd/mo-service/main.go b/cmd/mo-service/main.go index f0a4497bf209d..65ad565a9af6a 100644 --- a/cmd/mo-service/main.go +++ b/cmd/mo-service/main.go @@ -294,7 +294,7 @@ func startService( case metadata.ServiceType_LOG: return startLogService(cfg, stopper, fs, shutdownC) case metadata.ServiceType_PYTHON_UDF: - return startPythonUdfService(cfg, stopper) + return startPythonUdfWorker(cfg, stopper) default: panic("unknown service type") } @@ -741,8 +741,8 @@ func waitProxyFileServiceRetry(ctx context.Context, delay time.Duration) error { } } -// startPythonUdfService starts the python udf service. -func startPythonUdfService(cfg *Config, stopper *stopper.Stopper) error { +// startPythonUdfWorker starts the Python UDF worker. +func startPythonUdfWorker(cfg *Config, stopper *stopper.Stopper) error { if err := waitClusterCondition(cfg.mustGetServiceUUID(), cfg.HAKeeperClient, waitHAKeeperRunning); err != nil { return err } @@ -755,12 +755,12 @@ func startPythonUdfService(cfg *Config, stopper *stopper.Stopper) error { finish(err) }) } - err := stopper.RunNamedTask("python-udf-service", func(ctx context.Context) { + err := stopper.RunNamedTask("python-udf-worker", func(ctx context.Context) { var closeErr error defer func() { finishTask(closeErr) }() roleCtx, cancelRole := serviceLifecycle.roleContext(ctx, serviceRolePython) defer cancelRole() - s, err := python.NewSupervisor(cfg.PythonUdfServerConfig) + s, err := python.NewSupervisor(cfg.PythonUdfWorkerConfig) if err != nil { panic(err) } @@ -770,7 +770,7 @@ func startPythonUdfService(cfg *Config, stopper *stopper.Stopper) error { <-roleCtx.Done() if err := s.Close(); err != nil { closeErr = err - logutil.GetGlobalLogger().Error("failed to close python udf service", zap.Error(err)) + logutil.GetGlobalLogger().Error("failed to close Python UDF worker", zap.Error(err)) } }) if err != nil { diff --git a/etc/launch-with-python-udf-server/cn.toml b/etc/launch-with-python-udf-worker/cn.toml similarity index 100% rename from etc/launch-with-python-udf-server/cn.toml rename to etc/launch-with-python-udf-worker/cn.toml diff --git a/etc/launch-with-python-udf-server/launch.toml b/etc/launch-with-python-udf-worker/launch.toml similarity index 54% rename from etc/launch-with-python-udf-server/launch.toml rename to etc/launch-with-python-udf-worker/launch.toml index 1b75cdaf1d3b1..610a771783707 100644 --- a/etc/launch-with-python-udf-server/launch.toml +++ b/etc/launch-with-python-udf-worker/launch.toml @@ -7,10 +7,9 @@ tnservices = [ ] cnservices = [ - "./etc/launch-with-python-udf-server/cn.toml" + "./etc/launch-with-python-udf-worker/cn.toml" ] python-udf-services = [ - "./etc/launch-with-python-udf-server/python-udf-server.toml" + "./etc/launch-with-python-udf-worker/python-udf-worker.toml" ] - diff --git a/etc/launch-with-python-udf-server/python-udf-server.toml b/etc/launch-with-python-udf-worker/python-udf-worker.toml similarity index 87% rename from etc/launch-with-python-udf-server/python-udf-server.toml rename to etc/launch-with-python-udf-worker/python-udf-worker.toml index 37efe868191bc..40a0d22bb0ade 100644 --- a/etc/launch-with-python-udf-server/python-udf-server.toml +++ b/etc/launch-with-python-udf-worker/python-udf-worker.toml @@ -1,6 +1,6 @@ service-type = "PYTHON_UDF" -[python-udf-server] +[python-udf-worker] uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41b2" address = "127.0.0.1:50051" path = "pkg/udf/python/worker" diff --git a/etc/v1/launch-with-python-udf-server/cn.toml b/etc/v1/launch-with-python-udf-worker/cn.toml similarity index 100% rename from etc/v1/launch-with-python-udf-server/cn.toml rename to etc/v1/launch-with-python-udf-worker/cn.toml diff --git a/etc/v1/launch-with-python-udf-server/launch.toml b/etc/v1/launch-with-python-udf-worker/launch.toml similarity index 55% rename from etc/v1/launch-with-python-udf-server/launch.toml rename to etc/v1/launch-with-python-udf-worker/launch.toml index 64d2458f05442..8171c1ead1cd7 100644 --- a/etc/v1/launch-with-python-udf-server/launch.toml +++ b/etc/v1/launch-with-python-udf-worker/launch.toml @@ -7,9 +7,9 @@ tnservices = [ ] cnservices = [ - "./etc/v1/launch-with-python-udf-server/cn.toml" + "./etc/v1/launch-with-python-udf-worker/cn.toml" ] python-udf-services = [ - "./etc/v1/launch-with-python-udf-server/python-udf-server.toml" + "./etc/v1/launch-with-python-udf-worker/python-udf-worker.toml" ] diff --git a/etc/v1/launch-with-python-udf-server/python-udf-server.toml b/etc/v1/launch-with-python-udf-worker/python-udf-worker.toml similarity index 87% rename from etc/v1/launch-with-python-udf-server/python-udf-server.toml rename to etc/v1/launch-with-python-udf-worker/python-udf-worker.toml index 37efe868191bc..40a0d22bb0ade 100644 --- a/etc/v1/launch-with-python-udf-server/python-udf-server.toml +++ b/etc/v1/launch-with-python-udf-worker/python-udf-worker.toml @@ -1,6 +1,6 @@ service-type = "PYTHON_UDF" -[python-udf-server] +[python-udf-worker] uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41b2" address = "127.0.0.1:50051" path = "pkg/udf/python/worker" diff --git a/optools/images/pythonserver/Dockerfile b/optools/images/pythonworker/Dockerfile similarity index 77% rename from optools/images/pythonserver/Dockerfile rename to optools/images/pythonworker/Dockerfile index 88022f7fafd1f..d273cfd41d450 100644 --- a/optools/images/pythonserver/Dockerfile +++ b/optools/images/pythonworker/Dockerfile @@ -1,6 +1,6 @@ # run from root path for debug: -# docker build -t mo-python-udf-runtime -f ./optools/images/pythonserver/Dockerfile ./pkg/udf/python/worker/ -# docker run -d --network host mo-python-udf-runtime +# docker build -t mo-python-udf-worker -f ./optools/images/pythonworker/Dockerfile ./pkg/udf/python/worker/ +# docker run -d --network host mo-python-udf-worker FROM python:3.12-bookworm diff --git a/pkg/embed/config.go b/pkg/embed/config.go index 1007a9f0a9ad6..7df08b1c281a3 100644 --- a/pkg/embed/config.go +++ b/pkg/embed/config.go @@ -94,8 +94,8 @@ type ServiceConfig struct { CN cnservice.Config `toml:"cn"` // ProxyConfig is the config of proxy. ProxyConfig proxy.Config `toml:"proxy"` - // PythonUdfServerConfig is the config of python udf server - PythonUdfServerConfig python.Config `toml:"python-udf-server"` + // PythonUdfWorkerConfig is the config of the Python UDF worker. + PythonUdfWorkerConfig python.Config `toml:"python-udf-worker"` // Observability parameters for the metric/trace Observability config.ObservabilityParameters `toml:"observability"` diff --git a/pkg/frontend/clone_database_source.go b/pkg/frontend/clone_database_source.go index 021cb35623e2a..3bbbdfe570016 100644 --- a/pkg/frontend/clone_database_source.go +++ b/pkg/frontend/clone_database_source.go @@ -711,8 +711,11 @@ func validateCloneUserDefinedFunctions(functions []userDefinedFunctionDefinition if strings.EqualFold(definition.lang, string(tree.PYTHON)) { var body function.PythonRoutineBody if err := json.Unmarshal([]byte(definition.body), &body); err != nil || - body.Handler == "" || (body.Source == "" && body.ArtifactDigest == "") || - body.ABIContract != udf.PythonABIContract || body.AdapterVersion != udf.PythonAdapterVersion { + body.Handler == "" || body.Source == "" || + (body.Mode != "SCALAR" && body.Mode != "VECTOR") || + (body.NullPolicy != udf.NullCallHandler && body.NullPolicy != udf.NullReturnNull) || + body.ABIContract != udf.PythonABIContract || body.AdapterVersion != udf.PythonAdapterVersion || + body.SDKVersion != udf.PythonSDKVersion { return moerr.NewNotSupportedNoCtxf( "CREATE DATABASE CLONE with incomplete %s function %s is not supported", definition.lang, diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index 3e45aafe8c590..e4cdcd9ee0ab2 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -77,40 +77,49 @@ func pythonUdfRetType(parameters []types.Type) types.Type { // the generic builtin STRICT bit. func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int, selectList *FunctionSelectList) error { if len(parameters) == 0 || parameters[0] == nil { - return fmt.Errorf("python runtime: missing routine descriptor") + return fmt.Errorf("python udf: missing routine descriptor") } if length < 0 { - return fmt.Errorf("python runtime: negative input length %d", length) + return fmt.Errorf("python udf: negative input length %d", length) } routine := &UdfWithContext{} encoded, isNull := vector.GenerateFunctionStrParameter(parameters[0]).GetStrValue(0) if isNull { - return fmt.Errorf("python runtime: routine descriptor is NULL") + return fmt.Errorf("python udf: routine descriptor is NULL") } if err := json.Unmarshal(encoded, routine); err != nil { - return fmt.Errorf("python runtime: decode routine descriptor: %w", err) + return fmt.Errorf("python udf: decode routine descriptor: %w", err) } if routine.Udf == nil { - return fmt.Errorf("python runtime: routine descriptor has no function") + return fmt.Errorf("python udf: routine descriptor has no function") } body := PythonRoutineBody{} if err := json.Unmarshal([]byte(routine.Body), &body); err != nil { - return fmt.Errorf("python runtime: decode Python routine body: %w", err) + return fmt.Errorf("python udf: decode Python routine body: %w", err) } if body.Handler == "" || body.Source == "" { - return fmt.Errorf("python runtime: routine handler and source are required") + return fmt.Errorf("python udf: routine handler and source are required") + } + if body.Mode != "SCALAR" && body.Mode != "VECTOR" { + return fmt.Errorf("python udf: unsupported mode %q", body.Mode) + } + if body.NullPolicy != udf.NullCallHandler && body.NullPolicy != udf.NullReturnNull { + return fmt.Errorf("python udf: unsupported NULL policy %q", body.NullPolicy) } if body.ABIContract != udf.PythonABIContract || body.AdapterVersion != udf.PythonAdapterVersion { - return fmt.Errorf("python runtime: unsupported Python ABI contract %q/%q", body.ABIContract, body.AdapterVersion) + return fmt.Errorf("python udf: unsupported Python ABI contract %q/%q", body.ABIContract, body.AdapterVersion) + } + if body.SDKVersion != udf.PythonSDKVersion { + return fmt.Errorf("python udf: unsupported Python SDK %q", body.SDKVersion) } argTypes, err := routineArgumentTypes(routine) if err != nil { return err } if len(parameters)-1 != len(argTypes) { - return fmt.Errorf("python runtime: routine has %d arguments, received %d", len(argTypes), len(parameters)-1) + return fmt.Errorf("python udf: routine has %d arguments, received %d", len(argTypes), len(parameters)-1) } if length == 0 { @@ -118,11 +127,11 @@ func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapp } for index, input := range parameters[1:] { if input == nil || (!input.IsConst() && input.Length() < length) { - return fmt.Errorf("python runtime: input vector %d is shorter than invocation length", index) + return fmt.Errorf("python udf: input vector %d is shorter than invocation length", index) } } if selectList != nil && len(selectList.SelectList) < length { - return fmt.Errorf("python runtime: selection list is shorter than invocation length") + return fmt.Errorf("python udf: selection list is shorter than invocation length") } selected := make([]int64, 0, length) @@ -150,13 +159,13 @@ func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapp compacted = make([]*vector.Vector, len(inputs)) for i, input := range inputs { if input == nil { - return fmt.Errorf("python runtime: input vector %d is nil", i) + return fmt.Errorf("python udf: input vector %d is nil", i) } compacted[i] = vector.NewOffHeapVecWithType(*input.GetType()) compacted[i].SetIsBin(input.GetIsBin()) if err := compacted[i].Union(input, selected, proc.Mp()); err != nil { freeVectors(compacted, proc.Mp()) - return fmt.Errorf("python runtime: compact input %d: %w", i, err) + return fmt.Errorf("python udf: compact input %d: %w", i, err) } } inputs = compacted @@ -173,7 +182,7 @@ func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapp accountID, err := defines.GetAccountId(proc.Ctx) if err != nil { - return fmt.Errorf("python runtime: resolve account: %w", err) + return fmt.Errorf("python udf: resolve account: %w", err) } tuple, err := invocationTuple(routine.Context, proc.QueryId(), accountID) if err != nil { @@ -241,11 +250,11 @@ func routineArgumentTypes(routine *UdfWithContext) ([]types.Type, error) { args := make([]types.Type, len(routine.Args)) for i, arg := range routine.Args { if arg == nil { - return nil, fmt.Errorf("python runtime: routine argument %d is nil", i) + return nil, fmt.Errorf("python udf: routine argument %d is nil", i) } typ, ok := types.Types[arg.Type] if !ok { - return nil, fmt.Errorf("python runtime: unknown routine argument type %q", arg.Type) + return nil, fmt.Errorf("python udf: unknown routine argument type %q", arg.Type) } args[i] = typ.ToType() } @@ -279,7 +288,7 @@ func invocationTuple(context map[string]string, queryID string, accountID uint32 if statementID == "" { id, err := uuid.NewV7() if err != nil { - return protocol.FencingTuple{}, fmt.Errorf("python runtime: create statement fence: %w", err) + return protocol.FencingTuple{}, fmt.Errorf("python udf: create statement fence: %w", err) } statementID = id.String() } @@ -289,7 +298,7 @@ func invocationTuple(context map[string]string, queryID string, accountID uint32 } invocationID, err := uuid.NewV7() if err != nil { - return protocol.FencingTuple{}, fmt.Errorf("python runtime: create invocation fence: %w", err) + return protocol.FencingTuple{}, fmt.Errorf("python udf: create invocation fence: %w", err) } groupEpoch, err := positiveContextUint(context, "group_epoch", 1) if err != nil { @@ -316,7 +325,7 @@ func positiveContextUint(context map[string]string, key string, fallback uint64) } parsed, err := strconv.ParseUint(value, 10, 64) if err != nil || parsed == 0 { - return 0, fmt.Errorf("python runtime: invalid %s %q", key, value) + return 0, fmt.Errorf("python udf: invalid %s %q", key, value) } return parsed, nil } diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index ea7a61941cb00..b2a9403d32b39 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -237,7 +237,11 @@ func (s *OutputSnapshot) Validate(expectedLength int, expectedDigest string) err if expectedLength >= 0 && len(s.backing) != expectedLength { return fmt.Errorf("%w: output snapshot length %d, expected %d", ErrProtocol, len(s.backing), expectedLength) } - if expectedDigest != "" && !equalFoldHex(expectedDigest, s.Digest()) { + currentDigest := sha256.Sum256(s.backing) + if currentDigest != s.digest { + return fmt.Errorf("%w: output snapshot backing changed", ErrProtocol) + } + if expectedDigest != "" && !equalFoldHex(expectedDigest, hex.EncodeToString(currentDigest[:])) { return fmt.Errorf("%w: output snapshot digest changed", ErrProtocol) } return nil @@ -377,7 +381,9 @@ func (t *OpenToken) Commit() error { release := g.canReleaseLocked() g.mu.Unlock() if release { - _ = t.group.releaseIfReady() + if err := t.group.releaseIfReady(); err != nil { + t.result = errors.Join(t.result, err) + } } return } diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index f535bf43df98f..c1676b4351b1d 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -79,6 +79,13 @@ func TestOutputSnapshotFreezesBeforeWorkerCanRewrite(t *testing.T) { require.NoError(t, empty.Validate(0, empty.Digest())) } +func TestOutputSnapshotDetectsTrustedBackingMutation(t *testing.T) { + snapshot, err := FreezeOutput([]byte("trusted"), 1024) + require.NoError(t, err) + snapshot.TrustedBytes()[0] = 'X' + require.ErrorContains(t, snapshot.Validate(snapshot.Len(), snapshot.Digest()), "backing changed") +} + func TestExecutionGroupReleasesOnlyAfterCloseAndAllMembersTerminal(t *testing.T) { var releases atomic.Int32 group, err := NewExecutionGroup("g", 1, 2, func() error { @@ -189,3 +196,27 @@ func TestExecutionGroupReleaseErrorCanBeRetried(t *testing.T) { require.Equal(t, GroupReleased, group.State()) require.Equal(t, int32(2), attempts.Load()) } + +func TestExecutionGroupCommitReportsReleaseFailure(t *testing.T) { + var attempts atomic.Int32 + group, err := NewExecutionGroup("g", 1, 1, func() error { + if attempts.Add(1) == 1 { + return errors.New("temporary release failure") + } + return nil + }) + require.NoError(t, err) + open, err := group.BeginOpen("member") + require.NoError(t, err) + require.NoError(t, group.Close(ReasonCancel)) + + err = open.Commit() + require.ErrorIs(t, err, ErrGroupClosed) + require.ErrorContains(t, err, "temporary release failure") + require.ErrorIs(t, open.Commit(), ErrGroupClosed) + require.ErrorContains(t, open.Commit(), "temporary release failure") + require.Equal(t, GroupDraining, group.State()) + require.NoError(t, group.Close(ReasonCancel)) + require.Equal(t, GroupReleased, group.State()) + require.Equal(t, int32(2), attempts.Load()) +} diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 65a66dec35d61..df82f10317a0c 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -70,11 +70,11 @@ func NewTypeDescriptor(typ types.Type) (TypeDescriptor, error) { types.T_binary, types.T_varbinary, types.T_blob, types.T_array_float32, types.T_array_float64: default: - return TypeDescriptor{}, fmt.Errorf("python runtime does not support MatrixOne type %s", typ.String()) + return TypeDescriptor{}, fmt.Errorf("python udf does not support MatrixOne type %s", typ.String()) } if typ.Oid == types.T_array_float32 || typ.Oid == types.T_array_float64 { if typ.Width <= 0 { - return TypeDescriptor{}, fmt.Errorf("python runtime requires a positive vector dimension for %s", typ.String()) + return TypeDescriptor{}, fmt.Errorf("python udf requires a positive vector dimension for %s", typ.String()) } d.OffsetWidth = 0 } @@ -566,11 +566,14 @@ func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vect return nil } if mp == nil { - return fmt.Errorf("python runtime: missing memory pool for Arrow result") + return fmt.Errorf("python udf: missing memory pool for Arrow result") } if err := validateArrayType(descriptor, input); err != nil { return err } + if err := validateArrowValueDomain(descriptor, input); err != nil { + return err + } result.GetResultVector().SetTypeScale(descriptor.Scale) typ := types.T(descriptor.TypeID) for i := 0; i < input.Len(); i++ { @@ -724,6 +727,100 @@ func validateArrayType(descriptor TypeDescriptor, input arrow.Array) error { } return nil } + +func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) error { + if input == nil { + return fmt.Errorf("TYPE_CONTRACT: missing Arrow result") + } + for row := 0; row < input.Len(); row++ { + if input.IsNull(row) { + continue + } + switch types.T(descriptor.TypeID) { + case types.T_char, types.T_varchar, types.T_text: + if descriptor.Width > 0 && int32(len([]byte(input.(*array.String).Value(row)))) > descriptor.Width { + return fmt.Errorf("TYPE_CONTRACT: string row %d exceeds width %d", row, descriptor.Width) + } + case types.T_binary, types.T_varbinary, types.T_blob: + if descriptor.Width > 0 && int32(len(input.(*array.Binary).Value(row))) > descriptor.Width { + return fmt.Errorf("TYPE_CONTRACT: binary row %d exceeds width %d", row, descriptor.Width) + } + case types.T_time: + value := types.Time(input.(*array.Duration).Value(row)) + if !types.IsMySQLTime(value) || !hasExactMicrosecondScale(int64(value), descriptor.Scale) { + return fmt.Errorf("TYPE_CONTRACT: TIME row %d is outside the declared SQL domain", row) + } + case types.T_date, types.T_datetime, types.T_timestamp: + structValue := input.(*array.Struct) + zeroField, valueField := structValue.Field(0), structValue.Field(1) + if zeroField.IsNull(row) || valueField.IsNull(row) { + return fmt.Errorf("TYPE_CONTRACT: temporal row %d has a null child", row) + } + zero := zeroField.(*array.Boolean).Value(row) + switch types.T(descriptor.TypeID) { + case types.T_date: + value := valueField.(*array.Date32).Value(row) + if zero && value != 0 { + return fmt.Errorf("TYPE_CONTRACT: DATE zero row %d has a non-zero placeholder", row) + } + if !zero { + date := types.DaysFromUnixEpochToDate(int32(value)) + year, month, day, _ := date.Calendar(true) + if !types.ValidDate(year, month, day) { + return fmt.Errorf("TYPE_CONTRACT: DATE row %d is outside the SQL domain", row) + } + } + case types.T_datetime: + value := valueField.(*array.Timestamp).Value(row) + if zero && value != 0 { + return fmt.Errorf("TYPE_CONTRACT: DATETIME zero row %d has a non-zero placeholder", row) + } + if !zero { + absolute, ok := addUnixEpoch(int64(value)) + if !ok || !hasExactMicrosecondScale(absolute, descriptor.Scale) { + return fmt.Errorf("TYPE_CONTRACT: DATETIME row %d is outside the declared SQL domain", row) + } + datetime := types.Datetime(absolute) + year, month, day, _ := datetime.ToDate().Calendar(true) + if !types.ValidDatetime(year, month, day) { + return fmt.Errorf("TYPE_CONTRACT: DATETIME row %d is outside the SQL domain", row) + } + } + case types.T_timestamp: + value := valueField.(*array.Timestamp).Value(row) + if zero && value != 0 { + return fmt.Errorf("TYPE_CONTRACT: TIMESTAMP zero row %d has a non-zero placeholder", row) + } + if !zero { + absolute, ok := addUnixEpoch(int64(value)) + if !ok || absolute < int64(types.TimestampMinValue) || absolute > int64(types.TimestampMaxValue) || !hasExactMicrosecondScale(absolute, descriptor.Scale) { + return fmt.Errorf("TYPE_CONTRACT: TIMESTAMP row %d is outside the declared SQL domain", row) + } + } + } + } + } + return nil +} + +func addUnixEpoch(value int64) (int64, bool) { + epoch := types.GetUnixEpochSecs() + if value > math.MaxInt64-epoch || value < math.MinInt64+epoch { + return 0, false + } + return value + epoch, true +} + +func hasExactMicrosecondScale(value int64, scale int32) bool { + if scale < 0 || scale > 6 { + return false + } + quantum := int64(1) + for i := scale; i < 6; i++ { + quantum *= 10 + } + return value%quantum == 0 +} func decimalFromArray(value decimal128.Num, narrow bool) (any, error) { high, low := uint64(value.HighBits()), value.LowBits() if narrow && high != 0 && high != math.MaxUint64 { diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index f4ed3027bd689..3898dce4413f8 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -73,3 +73,20 @@ func TestZeroArgumentRecordPreservesRows(t *testing.T) { require.Equal(t, int64(3), decoded.NumRows()) require.Equal(t, int64(0), decoded.NumCols()) } + +func TestArrowValueDomainRejectsWidthAndTimeOverflow(t *testing.T) { + allocator := memory.NewGoAllocator() + stringBuilder := array.NewStringBuilder(allocator) + stringBuilder.Append("abcd") + strings := stringBuilder.NewStringArray() + defer strings.Release() + stringDescriptor := TypeDescriptor{TypeID: int32(types.T_varchar), Width: 3, OffsetWidth: 32} + require.ErrorContains(t, validateArrowValueDomain(stringDescriptor, strings), "exceeds width") + + timeBuilder := array.NewDurationBuilder(allocator, &arrow.DurationType{Unit: arrow.Microsecond}) + timeBuilder.Append(arrow.Duration(types.MySQLTimeMax + 1)) + times := timeBuilder.NewDurationArray() + defer times.Release() + timeDescriptor := TypeDescriptor{TypeID: int32(types.T_time), Scale: 6, OffsetWidth: 32} + require.ErrorContains(t, validateArrowValueDomain(timeDescriptor, times), "outside the declared SQL domain") +} diff --git a/pkg/udf/python/config.go b/pkg/udf/python/config.go index 4c4d191639fe0..937736bb8a958 100644 --- a/pkg/udf/python/config.go +++ b/pkg/udf/python/config.go @@ -24,10 +24,10 @@ type Config struct { func (c *Config) Validate() error { if c.Address == "" { - return moerr.NewInternalError(context.Background(), "missing python runtime address") + return moerr.NewInternalError(context.Background(), "missing python udf address") } if c.Path == "" { - return moerr.NewInternalError(context.Background(), "missing python runtime path") + return moerr.NewInternalError(context.Background(), "missing python udf path") } return nil } @@ -41,16 +41,16 @@ type ClientConfig struct { func (c *ClientConfig) Validate() error { if c.ServerAddress == "" { - return moerr.NewInternalError(context.Background(), "missing python runtime address") + return moerr.NewInternalError(context.Background(), "missing python udf address") } if c.MaxBatchBytes < 0 || c.MaxBatchBytes > 1<<30 { - return moerr.NewInternalError(context.Background(), "invalid python runtime max batch bytes") + return moerr.NewInternalError(context.Background(), "invalid python udf max batch bytes") } if c.MaxBatchRows < 0 || c.MaxBatchRows > 1<<30 { - return moerr.NewInternalError(context.Background(), "invalid python runtime max batch rows") + return moerr.NewInternalError(context.Background(), "invalid python udf max batch rows") } if c.RequestTimeout < 0 { - return moerr.NewInternalError(context.Background(), "invalid python runtime request timeout") + return moerr.NewInternalError(context.Background(), "invalid python udf request timeout") } return nil } diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 00442d64eafed..25860017e7ba3 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -121,7 +121,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul streamCtx, cancel := context.WithTimeout(ctx, g.cfg.RequestTimeout) defer cancel() if invocation == nil || result == nil || mp == nil { - return fmt.Errorf("python runtime: nil invocation, result, or memory pool") + return fmt.Errorf("python udf: nil invocation, result, or memory pool") } if err := validateInvocation(invocation); err != nil { return err @@ -147,7 +147,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul } openBody, err := json.Marshal(openPayload{Handler: invocation.Handler, Source: invocation.Source, Mode: invocation.Mode, NullPolicy: invocation.NullPolicy, ABIContract: invocation.ABIContract, AdapterVersion: invocation.AdapterVersion, SDKVersion: invocation.SDKVersion, Context: cloneMap(invocation.Context), Args: args, Return: returnDescriptor, MaxBatchBytes: g.cfg.MaxBatchBytes, MaxBatchRows: g.cfg.MaxBatchRows}) if err != nil { - return fmt.Errorf("python runtime: encode open payload: %w", err) + return fmt.Errorf("python udf: encode open payload: %w", err) } open, err := protocol.MarshalControl(protocol.Control{Kind: "OpenInvocation", Tuple: invocation.Tuple, Payload: openBody}) if err != nil { @@ -156,7 +156,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul stream, err := g.flight.DoExchange(streamCtx) if err != nil { - return fmt.Errorf("python runtime: open Arrow Flight exchange: %w", err) + return fmt.Errorf("python udf: open Arrow Flight exchange: %w", err) } // Flight carries the invocation command in the descriptor. The descriptor // is delivered to the server separately from the Arrow IPC reader; putting @@ -183,7 +183,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return err } if len(batch.Frames) != 2 { - return fmt.Errorf("python runtime: input batch contains %d Arrow frames", len(batch.Frames)) + return fmt.Errorf("python udf: input batch contains %d Arrow frames", len(batch.Frames)) } if batchIndex == 0 { inputSchema = append([]byte(nil), batch.Frames[0].Header...) @@ -191,7 +191,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return err } } else if !bytes.Equal(inputSchema, batch.Frames[0].Header) { - return fmt.Errorf("python runtime: input batches do not share one Arrow schema") + return fmt.Errorf("python udf: input batches do not share one Arrow schema") } sequenceNumber := batchIndex + 1 if err := sequence.AcceptInput(sequenceNumber); err != nil { @@ -237,7 +237,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul } } if !inputEnded || lastSequence != batchIndex { - return fmt.Errorf("python runtime: input stream did not reach EndInput") + return fmt.Errorf("python udf: input stream did not reach EndInput") } return g.receiveFinish(streamCtx, stream, invocation.Tuple, invocation.Length, rows, &sequence) } @@ -320,25 +320,25 @@ func (g *Gateway) receiveResultBatch( data, err := stream.Recv() if err != nil { if err == io.EOF { - return 0, fmt.Errorf("python runtime: exchange ended before result sequence %d", sequenceNumber) + return 0, fmt.Errorf("python udf: exchange ended before result sequence %d", sequenceNumber) } - return 0, fmt.Errorf("python runtime: receive result: %w", err) + return 0, fmt.Errorf("python udf: receive result: %w", err) } if data == nil || (len(data.AppMetadata) == 0 && len(data.DataHeader) == 0) { - return 0, fmt.Errorf("python runtime: empty Flight result") + return 0, fmt.Errorf("python udf: empty Flight result") } if len(data.DataHeader) > 0 { if *schemaFrame == nil { if len(data.DataBody) != 0 { - return 0, fmt.Errorf("python runtime: result schema contains a body") + return 0, fmt.Errorf("python udf: result schema contains a body") } - *schemaFrame = &ArrowFrame{Header: append([]byte(nil), data.DataHeader...)} if len(data.AppMetadata) > 0 { control, err := protocol.UnmarshalControl(data.AppMetadata) - if err != nil || control.Kind != "ResultSchema" { - return 0, fmt.Errorf("python runtime: invalid result schema metadata") + if err != nil || control.Tuple != tuple || control.Kind != "ResultSchema" { + return 0, fmt.Errorf("python udf: invalid result schema metadata") } } + *schemaFrame = &ArrowFrame{Header: append([]byte(nil), data.DataHeader...)} continue } control, err := protocol.UnmarshalControl(data.AppMetadata) @@ -346,7 +346,7 @@ func (g *Gateway) receiveResultBatch( return 0, err } if control.Tuple != tuple || control.Kind != "ResultBatch" || control.Sequence != sequenceNumber { - return 0, fmt.Errorf("python runtime: unexpected result sequence %d", control.Sequence) + return 0, fmt.Errorf("python udf: unexpected result sequence %d", control.Sequence) } if err := sequence.AcceptResult(control.Sequence); err != nil { return 0, err @@ -360,15 +360,15 @@ func (g *Gateway) receiveResultBatch( } decoded, err := DecodeRecordBatch(**schemaFrame, ArrowFrame{Header: append([]byte(nil), data.DataHeader...), Body: snapshot.TrustedBytes()}, g.cfg.MaxBatchBytes) if err != nil { - return 0, fmt.Errorf("python runtime: decode result: %w", err) + return 0, fmt.Errorf("python udf: decode result: %w", err) } if decoded.NumCols() != 1 || decoded.NumRows() <= 0 || decoded.NumRows() != expectedRows { decoded.Release() - return 0, fmt.Errorf("python runtime: result batch row count %d, expected %d", decoded.NumRows(), expectedRows) + return 0, fmt.Errorf("python udf: result batch row count %d, expected %d", decoded.NumRows(), expectedRows) } if decoded.Schema().Field(0).Name != "result" { decoded.Release() - return 0, fmt.Errorf("python runtime: result field has unexpected name %q", decoded.Schema().Field(0).Name) + return 0, fmt.Errorf("python udf: result field has unexpected name %q", decoded.Schema().Field(0).Name) } if err := returnDescriptor.ValidateField(decoded.Schema().Field(0)); err != nil { decoded.Release() @@ -392,22 +392,22 @@ func (g *Gateway) receiveResultBatch( return 0, err } if control.Tuple != tuple { - return 0, fmt.Errorf("python runtime: result tuple changed") + return 0, fmt.Errorf("python udf: result tuple changed") } switch control.Kind { case "ResultSchema": continue case "InputConsumed": if control.Sequence != sequenceNumber { - return 0, fmt.Errorf("python runtime: input sequence %d was consumed while waiting for result %d", control.Sequence, sequenceNumber) + return 0, fmt.Errorf("python udf: input sequence %d was consumed while waiting for result %d", control.Sequence, sequenceNumber) } continue case "Error": - return 0, fmt.Errorf("python runtime: worker error: %s", control.Reason) + return 0, fmt.Errorf("python udf: worker error: %s", control.Reason) case "Finish": - return 0, fmt.Errorf("python runtime: Finish arrived before result sequence %d", sequenceNumber) + return 0, fmt.Errorf("python udf: Finish arrived before result sequence %d", sequenceNumber) default: - return 0, fmt.Errorf("python runtime: unexpected control %q", control.Kind) + return 0, fmt.Errorf("python udf: unexpected control %q", control.Kind) } } } @@ -423,71 +423,59 @@ func (g *Gateway) receiveFinish( data, err := stream.Recv() if err != nil { if err == io.EOF { - return fmt.Errorf("python runtime: exchange ended before Finish") + return fmt.Errorf("python udf: exchange ended before Finish") } - return fmt.Errorf("python runtime: receive Finish: %w", err) + return fmt.Errorf("python udf: receive Finish: %w", err) } if data == nil || len(data.DataHeader) > 0 { - return fmt.Errorf("python runtime: unexpected Arrow data while finishing") + return fmt.Errorf("python udf: unexpected Arrow data while finishing") } control, err := protocol.UnmarshalControl(data.AppMetadata) if err != nil { return err } if control.Tuple != tuple { - return fmt.Errorf("python runtime: Finish tuple changed") + return fmt.Errorf("python udf: Finish tuple changed") } switch control.Kind { case "InputConsumed", "ResultSchema": continue case "Error": - return fmt.Errorf("python runtime: worker error: %s", control.Reason) + return fmt.Errorf("python udf: worker error: %s", control.Reason) case "Finish": lastInput, lastResult, acked, inputEnded := sequence.State() if control.Status != statusOK || control.FinishID == "" || rows != expectedRows || !inputEnded || control.LastSequence != lastInput || lastResult != lastInput || acked != lastInput || !sequence.ReadyToFinish() { - return fmt.Errorf("python runtime: invalid Finish status=%q rows=%d", control.Status, rows) + return fmt.Errorf("python udf: invalid Finish status=%q rows=%d", control.Status, rows) } return g.action(ctx, "AcknowledgeFinish", protocol.Control{Kind: "AcknowledgeFinish", Tuple: tuple, FinishID: control.FinishID}) default: - return fmt.Errorf("python runtime: unexpected control %q", control.Kind) + return fmt.Errorf("python udf: unexpected control %q", control.Kind) } } } func validateInvocation(invocation *udf.Invocation) error { if invocation.Language != "" && invocation.Language != udf.LanguagePython { - return fmt.Errorf("python runtime: unsupported language %q", invocation.Language) + return fmt.Errorf("python udf: unsupported language %q", invocation.Language) } if invocation.Handler == "" || invocation.Source == "" { - return fmt.Errorf("python runtime: handler and source are required") + return fmt.Errorf("python udf: handler and source are required") } if invocation.Length < 0 || len(invocation.Args) != len(invocation.Inputs) { - return fmt.Errorf("python runtime: invalid input shape") - } - if invocation.Mode == "" { - invocation.Mode = ModeScalar + return fmt.Errorf("python udf: invalid input shape") } if invocation.Mode != ModeScalar && invocation.Mode != ModeVector { - return fmt.Errorf("python runtime: unsupported mode %q", invocation.Mode) - } - if invocation.NullPolicy == "" { - invocation.NullPolicy = NullCallHandler + return fmt.Errorf("python udf: unsupported mode %q", invocation.Mode) } if invocation.NullPolicy != NullCallHandler && invocation.NullPolicy != NullReturnNull { - return fmt.Errorf("python runtime: unsupported NULL policy %q", invocation.NullPolicy) - } - if invocation.ABIContract == "" { - invocation.ABIContract = udf.PythonABIContract - } - if invocation.AdapterVersion == "" { - invocation.AdapterVersion = udf.PythonAdapterVersion - } - if invocation.SDKVersion == "" { - invocation.SDKVersion = udf.PythonSDKVersion + return fmt.Errorf("python udf: unsupported NULL policy %q", invocation.NullPolicy) } if invocation.ABIContract != udf.PythonABIContract || invocation.AdapterVersion != udf.PythonAdapterVersion { - return fmt.Errorf("python runtime: unsupported Python ABI contract %q/%q", invocation.ABIContract, invocation.AdapterVersion) + return fmt.Errorf("python udf: unsupported Python ABI contract %q/%q", invocation.ABIContract, invocation.AdapterVersion) + } + if invocation.SDKVersion != udf.PythonSDKVersion { + return fmt.Errorf("python udf: unsupported Python SDK %q", invocation.SDKVersion) } return invocation.Tuple.Validate() } @@ -501,25 +489,28 @@ func (g *Gateway) action(ctx context.Context, kind string, control protocol.Cont defer cancel() stream, err := g.flight.DoAction(actionCtx, &flight.Action{Type: kind, Body: body}) if err != nil { - return fmt.Errorf("python runtime: %s: %w", kind, err) + return fmt.Errorf("python udf: %s: %w", kind, err) } result, err := stream.Recv() if err != nil { return err } if result == nil { - return fmt.Errorf("python runtime: empty %s response", kind) + return fmt.Errorf("python udf: empty %s response", kind) } ack, err := protocol.UnmarshalControl(result.Body) if err != nil { return err } + if ack.Tuple != control.Tuple || ack.Kind != "Ack" { + return fmt.Errorf("python udf: %s returned an invalid ACK", kind) + } if ack.Status != statusOK { - return fmt.Errorf("python runtime: %s rejected: %s", kind, ack.Reason) + return fmt.Errorf("python udf: %s rejected: %s", kind, ack.Reason) } if _, err := stream.Recv(); err != io.EOF { if err == nil { - return fmt.Errorf("python runtime: %s returned multiple results", kind) + return fmt.Errorf("python udf: %s returned multiple results", kind) } return err } diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go new file mode 100644 index 0000000000000..341b84dc750fc --- /dev/null +++ b/pkg/udf/python/gateway_test.go @@ -0,0 +1,60 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package python + +import ( + "testing" + + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/matrixorigin/matrixone/pkg/udf/protocol" + "github.com/stretchr/testify/require" +) + +func validInvocation() *udf.Invocation { + return &udf.Invocation{ + Language: udf.LanguagePython, + Handler: "add", + Source: "def add(ctx, value): return value", + Args: []types.Type{types.T_int64.ToType()}, + ReturnType: types.T_int64.ToType(), + Length: 0, + Inputs: []*vector.Vector{nil}, + Mode: ModeScalar, + NullPolicy: NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + Tuple: protocol.FencingTuple{ + AccountID: 1, StatementID: "statement", GroupID: "group", + GroupEpoch: 1, InvocationID: "invocation", LeaseEpoch: 1, + }, + } +} + +func TestValidateInvocationRequiresFrozenContract(t *testing.T) { + base := validInvocation() + require.NoError(t, validateInvocation(base)) + + cases := []struct { + name string + mutate func(*udf.Invocation) + }{ + {name: "mode", mutate: func(invocation *udf.Invocation) { invocation.Mode = "" }}, + {name: "null policy", mutate: func(invocation *udf.Invocation) { invocation.NullPolicy = "" }}, + {name: "ABI", mutate: func(invocation *udf.Invocation) { invocation.ABIContract = "" }}, + {name: "adapter", mutate: func(invocation *udf.Invocation) { invocation.AdapterVersion = "" }}, + {name: "SDK", mutate: func(invocation *udf.Invocation) { invocation.SDKVersion = "" }}, + } + for _, test := range cases { + t.Run(test.name, func(t *testing.T) { + invocation := validInvocation() + test.mutate(invocation) + require.Error(t, validateInvocation(invocation)) + }) + } +} diff --git a/pkg/udf/python/supervisor.go b/pkg/udf/python/supervisor.go index 901aa8bdc0526..14674b2b376c2 100644 --- a/pkg/udf/python/supervisor.go +++ b/pkg/udf/python/supervisor.go @@ -13,7 +13,6 @@ import ( "os" "os/exec" "path/filepath" - "strconv" "sync" "sync/atomic" @@ -62,7 +61,7 @@ func (s *Supervisor) Start() error { if err != nil { return err } - logPath := filepath.Join(filepath.Dir(exePath), "python-runtime-"+strconv.Itoa(int(supervisorNumber.Add(1))+0)+".log") + logPath := filepath.Join(filepath.Dir(exePath), fmt.Sprintf("python-udf-worker-%d.log", supervisorNumber.Add(1))) logFile, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) if err != nil { return err @@ -75,7 +74,7 @@ func (s *Supervisor) Start() error { } s.cmd, s.log = cmd, logFile go s.wait(cmd, logFile) - logutil.Infof("started Python runtime worker: %s", cmd.String()) + logutil.Infof("started Python UDF worker: %s", cmd.String()) return nil } @@ -88,7 +87,7 @@ func (s *Supervisor) wait(cmd *exec.Cmd, log io.WriteCloser) { } s.mu.Unlock() if err != nil { - logutil.Errorf("Python runtime worker exited: %v", err) + logutil.Errorf("Python UDF worker exited: %v", err) } } @@ -104,7 +103,7 @@ func (s *Supervisor) Close() error { return nil } if err := cmd.Process.Kill(); err != nil && !errors.Is(err, os.ErrProcessDone) { - return fmt.Errorf("stop Python runtime worker: %w", err) + return fmt.Errorf("stop Python UDF worker: %w", err) } if log != nil { return log.Close() diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index af802a9ae7fff..752a1469e6f5a 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -2,6 +2,7 @@ import datetime import importlib.util +import json import pathlib import sys import unittest @@ -50,6 +51,14 @@ def test_zero_temporal_is_distinct_from_null(self): self.assertEqual(True, array.field("is_zero")[0].as_py()) self.assertEqual(datetime.date(1970, 1, 1), array.field("value")[0].as_py()) + def test_scalar_value_domain_is_checked_before_arrow_encoding(self): + string_descriptor = {"type_id": worker.VARCHAR, "width": 3, "offset_width": 32} + with self.assertRaisesRegex(ValueError, "string exceeds"): + worker._output_array(["abcd"], string_descriptor, 1) + time_descriptor = {"type_id": worker.TIME, "scale": 6, "offset_width": 32} + with self.assertRaisesRegex(ValueError, "TIME is outside"): + worker._output_array([datetime.timedelta(hours=839)], time_descriptor, 1) + def test_zero_argument_vector_uses_context_rows(self): descriptor = {"type_id": worker.INT64, "offset_width": 32} output = pa.array([7, 7, 7], type=pa.int64()) @@ -64,7 +73,7 @@ def test_statement_context_is_whitelisted_and_frozen(self): "statement_timestamp_utc": "1704067200123456", "session_timezone_kind": "FIXED_OFFSET", "session_timezone_offset_minutes": "+510", - "sql_mode": '["ANSI", "STRICT"]', + "sql_mode": '["ANSI","STRICT"]', "current_database": "app", "current_user": "alice", "current_role": "writer", @@ -127,6 +136,20 @@ def test_active_fence_cannot_be_admitted_twice(self): {"account_id": 1, "statement_id": "statement", "group_id": "group", "group_epoch": 1, "invocation_id": "invocation", "lease_epoch": 1}, ) + def test_control_numeric_fields_are_strict(self): + tuple_value = { + "account_id": 1, + "statement_id": "statement", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invocation", + "lease_epoch": 1, + } + with self.assertRaisesRegex(ValueError, "unsupported control"): + worker._decode_control(json.dumps({"version": True, "kind": "InputBatch", "tuple": tuple_value}).encode()) + with self.assertRaisesRegex(ValueError, "invalid control field sequence"): + worker._required_uint64({"sequence": "1"}, "sequence") + if __name__ == "__main__": unittest.main() diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 3a24237de18e3..3257a02d95240 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -36,7 +36,10 @@ MAX_TERMINAL_BYTES = 16 << 20 TERMINAL_TTL_SECONDS = 300.0 ACK_TIMEOUT_SECONDS = 60.0 -DEFAULT_MAX_BATCH_ROWS = 65536 +_MICROS_PER_SECOND = 1_000_000 +_MAX_TIME_MICROS = (838 * 60 * 60 + 59 * 60 + 59) * _MICROS_PER_SECOND +_MIN_TIMESTAMP = _datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=_datetime.timezone.utc) +_MAX_TIMESTAMP = _datetime.datetime(9999, 12, 31, 23, 59, 59, 999999, tzinfo=_datetime.timezone.utc) BOOL = 10 INT8, INT16, INT32, INT64 = 20, 21, 22, 23 @@ -57,7 +60,7 @@ ADAPTER_VERSION = "2026-09" SDK_VERSION = "1.0" -log = logging.getLogger("matrixone.python.runtime") +log = logging.getLogger("matrixone.python.udf.worker") @dataclass(frozen=True, slots=True) @@ -151,6 +154,15 @@ def _required_context_value(context: Dict[str, Any], key: str) -> str: return value +def _optional_context_value(context: Dict[str, Any], key: str) -> Optional[str]: + value = context.get(key) + if value is None: + return None + if not isinstance(value, str): + raise ValueError(f"PROTOCOL: statement context field {key} must be text") + return value or None + + def _statement_context(raw: Any) -> Optional[StatementContext]: if raw is None: return None @@ -175,7 +187,7 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: if timezone_kind == "IANA": timezone_name = _required_context_value(raw, "session_timezone_name") tzdb_version = _required_context_value(raw, "session_timezone_tzdb_version") - if raw.get("session_timezone_offset_minutes"): + if "session_timezone_offset_minutes" in raw: raise ValueError("PROTOCOL: IANA timezone cannot carry a fixed offset") timezone = TimezoneContext("IANA", name=timezone_name, tzdb_version=tzdb_version) elif timezone_kind == "FIXED_OFFSET": @@ -186,7 +198,7 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: raise ValueError("PROTOCOL: invalid fixed timezone offset") from exc if offset_minutes < -839 or offset_minutes > 840: raise ValueError("PROTOCOL: fixed timezone offset is outside SQL range") - if raw.get("session_timezone_name") or raw.get("session_timezone_tzdb_version"): + if "session_timezone_name" in raw or "session_timezone_tzdb_version" in raw: raise ValueError("PROTOCOL: fixed timezone cannot carry IANA identity") timezone = TimezoneContext("FIXED_OFFSET", offset_minutes=offset_minutes) else: @@ -200,7 +212,7 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: if not isinstance(sql_mode_value, list) or any(not isinstance(item, str) for item in sql_mode_value): raise ValueError("PROTOCOL: sql_mode must be an array of strings") sql_mode = tuple(sorted(set(sql_mode_value))) - if list(sql_mode) != sql_mode_value: + if list(sql_mode) != sql_mode_value or json.dumps(sql_mode_value, separators=(",", ":"), ensure_ascii=True) != sql_mode_text: raise ValueError("PROTOCOL: sql_mode is not canonical") current_user = _required_context_value(raw, "current_user") @@ -209,9 +221,9 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: statement_timestamp_utc=timestamp, session_timezone=timezone, sql_mode=sql_mode, - current_database=raw.get("current_database") or None, + current_database=_optional_context_value(raw, "current_database"), current_user=current_user, - current_role=raw.get("current_role") or None, + current_role=_optional_context_value(raw, "current_role"), connection_collation=connection_collation, ) @@ -243,7 +255,13 @@ def _decode_control(data: bytes) -> Dict[str, Any]: if not data or len(data) > MAX_CONTROL_BYTES: raise ValueError("PROTOCOL: invalid control size") value = json.loads(bytes(data).decode("utf-8")) - if not isinstance(value, dict) or value.get("version") != PROTOCOL_VERSION or not isinstance(value.get("kind"), str) or not value["kind"]: + if ( + not isinstance(value, dict) + or type(value.get("version")) is not int + or value["version"] != PROTOCOL_VERSION + or not isinstance(value.get("kind"), str) + or not value["kind"] + ): raise ValueError("PROTOCOL: unsupported control") _tuple_key(value.get("tuple") or {}) return value @@ -254,6 +272,28 @@ def _require_tuple(value: Dict[str, Any], expected: Dict[str, Any]) -> None: raise ValueError("PROTOCOL: fencing tuple changed") +def _required_string(value: Dict[str, Any], key: str) -> str: + item = value.get(key) + if not isinstance(item, str) or not item: + raise ValueError(f"PROTOCOL: missing invocation field {key}") + return item + + +def _required_positive_int(value: Dict[str, Any], key: str, maximum: int) -> int: + item = value.get(key) + if isinstance(item, bool) or not isinstance(item, int) or item <= 0 or item > maximum: + raise ValueError(f"PROTOCOL: invalid invocation field {key}") + return item + + +def _required_uint64(value: Dict[str, Any], key: str, allow_zero: bool = False) -> int: + item = value.get(key) + minimum = 0 if allow_zero else 1 + if isinstance(item, bool) or not isinstance(item, int) or item < minimum or item > (1 << 64) - 1: + raise ValueError(f"PROTOCOL: invalid control field {key}") + return item + + def _encode_control(value: Dict[str, Any]) -> bytes: value = dict(value) value.setdefault("version", PROTOCOL_VERSION) @@ -428,6 +468,19 @@ def _check_json(value: str) -> str: return value +def _check_microsecond_scale(value: int, descriptor: Dict[str, Any]) -> None: + scale = int(descriptor.get("scale") or 0) + if scale < 0 or scale > 6: + raise ValueError("TYPE_CONTRACT: temporal scale is outside the supported range") + quantum = 10 ** (6 - scale) + if value % quantum != 0: + raise ValueError("TYPE_CONTRACT: temporal value exceeds the declared scale") + + +def _timedelta_micros(value: _datetime.timedelta) -> int: + return (value.days * 24 * 60 * 60 + value.seconds) * _MICROS_PER_SECOND + value.microseconds + + def _check_scalar(value: Any, descriptor: Dict[str, Any]): if value is None: return None @@ -435,21 +488,37 @@ def _check_scalar(value: Any, descriptor: Dict[str, Any]): if type_id == BOOL and type(value) is not bool: raise ValueError("TYPE_CONTRACT: expected bool") if type_id in (INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64) and (type(value) is not int): raise ValueError("TYPE_CONTRACT: expected integer") if type_id in (FLOAT32, FLOAT64) and type(value) is not float: raise ValueError("TYPE_CONTRACT: expected float") - if type_id in (CHAR, VARCHAR, TEXT) and type(value) is not str: raise ValueError("TYPE_CONTRACT: expected string") + if type_id in (CHAR, VARCHAR, TEXT): + if type(value) is not str: raise ValueError("TYPE_CONTRACT: expected string") + width = int(descriptor.get("width") or 0) + if width > 0 and len(value.encode("utf-8")) > width: raise ValueError("TYPE_CONTRACT: string exceeds the declared width") + return value if type_id == JSON: return _check_json(value) - if type_id in (BINARY, VARBINARY, BLOB) and type(value) is not bytes: raise ValueError("TYPE_CONTRACT: expected bytes") + if type_id in (BINARY, VARBINARY, BLOB): + if type(value) is not bytes: raise ValueError("TYPE_CONTRACT: expected bytes") + width = int(descriptor.get("width") or 0) + if width > 0 and len(value) > width: raise ValueError("TYPE_CONTRACT: binary value exceeds the declared width") + return value if type_id == UUID: if not isinstance(value, _uuid.UUID): raise ValueError("TYPE_CONTRACT: expected uuid.UUID") return value.bytes - if type_id == TIME and not isinstance(value, _datetime.timedelta): raise ValueError("TYPE_CONTRACT: expected datetime.timedelta") + if type_id == TIME: + if not isinstance(value, _datetime.timedelta): raise ValueError("TYPE_CONTRACT: expected datetime.timedelta") + micros = _timedelta_micros(value) + if abs(micros) > _MAX_TIME_MICROS: raise ValueError("TYPE_CONTRACT: TIME is outside the SQL range") + _check_microsecond_scale(micros, descriptor) + return value if type_id == DATE: if not isinstance(value, SqlDate) or (value.is_zero and value.value is not None) or (not value.is_zero and type(value.value) is not _datetime.date): raise ValueError("TYPE_CONTRACT: invalid SqlDate") return value if type_id == DATETIME: if not isinstance(value, SqlDatetime) or (value.is_zero and value.value is not None) or (not value.is_zero and (not isinstance(value.value, _datetime.datetime) or value.value.tzinfo is not None)): raise ValueError("TYPE_CONTRACT: invalid SqlDatetime") + if not value.is_zero: _check_microsecond_scale(value.value.microsecond, descriptor) return value if type_id == TIMESTAMP: if not isinstance(value, SqlTimestamp) or (value.is_zero and value.value is not None) or (not value.is_zero and (not isinstance(value.value, _datetime.datetime) or value.value.tzinfo is None or value.value.utcoffset() != _datetime.timedelta(0))): raise ValueError("TYPE_CONTRACT: invalid SqlTimestamp") + if not value.is_zero and not (_MIN_TIMESTAMP <= value.value <= _MAX_TIMESTAMP): raise ValueError("TYPE_CONTRACT: TIMESTAMP is outside the SQL range") + if not value.is_zero: _check_microsecond_scale(value.value.microsecond, descriptor) if not value.is_zero and value.value.tzinfo is not _datetime.timezone.utc: return SqlTimestamp(False, value.value.astimezone(_datetime.timezone.utc)) return value @@ -526,10 +595,7 @@ def _output_array(values: Any, descriptor: Dict[str, Any], rows: int) -> pa.Arra def _validate_array_values(array: pa.Array, descriptor: Dict[str, Any]) -> None: type_id = int(descriptor["type_id"]) - if type_id == JSON: - for index in range(len(array)): - if not array.is_null(index): _check_json(array[index].as_py()) - elif type_id in (DATE, DATETIME, TIMESTAMP): + if type_id in (DATE, DATETIME, TIMESTAMP): struct = array for index in range(len(struct)): if struct.is_null(index): continue @@ -538,6 +604,18 @@ def _validate_array_values(array: pa.Array, descriptor: Dict[str, Any]) -> None: if value is None: raise ValueError("TYPE_CONTRACT: temporal child is null") if is_zero and ((type_id == DATE and value != _datetime.date(1970, 1, 1)) or (type_id == DATETIME and value != _datetime.datetime(1970, 1, 1)) or (type_id == TIMESTAMP and value != _datetime.datetime(1970, 1, 1, tzinfo=_datetime.timezone.utc))): raise ValueError("TYPE_CONTRACT: temporal zero placeholder is invalid") + if not is_zero: + if type_id == DATE: _check_scalar(SqlDate(False, value), descriptor) + elif type_id == DATETIME: _check_scalar(SqlDatetime(False, value), descriptor) + else: _check_scalar(SqlTimestamp(False, value), descriptor) + elif type_id in (CHAR, VARCHAR, TEXT, JSON, BINARY, VARBINARY, BLOB, UUID, TIME, DECIMAL64, DECIMAL128): + for index in range(len(array)): + if array.is_null(index): continue + value = array[index].as_py() + if type_id == UUID: + if not isinstance(value, (bytes, bytearray)) or len(value) != 16: raise ValueError("TYPE_CONTRACT: UUID must contain 16 bytes") + else: + _check_scalar(value, descriptor) class _InvocationState: @@ -643,9 +721,9 @@ def do_action(self, context, action): return raise ValueError("PROTOCOL: unknown invocation") if action.type == "AcknowledgeResults": - state.ack_result(int(control.get("ack_sequence", 0))) + state.ack_result(_required_uint64(control, "ack_sequence")) elif action.type == "AcknowledgeFinish": - state.ack_finish(str(control.get("finish_id", ""))) + state.ack_finish(_required_string(control, "finish_id")) yield _encode_control({"kind": "Ack", "tuple": control["tuple"], "status": "OK", "ack_sequence": control.get("ack_sequence", 0)}) def do_exchange(self, context, descriptor, reader, writer): @@ -658,27 +736,30 @@ def do_exchange(self, context, descriptor, reader, writer): raise ValueError("PROTOCOL: exchange is missing the invocation descriptor") open_control = _decode_control(command) if open_control["kind"] != "OpenInvocation": raise ValueError("PROTOCOL: first message must open an invocation") - if not isinstance(open_control.get("payload"), (dict, str)): + if not isinstance(open_control.get("payload"), dict): raise ValueError("PROTOCOL: invocation payload must be an object") key = _tuple_key(open_control["tuple"]) - payload = open_control.get("payload") or {} - if isinstance(payload, str): - payload = json.loads(payload) - if not isinstance(payload, dict): - raise ValueError("PROTOCOL: invocation payload must be an object") - args = list(payload.get("args", [])); result_descriptor = payload["return"] + payload = open_control["payload"] + args = payload.get("args") + result_descriptor = payload.get("return") + if not isinstance(args, list) or any(not isinstance(item, dict) for item in args): + raise ValueError("PROTOCOL: invocation args must be an array of descriptors") + if not isinstance(result_descriptor, dict): + raise ValueError("PROTOCOL: invocation return must be a descriptor") statement_context = _statement_context(payload.get("context")) - mode = payload.get("mode", MODE_SCALAR); null_policy = payload.get("null_policy", NULL_CALL) - abi_contract = payload.get("abi_contract", ABI_CONTRACT) - adapter_version = payload.get("adapter_version", ADAPTER_VERSION) - sdk_version = payload.get("sdk_version", SDK_VERSION) - max_batch_rows = int(payload.get("max_batch_rows", DEFAULT_MAX_BATCH_ROWS)) + mode = _required_string(payload, "mode") + null_policy = _required_string(payload, "null_policy") + abi_contract = _required_string(payload, "abi_contract") + adapter_version = _required_string(payload, "adapter_version") + sdk_version = _required_string(payload, "sdk_version") + max_batch_bytes = _required_positive_int(payload, "max_batch_bytes", 1 << 30) + max_batch_rows = _required_positive_int(payload, "max_batch_rows", 1 << 30) if mode not in (MODE_SCALAR, MODE_VECTOR) or null_policy not in (NULL_CALL, NULL_RETURN): raise ValueError("PROTOCOL: unsupported call mode or NULL policy") if abi_contract != ABI_CONTRACT or adapter_version != ADAPTER_VERSION: raise ValueError("PROTOCOL: unsupported Python ABI contract") - if max_batch_rows <= 0: raise ValueError("PROTOCOL: invalid max batch rows") + if sdk_version != SDK_VERSION: raise ValueError("PROTOCOL: unsupported Python SDK") state = self._admit(key) state.tuple = open_control["tuple"] - handler = _load_handler(payload["source"], payload["handler"]) + handler = _load_handler(_required_string(payload, "source"), _required_string(payload, "handler")) schema = None result_field = _field("result", result_descriptor) result_schema = pa.schema([result_field]) @@ -698,11 +779,12 @@ def do_exchange(self, context, descriptor, reader, writer): control = _decode_control(chunk.app_metadata) _require_tuple(control["tuple"], open_control["tuple"]) if control["kind"] != "InputBatch": raise ValueError("PROTOCOL: data batch is missing InputBatch") - sequence = int(control.get("sequence", 0)) + sequence = _required_uint64(control, "sequence") if sequence != state.last_result + 1: raise ValueError("PROTOCOL: input sequence is not contiguous") batch = chunk.data if batch.num_rows <= 0: raise ValueError("PROTOCOL: empty input batch") if batch.num_rows > max_batch_rows: raise ValueError("RESOURCE_EXHAUSTED: input batch has too many rows") + if batch.nbytes > max_batch_bytes: raise ValueError("RESOURCE_EXHAUSTED: input batch exceeds byte limit") if mode == MODE_VECTOR: call_context = VectorContext(sdk_version, _CallLogger(), statement_context, batch.num_rows) try: @@ -725,6 +807,8 @@ def do_exchange(self, context, descriptor, reader, writer): output = values output_array = _output_array(output, result_descriptor, batch.num_rows) output_batch = pa.RecordBatch.from_arrays([output_array], schema=result_schema) + if pa.ipc.get_record_batch_size(output_batch) > max_batch_bytes: + raise ValueError("RESOURCE_EXHAUSTED: output batch exceeds byte limit") state.last_result = sequence writer.write_metadata(_encode_control({"kind": "InputConsumed", "tuple": open_control["tuple"], "sequence": sequence})) writer.write_with_metadata(output_batch, _encode_control({"kind": "ResultBatch", "tuple": open_control["tuple"], "sequence": sequence})) @@ -733,7 +817,7 @@ def do_exchange(self, context, descriptor, reader, writer): control = _decode_control(chunk.app_metadata) _require_tuple(control["tuple"], open_control["tuple"]) if control["kind"] == "EndInput": - if ended or int(control.get("last_sequence", -1)) != state.last_result: raise ValueError("PROTOCOL: invalid EndInput") + if ended or _required_uint64(control, "last_sequence", allow_zero=True) != state.last_result: raise ValueError("PROTOCOL: invalid EndInput") ended = True elif control["kind"] != "OpenInvocation": raise ValueError("PROTOCOL: unexpected control without Arrow data") From ee175c0a1a929161a39dee629a7807c7143a58d0 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 17:35:15 +0800 Subject: [PATCH 005/241] fix(udf): align SQL selection and system account fences --- pkg/sql/plan/function/python_udf.go | 7 ++++++- pkg/udf/protocol/protocol.go | 5 ++++- pkg/udf/protocol/protocol_test.go | 8 ++++++++ pkg/udf/python/worker/test_worker.py | 6 +++++- pkg/udf/python/worker/worker.py | 11 +++++++++-- 5 files changed, 32 insertions(+), 5 deletions(-) diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index e4cdcd9ee0ab2..c63a872febb43 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -130,7 +130,12 @@ func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapp return fmt.Errorf("python udf: input vector %d is shorter than invocation length", index) } } - if selectList != nil && len(selectList.SelectList) < length { + // FunctionExpressionExecutor passes an empty, non-nil select list when the + // caller selected every row. In that state AnyNull is false and the + // missing bitmap means "all rows", not a truncated selection. A partial + // selection must still carry one entry per invocation row so that a row + // cannot accidentally be evaluated after CASE/short-circuit filtering. + if selectList != nil && !selectList.ShouldEvalAllRow() && len(selectList.SelectList) < length { return fmt.Errorf("python udf: selection list is shorter than invocation length") } diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index b2a9403d32b39..419e1fb31acd3 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -59,7 +59,10 @@ type FencingTuple struct { } func (t FencingTuple) Validate() error { - if t.AccountID == 0 || t.StatementID == "" || t.GroupID == "" || + // Account zero is the reserved system account in MatrixOne and is a valid + // execution identity. The remaining fields are generation fences and must + // never be zero or empty. + if t.StatementID == "" || t.GroupID == "" || t.GroupEpoch == 0 || t.InvocationID == "" || t.LeaseEpoch == 0 { return fmt.Errorf("%w: incomplete fencing tuple", ErrProtocol) } diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index c1676b4351b1d..a9268fa7bd1d9 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -48,6 +48,14 @@ func TestControlRoundTripIsBoundedAndVersioned(t *testing.T) { require.ErrorIs(t, err, ErrProtocol) } +func TestSystemAccountIsValidFencingIdentity(t *testing.T) { + tuple := testTuple() + tuple.AccountID = 0 + require.NoError(t, tuple.Validate()) + _, err := MarshalControl(Control{Kind: "OpenInvocation", Tuple: tuple}) + require.NoError(t, err) +} + func TestSequenceKeepsHalfCloseIndependentFromResults(t *testing.T) { var sequence Sequence require.NoError(t, sequence.AcceptInput(1)) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 752a1469e6f5a..aa26968e6bf02 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -138,13 +138,17 @@ def test_active_fence_cannot_be_admitted_twice(self): def test_control_numeric_fields_are_strict(self): tuple_value = { - "account_id": 1, + "account_id": 0, "statement_id": "statement", "group_id": "group", "group_epoch": 1, "invocation_id": "invocation", "lease_epoch": 1, } + self.assertEqual( + (0, "statement", "group", 1, "invocation", 1), + worker._tuple_key(tuple_value), + ) with self.assertRaisesRegex(ValueError, "unsupported control"): worker._decode_control(json.dumps({"version": True, "kind": "InputBatch", "tuple": tuple_value}).encode()) with self.assertRaisesRegex(ValueError, "invalid control field sequence"): diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 3257a02d95240..9dd4b68e2c3ef 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -230,15 +230,22 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: def _tuple_key(value: Dict[str, Any]) -> tuple: string_fields = ("statement_id", "group_id", "invocation_id") - numeric_fields = ("account_id", "group_epoch", "lease_epoch") if not isinstance(value, dict) or any(not isinstance(value.get(k), str) or not value[k] for k in string_fields): raise ValueError("PROTOCOL: incomplete fencing tuple") + account_id = value.get("account_id") + if ( + isinstance(account_id, bool) + or not isinstance(account_id, int) + or account_id < 0 + or account_id > (1 << 64) - 1 + ): + raise ValueError("PROTOCOL: incomplete fencing tuple") if any( isinstance(value.get(k), bool) or not isinstance(value.get(k), int) or value[k] <= 0 or value[k] > (1 << 64) - 1 - for k in numeric_fields + for k in ("group_epoch", "lease_epoch") ): raise ValueError("PROTOCOL: incomplete fencing tuple") return ( From a9439dc70557045bddda6d137255670e0247bbe9 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 18:16:59 +0800 Subject: [PATCH 006/241] test(udf): add Python cases to CI BVT --- .github/workflows/python-udf-bvt.yaml | 112 ++++++++++++++++++ .../python-udf-worker.toml | 1 + optools/bvt_ut/entrypoint.sh | 4 +- optools/run_bvt.sh | 6 +- optools/run_bvt_group.sh | 4 + optools/run_python_udf_bvt.sh | 36 ++++++ test/distributed/cases/udf_python/README.md | 24 ++++ .../cases/udf_python/udf_python.result | 19 +++ .../cases/udf_python/udf_python.sql | 14 +++ 9 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/python-udf-bvt.yaml create mode 100755 optools/run_python_udf_bvt.sh create mode 100644 test/distributed/cases/udf_python/README.md create mode 100644 test/distributed/cases/udf_python/udf_python.result create mode 100644 test/distributed/cases/udf_python/udf_python.sql diff --git a/.github/workflows/python-udf-bvt.yaml b/.github/workflows/python-udf-bvt.yaml new file mode 100644 index 0000000000000..56a2985b51eea --- /dev/null +++ b/.github/workflows/python-udf-bvt.yaml @@ -0,0 +1,112 @@ +name: MatrixOne Python UDF BVT + +on: + workflow_call: + inputs: + head_repository: + description: "Repository containing the PR head" + required: true + type: string + head_sha: + description: "Exact PR head commit" + required: true + type: string + build_artifact: + description: "Optional shared MatrixOne build artifact" + required: false + type: string + default: "" + +permissions: + contents: read + +jobs: + bvt: + name: Python UDF SQL cases + runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-22.04' }} + timeout-minutes: 45 + steps: + - name: Checkout MatrixOne head + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false + fetch-depth: 3 + repository: ${{ inputs.head_repository }} + ref: ${{ inputs.head_sha }} + + - name: Set up Go and Java + uses: matrixorigin/CI/actions/setup-env@main + with: + go-version-file: "${{ github.workspace }}/go.mod" + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install the locked worker dependency + run: >- + python3 -m pip install --no-cache-dir --only-binary=:all: + -r pkg/udf/python/worker/requirements.txt + + - name: Download shared MatrixOne build + if: ${{ inputs.build_artifact != '' }} + continue-on-error: true + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.build_artifact }} + path: ${{ runner.temp }}/mo-prebuilt + + - name: Restore the shared runtime or build locally + env: + EXPECTED_HEAD_SHA: ${{ inputs.head_sha }} + run: | + set -euo pipefail + artifact="${RUNNER_TEMP}/mo-prebuilt/mo-build.tar.gz" + if [ -s "${artifact}" ]; then + unpacked="${RUNNER_TEMP}/mo-prebuilt/unpacked" + rm -rf "${unpacked}" + mkdir -p "${unpacked}" + if tar -xzf "${artifact}" -C "${unpacked}"; then + artifact_head_sha=$(sed -n 's/^head_sha=//p' "${unpacked}/BUILD_INFO" 2>/dev/null || true) + artifact_build_opt=$(sed -n 's/^gobuild_opt=//p' "${unpacked}/BUILD_INFO" 2>/dev/null || true) + if [ "${artifact_head_sha}" = "${EXPECTED_HEAD_SHA}" ] && [ "${artifact_build_opt}" = "-cover" ]; then + cp -a "${unpacked}/BUILD_INFO" "${unpacked}/mo-service" "${unpacked}/lib" "${unpacked}/dict" "${GITHUB_WORKSPACE}/" + chmod +x mo-service + else + echo "::warning::shared build metadata mismatch; falling back to a local build" + fi + else + echo "::warning::shared build artifact could not be extracted; falling back to a local build" + fi + fi + if [ ! -x mo-service ]; then + make build + fi + mkdir -p "${RUNNER_TEMP}/gocoverdir" + + - name: Checkout mo-tester + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + repository: matrixorigin/mo-tester + ref: main + path: mo-tester + persist-credentials: false + + - name: Run Python UDF BVT cases + env: + GOCOVERDIR: ${{ runner.temp }}/gocoverdir + run: | + set -euo pipefail + ./optools/run_python_udf_bvt.sh "${GITHUB_WORKSPACE}" "${GITHUB_WORKSPACE}/mo-tester" + + - name: Upload Python UDF BVT diagnostics + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: python-udf-bvt-${{ github.run_id }}-${{ github.run_attempt }} + if-no-files-found: ignore + path: | + mo-service.log + python-udf-worker-*.log + mo-tester/report diff --git a/etc/launch-with-python-udf-worker/python-udf-worker.toml b/etc/launch-with-python-udf-worker/python-udf-worker.toml index 40a0d22bb0ade..21a661af1af09 100644 --- a/etc/launch-with-python-udf-worker/python-udf-worker.toml +++ b/etc/launch-with-python-udf-worker/python-udf-worker.toml @@ -4,3 +4,4 @@ service-type = "PYTHON_UDF" uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41b2" address = "127.0.0.1:50051" path = "pkg/udf/python/worker" +python = "python3" diff --git a/optools/bvt_ut/entrypoint.sh b/optools/bvt_ut/entrypoint.sh index d57a599fd34f1..fe3741ab456f3 100755 --- a/optools/bvt_ut/entrypoint.sh +++ b/optools/bvt_ut/entrypoint.sh @@ -45,7 +45,7 @@ function run_bvt() { echo ">>>>>>>>>>>>>>>>>>>>>>>> start bvt" # use test/distributed/cases as default test cases echo "> test case: test/distributed/cases" - cd mo-tester && ./run.sh -n -g -o -p /matrixone-test/test/distributed/cases -e optimistic 2>&1 + cd mo-tester && ./run.sh -n -g -o -p /matrixone-test/test/distributed/cases -e optimistic,udf_python 2>&1 } function bvt_ut() { @@ -63,4 +63,4 @@ function bvt_ut() { run_bvt } -bvt_ut \ No newline at end of file +bvt_ut diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index 0a46252e8912f..5d53fb370bda5 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -72,6 +72,10 @@ function launch_jstfu() { } launch_mo -launch_jstfu || exit $? +if [[ "${SKIP_JSTFU:-false}" == "true" ]]; then + echo "skip jstfu for this BVT suite" +else + launch_jstfu || exit $? +fi wait_system_init exit $? diff --git a/optools/run_bvt_group.sh b/optools/run_bvt_group.sh index 1984aac8bfb6b..ccf53d4c0fb4c 100644 --- a/optools/run_bvt_group.sh +++ b/optools/run_bvt_group.sh @@ -36,6 +36,10 @@ while IFS= read -r script_path; do relative_path=${script_path#"${case_root}/"} [[ "${relative_path}" == *optimistic* ]] && continue top_level=${relative_path%%/*} + # Python UDF needs an explicit worker-enabled launch and Python/pyarrow + # dependencies. Keep it out of the ordinary two-group BVT runs; the + # dedicated runner executes this suite with the worker enabled. + [[ "${top_level}" == "udf_python" ]] && continue case "${top_level}" in array|auto_increment|benchmark|dataXtest|ddl|disttae|fake_pk|function|git4data|hint|join|keyword|load_data|mo_cloud|optimizer|pg_cast|plugin|prepare|procedure|query_result|sample|save_query_result|sequence|snapshot|sql_inject|stage|system|system_variable|temporary|tenant|tenxcloud_xx|time_window|union|util|vector|view) diff --git a/optools/run_python_udf_bvt.sh b/optools/run_python_udf_bvt.sh new file mode 100755 index 0000000000000..670c4b7293caf --- /dev/null +++ b/optools/run_python_udf_bvt.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +# Copyright 2026 Matrix Origin +# +# 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. + +set -euo pipefail + +workspace=$(cd "${1:-.}" && pwd) +tester_dir=${2:-"${workspace}/mo-tester"} +python_bin=${PYTHON_UDF_PYTHON:-python3} + +if [[ ! -x "${workspace}/mo-service" ]]; then + (cd "${workspace}" && make build) +fi + +if [[ ! -d "${tester_dir}" ]]; then + git clone --depth=1 https://github.com/matrixorigin/mo-tester.git "${tester_dir}" +fi + +"${python_bin}" -c 'import pyarrow; assert pyarrow.__version__ == "24.0.0", pyarrow.__version__' + +SKIP_JSTFU=true "${workspace}/optools/run_bvt.sh" "${workspace}" launch-with-python-udf-worker + +cd "${tester_dir}" +./run.sh -n -g -o -p "${workspace}/test/distributed/cases/udf_python" 2>&1 diff --git a/test/distributed/cases/udf_python/README.md b/test/distributed/cases/udf_python/README.md new file mode 100644 index 0000000000000..00b87dbcb14ec --- /dev/null +++ b/test/distributed/cases/udf_python/README.md @@ -0,0 +1,24 @@ +# Python UDF BVT cases + +Put SQL cases that require the Python UDF worker in this directory. Each case +needs a matching `.result` file generated by `mo-tester`. + +Run the complete Python UDF suite locally with: + +```bash +python3 -m pip install -r pkg/udf/python/worker/requirements.txt +./optools/run_python_udf_bvt.sh "$(pwd)" /path/to/mo-tester +``` + +To create or refresh a result file after reviewing the expected output, start +the worker-enabled launch and use `mo-tester`'s `genrs` mode: + +```bash +SKIP_JSTFU=true ./optools/run_bvt.sh . launch-with-python-udf-worker +cd /path/to/mo-tester +./run.sh -p /path/to/matrixone/test/distributed/cases/udf_python/example.sql -m genrs -g +``` + +The ordinary BVT jobs intentionally skip this directory because their launch +configuration does not start a Python worker. The dedicated Python UDF CI job +runs every case here with the worker and the pinned `pyarrow` dependency. diff --git a/test/distributed/cases/udf_python/udf_python.result b/test/distributed/cases/udf_python/udf_python.result new file mode 100644 index 0000000000000..8534ba2ba2c2d --- /dev/null +++ b/test/distributed/cases/udf_python/udf_python.result @@ -0,0 +1,19 @@ +drop database if exists udf_python_bvt; +create database udf_python_bvt; +use udf_python_bvt; +create function python_bvt_add (x int) returns int language python as 'def python_bvt_add(ctx, x): return None if x is None else x + 1' handler 'python_bvt_add'; +create table input_values (v int); +insert into input_values values (1), (null), (3); +select v, python_bvt_add(v) as plus_one from input_values order by v is null, v; +➤ v[4,32,0] ¦ plus_one[4,32,0] 𝄀 +1 ¦ 2 𝄀 +3 ¦ 4 𝄀 +null ¦ null +select case when v is null then 99 else python_bvt_add(v) end as guarded from input_values order by v is null, v; +➤ guarded[-5,64,0] 𝄀 +2 𝄀 +4 𝄀 +99 +drop function python_bvt_add(int); +drop table input_values; +drop database udf_python_bvt; diff --git a/test/distributed/cases/udf_python/udf_python.sql b/test/distributed/cases/udf_python/udf_python.sql new file mode 100644 index 0000000000000..26799d1531eea --- /dev/null +++ b/test/distributed/cases/udf_python/udf_python.sql @@ -0,0 +1,14 @@ +drop database if exists udf_python_bvt; +create database udf_python_bvt; +use udf_python_bvt; + +create function python_bvt_add (x int) returns int language python as 'def python_bvt_add(ctx, x): return None if x is None else x + 1' handler 'python_bvt_add'; +create table input_values (v int); +insert into input_values values (1), (null), (3); + +select v, python_bvt_add(v) as plus_one from input_values order by v is null, v; +select case when v is null then 99 else python_bvt_add(v) end as guarded from input_values order by v is null, v; + +drop function python_bvt_add(int); +drop table input_values; +drop database udf_python_bvt; From b086914f42c54826052954dfbec6899e2008ba3f Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 18:17:35 +0800 Subject: [PATCH 007/241] chore(udf): remove stale Python service ignore rules --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 87a8cfb0641bc..f462e7b732058 100644 --- a/.gitignore +++ b/.gitignore @@ -77,8 +77,6 @@ node-*-data/ pkg/catalog/test/ pkg/config/system_vars.go pkg/config/system_vars_test.go -pkg/udf/pythonservice/pyserver/udf/ -pkg/udf/pythonservice/pyserver/__pycache__/ path_to_file tester-log/ ut-report/ From 58cd90c93811e7cf27ec4b10e8dc4f0d7b8d2f4b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 18:18:14 +0800 Subject: [PATCH 008/241] ci(udf): harden Python BVT build fallback --- .github/workflows/python-udf-bvt.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-udf-bvt.yaml b/.github/workflows/python-udf-bvt.yaml index 56a2985b51eea..25c9a9565cabc 100644 --- a/.github/workflows/python-udf-bvt.yaml +++ b/.github/workflows/python-udf-bvt.yaml @@ -70,11 +70,15 @@ jobs: if tar -xzf "${artifact}" -C "${unpacked}"; then artifact_head_sha=$(sed -n 's/^head_sha=//p' "${unpacked}/BUILD_INFO" 2>/dev/null || true) artifact_build_opt=$(sed -n 's/^gobuild_opt=//p' "${unpacked}/BUILD_INFO" 2>/dev/null || true) - if [ "${artifact_head_sha}" = "${EXPECTED_HEAD_SHA}" ] && [ "${artifact_build_opt}" = "-cover" ]; then + if [ "${artifact_head_sha}" = "${EXPECTED_HEAD_SHA}" ] \ + && [ "${artifact_build_opt}" = "-cover" ] \ + && [ -x "${unpacked}/mo-service" ] \ + && [ -d "${unpacked}/lib" ] \ + && [ -d "${unpacked}/dict" ]; then cp -a "${unpacked}/BUILD_INFO" "${unpacked}/mo-service" "${unpacked}/lib" "${unpacked}/dict" "${GITHUB_WORKSPACE}/" chmod +x mo-service else - echo "::warning::shared build metadata mismatch; falling back to a local build" + echo "::warning::shared build artifact is incomplete or mismatched; falling back to a local build" fi else echo "::warning::shared build artifact could not be extracted; falling back to a local build" From 28875c29b4d3f91a8c4e954a06fb0223927d03e3 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 20:21:55 +0800 Subject: [PATCH 009/241] test(udf): run Python cases in ordinary BVT --- .github/workflows/python-udf-bvt.yaml | 116 ------------------ etc/launch-tae-compose/README.md | 5 + etc/launch-tae-compose/compose.yaml | 59 ++++++++- etc/launch-tae-compose/config/cn-0.toml | 3 + etc/launch-tae-compose/config/cn-1.toml | 3 + etc/launch/cn.toml | 3 + etc/launch/launch.toml | 3 + optools/bvt_ut/Dockerfile | 11 ++ optools/bvt_ut/entrypoint.sh | 2 +- optools/images/Dockerfile | 4 +- optools/run_bvt_group.sh | 15 +-- optools/run_python_udf_bvt.sh | 36 ------ .../udf/python/worker}/Dockerfile | 4 +- test/distributed/cases/udf_python/README.md | 22 ++-- 14 files changed, 109 insertions(+), 177 deletions(-) delete mode 100644 .github/workflows/python-udf-bvt.yaml delete mode 100755 optools/run_python_udf_bvt.sh rename {optools/images/pythonworker => pkg/udf/python/worker}/Dockerfile (80%) diff --git a/.github/workflows/python-udf-bvt.yaml b/.github/workflows/python-udf-bvt.yaml deleted file mode 100644 index 25c9a9565cabc..0000000000000 --- a/.github/workflows/python-udf-bvt.yaml +++ /dev/null @@ -1,116 +0,0 @@ -name: MatrixOne Python UDF BVT - -on: - workflow_call: - inputs: - head_repository: - description: "Repository containing the PR head" - required: true - type: string - head_sha: - description: "Exact PR head commit" - required: true - type: string - build_artifact: - description: "Optional shared MatrixOne build artifact" - required: false - type: string - default: "" - -permissions: - contents: read - -jobs: - bvt: - name: Python UDF SQL cases - runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-22.04' }} - timeout-minutes: 45 - steps: - - name: Checkout MatrixOne head - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - persist-credentials: false - fetch-depth: 3 - repository: ${{ inputs.head_repository }} - ref: ${{ inputs.head_sha }} - - - name: Set up Go and Java - uses: matrixorigin/CI/actions/setup-env@main - with: - go-version-file: "${{ github.workspace }}/go.mod" - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.12" - - - name: Install the locked worker dependency - run: >- - python3 -m pip install --no-cache-dir --only-binary=:all: - -r pkg/udf/python/worker/requirements.txt - - - name: Download shared MatrixOne build - if: ${{ inputs.build_artifact != '' }} - continue-on-error: true - uses: actions/download-artifact@v4 - with: - name: ${{ inputs.build_artifact }} - path: ${{ runner.temp }}/mo-prebuilt - - - name: Restore the shared runtime or build locally - env: - EXPECTED_HEAD_SHA: ${{ inputs.head_sha }} - run: | - set -euo pipefail - artifact="${RUNNER_TEMP}/mo-prebuilt/mo-build.tar.gz" - if [ -s "${artifact}" ]; then - unpacked="${RUNNER_TEMP}/mo-prebuilt/unpacked" - rm -rf "${unpacked}" - mkdir -p "${unpacked}" - if tar -xzf "${artifact}" -C "${unpacked}"; then - artifact_head_sha=$(sed -n 's/^head_sha=//p' "${unpacked}/BUILD_INFO" 2>/dev/null || true) - artifact_build_opt=$(sed -n 's/^gobuild_opt=//p' "${unpacked}/BUILD_INFO" 2>/dev/null || true) - if [ "${artifact_head_sha}" = "${EXPECTED_HEAD_SHA}" ] \ - && [ "${artifact_build_opt}" = "-cover" ] \ - && [ -x "${unpacked}/mo-service" ] \ - && [ -d "${unpacked}/lib" ] \ - && [ -d "${unpacked}/dict" ]; then - cp -a "${unpacked}/BUILD_INFO" "${unpacked}/mo-service" "${unpacked}/lib" "${unpacked}/dict" "${GITHUB_WORKSPACE}/" - chmod +x mo-service - else - echo "::warning::shared build artifact is incomplete or mismatched; falling back to a local build" - fi - else - echo "::warning::shared build artifact could not be extracted; falling back to a local build" - fi - fi - if [ ! -x mo-service ]; then - make build - fi - mkdir -p "${RUNNER_TEMP}/gocoverdir" - - - name: Checkout mo-tester - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - repository: matrixorigin/mo-tester - ref: main - path: mo-tester - persist-credentials: false - - - name: Run Python UDF BVT cases - env: - GOCOVERDIR: ${{ runner.temp }}/gocoverdir - run: | - set -euo pipefail - ./optools/run_python_udf_bvt.sh "${GITHUB_WORKSPACE}" "${GITHUB_WORKSPACE}/mo-tester" - - - name: Upload Python UDF BVT diagnostics - if: ${{ always() }} - uses: actions/upload-artifact@v4 - with: - name: python-udf-bvt-${{ github.run_id }}-${{ github.run_attempt }} - if-no-files-found: ignore - path: | - mo-service.log - python-udf-worker-*.log - mo-tester/report diff --git a/etc/launch-tae-compose/README.md b/etc/launch-tae-compose/README.md index 6e40e3ac0fd9d..46092b441f56a 100644 --- a/etc/launch-tae-compose/README.md +++ b/etc/launch-tae-compose/README.md @@ -45,6 +45,11 @@ MatrixOne's trusted main-branch cache warmer keeps the Maven repository and wrapper distribution available to PR CI. Pull-request jobs restore that cache read-only; they never publish dependencies resolved from an untrusted head. +The compose BVT starts one Python UDF worker per CN. The worker image is shared +by both services, while the worker processes, addresses, and failure domains +remain separate (`cn-0` uses `python-udf-worker-cn0`, and `cn-1` uses +`python-udf-worker-cn1`). + ## Check log ```shell diff --git a/etc/launch-tae-compose/compose.yaml b/etc/launch-tae-compose/compose.yaml index 7a5a3c053fb5f..de18214d88376 100644 --- a/etc/launch-tae-compose/compose.yaml +++ b/etc/launch-tae-compose/compose.yaml @@ -28,6 +28,18 @@ x-mo-common: &mo-common - NET_ADMIN tty: true +x-python-udf-worker: &python-udf-worker + image: matrixorigin/mo-python-udf-worker:latest + restart: on-failure + profiles: + - launch + - launch-multi-cn + healthcheck: + test: ["CMD", "python", "-c", "import socket; s=socket.create_connection(('127.0.0.1', 50051), 1); s.close()"] + interval: 1s + timeout: 2s + retries: 30 + services: cn-0: @@ -40,7 +52,10 @@ services: - launch - launch-multi-cn depends_on: - - tn + tn: + condition: service_started + python-udf-worker-cn0: + condition: service_healthy ports: - "6002" - "12345:12345" @@ -59,7 +74,10 @@ services: <<: *mo-common entrypoint: ["/bin/bash","-c","set -euo pipefail; exec /mo-service -debug-http :12345 -cfg /config/cn-1.toml > >(tee -a /log/cn-1.log) 2>&1"] depends_on: - - tn + tn: + condition: service_started + python-udf-worker-cn1: + condition: service_healthy ports: - "6002" - "22345:12345" @@ -146,6 +164,43 @@ services: aliases: - "logservice" + # Build the worker image once. The two CN-scoped worker services below use + # the resulting image and keep their process and failure domains separate. + python-udf-worker-image: + container_name: python-udf-worker-image + build: + context: ../../pkg/udf/python/worker + dockerfile: Dockerfile + image: matrixorigin/mo-python-udf-worker:latest + pull_policy: build + command: ["true"] + restart: "no" + profiles: + - launch + - launch-multi-cn + + python-udf-worker-cn0: + <<: *python-udf-worker + container_name: python-udf-worker-cn0 + depends_on: + python-udf-worker-image: + condition: service_completed_successfully + networks: + monet: + aliases: + - "python-udf-worker-cn0" + + python-udf-worker-cn1: + <<: *python-udf-worker + container_name: python-udf-worker-cn1 + depends_on: + python-udf-worker-image: + condition: service_completed_successfully + networks: + monet: + aliases: + - "python-udf-worker-cn1" + # --------------------------------------------------------------------- # jstfu: the datastream external table gRPC server (xtool/jstfu), needed # by test/distributed/cases/datastream. The BVT cases address it as diff --git a/etc/launch-tae-compose/config/cn-0.toml b/etc/launch-tae-compose/config/cn-0.toml index 215f9967f8938..662553a5a8806 100644 --- a/etc/launch-tae-compose/config/cn-0.toml +++ b/etc/launch-tae-compose/config/cn-0.toml @@ -66,3 +66,6 @@ enable-write = true enable-delete = true enable-dml = true enable-maintenance = true + +[cn.python-udf-client] +server-address = "python-udf-worker-cn0:50051" diff --git a/etc/launch-tae-compose/config/cn-1.toml b/etc/launch-tae-compose/config/cn-1.toml index d53336c99a27c..49b1cad684d43 100644 --- a/etc/launch-tae-compose/config/cn-1.toml +++ b/etc/launch-tae-compose/config/cn-1.toml @@ -66,3 +66,6 @@ enable-write = true enable-delete = true enable-dml = true enable-maintenance = true + +[cn.python-udf-client] +server-address = "python-udf-worker-cn1:50051" diff --git a/etc/launch/cn.toml b/etc/launch/cn.toml index f989f16a9bff6..8c315e594bb32 100644 --- a/etc/launch/cn.toml +++ b/etc/launch/cn.toml @@ -49,3 +49,6 @@ enable-write = true enable-delete = true enable-dml = true enable-maintenance = true + +[cn.python-udf-client] +server-address = "127.0.0.1:50051" diff --git a/etc/launch/launch.toml b/etc/launch/launch.toml index ddc12393f2e9c..19f97c824f70e 100644 --- a/etc/launch/launch.toml +++ b/etc/launch/launch.toml @@ -10,3 +10,6 @@ cnservices = [ "./etc/launch/cn.toml" ] +python-udf-services = [ + "./etc/launch-with-python-udf-worker/python-udf-worker.toml" +] diff --git a/optools/bvt_ut/Dockerfile b/optools/bvt_ut/Dockerfile index e0d1d757d8ee2..84af02779ea8a 100644 --- a/optools/bvt_ut/Dockerfile +++ b/optools/bvt_ut/Dockerfile @@ -10,6 +10,17 @@ ENV ENABLE_UT="false" RUN go env -w GOPROXY="${GOPROXY}" +# The ordinary launch BVT starts the Python UDF worker together with the +# MatrixOne services. Keep its environment pinned to the same contract used by +# the compose worker image. +RUN apt-get update && \ + apt-get install -y --no-install-recommends python3-pip && \ + rm -rf /var/lib/apt/lists/* + +COPY pkg/udf/python/worker/requirements.txt /tmp/python-udf-requirements.txt +RUN python3 -m pip install --break-system-packages --no-cache-dir --only-binary=:all: \ + -r /tmp/python-udf-requirements.txt + RUN mkdir -p /matrixone-test WORKDIR /matrixone-test diff --git a/optools/bvt_ut/entrypoint.sh b/optools/bvt_ut/entrypoint.sh index fe3741ab456f3..e048892438fc9 100755 --- a/optools/bvt_ut/entrypoint.sh +++ b/optools/bvt_ut/entrypoint.sh @@ -45,7 +45,7 @@ function run_bvt() { echo ">>>>>>>>>>>>>>>>>>>>>>>> start bvt" # use test/distributed/cases as default test cases echo "> test case: test/distributed/cases" - cd mo-tester && ./run.sh -n -g -o -p /matrixone-test/test/distributed/cases -e optimistic,udf_python 2>&1 + cd mo-tester && ./run.sh -n -g -o -p /matrixone-test/test/distributed/cases -e optimistic 2>&1 } function bvt_ut() { diff --git a/optools/images/Dockerfile b/optools/images/Dockerfile index c72c83ed0f186..f0fb1f142a221 100644 --- a/optools/images/Dockerfile +++ b/optools/images/Dockerfile @@ -64,8 +64,8 @@ FROM matrixorigin/ubuntu:22.04 COPY --from=builder /go/src/github.com/matrixorigin/matrixone/mo-service /mo-service COPY --from=builder /go/src/github.com/matrixorigin/matrixone/etc /etc -COPY --from=builder /go/src/github.com/matrixorigin/matrixone/thirdparties/install/lib/*.so /usr/local/lib -COPY --from=builder /go/src/github.com/matrixorigin/matrixone/cgo/*.so /usr/local/lib +COPY --from=builder /go/src/github.com/matrixorigin/matrixone/thirdparties/install/lib/*.so /usr/local/lib/ +COPY --from=builder /go/src/github.com/matrixorigin/matrixone/cgo/*.so /usr/local/lib/ COPY --from=builder /go/src/github.com/matrixorigin/matrixone/pkg/monlp/tokenizer/dict /usr/local/share/jieba ENV MO_JIEBA_DICT_DIR=/usr/local/share/jieba diff --git a/optools/run_bvt_group.sh b/optools/run_bvt_group.sh index ccf53d4c0fb4c..17566dd4e5bbf 100644 --- a/optools/run_bvt_group.sh +++ b/optools/run_bvt_group.sh @@ -26,26 +26,19 @@ if ! [[ "${group_id}" =~ ^[01]$ ]]; then fi declare -a included_scripts=() -declare -a resource_args=() if [[ -n "${resource_dir}" ]]; then resource_dir=$(cd "${resource_dir}" && pwd) - resource_args=(-s "${resource_dir}") fi while IFS= read -r script_path; do relative_path=${script_path#"${case_root}/"} [[ "${relative_path}" == *optimistic* ]] && continue top_level=${relative_path%%/*} - # Python UDF needs an explicit worker-enabled launch and Python/pyarrow - # dependencies. Keep it out of the ordinary two-group BVT runs; the - # dedicated runner executes this suite with the worker enabled. - [[ "${top_level}" == "udf_python" ]] && continue - case "${top_level}" in array|auto_increment|benchmark|dataXtest|ddl|disttae|fake_pk|function|git4data|hint|join|keyword|load_data|mo_cloud|optimizer|pg_cast|plugin|prepare|procedure|query_result|sample|save_query_result|sequence|snapshot|sql_inject|stage|system|system_variable|temporary|tenant|tenxcloud_xx|time_window|union|util|vector|view) assigned_group=0 ;; - analyze|charset_collation|comment|cte|database|distinct|dml|dtype|expression|feature_limit|foreign_key|fulltext|geo|iceberg|log|metadata|operator|pessimistic_transaction|pitr|plan_cache|publication_subscription|qexec|recursive_cte|replace_statement|result_count|security|set|sql_source_type|statement_query_type|subquery|table|task|udf|window|zz_accesscontrol|zz_statement_query_type) + analyze|charset_collation|comment|cte|database|distinct|dml|dtype|expression|feature_limit|foreign_key|fulltext|geo|iceberg|log|metadata|operator|pessimistic_transaction|pitr|plan_cache|publication_subscription|qexec|recursive_cte|replace_statement|result_count|security|set|sql_source_type|statement_query_type|subquery|table|task|udf|udf_python|window|zz_accesscontrol|zz_statement_query_type) assigned_group=1 ;; *) @@ -73,4 +66,8 @@ fi printf '%s\n' "${included_scripts[@]}" cd "${tester_dir}" -./run.sh -n -g -o -p "${case_root}" -i "${include_list}" "${resource_args[@]}" +if [[ -n "${resource_dir}" ]]; then + ./run.sh -n -g -o -p "${case_root}" -i "${include_list}" -s "${resource_dir}" +else + ./run.sh -n -g -o -p "${case_root}" -i "${include_list}" +fi diff --git a/optools/run_python_udf_bvt.sh b/optools/run_python_udf_bvt.sh deleted file mode 100755 index 670c4b7293caf..0000000000000 --- a/optools/run_python_udf_bvt.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2026 Matrix Origin -# -# 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. - -set -euo pipefail - -workspace=$(cd "${1:-.}" && pwd) -tester_dir=${2:-"${workspace}/mo-tester"} -python_bin=${PYTHON_UDF_PYTHON:-python3} - -if [[ ! -x "${workspace}/mo-service" ]]; then - (cd "${workspace}" && make build) -fi - -if [[ ! -d "${tester_dir}" ]]; then - git clone --depth=1 https://github.com/matrixorigin/mo-tester.git "${tester_dir}" -fi - -"${python_bin}" -c 'import pyarrow; assert pyarrow.__version__ == "24.0.0", pyarrow.__version__' - -SKIP_JSTFU=true "${workspace}/optools/run_bvt.sh" "${workspace}" launch-with-python-udf-worker - -cd "${tester_dir}" -./run.sh -n -g -o -p "${workspace}/test/distributed/cases/udf_python" 2>&1 diff --git a/optools/images/pythonworker/Dockerfile b/pkg/udf/python/worker/Dockerfile similarity index 80% rename from optools/images/pythonworker/Dockerfile rename to pkg/udf/python/worker/Dockerfile index d273cfd41d450..3fdb7d5528114 100644 --- a/optools/images/pythonworker/Dockerfile +++ b/pkg/udf/python/worker/Dockerfile @@ -1,8 +1,8 @@ # run from root path for debug: -# docker build -t mo-python-udf-worker -f ./optools/images/pythonworker/Dockerfile ./pkg/udf/python/worker/ +# docker build -t mo-python-udf-worker -f ./pkg/udf/python/worker/Dockerfile ./pkg/udf/python/worker/ # docker run -d --network host mo-python-udf-worker -FROM python:3.12-bookworm +FROM python:3.12-slim-bookworm RUN useradd -m -s /bin/bash mo diff --git a/test/distributed/cases/udf_python/README.md b/test/distributed/cases/udf_python/README.md index 00b87dbcb14ec..8c717c7021153 100644 --- a/test/distributed/cases/udf_python/README.md +++ b/test/distributed/cases/udf_python/README.md @@ -1,24 +1,28 @@ # Python UDF BVT cases Put SQL cases that require the Python UDF worker in this directory. Each case -needs a matching `.result` file generated by `mo-tester`. +needs a matching `.result` file generated by `mo-tester`. These cases are part +of the ordinary BVT suite and run with the other SQL cases. -Run the complete Python UDF suite locally with: +For a local launch BVT, install the locked worker dependency once and use the +normal BVT commands: ```bash python3 -m pip install -r pkg/udf/python/worker/requirements.txt -./optools/run_python_udf_bvt.sh "$(pwd)" /path/to/mo-tester +./optools/run_bvt.sh . launch +cd /path/to/mo-tester +./run.sh -n -g -o -p /path/to/matrixone/test/distributed/cases ``` -To create or refresh a result file after reviewing the expected output, start -the worker-enabled launch and use `mo-tester`'s `genrs` mode: +To create or refresh a result file after reviewing the expected output, keep +the normal worker-enabled launch running and use `mo-tester`'s `genrs` mode: ```bash -SKIP_JSTFU=true ./optools/run_bvt.sh . launch-with-python-udf-worker +SKIP_JSTFU=true ./optools/run_bvt.sh . launch cd /path/to/mo-tester ./run.sh -p /path/to/matrixone/test/distributed/cases/udf_python/example.sql -m genrs -g ``` -The ordinary BVT jobs intentionally skip this directory because their launch -configuration does not start a Python worker. The dedicated Python UDF CI job -runs every case here with the worker and the pinned `pyarrow` dependency. +The ordinary launch manifest starts one worker for the single CN. Compose BVT +starts one isolated worker service per CN from the same pinned image, so adding +a SQL case here does not require another CI workflow. From ef77e8231d1a1eba38dbc803a20194988529060a Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 21:02:43 +0800 Subject: [PATCH 010/241] test(udf): expand Python boundary BVT coverage --- pkg/frontend/authenticate.go | 27 +++++++ pkg/frontend/compiler_context.go | 3 + pkg/sql/plan/build_util.go | 11 +++ pkg/sql/plan/function/python_udf.go | 10 +++ pkg/sql/plan/function/udf.go | 80 ++++++++++++++++--- pkg/sql/plan/function/udf_test.go | 56 +++++++++++++ pkg/udf/python/worker/test_worker.py | 18 +++++ pkg/udf/python/worker/worker.py | 19 +++-- test/distributed/cases/udf_python/README.md | 19 +++++ .../cases/udf_python/control_flow.result | 51 ++++++++++++ .../cases/udf_python/control_flow.sql | 49 ++++++++++++ .../udf_python/numeric_boundaries.result | 70 ++++++++++++++++ .../cases/udf_python/numeric_boundaries.sql | 72 +++++++++++++++++ .../udf_python/temporal_boundaries.result | 41 ++++++++++ .../cases/udf_python/temporal_boundaries.sql | 43 ++++++++++ .../cases/udf_python/value_types.result | 72 +++++++++++++++++ .../cases/udf_python/value_types.sql | 64 +++++++++++++++ 17 files changed, 687 insertions(+), 18 deletions(-) create mode 100644 pkg/sql/plan/function/udf_test.go create mode 100644 test/distributed/cases/udf_python/control_flow.result create mode 100644 test/distributed/cases/udf_python/control_flow.sql create mode 100644 test/distributed/cases/udf_python/numeric_boundaries.result create mode 100644 test/distributed/cases/udf_python/numeric_boundaries.sql create mode 100644 test/distributed/cases/udf_python/temporal_boundaries.result create mode 100644 test/distributed/cases/udf_python/temporal_boundaries.sql create mode 100644 test/distributed/cases/udf_python/value_types.result create mode 100644 test/distributed/cases/udf_python/value_types.sql diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index 24bfcb872220a..30f1a0e7d1dc1 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -11680,6 +11680,8 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C var argList []*function.Arg var typeList []string var erArray []ExecResult + var pythonArgTypes []function.PythonTypeDescriptor + var pythonReturnType *function.PythonTypeDescriptor // a database must be selected or specified as qualifier when create a function if cf.Name.HasNoNameQualifier() { @@ -11723,6 +11725,18 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C if err != nil { return err } + if cf.Language == string(tree.PYTHON) { + returnType, typeErr := plan2.GetFunctionTypeFromAst(cf.ReturnType.Type) + if typeErr != nil { + return typeErr + } + descriptor, typeErr := function.NewPythonTypeDescriptor(returnType) + if typeErr != nil { + return typeErr + } + pythonReturnType = &descriptor + pythonArgTypes = make([]function.PythonTypeDescriptor, len(cf.Args)) + } // build argmap and marshal as json argList = make([]*function.Arg, len(cf.Args)) @@ -11737,6 +11751,17 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C } argList[i].Type = typ typeList[i] = typ + if cf.Language == string(tree.PYTHON) { + argType, typeErr := plan2.GetFunctionTypeFromAst(cf.Args[i].(*tree.FunctionArgDecl).Type) + if typeErr != nil { + return typeErr + } + descriptor, typeErr := function.NewPythonTypeDescriptor(argType) + if typeErr != nil { + return typeErr + } + pythonArgTypes[i] = descriptor + } } argsJson, err = json.Marshal(argList) if err != nil { @@ -11781,6 +11806,8 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C ABIContract: udf.PythonABIContract, AdapterVersion: udf.PythonAdapterVersion, SDKVersion: udf.PythonSDKVersion, + ArgTypes: pythonArgTypes, + ReturnType: pythonReturnType, } var byt []byte byt, err = json.Marshal(nb) diff --git a/pkg/frontend/compiler_context.go b/pkg/frontend/compiler_context.go index 97ba3e5a2622e..f38fccbb549ee 100644 --- a/pkg/frontend/compiler_context.go +++ b/pkg/frontend/compiler_context.go @@ -997,6 +997,9 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex return nil, getErr } udf.SQLMode = &mode + if err = udf.LoadPythonTypeContract(); err != nil { + return nil, err + } // arg type check argList := make([]*function.Arg, 0) err = json.Unmarshal([]byte(argstr), &argList) diff --git a/pkg/sql/plan/build_util.go b/pkg/sql/plan/build_util.go index 13181bebe3369..7bcfa30fbec7c 100644 --- a/pkg/sql/plan/build_util.go +++ b/pkg/sql/plan/build_util.go @@ -136,6 +136,17 @@ func GetFunctionArgTypeStrFromAst(arg tree.FunctionArg) (string, error) { return GetFunctionTypeStrFromAst(argDecl.Type) } +// GetFunctionTypeFromAst retains the full type attributes needed by external +// routine ABIs. GetFunctionTypeStrFromAst intentionally returns only the +// logical catalog name for legacy UDF overload identity. +func GetFunctionTypeFromAst(typRef tree.ResolvableTypeReference) (types.Type, error) { + typ, err := getTypeFromAst(moerr.Context(), typRef) + if err != nil { + return types.Type{}, err + } + return types.NewWithCharset(types.T(typ.Id), typ.Width, typ.Scale, uint8(typ.Charset)), nil +} + func GetFunctionTypeStrFromAst(typRef tree.ResolvableTypeReference) (string, error) { typ, err := getTypeFromAst(moerr.Context(), typRef) if err != nil { diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index c63a872febb43..5531541f2850a 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -94,6 +94,9 @@ func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapp if routine.Udf == nil { return fmt.Errorf("python udf: routine descriptor has no function") } + if err := routine.LoadPythonTypeContract(); err != nil { + return fmt.Errorf("python udf: decode Python type contract: %w", err) + } body := PythonRoutineBody{} if err := json.Unmarshal([]byte(routine.Body), &body); err != nil { @@ -249,6 +252,13 @@ func hasNullInput(inputs []*vector.Vector, row int) bool { } func routineArgumentTypes(routine *UdfWithContext) ([]types.Type, error) { + if len(routine.PythonArgTypes) != 0 { + args := make([]types.Type, len(routine.PythonArgTypes)) + for i, descriptor := range routine.PythonArgTypes { + args[i] = descriptor.Type() + } + return args, nil + } if len(routine.ArgsType) != 0 || len(routine.Args) == 0 { return append([]types.Type(nil), routine.ArgsType...), nil } diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index 2f427b4349005..47d0fb22800b4 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -14,6 +14,7 @@ import ( "github.com/google/uuid" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/pb/plan" + pythonudf "github.com/matrixorigin/matrixone/pkg/udf/python" ) type Udf struct { @@ -25,6 +26,12 @@ type Udf struct { ModifiedTime string `json:"modified_time"` SQLMode *string `json:"-"` ArgsType []types.Type `json:"-"` + // PythonArgTypes and PythonReturnType preserve the exact SQL declaration + // for Python's Arrow contract. The legacy catalog's args/rettype columns + // intentionally keep only logical type names, which is insufficient for + // width and scale validation. + PythonArgTypes []PythonTypeDescriptor `json:"-"` + PythonReturnType *PythonTypeDescriptor `json:"-"` } type UdfWithContext struct { @@ -36,15 +43,26 @@ type UdfWithContext struct { // catalog must persist mode and NULL policy with the source so execution does // not infer either from a generic SQL function class bit. type PythonRoutineBody struct { - Handler string `json:"handler"` - Source string `json:"source,omitempty"` - Mode string `json:"mode"` - NullPolicy string `json:"null_policy"` - ABIContract string `json:"abi_contract"` - AdapterVersion string `json:"adapter_version"` - ArtifactDigest string `json:"artifact_digest,omitempty"` - EnvironmentDigest string `json:"environment_digest,omitempty"` - SDKVersion string `json:"sdk_version,omitempty"` + Handler string `json:"handler"` + Source string `json:"source,omitempty"` + Mode string `json:"mode"` + NullPolicy string `json:"null_policy"` + ABIContract string `json:"abi_contract"` + AdapterVersion string `json:"adapter_version"` + ArtifactDigest string `json:"artifact_digest,omitempty"` + EnvironmentDigest string `json:"environment_digest,omitempty"` + SDKVersion string `json:"sdk_version,omitempty"` + ArgTypes []PythonTypeDescriptor `json:"arg_types,omitempty"` + ReturnType *PythonTypeDescriptor `json:"return_type,omitempty"` +} + +// PythonTypeDescriptor is the single Arrow ABI descriptor used by both plan +// resolution and the Python adapter. The UDF package keeps it as an alias so +// the catalog body and the Arrow metadata cannot drift independently. +type PythonTypeDescriptor = pythonudf.TypeDescriptor + +func NewPythonTypeDescriptor(typ types.Type) (PythonTypeDescriptor, error) { + return pythonudf.NewTypeDescriptor(typ) } type Arg struct { @@ -59,15 +77,51 @@ func (u *Udf) GetPlanExpr() *plan.Expr { } func (u *Udf) GetArgsPlanType() []*plan.Type { - result := make([]*plan.Type, len(u.ArgsType)) - for i, typ := range u.ArgsType { + args := u.GetArgsType() + result := make([]*plan.Type, len(args)) + for i, typ := range args { result[i] = type2PlanType(typ) } return result } func (u *Udf) GetRetPlanType() *plan.Type { return type2PlanType(u.GetRetType()) } -func (u *Udf) GetArgsType() []types.Type { return u.ArgsType } -func (u *Udf) GetRetType() types.Type { return types.Types[u.RetType].ToType() } +func (u *Udf) GetArgsType() []types.Type { + if len(u.PythonArgTypes) != 0 { + args := make([]types.Type, len(u.PythonArgTypes)) + for i, descriptor := range u.PythonArgTypes { + args[i] = descriptor.Type() + } + return args + } + return u.ArgsType +} +func (u *Udf) GetRetType() types.Type { + if u.PythonReturnType != nil { + return u.PythonReturnType.Type() + } + return types.Types[u.RetType].ToType() +} + +// LoadPythonTypeContract copies exact type metadata persisted in the Python +// routine body into the plan object. Older catalog rows have no such fields +// and intentionally retain the legacy logical-type fallback. +func (u *Udf) LoadPythonTypeContract() error { + if u.Language != "python" { + return nil + } + body := PythonRoutineBody{} + if err := json.Unmarshal([]byte(u.Body), &body); err != nil { + return err + } + if len(body.ArgTypes) != 0 { + u.PythonArgTypes = append([]PythonTypeDescriptor(nil), body.ArgTypes...) + } + if body.ReturnType != nil { + returnType := *body.ReturnType + u.PythonReturnType = &returnType + } + return nil +} func type2PlanType(typ types.Type) *plan.Type { return &plan.Type{Id: int32(typ.Oid), Width: typ.Width, Scale: typ.Scale, Charset: uint32(typ.Charset)} } diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go new file mode 100644 index 0000000000000..1217fa5e59dd9 --- /dev/null +++ b/pkg/sql/plan/function/udf_test.go @@ -0,0 +1,56 @@ +// Copyright 2026 Matrix Origin +// +// 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 function + +import ( + "encoding/json" + "testing" + + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/stretchr/testify/require" +) + +func TestPythonTypeContractPreservesDeclaredShape(t *testing.T) { + argument := types.New(types.T_decimal64, 18, 6) + returnType := types.New(types.T_varchar, 64, 0) + argumentDescriptor, err := NewPythonTypeDescriptor(argument) + require.NoError(t, err) + returnDescriptor, err := NewPythonTypeDescriptor(returnType) + require.NoError(t, err) + body, err := json.Marshal(PythonRoutineBody{ + ArgTypes: []PythonTypeDescriptor{argumentDescriptor}, + ReturnType: &returnDescriptor, + }) + require.NoError(t, err) + + routine := &Udf{Language: "python", Body: string(body), ArgsType: []types.Type{types.T_decimal64.ToType()}} + require.NoError(t, routine.LoadPythonTypeContract()) + require.Equal(t, argument, routine.GetArgsType()[0]) + require.Equal(t, returnType, routine.GetRetType()) + require.Equal(t, int32(6), routine.GetArgsPlanType()[0].Scale) + require.Equal(t, int32(64), routine.GetRetPlanType().Width) +} + +func TestPythonTypeContractKeepsLegacyFallback(t *testing.T) { + routine := &Udf{ + Language: "python", + Body: `{"handler":"legacy","source":"def legacy(ctx, x): return x"}`, + ArgsType: []types.Type{types.T_int32.ToType()}, + RetType: "int", + } + require.NoError(t, routine.LoadPythonTypeContract()) + require.Equal(t, types.T_int32.ToType(), routine.GetArgsType()[0]) + require.Equal(t, types.T_int32.ToType(), routine.GetRetType()) +} diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index aa26968e6bf02..6a8a31a9beeca 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -6,6 +6,7 @@ import pathlib import sys import unittest +import uuid import pyarrow as pa @@ -51,6 +52,23 @@ def test_zero_temporal_is_distinct_from_null(self): self.assertEqual(True, array.field("is_zero")[0].as_py()) self.assertEqual(datetime.date(1970, 1, 1), array.field("value")[0].as_py()) + def test_json_input_is_canonicalized_before_handler(self): + descriptor = {"type_id": worker.JSON, "offset_width": 32, "json_encoding": "canonical_text"} + array = pa.array(['{"b": [true, null, "中"], "a": 1}'], type=pa.string()) + self.assertEqual( + '{"b":[true,null,"中"],"a":1}', + worker._scalar_input(array, 0, descriptor), + ) + + def test_uuid_scalar_round_trip_keeps_uuid_object_until_array_encoding(self): + descriptor = {"type_id": worker.UUID, "offset_width": 0} + value = uuid.UUID("123e4567-e89b-12d3-a456-426614174000") + checked = worker._check_scalar(value, descriptor) + self.assertIsInstance(checked, uuid.UUID) + array = worker._output_array([checked, None], descriptor, 2) + self.assertEqual(value.bytes, array[0].as_py()) + self.assertIsNone(array[1].as_py()) + def test_scalar_value_domain_is_checked_before_arrow_encoding(self): string_descriptor = {"type_id": worker.VARCHAR, "width": 3, "offset_width": 32} with self.assertRaisesRegex(ValueError, "string exceeds"): diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 9dd4b68e2c3ef..9c3a8d6fdfa3d 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -457,19 +457,28 @@ def _scalar_input(array: pa.Array, row: int, descriptor: Dict[str, Any]): if type_id == DATETIME: return SqlDatetime(zero, None if zero else child) return SqlTimestamp(zero, None if zero else child) + if type_id == JSON: + return _canonical_json_text(value) if type_id == UUID: return _uuid.UUID(bytes=bytes(value)) return value -def _check_json(value: str) -> str: +def _canonical_json_text(value: str) -> str: if not isinstance(value, str): - raise ValueError("TYPE_CONTRACT: JSON result must be canonical text") + raise ValueError("TYPE_CONTRACT: JSON value must be text") try: parsed = json.loads(value) except Exception as exc: - raise ValueError("TYPE_CONTRACT: invalid JSON result") from exc - canonical = json.dumps(parsed, ensure_ascii=False, separators=(",", ":")) + raise ValueError("TYPE_CONTRACT: invalid JSON input") from exc + return json.dumps(parsed, ensure_ascii=False, separators=(",", ":")) + + +def _check_json(value: str) -> str: + try: + canonical = _canonical_json_text(value) + except ValueError as exc: + raise ValueError("TYPE_CONTRACT: JSON result must be canonical text") from exc if canonical != value: raise ValueError("TYPE_CONTRACT: JSON result is not canonical text") return value @@ -508,7 +517,7 @@ def _check_scalar(value: Any, descriptor: Dict[str, Any]): return value if type_id == UUID: if not isinstance(value, _uuid.UUID): raise ValueError("TYPE_CONTRACT: expected uuid.UUID") - return value.bytes + return value if type_id == TIME: if not isinstance(value, _datetime.timedelta): raise ValueError("TYPE_CONTRACT: expected datetime.timedelta") micros = _timedelta_micros(value) diff --git a/test/distributed/cases/udf_python/README.md b/test/distributed/cases/udf_python/README.md index 8c717c7021153..2efd69b2cbbd4 100644 --- a/test/distributed/cases/udf_python/README.md +++ b/test/distributed/cases/udf_python/README.md @@ -26,3 +26,22 @@ cd /path/to/mo-tester The ordinary launch manifest starts one worker for the single CN. Compose BVT starts one isolated worker service per CN from the same pinned image, so adding a SQL case here does not require another CI workflow. + +The cases keep the data sets small and target contract boundaries: + +- `control_flow.sql` checks NULL delivery, handler-produced NULL, multiple + arguments, zero-argument scalar calls, CASE selection, and empty input. +- `numeric_boundaries.sql` checks signed and unsigned integer limits, floating + point values, booleans, decimal scale, and NULL. +- `value_types.sql` checks empty and Unicode text, binary values, canonical JSON, + UUID round trips, and NULL. +- `temporal_boundaries.sql` checks leap days, microseconds, TIME limits, SQL + zero-date values, and NULL. + +The shape follows established correctness coverage from +[DuckDB's scalar UDF tests](https://github.com/duckdb/duckdb-go/blob/main/scalar_udf_test.go) +(NULLs, multiple rows, multiple arguments, and errors) and +[Apache Arrow's extension type tests](https://github.com/apache/arrow/blob/main/python/pyarrow/tests/test_extension_type.py) +(null-aware arrays, fixed-size binary values, and type validation). The SQL +cases adapt those ideas to MatrixOne's Python Arrow boundary rather than +copying another project's implementation. diff --git a/test/distributed/cases/udf_python/control_flow.result b/test/distributed/cases/udf_python/control_flow.result new file mode 100644 index 0000000000000..c43e9bf1c0fc0 --- /dev/null +++ b/test/distributed/cases/udf_python/control_flow.result @@ -0,0 +1,51 @@ +drop database if exists udf_python_control_bvt; +create database udf_python_control_bvt; +use udf_python_control_bvt; +create function python_bvt_mark_null (x varchar(32)) returns varchar(64) language python as 'def python_bvt_mark_null(ctx, x): return "" if x is None else "<" + x + ">"' handler 'python_bvt_mark_null'; +create function python_bvt_add_one (x int) returns int language python as 'def python_bvt_add_one(ctx, x): return None if x is None else x + 1' handler 'python_bvt_add_one'; +create function python_bvt_add_pair (x int, y int) returns int language python as 'def python_bvt_add_pair(ctx, x, y): return None if x is None or y is None else x + y' handler 'python_bvt_add_pair'; +create function python_bvt_zero_arg () returns int language python as 'def python_bvt_zero_arg(ctx): return 7' handler 'python_bvt_zero_arg'; +create function python_bvt_must_not_run (x int) returns int language python as 'def python_bvt_must_not_run(ctx, x): raise RuntimeError("unselected Python branch was executed")' handler 'python_bvt_must_not_run'; +create function python_bvt_empty_input (x int) returns int language python as 'def python_bvt_empty_input(ctx, x): raise RuntimeError("empty input was executed")' handler 'python_bvt_empty_input'; +create table control_values (id int, label varchar(32), value int); +insert into control_values values +(1, 'empty', 1), +(2, '中😀', 2), +(3, null, 3); +select id, python_bvt_mark_null(label) as marked +from control_values order by id; +➤ id[4,32,0] ¦ marked[12,64,0] 𝄀 +1 ¦ 𝄀 +2 ¦ <中😀> 𝄀 +3 ¦ +select id, python_bvt_zero_arg() as constant +from control_values order by id; +➤ id[4,32,0] ¦ constant[4,32,0] 𝄀 +1 ¦ 7 𝄀 +2 ¦ 7 𝄀 +3 ¦ 7 +select id, python_bvt_add_pair(value, id) as pair_sum +from control_values order by id; +➤ id[4,32,0] ¦ pair_sum[4,32,0] 𝄀 +1 ¦ 2 𝄀 +2 ¦ 4 𝄀 +3 ¦ 6 +select id, +case when value < 0 then python_bvt_must_not_run(value) +else 99 end as guarded +from control_values order by id; +➤ id[4,32,0] ¦ guarded[-5,64,0] 𝄀 +1 ¦ 99 𝄀 +2 ¦ 99 𝄀 +3 ¦ 99 +select python_bvt_empty_input(value) as never_returned +from control_values where 1 = 0; +➤ never_returned[4,32,0] +drop function python_bvt_mark_null(varchar(32)); +drop function python_bvt_add_one(int); +drop function python_bvt_add_pair(int, int); +drop function python_bvt_zero_arg(); +drop function python_bvt_must_not_run(int); +drop function python_bvt_empty_input(int); +drop table control_values; +drop database udf_python_control_bvt; diff --git a/test/distributed/cases/udf_python/control_flow.sql b/test/distributed/cases/udf_python/control_flow.sql new file mode 100644 index 0000000000000..956e83e0988f3 --- /dev/null +++ b/test/distributed/cases/udf_python/control_flow.sql @@ -0,0 +1,49 @@ +-- Correctness boundaries for scalar invocation, NULL handling, empty input, +-- zero-argument calls, and CASE selection masks. +drop database if exists udf_python_control_bvt; +create database udf_python_control_bvt; +use udf_python_control_bvt; + +create function python_bvt_mark_null (x varchar(32)) returns varchar(64) language python as 'def python_bvt_mark_null(ctx, x): return "" if x is None else "<" + x + ">"' handler 'python_bvt_mark_null'; +create function python_bvt_add_one (x int) returns int language python as 'def python_bvt_add_one(ctx, x): return None if x is None else x + 1' handler 'python_bvt_add_one'; +create function python_bvt_add_pair (x int, y int) returns int language python as 'def python_bvt_add_pair(ctx, x, y): return None if x is None or y is None else x + y' handler 'python_bvt_add_pair'; +create function python_bvt_zero_arg () returns int language python as 'def python_bvt_zero_arg(ctx): return 7' handler 'python_bvt_zero_arg'; +create function python_bvt_must_not_run (x int) returns int language python as 'def python_bvt_must_not_run(ctx, x): raise RuntimeError("unselected Python branch was executed")' handler 'python_bvt_must_not_run'; +create function python_bvt_empty_input (x int) returns int language python as 'def python_bvt_empty_input(ctx, x): raise RuntimeError("empty input was executed")' handler 'python_bvt_empty_input'; + +create table control_values (id int, label varchar(32), value int); +insert into control_values values + (1, 'empty', 1), + (2, '中😀', 2), + (3, null, 3); + +-- The default policy passes NULL to the handler and preserves a handler NULL. +select id, python_bvt_mark_null(label) as marked +from control_values order by id; + +-- A zero-argument scalar still produces one result per input row. +select id, python_bvt_zero_arg() as constant +from control_values order by id; + +-- Multiple arguments preserve row order and NULLs independently. +select id, python_bvt_add_pair(value, id) as pair_sum +from control_values order by id; + +-- A CASE branch with no selected rows must not invoke its Python handler. +select id, + case when value < 0 then python_bvt_must_not_run(value) + else 99 end as guarded +from control_values order by id; + +-- An empty input batch must finish without opening a worker invocation. +select python_bvt_empty_input(value) as never_returned +from control_values where 1 = 0; + +drop function python_bvt_mark_null(varchar(32)); +drop function python_bvt_add_one(int); +drop function python_bvt_add_pair(int, int); +drop function python_bvt_zero_arg(); +drop function python_bvt_must_not_run(int); +drop function python_bvt_empty_input(int); +drop table control_values; +drop database udf_python_control_bvt; diff --git a/test/distributed/cases/udf_python/numeric_boundaries.result b/test/distributed/cases/udf_python/numeric_boundaries.result new file mode 100644 index 0000000000000..27cddaf47fda9 --- /dev/null +++ b/test/distributed/cases/udf_python/numeric_boundaries.result @@ -0,0 +1,70 @@ +drop database if exists udf_python_numeric_bvt; +create database udf_python_numeric_bvt; +use udf_python_numeric_bvt; +create function python_bvt_tinyint (x tinyint) returns tinyint language python as 'def python_bvt_tinyint(ctx, x): return x' handler 'python_bvt_tinyint'; +create function python_bvt_smallint (x smallint) returns smallint language python as 'def python_bvt_smallint(ctx, x): return x' handler 'python_bvt_smallint'; +create function python_bvt_int (x int) returns int language python as 'def python_bvt_int(ctx, x): return x' handler 'python_bvt_int'; +create function python_bvt_bigint (x bigint) returns bigint language python as 'def python_bvt_bigint(ctx, x): return x' handler 'python_bvt_bigint'; +create function python_bvt_tinyuint (x tinyint unsigned) returns tinyint unsigned language python as 'def python_bvt_tinyuint(ctx, x): return x' handler 'python_bvt_tinyuint'; +create function python_bvt_smalluint (x smallint unsigned) returns smallint unsigned language python as 'def python_bvt_smalluint(ctx, x): return x' handler 'python_bvt_smalluint'; +create function python_bvt_uint (x int unsigned) returns int unsigned language python as 'def python_bvt_uint(ctx, x): return x' handler 'python_bvt_uint'; +create function python_bvt_biguint (x bigint unsigned) returns bigint unsigned language python as 'def python_bvt_biguint(ctx, x): return x' handler 'python_bvt_biguint'; +create function python_bvt_float (x float) returns float language python as 'def python_bvt_float(ctx, x): return x' handler 'python_bvt_float'; +create function python_bvt_double (x double) returns double language python as 'def python_bvt_double(ctx, x): return x' handler 'python_bvt_double'; +create function python_bvt_bool (x bool) returns bool language python as 'def python_bvt_bool(ctx, x): return x' handler 'python_bvt_bool'; +create function python_bvt_decimal64 (x decimal(18,6)) returns decimal(18,6) language python as 'def python_bvt_decimal64(ctx, x): return x' handler 'python_bvt_decimal64'; +create function python_bvt_decimal128 (x decimal(38,10)) returns decimal(38,10) language python as 'def python_bvt_decimal128(ctx, x): return x' handler 'python_bvt_decimal128'; +create table numeric_values ( +tiny_v tinyint, +small_v smallint, +int_v int, +big_v bigint, +tiny_u tinyint unsigned, +small_u smallint unsigned, +int_u int unsigned, +big_u bigint unsigned, +float_v float, +double_v double, +bool_v bool, +decimal64_v decimal(18,6), +decimal128_v decimal(38,10) +); +insert into numeric_values values +(-128, -32768, -2147483648, -9223372036854775808, +0, 0, 0, 0, -0.0, -0.0, false, -0.000001, -9999999999999999999999999999.9999999999), +(127, 32767, 2147483647, 9223372036854775807, +255, 65535, 4294967295, 18446744073709551615, 3.25, 1.0, true, 999999999999.999999, 9999999999999999999999999999.9999999999), +(null, null, null, null, null, null, null, null, null, null, null, null, null); +select python_bvt_tinyint(tiny_v) as tiny_v, +python_bvt_smallint(small_v) as small_v, +python_bvt_int(int_v) as int_v, +python_bvt_bigint(big_v) as big_v, +python_bvt_tinyuint(tiny_u) as tiny_u, +python_bvt_smalluint(small_u) as small_u, +python_bvt_uint(int_u) as int_u, +python_bvt_biguint(big_u) as big_u, +python_bvt_float(float_v) as float_v, +python_bvt_double(double_v) as double_v, +python_bvt_bool(bool_v) as bool_v, +python_bvt_decimal64(decimal64_v) as decimal64_v, +python_bvt_decimal128(decimal128_v) as decimal128_v +from numeric_values order by big_v is null, big_v; +➤ tiny_v[-6,8,0] ¦ small_v[5,16,0] ¦ int_v[4,32,0] ¦ big_v[-5,64,0] ¦ tiny_u[-6,8,0] ¦ small_u[5,16,0] ¦ int_u[4,32,0] ¦ big_u[-5,64,0] ¦ float_v[7,23,31] ¦ double_v[8,53,31] ¦ bool_v[-7,1,0] ¦ decimal64_v[3,18,6] ¦ decimal128_v[3,38,10] 𝄀 +-128 ¦ -32768 ¦ -2147483648 ¦ -9223372036854775808 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ -0.0 ¦ -0.0 ¦ 0 ¦ -0.000001 ¦ -9999999999999999999999999999.9999999999 𝄀 +127 ¦ 32767 ¦ 2147483647 ¦ 9223372036854775807 ¦ 255 ¦ 65535 ¦ 4294967295 ¦ 18446744073709551615 ¦ 3.25 ¦ 1.0 ¦ 1 ¦ 999999999999.999999 ¦ 9999999999999999999999999999.9999999999 𝄀 +null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null +drop function python_bvt_tinyint(tinyint); +drop function python_bvt_smallint(smallint); +drop function python_bvt_int(int); +drop function python_bvt_bigint(bigint); +drop function python_bvt_tinyuint(tinyint unsigned); +drop function python_bvt_smalluint(smallint unsigned); +drop function python_bvt_uint(int unsigned); +drop function python_bvt_biguint(bigint unsigned); +drop function python_bvt_float(float); +drop function python_bvt_double(double); +drop function python_bvt_bool(bool); +drop function python_bvt_decimal64(decimal(18,6)); +drop function python_bvt_decimal128(decimal(38,10)); +drop table numeric_values; +drop database udf_python_numeric_bvt; diff --git a/test/distributed/cases/udf_python/numeric_boundaries.sql b/test/distributed/cases/udf_python/numeric_boundaries.sql new file mode 100644 index 0000000000000..0c00e1f813be5 --- /dev/null +++ b/test/distributed/cases/udf_python/numeric_boundaries.sql @@ -0,0 +1,72 @@ +-- Small, exact boundary values for every scalar numeric family supported by +-- the Python Arrow adapter. +drop database if exists udf_python_numeric_bvt; +create database udf_python_numeric_bvt; +use udf_python_numeric_bvt; + +create function python_bvt_tinyint (x tinyint) returns tinyint language python as 'def python_bvt_tinyint(ctx, x): return x' handler 'python_bvt_tinyint'; +create function python_bvt_smallint (x smallint) returns smallint language python as 'def python_bvt_smallint(ctx, x): return x' handler 'python_bvt_smallint'; +create function python_bvt_int (x int) returns int language python as 'def python_bvt_int(ctx, x): return x' handler 'python_bvt_int'; +create function python_bvt_bigint (x bigint) returns bigint language python as 'def python_bvt_bigint(ctx, x): return x' handler 'python_bvt_bigint'; +create function python_bvt_tinyuint (x tinyint unsigned) returns tinyint unsigned language python as 'def python_bvt_tinyuint(ctx, x): return x' handler 'python_bvt_tinyuint'; +create function python_bvt_smalluint (x smallint unsigned) returns smallint unsigned language python as 'def python_bvt_smalluint(ctx, x): return x' handler 'python_bvt_smalluint'; +create function python_bvt_uint (x int unsigned) returns int unsigned language python as 'def python_bvt_uint(ctx, x): return x' handler 'python_bvt_uint'; +create function python_bvt_biguint (x bigint unsigned) returns bigint unsigned language python as 'def python_bvt_biguint(ctx, x): return x' handler 'python_bvt_biguint'; +create function python_bvt_float (x float) returns float language python as 'def python_bvt_float(ctx, x): return x' handler 'python_bvt_float'; +create function python_bvt_double (x double) returns double language python as 'def python_bvt_double(ctx, x): return x' handler 'python_bvt_double'; +create function python_bvt_bool (x bool) returns bool language python as 'def python_bvt_bool(ctx, x): return x' handler 'python_bvt_bool'; +create function python_bvt_decimal64 (x decimal(18,6)) returns decimal(18,6) language python as 'def python_bvt_decimal64(ctx, x): return x' handler 'python_bvt_decimal64'; +create function python_bvt_decimal128 (x decimal(38,10)) returns decimal(38,10) language python as 'def python_bvt_decimal128(ctx, x): return x' handler 'python_bvt_decimal128'; + +create table numeric_values ( + tiny_v tinyint, + small_v smallint, + int_v int, + big_v bigint, + tiny_u tinyint unsigned, + small_u smallint unsigned, + int_u int unsigned, + big_u bigint unsigned, + float_v float, + double_v double, + bool_v bool, + decimal64_v decimal(18,6), + decimal128_v decimal(38,10) +); +insert into numeric_values values + (-128, -32768, -2147483648, -9223372036854775808, + 0, 0, 0, 0, -0.0, -0.0, false, -0.000001, -9999999999999999999999999999.9999999999), + (127, 32767, 2147483647, 9223372036854775807, + 255, 65535, 4294967295, 18446744073709551615, 3.25, 1.0, true, 999999999999.999999, 9999999999999999999999999999.9999999999), + (null, null, null, null, null, null, null, null, null, null, null, null, null); + +select python_bvt_tinyint(tiny_v) as tiny_v, + python_bvt_smallint(small_v) as small_v, + python_bvt_int(int_v) as int_v, + python_bvt_bigint(big_v) as big_v, + python_bvt_tinyuint(tiny_u) as tiny_u, + python_bvt_smalluint(small_u) as small_u, + python_bvt_uint(int_u) as int_u, + python_bvt_biguint(big_u) as big_u, + python_bvt_float(float_v) as float_v, + python_bvt_double(double_v) as double_v, + python_bvt_bool(bool_v) as bool_v, + python_bvt_decimal64(decimal64_v) as decimal64_v, + python_bvt_decimal128(decimal128_v) as decimal128_v +from numeric_values order by big_v is null, big_v; + +drop function python_bvt_tinyint(tinyint); +drop function python_bvt_smallint(smallint); +drop function python_bvt_int(int); +drop function python_bvt_bigint(bigint); +drop function python_bvt_tinyuint(tinyint unsigned); +drop function python_bvt_smalluint(smallint unsigned); +drop function python_bvt_uint(int unsigned); +drop function python_bvt_biguint(bigint unsigned); +drop function python_bvt_float(float); +drop function python_bvt_double(double); +drop function python_bvt_bool(bool); +drop function python_bvt_decimal64(decimal(18,6)); +drop function python_bvt_decimal128(decimal(38,10)); +drop table numeric_values; +drop database udf_python_numeric_bvt; diff --git a/test/distributed/cases/udf_python/temporal_boundaries.result b/test/distributed/cases/udf_python/temporal_boundaries.result new file mode 100644 index 0000000000000..1c90a1f65d00a --- /dev/null +++ b/test/distributed/cases/udf_python/temporal_boundaries.result @@ -0,0 +1,41 @@ +drop database if exists udf_python_temporal_bvt; +create database udf_python_temporal_bvt; +use udf_python_temporal_bvt; +create function python_bvt_date (x date) returns date language python as 'def python_bvt_date(ctx, x): return x' handler 'python_bvt_date'; +create function python_bvt_datetime (x datetime(6)) returns datetime(6) language python as 'def python_bvt_datetime(ctx, x): return x' handler 'python_bvt_datetime'; +create function python_bvt_timestamp (x timestamp(6)) returns timestamp(6) language python as 'def python_bvt_timestamp(ctx, x): return x' handler 'python_bvt_timestamp'; +create function python_bvt_time (x time(6)) returns time(6) language python as 'def python_bvt_time(ctx, x): return x' handler 'python_bvt_time'; +create table temporal_values ( +id int, +date_v date, +datetime_v datetime(6), +timestamp_v timestamp(6), +time_v time(6) +); +insert into temporal_values values +(1, '2024-02-29', '2024-02-29 23:59:59.123456', '2024-02-29 23:59:59.123456', '-838:59:59'), +(2, '2024-03-01', '2024-03-01 00:00:00.000000', '2024-03-01 00:00:00.000000', '838:59:59'), +(3, null, null, null, null); +select id, python_bvt_date(date_v) as date_v, +python_bvt_datetime(datetime_v) as datetime_v, +python_bvt_timestamp(timestamp_v) as timestamp_v, +python_bvt_time(time_v) as time_v +from temporal_values order by id; +➤ id[4,32,0] ¦ date_v[91,10,0] ¦ datetime_v[93,26,0] ¦ timestamp_v[93,26,0] ¦ time_v[92,17,0] 𝄀 +1 ¦ 2024-02-29 ¦ 2024-02-29 23:59:59.123456000 ¦ 2024-02-29 23:59:59.123456000 ¦ -838:59:59 𝄀 +2 ¦ 2024-03-01 ¦ 2024-03-01 00:00:00 ¦ 2024-03-01 00:00:00 ¦ 838:59:59 𝄀 +3 ¦ null ¦ null ¦ null ¦ null +set @udf_python_saved_sql_mode = @@sql_mode; +set session sql_mode = ''; +select python_bvt_date(cast('0000-00-00' as date)) as zero_date, +python_bvt_datetime(cast('0000-00-00 00:00:00' as datetime(6))) as zero_datetime, +python_bvt_timestamp(cast('0000-00-00 00:00:00' as timestamp(6))) as zero_timestamp; +➤ zero_date[91,10,0] ¦ zero_datetime[93,26,0] ¦ zero_timestamp[93,26,0] 𝄀 +0000-00-00 ¦ 0000-00-00 00:00:00 ¦ 0000-00-00 00:00:00 +set session sql_mode = @udf_python_saved_sql_mode; +drop function python_bvt_date(date); +drop function python_bvt_datetime(datetime(6)); +drop function python_bvt_timestamp(timestamp(6)); +drop function python_bvt_time(time(6)); +drop table temporal_values; +drop database udf_python_temporal_bvt; diff --git a/test/distributed/cases/udf_python/temporal_boundaries.sql b/test/distributed/cases/udf_python/temporal_boundaries.sql new file mode 100644 index 0000000000000..502107777c7bb --- /dev/null +++ b/test/distributed/cases/udf_python/temporal_boundaries.sql @@ -0,0 +1,43 @@ +-- SQL temporal values, including the explicit zero-date representation that +-- cannot be represented by Python's datetime.date/datetime classes. +drop database if exists udf_python_temporal_bvt; +create database udf_python_temporal_bvt; +use udf_python_temporal_bvt; + +create function python_bvt_date (x date) returns date language python as 'def python_bvt_date(ctx, x): return x' handler 'python_bvt_date'; +create function python_bvt_datetime (x datetime(6)) returns datetime(6) language python as 'def python_bvt_datetime(ctx, x): return x' handler 'python_bvt_datetime'; +create function python_bvt_timestamp (x timestamp(6)) returns timestamp(6) language python as 'def python_bvt_timestamp(ctx, x): return x' handler 'python_bvt_timestamp'; +create function python_bvt_time (x time(6)) returns time(6) language python as 'def python_bvt_time(ctx, x): return x' handler 'python_bvt_time'; + +create table temporal_values ( + id int, + date_v date, + datetime_v datetime(6), + timestamp_v timestamp(6), + time_v time(6) +); +insert into temporal_values values + (1, '2024-02-29', '2024-02-29 23:59:59.123456', '2024-02-29 23:59:59.123456', '-838:59:59'), + (2, '2024-03-01', '2024-03-01 00:00:00.000000', '2024-03-01 00:00:00.000000', '838:59:59'), + (3, null, null, null, null); + +select id, python_bvt_date(date_v) as date_v, + python_bvt_datetime(datetime_v) as datetime_v, + python_bvt_timestamp(timestamp_v) as timestamp_v, + python_bvt_time(time_v) as time_v +from temporal_values order by id; + +-- Zero temporal values are valid values and must stay distinct from SQL NULL. +set @udf_python_saved_sql_mode = @@sql_mode; +set session sql_mode = ''; +select python_bvt_date(cast('0000-00-00' as date)) as zero_date, + python_bvt_datetime(cast('0000-00-00 00:00:00' as datetime(6))) as zero_datetime, + python_bvt_timestamp(cast('0000-00-00 00:00:00' as timestamp(6))) as zero_timestamp; +set session sql_mode = @udf_python_saved_sql_mode; + +drop function python_bvt_date(date); +drop function python_bvt_datetime(datetime(6)); +drop function python_bvt_timestamp(timestamp(6)); +drop function python_bvt_time(time(6)); +drop table temporal_values; +drop database udf_python_temporal_bvt; diff --git a/test/distributed/cases/udf_python/value_types.result b/test/distributed/cases/udf_python/value_types.result new file mode 100644 index 0000000000000..26b59820c098e --- /dev/null +++ b/test/distributed/cases/udf_python/value_types.result @@ -0,0 +1,72 @@ +drop database if exists udf_python_values_bvt; +create database udf_python_values_bvt; +use udf_python_values_bvt; +create function python_bvt_varchar (x varchar(64)) returns varchar(64) language python as 'def python_bvt_varchar(ctx, x): return x' handler 'python_bvt_varchar'; +create function python_bvt_text (x text) returns text language python as 'def python_bvt_text(ctx, x): return x' handler 'python_bvt_text'; +create function python_bvt_varbinary (x varbinary(8)) returns varbinary(8) language python as 'def python_bvt_varbinary(ctx, x): return x' handler 'python_bvt_varbinary'; +create function python_bvt_blob (x blob) returns blob language python as 'def python_bvt_blob(ctx, x): return x' handler 'python_bvt_blob'; +create function python_bvt_json (x json) returns json language python as 'def python_bvt_json(ctx, x): return None if x is None else __import__("json").dumps(__import__("json").loads(x), ensure_ascii=False, separators=(",", ":"))' handler 'python_bvt_json'; +create function python_bvt_uuid (x uuid) returns uuid language python as 'def python_bvt_uuid(ctx, x): return x' handler 'python_bvt_uuid'; +create table text_values (id int, value varchar(64), long_value text); +insert into text_values values +(1, '', repeat('a', 64)), +(2, '中😀', '数据库'), +(3, repeat('v', 64), repeat('b', 64)), +(4, null, null); +select id, python_bvt_varchar(value) as value, +python_bvt_text(long_value) as long_value +from text_values order by id; +➤ id[4,32,0] ¦ value[12,64,0] ¦ long_value[-1,16383,0] 𝄀 +1 ¦ ¦ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 𝄀 +2 ¦ 中😀 ¦ 数据库 𝄀 +3 ¦ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv ¦ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 𝄀 +4 ¦ null ¦ null +create table binary_values (id int, var_value varbinary(8), blob_value blob); +insert into binary_values values +(1, unhex(''), unhex('')), +(2, unhex('00010203ff'), unhex('00ff10')), +(3, unhex('00010203ff060708'), unhex('00010203ff060708')), +(4, null, null); +select id, hex(python_bvt_varbinary(var_value)) as var_value, +hex(python_bvt_blob(blob_value)) as blob_value +from binary_values order by id; +➤ id[4,32,0] ¦ var_value[12,16,0] ¦ blob_value[-1,16383,0] 𝄀 +1 ¦ ¦ 𝄀 +2 ¦ 00010203FF ¦ 00FF10 𝄀 +3 ¦ 00010203FF060708 ¦ 00010203FF060708 𝄀 +4 ¦ null ¦ null +create table json_values (id int, value json); +insert into json_values values +(1, '{}'), +(2, '{"a":1,"b":[true,null,"中"]}'), +(3, '1'), +(4, null); +select id, python_bvt_json(value) as value +from json_values order by id; +➤ id[4,32,0] ¦ value[-1,2147483647,0] 𝄀 +1 ¦ {} 𝄀 +2 ¦ {"a": 1, "b": [true, null, "中"]} 𝄀 +3 ¦ 1 𝄀 +4 ¦ null +create table uuid_values (id int, value uuid); +insert into uuid_values values +(1, cast('00000000-0000-0000-0000-000000000000' as uuid)), +(2, cast('123e4567-e89b-12d3-a456-426614174000' as uuid)), +(3, null); +select id, python_bvt_uuid(value) as value +from uuid_values order by id; +➤ id[4,32,0] ¦ value[12,-1,0] 𝄀 +1 ¦ 00000000-0000-0000-0000-000000000000 𝄀 +2 ¦ 123e4567-e89b-12d3-a456-426614174000 𝄀 +3 ¦ null +drop function python_bvt_varchar(varchar(64)); +drop function python_bvt_text(text); +drop function python_bvt_varbinary(varbinary(8)); +drop function python_bvt_blob(blob); +drop function python_bvt_json(json); +drop function python_bvt_uuid(uuid); +drop table text_values; +drop table binary_values; +drop table json_values; +drop table uuid_values; +drop database udf_python_values_bvt; diff --git a/test/distributed/cases/udf_python/value_types.sql b/test/distributed/cases/udf_python/value_types.sql new file mode 100644 index 0000000000000..a9497376d4fb0 --- /dev/null +++ b/test/distributed/cases/udf_python/value_types.sql @@ -0,0 +1,64 @@ +-- Boundary values for variable-width text, binary payloads, JSON, and UUID. +drop database if exists udf_python_values_bvt; +create database udf_python_values_bvt; +use udf_python_values_bvt; + +create function python_bvt_varchar (x varchar(64)) returns varchar(64) language python as 'def python_bvt_varchar(ctx, x): return x' handler 'python_bvt_varchar'; +create function python_bvt_text (x text) returns text language python as 'def python_bvt_text(ctx, x): return x' handler 'python_bvt_text'; +create function python_bvt_varbinary (x varbinary(8)) returns varbinary(8) language python as 'def python_bvt_varbinary(ctx, x): return x' handler 'python_bvt_varbinary'; +create function python_bvt_blob (x blob) returns blob language python as 'def python_bvt_blob(ctx, x): return x' handler 'python_bvt_blob'; +create function python_bvt_json (x json) returns json language python as 'def python_bvt_json(ctx, x): return None if x is None else __import__("json").dumps(__import__("json").loads(x), ensure_ascii=False, separators=(",", ":"))' handler 'python_bvt_json'; +create function python_bvt_uuid (x uuid) returns uuid language python as 'def python_bvt_uuid(ctx, x): return x' handler 'python_bvt_uuid'; + +create table text_values (id int, value varchar(64), long_value text); +insert into text_values values + (1, '', repeat('a', 64)), + (2, '中😀', '数据库'), + (3, repeat('v', 64), repeat('b', 64)), + (4, null, null); + +select id, python_bvt_varchar(value) as value, + python_bvt_text(long_value) as long_value +from text_values order by id; + +create table binary_values (id int, var_value varbinary(8), blob_value blob); +insert into binary_values values + (1, unhex(''), unhex('')), + (2, unhex('00010203ff'), unhex('00ff10')), + (3, unhex('00010203ff060708'), unhex('00010203ff060708')), + (4, null, null); + +select id, hex(python_bvt_varbinary(var_value)) as var_value, + hex(python_bvt_blob(blob_value)) as blob_value +from binary_values order by id; + +create table json_values (id int, value json); +insert into json_values values + (1, '{}'), + (2, '{"a":1,"b":[true,null,"中"]}'), + (3, '1'), + (4, null); + +select id, python_bvt_json(value) as value +from json_values order by id; + +create table uuid_values (id int, value uuid); +insert into uuid_values values + (1, cast('00000000-0000-0000-0000-000000000000' as uuid)), + (2, cast('123e4567-e89b-12d3-a456-426614174000' as uuid)), + (3, null); + +select id, python_bvt_uuid(value) as value +from uuid_values order by id; + +drop function python_bvt_varchar(varchar(64)); +drop function python_bvt_text(text); +drop function python_bvt_varbinary(varbinary(8)); +drop function python_bvt_blob(blob); +drop function python_bvt_json(json); +drop function python_bvt_uuid(uuid); +drop table text_values; +drop table binary_values; +drop table json_values; +drop table uuid_values; +drop database udf_python_values_bvt; From 924e32810b1e0e39d735ed95a2f6ad556036630a Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 21:04:30 +0800 Subject: [PATCH 011/241] test(udf): cover null multi-argument calls --- test/distributed/cases/udf_python/control_flow.result | 4 ++-- test/distributed/cases/udf_python/control_flow.sql | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/distributed/cases/udf_python/control_flow.result b/test/distributed/cases/udf_python/control_flow.result index c43e9bf1c0fc0..1c55957986b2c 100644 --- a/test/distributed/cases/udf_python/control_flow.result +++ b/test/distributed/cases/udf_python/control_flow.result @@ -24,12 +24,12 @@ from control_values order by id; 1 ¦ 7 𝄀 2 ¦ 7 𝄀 3 ¦ 7 -select id, python_bvt_add_pair(value, id) as pair_sum +select id, python_bvt_add_pair(value, case when id = 3 then null else id end) as pair_sum from control_values order by id; ➤ id[4,32,0] ¦ pair_sum[4,32,0] 𝄀 1 ¦ 2 𝄀 2 ¦ 4 𝄀 -3 ¦ 6 +3 ¦ null select id, case when value < 0 then python_bvt_must_not_run(value) else 99 end as guarded diff --git a/test/distributed/cases/udf_python/control_flow.sql b/test/distributed/cases/udf_python/control_flow.sql index 956e83e0988f3..c60cb08619d8a 100644 --- a/test/distributed/cases/udf_python/control_flow.sql +++ b/test/distributed/cases/udf_python/control_flow.sql @@ -26,7 +26,7 @@ select id, python_bvt_zero_arg() as constant from control_values order by id; -- Multiple arguments preserve row order and NULLs independently. -select id, python_bvt_add_pair(value, id) as pair_sum +select id, python_bvt_add_pair(value, case when id = 3 then null else id end) as pair_sum from control_values order by id; -- A CASE branch with no selected rows must not invoke its Python handler. From a86ae18af44115da4165e32c739bd1ed55da8c4c Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 22:01:39 +0800 Subject: [PATCH 012/241] fix(udf): close Python execution and type contracts --- etc/launch-tae-compose/config/cn-0.toml | 2 + etc/launch-tae-compose/config/cn-1.toml | 2 + etc/launch-with-python-udf-worker/cn.toml | 2 + etc/launch/cn.toml | 1 + etc/launch/launch.toml | 4 - etc/v1/launch-with-python-udf-worker/cn.toml | 2 + optools/run_bvt.sh | 9 +- pkg/cnservice/server.go | 2 +- pkg/sql/plan/function/list_builtIn.go | 4 + pkg/sql/plan/function/python_udf.go | 16 +- pkg/sql/plan/function/udf_test.go | 25 ++ pkg/udf/python/arrow.go | 55 ++- pkg/udf/python/arrow_test.go | 44 +++ pkg/udf/python/config.go | 19 +- pkg/udf/python/config_test.go | 25 ++ pkg/udf/python/gateway.go | 3 +- pkg/udf/python/worker/test_worker.py | 65 ++++ pkg/udf/python/worker/worker.py | 323 +++++++++++++++--- test/distributed/cases/udf_python/README.md | 10 +- .../cases/udf_python/numeric_boundaries.sql | 6 + 20 files changed, 555 insertions(+), 64 deletions(-) create mode 100644 pkg/udf/python/config_test.go diff --git a/etc/launch-tae-compose/config/cn-0.toml b/etc/launch-tae-compose/config/cn-0.toml index 662553a5a8806..d75de7326e2f2 100644 --- a/etc/launch-tae-compose/config/cn-0.toml +++ b/etc/launch-tae-compose/config/cn-0.toml @@ -68,4 +68,6 @@ enable-dml = true enable-maintenance = true [cn.python-udf-client] +enabled = true +allow-unisolated = true server-address = "python-udf-worker-cn0:50051" diff --git a/etc/launch-tae-compose/config/cn-1.toml b/etc/launch-tae-compose/config/cn-1.toml index 49b1cad684d43..479e8784e4c1d 100644 --- a/etc/launch-tae-compose/config/cn-1.toml +++ b/etc/launch-tae-compose/config/cn-1.toml @@ -68,4 +68,6 @@ enable-dml = true enable-maintenance = true [cn.python-udf-client] +enabled = true +allow-unisolated = true server-address = "python-udf-worker-cn1:50051" diff --git a/etc/launch-with-python-udf-worker/cn.toml b/etc/launch-with-python-udf-worker/cn.toml index 424dc2b13c7c8..cf5b576cbc864 100644 --- a/etc/launch-with-python-udf-worker/cn.toml +++ b/etc/launch-with-python-udf-worker/cn.toml @@ -9,4 +9,6 @@ uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41bf" port-base = 18000 [cn.python-udf-client] +enabled = true +allow-unisolated = true server-address = "127.0.0.1:50051" diff --git a/etc/launch/cn.toml b/etc/launch/cn.toml index 8c315e594bb32..6348ab7e7361d 100644 --- a/etc/launch/cn.toml +++ b/etc/launch/cn.toml @@ -51,4 +51,5 @@ enable-dml = true enable-maintenance = true [cn.python-udf-client] +enabled = false server-address = "127.0.0.1:50051" diff --git a/etc/launch/launch.toml b/etc/launch/launch.toml index 19f97c824f70e..08b71744ce4e2 100644 --- a/etc/launch/launch.toml +++ b/etc/launch/launch.toml @@ -9,7 +9,3 @@ tnservices = [ cnservices = [ "./etc/launch/cn.toml" ] - -python-udf-services = [ - "./etc/launch-with-python-udf-worker/python-udf-worker.toml" -] diff --git a/etc/v1/launch-with-python-udf-worker/cn.toml b/etc/v1/launch-with-python-udf-worker/cn.toml index 424dc2b13c7c8..cf5b576cbc864 100644 --- a/etc/v1/launch-with-python-udf-worker/cn.toml +++ b/etc/v1/launch-with-python-udf-worker/cn.toml @@ -9,4 +9,6 @@ uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41bf" port-base = 18000 [cn.python-udf-client] +enabled = true +allow-unisolated = true server-address = "127.0.0.1:50051" diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index 5d53fb370bda5..0929047397241 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -22,7 +22,14 @@ PROXY=${3:-} function launch_mo() { cd $MO_WORKSPACE - ./mo-service -debug-http=:12345 -launch ./etc/$LAUNCH/launch.toml $PROXY &>mo-service.log & + # Ordinary launch BVT remains the single CI entry point, but its Python + # cases opt into the worker-enabled manifest explicitly. The generic + # etc/launch manifest stays safe for users who start mo-service directly. + local launch_config=$LAUNCH + if [[ "$LAUNCH" == "launch" ]]; then + launch_config=launch-with-python-udf-worker + fi + ./mo-service -debug-http=:12345 -launch ./etc/$launch_config/launch.toml $PROXY &>mo-service.log & } # this will wait mo all system init completed diff --git a/pkg/cnservice/server.go b/pkg/cnservice/server.go index d40fd5d698342..a89fa371adcbc 100644 --- a/pkg/cnservice/server.go +++ b/pkg/cnservice/server.go @@ -254,7 +254,7 @@ func NewService( // init UdfService var udfServices []udf.Runtime // add python client to handle python udf - if srv.cfg.PythonUdfClient.ServerAddress != "" { + if srv.cfg.PythonUdfClient.Enabled { var pc *python.Gateway pc, err = python.NewGateway(srv.cfg.PythonUdfClient) if err != nil { diff --git a/pkg/sql/plan/function/list_builtIn.go b/pkg/sql/plan/function/list_builtIn.go index cb9d4f28c2c3a..27ba6a6af55e7 100644 --- a/pkg/sql/plan/function/list_builtIn.go +++ b/pkg/sql/plan/function/list_builtIn.go @@ -16906,6 +16906,10 @@ var supportedOthersBuiltIns = []FuncNew{ { overloadId: 0, retType: pythonUdfRetType, + // A Python routine is user code. It may observe invocation + // context or maintain process-local state, so planning must never + // execute it once and broadcast the result to all rows. + volatile: true, newOp: func() executeLogicOfOverload { return runPythonUdf }, diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index 5531541f2850a..3b27d6f3e5ddb 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -42,8 +42,15 @@ func checkPythonUdf(overloads []overload, inputs []types.Type) checkResult { requiredArgs := inputs[size+1 : 2*size+1] needCast := false for i := 0; i < size; i++ { - if receivedArgs[i].Oid != requiredArgs[i].Oid { + if !pythonTypesEqual(receivedArgs[i], requiredArgs[i]) { canCast, _ := fixedImplicitTypeCast(receivedArgs[i], requiredArgs[i].Oid) + if receivedArgs[i].Oid == requiredArgs[i].Oid { + // SQL's cast executor is also the type normalizer for Python's + // frozen descriptor. In particular, DECIMAL scale and precision + // must be normalized before Arrow encoding; comparing only OID + // would reinterpret the same coefficient at the wrong scale. + canCast = true + } if !canCast { return newCheckResultWithFailure(failedFunctionParametersWrong) } @@ -62,6 +69,13 @@ func checkPythonUdf(overloads []overload, inputs []types.Type) checkResult { return newCheckResultWithSuccess(0) } +func pythonTypesEqual(left, right types.Type) bool { + return left.Oid == right.Oid && + left.Width == right.Width && + left.Scale == right.Scale && + left.Charset == right.Charset +} + // param parameters is same with param inputs in function checkPythonUdf func pythonUdfRetType(parameters []types.Type) types.Type { return parameters[len(parameters)-1] diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go index 1217fa5e59dd9..2a6ee085556c6 100644 --- a/pkg/sql/plan/function/udf_test.go +++ b/pkg/sql/plan/function/udf_test.go @@ -15,6 +15,7 @@ package function import ( + "context" "encoding/json" "testing" @@ -54,3 +55,27 @@ func TestPythonTypeContractKeepsLegacyFallback(t *testing.T) { require.Equal(t, types.T_int32.ToType(), routine.GetArgsType()[0]) require.Equal(t, types.T_int32.ToType(), routine.GetRetType()) } + +func TestPythonBindingNormalizesDecimalMetadata(t *testing.T) { + received := types.New(types.T_decimal64, 18, 2) + required := types.New(types.T_decimal64, 18, 6) + inputs := []types.Type{ + types.T_text.ToType(), + received, + required, + types.T_decimal64.ToType(), + } + result := checkPythonUdf(nil, inputs) + require.Equal(t, succeedWithCast, result.status) + require.Equal(t, required, result.finalType[1]) +} + +func TestPythonRoutineIsVolatile(t *testing.T) { + resolved, err := GetFunctionByName(context.Background(), "python_user_defined_function", []types.Type{ + types.T_text.ToType(), + types.T_text.ToType(), + }) + require.NoError(t, err) + _, overloadID := DecodeOverloadID(resolved.GetEncodedOverloadID()) + require.True(t, allSupportedFunctions[PYTHON_UDF].Overloads[overloadID].CannotFold()) +} diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index df82f10317a0c..707483a71e37e 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -24,6 +24,8 @@ import ( "errors" "fmt" "math" + "reflect" + "unicode/utf8" "github.com/apache/arrow-go/v18/arrow" "github.com/apache/arrow-go/v18/arrow/array" @@ -198,7 +200,7 @@ func (d TypeDescriptor) ValidateField(field arrow.Field) error { if err != nil { return err } - if field.Type == nil || field.Type.Fingerprint() != want.Type.Fingerprint() || field.Nullable != want.Nullable { + if field.Type == nil || !sameArrowType(field.Type, want.Type) || field.Nullable != want.Nullable { return fmt.Errorf("TYPE_CONTRACT: Arrow type %s does not match %s", field.Type, want.Type) } if !field.Metadata.Equal(want.Metadata) { @@ -207,6 +209,18 @@ func (d TypeDescriptor) ValidateField(field arrow.Field) error { return nil } +// sameArrowType intentionally compares the complete concrete Arrow type. +// Arrow-Go's Fingerprint is a physical layout fingerprint and, for some +// FixedSizeBinary versions, omits ByteWidth. A UUID contract must reject +// fixed_size_binary(1) even when that fingerprint collides with the expected +// fixed_size_binary(16). +func sameArrowType(left, right arrow.DataType) bool { + if left == nil || right == nil { + return left == right + } + return reflect.DeepEqual(left, right) +} + type ArrowFrame struct { Header []byte Body []byte @@ -700,6 +714,9 @@ func appendFloat32ArrayResult(input *array.FixedSizeList, row int, null bool, re values := input.ListValues().(*array.Float32) items := make([]float32, end-start) for i := start; i < end; i++ { + if values.IsNull(int(i)) { + return fmt.Errorf("TYPE_CONTRACT: vector child at row %d is null", row) + } items[i-start] = values.Value(int(i)) } return vector.AppendArray(result.GetResultVector(), items, false, mp) @@ -713,6 +730,9 @@ func appendFloat64ArrayResult(input *array.FixedSizeList, row int, null bool, re values := input.ListValues().(*array.Float64) items := make([]float64, end-start) for i := start; i < end; i++ { + if values.IsNull(int(i)) { + return fmt.Errorf("TYPE_CONTRACT: vector child at row %d is null", row) + } items[i-start] = values.Value(int(i)) } return vector.AppendArray(result.GetResultVector(), items, false, mp) @@ -722,7 +742,7 @@ func validateArrayType(descriptor TypeDescriptor, input arrow.Array) error { if err != nil { return err } - if input.DataType().Fingerprint() != want.Fingerprint() { + if !sameArrowType(input.DataType(), want) { return fmt.Errorf("TYPE_CONTRACT: output Arrow type %s does not match %s", input.DataType(), want) } return nil @@ -738,7 +758,7 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro } switch types.T(descriptor.TypeID) { case types.T_char, types.T_varchar, types.T_text: - if descriptor.Width > 0 && int32(len([]byte(input.(*array.String).Value(row)))) > descriptor.Width { + if descriptor.Width > 0 && int32(utf8.RuneCountInString(input.(*array.String).Value(row))) > descriptor.Width { return fmt.Errorf("TYPE_CONTRACT: string row %d exceeds width %d", row, descriptor.Width) } case types.T_binary, types.T_varbinary, types.T_blob: @@ -750,6 +770,35 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro if !types.IsMySQLTime(value) || !hasExactMicrosecondScale(int64(value), descriptor.Scale) { return fmt.Errorf("TYPE_CONTRACT: TIME row %d is outside the declared SQL domain", row) } + case types.T_decimal64, types.T_decimal128: + precision := descriptor.Width + if precision == 0 { + precision = 18 + if types.T(descriptor.TypeID) == types.T_decimal128 { + precision = 38 + } + } + if !input.(*array.Decimal128).Value(row).FitsInPrecision(precision) { + return fmt.Errorf("TYPE_CONTRACT: decimal row %d exceeds precision %d", row, precision) + } + case types.T_array_float32: + list := input.(*array.FixedSizeList) + values := list.ListValues().(*array.Float32) + start, end := list.ValueOffsets(row) + for child := start; child < end; child++ { + if values.IsNull(int(child)) { + return fmt.Errorf("TYPE_CONTRACT: vector child at row %d is null", row) + } + } + case types.T_array_float64: + list := input.(*array.FixedSizeList) + values := list.ListValues().(*array.Float64) + start, end := list.ValueOffsets(row) + for child := start; child < end; child++ { + if values.IsNull(int(child)) { + return fmt.Errorf("TYPE_CONTRACT: vector child at row %d is null", row) + } + } case types.T_date, types.T_datetime, types.T_timestamp: structValue := input.(*array.Struct) zeroField, valueField := structValue.Field(0), structValue.Field(1) diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 3898dce4413f8..7e388e4816c03 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -10,6 +10,7 @@ import ( "github.com/apache/arrow-go/v18/arrow" "github.com/apache/arrow-go/v18/arrow/array" + "github.com/apache/arrow-go/v18/arrow/decimal128" "github.com/apache/arrow-go/v18/arrow/memory" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/stretchr/testify/require" @@ -90,3 +91,46 @@ func TestArrowValueDomainRejectsWidthAndTimeOverflow(t *testing.T) { timeDescriptor := TypeDescriptor{TypeID: int32(types.T_time), Scale: 6, OffsetWidth: 32} require.ErrorContains(t, validateArrowValueDomain(timeDescriptor, times), "outside the declared SQL domain") } + +func TestArrowTypeValidationIncludesFixedBinaryWidth(t *testing.T) { + descriptor, err := NewTypeDescriptor(types.T_uuid.ToType()) + require.NoError(t, err) + builder := array.NewFixedSizeBinaryBuilder(memory.NewGoAllocator(), &arrow.FixedSizeBinaryType{ByteWidth: 1}) + builder.Append([]byte{0xff}) + values := builder.NewFixedSizeBinaryArray() + defer values.Release() + require.ErrorContains(t, validateArrayType(descriptor, values), "does not match") + + field, err := descriptor.Field("uuid") + require.NoError(t, err) + field.Type = &arrow.FixedSizeBinaryType{ByteWidth: 1} + require.ErrorContains(t, descriptor.ValidateField(field), "does not match") +} + +func TestArrowValueDomainRejectsDecimalOverflowAndNullableVectorChild(t *testing.T) { + decimalType := &arrow.Decimal128Type{Precision: 3, Scale: 0} + decimalBuilder := array.NewDecimal128Builder(memory.NewGoAllocator(), decimalType) + decimalBuilder.Append(decimal128.FromI64(1000)) + decimals := decimalBuilder.NewDecimal128Array() + defer decimals.Release() + decimalDescriptor := TypeDescriptor{TypeID: int32(types.T_decimal128), Width: 3, OffsetWidth: 32} + require.ErrorContains(t, validateArrowValueDomain(decimalDescriptor, decimals), "exceeds precision") + + listBuilder := array.NewFixedSizeListBuilder(memory.NewGoAllocator(), 2, arrow.PrimitiveTypes.Float32) + listBuilder.Append(true) + listBuilder.ValueBuilder().(*array.Float32Builder).Append(1) + listBuilder.ValueBuilder().(*array.Float32Builder).AppendNull() + lists := listBuilder.NewArray() + defer lists.Release() + vectorDescriptor := TypeDescriptor{TypeID: int32(types.T_array_float32), Width: 2} + require.ErrorContains(t, validateArrowValueDomain(vectorDescriptor, lists), "vector child") +} + +func TestArrowStringWidthCountsUnicodeCharacters(t *testing.T) { + builder := array.NewStringBuilder(memory.NewGoAllocator()) + builder.Append("中") + values := builder.NewStringArray() + defer values.Release() + descriptor := TypeDescriptor{TypeID: int32(types.T_varchar), Width: 1, OffsetWidth: 32} + require.NoError(t, validateArrowValueDomain(descriptor, values)) +} diff --git a/pkg/udf/python/config.go b/pkg/udf/python/config.go index 937736bb8a958..13ccc64588969 100644 --- a/pkg/udf/python/config.go +++ b/pkg/udf/python/config.go @@ -33,13 +33,24 @@ func (c *Config) Validate() error { } type ClientConfig struct { - ServerAddress string `toml:"server-address"` - MaxBatchBytes int64 `toml:"max-batch-bytes"` - MaxBatchRows int64 `toml:"max-batch-rows"` - RequestTimeout time.Duration `toml:"request-timeout"` + // Enabled is deliberately false by default. The Python worker is an + // unisolated development adapter until the production sandbox contract is + // deployed, so a generic CN launch must never attach it implicitly. + Enabled bool `toml:"enabled"` + AllowUnisolated bool `toml:"allow-unisolated"` + ServerAddress string `toml:"server-address"` + MaxBatchBytes int64 `toml:"max-batch-bytes"` + MaxBatchRows int64 `toml:"max-batch-rows"` + RequestTimeout time.Duration `toml:"request-timeout"` } func (c *ClientConfig) Validate() error { + if !c.Enabled { + return nil + } + if !c.AllowUnisolated { + return moerr.NewInternalError(context.Background(), "python udf requires explicit allow-unisolated until the sandbox is configured") + } if c.ServerAddress == "" { return moerr.NewInternalError(context.Background(), "missing python udf address") } diff --git a/pkg/udf/python/config_test.go b/pkg/udf/python/config_test.go new file mode 100644 index 0000000000000..090963b6709ea --- /dev/null +++ b/pkg/udf/python/config_test.go @@ -0,0 +1,25 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package python + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestClientConfigRequiresExplicitUnisolatedOptIn(t *testing.T) { + require.NoError(t, (&ClientConfig{}).Validate()) + require.NoError(t, (&ClientConfig{ServerAddress: "127.0.0.1:50051"}).Validate()) + + config := &ClientConfig{Enabled: true, ServerAddress: "127.0.0.1:50051"} + require.ErrorContains(t, config.Validate(), "allow-unisolated") + + config.AllowUnisolated = true + config.RequestTimeout = time.Second + require.NoError(t, config.Validate()) +} diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 25860017e7ba3..73084ee4561e8 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -110,6 +110,7 @@ type openPayload struct { Return TypeDescriptor `json:"return"` MaxBatchBytes int64 `json:"max_batch_bytes"` MaxBatchRows int64 `json:"max_batch_rows"` + HandlerTimeout float64 `json:"handler_timeout_seconds"` } func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, result vector.FunctionResultWrapper, mp *mpool.MPool) error { @@ -145,7 +146,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if err != nil { return err } - openBody, err := json.Marshal(openPayload{Handler: invocation.Handler, Source: invocation.Source, Mode: invocation.Mode, NullPolicy: invocation.NullPolicy, ABIContract: invocation.ABIContract, AdapterVersion: invocation.AdapterVersion, SDKVersion: invocation.SDKVersion, Context: cloneMap(invocation.Context), Args: args, Return: returnDescriptor, MaxBatchBytes: g.cfg.MaxBatchBytes, MaxBatchRows: g.cfg.MaxBatchRows}) + openBody, err := json.Marshal(openPayload{Handler: invocation.Handler, Source: invocation.Source, Mode: invocation.Mode, NullPolicy: invocation.NullPolicy, ABIContract: invocation.ABIContract, AdapterVersion: invocation.AdapterVersion, SDKVersion: invocation.SDKVersion, Context: cloneMap(invocation.Context), Args: args, Return: returnDescriptor, MaxBatchBytes: g.cfg.MaxBatchBytes, MaxBatchRows: g.cfg.MaxBatchRows, HandlerTimeout: g.cfg.RequestTimeout.Seconds()}) if err != nil { return fmt.Errorf("python udf: encode open payload: %w", err) } diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 6a8a31a9beeca..e43c07f8a49ca 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -4,7 +4,9 @@ import importlib.util import json import pathlib +import struct import sys +import time import unittest import uuid @@ -77,6 +79,69 @@ def test_scalar_value_domain_is_checked_before_arrow_encoding(self): with self.assertRaisesRegex(ValueError, "TIME is outside"): worker._output_array([datetime.timedelta(hours=839)], time_descriptor, 1) + def test_sql_string_width_counts_characters(self): + descriptor = {"type_id": worker.VARCHAR, "width": 1, "offset_width": 32} + array = worker._output_array(["中"], descriptor, 1) + self.assertEqual(["中"], array.to_pylist()) + + def test_decimal_precision_and_vector_child_validity_are_checked(self): + decimal_descriptor = {"type_id": worker.DECIMAL128, "width": 3, "scale": 0, "offset_width": 32} + with self.assertRaisesRegex(ValueError, "precision exceeded"): + worker._output_array([__import__("decimal").Decimal("1000")], decimal_descriptor, 1) + + vector_descriptor = {"type_id": worker.VECF32, "width": 2, "offset_width": 0} + child = pa.array([1.0, None, 3.0, 4.0], type=pa.float32()) + vector = pa.FixedSizeListArray.from_arrays(child, 2) + with self.assertRaisesRegex(ValueError, "child validity"): + worker._output_array(vector, vector_descriptor, 2) + + def test_scalar_vector_null_keeps_fixed_size_child_slots(self): + descriptor = {"type_id": worker.VECF32, "width": 2, "offset_width": 0} + array = worker._output_array( + [memoryview(struct.pack(" int return item +def _required_positive_float(value: Dict[str, Any], key: str, maximum: float) -> float: + item = value.get(key) + if isinstance(item, bool) or not isinstance(item, (int, float)) or item <= 0 or item > maximum: + raise ValueError(f"PROTOCOL: invalid invocation field {key}") + return float(item) + + def _required_uint64(value: Dict[str, Any], key: str, allow_zero: bool = False) -> int: item = value.get(key) minimum = 0 if allow_zero else 1 @@ -507,7 +523,7 @@ def _check_scalar(value: Any, descriptor: Dict[str, Any]): if type_id in (CHAR, VARCHAR, TEXT): if type(value) is not str: raise ValueError("TYPE_CONTRACT: expected string") width = int(descriptor.get("width") or 0) - if width > 0 and len(value.encode("utf-8")) > width: raise ValueError("TYPE_CONTRACT: string exceeds the declared width") + if width > 0 and len(value) > width: raise ValueError("TYPE_CONTRACT: string exceeds the declared width") return value if type_id == JSON: return _check_json(value) if type_id in (BINARY, VARBINARY, BLOB): @@ -552,8 +568,12 @@ def _check_scalar(value: Any, descriptor: Dict[str, Any]): return values if type_id in (DECIMAL64, DECIMAL128): if not isinstance(value, _decimal.Decimal): raise ValueError("TYPE_CONTRACT: expected decimal.Decimal") + if not value.is_finite(): raise ValueError("TYPE_CONTRACT: decimal must be finite") scale = int(descriptor.get("scale") or 0) - if -value.as_tuple().exponent != scale: raise ValueError("TYPE_CONTRACT: decimal scale mismatch") + exponent = value.as_tuple().exponent + if not isinstance(exponent, int) or -exponent != scale: raise ValueError("TYPE_CONTRACT: decimal scale mismatch") + precision = int(descriptor.get("width") or (18 if type_id == DECIMAL64 else 38)) + if len(value.as_tuple().digits) > precision: raise ValueError("TYPE_CONTRACT: decimal precision exceeded") return value @@ -597,7 +617,10 @@ def _output_array(values: Any, descriptor: Dict[str, Any], rows: int) -> pa.Arra checked.append(_check_scalar(value, descriptor)) try: child_type = pa.float32() if type_id == VECF32 else pa.float64() - flat = [item for row in checked if row is not None for item in row] + # A NULL parent still owns exactly `width` child slots in a + # FixedSizeListArray. Leaving those slots out changes the row + # layout and makes the following non-NULL rows shift left. + flat = [item for row in checked for item in (row if row is not None else [0] * width)] child = pa.array(flat, type=child_type) mask = pa.array([row is None for row in checked]) return pa.FixedSizeListArray.from_arrays(child, width, mask=mask) @@ -614,7 +637,7 @@ def _validate_array_values(array: pa.Array, descriptor: Dict[str, Any]) -> None: if type_id in (DATE, DATETIME, TIMESTAMP): struct = array for index in range(len(struct)): - if struct.is_null(index): continue + if not struct[index].is_valid: continue is_zero = bool(struct.field("is_zero")[index].as_py()) value = struct.field("value")[index].as_py() if value is None: raise ValueError("TYPE_CONTRACT: temporal child is null") @@ -624,9 +647,14 @@ def _validate_array_values(array: pa.Array, descriptor: Dict[str, Any]) -> None: if type_id == DATE: _check_scalar(SqlDate(False, value), descriptor) elif type_id == DATETIME: _check_scalar(SqlDatetime(False, value), descriptor) else: _check_scalar(SqlTimestamp(False, value), descriptor) + elif type_id in (VECF32, VECF64): + values = array.values + for index in range(len(values)): + if not values[index].is_valid: + raise ValueError("TYPE_CONTRACT: vector child validity must be non-null") elif type_id in (CHAR, VARCHAR, TEXT, JSON, BINARY, VARBINARY, BLOB, UUID, TIME, DECIMAL64, DECIMAL128): for index in range(len(array)): - if array.is_null(index): continue + if not array[index].is_valid: continue value = array[index].as_py() if type_id == UUID: if not isinstance(value, (bytes, bytearray)) or len(value) != 16: raise ValueError("TYPE_CONTRACT: UUID must contain 16 bytes") @@ -634,6 +662,191 @@ def _validate_array_values(array: pa.Array, descriptor: Dict[str, Any]) -> None: _check_scalar(value, descriptor) +class _DiscardText: + def write(self, value: str) -> int: + return len(value) + + def flush(self) -> None: + return None + + +def _serialize_record_batch(record: pa.RecordBatch) -> bytes: + sink = pa.BufferOutputStream() + with pa.ipc.new_stream(sink, record.schema) as stream: + stream.write_batch(record) + return sink.getvalue().to_pybytes() + + +def _deserialize_record_batch(data: bytes) -> pa.RecordBatch: + if not isinstance(data, (bytes, bytearray)) or not data: + raise ValueError("PROTOCOL: execution payload is missing an Arrow batch") + reader = pa.ipc.open_stream(pa.py_buffer(data)) + try: + try: + record = reader.read_next_batch() + except StopIteration as exc: + raise ValueError("PROTOCOL: execution payload contains no Arrow batch") from exc + try: + reader.read_next_batch() + except StopIteration: + return record + raise ValueError("PROTOCOL: execution payload contains multiple Arrow batches") + finally: + reader.close() + + +def _execute_handler_batch(request: Dict[str, Any]) -> bytes: + batch = _deserialize_record_batch(request["input"]) + args = request["args"] + result_descriptor = request["return"] + mode = request["mode"] + null_policy = request["null_policy"] + sdk_version = request["sdk_version"] + statement_context = _statement_context(request.get("context")) + + # User code has no stdout/stderr channel in the Flight protocol. Discard + # it so a print() cannot corrupt the length-prefixed response frame. + with contextlib.redirect_stdout(_DiscardText()), contextlib.redirect_stderr(_DiscardText()): + handler = _load_handler(request["source"], request["handler"]) + if mode == MODE_VECTOR: + call_context = VectorContext(sdk_version, _CallLogger(), statement_context, batch.num_rows) + output = handler(call_context, *[batch.column(index) for index in range(batch.num_columns)]) + if not isinstance(output, (pa.Array, pa.ChunkedArray)): + raise ValueError("TYPE_CONTRACT: VECTOR handler must return an Arrow Array or ChunkedArray") + else: + call_context = ScalarContext(sdk_version, _CallLogger(), statement_context) + values = [] + for row in range(batch.num_rows): + params = [_scalar_input(batch.column(index), row, args[index]) for index in range(batch.num_columns)] + if null_policy == NULL_RETURN and any(value is None for value in params): + values.append(None) + else: + values.append(handler(call_context, *params)) + output = values + output_array = _output_array(output, result_descriptor, batch.num_rows) + result_field = _field("result", result_descriptor) + result_batch = pa.RecordBatch.from_arrays( + [output_array], schema=pa.schema([result_field]) + ) + if pa.ipc.get_record_batch_size(result_batch) > request["max_batch_bytes"]: + raise ValueError("RESOURCE_EXHAUSTED: output batch exceeds byte limit") + return _serialize_record_batch(result_batch) + + +def _read_exact(stream, size: int) -> bytes: + result = bytearray() + while len(result) < size: + chunk = stream.read(size - len(result)) + if not chunk: + raise EOFError("execution frame ended unexpectedly") + result.extend(chunk) + return bytes(result) + + +def _write_execution_frame(stream, payload: bytes) -> None: + if len(payload) > MAX_EXECUTION_FRAME_BYTES: + raise ValueError("RESOURCE_EXHAUSTED: execution frame is too large") + stream.write(struct.pack(">Q", len(payload))) + stream.write(payload) + stream.flush() + + +def _execute_handler_subprocess() -> None: + try: + size = struct.unpack(">Q", _read_exact(sys.stdin.buffer, 8))[0] + if size > MAX_EXECUTION_FRAME_BYTES: + raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") + request = pickle.loads(_read_exact(sys.stdin.buffer, size)) + response = {"ok": True, "payload": _execute_handler_batch(request)} + except Exception as exc: + response = {"ok": False, "error": _safe_error(exc)} + _write_execution_frame(sys.stdout.buffer, pickle.dumps(response, protocol=5)) + + +def _context_is_cancelled(context) -> bool: + if context is None: + return False + try: + return bool(context.is_cancelled()) + except Exception: + return False + + +def _kill_execution_process(process: subprocess.Popen) -> None: + if process.poll() is None: + if os.name == "posix": + try: + os.killpg(process.pid, signal.SIGKILL) + except ProcessLookupError: + pass + else: + process.kill() + try: + process.wait(timeout=1.0) + except subprocess.TimeoutExpired: + process.kill() + process.wait() + + +def _run_handler_process(context, request: Dict[str, Any], timeout_seconds: float) -> bytes: + request_wire = pickle.dumps(request, protocol=5) + if len(request_wire) > MAX_EXECUTION_FRAME_BYTES: + raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") + popen_kwargs = { + "stdin": subprocess.PIPE, + "stdout": subprocess.PIPE, + "stderr": subprocess.DEVNULL, + "close_fds": True, + } + if os.name == "posix": + popen_kwargs["start_new_session"] = True + process = subprocess.Popen([sys.executable, os.path.abspath(__file__), "--execute-handler"], **popen_kwargs) + selector = selectors.DefaultSelector() + response = bytearray() + expected = None + try: + _write_execution_frame(process.stdin, request_wire) + process.stdin.close() + selector.register(process.stdout, selectors.EVENT_READ) + deadline = time.monotonic() + timeout_seconds + while True: + if _context_is_cancelled(context): + raise TimeoutError("DEADLINE_EXCEEDED: handler execution cancelled") + remaining = deadline - time.monotonic() + if remaining <= 0: + raise TimeoutError("DEADLINE_EXCEEDED: handler execution timeout") + events = selector.select(min(remaining, 0.1)) + if not events: + continue + chunk = os.read(process.stdout.fileno(), 65536) + if not chunk: + if expected is None or len(response) < expected: + raise ValueError("USER_CODE: handler process exited without a response") + break + response.extend(chunk) + if expected is None and len(response) >= 8: + expected = struct.unpack(">Q", response[:8])[0] + if expected > MAX_EXECUTION_FRAME_BYTES: + raise ValueError("RESOURCE_EXHAUSTED: execution response is too large") + if expected is not None and len(response) >= expected + 8: + break + payload = pickle.loads(bytes(response[8 : expected + 8])) + if not isinstance(payload, dict) or payload.get("ok") is not True: + raise ValueError(str(payload.get("error", "USER_CODE: handler process failed"))) + result = payload.get("payload") + if not isinstance(result, bytes): + raise ValueError("PROTOCOL: handler process returned an invalid Arrow payload") + return result + finally: + selector.close() + if process.poll() is None: + _kill_execution_process(process) + else: + process.wait() + process.stdout.close() + + + class _InvocationState: def __init__(self, tuple_value: Dict[str, Any], terminal_bytes: int): self.tuple = tuple_value @@ -651,13 +864,15 @@ def ack_result(self, sequence: int) -> None: self.acked_result = sequence self.condition.notify_all() - def wait_result_ack(self, sequence: int) -> None: + def wait_result_ack(self, sequence: int, context=None) -> None: deadline = time.monotonic() + ACK_TIMEOUT_SECONDS with self.condition: while self.acked_result < sequence: + if context is not None and context.is_cancelled(): + raise TimeoutError("DEADLINE_EXCEEDED: result ACK wait cancelled") remaining = deadline - time.monotonic() if remaining <= 0: raise TimeoutError("DEADLINE_EXCEEDED: result ACK timeout") - self.condition.wait(remaining) + self.condition.wait(min(remaining, 0.2)) def ack_finish(self, finish_id: str) -> None: with self.condition: @@ -665,13 +880,15 @@ def ack_finish(self, finish_id: str) -> None: self.finish_acked = True self.condition.notify_all() - def wait_finish_ack(self) -> None: + def wait_finish_ack(self, context=None) -> None: deadline = time.monotonic() + ACK_TIMEOUT_SECONDS with self.condition: while not self.finish_acked: + if context is not None and context.is_cancelled(): + raise TimeoutError("DEADLINE_EXCEEDED: Finish ACK wait cancelled") remaining = deadline - time.monotonic() if remaining <= 0: raise TimeoutError("DEADLINE_EXCEEDED: Finish ACK timeout") - self.condition.wait(remaining) + self.condition.wait(min(remaining, 0.2)) class RoutineFlightServer(flight.FlightServerBase): @@ -720,6 +937,22 @@ def _remember_terminal_locked(self, key: tuple, state: _InvocationState) -> None self._terminal.move_to_end(key) self._terminal_bytes += state.terminal_bytes + def _finish_invocation(self, key: tuple, state: Optional[_InvocationState]) -> None: + # A rejected duplicate Open has no ownership of the existing state. + # Cleanup must therefore be identity based, not key based. + if key is None or state is None: + return + with self._lock: + current = self._active.get(key) + if current is not state: + return + self._active.pop(key, None) + self._active_bytes -= state.terminal_bytes + # A started invocation is terminal even when the worker reports an + # error. Retaining the fence prevents a late retry from running + # user code a second time. + self._remember_terminal_locked(key, state) + def do_action(self, context, action): control = _decode_control(action.body) key = _tuple_key(control["tuple"]) @@ -770,12 +1003,16 @@ def do_exchange(self, context, descriptor, reader, writer): sdk_version = _required_string(payload, "sdk_version") max_batch_bytes = _required_positive_int(payload, "max_batch_bytes", 1 << 30) max_batch_rows = _required_positive_int(payload, "max_batch_rows", 1 << 30) + handler_timeout_seconds = _required_positive_float( + payload, "handler_timeout_seconds", 3600.0 + ) if mode not in (MODE_SCALAR, MODE_VECTOR) or null_policy not in (NULL_CALL, NULL_RETURN): raise ValueError("PROTOCOL: unsupported call mode or NULL policy") if abi_contract != ABI_CONTRACT or adapter_version != ADAPTER_VERSION: raise ValueError("PROTOCOL: unsupported Python ABI contract") if sdk_version != SDK_VERSION: raise ValueError("PROTOCOL: unsupported Python SDK") state = self._admit(key) state.tuple = open_control["tuple"] - handler = _load_handler(_required_string(payload, "source"), _required_string(payload, "handler")) + source = _required_string(payload, "source") + handler_name = _required_string(payload, "handler") schema = None result_field = _field("result", result_descriptor) result_schema = pa.schema([result_field]) @@ -801,34 +1038,33 @@ def do_exchange(self, context, descriptor, reader, writer): if batch.num_rows <= 0: raise ValueError("PROTOCOL: empty input batch") if batch.num_rows > max_batch_rows: raise ValueError("RESOURCE_EXHAUSTED: input batch has too many rows") if batch.nbytes > max_batch_bytes: raise ValueError("RESOURCE_EXHAUSTED: input batch exceeds byte limit") - if mode == MODE_VECTOR: - call_context = VectorContext(sdk_version, _CallLogger(), statement_context, batch.num_rows) - try: - output = handler(call_context, *[batch.column(index) for index in range(batch.num_columns)]) - except Exception as exc: - raise ValueError("USER_CODE: handler failed") from exc - if not isinstance(output, (pa.Array, pa.ChunkedArray)): - raise ValueError("TYPE_CONTRACT: VECTOR handler must return an Arrow Array or ChunkedArray") - else: - call_context = ScalarContext(sdk_version, _CallLogger(), statement_context) - values = [] - for row in range(batch.num_rows): - params = [_scalar_input(batch.column(index), row, args[index]) for index in range(batch.num_columns)] - if null_policy == NULL_RETURN and any(value is None for value in params): values.append(None) - else: - try: - values.append(handler(call_context, *params)) - except Exception as exc: - raise ValueError("USER_CODE: handler failed") from exc - output = values - output_array = _output_array(output, result_descriptor, batch.num_rows) - output_batch = pa.RecordBatch.from_arrays([output_array], schema=result_schema) + execution_request = { + "source": source, + "handler": handler_name, + "mode": mode, + "null_policy": null_policy, + "sdk_version": sdk_version, + "context": payload.get("context"), + "args": args, + "return": result_descriptor, + "max_batch_bytes": max_batch_bytes, + "input": _serialize_record_batch(batch), + } + output_wire = _run_handler_process( + context, execution_request, handler_timeout_seconds + ) + output_batch = _deserialize_record_batch(output_wire) + if output_batch.num_rows != batch.num_rows or output_batch.num_columns != 1: + raise ValueError("TYPE_CONTRACT: handler result has the wrong shape") + _validate_field(output_batch.schema.field(0), "result", result_descriptor) + output_array = output_batch.column(0) + _validate_array_values(output_array, result_descriptor) if pa.ipc.get_record_batch_size(output_batch) > max_batch_bytes: raise ValueError("RESOURCE_EXHAUSTED: output batch exceeds byte limit") state.last_result = sequence writer.write_metadata(_encode_control({"kind": "InputConsumed", "tuple": open_control["tuple"], "sequence": sequence})) writer.write_with_metadata(output_batch, _encode_control({"kind": "ResultBatch", "tuple": open_control["tuple"], "sequence": sequence})) - state.wait_result_ack(sequence) + state.wait_result_ack(sequence, context) elif chunk.app_metadata: control = _decode_control(chunk.app_metadata) _require_tuple(control["tuple"], open_control["tuple"]) @@ -841,7 +1077,7 @@ def do_exchange(self, context, descriptor, reader, writer): if state.acked_result != state.last_result: raise ValueError("PROTOCOL: result is not acknowledged") state.finish_id = _uuid.uuid4().hex writer.write_metadata(_encode_control({"kind": "Finish", "tuple": open_control["tuple"], "status": "OK", "finish_id": state.finish_id, "last_sequence": state.last_result})) - state.wait_finish_ack() + state.wait_finish_ack(context) except Exception as exc: if writer_started and key is not None: try: @@ -850,16 +1086,7 @@ def do_exchange(self, context, descriptor, reader, writer): pass raise finally: - if key is not None: - with self._lock: - current = self._active.pop(key, None) - if current is not None: - self._active_bytes -= current.terminal_bytes - # A started invocation is terminal even when the worker - # reports an error. Retaining the fence prevents a late - # retry from running user code a second time; the caller's - # error path remains responsible for reporting failure. - self._remember_terminal_locked(key, current) + self._finish_invocation(key, state) def _safe_error(exc: Exception) -> str: @@ -872,8 +1099,14 @@ def _safe_error(exc: Exception) -> str: def main() -> None: parser = argparse.ArgumentParser() - parser.add_argument("--address", required=True) + parser.add_argument("--execute-handler", action="store_true") + parser.add_argument("--address") args = parser.parse_args() + if args.execute_handler: + _execute_handler_subprocess() + return + if not args.address: + parser.error("--address is required for the Flight server") logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(levelname)s %(message)s") address = args.address if "://" in args.address else "grpc://" + args.address server = RoutineFlightServer(address) diff --git a/test/distributed/cases/udf_python/README.md b/test/distributed/cases/udf_python/README.md index 2efd69b2cbbd4..2e34d22d10070 100644 --- a/test/distributed/cases/udf_python/README.md +++ b/test/distributed/cases/udf_python/README.md @@ -5,7 +5,9 @@ needs a matching `.result` file generated by `mo-tester`. These cases are part of the ordinary BVT suite and run with the other SQL cases. For a local launch BVT, install the locked worker dependency once and use the -normal BVT commands: +normal BVT commands. `run_bvt.sh . launch` selects the explicit +worker-enabled manifest for this ordinary BVT entry point; starting +`etc/launch/launch.toml` directly leaves Python disabled. ```bash python3 -m pip install -r pkg/udf/python/worker/requirements.txt @@ -23,9 +25,9 @@ cd /path/to/mo-tester ./run.sh -p /path/to/matrixone/test/distributed/cases/udf_python/example.sql -m genrs -g ``` -The ordinary launch manifest starts one worker for the single CN. Compose BVT -starts one isolated worker service per CN from the same pinned image, so adding -a SQL case here does not require another CI workflow. +The ordinary BVT launch starts one worker for the single CN. Compose BVT starts +one isolated worker service per CN from the same pinned image, so adding a SQL +case here does not require another CI workflow. The cases keep the data sets small and target contract boundaries: diff --git a/test/distributed/cases/udf_python/numeric_boundaries.sql b/test/distributed/cases/udf_python/numeric_boundaries.sql index 0c00e1f813be5..9d63739488d49 100644 --- a/test/distributed/cases/udf_python/numeric_boundaries.sql +++ b/test/distributed/cases/udf_python/numeric_boundaries.sql @@ -17,6 +17,7 @@ create function python_bvt_double (x double) returns double language python as ' create function python_bvt_bool (x bool) returns bool language python as 'def python_bvt_bool(ctx, x): return x' handler 'python_bvt_bool'; create function python_bvt_decimal64 (x decimal(18,6)) returns decimal(18,6) language python as 'def python_bvt_decimal64(ctx, x): return x' handler 'python_bvt_decimal64'; create function python_bvt_decimal128 (x decimal(38,10)) returns decimal(38,10) language python as 'def python_bvt_decimal128(ctx, x): return x' handler 'python_bvt_decimal128'; +create function python_bvt_decimal_rescale (x decimal(18,6)) returns decimal(18,6) language python as 'def python_bvt_decimal_rescale(ctx, x): return x' handler 'python_bvt_decimal_rescale'; create table numeric_values ( tiny_v tinyint, @@ -55,6 +56,10 @@ select python_bvt_tinyint(tiny_v) as tiny_v, python_bvt_decimal128(decimal128_v) as decimal128_v from numeric_values order by big_v is null, big_v; +-- The planner must normalize DECIMAL(18,2) to the declared scale before the +-- Arrow encoder sees the coefficient; 1.23 must remain 1.230000. +select python_bvt_decimal_rescale(cast('1.23' as decimal(18,2))) as decimal_rescaled; + drop function python_bvt_tinyint(tinyint); drop function python_bvt_smallint(smallint); drop function python_bvt_int(int); @@ -68,5 +73,6 @@ drop function python_bvt_double(double); drop function python_bvt_bool(bool); drop function python_bvt_decimal64(decimal(18,6)); drop function python_bvt_decimal128(decimal(38,10)); +drop function python_bvt_decimal_rescale(decimal(18,6)); drop table numeric_values; drop database udf_python_numeric_bvt; From 59c3807530165d638efb1411f4e060a6846b47b8 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 22:01:43 +0800 Subject: [PATCH 013/241] fix(udf): separate active and terminal reservations --- pkg/udf/protocol/protocol.go | 37 ++++++++++++++++++++++++- pkg/udf/protocol/protocol_test.go | 45 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 419e1fb31acd3..3b3722d908514 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -325,6 +325,7 @@ type ExecutionGroup struct { registered int inFlight int members map[string]bool + pending map[string]struct{} terminal map[string]bool closing bool releaseBusy bool @@ -339,7 +340,8 @@ func NewExecutionGroup(id string, epoch uint64, maxMembers int, release func() e } return &ExecutionGroup{ id: id, epoch: epoch, maxMembers: maxMembers, - members: make(map[string]bool), terminal: make(map[string]bool), release: release, + members: make(map[string]bool), pending: make(map[string]struct{}), + terminal: make(map[string]bool), release: release, }, nil } @@ -357,9 +359,13 @@ func (g *ExecutionGroup) BeginOpen(memberID string) (*OpenToken, error) { if g.members[memberID] || g.terminal[memberID] { return nil, ErrDuplicate } + if _, exists := g.pending[memberID]; exists { + return nil, ErrDuplicate + } if g.registered+g.inFlight >= g.maxMembers { return nil, fmt.Errorf("%w: member limit %d reached", ErrLedgerFull, g.maxMembers) } + g.pending[memberID] = struct{}{} g.inFlight++ return &OpenToken{group: g, memberID: memberID}, nil } @@ -378,6 +384,7 @@ func (t *OpenToken) Commit() error { t.once.Do(func() { g := t.group g.mu.Lock() + delete(g.pending, t.memberID) g.inFlight-- if g.closing || g.released { t.result = ErrGroupClosed @@ -404,6 +411,7 @@ func (t *OpenToken) Abort() error { t.once.Do(func() { g := t.group g.mu.Lock() + delete(g.pending, t.memberID) g.inFlight-- release := g.canReleaseLocked() g.mu.Unlock() @@ -606,6 +614,13 @@ func (l *TerminalLedger) Expire(now time.Time) int { defer l.mu.Unlock() removed := 0 for key, entry := range l.entries { + // Active entries represent work that may still produce a result. Their + // admission credit belongs to the running execution and can only be + // released by an explicit termination/recovery path. Expiry is solely + // for completed deduplication tombstones. + if !entry.tombstone { + continue + } if !now.Before(entry.expiresAt) { delete(l.entries, key) l.reservedN-- @@ -616,6 +631,26 @@ func (l *TerminalLedger) Expire(now time.Time) int { return removed } +// Abandon removes an active execution after its owner has confirmed +// cancellation, crash recovery, or another terminal failure. It is separate +// from Expire so a clock cannot reclaim a live invocation's deduplication +// entry. +func (l *TerminalLedger) Abandon(key string) error { + l.mu.Lock() + defer l.mu.Unlock() + entry, ok := l.entries[key] + if !ok { + return ErrUnknownIdentity + } + if entry.tombstone { + return ErrProtocol + } + delete(l.entries, key) + l.reservedN-- + l.reservedB -= entry.bytes + return nil +} + func (l *TerminalLedger) Counts() (entries int, bytes int64) { l.mu.Lock() defer l.mu.Unlock() diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index a9268fa7bd1d9..624e4035f1c29 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -158,6 +158,30 @@ func TestExecutionGroupZeroMemberAndAbortedOpenRelease(t *testing.T) { require.ErrorIs(t, open.Commit(), ErrGroupClosed) } +func TestExecutionGroupReservesPendingMemberIdentity(t *testing.T) { + group, err := NewExecutionGroup("g", 1, 2, func() error { return nil }) + require.NoError(t, err) + first, err := group.BeginOpen("member") + require.NoError(t, err) + _, err = group.BeginOpen("member") + require.ErrorIs(t, err, ErrDuplicate) + registered, active, inFlight := group.Counts() + require.Equal(t, 0, registered) + require.Equal(t, 0, active) + require.Equal(t, 1, inFlight) + require.NoError(t, first.Abort()) + _, _, inFlight = group.Counts() + require.Zero(t, inFlight) + + second, err := group.BeginOpen("member") + require.NoError(t, err) + require.NoError(t, second.Commit()) + registered, active, inFlight = group.Counts() + require.Equal(t, 1, registered) + require.Equal(t, 1, active) + require.Zero(t, inFlight) +} + func TestTerminalLedgerRetainsTombstonesUntilExpiry(t *testing.T) { ledger, err := NewTerminalLedger(2, 200) require.NoError(t, err) @@ -171,6 +195,7 @@ func TestTerminalLedgerRetainsTombstonesUntilExpiry(t *testing.T) { second, err := ledger.Reserve("g2", 1, 100) require.NoError(t, err) require.NoError(t, second.Add("i2", 100, now.Add(time.Hour))) + require.NoError(t, ledger.Complete("i2")) second.ReleaseUnused() _, err = ledger.Reserve("g3", 1, 1) require.ErrorIs(t, err, ErrLedgerFull) @@ -188,6 +213,26 @@ func TestTerminalLedgerRetainsTombstonesUntilExpiry(t *testing.T) { require.NoError(t, ledger.Complete("i3")) } +func TestTerminalLedgerDoesNotExpireActiveEntries(t *testing.T) { + ledger, err := NewTerminalLedger(1, 100) + require.NoError(t, err) + now := time.Unix(100, 0) + credit, err := ledger.Reserve("g", 1, 100) + require.NoError(t, err) + require.NoError(t, credit.Add("active", 100, now.Add(time.Second))) + credit.ReleaseUnused() + require.Equal(t, 0, ledger.Expire(now.Add(time.Hour))) + entries, bytes := ledger.Counts() + require.Equal(t, 1, entries) + require.Equal(t, int64(100), bytes) + _, err = ledger.Reserve("other", 1, 1) + require.ErrorIs(t, err, ErrLedgerFull) + require.NoError(t, ledger.Abandon("active")) + entries, bytes = ledger.Counts() + require.Zero(t, entries) + require.Zero(t, bytes) +} + func TestExecutionGroupReleaseErrorCanBeRetried(t *testing.T) { var attempts atomic.Int32 group, err := NewExecutionGroup("g", 1, 1, func() error { From 49c3ed2bd38f1732d19267be75452b94dde44e83 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 22:09:30 +0800 Subject: [PATCH 014/241] test(udf): update decimal normalization baseline --- test/distributed/cases/udf_python/numeric_boundaries.result | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/distributed/cases/udf_python/numeric_boundaries.result b/test/distributed/cases/udf_python/numeric_boundaries.result index 27cddaf47fda9..c368b8dac5cac 100644 --- a/test/distributed/cases/udf_python/numeric_boundaries.result +++ b/test/distributed/cases/udf_python/numeric_boundaries.result @@ -14,6 +14,7 @@ create function python_bvt_double (x double) returns double language python as ' create function python_bvt_bool (x bool) returns bool language python as 'def python_bvt_bool(ctx, x): return x' handler 'python_bvt_bool'; create function python_bvt_decimal64 (x decimal(18,6)) returns decimal(18,6) language python as 'def python_bvt_decimal64(ctx, x): return x' handler 'python_bvt_decimal64'; create function python_bvt_decimal128 (x decimal(38,10)) returns decimal(38,10) language python as 'def python_bvt_decimal128(ctx, x): return x' handler 'python_bvt_decimal128'; +create function python_bvt_decimal_rescale (x decimal(18,6)) returns decimal(18,6) language python as 'def python_bvt_decimal_rescale(ctx, x): return x' handler 'python_bvt_decimal_rescale'; create table numeric_values ( tiny_v tinyint, small_v smallint, @@ -53,6 +54,9 @@ from numeric_values order by big_v is null, big_v; -128 ¦ -32768 ¦ -2147483648 ¦ -9223372036854775808 ¦ 0 ¦ 0 ¦ 0 ¦ 0 ¦ -0.0 ¦ -0.0 ¦ 0 ¦ -0.000001 ¦ -9999999999999999999999999999.9999999999 𝄀 127 ¦ 32767 ¦ 2147483647 ¦ 9223372036854775807 ¦ 255 ¦ 65535 ¦ 4294967295 ¦ 18446744073709551615 ¦ 3.25 ¦ 1.0 ¦ 1 ¦ 999999999999.999999 ¦ 9999999999999999999999999999.9999999999 𝄀 null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null ¦ null +select python_bvt_decimal_rescale(cast('1.23' as decimal(18,2))) as decimal_rescaled; +➤ decimal_rescaled[3,18,6] 𝄀 +1.230000 drop function python_bvt_tinyint(tinyint); drop function python_bvt_smallint(smallint); drop function python_bvt_int(int); @@ -66,5 +70,6 @@ drop function python_bvt_double(double); drop function python_bvt_bool(bool); drop function python_bvt_decimal64(decimal(18,6)); drop function python_bvt_decimal128(decimal(38,10)); +drop function python_bvt_decimal_rescale(decimal(18,6)); drop table numeric_values; drop database udf_python_numeric_bvt; From 509b50f50777cc0383710bc5962dec60a0749012 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 22:13:25 +0800 Subject: [PATCH 015/241] fix(udf): harden handler response ownership --- pkg/udf/protocol/protocol_test.go | 2 ++ pkg/udf/python/gateway.go | 5 +++-- pkg/udf/python/worker/test_worker.py | 18 ++++++++++++++++++ pkg/udf/python/worker/worker.py | 27 +++++++++++++++++---------- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index 624e4035f1c29..7ae2198ecb2aa 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -80,7 +80,9 @@ func TestOutputSnapshotFreezesBeforeWorkerCanRewrite(t *testing.T) { worker[0] = 'X' require.NoError(t, snapshot.Validate(len("trusted-before-barrier"), snapshot.Digest())) + worker[1] = 'Y' require.Equal(t, "trusted-before-barrier", string(snapshot.Bytes())) + require.Equal(t, "trusted-before-barrier", string(snapshot.TrustedBytes())) empty, err := FreezeOutput(nil, 1024) require.NoError(t, err) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 73084ee4561e8..cfcffad2689b0 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -363,9 +363,10 @@ func (g *Gateway) receiveResultBatch( if err != nil { return 0, fmt.Errorf("python udf: decode result: %w", err) } - if decoded.NumCols() != 1 || decoded.NumRows() <= 0 || decoded.NumRows() != expectedRows { + decodedRows := decoded.NumRows() + if decoded.NumCols() != 1 || decodedRows <= 0 || decodedRows != expectedRows { decoded.Release() - return 0, fmt.Errorf("python udf: result batch row count %d, expected %d", decoded.NumRows(), expectedRows) + return 0, fmt.Errorf("python udf: result batch row count %d, expected %d", decodedRows, expectedRows) } if decoded.Schema().Field(0).Name != "result" { decoded.Release() diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index e43c07f8a49ca..4754fd24fff39 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -142,6 +142,24 @@ def test_handler_process_is_fresh_and_can_be_terminated(self): worker._run_handler_process(None, request, 0.1) self.assertLess(time.monotonic() - started, 2) + def test_handler_stdout_cannot_inject_parent_protocol(self): + descriptor = {"type_id": worker.INT64, "offset_width": 32} + batch = pa.RecordBatch.from_arrays([pa.array([1], type=pa.int64())], ["arg_0"]) + request = { + "source": "import os\ndef f(ctx, x): os.write(1, b'\\x00' * 8); return x", + "handler": "f", + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "sdk_version": worker.SDK_VERSION, + "context": None, + "args": [descriptor], + "return": descriptor, + "max_batch_bytes": 1 << 20, + "input": worker._serialize_record_batch(batch), + } + with self.assertRaisesRegex(ValueError, "handler process"): + worker._run_handler_process(None, request, 3) + def test_zero_argument_vector_uses_context_rows(self): descriptor = {"type_id": worker.INT64, "offset_width": 32} output = pa.array([7, 7, 7], type=pa.int64()) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 908ceb97a7f39..583ab1df8aabf 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -45,6 +45,8 @@ TERMINAL_TTL_SECONDS = 300.0 ACK_TIMEOUT_SECONDS = 60.0 MAX_EXECUTION_FRAME_BYTES = 1 << 30 +_HANDLER_RESPONSE_ERROR = 0 +_HANDLER_RESPONSE_OK = 1 _MICROS_PER_SECOND = 1_000_000 _MAX_TIME_MICROS = (838 * 60 * 60 + 59 * 60 + 59) * _MICROS_PER_SECOND _MIN_TIMESTAMP = _datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=_datetime.timezone.utc) @@ -757,10 +759,10 @@ def _execute_handler_subprocess() -> None: if size > MAX_EXECUTION_FRAME_BYTES: raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") request = pickle.loads(_read_exact(sys.stdin.buffer, size)) - response = {"ok": True, "payload": _execute_handler_batch(request)} + response = bytes([_HANDLER_RESPONSE_OK]) + _execute_handler_batch(request) except Exception as exc: - response = {"ok": False, "error": _safe_error(exc)} - _write_execution_frame(sys.stdout.buffer, pickle.dumps(response, protocol=5)) + response = bytes([_HANDLER_RESPONSE_ERROR]) + _safe_error(exc).encode("utf-8") + _write_execution_frame(sys.stdout.buffer, response) def _context_is_cancelled(context) -> bool: @@ -830,13 +832,18 @@ def _run_handler_process(context, request: Dict[str, Any], timeout_seconds: floa raise ValueError("RESOURCE_EXHAUSTED: execution response is too large") if expected is not None and len(response) >= expected + 8: break - payload = pickle.loads(bytes(response[8 : expected + 8])) - if not isinstance(payload, dict) or payload.get("ok") is not True: - raise ValueError(str(payload.get("error", "USER_CODE: handler process failed"))) - result = payload.get("payload") - if not isinstance(result, bytes): - raise ValueError("PROTOCOL: handler process returned an invalid Arrow payload") - return result + payload = bytes(response[8 : expected + 8]) + if not payload: + raise ValueError("PROTOCOL: handler process returned an empty response") + if payload[0] == _HANDLER_RESPONSE_ERROR: + try: + message = payload[1:].decode("utf-8") + except UnicodeDecodeError as exc: + raise ValueError("PROTOCOL: handler process returned an invalid error") from exc + raise ValueError(message or "USER_CODE: handler process failed") + if payload[0] != _HANDLER_RESPONSE_OK: + raise ValueError("PROTOCOL: handler process returned an unknown status") + return payload[1:] finally: selector.close() if process.poll() is None: From a6e130f9c052812cff465b553f083624f7fb70a4 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 22:18:10 +0800 Subject: [PATCH 016/241] refactor(udf): clarify execution sequence ownership --- pkg/udf/python/gateway.go | 28 ++++++++++++++-------------- pkg/udf/python/worker/test_worker.py | 12 ++++++------ pkg/udf/python/worker/worker.py | 19 ++++++++++++------- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index cfcffad2689b0..3c7fdbd6b9ced 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -98,19 +98,19 @@ func (g *Gateway) Close() error { } type openPayload struct { - Handler string `json:"handler"` - Source string `json:"source"` - Mode string `json:"mode"` - NullPolicy string `json:"null_policy"` - ABIContract string `json:"abi_contract"` - AdapterVersion string `json:"adapter_version"` - SDKVersion string `json:"sdk_version"` - Context map[string]string `json:"context,omitempty"` - Args []TypeDescriptor `json:"args"` - Return TypeDescriptor `json:"return"` - MaxBatchBytes int64 `json:"max_batch_bytes"` - MaxBatchRows int64 `json:"max_batch_rows"` - HandlerTimeout float64 `json:"handler_timeout_seconds"` + Handler string `json:"handler"` + Source string `json:"source"` + Mode string `json:"mode"` + NullPolicy string `json:"null_policy"` + ABIContract string `json:"abi_contract"` + AdapterVersion string `json:"adapter_version"` + SDKVersion string `json:"sdk_version"` + Context map[string]string `json:"context,omitempty"` + Args []TypeDescriptor `json:"args"` + Return TypeDescriptor `json:"return"` + MaxBatchBytes int64 `json:"max_batch_bytes"` + MaxBatchRows int64 `json:"max_batch_rows"` + HandlerTimeoutSeconds float64 `json:"handler_timeout_seconds"` } func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, result vector.FunctionResultWrapper, mp *mpool.MPool) error { @@ -146,7 +146,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if err != nil { return err } - openBody, err := json.Marshal(openPayload{Handler: invocation.Handler, Source: invocation.Source, Mode: invocation.Mode, NullPolicy: invocation.NullPolicy, ABIContract: invocation.ABIContract, AdapterVersion: invocation.AdapterVersion, SDKVersion: invocation.SDKVersion, Context: cloneMap(invocation.Context), Args: args, Return: returnDescriptor, MaxBatchBytes: g.cfg.MaxBatchBytes, MaxBatchRows: g.cfg.MaxBatchRows, HandlerTimeout: g.cfg.RequestTimeout.Seconds()}) + openBody, err := json.Marshal(openPayload{Handler: invocation.Handler, Source: invocation.Source, Mode: invocation.Mode, NullPolicy: invocation.NullPolicy, ABIContract: invocation.ABIContract, AdapterVersion: invocation.AdapterVersion, SDKVersion: invocation.SDKVersion, Context: cloneMap(invocation.Context), Args: args, Return: returnDescriptor, MaxBatchBytes: g.cfg.MaxBatchBytes, MaxBatchRows: g.cfg.MaxBatchRows, HandlerTimeoutSeconds: g.cfg.RequestTimeout.Seconds()}) if err != nil { return fmt.Errorf("python udf: encode open payload: %w", err) } diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 4754fd24fff39..75349c4767681 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -201,11 +201,11 @@ def test_statement_context_is_whitelisted_and_frozen(self): ) def test_terminal_admission_does_not_evict_live_tombstones(self): - old_records = worker.MAX_TERMINAL_RECORDS - old_bytes = worker.MAX_TERMINAL_BYTES + old_records = worker.MAX_LEDGER_ENTRIES + old_bytes = worker.MAX_LEDGER_BYTES try: - worker.MAX_TERMINAL_RECORDS = 1 - worker.MAX_TERMINAL_BYTES = 1 << 20 + worker.MAX_LEDGER_ENTRIES = 1 + worker.MAX_LEDGER_BYTES = 1 << 20 server = worker.RoutineFlightServer("grpc://127.0.0.1:0") first = (1, "statement", "group", 1, "invocation", 1) state = server._admit(first) @@ -222,8 +222,8 @@ def test_terminal_admission_does_not_evict_live_tombstones(self): second = server._admit((1, "statement", "group", 1, "second", 1)) self.assertIsNotNone(second) finally: - worker.MAX_TERMINAL_RECORDS = old_records - worker.MAX_TERMINAL_BYTES = old_bytes + worker.MAX_LEDGER_ENTRIES = old_records + worker.MAX_LEDGER_BYTES = old_bytes def test_active_fence_cannot_be_admitted_twice(self): server = worker.RoutineFlightServer("grpc://127.0.0.1:0") diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 583ab1df8aabf..e29caf8a02906 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -40,8 +40,11 @@ PROTOCOL_VERSION = 1 MAX_CONTROL_BYTES = 1 << 20 -MAX_TERMINAL_RECORDS = 10000 -MAX_TERMINAL_BYTES = 16 << 20 +# Admission bounds cover active fences and retained terminal tombstones. The +# names deliberately describe the whole ledger so a future cleanup change +# cannot mistake active work for reclaimable terminal state. +MAX_LEDGER_ENTRIES = 10000 +MAX_LEDGER_BYTES = 16 << 20 TERMINAL_TTL_SECONDS = 300.0 ACK_TIMEOUT_SECONDS = 60.0 MAX_EXECUTION_FRAME_BYTES = 1 << 30 @@ -859,6 +862,7 @@ def __init__(self, tuple_value: Dict[str, Any], terminal_bytes: int): self.tuple = tuple_value self.terminal_bytes = terminal_bytes self.condition = threading.Condition() + self.last_input = 0 self.last_result = 0 self.acked_result = 0 self.finish_id: Optional[str] = None @@ -929,9 +933,9 @@ def _admit(self, key: tuple) -> _InvocationState: raise ValueError("PROTOCOL: invocation fence is active") if key in self._terminal: raise ValueError("PROTOCOL: invocation fence is terminal") - if len(self._active) + len(self._terminal) >= MAX_TERMINAL_RECORDS: + if len(self._active) + len(self._terminal) >= MAX_LEDGER_ENTRIES: raise ValueError("RESOURCE_EXHAUSTED: terminal ledger entries are full") - if self._active_bytes + self._terminal_bytes + size > MAX_TERMINAL_BYTES: + if self._active_bytes + self._terminal_bytes + size > MAX_LEDGER_BYTES: raise ValueError("RESOURCE_EXHAUSTED: terminal ledger bytes are full") state = _InvocationState({}, size) self._active[key] = state @@ -1040,7 +1044,7 @@ def do_exchange(self, context, descriptor, reader, writer): _require_tuple(control["tuple"], open_control["tuple"]) if control["kind"] != "InputBatch": raise ValueError("PROTOCOL: data batch is missing InputBatch") sequence = _required_uint64(control, "sequence") - if sequence != state.last_result + 1: raise ValueError("PROTOCOL: input sequence is not contiguous") + if sequence != state.last_input + 1: raise ValueError("PROTOCOL: input sequence is not contiguous") batch = chunk.data if batch.num_rows <= 0: raise ValueError("PROTOCOL: empty input batch") if batch.num_rows > max_batch_rows: raise ValueError("RESOURCE_EXHAUSTED: input batch has too many rows") @@ -1068,6 +1072,7 @@ def do_exchange(self, context, descriptor, reader, writer): _validate_array_values(output_array, result_descriptor) if pa.ipc.get_record_batch_size(output_batch) > max_batch_bytes: raise ValueError("RESOURCE_EXHAUSTED: output batch exceeds byte limit") + state.last_input = sequence state.last_result = sequence writer.write_metadata(_encode_control({"kind": "InputConsumed", "tuple": open_control["tuple"], "sequence": sequence})) writer.write_with_metadata(output_batch, _encode_control({"kind": "ResultBatch", "tuple": open_control["tuple"], "sequence": sequence})) @@ -1076,14 +1081,14 @@ def do_exchange(self, context, descriptor, reader, writer): control = _decode_control(chunk.app_metadata) _require_tuple(control["tuple"], open_control["tuple"]) if control["kind"] == "EndInput": - if ended or _required_uint64(control, "last_sequence", allow_zero=True) != state.last_result: raise ValueError("PROTOCOL: invalid EndInput") + if ended or _required_uint64(control, "last_sequence", allow_zero=True) != state.last_input: raise ValueError("PROTOCOL: invalid EndInput") ended = True elif control["kind"] != "OpenInvocation": raise ValueError("PROTOCOL: unexpected control without Arrow data") if not ended: raise ValueError("PROTOCOL: input stream ended before EndInput") if state.acked_result != state.last_result: raise ValueError("PROTOCOL: result is not acknowledged") state.finish_id = _uuid.uuid4().hex - writer.write_metadata(_encode_control({"kind": "Finish", "tuple": open_control["tuple"], "status": "OK", "finish_id": state.finish_id, "last_sequence": state.last_result})) + writer.write_metadata(_encode_control({"kind": "Finish", "tuple": open_control["tuple"], "status": "OK", "finish_id": state.finish_id, "last_sequence": state.last_input})) state.wait_finish_ack(context) except Exception as exc: if writer_started and key is not None: From ba28d8c8db8c9f7c7b0b44d6ae71e8425fd36de7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 22:20:09 +0800 Subject: [PATCH 017/241] fix(udf): encode UUID width in the ABI fingerprint --- pkg/udf/python/arrow.go | 9 ++++++++- pkg/udf/python/arrow_test.go | 3 +++ pkg/udf/python/worker/test_worker.py | 1 + pkg/udf/python/worker/worker.py | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 707483a71e37e..ba7812ea489be 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -99,11 +99,18 @@ func (d TypeDescriptor) Fingerprint() (string, error) { if err != nil { return "", err } + physicalFingerprint := physical.Fingerprint() + if types.T(d.TypeID) == types.T_uuid { + // Arrow-Go's FixedSizeBinary fingerprint omits ByteWidth. Keep the + // UUID width in the cross-language fingerprint as part of the frozen + // physical contract instead of relying only on the local type check. + physicalFingerprint = "@P[16]" + } h := sha256.New() h.Write([]byte("matrixone-python-udf-type\x00")) h.Write(canonical) h.Write([]byte{0}) - h.Write([]byte(physical.Fingerprint())) + h.Write([]byte(physicalFingerprint)) return hex.EncodeToString(h.Sum(nil)), nil } diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 7e388e4816c03..b658c67e2ecfb 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -95,6 +95,9 @@ func TestArrowValueDomainRejectsWidthAndTimeOverflow(t *testing.T) { func TestArrowTypeValidationIncludesFixedBinaryWidth(t *testing.T) { descriptor, err := NewTypeDescriptor(types.T_uuid.ToType()) require.NoError(t, err) + fingerprint, err := descriptor.Fingerprint() + require.NoError(t, err) + require.Equal(t, "370e2939c178acee55aaae27a7bcf92937a203e2788e9e0140d84884be042780", fingerprint) builder := array.NewFixedSizeBinaryBuilder(memory.NewGoAllocator(), &arrow.FixedSizeBinaryType{ByteWidth: 1}) builder.Append([]byte{0xff}) values := builder.NewFixedSizeBinaryArray() diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 75349c4767681..ce331a65fab90 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -26,6 +26,7 @@ def test_go_python_fingerprint_vectors(self): ({"type_id": worker.INT64, "offset_width": 32}, "482d3c55b8a9d662c2b41326b3ca55cbae65153e662c47c4919ba020d006262b"), ({"type_id": worker.VARCHAR, "width": 65535, "charset": 3, "offset_width": 32}, "e35cb66adb4bce519a6f3ec9cfa8a33adad6202cbe678f5fecffdeb28d65b824"), ({"type_id": worker.JSON, "offset_width": 32, "json_encoding": "canonical_text"}, "b156af5241a070ff80a287da19c46d1593dabee4fb5429f964452e711cd275eb"), + ({"type_id": worker.UUID, "offset_width": 0}, "370e2939c178acee55aaae27a7bcf92937a203e2788e9e0140d84884be042780"), ({"type_id": worker.DATE, "offset_width": 32, "temporal_encoding": "sql_zero_struct"}, "8c401bde992eb173ca8aedca97dbd9f47453b7a860fae199ae0439307e858b4b"), ] for descriptor, expected in cases: diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index e29caf8a02906..d5ded28d22e9f 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -355,7 +355,7 @@ def _physical_fingerprint(descriptor: Dict[str, Any]) -> str: if type_id in (CHAR, VARCHAR, TEXT, JSON): return "@d" if int(descriptor.get("offset_width", 32)) == 64 else "@N" if type_id == UUID: - return "@P" + return "@P[16]" if type_id in (DECIMAL64, DECIMAL128): precision = int(descriptor.get("width") or (18 if type_id == DECIMAL64 else 38)) return f"@X[128,{precision},{int(descriptor.get('scale') or 0)}]" From 8a103fe655911dd8dfa7a2d65649965d9730c5e2 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 9 Sep 2026 23:06:54 +0800 Subject: [PATCH 018/241] fix(udf): close Python execution channel contracts --- pkg/udf/python/worker/test_worker.py | 218 ++++++++++++++++++++++++++- pkg/udf/python/worker/worker.py | 178 +++++++++++++++++----- 2 files changed, 355 insertions(+), 41 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index ce331a65fab90..3fb9472245144 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -3,12 +3,19 @@ import datetime import importlib.util import json +import os import pathlib +import signal import struct +import subprocess import sys +import tempfile +import threading import time +import types import unittest import uuid +from unittest import mock import pyarrow as pa @@ -96,6 +103,11 @@ def test_decimal_precision_and_vector_child_validity_are_checked(self): with self.assertRaisesRegex(ValueError, "child validity"): worker._output_array(vector, vector_descriptor, 2) + valid = pa.array([None, [1.0, 2.0]], type=pa.list_(pa.float32(), 2)) + self.assertEqual(valid.to_pylist(), worker._output_array(valid, vector_descriptor, 2).to_pylist()) + visible = valid.slice(1, 1) + self.assertEqual(visible.to_pylist(), worker._output_array(visible, vector_descriptor, 1).to_pylist()) + def test_scalar_vector_null_keeps_fixed_size_child_slots(self): descriptor = {"type_id": worker.VECF32, "width": 2, "offset_width": 0} array = worker._output_array( @@ -158,8 +170,212 @@ def test_handler_stdout_cannot_inject_parent_protocol(self): "max_batch_bytes": 1 << 20, "input": worker._serialize_record_batch(batch), } - with self.assertRaisesRegex(ValueError, "handler process"): + result = worker._deserialize_record_batch( worker._run_handler_process(None, request, 3) + ) + self.assertEqual([1], result.column(0).to_pylist()) + + def test_handler_cannot_forge_completion_on_stdout(self): + descriptor = {"type_id": worker.INT64, "offset_width": 32} + batch = pa.RecordBatch.from_arrays([pa.array([77], type=pa.int64())], ["arg_0"]) + result_batch = pa.RecordBatch.from_arrays( + [pa.array([77], type=pa.int64())], ["result"] + ) + frame = struct.pack(">Q", len(bytes([worker._HANDLER_RESPONSE_OK]) + worker._serialize_record_batch(result_batch))) + frame += bytes([worker._HANDLER_RESPONSE_OK]) + worker._serialize_record_batch(result_batch) + request = { + "source": ( + "import os,time\n" + f"def f(ctx, x):\n os.write(1, {frame!r})\n" + " time.sleep(5)\n" + " raise RuntimeError('handler never returned success')\n" + ), + "handler": "f", + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "sdk_version": worker.SDK_VERSION, + "context": None, + "args": [descriptor], + "return": descriptor, + "max_batch_bytes": 1 << 20, + "input": worker._serialize_record_batch(batch), + } + with self.assertRaisesRegex(TimeoutError, "handler execution timeout"): + worker._run_handler_process(None, request, 0.1) + + def test_end_input_rejects_late_batch_without_running_handler(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + fence = { + "account_id": 1, + "statement_id": "review", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "late-input", + "lease_epoch": 1, + } + key = worker._tuple_key(fence) + descriptor = {"type_id": worker.INT64, "offset_width": 32} + batch = pa.RecordBatch.from_arrays( + [pa.array([1], type=pa.int64())], + schema=pa.schema([worker._field("arg_0", descriptor)]), + ) + payload = { + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "abi_contract": worker.ABI_CONTRACT, + "adapter_version": worker.ADAPTER_VERSION, + "sdk_version": worker.SDK_VERSION, + "args": [descriptor], + "return": descriptor, + "source": "def f(ctx, x): return x", + "handler": "f", + "max_batch_bytes": 1 << 20, + "max_batch_rows": 1024, + "handler_timeout_seconds": 2, + } + messages = [] + + def control(kind, **fields): + return worker._encode_control(dict(kind=kind, tuple=fence, **fields)) + + chunks = iter( + [ + types.SimpleNamespace( + data=None, + app_metadata=control("EndInput", last_sequence=0), + ), + types.SimpleNamespace( + data=batch, + app_metadata=control("InputBatch", sequence=1), + ), + ] + ) + reader = types.SimpleNamespace(schema=batch.schema, read_chunk=lambda: next(chunks)) + + class Writer: + def begin(self, schema): + pass + + def write_metadata(self, data): + messages.append(worker._decode_control(data)) + + def write_with_metadata(self, record, data): + messages.append(worker._decode_control(data)) + + handler = mock.Mock() + try: + with mock.patch.object(worker, "_run_handler_process", handler): + with self.assertRaisesRegex(ValueError, "after EndInput"): + server.do_exchange( + types.SimpleNamespace(is_cancelled=lambda: False), + types.SimpleNamespace( + command=control("OpenInvocation", payload=payload) + ), + reader, + Writer(), + ) + finally: + server.shutdown() + self.assertEqual(0, handler.call_count) + + @unittest.skipUnless(os.name == "posix", "process-group test") + def test_descendant_is_killed_after_handler_leader_exits(self): + with tempfile.TemporaryDirectory(prefix="mo-udf-owned-child-") as artifact: + witness = pathlib.Path(artifact) / "owned-child.json" + descendant = "import os,time; time.sleep(0.15); os.close(1); time.sleep(10)" + source = ( + "import json,os,pathlib,subprocess,sys\n" + "def f(ctx,x):\n" + f" child=subprocess.Popen([sys.executable,'-c',{descendant!r}],stdin=subprocess.DEVNULL)\n" + f" pathlib.Path({str(witness)!r}).write_text(json.dumps(dict(pid=child.pid,pgid=os.getpgrp())))\n" + " os._exit(7)\n" + ) + descriptor = {"type_id": worker.INT64, "offset_width": 32} + batch = pa.RecordBatch.from_arrays([pa.array([1], type=pa.int64())], ["arg_0"]) + request = { + "source": source, + "handler": "f", + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "sdk_version": worker.SDK_VERSION, + "context": None, + "args": [descriptor], + "return": descriptor, + "max_batch_bytes": 1 << 20, + "input": worker._serialize_record_batch(batch), + } + try: + with self.assertRaisesRegex(ValueError, "handler process"): + worker._run_handler_process(None, request, 2) + observed = json.loads(witness.read_text()) + try: + survived = os.getpgid(observed["pid"]) == observed["pgid"] + except ProcessLookupError: + survived = False + self.assertFalse(survived) + finally: + if witness.exists(): + owned = json.loads(witness.read_text()) + try: + if os.getpgid(owned["pid"]) == owned["pgid"]: + os.kill(owned["pid"], signal.SIGKILL) + except ProcessLookupError: + pass + + @unittest.skipUnless(os.name == "posix", "non-blocking pipe test") + def test_request_write_observes_handler_deadline(self): + created = [] + entered = threading.Event() + real_popen = subprocess.Popen + + def no_reader(argv, **kwargs): + process = real_popen( + [sys.executable, "-c", "import time; time.sleep(10)"], **kwargs + ) + created.append(process) + entered.set() + return process + + descriptor = {"type_id": worker.INT64, "offset_width": 32} + batch = pa.RecordBatch.from_arrays([pa.array([1], type=pa.int64())], ["arg_0"]) + request = { + "source": "def f(ctx, x): return x", + "handler": "f", + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "sdk_version": worker.SDK_VERSION, + "context": None, + "args": [descriptor], + "return": descriptor, + "max_batch_bytes": 1 << 20, + "input": worker._serialize_record_batch(batch), + "probe_padding": b"x" * (1 << 20), + } + outcome = [] + + def invoke(): + try: + worker._run_handler_process(None, request, 0.05) + except Exception as exc: + outcome.append(type(exc).__name__) + + thread = threading.Thread(target=invoke, daemon=True) + try: + with mock.patch.object(worker.subprocess, "Popen", side_effect=no_reader): + thread.start() + self.assertTrue(entered.wait(1)) + thread.join(0.5) + self.assertFalse(thread.is_alive()) + self.assertEqual(["TimeoutError"], outcome) + finally: + for process in created: + if process.poll() is None: + os.killpg(process.pid, signal.SIGKILL) + thread.join(2) + for process in created: + process.wait(timeout=1) + if process.stdin: + process.stdin.close() def test_zero_argument_vector_uses_context_rows(self): descriptor = {"type_id": worker.INT64, "offset_width": 32} diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index d5ded28d22e9f..5ce252a138f3e 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -50,6 +50,7 @@ MAX_EXECUTION_FRAME_BYTES = 1 << 30 _HANDLER_RESPONSE_ERROR = 0 _HANDLER_RESPONSE_OK = 1 +_HANDLER_RESPONSE_FD_ENV = "MATRIXONE_HANDLER_RESPONSE_FD" _MICROS_PER_SECOND = 1_000_000 _MAX_TIME_MICROS = (838 * 60 * 60 + 59 * 60 + 59) * _MICROS_PER_SECOND _MIN_TIMESTAMP = _datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=_datetime.timezone.utc) @@ -653,10 +654,18 @@ def _validate_array_values(array: pa.Array, descriptor: Dict[str, Any]) -> None: elif type_id == DATETIME: _check_scalar(SqlDatetime(False, value), descriptor) else: _check_scalar(SqlTimestamp(False, value), descriptor) elif type_id in (VECF32, VECF64): - values = array.values - for index in range(len(values)): - if not values[index].is_valid: - raise ValueError("TYPE_CONTRACT: vector child validity must be non-null") + # A FixedSizeListArray may have both null parents and a non-zero row + # offset. Its backing child array can therefore contain nulls that + # are either hidden behind a null parent or outside the visible slice. + # Only the children belonging to visible, non-null rows are part of + # the SQL value domain. + for row in range(len(array)): + value = array[row] + if not value.is_valid: + continue + for child in value.values: + if not child.is_valid: + raise ValueError("TYPE_CONTRACT: vector child validity must be non-null") elif type_id in (CHAR, VARCHAR, TEXT, JSON, BINARY, VARBINARY, BLOB, UUID, TIME, DECIMAL64, DECIMAL128): for index in range(len(array)): if not array[index].is_valid: continue @@ -757,6 +766,14 @@ def _write_execution_frame(stream, payload: bytes) -> None: def _execute_handler_subprocess() -> None: + response_fd_text = os.environ.pop(_HANDLER_RESPONSE_FD_ENV, None) + if response_fd_text is None: + raise ValueError("PROTOCOL: handler response channel is missing") + try: + response_fd = int(response_fd_text) + response_stream = os.fdopen(response_fd, "wb", buffering=0, closefd=True) + except (OSError, TypeError, ValueError) as exc: + raise ValueError("PROTOCOL: handler response channel is invalid") from exc try: size = struct.unpack(">Q", _read_exact(sys.stdin.buffer, 8))[0] if size > MAX_EXECUTION_FRAME_BYTES: @@ -765,7 +782,12 @@ def _execute_handler_subprocess() -> None: response = bytes([_HANDLER_RESPONSE_OK]) + _execute_handler_batch(request) except Exception as exc: response = bytes([_HANDLER_RESPONSE_ERROR]) + _safe_error(exc).encode("utf-8") - _write_execution_frame(sys.stdout.buffer, response) + try: + # This descriptor is created by the adapter and is distinct from the + # process stdout/stderr descriptors available to handler code. + _write_execution_frame(response_stream, response) + finally: + response_stream.close() def _context_is_cancelled(context) -> bool: @@ -778,14 +800,16 @@ def _context_is_cancelled(context) -> bool: def _kill_execution_process(process: subprocess.Popen) -> None: - if process.poll() is None: - if os.name == "posix": - try: - os.killpg(process.pid, signal.SIGKILL) - except ProcessLookupError: - pass - else: - process.kill() + # The leader can already have exited while one of its descendants keeps + # the execution alive. Always address the process group first; checking + # poll() before killpg() leaves that descendant outside the cleanup path. + if os.name == "posix": + try: + os.killpg(process.pid, signal.SIGKILL) + except ProcessLookupError: + pass + elif process.poll() is None: + process.kill() try: process.wait(timeout=1.0) except subprocess.TimeoutExpired: @@ -793,27 +817,63 @@ def _kill_execution_process(process: subprocess.Popen) -> None: process.wait() +def _execution_group_alive(process: subprocess.Popen) -> bool: + if os.name != "posix": + return process.poll() is None + try: + os.killpg(process.pid, 0) + except ProcessLookupError: + return False + except PermissionError: + return True + return True + + def _run_handler_process(context, request: Dict[str, Any], timeout_seconds: float) -> bytes: + deadline = time.monotonic() + timeout_seconds request_wire = pickle.dumps(request, protocol=5) if len(request_wire) > MAX_EXECUTION_FRAME_BYTES: raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") + request_frame = struct.pack(">Q", len(request_wire)) + request_wire + response_read_fd, response_write_fd = os.pipe() + process = None + selector = None popen_kwargs = { "stdin": subprocess.PIPE, - "stdout": subprocess.PIPE, + # Handler output is diagnostic-only. It must never share the + # adapter response channel, even when user code writes directly to + # file descriptor 1. + "stdout": subprocess.DEVNULL, "stderr": subprocess.DEVNULL, "close_fds": True, } if os.name == "posix": popen_kwargs["start_new_session"] = True - process = subprocess.Popen([sys.executable, os.path.abspath(__file__), "--execute-handler"], **popen_kwargs) - selector = selectors.DefaultSelector() + popen_kwargs["pass_fds"] = (response_write_fd,) + child_env = os.environ.copy() + child_env[_HANDLER_RESPONSE_FD_ENV] = str(response_write_fd) + # The extra descriptor is a protocol-channel separation mechanism, not a + # sandbox boundary. An unisolated handler with arbitrary OS access can + # still inspect inherited descriptors; production isolation must enforce + # the stronger policy that handler code cannot write this channel. + popen_kwargs["env"] = child_env response = bytearray() expected = None + response_eof = False + request_offset = 0 try: - _write_execution_frame(process.stdin, request_wire) - process.stdin.close() - selector.register(process.stdout, selectors.EVENT_READ) - deadline = time.monotonic() + timeout_seconds + process = subprocess.Popen( + [sys.executable, os.path.abspath(__file__), "--execute-handler"], + **popen_kwargs, + ) + os.close(response_write_fd) + response_write_fd = -1 + selector = selectors.DefaultSelector() + stdin_fd = process.stdin.fileno() + os.set_blocking(stdin_fd, False) + os.set_blocking(response_read_fd, False) + selector.register(stdin_fd, selectors.EVENT_WRITE, "request") + selector.register(response_read_fd, selectors.EVENT_READ, "response") while True: if _context_is_cancelled(context): raise TimeoutError("DEADLINE_EXCEEDED: handler execution cancelled") @@ -821,20 +881,47 @@ def _run_handler_process(context, request: Dict[str, Any], timeout_seconds: floa if remaining <= 0: raise TimeoutError("DEADLINE_EXCEEDED: handler execution timeout") events = selector.select(min(remaining, 0.1)) - if not events: - continue - chunk = os.read(process.stdout.fileno(), 65536) - if not chunk: - if expected is None or len(response) < expected: - raise ValueError("USER_CODE: handler process exited without a response") - break - response.extend(chunk) - if expected is None and len(response) >= 8: - expected = struct.unpack(">Q", response[:8])[0] - if expected > MAX_EXECUTION_FRAME_BYTES: - raise ValueError("RESOURCE_EXHAUSTED: execution response is too large") - if expected is not None and len(response) >= expected + 8: - break + for event, _ in events: + if event.data == "request": + try: + written = os.write(stdin_fd, request_frame[request_offset:]) + except BlockingIOError: + continue + except BrokenPipeError as exc: + raise ValueError("USER_CODE: handler process closed its request channel") from exc + request_offset += written + if request_offset == len(request_frame): + selector.unregister(stdin_fd) + process.stdin.close() + else: + try: + chunk = os.read(response_read_fd, 65536) + except BlockingIOError: + continue + if not chunk: + response_eof = True + selector.unregister(response_read_fd) + if expected is None or len(response) < expected + 8: + raise ValueError("USER_CODE: handler process exited without a response") + else: + response.extend(chunk) + if expected is None and len(response) >= 8: + expected = struct.unpack(">Q", response[:8])[0] + if expected > MAX_EXECUTION_FRAME_BYTES: + raise ValueError("RESOURCE_EXHAUSTED: execution response is too large") + if expected is not None and len(response) > expected + 8: + raise ValueError("PROTOCOL: handler process returned trailing response data") + + # A complete frame is not enough. The adapter wrapper must have + # returned normally, and all of its process-group descendants + # must be gone before the adapter accepts the result. + if process.poll() is not None: + if process.returncode != 0: + raise ValueError("USER_CODE: handler process exited abnormally") + if _execution_group_alive(process): + raise ValueError("USER_CODE: handler process left descendant processes") + if response_eof and expected is not None and len(response) == expected + 8: + break payload = bytes(response[8 : expected + 8]) if not payload: raise ValueError("PROTOCOL: handler process returned an empty response") @@ -848,12 +935,15 @@ def _run_handler_process(context, request: Dict[str, Any], timeout_seconds: floa raise ValueError("PROTOCOL: handler process returned an unknown status") return payload[1:] finally: - selector.close() - if process.poll() is None: + if selector is not None: + selector.close() + if process is not None: _kill_execution_process(process) - else: - process.wait() - process.stdout.close() + if process.stdin is not None: + process.stdin.close() + if response_write_fd >= 0: + os.close(response_write_fd) + os.close(response_read_fd) @@ -1037,6 +1127,8 @@ def do_exchange(self, context, descriptor, reader, writer): except StopIteration: break if chunk.data is not None: + if ended: + raise ValueError("PROTOCOL: input arrived after EndInput") if schema is None: schema = reader.schema _validate_schema(schema, args) @@ -1081,7 +1173,13 @@ def do_exchange(self, context, descriptor, reader, writer): control = _decode_control(chunk.app_metadata) _require_tuple(control["tuple"], open_control["tuple"]) if control["kind"] == "EndInput": - if ended or _required_uint64(control, "last_sequence", allow_zero=True) != state.last_input: raise ValueError("PROTOCOL: invalid EndInput") + last_sequence = _required_uint64(control, "last_sequence", allow_zero=True) + if ended: + if last_sequence != state.last_input: + raise ValueError("PROTOCOL: EndInput changed after input was closed") + continue + if last_sequence != state.last_input: + raise ValueError("PROTOCOL: invalid EndInput") ended = True elif control["kind"] != "OpenInvocation": raise ValueError("PROTOCOL: unexpected control without Arrow data") From 71df7d5a0ada89e101807a787e1056072823cb88 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 10:47:36 +0800 Subject: [PATCH 019/241] fix(udf): close Python gateway response contracts --- pkg/udf/python/arrow.go | 23 +++++++++++++--- pkg/udf/python/arrow_test.go | 32 ++++++++++++++++++++++ pkg/udf/python/gateway.go | 47 +++++++++++++++++++++++---------- pkg/udf/python/gateway_test.go | 18 +++++++++++++ pkg/udf/python/worker/worker.py | 20 ++++++++++++-- 5 files changed, 121 insertions(+), 19 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index ba7812ea489be..484d16aff3b09 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -540,12 +540,23 @@ func DecodeRecordBatch(schemaFrame, batchFrame ArrowFrame, maxBytes int64) (arro if len(schemaFrame.Header) == 0 || len(batchFrame.Header) == 0 || maxBytes <= 0 { return nil, fmt.Errorf("invalid Arrow output frames") } - if _, err := arrowipc.InspectMessage(context.Background(), schemaFrame.Header, arrowipc.ValidationOptions{MaxMetadataBytes: arrowipc.DefaultMaxMetadataBytes, MaxBodyBytes: 0, BodyEnvelopeBytes: 0, MaxDecodedRecordBytes: 1}); err != nil { + if len(schemaFrame.Body) != 0 { + return nil, fmt.Errorf("invalid Arrow schema frame body") + } + schemaInfo, err := arrowipc.InspectMessage(context.Background(), schemaFrame.Header, arrowipc.ValidationOptions{MaxMetadataBytes: arrowipc.DefaultMaxMetadataBytes, MaxBodyBytes: 0, BodyEnvelopeBytes: 0, MaxDecodedRecordBytes: 1}) + if err != nil { return nil, err } - if _, err := arrowipc.InspectMessage(context.Background(), batchFrame.Header, arrowipc.ValidationOptions{MaxMetadataBytes: arrowipc.DefaultMaxMetadataBytes, MaxBodyBytes: maxBytes, BodyEnvelopeBytes: int64(len(batchFrame.Body)), Body: batchFrame.Body, ValidateBody: true, MaxDecodedRecordBytes: maxBytes}); err != nil { + if schemaInfo.HeaderType != arrowipc.MessageHeaderSchema { + return nil, fmt.Errorf("invalid Arrow schema frame header %d", schemaInfo.HeaderType) + } + batchInfo, err := arrowipc.InspectMessage(context.Background(), batchFrame.Header, arrowipc.ValidationOptions{MaxMetadataBytes: arrowipc.DefaultMaxMetadataBytes, MaxBodyBytes: maxBytes, BodyEnvelopeBytes: int64(len(batchFrame.Body)), Body: batchFrame.Body, ValidateBody: true, MaxDecodedRecordBytes: maxBytes}) + if err != nil { return nil, err } + if batchInfo.HeaderType != arrowipc.MessageHeaderRecordBatch { + return nil, fmt.Errorf("invalid Arrow record frame header %d", batchInfo.HeaderType) + } stream := make([]byte, 0, len(schemaFrame.Header)+len(batchFrame.Header)+len(batchFrame.Body)+32) stream = appendIPCFrame(stream, schemaFrame.Header, schemaFrame.Body) stream = appendIPCFrame(stream, batchFrame.Header, batchFrame.Body) @@ -583,7 +594,13 @@ func appendIPCFrame(dst, header, body []byte) []byte { } func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vector.FunctionResultWrapper, mp *mpool.MPool) error { - if input == nil || result == nil || input.Len() == 0 { + if input == nil { + return fmt.Errorf("TYPE_CONTRACT: missing Arrow result") + } + if result == nil { + return fmt.Errorf("python udf: missing result wrapper") + } + if input.Len() == 0 { return nil } if mp == nil { diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index b658c67e2ecfb..716290debabf8 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -62,6 +62,38 @@ func TestEncodeRecordBatchUsesFlightPayloadFrames(t *testing.T) { require.Equal(t, int64(3), decodedValues.Value(2)) } +func TestDecodeRecordBatchRequiresSchemaAndRecordHeaders(t *testing.T) { + descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + field, err := descriptor.Field("arg_0") + require.NoError(t, err) + builder := array.NewInt64Builder(memory.NewGoAllocator()) + builder.Append(1) + values := builder.NewInt64Array() + defer values.Release() + record := array.NewRecordBatch(arrow.NewSchema([]arrow.Field{field}, nil), []arrow.Array{values}, 1) + defer record.Release() + frames, err := EncodeRecordBatch(record, DefaultMaxBatchBytes) + require.NoError(t, err) + + _, err = DecodeRecordBatch(ArrowFrame{Header: frames[1].Header}, frames[1], DefaultMaxBatchBytes) + require.Error(t, err) + _, err = DecodeRecordBatch(frames[0], frames[0], DefaultMaxBatchBytes) + require.ErrorContains(t, err, "record frame header") + _, err = DecodeRecordBatch(ArrowFrame{Header: frames[0].Header, Body: []byte{1}}, frames[1], DefaultMaxBatchBytes) + require.ErrorContains(t, err, "schema frame body") +} + +func TestAppendArrowResultRejectsMissingConsumer(t *testing.T) { + builder := array.NewInt64Builder(memory.NewGoAllocator()) + builder.Append(1) + values := builder.NewInt64Array() + defer values.Release() + descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + require.ErrorContains(t, AppendArrowResult(descriptor, values, nil, nil), "missing result wrapper") +} + func TestZeroArgumentRecordPreservesRows(t *testing.T) { record := array.NewRecordBatch(arrow.NewSchema(nil, nil), nil, 3) defer record.Release() diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 3c7fdbd6b9ced..d7cf2df554aea 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -127,13 +127,6 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if err := validateInvocation(invocation); err != nil { return err } - if invocation.Length == 0 { - return result.PreExtendAndReset(0) - } - if err := g.connect(); err != nil { - return err - } - args := make([]TypeDescriptor, len(invocation.Args)) for i, typ := range invocation.Args { var err error @@ -146,6 +139,12 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if err != nil { return err } + if invocation.Length == 0 { + return result.PreExtendAndReset(0) + } + if err := g.connect(); err != nil { + return err + } openBody, err := json.Marshal(openPayload{Handler: invocation.Handler, Source: invocation.Source, Mode: invocation.Mode, NullPolicy: invocation.NullPolicy, ABIContract: invocation.ABIContract, AdapterVersion: invocation.AdapterVersion, SDKVersion: invocation.SDKVersion, Context: cloneMap(invocation.Context), Args: args, Return: returnDescriptor, MaxBatchBytes: g.cfg.MaxBatchBytes, MaxBatchRows: g.cfg.MaxBatchRows, HandlerTimeoutSeconds: g.cfg.RequestTimeout.Seconds()}) if err != nil { return fmt.Errorf("python udf: encode open payload: %w", err) @@ -333,11 +332,12 @@ func (g *Gateway) receiveResultBatch( if len(data.DataBody) != 0 { return 0, fmt.Errorf("python udf: result schema contains a body") } - if len(data.AppMetadata) > 0 { - control, err := protocol.UnmarshalControl(data.AppMetadata) - if err != nil || control.Tuple != tuple || control.Kind != "ResultSchema" { - return 0, fmt.Errorf("python udf: invalid result schema metadata") - } + if len(data.AppMetadata) == 0 { + return 0, fmt.Errorf("python udf: result schema is missing metadata") + } + control, err := protocol.UnmarshalControl(data.AppMetadata) + if err != nil || control.Tuple != tuple || control.Kind != "ResultSchema" { + return 0, fmt.Errorf("python udf: invalid result schema metadata") } *schemaFrame = &ArrowFrame{Header: append([]byte(nil), data.DataHeader...)} continue @@ -504,8 +504,8 @@ func (g *Gateway) action(ctx context.Context, kind string, control protocol.Cont if err != nil { return err } - if ack.Tuple != control.Tuple || ack.Kind != "Ack" { - return fmt.Errorf("python udf: %s returned an invalid ACK", kind) + if err := validateActionAck(kind, control, ack); err != nil { + return err } if ack.Status != statusOK { return fmt.Errorf("python udf: %s rejected: %s", kind, ack.Reason) @@ -519,6 +519,25 @@ func (g *Gateway) action(ctx context.Context, kind string, control protocol.Cont return nil } +func validateActionAck(kind string, request, ack protocol.Control) error { + if ack.Tuple != request.Tuple || ack.Kind != "Ack" { + return fmt.Errorf("python udf: %s returned an invalid ACK", kind) + } + switch kind { + case "AcknowledgeResults": + if ack.AckSequence != request.AckSequence { + return fmt.Errorf("python udf: %s ACK sequence %d, expected %d", kind, ack.AckSequence, request.AckSequence) + } + case "AcknowledgeFinish": + if ack.FinishID != request.FinishID { + return fmt.Errorf("python udf: %s ACK finish ID does not match the request", kind) + } + default: + return fmt.Errorf("python udf: unsupported action %q", kind) + } + return nil +} + func cloneMap(input map[string]string) map[string]string { if len(input) == 0 { return nil diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index 341b84dc750fc..818e82a7106e9 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -58,3 +58,21 @@ func TestValidateInvocationRequiresFrozenContract(t *testing.T) { }) } } + +func TestValidateActionAckCorrelatesTheRequestedFence(t *testing.T) { + request := protocol.Control{ + Kind: "AcknowledgeResults", + Tuple: validInvocation().Tuple, + AckSequence: 3, + } + ack := protocol.Control{Kind: "Ack", Tuple: request.Tuple, Status: statusOK, AckSequence: 3} + require.NoError(t, validateActionAck(request.Kind, request, ack)) + ack.AckSequence = 2 + require.ErrorContains(t, validateActionAck(request.Kind, request, ack), "ACK sequence") + + finish := protocol.Control{Kind: "AcknowledgeFinish", Tuple: request.Tuple, FinishID: "finish-1"} + finishAck := protocol.Control{Kind: "Ack", Tuple: request.Tuple, Status: statusOK, FinishID: "finish-1"} + require.NoError(t, validateActionAck(finish.Kind, finish, finishAck)) + finishAck.FinishID = "finish-2" + require.ErrorContains(t, validateActionAck(finish.Kind, finish, finishAck), "finish ID") +} diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 5ce252a138f3e..d839d6e90bd81 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1067,14 +1067,30 @@ def do_action(self, context, action): terminal = key in self._terminal if state is None: if terminal: - yield _encode_control({"kind": "Ack", "tuple": control["tuple"], "status": "OK"}) + yield _encode_control( + { + "kind": "Ack", + "tuple": control["tuple"], + "status": "OK", + "ack_sequence": control.get("ack_sequence", 0), + "finish_id": control.get("finish_id", ""), + } + ) return raise ValueError("PROTOCOL: unknown invocation") if action.type == "AcknowledgeResults": state.ack_result(_required_uint64(control, "ack_sequence")) elif action.type == "AcknowledgeFinish": state.ack_finish(_required_string(control, "finish_id")) - yield _encode_control({"kind": "Ack", "tuple": control["tuple"], "status": "OK", "ack_sequence": control.get("ack_sequence", 0)}) + yield _encode_control( + { + "kind": "Ack", + "tuple": control["tuple"], + "status": "OK", + "ack_sequence": control.get("ack_sequence", 0), + "finish_id": control.get("finish_id", ""), + } + ) def do_exchange(self, context, descriptor, reader, writer): state = None From e0efca5bbbd1341630073083f17ec0e716f59ff6 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 10:51:51 +0800 Subject: [PATCH 020/241] fix(udf): make Python runtime shutdown terminal --- pkg/udf/python/gateway.go | 16 +++++++ pkg/udf/python/gateway_test.go | 8 ++++ pkg/udf/python/supervisor.go | 34 +++++++------ pkg/udf/python/supervisor_process_other.go | 14 ++++++ pkg/udf/python/supervisor_process_unix.go | 26 ++++++++++ pkg/udf/python/supervisor_test.go | 45 ++++++++++++++++++ pkg/udf/python/worker/test_worker.py | 46 +++++++++++++++++- pkg/udf/python/worker/worker.py | 55 +++++++++++++++------- 8 files changed, 211 insertions(+), 33 deletions(-) create mode 100644 pkg/udf/python/supervisor_process_other.go create mode 100644 pkg/udf/python/supervisor_process_unix.go create mode 100644 pkg/udf/python/supervisor_test.go diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index d7cf2df554aea..8cba52c105cee 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -36,12 +36,15 @@ const ( statusOK = "OK" ) +var errGatewayClosed = errors.New("python udf gateway is closed") + type Gateway struct { cfg ClientConfig conn *grpc.ClientConn flight flight.FlightServiceClient mu sync.Mutex lifecycle sync.RWMutex + closed bool } func NewGateway(cfg ClientConfig) (*Gateway, error) { @@ -65,6 +68,9 @@ func (g *Gateway) Language() string { return udf.LanguagePython } func (g *Gateway) connect() error { g.mu.Lock() defer g.mu.Unlock() + if g.closed { + return errGatewayClosed + } if g.flight != nil { return nil } @@ -88,6 +94,10 @@ func (g *Gateway) Close() error { defer g.lifecycle.Unlock() g.mu.Lock() defer g.mu.Unlock() + if g.closed { + return nil + } + g.closed = true if g.conn == nil { return nil } @@ -116,6 +126,12 @@ type openPayload struct { func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, result vector.FunctionResultWrapper, mp *mpool.MPool) error { g.lifecycle.RLock() defer g.lifecycle.RUnlock() + g.mu.Lock() + closed := g.closed + g.mu.Unlock() + if closed { + return errGatewayClosed + } if ctx == nil { ctx = context.Background() } diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index 818e82a7106e9..f83abcca7e31b 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -76,3 +76,11 @@ func TestValidateActionAckCorrelatesTheRequestedFence(t *testing.T) { finishAck.FinishID = "finish-2" require.ErrorContains(t, validateActionAck(finish.Kind, finish, finishAck), "finish ID") } + +func TestGatewayCloseIsTerminal(t *testing.T) { + gateway, err := NewGateway(ClientConfig{}) + require.NoError(t, err) + require.NoError(t, gateway.Close()) + require.ErrorIs(t, gateway.connect(), errGatewayClosed) + require.NoError(t, gateway.Close()) +} diff --git a/pkg/udf/python/supervisor.go b/pkg/udf/python/supervisor.go index 14674b2b376c2..30d85fc2233f4 100644 --- a/pkg/udf/python/supervisor.go +++ b/pkg/udf/python/supervisor.go @@ -20,10 +20,11 @@ import ( ) type Supervisor struct { - cfg Config - mu sync.Mutex - cmd *exec.Cmd - log io.WriteCloser + cfg Config + mu sync.Mutex + cmd *exec.Cmd + log io.WriteCloser + done chan struct{} } var supervisorNumber atomic.Int32 @@ -67,25 +68,28 @@ func (s *Supervisor) Start() error { return err } cmd := exec.Command(executable, "-u", workerPath, "--address="+s.cfg.Address) + prepareSupervisorCommand(cmd) cmd.Stdout, cmd.Stderr = logFile, logFile if err := cmd.Start(); err != nil { _ = logFile.Close() return err } - s.cmd, s.log = cmd, logFile - go s.wait(cmd, logFile) + done := make(chan struct{}) + s.cmd, s.log, s.done = cmd, logFile, done + go s.wait(cmd, logFile, done) logutil.Infof("started Python UDF worker: %s", cmd.String()) return nil } -func (s *Supervisor) wait(cmd *exec.Cmd, log io.WriteCloser) { +func (s *Supervisor) wait(cmd *exec.Cmd, log io.WriteCloser, done chan struct{}) { err := cmd.Wait() _ = log.Close() s.mu.Lock() if s.cmd == cmd { - s.cmd, s.log = nil, nil + s.cmd, s.log, s.done = nil, nil, nil } s.mu.Unlock() + close(done) if err != nil { logutil.Errorf("Python UDF worker exited: %v", err) } @@ -93,8 +97,7 @@ func (s *Supervisor) wait(cmd *exec.Cmd, log io.WriteCloser) { func (s *Supervisor) Close() error { s.mu.Lock() - cmd, log := s.cmd, s.log - s.cmd, s.log = nil, nil + cmd, log, done := s.cmd, s.log, s.done s.mu.Unlock() if cmd == nil { if log != nil { @@ -102,11 +105,12 @@ func (s *Supervisor) Close() error { } return nil } - if err := cmd.Process.Kill(); err != nil && !errors.Is(err, os.ErrProcessDone) { - return fmt.Errorf("stop Python UDF worker: %w", err) + var closeErr error + if err := killSupervisorProcess(cmd); err != nil && !errors.Is(err, os.ErrProcessDone) { + closeErr = fmt.Errorf("stop Python UDF worker: %w", err) } - if log != nil { - return log.Close() + if done != nil { + <-done } - return nil + return closeErr } diff --git a/pkg/udf/python/supervisor_process_other.go b/pkg/udf/python/supervisor_process_other.go new file mode 100644 index 0000000000000..6ec19f6431cc9 --- /dev/null +++ b/pkg/udf/python/supervisor_process_other.go @@ -0,0 +1,14 @@ +//go:build !(aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris) + +package python + +import "os/exec" + +func prepareSupervisorCommand(*exec.Cmd) {} + +func killSupervisorProcess(cmd *exec.Cmd) error { + if cmd == nil || cmd.Process == nil { + return nil + } + return cmd.Process.Kill() +} diff --git a/pkg/udf/python/supervisor_process_unix.go b/pkg/udf/python/supervisor_process_unix.go new file mode 100644 index 0000000000000..20bbb1f545436 --- /dev/null +++ b/pkg/udf/python/supervisor_process_unix.go @@ -0,0 +1,26 @@ +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris + +package python + +import ( + "errors" + "os/exec" + "syscall" +) + +func prepareSupervisorCommand(cmd *exec.Cmd) { + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} +} + +func killSupervisorProcess(cmd *exec.Cmd) error { + if cmd == nil || cmd.Process == nil { + return nil + } + if err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL); err != nil { + if errors.Is(err, syscall.ESRCH) { + return cmd.Process.Kill() + } + return err + } + return nil +} diff --git a/pkg/udf/python/supervisor_test.go b/pkg/udf/python/supervisor_test.go new file mode 100644 index 0000000000000..b5f17f2cfc6cb --- /dev/null +++ b/pkg/udf/python/supervisor_test.go @@ -0,0 +1,45 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package python + +import ( + "os" + "path/filepath" + "runtime" + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestSupervisorCloseStopsTheCurrentWorkerBeforeReturning(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("worker supervisor test uses a POSIX executable script") + } + dir := t.TempDir() + workerPath := filepath.Join(dir, "worker.py") + require.NoError(t, os.WriteFile(workerPath, []byte("#!/bin/sh\nwhile :; do sleep 1; done\n"), 0o755)) + + supervisor, err := NewSupervisor(Config{Address: "127.0.0.1:0", Path: dir, Python: "/bin/sh"}) + require.NoError(t, err) + require.NoError(t, supervisor.Start()) + require.Eventually(t, func() bool { + supervisor.mu.Lock() + defer supervisor.mu.Unlock() + return supervisor.cmd != nil + }, time.Second, time.Millisecond) + require.NoError(t, supervisor.Close()) + require.Eventually(t, func() bool { + supervisor.mu.Lock() + defer supervisor.mu.Unlock() + return supervisor.cmd == nil && supervisor.done == nil + }, time.Second, time.Millisecond) + + // A second start is only safe after the first wait has completed. This + // catches a Close implementation that clears cmd and returns before Wait. + require.NoError(t, supervisor.Start()) + require.NoError(t, supervisor.Close()) +} diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 3fb9472245144..a49d25373dec6 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -434,7 +434,9 @@ def test_terminal_admission_does_not_evict_live_tombstones(self): server._admit((1, "statement", "group", 1, "second", 1)) self.assertIn(first, server._terminal) with server._lock: - server._terminal[first] = (0.0, state.terminal_bytes) + server._terminal[first] = worker._TerminalRecord( + 0.0, state.terminal_bytes, state.last_result, state.finish_id + ) server._purge_terminal_locked(1.0) second = server._admit((1, "statement", "group", 1, "second", 1)) self.assertIsNotNone(second) @@ -442,6 +444,48 @@ def test_terminal_admission_does_not_evict_live_tombstones(self): worker.MAX_LEDGER_ENTRIES = old_records worker.MAX_LEDGER_BYTES = old_bytes + def test_terminal_ack_requires_the_completed_fence(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + key = (1, "statement", "group", 1, "completed", 1) + state = server._admit(key) + state.last_result = 2 + state.finish_id = "finish-2" + server._finish_invocation(key, state) + + tuple_value = { + "account_id": key[0], + "statement_id": key[1], + "group_id": key[2], + "group_epoch": key[3], + "invocation_id": key[4], + "lease_epoch": key[5], + } + result_action = types.SimpleNamespace( + type="AcknowledgeResults", + body=worker._encode_control( + { + "kind": "AcknowledgeResults", + "tuple": tuple_value, + "ack_sequence": 2, + } + ), + ) + ack = worker._decode_control(next(server.do_action(None, result_action))) + self.assertEqual(2, ack["ack_sequence"]) + + wrong_action = types.SimpleNamespace( + type="AcknowledgeResults", + body=worker._encode_control( + { + "kind": "AcknowledgeResults", + "tuple": tuple_value, + "ack_sequence": 1, + } + ), + ) + with self.assertRaisesRegex(ValueError, "completed result"): + next(server.do_action(None, wrong_action)) + def test_active_fence_cannot_be_admitted_twice(self): server = worker.RoutineFlightServer("grpc://127.0.0.1:0") key = (1, "statement", "group", 1, "invocation", 1) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index d839d6e90bd81..7d581e47b9d45 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -143,6 +143,14 @@ class VectorContext: num_rows: int = 0 +@dataclass(frozen=True, slots=True) +class _TerminalRecord: + expires_at: float + bytes: int + last_result: int + finish_id: Optional[str] + + _FENCING_CONTEXT_KEYS = frozenset( {"account_id", "statement_id", "group_id", "group_epoch", "invocation_id", "lease_epoch"} ) @@ -997,7 +1005,7 @@ def __init__(self, location: str): super().__init__(location) self._lock = threading.RLock() self._active: Dict[tuple, _InvocationState] = {} - self._terminal: OrderedDict[tuple, tuple[float, int]] = OrderedDict() + self._terminal: OrderedDict[tuple, _TerminalRecord] = OrderedDict() self._terminal_bytes = 0 self._active_bytes = 0 @@ -1010,10 +1018,10 @@ def _entry_bytes(key: tuple) -> int: return len(encoded) + 128 def _purge_terminal_locked(self, now: float) -> None: - expired = [key for key, (deadline, _) in self._terminal.items() if deadline <= now] + expired = [key for key, record in self._terminal.items() if record.expires_at <= now] for key in expired: - _, size = self._terminal.pop(key) - self._terminal_bytes -= size + record = self._terminal.pop(key) + self._terminal_bytes -= record.bytes def _admit(self, key: tuple) -> _InvocationState: size = self._entry_bytes(key) @@ -1034,7 +1042,9 @@ def _admit(self, key: tuple) -> _InvocationState: def _remember_terminal_locked(self, key: tuple, state: _InvocationState) -> None: deadline = time.monotonic() + TERMINAL_TTL_SECONDS - self._terminal[key] = (deadline, state.terminal_bytes) + self._terminal[key] = _TerminalRecord( + deadline, state.terminal_bytes, state.last_result, state.finish_id + ) self._terminal.move_to_end(key) self._terminal_bytes += state.terminal_bytes @@ -1064,19 +1074,30 @@ def do_action(self, context, action): with self._lock: self._purge_terminal_locked(time.monotonic()) state = self._active.get(key) - terminal = key in self._terminal + terminal = self._terminal.get(key) if state is None: - if terminal: - yield _encode_control( - { - "kind": "Ack", - "tuple": control["tuple"], - "status": "OK", - "ack_sequence": control.get("ack_sequence", 0), - "finish_id": control.get("finish_id", ""), - } - ) - return + if terminal is None: + raise ValueError("PROTOCOL: unknown invocation") + if not terminal.finish_id: + raise ValueError("PROTOCOL: invocation did not complete successfully") + if action.type == "AcknowledgeResults": + sequence = _required_uint64(control, "ack_sequence") + if sequence != terminal.last_result: + raise ValueError("PROTOCOL: terminal result ACK does not match the completed result") + else: + finish_id = _required_string(control, "finish_id") + if finish_id != terminal.finish_id: + raise ValueError("PROTOCOL: terminal Finish ACK does not match the completed Finish") + yield _encode_control( + { + "kind": "Ack", + "tuple": control["tuple"], + "status": "OK", + "ack_sequence": control.get("ack_sequence", 0), + "finish_id": control.get("finish_id", ""), + } + ) + return raise ValueError("PROTOCOL: unknown invocation") if action.type == "AcknowledgeResults": state.ack_result(_required_uint64(control, "ack_sequence")) From 91c916d484f6e929426a1715ab83efc9fb5d1385 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 11:49:45 +0800 Subject: [PATCH 021/241] fix(udf): close Python SQL and runtime contracts --- etc/v1/launch-with-python-udf-worker/cn.toml | 14 --- .../launch-with-python-udf-worker/launch.toml | 15 --- .../python-udf-worker.toml | 6 -- pkg/frontend/authenticate.go | 12 ++- pkg/sql/parsers/dialect/mysql/keywords.go | 4 + pkg/sql/parsers/dialect/mysql/mysql_sql.y | 58 +++++++++++- .../parsers/dialect/mysql/mysql_sql_test.go | 38 ++++++++ pkg/sql/parsers/tree/function.go | 33 +++++++ pkg/udf/protocol/protocol.go | 2 +- pkg/udf/protocol/protocol_test.go | 1 + pkg/udf/python/arrow.go | 12 +-- pkg/udf/python/arrow_test.go | 20 ++++ pkg/udf/python/gateway.go | 93 ++++++++++++------- pkg/udf/python/supervisor.go | 52 +++++------ pkg/udf/python/worker/test_worker.py | 6 ++ pkg/udf/python/worker/worker.py | 3 +- .../cases/udf_python/vector_mode.result | 31 +++++++ .../cases/udf_python/vector_mode.sql | 31 +++++++ 18 files changed, 318 insertions(+), 113 deletions(-) delete mode 100644 etc/v1/launch-with-python-udf-worker/cn.toml delete mode 100644 etc/v1/launch-with-python-udf-worker/launch.toml delete mode 100644 etc/v1/launch-with-python-udf-worker/python-udf-worker.toml create mode 100644 test/distributed/cases/udf_python/vector_mode.result create mode 100644 test/distributed/cases/udf_python/vector_mode.sql diff --git a/etc/v1/launch-with-python-udf-worker/cn.toml b/etc/v1/launch-with-python-udf-worker/cn.toml deleted file mode 100644 index cf5b576cbc864..0000000000000 --- a/etc/v1/launch-with-python-udf-worker/cn.toml +++ /dev/null @@ -1,14 +0,0 @@ -service-type = "CN" -data-dir = "./mo-data" - -[log] -level = "info" - -[cn] -uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41bf" -port-base = 18000 - -[cn.python-udf-client] -enabled = true -allow-unisolated = true -server-address = "127.0.0.1:50051" diff --git a/etc/v1/launch-with-python-udf-worker/launch.toml b/etc/v1/launch-with-python-udf-worker/launch.toml deleted file mode 100644 index 8171c1ead1cd7..0000000000000 --- a/etc/v1/launch-with-python-udf-worker/launch.toml +++ /dev/null @@ -1,15 +0,0 @@ -logservices = [ - "./etc/v1/launch/log.toml", -] - -tnservices = [ - "./etc/v1/launch/tn.toml" -] - -cnservices = [ - "./etc/v1/launch-with-python-udf-worker/cn.toml" -] - -python-udf-services = [ - "./etc/v1/launch-with-python-udf-worker/python-udf-worker.toml" -] diff --git a/etc/v1/launch-with-python-udf-worker/python-udf-worker.toml b/etc/v1/launch-with-python-udf-worker/python-udf-worker.toml deleted file mode 100644 index 40a0d22bb0ade..0000000000000 --- a/etc/v1/launch-with-python-udf-worker/python-udf-worker.toml +++ /dev/null @@ -1,6 +0,0 @@ -service-type = "PYTHON_UDF" - -[python-udf-worker] -uuid = "dd1dccb4-4d3c-41f8-b482-5251dc7a41b2" -address = "127.0.0.1:50051" -path = "pkg/udf/python/worker" diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index 30f1a0e7d1dc1..da2fc6f2223c1 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -11797,12 +11797,20 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C if cf.Import { return moerr.NewNotSupportedNoCtx("Python artifact import requires the immutable artifact catalog") } + mode := cf.Mode + if mode == "" { + mode = "SCALAR" + } + nullPolicy := cf.NullPolicy + if nullPolicy == "" { + nullPolicy = udf.NullCallHandler + } nb := function.PythonRoutineBody{ Handler: cf.Handler, Source: cf.Body, - Mode: "SCALAR", - NullPolicy: udf.NullCallHandler, + Mode: mode, + NullPolicy: nullPolicy, ABIContract: udf.PythonABIContract, AdapterVersion: udf.PythonAdapterVersion, SDKVersion: udf.PythonSDKVersion, diff --git a/pkg/sql/parsers/dialect/mysql/keywords.go b/pkg/sql/parsers/dialect/mysql/keywords.go index ce91229d53701..a3fb939b9e649 100644 --- a/pkg/sql/parsers/dialect/mysql/keywords.go +++ b/pkg/sql/parsers/dialect/mysql/keywords.go @@ -73,6 +73,7 @@ func init() { "bit_and": BIT_AND, "bit_xor": BIT_XOR, "call": CALL, + "called": CALLED, "cancel": CANCEL, "catalog": CATALOG, "catalogs": CATALOGS, @@ -271,6 +272,7 @@ func init() { "mongodb_path": MONGODB_PATH, "if": IF, "ignore": IGNORE, + "input": INPUT, "in": IN, "index": INDEX, "indexes": INDEXES, @@ -483,6 +485,7 @@ func init() { "row_number": ROW_NUMBER, "rtree": RTREE, "schema": SCHEMA, + "scalar": SCALAR, "schemas": SCHEMAS, "schedule": SCHEDULE, "second": SECOND, @@ -727,6 +730,7 @@ func init() { "array": ARRAY, "array_agg": JSON_ARRAYAGG, "vecf32": VECF32, + "vector": VECTOR, "vecf64": VECF64, "vecbf16": VECBF16, "vecf16": VECF16, diff --git a/pkg/sql/parsers/dialect/mysql/mysql_sql.y b/pkg/sql/parsers/dialect/mysql/mysql_sql.y index 50d6cc05f9ae0..ea2f35dbe1945 100644 --- a/pkg/sql/parsers/dialect/mysql/mysql_sql.y +++ b/pkg/sql/parsers/dialect/mysql/mysql_sql.y @@ -250,6 +250,7 @@ func makeWindowSpec(refName *tree.CStr, partitionBy tree.Exprs, orderBy tree.Ord funcArgs tree.FunctionArgs funcArgDecl *tree.FunctionArgDecl funcReturn *tree.ReturnType + pythonFunctionOptions tree.PythonFunctionOptions procName *tree.ProcedureName procArg tree.ProcedureArg @@ -608,6 +609,7 @@ func makeWindowSpec(refName *tree.CStr, partitionBy tree.Exprs, orderBy tree.Ord // Revoke %token REVOKE FUNCTION PRIVILEGES TABLESPACE EXECUTE SUPER GRANT OPTION REFERENCES REPLICATION %token SLAVE CLIENT USAGE RELOAD FILE FILES TEMPORARY ROUTINE EVENT SHUTDOWN +%token CALLED INPUT SCALAR VECTOR // Type Modifiers %token NULLX AUTO_INCREMENT APPROXNUM SIGNED UNSIGNED ZEROFILL ENGINES LOW_CARDINALITY AUTOEXTEND_SIZE @@ -865,7 +867,8 @@ func makeWindowSpec(refName *tree.CStr, partitionBy tree.Exprs, orderBy tree.Ord %type func_arg_decl %type func_return %type func_body_import internal_opt -%type func_lang extension_lang extension_name +%type func_lang extension_lang extension_name func_null_policy func_mode +%type func_python_options_opt %type proc_name %type proc_args_list_opt proc_args_list @@ -8899,7 +8902,7 @@ opt_lang: } create_function_stmt: - CREATE replace_opt FUNCTION func_name '(' func_args_list_opt ')' RETURNS func_return LANGUAGE func_lang func_body_import STRING func_handler_opt + CREATE replace_opt FUNCTION func_name '(' func_args_list_opt ')' RETURNS func_return LANGUAGE func_lang func_body_import STRING func_handler_opt func_python_options_opt { if $13 == "" { yylex.Error("no function body error") @@ -8918,8 +8921,9 @@ create_function_stmt: var Import = $12 var Body = $13 var Handler = $14 + var Options = $15 - $$ = tree.NewCreateFunction( + node := tree.NewCreateFunction( Replace, Name, Args, @@ -8929,6 +8933,9 @@ create_function_stmt: Body, Handler, ) + node.Mode = Options.Mode + node.NullPolicy = Options.NullPolicy + $$ = node } func_name: @@ -9014,6 +9021,47 @@ func_handler: $$ = $2 } +func_python_options_opt: + { + $$ = tree.PythonFunctionOptions{} + } +| MODE func_mode + { + $$ = tree.PythonFunctionOptions{Mode: $2} + } +| func_null_policy + { + $$ = tree.PythonFunctionOptions{NullPolicy: $1} + } +| MODE func_mode func_null_policy + { + $$ = tree.PythonFunctionOptions{Mode: $2, NullPolicy: $3} + } +| func_null_policy MODE func_mode + { + $$ = tree.PythonFunctionOptions{Mode: $3, NullPolicy: $1} + } + +func_mode: + SCALAR + { + $$ = "SCALAR" + } +| VECTOR + { + $$ = "VECTOR" + } + +func_null_policy: + CALLED ON NULL INPUT + { + $$ = "CALLED_ON_NULL_INPUT" + } +| RETURNS NULL ON NULL INPUT + { + $$ = "RETURNS_NULL_ON_NULL_INPUT" + } + create_view_stmt: CREATE view_list_opt VIEW not_exists_opt table_name column_list_opt AS ctas_select_stmt view_tail { @@ -16448,6 +16496,7 @@ non_reserved_keyword: | BLOB | BOOL | BITS_PER_CODE +| CALLED | BRANCH | CATALOG | CATALOGS @@ -16529,6 +16578,7 @@ non_reserved_keyword: | PERSIST | GRANT | INCLUDE +| INPUT | INT | INTEGER | INDEXES @@ -16620,6 +16670,7 @@ non_reserved_keyword: | PROFILES | PROFILE | ROLE +| SCALAR | RULE | RULES | RANGE @@ -16678,6 +16729,7 @@ non_reserved_keyword: | VARBINARY | VARCHAR | VARIABLES +| VECTOR | VIEW | VIRTUAL | WRITE diff --git a/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go b/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go index 3a8ab62349d06..838861d9e54d9 100644 --- a/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go +++ b/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go @@ -151,6 +151,44 @@ func TestShowGrantsForCurrentUser(t *testing.T) { } } +func TestPythonFunctionOptions(t *testing.T) { + stmt, err := ParseOne(context.Background(), + "create function py (x int) returns int language python as 'def py(ctx, x): return x' handler 'py' mode vector returns null on null input", 1) + require.NoError(t, err) + defer stmt.Free() + + create, ok := stmt.(*tree.CreateFunction) + require.True(t, ok) + require.Equal(t, "VECTOR", create.Mode) + require.Equal(t, "RETURNS_NULL_ON_NULL_INPUT", create.NullPolicy) + require.NoError(t, create.Valid()) + require.Equal(t, + "create function py (x int) returns int language python as 'def py(ctx, x): return x' handler 'py' mode vector returns null on null input", + tree.String(stmt, dialect.MYSQL)) + + reversed, err := ParseOne(context.Background(), + "create function py (x int) returns int language python as 'def py(ctx, x): return x' handler 'py' returns null on null input mode scalar", 1) + require.NoError(t, err) + defer reversed.Free() + reversedCreate := reversed.(*tree.CreateFunction) + require.Equal(t, "SCALAR", reversedCreate.Mode) + require.Equal(t, "RETURNS_NULL_ON_NULL_INPUT", reversedCreate.NullPolicy) + + called, err := ParseOne(context.Background(), + "create function py (x int) returns int language python as 'def py(ctx, x): return x' handler 'py' mode vector called on null input", 1) + require.NoError(t, err) + defer called.Free() + calledCreate := called.(*tree.CreateFunction) + require.Equal(t, "VECTOR", calledCreate.Mode) + require.Equal(t, "CALLED_ON_NULL_INPUT", calledCreate.NullPolicy) + + sqlOptions, err := ParseOne(context.Background(), + "create function sql_fn (x int) returns int language sql as 'select $1' mode vector", 1) + require.NoError(t, err) + defer sqlOptions.Free() + require.ErrorContains(t, sqlOptions.(*tree.CreateFunction).Valid(), "require LANGUAGE PYTHON") +} + func TestCreateTablePreservesIndexIdentifierCase(t *testing.T) { stmt, err := ParseOne(context.Background(), "create table t (id int, v varchar(20), key MixedCaseIdx(v), unique key `UniQue_Mix`(id))", 1) diff --git a/pkg/sql/parsers/tree/function.go b/pkg/sql/parsers/tree/function.go index 267509c212720..f5d6d16476bcc 100644 --- a/pkg/sql/parsers/tree/function.go +++ b/pkg/sql/parsers/tree/function.go @@ -179,6 +179,16 @@ type CreateFunction struct { Import bool Body string Handler string + // Mode and NullPolicy are Python routine options. Empty values mean that + // the language default applies; the frontend persists the resolved values + // in the routine body so execution never has to infer them later. + Mode string + NullPolicy string +} + +type PythonFunctionOptions struct { + Mode string + NullPolicy string } func NewCreateFunction(replace bool, name *FunctionName, args FunctionArgs, returnType *ReturnType, lang string, import_ bool, body string, handler string) *CreateFunction { @@ -201,8 +211,23 @@ func (node *CreateFunction) Valid() error { if node.Import { return moerr.NewInvalidInputNoCtx("import") } + if node.Mode != "" || node.NullPolicy != "" { + return moerr.NewInvalidInputNoCtx("Python function options require LANGUAGE PYTHON") + } return nil case string(PYTHON): + if node.Mode != "" { + node.Mode = strings.ToUpper(node.Mode) + if node.Mode != "SCALAR" && node.Mode != "VECTOR" { + return moerr.NewInvalidArgNoCtx("Python function mode", node.Mode) + } + } + if node.NullPolicy != "" { + node.NullPolicy = strings.ToUpper(node.NullPolicy) + if node.NullPolicy != "CALLED_ON_NULL_INPUT" && node.NullPolicy != "RETURNS_NULL_ON_NULL_INPUT" { + return moerr.NewInvalidArgNoCtx("Python function NULL policy", node.NullPolicy) + } + } return nil default: return moerr.NewInvalidArgNoCtx("function language", node.Language) @@ -251,6 +276,14 @@ func (node *CreateFunction) Format(ctx *FmtCtx) { ctx.WriteString(node.Handler) ctx.WriteString("'") } + if node.Mode != "" { + ctx.WriteString(" mode ") + ctx.WriteString(strings.ToLower(node.Mode)) + } + if node.NullPolicy != "" { + ctx.WriteByte(' ') + ctx.WriteString(strings.ToLower(strings.ReplaceAll(node.NullPolicy, "_", " "))) + } } func (node *CreateFunction) GetStatementType() string { return "CreateFunction" } diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 3b3722d908514..13d0df81d9b21 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -182,7 +182,7 @@ func (s *Sequence) AcceptResult(sequence uint64) error { func (s *Sequence) AcknowledgeResults(sequence uint64) error { s.mu.Lock() defer s.mu.Unlock() - if sequence < s.ackedResult || sequence > s.lastResult { + if sequence == 0 || sequence < s.ackedResult || sequence > s.lastResult { return fmt.Errorf("%w: result ACK %d outside [%d,%d]", ErrSequence, sequence, s.ackedResult, s.lastResult) } s.ackedResult = sequence diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index 7ae2198ecb2aa..0ab88d5fc3148 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -70,6 +70,7 @@ func TestSequenceKeepsHalfCloseIndependentFromResults(t *testing.T) { require.ErrorIs(t, sequence.AcceptInput(3), ErrSequence) require.ErrorIs(t, sequence.AcknowledgeResults(3), ErrSequence) + require.ErrorIs(t, sequence.AcknowledgeResults(0), ErrSequence) require.NoError(t, sequence.EndInput(2)) } diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 484d16aff3b09..b85fa657ce943 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -600,18 +600,18 @@ func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vect if result == nil { return fmt.Errorf("python udf: missing result wrapper") } - if input.Len() == 0 { - return nil - } - if mp == nil { - return fmt.Errorf("python udf: missing memory pool for Arrow result") - } if err := validateArrayType(descriptor, input); err != nil { return err } if err := validateArrowValueDomain(descriptor, input); err != nil { return err } + if input.Len() == 0 { + return nil + } + if mp == nil { + return fmt.Errorf("python udf: missing memory pool for Arrow result") + } result.GetResultVector().SetTypeScale(descriptor.Scale) typ := types.T(descriptor.TypeID) for i := 0; i < input.Len(); i++ { diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 716290debabf8..acc8ca40f451b 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -12,7 +12,9 @@ import ( "github.com/apache/arrow-go/v18/arrow/array" "github.com/apache/arrow-go/v18/arrow/decimal128" "github.com/apache/arrow-go/v18/arrow/memory" + "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" "github.com/stretchr/testify/require" ) @@ -94,6 +96,24 @@ func TestAppendArrowResultRejectsMissingConsumer(t *testing.T) { require.ErrorContains(t, AppendArrowResult(descriptor, values, nil, nil), "missing result wrapper") } +func TestAppendArrowResultValidatesEmptyArrayType(t *testing.T) { + allocator := memory.NewGoAllocator() + stringBuilder := array.NewStringBuilder(allocator) + values := stringBuilder.NewStringArray() + defer values.Release() + + mp := mpool.MustNewZeroNoFixed() + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer func() { + result.Free() + mpool.DeleteMPool(mp) + }() + descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + + require.ErrorContains(t, AppendArrowResult(descriptor, values, result, mp), "Arrow type") +} + func TestZeroArgumentRecordPreservesRows(t *testing.T) { record := array.NewRecordBatch(arrow.NewSchema(nil, nil), nil, 3) defer record.Release() diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 8cba52c105cee..d99c397691699 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -39,12 +39,11 @@ const ( var errGatewayClosed = errors.New("python udf gateway is closed") type Gateway struct { - cfg ClientConfig - conn *grpc.ClientConn - flight flight.FlightServiceClient - mu sync.Mutex - lifecycle sync.RWMutex - closed bool + cfg ClientConfig + conn *grpc.ClientConn + flight flight.FlightServiceClient + mu sync.Mutex + closed bool } func NewGateway(cfg ClientConfig) (*Gateway, error) { @@ -66,13 +65,18 @@ func NewGateway(cfg ClientConfig) (*Gateway, error) { func (g *Gateway) Language() string { return udf.LanguagePython } func (g *Gateway) connect() error { + _, err := g.flightClient() + return err +} + +func (g *Gateway) flightClient() (flight.FlightServiceClient, error) { g.mu.Lock() defer g.mu.Unlock() if g.closed { - return errGatewayClosed + return nil, errGatewayClosed } if g.flight != nil { - return nil + return g.flight, nil } conn, err := grpc.NewClient(g.cfg.ServerAddress, grpc.WithTransportCredentials(insecure.NewCredentials()), @@ -82,29 +86,31 @@ func (g *Gateway) connect() error { ), ) if err != nil { - return err + return nil, err } g.conn = conn g.flight = flight.NewFlightServiceClient(conn) - return nil + return g.flight, nil } func (g *Gateway) Close() error { - g.lifecycle.Lock() - defer g.lifecycle.Unlock() g.mu.Lock() - defer g.mu.Unlock() if g.closed { + g.mu.Unlock() return nil } g.closed = true - if g.conn == nil { + conn := g.conn + g.conn = nil + g.mu.Unlock() + if conn == nil { return nil } - err := g.conn.Close() - g.conn = nil - g.flight = nil - return err + // Closing the connection is deliberately outside the mutex. gRPC uses + // this operation to interrupt in-flight exchanges; holding a lifecycle + // read lock until Execute returns would make shutdown wait for the very RPC + // it needs to cancel. + return conn.Close() } type openPayload struct { @@ -124,8 +130,6 @@ type openPayload struct { } func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, result vector.FunctionResultWrapper, mp *mpool.MPool) error { - g.lifecycle.RLock() - defer g.lifecycle.RUnlock() g.mu.Lock() closed := g.closed g.mu.Unlock() @@ -158,7 +162,8 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if invocation.Length == 0 { return result.PreExtendAndReset(0) } - if err := g.connect(); err != nil { + client, err := g.flightClient() + if err != nil { return err } openBody, err := json.Marshal(openPayload{Handler: invocation.Handler, Source: invocation.Source, Mode: invocation.Mode, NullPolicy: invocation.NullPolicy, ABIContract: invocation.ABIContract, AdapterVersion: invocation.AdapterVersion, SDKVersion: invocation.SDKVersion, Context: cloneMap(invocation.Context), Args: args, Return: returnDescriptor, MaxBatchBytes: g.cfg.MaxBatchBytes, MaxBatchRows: g.cfg.MaxBatchRows, HandlerTimeoutSeconds: g.cfg.RequestTimeout.Seconds()}) @@ -170,7 +175,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return err } - stream, err := g.flight.DoExchange(streamCtx) + stream, err := client.DoExchange(streamCtx) if err != nil { return fmt.Errorf("python udf: open Arrow Flight exchange: %w", err) } @@ -187,6 +192,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul var sequence protocol.Sequence var schemaFrame *ArrowFrame + schemaReady := false var inputSchema []byte rows := 0 var start int64 @@ -241,7 +247,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul } inputEnded = true } - batchRows, err := g.receiveResultBatch(streamCtx, stream, invocation.Tuple, sequenceNumber, batch.Rows, &schemaFrame, returnDescriptor, result, mp, &sequence) + batchRows, err := g.receiveResultBatch(streamCtx, client, stream, invocation.Tuple, sequenceNumber, batch.Rows, &schemaFrame, &schemaReady, returnDescriptor, result, mp, &sequence) if err != nil { return err } @@ -255,7 +261,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if !inputEnded || lastSequence != batchIndex { return fmt.Errorf("python udf: input stream did not reach EndInput") } - return g.receiveFinish(streamCtx, stream, invocation.Tuple, invocation.Length, rows, &sequence) + return g.receiveFinish(streamCtx, client, stream, invocation.Tuple, invocation.Length, rows, &sequence) } func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaining, maxBytes, maxRows int64) (encodedRecordBatch, error) { @@ -322,11 +328,13 @@ func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaini func (g *Gateway) receiveResultBatch( ctx context.Context, + client flight.FlightServiceClient, stream flight.FlightService_DoExchangeClient, tuple protocol.FencingTuple, sequenceNumber uint64, expectedRows int64, schemaFrame **ArrowFrame, + schemaReady *bool, returnDescriptor TypeDescriptor, result vector.FunctionResultWrapper, mp *mpool.MPool, @@ -348,16 +356,18 @@ func (g *Gateway) receiveResultBatch( if len(data.DataBody) != 0 { return 0, fmt.Errorf("python udf: result schema contains a body") } - if len(data.AppMetadata) == 0 { - return 0, fmt.Errorf("python udf: result schema is missing metadata") - } - control, err := protocol.UnmarshalControl(data.AppMetadata) - if err != nil || control.Tuple != tuple || control.Kind != "ResultSchema" { - return 0, fmt.Errorf("python udf: invalid result schema metadata") - } *schemaFrame = &ArrowFrame{Header: append([]byte(nil), data.DataHeader...)} + if len(data.AppMetadata) != 0 { + if err := validateResultSchemaMetadata(data.AppMetadata, tuple); err != nil { + return 0, err + } + *schemaReady = true + } continue } + if !*schemaReady { + return 0, fmt.Errorf("python udf: result schema metadata was not received") + } control, err := protocol.UnmarshalControl(data.AppMetadata) if err != nil { return 0, err @@ -397,7 +407,7 @@ func (g *Gateway) receiveResultBatch( return 0, err } decoded.Release() - if err := g.action(ctx, "AcknowledgeResults", protocol.Control{Kind: "AcknowledgeResults", Tuple: tuple, AckSequence: control.Sequence}); err != nil { + if err := g.action(ctx, client, "AcknowledgeResults", protocol.Control{Kind: "AcknowledgeResults", Tuple: tuple, AckSequence: control.Sequence}); err != nil { return 0, err } if err := sequence.AcknowledgeResults(control.Sequence); err != nil { @@ -414,6 +424,10 @@ func (g *Gateway) receiveResultBatch( } switch control.Kind { case "ResultSchema": + if *schemaFrame == nil || *schemaReady { + return 0, fmt.Errorf("python udf: invalid result schema metadata") + } + *schemaReady = true continue case "InputConsumed": if control.Sequence != sequenceNumber { @@ -430,8 +444,17 @@ func (g *Gateway) receiveResultBatch( } } +func validateResultSchemaMetadata(metadata []byte, tuple protocol.FencingTuple) error { + control, err := protocol.UnmarshalControl(metadata) + if err != nil || control.Tuple != tuple || control.Kind != "ResultSchema" { + return fmt.Errorf("python udf: invalid result schema metadata") + } + return nil +} + func (g *Gateway) receiveFinish( ctx context.Context, + client flight.FlightServiceClient, stream flight.FlightService_DoExchangeClient, tuple protocol.FencingTuple, expectedRows, rows int, @@ -466,7 +489,7 @@ func (g *Gateway) receiveFinish( !inputEnded || control.LastSequence != lastInput || lastResult != lastInput || acked != lastInput || !sequence.ReadyToFinish() { return fmt.Errorf("python udf: invalid Finish status=%q rows=%d", control.Status, rows) } - return g.action(ctx, "AcknowledgeFinish", protocol.Control{Kind: "AcknowledgeFinish", Tuple: tuple, FinishID: control.FinishID}) + return g.action(ctx, client, "AcknowledgeFinish", protocol.Control{Kind: "AcknowledgeFinish", Tuple: tuple, FinishID: control.FinishID}) default: return fmt.Errorf("python udf: unexpected control %q", control.Kind) } @@ -498,14 +521,14 @@ func validateInvocation(invocation *udf.Invocation) error { return invocation.Tuple.Validate() } -func (g *Gateway) action(ctx context.Context, kind string, control protocol.Control) error { +func (g *Gateway) action(ctx context.Context, client flight.FlightServiceClient, kind string, control protocol.Control) error { body, err := protocol.MarshalControl(control) if err != nil { return err } actionCtx, cancel := context.WithTimeout(ctx, g.cfg.RequestTimeout) defer cancel() - stream, err := g.flight.DoAction(actionCtx, &flight.Action{Type: kind, Body: body}) + stream, err := client.DoAction(actionCtx, &flight.Action{Type: kind, Body: body}) if err != nil { return fmt.Errorf("python udf: %s: %w", kind, err) } diff --git a/pkg/udf/python/supervisor.go b/pkg/udf/python/supervisor.go index 30d85fc2233f4..87df045f68ac8 100644 --- a/pkg/udf/python/supervisor.go +++ b/pkg/udf/python/supervisor.go @@ -9,26 +9,24 @@ package python import ( "errors" "fmt" - "io" "os" "os/exec" "path/filepath" "sync" - "sync/atomic" "github.com/matrixorigin/matrixone/pkg/logutil" ) +var errSupervisorClosing = errors.New("python udf worker is shutting down") + type Supervisor struct { - cfg Config - mu sync.Mutex - cmd *exec.Cmd - log io.WriteCloser - done chan struct{} + cfg Config + mu sync.Mutex + cmd *exec.Cmd + done chan struct{} + closing bool } -var supervisorNumber atomic.Int32 - func NewSupervisor(cfg Config) (*Supervisor, error) { if err := cfg.Validate(); err != nil { return nil, err @@ -39,6 +37,9 @@ func NewSupervisor(cfg Config) (*Supervisor, error) { func (s *Supervisor) Start() error { s.mu.Lock() defer s.mu.Unlock() + if s.closing { + return errSupervisorClosing + } if s.cmd != nil { return nil } @@ -58,35 +59,28 @@ func (s *Supervisor) Start() error { if executable == "" { executable = "python" } - exePath, err := os.Executable() - if err != nil { - return err - } - logPath := filepath.Join(filepath.Dir(exePath), fmt.Sprintf("python-udf-worker-%d.log", supervisorNumber.Add(1))) - logFile, err := os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) - if err != nil { - return err - } cmd := exec.Command(executable, "-u", workerPath, "--address="+s.cfg.Address) prepareSupervisorCommand(cmd) - cmd.Stdout, cmd.Stderr = logFile, logFile + // The MatrixOne service owns process logging. Inheriting stderr keeps + // worker diagnostics in the service log and avoids an unbounded, per-start + // file beside the binary. + cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr if err := cmd.Start(); err != nil { - _ = logFile.Close() return err } done := make(chan struct{}) - s.cmd, s.log, s.done = cmd, logFile, done - go s.wait(cmd, logFile, done) + s.cmd, s.done = cmd, done + go s.wait(cmd, done) logutil.Infof("started Python UDF worker: %s", cmd.String()) return nil } -func (s *Supervisor) wait(cmd *exec.Cmd, log io.WriteCloser, done chan struct{}) { +func (s *Supervisor) wait(cmd *exec.Cmd, done chan struct{}) { err := cmd.Wait() - _ = log.Close() s.mu.Lock() if s.cmd == cmd { - s.cmd, s.log, s.done = nil, nil, nil + s.cmd, s.done = nil, nil + s.closing = false } s.mu.Unlock() close(done) @@ -97,12 +91,12 @@ func (s *Supervisor) wait(cmd *exec.Cmd, log io.WriteCloser, done chan struct{}) func (s *Supervisor) Close() error { s.mu.Lock() - cmd, log, done := s.cmd, s.log, s.done + cmd, done := s.cmd, s.done + if cmd != nil { + s.closing = true + } s.mu.Unlock() if cmd == nil { - if log != nil { - return log.Close() - } return nil } var closeErr error diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index a49d25373dec6..6772d68b87392 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -516,6 +516,12 @@ def test_control_numeric_fields_are_strict(self): with self.assertRaisesRegex(ValueError, "invalid control field sequence"): worker._required_uint64({"sequence": "1"}, "sequence") + def test_result_ack_rejects_zero_sequence(self): + state = worker._InvocationState({}, 1) + state.last_result = 1 + with self.assertRaisesRegex(ValueError, "result ACK"): + state.ack_result(0) + if __name__ == "__main__": unittest.main() diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 7d581e47b9d45..8cc22bac35503 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -968,7 +968,7 @@ def __init__(self, tuple_value: Dict[str, Any], terminal_bytes: int): def ack_result(self, sequence: int) -> None: with self.condition: - if sequence < self.acked_result or sequence > self.last_result: + if sequence <= 0 or sequence < self.acked_result or sequence > self.last_result: raise ValueError("PROTOCOL: result ACK is outside the received range") self.acked_result = sequence self.condition.notify_all() @@ -1098,7 +1098,6 @@ def do_action(self, context, action): } ) return - raise ValueError("PROTOCOL: unknown invocation") if action.type == "AcknowledgeResults": state.ack_result(_required_uint64(control, "ack_sequence")) elif action.type == "AcknowledgeFinish": diff --git a/test/distributed/cases/udf_python/vector_mode.result b/test/distributed/cases/udf_python/vector_mode.result new file mode 100644 index 0000000000000..3c7c9bd29c6e5 --- /dev/null +++ b/test/distributed/cases/udf_python/vector_mode.result @@ -0,0 +1,31 @@ +drop database if exists udf_python_vector_bvt; +create database udf_python_vector_bvt; +use udf_python_vector_bvt; +create function python_bvt_vector (x int) returns int language python as 'python_bvt_vector = lambda ctx, values: __import__("pyarrow").array([-99 if value.as_py() is None else value.as_py() + 10 for value in values], type=__import__("pyarrow").int32())' handler 'python_bvt_vector' mode vector; +create function python_bvt_vector_strict (x int) returns int language python as 'python_bvt_vector_strict = lambda ctx, values: __import__("pyarrow").array([value.as_py() + 10 for value in values], type=__import__("pyarrow").int32())' handler 'python_bvt_vector_strict' mode vector returns null on null input; +create function python_bvt_zero_vector () returns int language python as 'python_bvt_zero_vector = lambda ctx: __import__("pyarrow").array([7] * ctx.num_rows, type=__import__("pyarrow").int32())' handler 'python_bvt_zero_vector' mode vector; +create table vector_values (id int, value int); +insert into vector_values values (1, 1), (2, null), (3, 2); +select id, python_bvt_vector(value) as called_result +from vector_values order by id; +➤ id[4,32,0] ¦ called_result[4,32,0] 𝄀 +1 ¦ 11 𝄀 +2 ¦ -99 𝄀 +3 ¦ 12 +select id, python_bvt_vector_strict(value) as strict_result +from vector_values order by id; +➤ id[4,32,0] ¦ strict_result[4,32,0] 𝄀 +1 ¦ 11 𝄀 +2 ¦ null 𝄀 +3 ¦ 12 +select id, python_bvt_zero_vector() as zero_result +from vector_values order by id; +➤ id[4,32,0] ¦ zero_result[4,32,0] 𝄀 +1 ¦ 7 𝄀 +2 ¦ 7 𝄀 +3 ¦ 7 +drop function python_bvt_vector(int); +drop function python_bvt_vector_strict(int); +drop function python_bvt_zero_vector(); +drop table vector_values; +drop database udf_python_vector_bvt; diff --git a/test/distributed/cases/udf_python/vector_mode.sql b/test/distributed/cases/udf_python/vector_mode.sql new file mode 100644 index 0000000000000..6051e26aa69ab --- /dev/null +++ b/test/distributed/cases/udf_python/vector_mode.sql @@ -0,0 +1,31 @@ +-- Vector handlers receive one Arrow array per argument and return one Arrow +-- array with the same number of rows. Both NULL policies are exercised here. +drop database if exists udf_python_vector_bvt; +create database udf_python_vector_bvt; +use udf_python_vector_bvt; + +create function python_bvt_vector (x int) returns int language python as 'python_bvt_vector = lambda ctx, values: __import__("pyarrow").array([-99 if value.as_py() is None else value.as_py() + 10 for value in values], type=__import__("pyarrow").int32())' handler 'python_bvt_vector' mode vector; +create function python_bvt_vector_strict (x int) returns int language python as 'python_bvt_vector_strict = lambda ctx, values: __import__("pyarrow").array([value.as_py() + 10 for value in values], type=__import__("pyarrow").int32())' handler 'python_bvt_vector_strict' mode vector returns null on null input; +create function python_bvt_zero_vector () returns int language python as 'python_bvt_zero_vector = lambda ctx: __import__("pyarrow").array([7] * ctx.num_rows, type=__import__("pyarrow").int32())' handler 'python_bvt_zero_vector' mode vector; + +create table vector_values (id int, value int); +insert into vector_values values (1, 1), (2, null), (3, 2); + +-- CALLED ON NULL INPUT reaches the vector handler for the NULL row. +select id, python_bvt_vector(value) as called_result +from vector_values order by id; + +-- RETURNS NULL ON NULL INPUT compacts the selected rows and scatters NULL +-- back to the original row positions. +select id, python_bvt_vector_strict(value) as strict_result +from vector_values order by id; + +-- A zero-argument VECTOR routine gets its result shape from ctx.num_rows. +select id, python_bvt_zero_vector() as zero_result +from vector_values order by id; + +drop function python_bvt_vector(int); +drop function python_bvt_vector_strict(int); +drop function python_bvt_zero_vector(); +drop table vector_values; +drop database udf_python_vector_bvt; From 7bc4ae5006756600549a9500d54cb4626284419c Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 12:03:36 +0800 Subject: [PATCH 022/241] fix(udf): require complete Python type contracts --- pkg/frontend/compiler_context.go | 5 ++- pkg/sql/plan/function/python_udf.go | 2 +- pkg/sql/plan/function/udf.go | 69 ++++++++++++++++++++++++----- pkg/sql/plan/function/udf_test.go | 31 +++++++++++-- 4 files changed, 92 insertions(+), 15 deletions(-) diff --git a/pkg/frontend/compiler_context.go b/pkg/frontend/compiler_context.go index f38fccbb549ee..dbd756b0a3b32 100644 --- a/pkg/frontend/compiler_context.go +++ b/pkg/frontend/compiler_context.go @@ -1009,6 +1009,10 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex if len(argList) != len(args) { // mismatch continue } + udf.Args = argList + if err = udf.ValidatePythonTypeContract(); err != nil { + return nil, err + } toList := make([]types.T, len(args)) for j := range argList { @@ -1024,7 +1028,6 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex continue } - udf.Args = argList matchedList = append(matchedList, &MatchUdf{ Udf: udf, Cost: cost, diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index 3b27d6f3e5ddb..5ef466e73d678 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -266,7 +266,7 @@ func hasNullInput(inputs []*vector.Vector, row int) bool { } func routineArgumentTypes(routine *UdfWithContext) ([]types.Type, error) { - if len(routine.PythonArgTypes) != 0 { + if routine.Language == "python" { args := make([]types.Type, len(routine.PythonArgTypes)) for i, descriptor := range routine.PythonArgTypes { args[i] = descriptor.Type() diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index 47d0fb22800b4..4e2af1402c2b2 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -10,6 +10,8 @@ package function import ( "encoding/json" + "fmt" + "reflect" "github.com/google/uuid" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -86,7 +88,7 @@ func (u *Udf) GetArgsPlanType() []*plan.Type { } func (u *Udf) GetRetPlanType() *plan.Type { return type2PlanType(u.GetRetType()) } func (u *Udf) GetArgsType() []types.Type { - if len(u.PythonArgTypes) != 0 { + if u.Language == "python" { args := make([]types.Type, len(u.PythonArgTypes)) for i, descriptor := range u.PythonArgTypes { args[i] = descriptor.Type() @@ -96,29 +98,76 @@ func (u *Udf) GetArgsType() []types.Type { return u.ArgsType } func (u *Udf) GetRetType() types.Type { - if u.PythonReturnType != nil { + if u.Language == "python" { + if u.PythonReturnType == nil { + return types.Type{} + } return u.PythonReturnType.Type() } return types.Types[u.RetType].ToType() } -// LoadPythonTypeContract copies exact type metadata persisted in the Python -// routine body into the plan object. Older catalog rows have no such fields -// and intentionally retain the legacy logical-type fallback. +// LoadPythonTypeContract loads the exact type metadata persisted in the Python +// routine body. Python execution has one ABI, so an incomplete body is +// rejected instead of being reinterpreted through the legacy logical-type +// columns. func (u *Udf) LoadPythonTypeContract() error { if u.Language != "python" { return nil } + u.PythonArgTypes = nil + u.PythonReturnType = nil body := PythonRoutineBody{} if err := json.Unmarshal([]byte(u.Body), &body); err != nil { return err } - if len(body.ArgTypes) != 0 { - u.PythonArgTypes = append([]PythonTypeDescriptor(nil), body.ArgTypes...) + if body.ReturnType == nil { + return fmt.Errorf("python routine is missing return descriptor") + } + for i, descriptor := range body.ArgTypes { + if err := validatePythonTypeDescriptor(descriptor); err != nil { + return fmt.Errorf("python routine argument descriptor %d: %w", i, err) + } + } + if err := validatePythonTypeDescriptor(*body.ReturnType); err != nil { + return fmt.Errorf("python routine return descriptor: %w", err) + } + u.PythonArgTypes = append([]PythonTypeDescriptor(nil), body.ArgTypes...) + returnType := *body.ReturnType + u.PythonReturnType = &returnType + return nil +} + +// ValidatePythonTypeContract checks the descriptor count after catalog +// argument names have been decoded. LoadPythonTypeContract deliberately runs +// before that decode during lookup, so this second check closes the only point +// where an argument list and its exact ABI could otherwise diverge. +func (u *Udf) ValidatePythonTypeContract() error { + if u.Language != "python" { + return nil + } + if u.PythonReturnType == nil { + return fmt.Errorf("python routine is missing return descriptor") + } + if len(u.PythonArgTypes) != len(u.Args) { + return fmt.Errorf("python routine has %d descriptors for %d arguments", len(u.PythonArgTypes), len(u.Args)) + } + for i, descriptor := range u.PythonArgTypes { + if err := validatePythonTypeDescriptor(descriptor); err != nil { + return fmt.Errorf("python routine argument descriptor %d: %w", i, err) + } + } + return validatePythonTypeDescriptor(*u.PythonReturnType) +} + +func validatePythonTypeDescriptor(descriptor PythonTypeDescriptor) error { + typ := descriptor.Type() + canonical, err := NewPythonTypeDescriptor(typ) + if err != nil { + return err } - if body.ReturnType != nil { - returnType := *body.ReturnType - u.PythonReturnType = &returnType + if !reflect.DeepEqual(canonical, descriptor) { + return fmt.Errorf("descriptor is not canonical for %s", typ.String()) } return nil } diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go index 2a6ee085556c6..a844109c5e3f3 100644 --- a/pkg/sql/plan/function/udf_test.go +++ b/pkg/sql/plan/function/udf_test.go @@ -38,22 +38,47 @@ func TestPythonTypeContractPreservesDeclaredShape(t *testing.T) { routine := &Udf{Language: "python", Body: string(body), ArgsType: []types.Type{types.T_decimal64.ToType()}} require.NoError(t, routine.LoadPythonTypeContract()) + routine.Args = []*Arg{{Type: "decimal"}} + require.NoError(t, routine.ValidatePythonTypeContract()) require.Equal(t, argument, routine.GetArgsType()[0]) require.Equal(t, returnType, routine.GetRetType()) require.Equal(t, int32(6), routine.GetArgsPlanType()[0].Scale) require.Equal(t, int32(64), routine.GetRetPlanType().Width) } -func TestPythonTypeContractKeepsLegacyFallback(t *testing.T) { +func TestPythonTypeContractRejectsMissingReturnDescriptor(t *testing.T) { routine := &Udf{ Language: "python", Body: `{"handler":"legacy","source":"def legacy(ctx, x): return x"}`, ArgsType: []types.Type{types.T_int32.ToType()}, RetType: "int", } + require.ErrorContains(t, routine.LoadPythonTypeContract(), "return descriptor") +} + +func TestPythonTypeContractRejectsArgumentCountMismatch(t *testing.T) { + argument, err := NewPythonTypeDescriptor(types.T_int32.ToType()) + require.NoError(t, err) + returnType, err := NewPythonTypeDescriptor(types.T_int32.ToType()) + require.NoError(t, err) + body, err := json.Marshal(PythonRoutineBody{ArgTypes: []PythonTypeDescriptor{argument}, ReturnType: &returnType}) + require.NoError(t, err) + routine := &Udf{Language: "python", Body: string(body)} + require.NoError(t, routine.LoadPythonTypeContract()) + require.ErrorContains(t, routine.ValidatePythonTypeContract(), "descriptors for 0 arguments") +} + +func TestPythonTypeContractReloadReplacesDescriptors(t *testing.T) { + argument, err := NewPythonTypeDescriptor(types.T_int32.ToType()) + require.NoError(t, err) + returnType, err := NewPythonTypeDescriptor(types.T_int32.ToType()) + require.NoError(t, err) + body, err := json.Marshal(PythonRoutineBody{ArgTypes: []PythonTypeDescriptor{argument}, ReturnType: &returnType}) + require.NoError(t, err) + routine := &Udf{Language: "python", Body: string(body)} + require.NoError(t, routine.LoadPythonTypeContract()) require.NoError(t, routine.LoadPythonTypeContract()) - require.Equal(t, types.T_int32.ToType(), routine.GetArgsType()[0]) - require.Equal(t, types.T_int32.ToType(), routine.GetRetType()) + require.Len(t, routine.PythonArgTypes, 1) } func TestPythonBindingNormalizesDecimalMetadata(t *testing.T) { From cebd019867fda3d0549d445209706466c11ece9b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 12:04:51 +0800 Subject: [PATCH 023/241] fix(udf): enforce one-shot group state transitions --- pkg/udf/protocol/protocol.go | 89 +++++++++++++++++++------------ pkg/udf/protocol/protocol_test.go | 18 +++++-- 2 files changed, 69 insertions(+), 38 deletions(-) diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 13d0df81d9b21..9fc962d572aa7 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -373,53 +373,70 @@ func (g *ExecutionGroup) BeginOpen(memberID string) (*OpenToken, error) { type OpenToken struct { group *ExecutionGroup memberID string - once sync.Once - result error + mu sync.Mutex + state openTokenState } +type openTokenState uint8 + +const ( + openTokenPending openTokenState = iota + openTokenCommitted + openTokenAborted +) + func (t *OpenToken) Commit() error { if t == nil || t.group == nil { return ErrUnknownIdentity } - t.once.Do(func() { - g := t.group - g.mu.Lock() - delete(g.pending, t.memberID) - g.inFlight-- - if g.closing || g.released { - t.result = ErrGroupClosed - release := g.canReleaseLocked() - g.mu.Unlock() - if release { - if err := t.group.releaseIfReady(); err != nil { - t.result = errors.Join(t.result, err) - } - } - return - } - g.members[t.memberID] = true - g.registered++ + if err := t.begin(openTokenCommitted); err != nil { + return err + } + g := t.group + g.mu.Lock() + delete(g.pending, t.memberID) + g.inFlight-- + if g.closing || g.released { + release := g.canReleaseLocked() g.mu.Unlock() - }) - return t.result + if release { + return errors.Join(ErrGroupClosed, g.releaseIfReady()) + } + return ErrGroupClosed + } + g.members[t.memberID] = true + g.registered++ + g.mu.Unlock() + return nil } func (t *OpenToken) Abort() error { if t == nil || t.group == nil { return ErrUnknownIdentity } - t.once.Do(func() { - g := t.group - g.mu.Lock() - delete(g.pending, t.memberID) - g.inFlight-- - release := g.canReleaseLocked() - g.mu.Unlock() - if release { - t.result = t.group.releaseIfReady() - } - }) - return t.result + if err := t.begin(openTokenAborted); err != nil { + return err + } + g := t.group + g.mu.Lock() + delete(g.pending, t.memberID) + g.inFlight-- + release := g.canReleaseLocked() + g.mu.Unlock() + if release { + return g.releaseIfReady() + } + return nil +} + +func (t *OpenToken) begin(state openTokenState) error { + t.mu.Lock() + defer t.mu.Unlock() + if t.state != openTokenPending { + return fmt.Errorf("%w: open token was already finalized", ErrProtocol) + } + t.state = state + return nil } func (g *ExecutionGroup) Close(reason CloseReason) error { @@ -427,6 +444,10 @@ func (g *ExecutionGroup) Close(reason CloseReason) error { return fmt.Errorf("%w: close reason is empty", ErrProtocol) } g.mu.Lock() + if g.closing && g.reason != reason { + g.mu.Unlock() + return fmt.Errorf("%w: close reason changed from %q to %q", ErrProtocol, g.reason, reason) + } if g.released { g.mu.Unlock() return nil diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index 0ab88d5fc3148..c640e2483e519 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -123,7 +123,8 @@ func TestExecutionGroupReleasesOnlyAfterCloseAndAllMembersTerminal(t *testing.T) _, err = group.BeginOpen("late") require.ErrorIs(t, err, ErrGroupClosed) - require.NoError(t, group.Close(ReasonCancel)) + require.ErrorIs(t, group.Close(ReasonCancel), ErrProtocol) + require.NoError(t, group.Close(ReasonInputEOF)) require.Equal(t, int32(1), releases.Load()) } @@ -158,7 +159,7 @@ func TestExecutionGroupZeroMemberAndAbortedOpenRelease(t *testing.T) { require.NoError(t, err) require.NoError(t, group.Close(ReasonCancel)) require.ErrorIs(t, open.Commit(), ErrGroupClosed) - require.ErrorIs(t, open.Commit(), ErrGroupClosed) + require.ErrorIs(t, open.Commit(), ErrProtocol) } func TestExecutionGroupReservesPendingMemberIdentity(t *testing.T) { @@ -185,6 +186,15 @@ func TestExecutionGroupReservesPendingMemberIdentity(t *testing.T) { require.Zero(t, inFlight) } +func TestExecutionGroupCloseReasonIsImmutable(t *testing.T) { + group, err := NewExecutionGroup("g", 1, 1, func() error { return nil }) + require.NoError(t, err) + require.NoError(t, group.Close(ReasonIdle)) + require.NoError(t, group.Close(ReasonIdle)) + require.ErrorIs(t, group.Close(ReasonCancel), ErrProtocol) + require.Equal(t, ReasonIdle, group.Reason()) +} + func TestTerminalLedgerRetainsTombstonesUntilExpiry(t *testing.T) { ledger, err := NewTerminalLedger(2, 200) require.NoError(t, err) @@ -269,8 +279,8 @@ func TestExecutionGroupCommitReportsReleaseFailure(t *testing.T) { err = open.Commit() require.ErrorIs(t, err, ErrGroupClosed) require.ErrorContains(t, err, "temporary release failure") - require.ErrorIs(t, open.Commit(), ErrGroupClosed) - require.ErrorContains(t, open.Commit(), "temporary release failure") + require.ErrorIs(t, open.Commit(), ErrProtocol) + require.ErrorIs(t, open.Abort(), ErrProtocol) require.Equal(t, GroupDraining, group.State()) require.NoError(t, group.Close(ReasonCancel)) require.Equal(t, GroupReleased, group.State()) From 6d5d864b497521ed1a72d74318970ec10164bef2 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 12:06:21 +0800 Subject: [PATCH 024/241] fix(udf): reject late Flight completion controls --- pkg/udf/python/gateway.go | 10 +++++- pkg/udf/python/gateway_test.go | 56 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index d99c397691699..2c6753851c1dd 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -340,6 +340,7 @@ func (g *Gateway) receiveResultBatch( mp *mpool.MPool, sequence *protocol.Sequence, ) (int, error) { + inputConsumed := false for { data, err := stream.Recv() if err != nil { @@ -375,6 +376,9 @@ func (g *Gateway) receiveResultBatch( if control.Tuple != tuple || control.Kind != "ResultBatch" || control.Sequence != sequenceNumber { return 0, fmt.Errorf("python udf: unexpected result sequence %d", control.Sequence) } + if !inputConsumed { + return 0, fmt.Errorf("python udf: result sequence %d arrived before InputConsumed", sequenceNumber) + } if err := sequence.AcceptResult(control.Sequence); err != nil { return 0, err } @@ -433,6 +437,10 @@ func (g *Gateway) receiveResultBatch( if control.Sequence != sequenceNumber { return 0, fmt.Errorf("python udf: input sequence %d was consumed while waiting for result %d", control.Sequence, sequenceNumber) } + if inputConsumed { + return 0, fmt.Errorf("python udf: input sequence %d was consumed more than once", sequenceNumber) + } + inputConsumed = true continue case "Error": return 0, fmt.Errorf("python udf: worker error: %s", control.Reason) @@ -480,7 +488,7 @@ func (g *Gateway) receiveFinish( } switch control.Kind { case "InputConsumed", "ResultSchema": - continue + return fmt.Errorf("python udf: %s arrived after result stream was drained", control.Kind) case "Error": return fmt.Errorf("python udf: worker error: %s", control.Reason) case "Finish": diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index f83abcca7e31b..793c5070374a0 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -6,15 +6,50 @@ package python import ( + "context" + "io" "testing" + "time" + "github.com/apache/arrow-go/v18/arrow/flight/gen/flight" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" "github.com/matrixorigin/matrixone/pkg/udf" "github.com/matrixorigin/matrixone/pkg/udf/protocol" "github.com/stretchr/testify/require" + "google.golang.org/grpc" ) +type gatewayResultStream struct { + grpc.ClientStream + results []*flight.FlightData + index int +} + +func (s *gatewayResultStream) Recv() (*flight.FlightData, error) { + if s.index == len(s.results) { + return nil, io.EOF + } + result := s.results[s.index] + s.index++ + return result, nil +} + +func (s *gatewayResultStream) Send(*flight.FlightData) error { + return nil +} + +func gatewayControl(t *testing.T, kind string, tuple protocol.FencingTuple, fields ...func(*protocol.Control)) *flight.FlightData { + t.Helper() + control := protocol.Control{Kind: kind, Tuple: tuple} + for _, field := range fields { + field(&control) + } + encoded, err := protocol.MarshalControl(control) + require.NoError(t, err) + return &flight.FlightData{AppMetadata: encoded} +} + func validInvocation() *udf.Invocation { return &udf.Invocation{ Language: udf.LanguagePython, @@ -84,3 +119,24 @@ func TestGatewayCloseIsTerminal(t *testing.T) { require.ErrorIs(t, gateway.connect(), errGatewayClosed) require.NoError(t, gateway.Close()) } + +func TestGatewayFinishRejectsLateHalfStreamControls(t *testing.T) { + tuple := validInvocation().Tuple + for _, kind := range []string{"InputConsumed", "ResultSchema"} { + t.Run(kind, func(t *testing.T) { + sequence := protocol.Sequence{} + require.NoError(t, sequence.AcceptInput(1)) + require.NoError(t, sequence.EndInput(1)) + require.NoError(t, sequence.AcceptResult(1)) + require.NoError(t, sequence.AcknowledgeResults(1)) + stream := &gatewayResultStream{results: []*flight.FlightData{ + gatewayControl(t, kind, tuple, func(control *protocol.Control) { + control.Sequence = 1 + }), + }} + gateway := &Gateway{cfg: ClientConfig{RequestTimeout: time.Second}} + err := gateway.receiveFinish(context.Background(), nil, stream, tuple, 1, 1, &sequence) + require.ErrorContains(t, err, "arrived after result stream was drained") + }) + } +} From 57cfa7416bf3299d85437e08aad1f3313ddd767c Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 12:08:45 +0800 Subject: [PATCH 025/241] fix(udf): align Python JSON validation with SQL --- pkg/udf/python/worker/test_worker.py | 8 ++++++++ pkg/udf/python/worker/worker.py | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 6772d68b87392..28e658bbad38a 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -70,6 +70,14 @@ def test_json_input_is_canonicalized_before_handler(self): worker._scalar_input(array, 0, descriptor), ) + def test_json_rejects_nonstandard_numbers(self): + descriptor = {"type_id": worker.JSON, "offset_width": 32, "json_encoding": "canonical_text"} + for value in ("NaN", "Infinity", "-Infinity", "1e9999"): + with self.assertRaisesRegex(ValueError, "invalid JSON"): + worker._canonical_json_text(value) + with self.assertRaisesRegex(ValueError, "JSON result"): + worker._check_scalar(value, descriptor) + def test_uuid_scalar_round_trip_keeps_uuid_object_until_array_encoding(self): descriptor = {"type_id": worker.UUID, "offset_width": 0} value = uuid.UUID("123e4567-e89b-12d3-a456-426614174000") diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 8cc22bac35503..f96705f3163db 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -21,6 +21,7 @@ import inspect import json import logging +import math import os import pickle import selectors @@ -497,8 +498,22 @@ def _scalar_input(array: pa.Array, row: int, descriptor: Dict[str, Any]): def _canonical_json_text(value: str) -> str: if not isinstance(value, str): raise ValueError("TYPE_CONTRACT: JSON value must be text") + + def reject_nonstandard_number(_constant: str): + raise ValueError("non-standard JSON number") + + def reject_nonfinite_float(number: str): + parsed = float(number) + if not math.isfinite(parsed): + raise ValueError("non-finite JSON number") + return parsed + try: - parsed = json.loads(value) + parsed = json.loads( + value, + parse_constant=reject_nonstandard_number, + parse_float=reject_nonfinite_float, + ) except Exception as exc: raise ValueError("TYPE_CONTRACT: invalid JSON input") from exc return json.dumps(parsed, ensure_ascii=False, separators=(",", ":")) From 1251d51d9180e58503e84911a467f0ae3fe0bd36 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 12:10:05 +0800 Subject: [PATCH 026/241] fix(udf): isolate Python handler environment --- pkg/udf/python/worker/test_worker.py | 23 +++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 11 ++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 28e658bbad38a..de513484a2161 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -183,6 +183,29 @@ def test_handler_stdout_cannot_inject_parent_protocol(self): ) self.assertEqual([1], result.column(0).to_pylist()) + def test_handler_does_not_inherit_parent_environment(self): + descriptor = {"type_id": worker.BOOL, "offset_width": 32} + batch = pa.RecordBatch.from_arrays( + [pa.array([True], type=pa.bool_())], ["arg_0"] + ) + request = { + "source": "import os;\ndef f(ctx, x): return 'MATRIXONE_TEST_SECRET' in os.environ", + "handler": "f", + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "sdk_version": worker.SDK_VERSION, + "context": None, + "args": [descriptor], + "return": descriptor, + "max_batch_bytes": 1 << 20, + "input": worker._serialize_record_batch(batch), + } + with mock.patch.dict(os.environ, {"MATRIXONE_TEST_SECRET": "must-not-leak"}, clear=False): + result = worker._deserialize_record_batch( + worker._run_handler_process(None, request, 3) + ) + self.assertEqual([False], result.column(0).to_pylist()) + def test_handler_cannot_forge_completion_on_stdout(self): descriptor = {"type_id": worker.INT64, "offset_width": 32} batch = pa.RecordBatch.from_arrays([pa.array([77], type=pa.int64())], ["arg_0"]) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index f96705f3163db..679fc1edcfb8f 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -52,6 +52,7 @@ _HANDLER_RESPONSE_ERROR = 0 _HANDLER_RESPONSE_OK = 1 _HANDLER_RESPONSE_FD_ENV = "MATRIXONE_HANDLER_RESPONSE_FD" +_HANDLER_ENV_ALLOWLIST = frozenset({"PATH"}) _MICROS_PER_SECOND = 1_000_000 _MAX_TIME_MICROS = (838 * 60 * 60 + 59 * 60 + 59) * _MICROS_PER_SECOND _MIN_TIMESTAMP = _datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=_datetime.timezone.utc) @@ -873,7 +874,15 @@ def _run_handler_process(context, request: Dict[str, Any], timeout_seconds: floa if os.name == "posix": popen_kwargs["start_new_session"] = True popen_kwargs["pass_fds"] = (response_write_fd,) - child_env = os.environ.copy() + # User code runs under a separate execution identity. In particular, do + # not inherit CN, object-store, database, or tenant credentials from the + # worker process. Routine dependencies are supplied by the selected Python + # environment and do not need ambient environment variables. + child_env = { + name: value + for name, value in os.environ.items() + if name in _HANDLER_ENV_ALLOWLIST + } child_env[_HANDLER_RESPONSE_FD_ENV] = str(response_write_fd) # The extra descriptor is a protocol-channel separation mechanism, not a # sandbox boundary. An unisolated handler with arbitrary OS access can From 1dc1bde055ff849cebddf11420d3a7f3a2081dd1 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 12:17:17 +0800 Subject: [PATCH 027/241] fix(udf): enforce complete Python routine bodies --- .../parsers/dialect/mysql/mysql_sql_test.go | 12 +++ pkg/sql/parsers/tree/function.go | 3 + pkg/sql/plan/function/python_udf.go | 19 +---- pkg/sql/plan/function/udf.go | 75 +++++++++++++++---- pkg/sql/plan/function/udf_test.go | 63 ++++++++++++++-- 5 files changed, 137 insertions(+), 35 deletions(-) diff --git a/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go b/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go index 838861d9e54d9..14d4a9ea58609 100644 --- a/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go +++ b/pkg/sql/parsers/dialect/mysql/mysql_sql_test.go @@ -189,6 +189,18 @@ func TestPythonFunctionOptions(t *testing.T) { require.ErrorContains(t, sqlOptions.(*tree.CreateFunction).Valid(), "require LANGUAGE PYTHON") } +func TestPythonFunctionImportIsRejectedBeforeExecution(t *testing.T) { + stmt, err := ParseOne(context.Background(), + "create function py (x int) returns int language python import 'udf.py' handler 'py'", 1) + require.NoError(t, err) + defer stmt.Free() + + create, ok := stmt.(*tree.CreateFunction) + require.True(t, ok) + require.True(t, create.Import) + require.ErrorContains(t, create.Valid(), "immutable artifact catalog") +} + func TestCreateTablePreservesIndexIdentifierCase(t *testing.T) { stmt, err := ParseOne(context.Background(), "create table t (id int, v varchar(20), key MixedCaseIdx(v), unique key `UniQue_Mix`(id))", 1) diff --git a/pkg/sql/parsers/tree/function.go b/pkg/sql/parsers/tree/function.go index f5d6d16476bcc..a1e225939ee92 100644 --- a/pkg/sql/parsers/tree/function.go +++ b/pkg/sql/parsers/tree/function.go @@ -216,6 +216,9 @@ func (node *CreateFunction) Valid() error { } return nil case string(PYTHON): + if node.Import { + return moerr.NewNotSupportedNoCtx("Python artifact import requires the immutable artifact catalog") + } if node.Mode != "" { node.Mode = strings.ToUpper(node.Mode) if node.Mode != "SCALAR" && node.Mode != "VECTOR" { diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index 5ef466e73d678..57496bb53d63b 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -112,25 +112,10 @@ func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapp return fmt.Errorf("python udf: decode Python type contract: %w", err) } - body := PythonRoutineBody{} - if err := json.Unmarshal([]byte(routine.Body), &body); err != nil { + body, err := DecodePythonRoutineBody(routine.Body) + if err != nil { return fmt.Errorf("python udf: decode Python routine body: %w", err) } - if body.Handler == "" || body.Source == "" { - return fmt.Errorf("python udf: routine handler and source are required") - } - if body.Mode != "SCALAR" && body.Mode != "VECTOR" { - return fmt.Errorf("python udf: unsupported mode %q", body.Mode) - } - if body.NullPolicy != udf.NullCallHandler && body.NullPolicy != udf.NullReturnNull { - return fmt.Errorf("python udf: unsupported NULL policy %q", body.NullPolicy) - } - if body.ABIContract != udf.PythonABIContract || body.AdapterVersion != udf.PythonAdapterVersion { - return fmt.Errorf("python udf: unsupported Python ABI contract %q/%q", body.ABIContract, body.AdapterVersion) - } - if body.SDKVersion != udf.PythonSDKVersion { - return fmt.Errorf("python udf: unsupported Python SDK %q", body.SDKVersion) - } argTypes, err := routineArgumentTypes(routine) if err != nil { return err diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index 4e2af1402c2b2..c3beb559981df 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -11,11 +11,14 @@ package function import ( "encoding/json" "fmt" + "io" "reflect" + "strings" "github.com/google/uuid" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/pb/plan" + "github.com/matrixorigin/matrixone/pkg/udf" pythonudf "github.com/matrixorigin/matrixone/pkg/udf/python" ) @@ -58,6 +61,63 @@ type PythonRoutineBody struct { ReturnType *PythonTypeDescriptor `json:"return_type,omitempty"` } +// DecodePythonRoutineBody decodes the one catalog representation accepted by +// the Python execution path. Catalog data is an execution authority, so an +// unknown field or a second JSON value must be rejected instead of being +// silently ignored by encoding/json. +func DecodePythonRoutineBody(raw string) (PythonRoutineBody, error) { + decoder := json.NewDecoder(strings.NewReader(raw)) + decoder.DisallowUnknownFields() + var body PythonRoutineBody + if err := decoder.Decode(&body); err != nil { + return PythonRoutineBody{}, err + } + var extra json.RawMessage + if err := decoder.Decode(&extra); err != io.EOF { + if err == nil { + return PythonRoutineBody{}, fmt.Errorf("python routine body contains multiple JSON values") + } + return PythonRoutineBody{}, err + } + if err := body.Validate(); err != nil { + return PythonRoutineBody{}, err + } + return body, nil +} + +// Validate checks fields that are independent of the catalog argument list. +// The argument count is checked by Udf.ValidatePythonTypeContract after the +// legacy catalog args column has been decoded. +func (body PythonRoutineBody) Validate() error { + if body.Handler == "" || body.Source == "" { + return fmt.Errorf("python routine handler and source are required") + } + if body.Mode != "SCALAR" && body.Mode != "VECTOR" { + return fmt.Errorf("python routine has unsupported mode %q", body.Mode) + } + if body.NullPolicy != udf.NullCallHandler && body.NullPolicy != udf.NullReturnNull { + return fmt.Errorf("python routine has unsupported NULL policy %q", body.NullPolicy) + } + if body.ABIContract != udf.PythonABIContract || body.AdapterVersion != udf.PythonAdapterVersion { + return fmt.Errorf("python routine has unsupported ABI contract %q/%q", body.ABIContract, body.AdapterVersion) + } + if body.SDKVersion != udf.PythonSDKVersion { + return fmt.Errorf("python routine has unsupported SDK %q", body.SDKVersion) + } + if body.ReturnType == nil { + return fmt.Errorf("python routine is missing return descriptor") + } + for i, descriptor := range body.ArgTypes { + if err := validatePythonTypeDescriptor(descriptor); err != nil { + return fmt.Errorf("python routine argument descriptor %d: %w", i, err) + } + } + if err := validatePythonTypeDescriptor(*body.ReturnType); err != nil { + return fmt.Errorf("python routine return descriptor: %w", err) + } + return nil +} + // PythonTypeDescriptor is the single Arrow ABI descriptor used by both plan // resolution and the Python adapter. The UDF package keeps it as an alias so // the catalog body and the Arrow metadata cannot drift independently. @@ -117,21 +177,10 @@ func (u *Udf) LoadPythonTypeContract() error { } u.PythonArgTypes = nil u.PythonReturnType = nil - body := PythonRoutineBody{} - if err := json.Unmarshal([]byte(u.Body), &body); err != nil { + body, err := DecodePythonRoutineBody(u.Body) + if err != nil { return err } - if body.ReturnType == nil { - return fmt.Errorf("python routine is missing return descriptor") - } - for i, descriptor := range body.ArgTypes { - if err := validatePythonTypeDescriptor(descriptor); err != nil { - return fmt.Errorf("python routine argument descriptor %d: %w", i, err) - } - } - if err := validatePythonTypeDescriptor(*body.ReturnType); err != nil { - return fmt.Errorf("python routine return descriptor: %w", err) - } u.PythonArgTypes = append([]PythonTypeDescriptor(nil), body.ArgTypes...) returnType := *body.ReturnType u.PythonReturnType = &returnType diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go index a844109c5e3f3..fc43f1f0388a0 100644 --- a/pkg/sql/plan/function/udf_test.go +++ b/pkg/sql/plan/function/udf_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/udf" "github.com/stretchr/testify/require" ) @@ -31,8 +32,15 @@ func TestPythonTypeContractPreservesDeclaredShape(t *testing.T) { returnDescriptor, err := NewPythonTypeDescriptor(returnType) require.NoError(t, err) body, err := json.Marshal(PythonRoutineBody{ - ArgTypes: []PythonTypeDescriptor{argumentDescriptor}, - ReturnType: &returnDescriptor, + Handler: "identity", + Source: "def identity(ctx, x): return x", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []PythonTypeDescriptor{argumentDescriptor}, + ReturnType: &returnDescriptor, }) require.NoError(t, err) @@ -49,7 +57,10 @@ func TestPythonTypeContractPreservesDeclaredShape(t *testing.T) { func TestPythonTypeContractRejectsMissingReturnDescriptor(t *testing.T) { routine := &Udf{ Language: "python", - Body: `{"handler":"legacy","source":"def legacy(ctx, x): return x"}`, + Body: `{"handler":"legacy","source":"def legacy(ctx, x): return x",` + + `"mode":"SCALAR","null_policy":"CALLED_ON_NULL_INPUT",` + + `"abi_contract":"PYTHON_ARROW","adapter_version":"2026-09",` + + `"sdk_version":"1.0"}`, ArgsType: []types.Type{types.T_int32.ToType()}, RetType: "int", } @@ -61,7 +72,17 @@ func TestPythonTypeContractRejectsArgumentCountMismatch(t *testing.T) { require.NoError(t, err) returnType, err := NewPythonTypeDescriptor(types.T_int32.ToType()) require.NoError(t, err) - body, err := json.Marshal(PythonRoutineBody{ArgTypes: []PythonTypeDescriptor{argument}, ReturnType: &returnType}) + body, err := json.Marshal(PythonRoutineBody{ + Handler: "identity", + Source: "def identity(ctx, x): return x", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []PythonTypeDescriptor{argument}, + ReturnType: &returnType, + }) require.NoError(t, err) routine := &Udf{Language: "python", Body: string(body)} require.NoError(t, routine.LoadPythonTypeContract()) @@ -73,7 +94,17 @@ func TestPythonTypeContractReloadReplacesDescriptors(t *testing.T) { require.NoError(t, err) returnType, err := NewPythonTypeDescriptor(types.T_int32.ToType()) require.NoError(t, err) - body, err := json.Marshal(PythonRoutineBody{ArgTypes: []PythonTypeDescriptor{argument}, ReturnType: &returnType}) + body, err := json.Marshal(PythonRoutineBody{ + Handler: "identity", + Source: "def identity(ctx, x): return x", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []PythonTypeDescriptor{argument}, + ReturnType: &returnType, + }) require.NoError(t, err) routine := &Udf{Language: "python", Body: string(body)} require.NoError(t, routine.LoadPythonTypeContract()) @@ -81,6 +112,28 @@ func TestPythonTypeContractReloadReplacesDescriptors(t *testing.T) { require.Len(t, routine.PythonArgTypes, 1) } +func TestPythonRoutineBodyRejectsUnknownAndTrailingData(t *testing.T) { + valid, err := json.Marshal(PythonRoutineBody{ + Handler: "identity", + Source: "def identity(ctx): return 1", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ReturnType: func() *PythonTypeDescriptor { d, _ := NewPythonTypeDescriptor(types.T_int32.ToType()); return &d }(), + }) + require.NoError(t, err) + + var withUnknown map[string]any + require.NoError(t, json.Unmarshal(valid, &withUnknown)) + withUnknown["future_field"] = true + unknown, err := json.Marshal(withUnknown) + require.NoError(t, err) + require.ErrorContains(t, func() error { _, err := DecodePythonRoutineBody(string(unknown)); return err }(), "unknown field") + require.ErrorContains(t, func() error { _, err := DecodePythonRoutineBody(string(valid) + string(valid)); return err }(), "multiple JSON values") +} + func TestPythonBindingNormalizesDecimalMetadata(t *testing.T) { received := types.New(types.T_decimal64, 18, 2) required := types.New(types.T_decimal64, 18, 6) From c2e317288777f2826c6a7de71a2c4609c552aa86 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 12:19:34 +0800 Subject: [PATCH 028/241] fix(udf): reject non-finite handler deadlines --- pkg/udf/python/worker/test_worker.py | 2 ++ pkg/udf/python/worker/worker.py | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index de513484a2161..c031ef786cd94 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -546,6 +546,8 @@ def test_control_numeric_fields_are_strict(self): worker._decode_control(json.dumps({"version": True, "kind": "InputBatch", "tuple": tuple_value}).encode()) with self.assertRaisesRegex(ValueError, "invalid control field sequence"): worker._required_uint64({"sequence": "1"}, "sequence") + with self.assertRaisesRegex(ValueError, "invalid invocation field timeout"): + worker._required_positive_float({"timeout": float("nan")}, "timeout", 60.0) def test_result_ack_rejects_zero_sequence(self): state = worker._InvocationState({}, 1) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 679fc1edcfb8f..bb03e7638bd3e 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -320,7 +320,13 @@ def _required_positive_int(value: Dict[str, Any], key: str, maximum: int) -> int def _required_positive_float(value: Dict[str, Any], key: str, maximum: float) -> float: item = value.get(key) - if isinstance(item, bool) or not isinstance(item, (int, float)) or item <= 0 or item > maximum: + if ( + isinstance(item, bool) + or not isinstance(item, (int, float)) + or not math.isfinite(item) + or item <= 0 + or item > maximum + ): raise ValueError(f"PROTOCOL: invalid invocation field {key}") return float(item) From 4c03b1c6efc2b4072aa7886b2eadd6262ddbc36b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 12:24:17 +0800 Subject: [PATCH 029/241] fix(udf): validate Python execution input shapes --- pkg/sql/plan/function/python_udf.go | 44 ++++++++++++++++++++++++++--- pkg/sql/plan/function/udf_test.go | 18 ++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index 57496bb53d63b..0b25207216d47 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -93,6 +93,9 @@ func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapp if len(parameters) == 0 || parameters[0] == nil { return fmt.Errorf("python udf: missing routine descriptor") } + if err := validatePythonRoutineDescriptor(parameters[0]); err != nil { + return err + } if length < 0 { return fmt.Errorf("python udf: negative input length %d", length) } @@ -127,10 +130,8 @@ func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapp if length == 0 { return result.PreExtendAndReset(0) } - for index, input := range parameters[1:] { - if input == nil || (!input.IsConst() && input.Length() < length) { - return fmt.Errorf("python udf: input vector %d is shorter than invocation length", index) - } + if err := validatePythonInputVectors(parameters[1:], argTypes, length); err != nil { + return err } // FunctionExpressionExecutor passes an empty, non-nil select list when the // caller selected every row. In that state AnyNull is false and the @@ -241,6 +242,41 @@ func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapp return nil } +func validatePythonRoutineDescriptor(descriptor *vector.Vector) error { + if descriptor == nil { + return fmt.Errorf("python udf: missing routine descriptor") + } + if !descriptor.IsConst() { + return fmt.Errorf("python udf: routine descriptor must be constant") + } + if descriptor.Length() == 0 { + return fmt.Errorf("python udf: routine descriptor is empty") + } + return nil +} + +func validatePythonInputVectors(inputs []*vector.Vector, args []types.Type, length int) error { + if len(inputs) != len(args) { + return fmt.Errorf("python udf: input column count %d does not match routine argument count %d", len(inputs), len(args)) + } + for index, input := range inputs { + if input == nil { + return fmt.Errorf("python udf: input vector %d is nil", index) + } + if !input.IsConst() && input.Length() < length { + return fmt.Errorf("python udf: input vector %d is shorter than invocation length", index) + } + if input.GetType() == nil || !pythonTypesEqual(*input.GetType(), args[index]) { + actual := "" + if input.GetType() != nil { + actual = input.GetType().String() + } + return fmt.Errorf("python udf: input vector %d type %s does not match %s", index, actual, args[index].String()) + } + } + return nil +} + func hasNullInput(inputs []*vector.Vector, row int) bool { for _, input := range inputs { if input == nil || input.IsNull(uint64(row)) { diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go index fc43f1f0388a0..2018e7a00073a 100644 --- a/pkg/sql/plan/function/udf_test.go +++ b/pkg/sql/plan/function/udf_test.go @@ -20,6 +20,7 @@ import ( "testing" "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" "github.com/matrixorigin/matrixone/pkg/udf" "github.com/stretchr/testify/require" ) @@ -148,6 +149,23 @@ func TestPythonBindingNormalizesDecimalMetadata(t *testing.T) { require.Equal(t, required, result.finalType[1]) } +func TestPythonExecutionValidatesDescriptorAndInputTypes(t *testing.T) { + empty, err := vector.NewConstBytes(types.T_text.ToType(), nil, 0, nil) + require.NoError(t, err) + require.ErrorContains(t, validatePythonRoutineDescriptor(empty), "descriptor is empty") + + nonConst := vector.NewOffHeapVecWithTypeAndData( + types.T_text.ToType(), []byte("routine"), 1, 1, + ) + require.ErrorContains(t, validatePythonRoutineDescriptor(nonConst), "must be constant") + + input := vector.NewOffHeapVecWithTypeAndData(types.T_int32.ToType(), make([]byte, 4), 1, 1) + require.ErrorContains(t, + validatePythonInputVectors([]*vector.Vector{input}, []types.Type{types.T_int64.ToType()}, 1), + "does not match", + ) +} + func TestPythonRoutineIsVolatile(t *testing.T) { resolved, err := GetFunctionByName(context.Background(), "python_user_defined_function", []types.Type{ types.T_text.ToType(), From 397ac49b3504b48916cc52a6e31c408278989a1b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 12:29:43 +0800 Subject: [PATCH 030/241] fix(udf): validate Arrow physical descriptor limits --- pkg/sql/plan/function/udf.go | 3 +++ pkg/sql/plan/function/udf_test.go | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index c3beb559981df..980b8d4cb715c 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -218,6 +218,9 @@ func validatePythonTypeDescriptor(descriptor PythonTypeDescriptor) error { if !reflect.DeepEqual(canonical, descriptor) { return fmt.Errorf("descriptor is not canonical for %s", typ.String()) } + if _, err := descriptor.Fingerprint(); err != nil { + return fmt.Errorf("descriptor has no valid Arrow physical type: %w", err) + } return nil } func type2PlanType(typ types.Type) *plan.Type { diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go index 2018e7a00073a..e145a47324f0b 100644 --- a/pkg/sql/plan/function/udf_test.go +++ b/pkg/sql/plan/function/udf_test.go @@ -135,6 +135,27 @@ func TestPythonRoutineBodyRejectsUnknownAndTrailingData(t *testing.T) { require.ErrorContains(t, func() error { _, err := DecodePythonRoutineBody(string(valid) + string(valid)); return err }(), "multiple JSON values") } +func TestPythonTypeContractRejectsUnrepresentableArrowPrecision(t *testing.T) { + returnDescriptor := PythonTypeDescriptor{ + TypeID: int32(types.T_decimal128), + Width: 39, + OffsetWidth: 32, + } + body, err := json.Marshal(PythonRoutineBody{ + Handler: "identity", + Source: "def identity(ctx): return 1", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ReturnType: &returnDescriptor, + }) + require.NoError(t, err) + routine := &Udf{Language: "python", Body: string(body)} + require.ErrorContains(t, routine.LoadPythonTypeContract(), "precision") +} + func TestPythonBindingNormalizesDecimalMetadata(t *testing.T) { received := types.New(types.T_decimal64, 18, 2) required := types.New(types.T_decimal64, 18, 6) From 0b934c43bcdaaf0ac24bba91aa3b96e9d2f248b5 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 12:31:42 +0800 Subject: [PATCH 031/241] fix(udf): ignore null decimal payloads --- pkg/udf/python/arrow.go | 24 ++++++++++++++++-------- pkg/udf/python/arrow_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index b85fa657ce943..650db728280fb 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -662,19 +662,27 @@ func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vect return err } case types.T_decimal64: - value, err := decimalFromArray(input.(*array.Decimal128).Value(i), true) - if err != nil { - return err + var value types.Decimal64 + if !null { + converted, err := decimalFromArray(input.(*array.Decimal128).Value(i), true) + if err != nil { + return err + } + value = converted.(types.Decimal64) } - if err = vector.MustFunctionResult[types.Decimal64](result).Append(value.(types.Decimal64), null); err != nil { + if err := vector.MustFunctionResult[types.Decimal64](result).Append(value, null); err != nil { return err } case types.T_decimal128: - value, err := decimalFromArray(input.(*array.Decimal128).Value(i), false) - if err != nil { - return err + var value types.Decimal128 + if !null { + converted, err := decimalFromArray(input.(*array.Decimal128).Value(i), false) + if err != nil { + return err + } + value = converted.(types.Decimal128) } - if err = vector.MustFunctionResult[types.Decimal128](result).Append(value.(types.Decimal128), null); err != nil { + if err := vector.MustFunctionResult[types.Decimal128](result).Append(value, null); err != nil { return err } case types.T_char, types.T_varchar, types.T_text: diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index acc8ca40f451b..35adcc63d9a3b 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -6,6 +6,7 @@ package python import ( + "encoding/binary" "testing" "github.com/apache/arrow-go/v18/arrow" @@ -189,3 +190,28 @@ func TestArrowStringWidthCountsUnicodeCharacters(t *testing.T) { descriptor := TypeDescriptor{TypeID: int32(types.T_varchar), Width: 1, OffsetWidth: 32} require.NoError(t, validateArrowValueDomain(descriptor, values)) } + +func TestAppendArrowResultIgnoresNullDecimalPayload(t *testing.T) { + decimalType := &arrow.Decimal128Type{Precision: 18, Scale: 0} + validity := memory.NewBufferBytes([]byte{0}) + values := memory.NewBufferBytes(make([]byte, 16)) + // The physical coefficient of a NULL slot is unspecified. Make it a + // value that would not fit Decimal64 to ensure conversion never observes + // the payload after the validity check. + binary.LittleEndian.PutUint64(values.Bytes()[8:], 1) + data := array.NewData(decimalType, 1, []*memory.Buffer{validity, values}, nil, 1, 0) + decimals := array.NewDecimal128Data(data) + data.Release() + defer decimals.Release() + defer validity.Release() + defer values.Release() + + mp := mpool.MustNewZeroNoFixed() + result := vector.NewFunctionResultWrapper(types.T_decimal64.ToType(), mp) + defer result.Free() + require.NoError(t, result.PreExtendAndReset(1)) + + descriptor := TypeDescriptor{TypeID: int32(types.T_decimal64), Width: 18, OffsetWidth: 32} + require.NoError(t, AppendArrowResult(descriptor, decimals, result, mp)) + require.True(t, result.GetResultVector().IsNull(0)) +} From c0360501278076d1bd958421207685611f347564 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 12:41:01 +0800 Subject: [PATCH 032/241] fix(udf): honor SQL integer type equivalence --- pkg/sql/plan/function/python_udf.go | 10 ++++++---- pkg/sql/plan/function/udf_test.go | 6 ++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index 0b25207216d47..c47cb27cf2818 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -70,10 +70,12 @@ func checkPythonUdf(overloads []overload, inputs []types.Type) checkResult { } func pythonTypesEqual(left, right types.Type) bool { - return left.Oid == right.Oid && - left.Width == right.Width && - left.Scale == right.Scale && - left.Charset == right.Charset + // Type.Eq applies SQL value semantics. In particular, integer display + // width and the legacy scale marker are not part of the value contract; + // CASE and table expressions are allowed to materialize those fields + // differently while retaining the same fixed-width Arrow type. Decimal, + // string, temporal, and vector metadata remain part of the comparison. + return left.Eq(right) } // param parameters is same with param inputs in function checkPythonUdf diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go index e145a47324f0b..a5844164906ff 100644 --- a/pkg/sql/plan/function/udf_test.go +++ b/pkg/sql/plan/function/udf_test.go @@ -170,6 +170,12 @@ func TestPythonBindingNormalizesDecimalMetadata(t *testing.T) { require.Equal(t, required, result.finalType[1]) } +func TestPythonTypeEqualityUsesSQLIntegerSemantics(t *testing.T) { + declared := types.New(types.T_int32, 0, -1) + caseResult := types.New(types.T_int32, 32, -1) + require.True(t, pythonTypesEqual(declared, caseResult)) +} + func TestPythonExecutionValidatesDescriptorAndInputTypes(t *testing.T) { empty, err := vector.NewConstBytes(types.T_text.ToType(), nil, 0, nil) require.NoError(t, err) From a9ea3ff5e0cefdd467d3c6edb0b57a74d19d1f09 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:05:26 +0800 Subject: [PATCH 033/241] fix(udf): reject duplicate invocation opens --- pkg/udf/python/worker/test_worker.py | 63 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 4 +- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index c031ef786cd94..755e5847c5d48 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -309,6 +309,69 @@ def write_with_metadata(self, record, data): server.shutdown() self.assertEqual(0, handler.call_count) + def test_exchange_rejects_duplicate_open_control(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + fence = { + "account_id": 1, + "statement_id": "review", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "duplicate-open", + "lease_epoch": 1, + } + descriptor = {"type_id": worker.INT64, "offset_width": 32} + payload = { + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "abi_contract": worker.ABI_CONTRACT, + "adapter_version": worker.ADAPTER_VERSION, + "sdk_version": worker.SDK_VERSION, + "args": [descriptor], + "return": descriptor, + "source": "def f(ctx, x): return x", + "handler": "f", + "max_batch_bytes": 1 << 20, + "max_batch_rows": 1024, + "handler_timeout_seconds": 2, + } + + def control(kind, **fields): + return worker._encode_control(dict(kind=kind, tuple=fence, **fields)) + + duplicate = control("OpenInvocation", payload=payload) + chunks = iter( + [ + types.SimpleNamespace(data=None, app_metadata=duplicate), + types.SimpleNamespace( + data=None, app_metadata=control("EndInput", last_sequence=1) + ), + ] + ) + reader = types.SimpleNamespace( + schema=None, read_chunk=lambda: next(chunks) + ) + + class Writer: + def begin(self, schema): + pass + + def write_metadata(self, data): + pass + + def write_with_metadata(self, record, data): + pass + + try: + with self.assertRaisesRegex(ValueError, "duplicate OpenInvocation"): + server.do_exchange( + types.SimpleNamespace(is_cancelled=lambda: False), + types.SimpleNamespace(command=duplicate), + reader, + Writer(), + ) + finally: + server.shutdown() + @unittest.skipUnless(os.name == "posix", "process-group test") def test_descendant_is_killed_after_handler_leader_exits(self): with tempfile.TemporaryDirectory(prefix="mo-udf-owned-child-") as artifact: diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index bb03e7638bd3e..8f3bcf14e5a70 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1247,7 +1247,9 @@ def do_exchange(self, context, descriptor, reader, writer): if last_sequence != state.last_input: raise ValueError("PROTOCOL: invalid EndInput") ended = True - elif control["kind"] != "OpenInvocation": + elif control["kind"] == "OpenInvocation": + raise ValueError("PROTOCOL: duplicate OpenInvocation") + else: raise ValueError("PROTOCOL: unexpected control without Arrow data") if not ended: raise ValueError("PROTOCOL: input stream ended before EndInput") if state.acked_result != state.last_result: raise ValueError("PROTOCOL: result is not acknowledged") From 39dfcea412b0d9ee7219625d0114b8ce98a00220 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:07:58 +0800 Subject: [PATCH 034/241] fix(udf): reject unknown control envelope fields --- pkg/udf/protocol/protocol.go | 13 ++++++++++++- pkg/udf/protocol/protocol_test.go | 14 ++++++++++++++ pkg/udf/python/worker/test_worker.py | 21 +++++++++++++++++++++ pkg/udf/python/worker/worker.py | 18 ++++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 9fc962d572aa7..239dbd3209762 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -18,11 +18,13 @@ package protocol import ( + "bytes" "crypto/sha256" "encoding/hex" "encoding/json" "errors" "fmt" + "io" "sync" "time" ) @@ -113,9 +115,18 @@ func UnmarshalControl(data []byte) (Control, error) { return Control{}, fmt.Errorf("%w: control size %d is outside the allowed range", ErrProtocol, len(data)) } var control Control - if err := json.Unmarshal(data, &control); err != nil { + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(&control); err != nil { return Control{}, fmt.Errorf("%w: decode control: %v", ErrProtocol, err) } + var trailing any + if err := decoder.Decode(&trailing); err != io.EOF { + if err == nil { + return Control{}, fmt.Errorf("%w: control contains trailing JSON", ErrProtocol) + } + return Control{}, fmt.Errorf("%w: decode trailing control data: %v", ErrProtocol, err) + } if control.Version != Version || control.Kind == "" { return Control{}, fmt.Errorf("%w: unsupported control version %d", ErrProtocol, control.Version) } diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index c640e2483e519..d129668d2edea 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -16,6 +16,7 @@ package protocol import ( "bytes" + "encoding/json" "errors" "sync/atomic" "testing" @@ -48,6 +49,19 @@ func TestControlRoundTripIsBoundedAndVersioned(t *testing.T) { require.ErrorIs(t, err, ErrProtocol) } +func TestControlRejectsUnknownEnvelopeFields(t *testing.T) { + wire, err := MarshalControl(Control{Kind: "InputBatch", Tuple: testTuple(), Sequence: 1}) + require.NoError(t, err) + var object map[string]any + require.NoError(t, json.Unmarshal(wire, &object)) + object["future_field"] = "must not be ignored" + wire, err = json.Marshal(object) + require.NoError(t, err) + _, err = UnmarshalControl(wire) + require.ErrorIs(t, err, ErrProtocol) + require.ErrorContains(t, err, "unknown field") +} + func TestSystemAccountIsValidFencingIdentity(t *testing.T) { tuple := testTuple() tuple.AccountID = 0 diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 755e5847c5d48..41dd1cc3f8923 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -612,6 +612,27 @@ def test_control_numeric_fields_are_strict(self): with self.assertRaisesRegex(ValueError, "invalid invocation field timeout"): worker._required_positive_float({"timeout": float("nan")}, "timeout", 60.0) + def test_control_rejects_unknown_envelope_fields(self): + tuple_value = { + "account_id": 0, + "statement_id": "statement", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invocation", + "lease_epoch": 1, + } + value = { + "version": 1, + "kind": "InputBatch", + "tuple": tuple_value, + "sequence": 1, + "future_field": "must not be ignored", + } + with self.assertRaisesRegex(ValueError, "unsupported control field"): + worker._decode_control(json.dumps(value).encode()) + with self.assertRaisesRegex(ValueError, "unsupported control field"): + worker._encode_control(value) + def test_result_ack_rejects_zero_sequence(self): state = worker._InvocationState({}, 1) state.last_result = 1 diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 8f3bcf14e5a70..16823e0dc5c88 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -49,6 +49,20 @@ TERMINAL_TTL_SECONDS = 300.0 ACK_TIMEOUT_SECONDS = 60.0 MAX_EXECUTION_FRAME_BYTES = 1 << 30 +_CONTROL_KEYS = frozenset( + { + "version", + "kind", + "tuple", + "sequence", + "last_sequence", + "ack_sequence", + "finish_id", + "status", + "reason", + "payload", + } +) _HANDLER_RESPONSE_ERROR = 0 _HANDLER_RESPONSE_OK = 1 _HANDLER_RESPONSE_FD_ENV = "MATRIXONE_HANDLER_RESPONSE_FD" @@ -295,6 +309,8 @@ def _decode_control(data: bytes) -> Dict[str, Any]: or not value["kind"] ): raise ValueError("PROTOCOL: unsupported control") + if set(value) - _CONTROL_KEYS: + raise ValueError("PROTOCOL: unsupported control field") _tuple_key(value.get("tuple") or {}) return value @@ -341,6 +357,8 @@ def _required_uint64(value: Dict[str, Any], key: str, allow_zero: bool = False) def _encode_control(value: Dict[str, Any]) -> bytes: value = dict(value) + if set(value) - _CONTROL_KEYS: + raise ValueError("PROTOCOL: unsupported control field") value.setdefault("version", PROTOCOL_VERSION) _tuple_key(value["tuple"]) data = json.dumps(value, separators=(",", ":"), ensure_ascii=True).encode("utf-8") From 6762eb414ccd01475363f2a9e33ea60a58f38552 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:08:55 +0800 Subject: [PATCH 035/241] fix(udf): reject duplicate control JSON fields --- pkg/udf/protocol/protocol.go | 62 ++++++++++++++++++++++++++++ pkg/udf/protocol/protocol_test.go | 7 ++++ pkg/udf/python/worker/test_worker.py | 10 +++++ pkg/udf/python/worker/worker.py | 19 ++++++++- 4 files changed, 97 insertions(+), 1 deletion(-) diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 239dbd3209762..42274f57956c4 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -114,6 +114,9 @@ func UnmarshalControl(data []byte) (Control, error) { if len(data) == 0 || len(data) > MaxControlBytes { return Control{}, fmt.Errorf("%w: control size %d is outside the allowed range", ErrProtocol, len(data)) } + if err := rejectDuplicateJSONKeys(data); err != nil { + return Control{}, fmt.Errorf("%w: %v", ErrProtocol, err) + } var control Control decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() @@ -136,6 +139,65 @@ func UnmarshalControl(data []byte) (Control, error) { return control, nil } +func rejectDuplicateJSONKeys(data []byte) error { + decoder := json.NewDecoder(bytes.NewReader(data)) + if err := walkJSONValue(decoder); err != nil { + return err + } + var trailing any + if err := decoder.Decode(&trailing); err != io.EOF { + if err == nil { + return errors.New("control contains trailing JSON") + } + return fmt.Errorf("decode trailing control data: %v", err) + } + return nil +} + +func walkJSONValue(decoder *json.Decoder) error { + token, err := decoder.Token() + if err != nil { + return fmt.Errorf("decode control JSON: %v", err) + } + delim, ok := token.(json.Delim) + if !ok { + return nil + } + switch delim { + case '{': + seen := make(map[string]struct{}) + for decoder.More() { + keyToken, err := decoder.Token() + if err != nil { + return fmt.Errorf("decode control object key: %v", err) + } + key, ok := keyToken.(string) + if !ok { + return errors.New("control object key is not a string") + } + if _, exists := seen[key]; exists { + return fmt.Errorf("duplicate control JSON field %q", key) + } + seen[key] = struct{}{} + if err := walkJSONValue(decoder); err != nil { + return err + } + } + _, err = decoder.Token() + return err + case '[': + for decoder.More() { + if err := walkJSONValue(decoder); err != nil { + return err + } + } + _, err = decoder.Token() + return err + default: + return fmt.Errorf("unexpected control JSON delimiter %q", delim) + } +} + // Sequence validates the independent input and result directions of one // invocation. EndInput is a normal half-close; it does not make results // terminal until all results have been acknowledged. diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index d129668d2edea..206e46e6a8e5b 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -62,6 +62,13 @@ func TestControlRejectsUnknownEnvelopeFields(t *testing.T) { require.ErrorContains(t, err, "unknown field") } +func TestControlRejectsDuplicateJSONFields(t *testing.T) { + wire := []byte(`{"version":1,"kind":"InputBatch","tuple":{"account_id":1,"statement_id":"statement","group_id":"group","group_epoch":2,"invocation_id":"invocation","lease_epoch":3},"sequence":1,"sequence":2}`) + _, err := UnmarshalControl(wire) + require.ErrorIs(t, err, ErrProtocol) + require.ErrorContains(t, err, "duplicate control JSON field") +} + func TestSystemAccountIsValidFencingIdentity(t *testing.T) { tuple := testTuple() tuple.AccountID = 0 diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 41dd1cc3f8923..8cd5be5b5fd3e 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -633,6 +633,16 @@ def test_control_rejects_unknown_envelope_fields(self): with self.assertRaisesRegex(ValueError, "unsupported control field"): worker._encode_control(value) + def test_control_rejects_duplicate_json_fields(self): + wire = ( + b'{"version":1,"kind":"InputBatch","tuple":{"account_id":1,' + b'"statement_id":"statement","group_id":"group","group_epoch":1,' + b'"invocation_id":"invocation","lease_epoch":1},' + b'"sequence":1,"sequence":2}' + ) + with self.assertRaisesRegex(ValueError, "duplicate control JSON field"): + worker._decode_control(wire) + def test_result_ack_rejects_zero_sequence(self): state = worker._InvocationState({}, 1) state.last_result = 1 diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 16823e0dc5c88..a8d0f3e394781 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -297,10 +297,27 @@ def _tuple_key(value: Dict[str, Any]) -> tuple: ) +def _reject_duplicate_json_pairs(pairs): + result = {} + for key, value in pairs: + if key in result: + raise ValueError(f"PROTOCOL: duplicate control JSON field {key!r}") + result[key] = value + return result + + +def _reject_nonstandard_json_constant(value): + raise ValueError(f"PROTOCOL: invalid JSON constant {value}") + + def _decode_control(data: bytes) -> Dict[str, Any]: if not data or len(data) > MAX_CONTROL_BYTES: raise ValueError("PROTOCOL: invalid control size") - value = json.loads(bytes(data).decode("utf-8")) + value = json.loads( + bytes(data).decode("utf-8"), + object_pairs_hook=_reject_duplicate_json_pairs, + parse_constant=_reject_nonstandard_json_constant, + ) if ( not isinstance(value, dict) or type(value.get("version")) is not int From adffdd1a9e16c3f8a4abdb159ca5ac89af6242b5 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:09:47 +0800 Subject: [PATCH 036/241] fix(udf): validate opens before ledger admission --- pkg/udf/python/worker/test_worker.py | 47 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 11 +++++-- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 8cd5be5b5fd3e..2494d83e13835 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -372,6 +372,53 @@ def write_with_metadata(self, record, data): finally: server.shutdown() + def test_invalid_open_does_not_consume_terminal_ledger(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + fence = { + "account_id": 1, + "statement_id": "review", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invalid-open", + "lease_epoch": 1, + } + payload = { + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "abi_contract": worker.ABI_CONTRACT, + "adapter_version": worker.ADAPTER_VERSION, + "sdk_version": worker.SDK_VERSION, + "args": [{"type_id": worker.INT64, "offset_width": 32}], + "return": {"type_id": 999, "offset_width": 32}, + "source": "def f(ctx, x): return x", + "handler": "f", + "max_batch_bytes": 1 << 20, + "max_batch_rows": 1024, + "handler_timeout_seconds": 2, + } + command = worker._encode_control( + {"kind": "OpenInvocation", "tuple": fence, "payload": payload} + ) + reader = types.SimpleNamespace(schema=None, read_chunk=lambda: (_ for _ in ()).throw(StopIteration)) + writer = types.SimpleNamespace( + begin=lambda schema: None, + write_metadata=lambda data: None, + write_with_metadata=lambda record, data: None, + ) + key = worker._tuple_key(fence) + try: + with self.assertRaisesRegex(ValueError, "unsupported type id"): + server.do_exchange( + types.SimpleNamespace(is_cancelled=lambda: False), + types.SimpleNamespace(command=command), + reader, + writer, + ) + self.assertNotIn(key, server._active) + self.assertNotIn(key, server._terminal) + finally: + server.shutdown() + @unittest.skipUnless(os.name == "posix", "process-group test") def test_descendant_is_killed_after_handler_leader_exits(self): with tempfile.TemporaryDirectory(prefix="mo-udf-owned-child-") as artifact: diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index a8d0f3e394781..d428157c40cbe 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1211,12 +1211,17 @@ def do_exchange(self, context, descriptor, reader, writer): if mode not in (MODE_SCALAR, MODE_VECTOR) or null_policy not in (NULL_CALL, NULL_RETURN): raise ValueError("PROTOCOL: unsupported call mode or NULL policy") if abi_contract != ABI_CONTRACT or adapter_version != ADAPTER_VERSION: raise ValueError("PROTOCOL: unsupported Python ABI contract") if sdk_version != SDK_VERSION: raise ValueError("PROTOCOL: unsupported Python SDK") - state = self._admit(key) - state.tuple = open_control["tuple"] source = _required_string(payload, "source") handler_name = _required_string(payload, "handler") - schema = None + # Validate the complete frozen type contract before reserving a + # ledger entry. A malformed Open is rejected before it can leave + # a terminal tombstone behind. + for index, descriptor in enumerate(args): + _field(f"arg_{index}", descriptor) result_field = _field("result", result_descriptor) + state = self._admit(key) + state.tuple = open_control["tuple"] + schema = None result_schema = pa.schema([result_field]) writer.begin(result_schema) writer_started = True From 4a767005e4ebc2b94f8851cd599f47f4d1b49ab8 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:11:17 +0800 Subject: [PATCH 037/241] fix(udf): enforce Python descriptor shape --- pkg/udf/python/worker/test_worker.py | 11 +++++++++++ pkg/udf/python/worker/worker.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 2494d83e13835..4537ae2d4a827 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -52,6 +52,17 @@ def test_metadata_is_owned_by_adapter(self): with self.assertRaisesRegex(ValueError, "field name"): worker._validate_field(pa.field("other", field.type, metadata=field.metadata), "result", descriptor) + def test_type_descriptor_shape_is_strict(self): + with self.assertRaisesRegex(ValueError, "unsupported descriptor field"): + worker._field( + "result", + {"type_id": worker.INT64, "offset_width": 32, "future": 1}, + ) + with self.assertRaisesRegex(ValueError, "type_id must be an integer"): + worker._field("result", {"type_id": "23", "offset_width": 32}) + with self.assertRaisesRegex(ValueError, "offset_width must be an integer"): + worker._field("result", {"type_id": worker.INT64, "offset_width": "32"}) + def test_zero_temporal_is_distinct_from_null(self): descriptor = {"type_id": worker.DATE, "offset_width": 32, "temporal_encoding": "sql_zero_struct"} zero = worker.SqlDate(True, None) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index d428157c40cbe..7f0ef04a50eca 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -63,6 +63,21 @@ "payload", } ) +_DESCRIPTOR_KEYS = frozenset( + { + "type_id", + "width", + "scale", + "charset", + "offset_width", + "json_encoding", + "temporal_encoding", + } +) +_DESCRIPTOR_INT_KEYS = frozenset( + {"type_id", "width", "scale", "charset", "offset_width"} +) +_DESCRIPTOR_TEXT_KEYS = frozenset({"json_encoding", "temporal_encoding"}) _HANDLER_RESPONSE_ERROR = 0 _HANDLER_RESPONSE_OK = 1 _HANDLER_RESPONSE_FD_ENV = "MATRIXONE_HANDLER_RESPONSE_FD" @@ -385,6 +400,19 @@ def _encode_control(value: Dict[str, Any]) -> bytes: def _canonical_descriptor(descriptor: Dict[str, Any]) -> bytes: + if not isinstance(descriptor, dict): + raise ValueError("TYPE_CONTRACT: descriptor must be an object") + unknown = set(descriptor) - _DESCRIPTOR_KEYS + if unknown: + raise ValueError("TYPE_CONTRACT: unsupported descriptor field") + if type(descriptor.get("type_id")) is not int: + raise ValueError("TYPE_CONTRACT: descriptor type_id must be an integer") + for key in _DESCRIPTOR_INT_KEYS - {"type_id"}: + if key in descriptor and type(descriptor[key]) is not int: + raise ValueError(f"TYPE_CONTRACT: descriptor {key} must be an integer") + for key in _DESCRIPTOR_TEXT_KEYS: + if key in descriptor and type(descriptor[key]) is not str: + raise ValueError(f"TYPE_CONTRACT: descriptor {key} must be text") order = ("type_id", "width", "scale", "charset", "offset_width", "json_encoding", "temporal_encoding") result = {} for key in order: From 9c838fa2872ef4e9abba4decf84ec8a4e0c3e5c8 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:12:07 +0800 Subject: [PATCH 038/241] fix(udf): reject Arrow bodies on control frames --- pkg/udf/python/gateway.go | 5 ++++- pkg/udf/python/gateway_test.go | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 2c6753851c1dd..0329541172bad 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -419,6 +419,9 @@ func (g *Gateway) receiveResultBatch( } return int(expectedRows), nil } + if len(data.DataBody) != 0 { + return 0, fmt.Errorf("python udf: control frame contains an Arrow body") + } control, err := protocol.UnmarshalControl(data.AppMetadata) if err != nil { return 0, err @@ -476,7 +479,7 @@ func (g *Gateway) receiveFinish( } return fmt.Errorf("python udf: receive Finish: %w", err) } - if data == nil || len(data.DataHeader) > 0 { + if data == nil || len(data.DataHeader) > 0 || len(data.DataBody) > 0 { return fmt.Errorf("python udf: unexpected Arrow data while finishing") } control, err := protocol.UnmarshalControl(data.AppMetadata) diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index 793c5070374a0..f103923374c6c 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -140,3 +140,25 @@ func TestGatewayFinishRejectsLateHalfStreamControls(t *testing.T) { }) } } + +func TestGatewayRejectsArrowBodyOnControlFrame(t *testing.T) { + tuple := validInvocation().Tuple + sequence := protocol.Sequence{} + require.NoError(t, sequence.AcceptInput(1)) + require.NoError(t, sequence.EndInput(1)) + require.NoError(t, sequence.AcceptResult(1)) + require.NoError(t, sequence.AcknowledgeResults(1)) + control := gatewayControl(t, "Finish", tuple, func(value *protocol.Control) { + value.Status = statusOK + value.FinishID = "finish-1" + value.LastSequence = 1 + }) + control.DataBody = []byte("hidden Arrow payload") + gateway := &Gateway{cfg: ClientConfig{RequestTimeout: time.Second}} + err := gateway.receiveFinish( + context.Background(), nil, + &gatewayResultStream{results: []*flight.FlightData{control}}, + tuple, 1, 1, &sequence, + ) + require.ErrorContains(t, err, "unexpected Arrow data") +} From 334b505d75ac02aead134057777519d163e4f1b9 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:15:36 +0800 Subject: [PATCH 039/241] fix(udf): align Python fencing tuple validation --- pkg/udf/python/worker/test_worker.py | 16 ++++++++++++++++ pkg/udf/python/worker/worker.py | 12 ++++++++++++ 2 files changed, 28 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 4537ae2d4a827..2c1441a1649b2 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -691,6 +691,22 @@ def test_control_rejects_unknown_envelope_fields(self): with self.assertRaisesRegex(ValueError, "unsupported control field"): worker._encode_control(value) + def test_control_rejects_unknown_fencing_tuple_fields(self): + tuple_value = { + "account_id": 0, + "statement_id": "statement", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invocation", + "lease_epoch": 1, + "future_epoch": 2, + } + with self.assertRaisesRegex(ValueError, "unsupported fencing tuple field"): + worker._tuple_key(tuple_value) + value = {"version": 1, "kind": "InputBatch", "tuple": tuple_value, "sequence": 1} + with self.assertRaisesRegex(ValueError, "unsupported fencing tuple field"): + worker._decode_control(json.dumps(value).encode()) + def test_control_rejects_duplicate_json_fields(self): wire = ( b'{"version":1,"kind":"InputBatch","tuple":{"account_id":1,' diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 7f0ef04a50eca..ad9d6f6c3379a 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -63,6 +63,16 @@ "payload", } ) +_TUPLE_KEYS = frozenset( + { + "account_id", + "statement_id", + "group_id", + "group_epoch", + "invocation_id", + "lease_epoch", + } +) _DESCRIPTOR_KEYS = frozenset( { "type_id", @@ -283,6 +293,8 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: def _tuple_key(value: Dict[str, Any]) -> tuple: + if not isinstance(value, dict) or set(value) - _TUPLE_KEYS: + raise ValueError("PROTOCOL: unsupported fencing tuple field") string_fields = ("statement_id", "group_id", "invocation_id") if not isinstance(value, dict) or any(not isinstance(value.get(k), str) or not value[k] for k in string_fields): raise ValueError("PROTOCOL: incomplete fencing tuple") From 8105996161c33fd9a2b6feb83f98a70a4acec6fb Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:16:30 +0800 Subject: [PATCH 040/241] fix(udf): reject empty Flight input frames --- pkg/udf/python/worker/test_worker.py | 56 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 2 + 2 files changed, 58 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 2c1441a1649b2..11c576c3b2781 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -430,6 +430,62 @@ def test_invalid_open_does_not_consume_terminal_ledger(self): finally: server.shutdown() + def test_exchange_rejects_empty_input_frame(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + fence = { + "account_id": 1, + "statement_id": "review", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "empty-frame", + "lease_epoch": 1, + } + descriptor = {"type_id": worker.INT64, "offset_width": 32} + payload = { + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "abi_contract": worker.ABI_CONTRACT, + "adapter_version": worker.ADAPTER_VERSION, + "sdk_version": worker.SDK_VERSION, + "args": [descriptor], + "return": descriptor, + "source": "def f(ctx, x): return x", + "handler": "f", + "max_batch_bytes": 1 << 20, + "max_batch_rows": 1024, + "handler_timeout_seconds": 2, + } + + def control(kind, **fields): + return worker._encode_control(dict(kind=kind, tuple=fence, **fields)) + + chunks = iter( + [ + types.SimpleNamespace(data=None, app_metadata=b""), + types.SimpleNamespace( + data=None, app_metadata=control("EndInput", last_sequence=0) + ), + ] + ) + reader = types.SimpleNamespace(schema=None, read_chunk=lambda: next(chunks)) + writer = types.SimpleNamespace( + begin=lambda schema: None, + write_metadata=lambda data: None, + write_with_metadata=lambda record, data: None, + ) + command = control("OpenInvocation", payload=payload) + try: + with mock.patch.object(worker._InvocationState, "wait_finish_ack"): + with self.assertRaisesRegex(ValueError, "empty input frame"): + server.do_exchange( + types.SimpleNamespace(is_cancelled=lambda: False), + types.SimpleNamespace(command=command), + reader, + writer, + ) + finally: + server.shutdown() + @unittest.skipUnless(os.name == "posix", "process-group test") def test_descendant_is_killed_after_handler_leader_exits(self): with tempfile.TemporaryDirectory(prefix="mo-udf-owned-child-") as artifact: diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index ad9d6f6c3379a..3bac6dcb30c29 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1272,6 +1272,8 @@ def do_exchange(self, context, descriptor, reader, writer): chunk = reader.read_chunk() except StopIteration: break + if chunk is None or (chunk.data is None and not chunk.app_metadata): + raise ValueError("PROTOCOL: empty input frame") if chunk.data is not None: if ended: raise ValueError("PROTOCOL: input arrived after EndInput") From 4b0f8c177a77288cf8fb7260e3f35b4d0925687d Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:20:39 +0800 Subject: [PATCH 041/241] fix(udf): encode zero sequence control fields --- pkg/udf/protocol/protocol.go | 31 ++++++++++++++++++++++++++++ pkg/udf/protocol/protocol_test.go | 23 +++++++++++++++++++++ pkg/udf/python/worker/test_worker.py | 16 ++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 42274f57956c4..3e2d14298b612 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -87,6 +87,37 @@ type Control struct { Payload json.RawMessage `json:"payload,omitempty"` } +// MarshalJSON keeps closing controls self-describing when their final +// sequence is zero. The zero value is meaningful for an empty input stream; +// omitting it would make EndInput(0) indistinguishable from a malformed +// control at the Python boundary. Other controls retain the compact +// omission used for fields they do not own. +func (c Control) MarshalJSON() ([]byte, error) { + type wireControl struct { + Version int `json:"version"` + Kind string `json:"kind"` + Tuple FencingTuple `json:"tuple"` + Sequence uint64 `json:"sequence,omitempty"` + LastSequence *uint64 `json:"last_sequence,omitempty"` + AckSequence uint64 `json:"ack_sequence,omitempty"` + FinishID string `json:"finish_id,omitempty"` + Status string `json:"status,omitempty"` + Reason string `json:"reason,omitempty"` + Payload json.RawMessage `json:"payload,omitempty"` + } + wire := wireControl{ + Version: c.Version, Kind: c.Kind, Tuple: c.Tuple, + Sequence: c.Sequence, AckSequence: c.AckSequence, + FinishID: c.FinishID, Status: c.Status, Reason: c.Reason, + Payload: c.Payload, + } + if c.Kind == "EndInput" || c.Kind == "Finish" || c.LastSequence != 0 { + lastSequence := c.LastSequence + wire.LastSequence = &lastSequence + } + return json.Marshal(wire) +} + // MarshalControl produces the byte representation used in the Flight // application metadata field. Struct-field order is intentional: the same // bytes are used when a descriptor fingerprint is calculated. diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index 206e46e6a8e5b..97b5e08af9d3e 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -69,6 +69,29 @@ func TestControlRejectsDuplicateJSONFields(t *testing.T) { require.ErrorContains(t, err, "duplicate control JSON field") } +func TestClosingControlCarriesZeroLastSequence(t *testing.T) { + for _, kind := range []string{"EndInput", "Finish"} { + wire, err := MarshalControl(Control{Kind: kind, Tuple: testTuple()}) + require.NoError(t, err) + var object map[string]any + require.NoError(t, json.Unmarshal(wire, &object)) + lastSequence, ok := object["last_sequence"] + require.True(t, ok, "%s must carry an explicit last_sequence", kind) + require.Equal(t, float64(0), lastSequence) + + decoded, err := UnmarshalControl(wire) + require.NoError(t, err) + require.Zero(t, decoded.LastSequence) + } + + wire, err := MarshalControl(Control{Kind: "InputBatch", Tuple: testTuple(), Sequence: 1}) + require.NoError(t, err) + var object map[string]any + require.NoError(t, json.Unmarshal(wire, &object)) + _, ok := object["last_sequence"] + require.False(t, ok, "non-closing controls should not grow a closing-only field") +} + func TestSystemAccountIsValidFencingIdentity(t *testing.T) { tuple := testTuple() tuple.AccountID = 0 diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 11c576c3b2781..d036b9d93c5bd 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -63,6 +63,22 @@ def test_type_descriptor_shape_is_strict(self): with self.assertRaisesRegex(ValueError, "offset_width must be an integer"): worker._field("result", {"type_id": worker.INT64, "offset_width": "32"}) + def test_closing_control_preserves_zero_last_sequence(self): + fence = { + "account_id": 1, + "statement_id": "review", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "zero-sequence", + "lease_epoch": 1, + } + for kind in ("EndInput", "Finish"): + wire = worker._encode_control( + {"kind": kind, "tuple": fence, "last_sequence": 0} + ) + self.assertEqual(0, worker._decode_control(wire)["last_sequence"]) + self.assertIn(b'"last_sequence":0', wire) + def test_zero_temporal_is_distinct_from_null(self): descriptor = {"type_id": worker.DATE, "offset_width": 32, "temporal_encoding": "sql_zero_struct"} zero = worker.SqlDate(True, None) From 9712dca2516d944f1b36efc09f3096856963e8f6 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:27:50 +0800 Subject: [PATCH 042/241] fix(udf): enforce control field ownership --- pkg/udf/protocol/protocol.go | 121 +++++++++++++++++++++++++++ pkg/udf/protocol/protocol_test.go | 30 ++++++- pkg/udf/python/gateway_test.go | 4 +- pkg/udf/python/worker/test_worker.py | 40 ++++++++- pkg/udf/python/worker/worker.py | 93 ++++++++++++++++---- 5 files changed, 265 insertions(+), 23 deletions(-) diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 3e2d14298b612..ce044aed64efa 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -87,6 +87,117 @@ type Control struct { Payload json.RawMessage `json:"payload,omitempty"` } +type controlFieldRule struct { + allowed map[string]struct{} + required map[string]struct{} +} + +var controlFieldRules = map[string]controlFieldRule{ + "OpenInvocation": {allowed: map[string]struct{}{"payload": {}}, required: map[string]struct{}{"payload": {}}}, + "InputBatch": {allowed: map[string]struct{}{"sequence": {}}, required: map[string]struct{}{"sequence": {}}}, + "EndInput": {allowed: map[string]struct{}{"last_sequence": {}}, required: map[string]struct{}{"last_sequence": {}}}, + "ResultSchema": {allowed: map[string]struct{}{}}, + "InputConsumed": {allowed: map[string]struct{}{"sequence": {}}, required: map[string]struct{}{"sequence": {}}}, + "ResultBatch": {allowed: map[string]struct{}{"sequence": {}}, required: map[string]struct{}{"sequence": {}}}, + "Finish": {allowed: map[string]struct{}{"last_sequence": {}, "finish_id": {}, "status": {}}, required: map[string]struct{}{"last_sequence": {}, "finish_id": {}, "status": {}}}, + "AcknowledgeResults": {allowed: map[string]struct{}{"ack_sequence": {}}, required: map[string]struct{}{"ack_sequence": {}}}, + "AcknowledgeFinish": {allowed: map[string]struct{}{"finish_id": {}}, required: map[string]struct{}{"finish_id": {}}}, + "Ack": {allowed: map[string]struct{}{"ack_sequence": {}, "finish_id": {}, "status": {}}, required: map[string]struct{}{"status": {}}}, + "Error": {allowed: map[string]struct{}{"status": {}, "reason": {}}, required: map[string]struct{}{"status": {}, "reason": {}}}, +} + +var controlBaseFields = map[string]struct{}{ + "version": {}, "kind": {}, "tuple": {}, +} + +func validateControlFields(control Control, wire map[string]json.RawMessage) error { + rule, ok := controlFieldRules[control.Kind] + if !ok { + return fmt.Errorf("%w: unsupported control kind %q", ErrProtocol, control.Kind) + } + if wire != nil { + for field := range wire { + if _, base := controlBaseFields[field]; base { + continue + } + if _, allowed := rule.allowed[field]; !allowed { + return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, field, control.Kind) + } + } + for field := range rule.required { + if _, present := wire[field]; !present { + return fmt.Errorf("%w: control kind %q is missing field %q", ErrProtocol, control.Kind, field) + } + } + } + if control.Sequence != 0 { + if _, allowed := rule.allowed["sequence"]; !allowed { + return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "sequence", control.Kind) + } + } + if control.LastSequence != 0 { + if _, allowed := rule.allowed["last_sequence"]; !allowed { + return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "last_sequence", control.Kind) + } + } + if control.AckSequence != 0 { + if _, allowed := rule.allowed["ack_sequence"]; !allowed { + return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "ack_sequence", control.Kind) + } + } + if control.FinishID != "" { + if _, allowed := rule.allowed["finish_id"]; !allowed { + return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "finish_id", control.Kind) + } + } + if control.Status != "" { + if _, allowed := rule.allowed["status"]; !allowed { + return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "status", control.Kind) + } + } + if control.Reason != "" { + if _, allowed := rule.allowed["reason"]; !allowed { + return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "reason", control.Kind) + } + } + if len(control.Payload) != 0 { + if _, allowed := rule.allowed["payload"]; !allowed { + return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "payload", control.Kind) + } + } + switch control.Kind { + case "OpenInvocation": + if len(control.Payload) == 0 && wire == nil { + return fmt.Errorf("%w: control kind %q is missing field %q", ErrProtocol, control.Kind, "payload") + } + case "InputBatch", "InputConsumed", "ResultBatch": + if control.Sequence == 0 { + return fmt.Errorf("%w: control kind %q requires a positive sequence", ErrProtocol, control.Kind) + } + case "AcknowledgeResults": + if control.AckSequence == 0 { + return fmt.Errorf("%w: control kind %q requires a positive ack_sequence", ErrProtocol, control.Kind) + } + case "Finish": + if control.FinishID == "" || control.Status == "" { + return fmt.Errorf("%w: control kind %q requires finish_id and status", ErrProtocol, control.Kind) + } + case "AcknowledgeFinish": + if control.FinishID == "" { + return fmt.Errorf("%w: control kind %q requires finish_id", ErrProtocol, control.Kind) + } + case "Ack": + if control.Status == "" || ((control.AckSequence == 0) == (control.FinishID == "")) { + return fmt.Errorf("%w: Ack requires status and exactly one acknowledgement identity", ErrProtocol) + } + case "Error": + if control.Status == "" || control.Reason == "" { + return fmt.Errorf("%w: control kind %q requires status and reason", ErrProtocol, control.Kind) + } + } + return nil +} + // MarshalJSON keeps closing controls self-describing when their final // sequence is zero. The zero value is meaningful for an empty input stream; // omitting it would make EndInput(0) indistinguishable from a malformed @@ -131,6 +242,9 @@ func MarshalControl(control Control) ([]byte, error) { if err := control.Tuple.Validate(); err != nil { return nil, err } + if err := validateControlFields(control, nil); err != nil { + return nil, err + } encoded, err := json.Marshal(control) if err != nil { return nil, fmt.Errorf("%w: encode control: %v", ErrProtocol, err) @@ -167,6 +281,13 @@ func UnmarshalControl(data []byte) (Control, error) { if err := control.Tuple.Validate(); err != nil { return Control{}, err } + var fields map[string]json.RawMessage + if err := json.Unmarshal(data, &fields); err != nil { + return Control{}, fmt.Errorf("%w: control must be an object: %v", ErrProtocol, err) + } + if err := validateControlFields(control, fields); err != nil { + return Control{}, err + } return control, nil } diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index 97b5e08af9d3e..be08e92c386f7 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -69,9 +69,35 @@ func TestControlRejectsDuplicateJSONFields(t *testing.T) { require.ErrorContains(t, err, "duplicate control JSON field") } +func TestControlFieldsBelongToTheirKind(t *testing.T) { + wire, err := MarshalControl(Control{Kind: "InputBatch", Tuple: testTuple(), Sequence: 1}) + require.NoError(t, err) + var object map[string]any + require.NoError(t, json.Unmarshal(wire, &object)) + object["last_sequence"] = 1 + wire, err = json.Marshal(object) + require.NoError(t, err) + _, err = UnmarshalControl(wire) + require.ErrorIs(t, err, ErrProtocol) + require.ErrorContains(t, err, "not valid for control kind") + + _, err = MarshalControl(Control{Kind: "InputBatch", Tuple: testTuple(), Sequence: 1, Status: "ERROR"}) + require.ErrorIs(t, err, ErrProtocol) + require.ErrorContains(t, err, "not valid for control kind") + + _, err = UnmarshalControl([]byte(`{"version":1,"kind":"Unknown","tuple":{"account_id":1,"statement_id":"statement","group_id":"group","group_epoch":2,"invocation_id":"invocation","lease_epoch":3}}`)) + require.ErrorIs(t, err, ErrProtocol) + require.ErrorContains(t, err, "unsupported control kind") +} + func TestClosingControlCarriesZeroLastSequence(t *testing.T) { for _, kind := range []string{"EndInput", "Finish"} { - wire, err := MarshalControl(Control{Kind: kind, Tuple: testTuple()}) + control := Control{Kind: kind, Tuple: testTuple()} + if kind == "Finish" { + control.Status = "OK" + control.FinishID = "finish" + } + wire, err := MarshalControl(control) require.NoError(t, err) var object map[string]any require.NoError(t, json.Unmarshal(wire, &object)) @@ -96,7 +122,7 @@ func TestSystemAccountIsValidFencingIdentity(t *testing.T) { tuple := testTuple() tuple.AccountID = 0 require.NoError(t, tuple.Validate()) - _, err := MarshalControl(Control{Kind: "OpenInvocation", Tuple: tuple}) + _, err := MarshalControl(Control{Kind: "OpenInvocation", Tuple: tuple, Payload: []byte(`{}`)}) require.NoError(t, err) } diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index f103923374c6c..f4def0e6051a1 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -131,7 +131,9 @@ func TestGatewayFinishRejectsLateHalfStreamControls(t *testing.T) { require.NoError(t, sequence.AcknowledgeResults(1)) stream := &gatewayResultStream{results: []*flight.FlightData{ gatewayControl(t, kind, tuple, func(control *protocol.Control) { - control.Sequence = 1 + if kind == "InputConsumed" { + control.Sequence = 1 + } }), }} gateway := &Gateway{cfg: ClientConfig{RequestTimeout: time.Second}} diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index d036b9d93c5bd..cb7799d45be4b 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -72,9 +72,13 @@ def test_closing_control_preserves_zero_last_sequence(self): "invocation_id": "zero-sequence", "lease_epoch": 1, } - for kind in ("EndInput", "Finish"): + controls = { + "EndInput": {"last_sequence": 0}, + "Finish": {"last_sequence": 0, "finish_id": "finish", "status": "OK"}, + } + for kind, fields in controls.items(): wire = worker._encode_control( - {"kind": kind, "tuple": fence, "last_sequence": 0} + {"kind": kind, "tuple": fence, **fields} ) self.assertEqual(0, worker._decode_control(wire)["last_sequence"]) self.assertIn(b'"last_sequence":0', wire) @@ -763,6 +767,38 @@ def test_control_rejects_unknown_envelope_fields(self): with self.assertRaisesRegex(ValueError, "unsupported control field"): worker._encode_control(value) + def test_control_fields_belong_to_their_kind(self): + tuple_value = { + "account_id": 1, + "statement_id": "statement", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invocation", + "lease_epoch": 1, + } + input_batch = { + "version": worker.PROTOCOL_VERSION, + "kind": "InputBatch", + "tuple": tuple_value, + "sequence": 1, + } + with self.assertRaisesRegex(ValueError, "not valid for control kind"): + worker._encode_control({**input_batch, "last_sequence": 1}) + with self.assertRaisesRegex(ValueError, "not valid for control kind"): + worker._decode_control( + json.dumps({**input_batch, "last_sequence": 1}).encode() + ) + with self.assertRaisesRegex(ValueError, "unsupported control kind"): + worker._decode_control( + json.dumps( + { + "version": worker.PROTOCOL_VERSION, + "kind": "Unknown", + "tuple": tuple_value, + } + ).encode() + ) + def test_control_rejects_unknown_fencing_tuple_fields(self): tuple_value = { "account_id": 0, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 3bac6dcb30c29..8f0587be4eb66 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -63,6 +63,29 @@ "payload", } ) +_CONTROL_BASE_KEYS = frozenset({"version", "kind", "tuple"}) +_CONTROL_FIELD_RULES = { + "OpenInvocation": (frozenset({"payload"}), frozenset({"payload"})), + "InputBatch": (frozenset({"sequence"}), frozenset({"sequence"})), + "EndInput": (frozenset({"last_sequence"}), frozenset({"last_sequence"})), + "ResultSchema": (frozenset(), frozenset()), + "InputConsumed": (frozenset({"sequence"}), frozenset({"sequence"})), + "ResultBatch": (frozenset({"sequence"}), frozenset({"sequence"})), + "Finish": ( + frozenset({"last_sequence", "finish_id", "status"}), + frozenset({"last_sequence", "finish_id", "status"}), + ), + "AcknowledgeResults": ( + frozenset({"ack_sequence"}), + frozenset({"ack_sequence"}), + ), + "AcknowledgeFinish": (frozenset({"finish_id"}), frozenset({"finish_id"})), + "Ack": ( + frozenset({"ack_sequence", "finish_id", "status"}), + frozenset({"status"}), + ), + "Error": (frozenset({"status", "reason"}), frozenset({"status", "reason"})), +} _TUPLE_KEYS = frozenset( { "account_id", @@ -356,6 +379,7 @@ def _decode_control(data: bytes) -> Dict[str, Any]: if set(value) - _CONTROL_KEYS: raise ValueError("PROTOCOL: unsupported control field") _tuple_key(value.get("tuple") or {}) + _validate_control_fields(value, wire=True) return value @@ -399,12 +423,52 @@ def _required_uint64(value: Dict[str, Any], key: str, allow_zero: bool = False) return item +def _validate_control_fields(value: Dict[str, Any], wire: bool) -> None: + kind = value["kind"] + rule = _CONTROL_FIELD_RULES.get(kind) + if rule is None: + raise ValueError(f"PROTOCOL: unsupported control kind {kind!r}") + allowed, required = rule + fields = set(value) - _CONTROL_BASE_KEYS + invalid = fields - allowed + if invalid: + raise ValueError( + f"PROTOCOL: field {next(iter(invalid))!r} is not valid for control kind {kind!r}" + ) + if wire: + missing = required - set(value) + if missing: + raise ValueError( + f"PROTOCOL: control kind {kind!r} is missing field {next(iter(missing))!r}" + ) + if "sequence" in value: + _required_uint64(value, "sequence") + if "last_sequence" in value: + _required_uint64(value, "last_sequence", allow_zero=True) + if "ack_sequence" in value: + _required_uint64(value, "ack_sequence") + if "finish_id" in value: + _required_string(value, "finish_id") + if "status" in value: + _required_string(value, "status") + if "reason" in value: + _required_string(value, "reason") + if kind == "Ack": + if ("ack_sequence" in value) == ("finish_id" in value): + raise ValueError("PROTOCOL: Ack requires exactly one acknowledgement identity") + elif kind == "OpenInvocation" and ( + "payload" not in value or (wire and value["payload"] is None) + ): + raise ValueError("PROTOCOL: control kind 'OpenInvocation' is missing field 'payload'") + + def _encode_control(value: Dict[str, Any]) -> bytes: value = dict(value) if set(value) - _CONTROL_KEYS: raise ValueError("PROTOCOL: unsupported control field") value.setdefault("version", PROTOCOL_VERSION) _tuple_key(value["tuple"]) + _validate_control_fields(value, wire=False) data = json.dumps(value, separators=(",", ":"), ensure_ascii=True).encode("utf-8") if len(data) > MAX_CONTROL_BYTES: raise ValueError("PROTOCOL: control is too large") @@ -1193,29 +1257,22 @@ def do_action(self, context, action): finish_id = _required_string(control, "finish_id") if finish_id != terminal.finish_id: raise ValueError("PROTOCOL: terminal Finish ACK does not match the completed Finish") - yield _encode_control( - { - "kind": "Ack", - "tuple": control["tuple"], - "status": "OK", - "ack_sequence": control.get("ack_sequence", 0), - "finish_id": control.get("finish_id", ""), - } - ) + yield _encode_control(self._ack_control(control)) return if action.type == "AcknowledgeResults": state.ack_result(_required_uint64(control, "ack_sequence")) elif action.type == "AcknowledgeFinish": state.ack_finish(_required_string(control, "finish_id")) - yield _encode_control( - { - "kind": "Ack", - "tuple": control["tuple"], - "status": "OK", - "ack_sequence": control.get("ack_sequence", 0), - "finish_id": control.get("finish_id", ""), - } - ) + yield _encode_control(self._ack_control(control)) + + @staticmethod + def _ack_control(control: Dict[str, Any]) -> Dict[str, Any]: + value = {"kind": "Ack", "tuple": control["tuple"], "status": "OK"} + if control["kind"] == "AcknowledgeResults": + value["ack_sequence"] = control["ack_sequence"] + else: + value["finish_id"] = control["finish_id"] + return value def do_exchange(self, context, descriptor, reader, writer): state = None From 55e0bb977c3427b611bdc7d51e05541c39850e6b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:31:50 +0800 Subject: [PATCH 043/241] fix(udf): preserve decimal64 signed range --- pkg/udf/python/arrow.go | 11 ++++++++++- pkg/udf/python/arrow_test.go | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 650db728280fb..a3f6fc4b4a4b8 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -904,7 +904,7 @@ func hasExactMicrosecondScale(value int64, scale int32) bool { } func decimalFromArray(value decimal128.Num, narrow bool) (any, error) { high, low := uint64(value.HighBits()), value.LowBits() - if narrow && high != 0 && high != math.MaxUint64 { + if narrow && !decimal128FitsDecimal64(high, low) { return nil, fmt.Errorf("TYPE_CONTRACT: Decimal128 result does not fit Decimal64") } if narrow { @@ -912,6 +912,15 @@ func decimalFromArray(value decimal128.Num, narrow bool) (any, error) { } return types.Decimal128{B0_63: low, B64_127: high}, nil } + +func decimal128FitsDecimal64(high, low uint64) bool { + // A signed 128-bit value fits in signed 64 bits only when the high word is + // a proper sign extension of the low word. Checking the high word alone + // would turn +2^63 into the negative Decimal64 minimum. + return (high == 0 && low <= math.MaxInt64) || + (high == math.MaxUint64 && low >= uint64(1)<<63) +} + func appendTemporalResult(input *array.Struct, typ types.T, index int, result vector.FunctionResultWrapper) error { if input.IsNull(index) { return appendTemporalNull(typ, result) diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 35adcc63d9a3b..3d6ce2b6fc0ab 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -7,6 +7,7 @@ package python import ( "encoding/binary" + "math" "testing" "github.com/apache/arrow-go/v18/arrow" @@ -215,3 +216,18 @@ func TestAppendArrowResultIgnoresNullDecimalPayload(t *testing.T) { require.NoError(t, AppendArrowResult(descriptor, decimals, result, mp)) require.True(t, result.GetResultVector().IsNull(0)) } + +func TestDecimal128ToDecimal64ChecksSignedRange(t *testing.T) { + max, err := decimalFromArray(decimal128.New(0, math.MaxInt64), true) + require.NoError(t, err) + require.Equal(t, types.Decimal64(math.MaxInt64), max) + + min, err := decimalFromArray(decimal128.New(-1, uint64(1)<<63), true) + require.NoError(t, err) + require.Equal(t, types.Decimal64(uint64(1)<<63), min) + + _, err = decimalFromArray(decimal128.New(0, uint64(1)<<63), true) + require.ErrorContains(t, err, "does not fit Decimal64") + _, err = decimalFromArray(decimal128.New(-1, uint64(1)<<63-1), true) + require.ErrorContains(t, err, "does not fit Decimal64") +} From ddb411a3937045bf6cbe2ada55bc4c1c09be8175 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:32:20 +0800 Subject: [PATCH 044/241] fix(udf): reject nonstandard control JSON --- pkg/udf/python/worker/test_worker.py | 19 +++++++++++++++++++ pkg/udf/python/worker/worker.py | 10 +++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index cb7799d45be4b..a800f3ebe554e 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -799,6 +799,25 @@ def test_control_fields_belong_to_their_kind(self): ).encode() ) + def test_control_encoder_rejects_nonstandard_json_numbers(self): + tuple_value = { + "account_id": 1, + "statement_id": "statement", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invocation", + "lease_epoch": 1, + } + for number in (float("nan"), float("inf"), float("-inf")): + with self.assertRaisesRegex(ValueError, "invalid control JSON"): + worker._encode_control( + { + "kind": "OpenInvocation", + "tuple": tuple_value, + "payload": {"number": number}, + } + ) + def test_control_rejects_unknown_fencing_tuple_fields(self): tuple_value = { "account_id": 0, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 8f0587be4eb66..42b708184325c 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -469,7 +469,15 @@ def _encode_control(value: Dict[str, Any]) -> bytes: value.setdefault("version", PROTOCOL_VERSION) _tuple_key(value["tuple"]) _validate_control_fields(value, wire=False) - data = json.dumps(value, separators=(",", ":"), ensure_ascii=True).encode("utf-8") + try: + data = json.dumps( + value, + separators=(",", ":"), + ensure_ascii=True, + allow_nan=False, + ).encode("utf-8") + except (TypeError, ValueError, UnicodeError) as exc: + raise ValueError("PROTOCOL: invalid control JSON") from exc if len(data) > MAX_CONTROL_BYTES: raise ValueError("PROTOCOL: control is too large") return data From a08e2a1d3d3e0f187a05d86a08670bf909d30853 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:32:56 +0800 Subject: [PATCH 045/241] fix(udf): preserve fencing tuple encoding --- pkg/udf/protocol/protocol.go | 4 ++++ pkg/udf/protocol/protocol_test.go | 8 ++++++++ pkg/udf/python/worker/test_worker.py | 12 ++++++++++++ pkg/udf/python/worker/worker.py | 5 +++++ 4 files changed, 29 insertions(+) diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index ce044aed64efa..3f81620765bcc 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -27,6 +27,7 @@ import ( "io" "sync" "time" + "unicode/utf8" ) const ( @@ -68,6 +69,9 @@ func (t FencingTuple) Validate() error { t.GroupEpoch == 0 || t.InvocationID == "" || t.LeaseEpoch == 0 { return fmt.Errorf("%w: incomplete fencing tuple", ErrProtocol) } + if !utf8.ValidString(t.StatementID) || !utf8.ValidString(t.GroupID) || !utf8.ValidString(t.InvocationID) { + return fmt.Errorf("%w: fencing tuple contains invalid UTF-8", ErrProtocol) + } return nil } diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index be08e92c386f7..4052a9fbf91a9 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -126,6 +126,14 @@ func TestSystemAccountIsValidFencingIdentity(t *testing.T) { require.NoError(t, err) } +func TestFencingTupleRejectsInvalidUTF8(t *testing.T) { + tuple := testTuple() + tuple.StatementID = string([]byte{0xff}) + require.ErrorContains(t, tuple.Validate(), "invalid UTF-8") + _, err := MarshalControl(Control{Kind: "OpenInvocation", Tuple: tuple, Payload: []byte(`{}`)}) + require.ErrorContains(t, err, "invalid UTF-8") +} + func TestSequenceKeepsHalfCloseIndependentFromResults(t *testing.T) { var sequence Sequence require.NoError(t, sequence.AcceptInput(1)) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index a800f3ebe554e..260540c523f89 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -834,6 +834,18 @@ def test_control_rejects_unknown_fencing_tuple_fields(self): with self.assertRaisesRegex(ValueError, "unsupported fencing tuple field"): worker._decode_control(json.dumps(value).encode()) + def test_fencing_tuple_rejects_invalid_utf8(self): + tuple_value = { + "account_id": 1, + "statement_id": "\ud800", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invocation", + "lease_epoch": 1, + } + with self.assertRaisesRegex(ValueError, "invalid UTF-8"): + worker._tuple_key(tuple_value) + def test_control_rejects_duplicate_json_fields(self): wire = ( b'{"version":1,"kind":"InputBatch","tuple":{"account_id":1,' diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 42b708184325c..7d573ef0cfcf1 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -321,6 +321,11 @@ def _tuple_key(value: Dict[str, Any]) -> tuple: string_fields = ("statement_id", "group_id", "invocation_id") if not isinstance(value, dict) or any(not isinstance(value.get(k), str) or not value[k] for k in string_fields): raise ValueError("PROTOCOL: incomplete fencing tuple") + try: + for key in string_fields: + value[key].encode("utf-8") + except UnicodeEncodeError as exc: + raise ValueError("PROTOCOL: fencing tuple contains invalid UTF-8") from exc account_id = value.get("account_id") if ( isinstance(account_id, bool) From 58c0e3fcd4b9ce4f4fc7b645001b16048c2eed40 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:33:44 +0800 Subject: [PATCH 046/241] fix(udf): validate IANA timezone identities --- pkg/udf/python/worker/test_worker.py | 27 +++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 5 +++++ 2 files changed, 32 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 260540c523f89..4eec30c723577 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -645,6 +645,33 @@ def test_statement_context_is_whitelisted_and_frozen(self): } ) + def test_statement_context_rejects_unknown_iana_timezone(self): + with self.assertRaisesRegex(ValueError, "not present in the local tzdb"): + worker._statement_context( + { + "statement_timestamp_utc": "1704067200000000", + "session_timezone_kind": "IANA", + "session_timezone_name": "NoSuch/Zone", + "session_timezone_tzdb_version": "2025a", + "sql_mode": "[]", + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + ) + + context = worker._statement_context( + { + "statement_timestamp_utc": "1704067200000000", + "session_timezone_kind": "IANA", + "session_timezone_name": "UTC", + "session_timezone_tzdb_version": "2025a", + "sql_mode": "[]", + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + ) + self.assertEqual("UTC", context.session_timezone.name) + def test_terminal_admission_does_not_evict_live_tombstones(self): old_records = worker.MAX_LEDGER_ENTRIES old_bytes = worker.MAX_LEDGER_BYTES diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 7d573ef0cfcf1..879a7f289c927 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -35,6 +35,7 @@ from collections import OrderedDict from dataclasses import dataclass from typing import Any, Dict, Iterable, Optional +from zoneinfo import ZoneInfo, ZoneInfoNotFoundError import pyarrow as pa import pyarrow.flight as flight @@ -276,6 +277,10 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: tzdb_version = _required_context_value(raw, "session_timezone_tzdb_version") if "session_timezone_offset_minutes" in raw: raise ValueError("PROTOCOL: IANA timezone cannot carry a fixed offset") + try: + ZoneInfo(timezone_name) + except (ZoneInfoNotFoundError, ValueError) as exc: + raise ValueError("PROTOCOL: IANA timezone is not present in the local tzdb") from exc timezone = TimezoneContext("IANA", name=timezone_name, tzdb_version=tzdb_version) elif timezone_kind == "FIXED_OFFSET": offset_text = _required_context_value(raw, "session_timezone_offset_minutes") From b3dcaf0ab8c3a7addb0c0ca895c3727e992314ba Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:34:44 +0800 Subject: [PATCH 047/241] fix(udf): validate input Arrow values --- pkg/udf/python/worker/test_worker.py | 64 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 2 + 2 files changed, 66 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 4eec30c723577..6149b206bf6a6 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -506,6 +506,70 @@ def control(kind, **fields): finally: server.shutdown() + def test_exchange_rejects_invalid_input_values_before_handler(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + fence = { + "account_id": 1, + "statement_id": "review", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invalid-input-values", + "lease_epoch": 1, + } + descriptor = {"type_id": worker.VECF32, "width": 2, "offset_width": 0} + child = pa.array([1.0, None], type=pa.float32()) + invalid_vector = pa.FixedSizeListArray.from_arrays(child, 2) + batch = pa.RecordBatch.from_arrays( + [invalid_vector], + schema=pa.schema([worker._field("arg_0", descriptor)]), + ) + payload = { + "mode": worker.MODE_VECTOR, + "null_policy": worker.NULL_CALL, + "abi_contract": worker.ABI_CONTRACT, + "adapter_version": worker.ADAPTER_VERSION, + "sdk_version": worker.SDK_VERSION, + "args": [descriptor], + "return": descriptor, + "source": "def f(ctx, x): return x", + "handler": "f", + "max_batch_bytes": 1 << 20, + "max_batch_rows": 1024, + "handler_timeout_seconds": 2, + } + + def control(kind, **fields): + return worker._encode_control(dict(kind=kind, tuple=fence, **fields)) + + chunks = iter( + [ + types.SimpleNamespace( + data=batch, + app_metadata=control("InputBatch", sequence=1), + ), + ] + ) + reader = types.SimpleNamespace(schema=batch.schema, read_chunk=lambda: next(chunks)) + writer = types.SimpleNamespace( + begin=lambda schema: None, + write_metadata=lambda data: None, + write_with_metadata=lambda record, data: None, + ) + command = control("OpenInvocation", payload=payload) + try: + handler = mock.Mock() + with mock.patch.object(worker, "_run_handler_process", handler): + with self.assertRaisesRegex(ValueError, "child validity"): + server.do_exchange( + types.SimpleNamespace(is_cancelled=lambda: False), + types.SimpleNamespace(command=command), + reader, + writer, + ) + handler.assert_not_called() + finally: + server.shutdown() + @unittest.skipUnless(os.name == "posix", "process-group test") def test_descendant_is_killed_after_handler_leader_exits(self): with tempfile.TemporaryDirectory(prefix="mo-udf-owned-child-") as artifact: diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 879a7f289c927..cf8f5d7e77cb2 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1364,6 +1364,8 @@ def do_exchange(self, context, descriptor, reader, writer): if batch.num_rows <= 0: raise ValueError("PROTOCOL: empty input batch") if batch.num_rows > max_batch_rows: raise ValueError("RESOURCE_EXHAUSTED: input batch has too many rows") if batch.nbytes > max_batch_bytes: raise ValueError("RESOURCE_EXHAUSTED: input batch exceeds byte limit") + for index, descriptor in enumerate(args): + _validate_array_values(batch.column(index), descriptor) execution_request = { "source": source, "handler": handler_name, From 3ff6cc45cd409b00f53e1b4afb311d625ccbf980 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:36:49 +0800 Subject: [PATCH 048/241] fix(udf): reject empty constant inputs --- pkg/sql/plan/function/python_udf.go | 3 +++ pkg/udf/python/arrow.go | 2 +- pkg/udf/python/arrow_test.go | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index c47cb27cf2818..90b29bdf5cc44 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -265,6 +265,9 @@ func validatePythonInputVectors(inputs []*vector.Vector, args []types.Type, leng if input == nil { return fmt.Errorf("python udf: input vector %d is nil", index) } + if input.Length() == 0 { + return fmt.Errorf("python udf: input vector %d is empty", index) + } if !input.IsConst() && input.Length() < length { return fmt.Errorf("python udf: input vector %d is shorter than invocation length", index) } diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index a3f6fc4b4a4b8..66b47475ffddb 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -304,7 +304,7 @@ func BuildInputRecordRange(inputs []*vector.Vector, args []types.Type, start, le if err != nil { return nil, nil, err } - if inputs[i] == nil || (!inputs[i].IsConst() && inputs[i].Length() < start+length) { + if inputs[i] == nil || inputs[i].Length() == 0 || (!inputs[i].IsConst() && inputs[i].Length() < start+length) { return nil, nil, fmt.Errorf("input column %d is shorter than batch range", i) } } diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 3d6ce2b6fc0ab..6b6b9797dedb1 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -129,6 +129,20 @@ func TestZeroArgumentRecordPreservesRows(t *testing.T) { require.Equal(t, int64(0), decoded.NumCols()) } +func TestBuildInputRecordRejectsEmptyConstantVector(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + input := vector.NewConstNull(types.T_int64.ToType(), 0, mp) + defer input.Free(mp) + + _, _, err := BuildInputRecordRange( + []*vector.Vector{input}, + []types.Type{types.T_int64.ToType()}, + 0, + 1, + ) + require.ErrorContains(t, err, "shorter than batch range") +} + func TestArrowValueDomainRejectsWidthAndTimeOverflow(t *testing.T) { allocator := memory.NewGoAllocator() stringBuilder := array.NewStringBuilder(allocator) From 52c999668baf07dad4feb1d32ef2c9b164659329 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:40:18 +0800 Subject: [PATCH 049/241] fix(udf): classify malformed worker frames --- pkg/udf/python/worker/test_worker.py | 14 ++++++++++++++ pkg/udf/python/worker/worker.py | 24 ++++++++++++++++++------ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 6149b206bf6a6..26e1880f74a73 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -63,6 +63,20 @@ def test_type_descriptor_shape_is_strict(self): with self.assertRaisesRegex(ValueError, "offset_width must be an integer"): worker._field("result", {"type_id": worker.INT64, "offset_width": "32"}) + def test_malformed_control_is_reported_as_protocol_error(self): + with self.assertRaisesRegex(ValueError, "PROTOCOL: invalid control UTF-8"): + worker._decode_control(b"\xff") + with self.assertRaisesRegex(ValueError, "PROTOCOL: invalid control JSON"): + worker._decode_control(b"{") + self.assertEqual( + "PROTOCOL: invalid control JSON", + worker._safe_error(ValueError("PROTOCOL: invalid control JSON")), + ) + + def test_malformed_arrow_payload_is_reported_as_protocol_error(self): + with self.assertRaisesRegex(ValueError, "PROTOCOL: execution payload is not a valid Arrow stream"): + worker._deserialize_record_batch(b"not-an-arrow-stream") + def test_closing_control_preserves_zero_last_sequence(self): fence = { "account_id": 1, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index cf8f5d7e77cb2..d2e3f08771c81 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -373,11 +373,20 @@ def _reject_nonstandard_json_constant(value): def _decode_control(data: bytes) -> Dict[str, Any]: if not data or len(data) > MAX_CONTROL_BYTES: raise ValueError("PROTOCOL: invalid control size") - value = json.loads( - bytes(data).decode("utf-8"), - object_pairs_hook=_reject_duplicate_json_pairs, - parse_constant=_reject_nonstandard_json_constant, - ) + try: + text = bytes(data).decode("utf-8") + except UnicodeDecodeError as exc: + raise ValueError("PROTOCOL: invalid control UTF-8") from exc + try: + value = json.loads( + text, + object_pairs_hook=_reject_duplicate_json_pairs, + parse_constant=_reject_nonstandard_json_constant, + ) + except json.JSONDecodeError as exc: + raise ValueError("PROTOCOL: invalid control JSON") from exc + except RecursionError as exc: + raise ValueError("PROTOCOL: control JSON is too deeply nested") from exc if ( not isinstance(value, dict) or type(value.get("version")) is not int @@ -881,7 +890,10 @@ def _serialize_record_batch(record: pa.RecordBatch) -> bytes: def _deserialize_record_batch(data: bytes) -> pa.RecordBatch: if not isinstance(data, (bytes, bytearray)) or not data: raise ValueError("PROTOCOL: execution payload is missing an Arrow batch") - reader = pa.ipc.open_stream(pa.py_buffer(data)) + try: + reader = pa.ipc.open_stream(pa.py_buffer(data)) + except pa.ArrowException as exc: + raise ValueError("PROTOCOL: execution payload is not a valid Arrow stream") from exc try: try: record = reader.read_next_batch() From ff2dfd401c33c4c2a17ca4b5d0f55a411110bb8b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:44:03 +0800 Subject: [PATCH 050/241] fix(udf): enforce descriptor value domains --- pkg/udf/python/arrow.go | 80 ++++++++++++++++++++++++++++ pkg/udf/python/arrow_test.go | 13 +++++ pkg/udf/python/worker/test_worker.py | 11 ++++ pkg/udf/python/worker/worker.py | 57 ++++++++++++++++++++ 4 files changed, 161 insertions(+) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 66b47475ffddb..7d4b14dc8a08a 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -91,6 +91,9 @@ func (d TypeDescriptor) Type() types.Type { } func (d TypeDescriptor) canonical() ([]byte, error) { return json.Marshal(d) } func (d TypeDescriptor) Fingerprint() (string, error) { + if err := d.Validate(); err != nil { + return "", err + } canonical, err := d.canonical() if err != nil { return "", err @@ -114,6 +117,83 @@ func (d TypeDescriptor) Fingerprint() (string, error) { return hex.EncodeToString(h.Sum(nil)), nil } +// Validate checks the semantic fields that Arrow's physical type does not +// carry. Keeping this at the descriptor boundary makes manually constructed +// catalog or wire descriptors obey the same contract as descriptors produced +// from a SQL type. +func (d TypeDescriptor) Validate() error { + oid := types.T(d.TypeID) + if d.Width < 0 { + return fmt.Errorf("TYPE_CONTRACT: descriptor width must be non-negative") + } + if d.Scale < 0 { + return fmt.Errorf("TYPE_CONTRACT: descriptor scale must be non-negative") + } + expectedOffsetWidth := int32(32) + if oid == types.T_uuid || oid == types.T_array_float32 || oid == types.T_array_float64 { + expectedOffsetWidth = 0 + } + if d.OffsetWidth != expectedOffsetWidth { + return fmt.Errorf("TYPE_CONTRACT: descriptor offset_width must be %d for %s", expectedOffsetWidth, oid.String()) + } + if d.JSONEncoding != "" && (oid != types.T_json || d.JSONEncoding != "canonical_text") { + return fmt.Errorf("TYPE_CONTRACT: unsupported JSON encoding") + } + if d.TemporalEncoding != "" && (oid != types.T_date && oid != types.T_datetime && oid != types.T_timestamp || d.TemporalEncoding != "sql_zero_struct") { + return fmt.Errorf("TYPE_CONTRACT: unsupported temporal encoding") + } + + switch oid { + case types.T_bool, types.T_int8, types.T_int16, types.T_int32, types.T_int64, + types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, + types.T_float32, types.T_float64, types.T_json: + if d.Width != 0 || d.Scale != 0 || d.Charset != types.CharsetLegacy { + return fmt.Errorf("TYPE_CONTRACT: descriptor carries unused fields for %s", oid.String()) + } + case types.T_decimal64, types.T_decimal128: + maxPrecision := int32(38) + if oid == types.T_decimal64 { + maxPrecision = 18 + } + if d.Width < 1 || d.Width > maxPrecision { + return fmt.Errorf("TYPE_CONTRACT: decimal precision %d is outside %s range", d.Width, oid.String()) + } + if d.Scale > d.Width { + return fmt.Errorf("TYPE_CONTRACT: decimal scale %d exceeds precision %d", d.Scale, d.Width) + } + if d.Charset != types.CharsetLegacy { + return fmt.Errorf("TYPE_CONTRACT: decimal descriptor carries a charset") + } + case types.T_date: + if d.Scale != 0 || d.Charset != types.CharsetLegacy { + return fmt.Errorf("TYPE_CONTRACT: DATE descriptor has invalid scale or charset") + } + case types.T_time, types.T_datetime, types.T_timestamp: + if d.Scale > 6 || d.Charset != types.CharsetLegacy { + return fmt.Errorf("TYPE_CONTRACT: temporal scale or charset is outside the supported range") + } + case types.T_char, types.T_varchar, types.T_text: + if d.Charset > types.CharsetUTF8 { + return fmt.Errorf("TYPE_CONTRACT: unsupported text charset %d", d.Charset) + } + case types.T_binary, types.T_varbinary, types.T_blob: + if d.Charset != types.CharsetBinary { + return fmt.Errorf("TYPE_CONTRACT: binary descriptor must use the binary charset") + } + case types.T_uuid: + if d.Width != 0 || d.Scale != 0 || d.Charset != types.CharsetLegacy { + return fmt.Errorf("TYPE_CONTRACT: UUID descriptor carries unused fields") + } + case types.T_array_float32, types.T_array_float64: + if d.Width < 1 || d.Width > types.MaxArrayDimension || d.Scale != 0 || d.Charset != types.CharsetLegacy { + return fmt.Errorf("TYPE_CONTRACT: vector dimension or metadata is outside the supported range") + } + default: + return fmt.Errorf("TYPE_CONTRACT: unsupported MatrixOne type id %d", d.TypeID) + } + return nil +} + func (d TypeDescriptor) arrowType() (arrow.DataType, error) { switch types.T(d.TypeID) { case types.T_bool: diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 6b6b9797dedb1..c4b9c5b01570d 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -178,6 +178,19 @@ func TestArrowTypeValidationIncludesFixedBinaryWidth(t *testing.T) { require.ErrorContains(t, descriptor.ValidateField(field), "does not match") } +func TestTypeDescriptorRejectsNonCanonicalDomain(t *testing.T) { + invalid := []TypeDescriptor{ + {TypeID: int32(types.T_varchar), Width: -1, OffsetWidth: 32}, + {TypeID: int32(types.T_int64), OffsetWidth: 64}, + {TypeID: int32(types.T_decimal64), Width: 3, Scale: 4, OffsetWidth: 32}, + {TypeID: int32(types.T_array_float32), Width: types.MaxArrayDimension + 1}, + } + for _, descriptor := range invalid { + _, err := descriptor.Field("value") + require.Error(t, err, "%+v", descriptor) + } +} + func TestArrowValueDomainRejectsDecimalOverflowAndNullableVectorChild(t *testing.T) { decimalType := &arrow.Decimal128Type{Precision: 3, Scale: 0} decimalBuilder := array.NewDecimal128Builder(memory.NewGoAllocator(), decimalType) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 26e1880f74a73..8598ee6e5497e 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -77,6 +77,17 @@ def test_malformed_arrow_payload_is_reported_as_protocol_error(self): with self.assertRaisesRegex(ValueError, "PROTOCOL: execution payload is not a valid Arrow stream"): worker._deserialize_record_batch(b"not-an-arrow-stream") + def test_descriptor_domain_is_strict(self): + invalid = [ + {"type_id": worker.VARCHAR, "width": -1, "offset_width": 32}, + {"type_id": worker.INT64, "offset_width": 64}, + {"type_id": worker.DECIMAL64, "width": 3, "scale": 4, "offset_width": 32}, + {"type_id": worker.VECF32, "width": 65536, "offset_width": 0}, + ] + for descriptor in invalid: + with self.assertRaisesRegex(ValueError, "TYPE_CONTRACT"): + worker._field("value", descriptor) + def test_closing_control_preserves_zero_last_sequence(self): fence = { "account_id": 1, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index d2e3f08771c81..13643c85bc8e1 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -516,6 +516,7 @@ def _canonical_descriptor(descriptor: Dict[str, Any]) -> bytes: for key in _DESCRIPTOR_TEXT_KEYS: if key in descriptor and type(descriptor[key]) is not str: raise ValueError(f"TYPE_CONTRACT: descriptor {key} must be text") + _validate_descriptor_domain(descriptor) order = ("type_id", "width", "scale", "charset", "offset_width", "json_encoding", "temporal_encoding") result = {} for key in order: @@ -525,6 +526,62 @@ def _canonical_descriptor(descriptor: Dict[str, Any]) -> bytes: return json.dumps(result, separators=(",", ":"), ensure_ascii=True).encode("utf-8") +def _validate_descriptor_domain(descriptor: Dict[str, Any]) -> None: + type_id = int(descriptor["type_id"]) + width = int(descriptor.get("width") or 0) + scale = int(descriptor.get("scale") or 0) + charset = int(descriptor.get("charset") or 0) + expected_offset_width = 0 if type_id in (UUID, VECF32, VECF64) else 32 + if width < 0: + raise ValueError("TYPE_CONTRACT: descriptor width must be non-negative") + if scale < 0: + raise ValueError("TYPE_CONTRACT: descriptor scale must be non-negative") + if int(descriptor.get("offset_width") or expected_offset_width) != expected_offset_width: + raise ValueError( + f"TYPE_CONTRACT: descriptor offset_width must be {expected_offset_width}" + ) + json_encoding = descriptor.get("json_encoding") + if json_encoding not in (None, "") and (type_id != JSON or json_encoding != "canonical_text"): + raise ValueError("TYPE_CONTRACT: unsupported JSON encoding") + temporal_encoding = descriptor.get("temporal_encoding") + if temporal_encoding not in (None, "") and ( + type_id not in (DATE, DATETIME, TIMESTAMP) or temporal_encoding != "sql_zero_struct" + ): + raise ValueError("TYPE_CONTRACT: unsupported temporal encoding") + + if type_id in (BOOL, INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64, JSON): + if width or scale or charset: + raise ValueError("TYPE_CONTRACT: descriptor carries unused fields") + elif type_id in (DECIMAL64, DECIMAL128): + maximum = 18 if type_id == DECIMAL64 else 38 + if width < 1 or width > maximum: + raise ValueError("TYPE_CONTRACT: decimal precision is outside the supported range") + if scale > width: + raise ValueError("TYPE_CONTRACT: decimal scale exceeds precision") + if charset: + raise ValueError("TYPE_CONTRACT: decimal descriptor carries a charset") + elif type_id == DATE: + if scale or charset: + raise ValueError("TYPE_CONTRACT: DATE descriptor has invalid scale or charset") + elif type_id in (TIME, DATETIME, TIMESTAMP): + if scale > 6 or charset: + raise ValueError("TYPE_CONTRACT: temporal scale or charset is outside the supported range") + elif type_id in (CHAR, VARCHAR, TEXT): + if charset > 3: + raise ValueError("TYPE_CONTRACT: unsupported text charset") + elif type_id in (BINARY, VARBINARY, BLOB): + if charset != 1: + raise ValueError("TYPE_CONTRACT: binary descriptor must use the binary charset") + elif type_id == UUID: + if width or scale or charset: + raise ValueError("TYPE_CONTRACT: UUID descriptor carries unused fields") + elif type_id in (VECF32, VECF64): + if width < 1 or width > 65535 or scale or charset: + raise ValueError("TYPE_CONTRACT: vector dimension or metadata is outside the supported range") + else: + raise ValueError(f"TYPE_CONTRACT: unsupported type id {type_id}") + + def _physical_fingerprint(descriptor: Dict[str, Any]) -> str: type_id = int(descriptor["type_id"]) primitive = { From 1637ad29cc74364092608ab3d7625f3280b885a0 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:45:07 +0800 Subject: [PATCH 051/241] fix(udf): reject invalid control UTF-8 --- pkg/udf/protocol/protocol.go | 7 +++++++ pkg/udf/protocol/protocol_test.go | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 3f81620765bcc..61bce709bbee7 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -263,6 +263,13 @@ func UnmarshalControl(data []byte) (Control, error) { if len(data) == 0 || len(data) > MaxControlBytes { return Control{}, fmt.Errorf("%w: control size %d is outside the allowed range", ErrProtocol, len(data)) } + // encoding/json replaces invalid UTF-8 in JSON strings with U+FFFD. A + // fencing tuple is an identity, so accepting that replacement would make a + // malformed wire tuple refer to a different invocation than the sender + // intended. Reject the bytes before any JSON decoder can normalize them. + if !utf8.Valid(data) { + return Control{}, fmt.Errorf("%w: control contains invalid UTF-8", ErrProtocol) + } if err := rejectDuplicateJSONKeys(data); err != nil { return Control{}, fmt.Errorf("%w: %v", ErrProtocol, err) } diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index 4052a9fbf91a9..f22aaa2d3073e 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -134,6 +134,15 @@ func TestFencingTupleRejectsInvalidUTF8(t *testing.T) { require.ErrorContains(t, err, "invalid UTF-8") } +func TestUnmarshalControlRejectsInvalidWireUTF8(t *testing.T) { + wire := []byte(`{"version":1,"kind":"InputBatch","tuple":{"account_id":1,"statement_id":"`) + wire = append(wire, 0xff) + wire = append(wire, []byte(`","group_id":"group","group_epoch":2,"invocation_id":"invocation","lease_epoch":3},"sequence":1}`)...) + _, err := UnmarshalControl(wire) + require.ErrorIs(t, err, ErrProtocol) + require.ErrorContains(t, err, "invalid UTF-8") +} + func TestSequenceKeepsHalfCloseIndependentFromResults(t *testing.T) { var sequence Sequence require.NoError(t, sequence.AcceptInput(1)) From 548112a90499884917bcfdaac31ad280c9753eda Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 10 Sep 2026 14:49:23 +0800 Subject: [PATCH 052/241] fix(udf): validate every Python input batch --- pkg/udf/python/worker/test_worker.py | 12 ++++++++++++ pkg/udf/python/worker/worker.py | 14 +++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 8598ee6e5497e..91a2001b97284 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -88,6 +88,18 @@ def test_descriptor_domain_is_strict(self): with self.assertRaisesRegex(ValueError, "TYPE_CONTRACT"): worker._field("value", descriptor) + def test_every_input_batch_keeps_the_frozen_schema(self): + descriptor = {"type_id": worker.INT64, "offset_width": 32} + valid_schema = pa.schema([worker._field("arg_0", descriptor)]) + invalid_batch = pa.RecordBatch.from_arrays( + [pa.array([1], type=pa.int32())], + schema=pa.schema( + [pa.field("arg_0", pa.int32(), nullable=True, metadata=valid_schema.field(0).metadata)] + ), + ) + with self.assertRaisesRegex(ValueError, "Arrow type"): + worker._validate_input_batch_schema(invalid_batch, valid_schema, [descriptor]) + def test_closing_control_preserves_zero_last_sequence(self): fence = { "account_id": 1, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 13643c85bc8e1..1d526313ef063 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -683,6 +683,17 @@ def _validate_schema(schema: pa.Schema, descriptors: Iterable[Dict[str, Any]]) - _validate_field(schema.field(index), f"arg_{index}", descriptor) +def _validate_input_batch_schema( + batch: pa.RecordBatch, expected_schema: pa.Schema, descriptors: Iterable[Dict[str, Any]] +) -> None: + # Flight carries one stream schema, but each received RecordBatch still + # owns a schema object. Validate every batch so a later frame cannot + # replace a fixed-width Arrow type after the first frame was admitted. + _validate_schema(batch.schema, descriptors) + if batch.schema != expected_schema: + raise ValueError("TYPE_CONTRACT: input batch schema changed") + + def _load_handler(source: str, handler: str): namespace: Dict[str, Any] = {"__name__": "__matrixone_routine__"} exec(compile(source, "", "exec"), namespace, namespace) @@ -1424,12 +1435,13 @@ def do_exchange(self, context, descriptor, reader, writer): if schema is None: schema = reader.schema _validate_schema(schema, args) + batch = chunk.data + _validate_input_batch_schema(batch, schema, args) control = _decode_control(chunk.app_metadata) _require_tuple(control["tuple"], open_control["tuple"]) if control["kind"] != "InputBatch": raise ValueError("PROTOCOL: data batch is missing InputBatch") sequence = _required_uint64(control, "sequence") if sequence != state.last_input + 1: raise ValueError("PROTOCOL: input sequence is not contiguous") - batch = chunk.data if batch.num_rows <= 0: raise ValueError("PROTOCOL: empty input batch") if batch.num_rows > max_batch_rows: raise ValueError("RESOURCE_EXHAUSTED: input batch has too many rows") if batch.nbytes > max_batch_bytes: raise ValueError("RESOURCE_EXHAUSTED: input batch exceeds byte limit") From 11a633cecce074e15df2bf6d410fbff671b66be1 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 11 Sep 2026 17:58:24 +0800 Subject: [PATCH 053/241] feat(udf): implement long-term Python UDF execution --- cmd/mo-service/main.go | 25 +- etc/launch-tae-compose/config/cn-0.toml | 2 + etc/launch-tae-compose/config/cn-1.toml | 2 + etc/launch-with-python-udf-worker/cn.toml | 2 + optools/run_bvt.sh | 39 +- .../versions/v4_0_7/tenant_upgrade_list.go | 134 +- pkg/bootstrap/versions/v4_0_7/upgrade_test.go | 105 + pkg/cnservice/server.go | 6 +- pkg/cnservice/types.go | 3 + pkg/cnservice/types_test.go | 26 + pkg/frontend/authenticate.go | 886 ++- pkg/frontend/authenticate_test.go | 24 + pkg/frontend/clone.go | 17 + pkg/frontend/clone_database_source.go | 44 +- pkg/frontend/clone_database_source_test.go | 45 +- pkg/frontend/clone_test.go | 26 +- pkg/frontend/compiler_context.go | 490 +- pkg/frontend/computation_wrapper.go | 5 + pkg/frontend/mysql_cmd_executor.go | 15 +- pkg/frontend/pitr.go | 15 + pkg/frontend/predefined.go | 34 +- pkg/frontend/python_udf_catalog_test.go | 945 +++ pkg/frontend/routine_plan_validation.go | 509 ++ pkg/frontend/routine_plan_validation_test.go | 304 + pkg/frontend/snapshot.go | 16 +- pkg/frontend/snapshot_catalog_restore.go | 405 +- pkg/frontend/snapshot_restore_with_ts.go | 11 + pkg/frontend/snapshot_test.go | 121 +- pkg/pb/plan/collation_admission.pb.go | 19 + pkg/pb/plan/plan.pb.go | 6116 +++++++++++++---- pkg/sql/colexec/evalExpression.go | 30 +- pkg/sql/colexec/external_routine_eval.go | 704 ++ pkg/sql/colexec/external_routine_eval_test.go | 368 + pkg/sql/plan/base_binder.go | 90 +- pkg/sql/plan/deepcopy.go | 11 + pkg/sql/plan/deepcopy_test.go | 19 + pkg/sql/plan/expr_hash.go | 29 + pkg/sql/plan/expr_hash_test.go | 36 + pkg/sql/plan/function/function.go | 2 +- pkg/sql/plan/function/list_builtIn.go | 2 +- pkg/sql/plan/function/python_udf.go | 273 +- pkg/sql/plan/function/udf.go | 379 +- pkg/sql/plan/function/udf_test.go | 320 +- pkg/sql/plan/returning.go | 3 + pkg/sql/plan/routine_dependency.go | 105 + pkg/sql/plan/routine_dependency_test.go | 120 + pkg/sql/plan/rule/constant_fold.go | 6 + pkg/sql/plan/rule/constant_fold_test.go | 23 + pkg/sql/plan/types.go | 20 +- pkg/sql/plan/utils.go | 5 + pkg/udf/protocol/protocol.go | 185 +- pkg/udf/protocol/protocol_test.go | 83 +- pkg/udf/python/arrow.go | 55 +- pkg/udf/python/arrow_test.go | 273 + pkg/udf/python/artifact.go | 190 + pkg/udf/python/artifact_test.go | 97 + pkg/udf/python/config.go | 50 +- pkg/udf/python/config_test.go | 25 + pkg/udf/python/definition.go | 78 + pkg/udf/python/definition_test.go | 51 + pkg/udf/python/gateway.go | 968 ++- pkg/udf/python/gateway_admission_test.go | 200 + pkg/udf/python/gateway_benchmark_test.go | 118 + pkg/udf/python/gateway_integration_test.go | 631 ++ pkg/udf/python/gateway_test.go | 304 +- pkg/udf/python/supervisor.go | 41 +- pkg/udf/python/supervisor_test.go | 60 +- pkg/udf/python/testdata/type_descriptors.json | 29 + pkg/udf/python/worker/test_worker.py | 2156 +++++- pkg/udf/python/worker/worker.py | 1897 ++++- pkg/udf/python_contract.go | 86 + pkg/udf/python_contract_test.go | 28 + pkg/udf/runtime.go | 224 +- pkg/udf/runtime_test.go | 70 + pkg/udf/timezone.go | 47 + proto/plan.proto | 89 + test/distributed/cases/udf_python/README.md | 8 + .../cases/udf_python/dml_error_paths.result | 30 + .../cases/udf_python/dml_error_paths.sql | 31 + .../cases/udf_python/dml_positions.result | 17 + .../cases/udf_python/dml_positions.sql | 25 + .../udf_python/relational_positions.result | 59 + .../cases/udf_python/relational_positions.sql | 54 + .../udf_python/revision_lifecycle.result | 35 + .../cases/udf_python/revision_lifecycle.sql | 20 + 85 files changed, 18941 insertions(+), 2309 deletions(-) create mode 100644 pkg/bootstrap/versions/v4_0_7/upgrade_test.go create mode 100644 pkg/frontend/python_udf_catalog_test.go create mode 100644 pkg/frontend/routine_plan_validation.go create mode 100644 pkg/frontend/routine_plan_validation_test.go create mode 100644 pkg/sql/colexec/external_routine_eval.go create mode 100644 pkg/sql/colexec/external_routine_eval_test.go create mode 100644 pkg/sql/plan/routine_dependency.go create mode 100644 pkg/sql/plan/routine_dependency_test.go create mode 100644 pkg/udf/python/artifact.go create mode 100644 pkg/udf/python/artifact_test.go create mode 100644 pkg/udf/python/definition.go create mode 100644 pkg/udf/python/definition_test.go create mode 100644 pkg/udf/python/gateway_admission_test.go create mode 100644 pkg/udf/python/gateway_benchmark_test.go create mode 100644 pkg/udf/python/gateway_integration_test.go create mode 100644 pkg/udf/python/testdata/type_descriptors.json create mode 100644 pkg/udf/python_contract.go create mode 100644 pkg/udf/python_contract_test.go create mode 100644 pkg/udf/timezone.go create mode 100644 test/distributed/cases/udf_python/dml_error_paths.result create mode 100644 test/distributed/cases/udf_python/dml_error_paths.sql create mode 100644 test/distributed/cases/udf_python/dml_positions.result create mode 100644 test/distributed/cases/udf_python/dml_positions.sql create mode 100644 test/distributed/cases/udf_python/relational_positions.result create mode 100644 test/distributed/cases/udf_python/relational_positions.sql create mode 100644 test/distributed/cases/udf_python/revision_lifecycle.result create mode 100644 test/distributed/cases/udf_python/revision_lifecycle.sql diff --git a/cmd/mo-service/main.go b/cmd/mo-service/main.go index 65ad565a9af6a..c6bb1423f32ce 100644 --- a/cmd/mo-service/main.go +++ b/cmd/mo-service/main.go @@ -767,10 +767,27 @@ func startPythonUdfWorker(cfg *Config, stopper *stopper.Stopper) error { if err := s.Start(); err != nil { panic(err) } - <-roleCtx.Done() - if err := s.Close(); err != nil { - closeErr = err - logutil.GetGlobalLogger().Error("failed to close Python UDF worker", zap.Error(err)) + workerDone := s.Done() + select { + case <-roleCtx.Done(): + if err := s.Close(); err != nil { + closeErr = err + logutil.GetGlobalLogger().Error("failed to close Python UDF worker", zap.Error(err)) + } + case <-workerDone: + // A worker exit while the role is still running leaves CN with a + // configured but unusable Python runtime. Surface it as a fatal + // service event so the existing lifecycle supervisor drains CN + // before the worker dependency and does not accept partial service + // availability. A zero exit is still unexpected here. + if roleCtx.Err() == nil { + workerErr := s.Err() + if workerErr == nil { + workerErr = errors.New("process exited without an error") + } + closeErr = fmt.Errorf("Python UDF worker exited unexpectedly: %w", workerErr) + serviceLifecycle.notifyFatal(closeErr) + } } }) if err != nil { diff --git a/etc/launch-tae-compose/config/cn-0.toml b/etc/launch-tae-compose/config/cn-0.toml index d75de7326e2f2..0ea0b00c0449d 100644 --- a/etc/launch-tae-compose/config/cn-0.toml +++ b/etc/launch-tae-compose/config/cn-0.toml @@ -71,3 +71,5 @@ enable-maintenance = true enabled = true allow-unisolated = true server-address = "python-udf-worker-cn0:50051" +max-invocation-rows = 1048576 +max-invocation-result-bytes = 268435456 diff --git a/etc/launch-tae-compose/config/cn-1.toml b/etc/launch-tae-compose/config/cn-1.toml index 479e8784e4c1d..372d105e7869b 100644 --- a/etc/launch-tae-compose/config/cn-1.toml +++ b/etc/launch-tae-compose/config/cn-1.toml @@ -71,3 +71,5 @@ enable-maintenance = true enabled = true allow-unisolated = true server-address = "python-udf-worker-cn1:50051" +max-invocation-rows = 1048576 +max-invocation-result-bytes = 268435456 diff --git a/etc/launch-with-python-udf-worker/cn.toml b/etc/launch-with-python-udf-worker/cn.toml index cf5b576cbc864..76ae8790bf7b5 100644 --- a/etc/launch-with-python-udf-worker/cn.toml +++ b/etc/launch-with-python-udf-worker/cn.toml @@ -12,3 +12,5 @@ port-base = 18000 enabled = true allow-unisolated = true server-address = "127.0.0.1:50051" +max-invocation-rows = 1048576 +max-invocation-result-bytes = 268435456 diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index 0929047397241..ed1d3f19f8cf5 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -19,17 +19,20 @@ set -o nounset MO_WORKSPACE=$1 LAUNCH=$2 PROXY=${3:-} +LAUNCH_CONFIG=$LAUNCH +MO_PID="" function launch_mo() { cd $MO_WORKSPACE # Ordinary launch BVT remains the single CI entry point, but its Python # cases opt into the worker-enabled manifest explicitly. The generic # etc/launch manifest stays safe for users who start mo-service directly. - local launch_config=$LAUNCH + LAUNCH_CONFIG=$LAUNCH if [[ "$LAUNCH" == "launch" ]]; then - launch_config=launch-with-python-udf-worker + LAUNCH_CONFIG=launch-with-python-udf-worker fi - ./mo-service -debug-http=:12345 -launch ./etc/$launch_config/launch.toml $PROXY &>mo-service.log & + ./mo-service -debug-http=:12345 -launch ./etc/$LAUNCH_CONFIG/launch.toml $PROXY &>mo-service.log & + MO_PID=$! } # this will wait mo all system init completed @@ -45,6 +48,32 @@ function wait_system_init() { return 1 } +# MySQL readiness only proves that the CN frontend accepted connections. The +# worker is a separately started service, so Python UDF DDL/execution can still +# race its Flight listener. Keep this in the existing BVT launcher instead of +# adding a second CI job or making every SQL case retry its first call. +function wait_python_udf_worker() { + if [[ "$LAUNCH_CONFIG" != "launch-with-python-udf-worker" ]]; then + return 0 + fi + for num in {1..120} + do + if [[ -n "$MO_PID" ]] && ! kill -0 "$MO_PID" 2>/dev/null; then + echo "MatrixOne exited before Python UDF worker became ready" >&2 + tail -n 160 mo-service.log >&2 || true + return 1 + fi + if bash -c 'exec 3<>/dev/tcp/127.0.0.1/50051' 2>/dev/null; then + echo "Python UDF worker is ready, cost $num seconds" + return 0 + fi + sleep 1 + done + echo "Python UDF worker did not become ready on 127.0.0.1:50051" >&2 + tail -n 160 mo-service.log >&2 || true + return 1 +} + # Start the jstfu datastream server (xtool/jstfu) that # test/distributed/cases/datastream talks to on 127.0.0.1:4444. In this # launch deployment MO runs on the host, so a host jstfu is reachable from @@ -85,4 +114,8 @@ else launch_jstfu || exit $? fi wait_system_init +if [[ "$?" -ne 0 ]]; then + exit 1 +fi +wait_python_udf_worker exit $? diff --git a/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go b/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go index daf506c2bc0ba..b74bda45cab1c 100644 --- a/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go +++ b/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go @@ -18,7 +18,10 @@ import ( "fmt" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/catalog" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/runtime" + "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/defines" "github.com/matrixorigin/matrixone/pkg/util/executor" "github.com/matrixorigin/matrixone/pkg/util/sysview" @@ -28,9 +31,134 @@ import ( // only known at runtime (one metadata table per index, per account), which a fixed UpgSql // cannot express. It runs from HandleTenantUpgrade, the same escape hatch v4_0_6 uses for // upgradeLegacyForeignKeyMetadata. -// Keep the released v4.0.7 offset at zero. New catalog repairs belong to -// maintenance, not to an already-persisted historical upgrade identity. -var tenantUpgEntries = []versions.UpgradeEntry{} +var tenantUpgEntries = []versions.UpgradeEntry{ + addPythonRevisionHeadColumn("active_revision", "bigint unsigned not null default 0"), + addPythonRevisionHeadColumn("namespace_version", "bigint unsigned not null default 0"), + addPythonSignatureColumn("canonical_input_descriptor", fmt.Sprintf("varchar(%d) not null default ''", types.MaxStringSize), "arg_types"), + addPythonSignatureColumn("return_descriptor", fmt.Sprintf("varchar(%d) not null default ''", types.MaxStringSize), "canonical_input_descriptor"), + addPythonSignatureColumn("signature_key_schema_version", "int not null default 0", "return_descriptor"), + addPythonSignatureColumn("signature_fingerprint", "varchar(128) not null default ''", "signature_key_schema_version"), + addPythonSignatureIndex(), + dropLegacyPythonSignatureIndex(), + { + Schema: catalog.MO_CATALOG, + TableName: "mo_function_revisions", + UpgType: versions.CREATE_NEW_TABLE, + UpgSql: fmt.Sprintf(`create table mo_catalog.mo_function_revisions ( + function_id bigint unsigned not null, + revision bigint unsigned not null, + namespace_version bigint unsigned not null, + name varchar(100) not null, + args json not null, + arg_types varchar(%d) not null default '', + rettype varchar(20) not null, + body text not null, + language varchar(20) not null, + definition_schema_version int not null default 0, + abi_contract varchar(64) not null default '', + adapter_version varchar(64) not null default '', + artifact_digest varchar(128) not null default '', + environment_digest varchar(128) not null default '', + sdk_version varchar(64) not null default '', + null_policy varchar(64) not null default '', + volatility varchar(20) not null default 'VOLATILE', + definition_fingerprint varchar(128) not null default '', + created_time timestamp, + security_type varchar(10) not null default 'DEFINER', + primary key(function_id, revision) + )`, types.MaxStringSize), + RequiredProtocolVersion: defines.MORPCVersion48, + CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { + return versions.CheckTableDefinition(txn, accountID, catalog.MO_CATALOG, "mo_function_revisions") + }, + }, +} + +// addPythonSignatureIndex makes the shared function namespace distinguish the +// exact current Python descriptor while preserving the historical logical +// arg_types column for SQL UDFs and catalog readers. +func addPythonSignatureIndex() versions.UpgradeEntry { + return versions.UpgradeEntry{ + Schema: catalog.MO_CATALOG, + TableName: "mo_user_defined_function", + UpgType: versions.ADD_INDEX, + UpgSql: "create unique index name_db_arg_types_descriptor on mo_catalog.mo_user_defined_function(name, db, arg_types, canonical_input_descriptor)", + RequiredProtocolVersion: defines.MORPCVersion48, + CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { + return versions.CheckIndexDefinition( + txn, accountID, catalog.MO_CATALOG, "mo_user_defined_function", "name_db_arg_types_descriptor", + ) + }, + } +} + +func dropLegacyPythonSignatureIndex() versions.UpgradeEntry { + return versions.UpgradeEntry{ + Schema: catalog.MO_CATALOG, + TableName: "mo_user_defined_function", + UpgType: versions.DROP_INDEX, + UpgSql: "alter table mo_catalog.mo_user_defined_function drop index name_db_arg_types", + RequiredProtocolVersion: defines.MORPCVersion48, + CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { + exists, err := versions.CheckIndexDefinition( + txn, accountID, catalog.MO_CATALOG, "mo_user_defined_function", "name_db_arg_types", + ) + return !exists, err + }, + } +} + +func addPythonRevisionHeadColumn(name, definition string) versions.UpgradeEntry { + return versions.UpgradeEntry{ + Schema: catalog.MO_CATALOG, + TableName: "mo_user_defined_function", + UpgType: versions.ADD_COLUMN, + UpgSql: fmt.Sprintf( + "alter table mo_catalog.mo_user_defined_function add column %s %s after function_id", + name, definition, + ), + RequiredProtocolVersion: defines.MORPCVersion48, + CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { + column, err := versions.CheckTableColumn(txn, accountID, catalog.MO_CATALOG, "mo_user_defined_function", name) + if err != nil { + return false, err + } + if !column.IsExits { + return false, nil + } + if column.ColType == "" { + return false, moerr.NewInternalErrorNoCtxf("catalog column %s has no type", name) + } + return true, nil + }, + } +} + +func addPythonSignatureColumn(name, definition, after string) versions.UpgradeEntry { + return versions.UpgradeEntry{ + Schema: catalog.MO_CATALOG, + TableName: "mo_user_defined_function", + UpgType: versions.ADD_COLUMN, + UpgSql: fmt.Sprintf( + "alter table mo_catalog.mo_user_defined_function add column %s %s after %s", + name, definition, after, + ), + RequiredProtocolVersion: defines.MORPCVersion48, + CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { + column, err := versions.CheckTableColumn(txn, accountID, catalog.MO_CATALOG, "mo_user_defined_function", name) + if err != nil { + return false, err + } + if !column.IsExits { + return false, nil + } + if column.ColType == "" { + return false, moerr.NewInternalErrorNoCtxf("catalog column %s has no type", name) + } + return true, nil + }, + } +} // UpgradeInformationSchemaViewsAfterProtocolCheck replaces VIEWS for the // bounded maintenance owner, independently of the historical upgrade list. diff --git a/pkg/bootstrap/versions/v4_0_7/upgrade_test.go b/pkg/bootstrap/versions/v4_0_7/upgrade_test.go new file mode 100644 index 0000000000000..cb15460b65457 --- /dev/null +++ b/pkg/bootstrap/versions/v4_0_7/upgrade_test.go @@ -0,0 +1,105 @@ +// Copyright 2026 Matrix Origin +// +// 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 v4_0_7 + +import ( + "strings" + "testing" + + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/catalog" + "github.com/matrixorigin/matrixone/pkg/defines" +) + +func TestPythonFunctionRevisionUpgradeContract(t *testing.T) { + metadata := Handler.Metadata() + if metadata.Version != "4.0.7" || metadata.MinUpgradeVersion != "4.0.6" { + t.Fatalf("unexpected version metadata: %+v", metadata) + } + if metadata.UpgradeCluster != versions.No || metadata.UpgradeTenant != versions.Yes { + t.Fatalf("python catalog upgrade must be tenant scoped: %+v", metadata) + } + if metadata.VersionOffset != uint32(len(tenantUpgEntries)) { + t.Fatalf("version offset %d does not match tenant entries %d", metadata.VersionOffset, len(tenantUpgEntries)) + } + if metadata.RequiredProtocolVersion != defines.MORPCVersion48 { + t.Fatalf("unexpected protocol gate: %v", metadata.RequiredProtocolVersion) + } + + if len(tenantUpgEntries) != 9 { + t.Fatalf("expected six UDF identity columns, index replacement, and one revision table, got %d entries", len(tenantUpgEntries)) + } + for _, name := range []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + } { + var found bool + for _, entry := range tenantUpgEntries { + if entry.TableName == "mo_user_defined_function" && strings.Contains(strings.ToLower(entry.UpgSql), "add column "+name) { + found = true + if entry.UpgType != versions.ADD_COLUMN || entry.Schema != catalog.MO_CATALOG { + t.Fatalf("unexpected upgrade entry for %s: %+v", name, entry) + } + break + } + } + if !found { + t.Fatalf("missing mo_user_defined_function.%s upgrade", name) + } + } + + var addIndex, dropIndex, revision *versions.UpgradeEntry + for i := range tenantUpgEntries { + entry := &tenantUpgEntries[i] + lower := strings.ToLower(entry.UpgSql) + switch { + case strings.Contains(lower, "name_db_arg_types_descriptor"): + addIndex = entry + case strings.Contains(lower, "drop index name_db_arg_types"): + dropIndex = entry + case entry.TableName == "mo_function_revisions": + revision = entry + } + } + if addIndex == nil || addIndex.UpgType != versions.ADD_INDEX || addIndex.RequiredProtocolVersion != defines.MORPCVersion48 { + t.Fatalf("missing current Python signature index upgrade: %+v", addIndex) + } + if !strings.Contains(strings.ToLower(addIndex.UpgSql), "canonical_input_descriptor") { + t.Fatalf("current Python signature index omits exact descriptor: %s", addIndex.UpgSql) + } + if dropIndex == nil || dropIndex.UpgType != versions.DROP_INDEX || dropIndex.RequiredProtocolVersion != defines.MORPCVersion48 { + t.Fatalf("missing legacy signature index removal: %+v", dropIndex) + } + if revision == nil { + t.Fatal("missing Python revision table upgrade") + } + if revision.Schema != catalog.MO_CATALOG || revision.TableName != "mo_function_revisions" { + t.Fatalf("unexpected revision catalog identity: %+v", revision) + } + if revision.UpgType != versions.CREATE_NEW_TABLE || revision.RequiredProtocolVersion != defines.MORPCVersion48 { + t.Fatalf("unexpected revision catalog upgrade: %+v", revision) + } + lowerDDL := strings.ToLower(revision.UpgSql) + for _, column := range []string{ + "function_id", "revision", "namespace_version", "arg_types", + "definition_schema_version", "abi_contract", "adapter_version", + "artifact_digest", "environment_digest", "sdk_version", "null_policy", + "volatility", "definition_fingerprint", "primary key(function_id, revision)", + } { + if !strings.Contains(lowerDDL, column) { + t.Fatalf("revision catalog DDL missing %q: %s", column, revision.UpgSql) + } + } +} diff --git a/pkg/cnservice/server.go b/pkg/cnservice/server.go index a89fa371adcbc..93156c000f6ef 100644 --- a/pkg/cnservice/server.go +++ b/pkg/cnservice/server.go @@ -255,8 +255,12 @@ func NewService( var udfServices []udf.Runtime // add python client to handle python udf if srv.cfg.PythonUdfClient.Enabled { + artifactStore, storeErr := python.NewFileArtifactStore(srv.fileService, python.DefaultMaxArtifactBytes) + if storeErr != nil { + panic(storeErr) + } var pc *python.Gateway - pc, err = python.NewGateway(srv.cfg.PythonUdfClient) + pc, err = python.NewGatewayWithArtifactStore(srv.cfg.PythonUdfClient, artifactStore) if err != nil { return nil, err } diff --git a/pkg/cnservice/types.go b/pkg/cnservice/types.go index b2a4706efa922..21f422fd5d622 100644 --- a/pkg/cnservice/types.go +++ b/pkg/cnservice/types.go @@ -483,6 +483,9 @@ func (c *Config) Validate() error { if err := c.Sirius.validate(); err != nil { return err } + if err := c.PythonUdfClient.Validate(); err != nil { + return err + } if !metadata.ValidStateString(c.InitWorkState) { c.InitWorkState = metadata.WorkState_Working.String() diff --git a/pkg/cnservice/types_test.go b/pkg/cnservice/types_test.go index 4e589789fd00e..6e99eaa944b83 100644 --- a/pkg/cnservice/types_test.go +++ b/pkg/cnservice/types_test.go @@ -20,7 +20,9 @@ import ( "time" "github.com/matrixorigin/matrixone/pkg/common/moerr" + moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/matrixorigin/matrixone/pkg/logservice" + "github.com/matrixorigin/matrixone/pkg/pb/metadata" "github.com/stretchr/testify/require" ) @@ -60,3 +62,27 @@ func TestValidateServiceUUID(t *testing.T) { } require.NoError(t, validateCNServiceUUID(strings.Repeat("é", 63)+"x")) } + +func TestValidatePythonUdfClientContract(t *testing.T) { + service := "python-udf-config-" + t.Name() + rt := moruntime.NewRuntime(metadata.ServiceType_CN, service, nil) + moruntime.SetupServiceBasedRuntime(service, rt) + + disabled := Config{UUID: service} + require.NoError(t, disabled.Validate()) + + requiresOptIn := Config{UUID: service} + requiresOptIn.PythonUdfClient.Enabled = true + require.ErrorContains(t, requiresOptIn.Validate(), "allow-unisolated") + + requiresAddress := Config{UUID: service} + requiresAddress.PythonUdfClient.Enabled = true + requiresAddress.PythonUdfClient.AllowUnisolated = true + require.ErrorContains(t, requiresAddress.Validate(), "missing python udf address") + + valid := Config{UUID: service} + valid.PythonUdfClient.Enabled = true + valid.PythonUdfClient.AllowUnisolated = true + valid.PythonUdfClient.ServerAddress = "127.0.0.1:50051" + require.NoError(t, valid.Validate()) +} diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index da2fc6f2223c1..5aeb8e0f6bbcc 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -69,6 +69,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/stage/stageutil" "github.com/matrixorigin/matrixone/pkg/taskservice" "github.com/matrixorigin/matrixone/pkg/udf" + pythonudf "github.com/matrixorigin/matrixone/pkg/udf/python" "github.com/matrixorigin/matrixone/pkg/util/fault" "github.com/matrixorigin/matrixone/pkg/util/metric/mometric" v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2" @@ -939,6 +940,7 @@ var ( "mo_role_grant": 0, "mo_role_privs": 0, "mo_user_defined_function": 0, + "mo_function_revisions": 0, "mo_stored_procedure": 0, "mo_mysql_compatibility_mode": 0, catalog.MODatabaseDefaults: 0, @@ -981,6 +983,7 @@ var ( "mo_role_grant": 0, "mo_role_privs": 0, "mo_user_defined_function": 0, + "mo_function_revisions": 0, "mo_stored_procedure": 0, "mo_mysql_compatibility_mode": 0, catalog.MODatabaseDefaults: 0, @@ -1043,6 +1046,7 @@ var ( MoCatalogMoRoleGrantDDL, MoCatalogMoRolePrivsDDL, MoCatalogMoUserDefinedFunctionDDL, + MoCatalogMoFunctionRevisionDDL, MoCatalogMoMysqlCompatibilityModeDDL, catalog.MoDatabaseDefaultsDDL, MoCatalogMoSnapshotsDDL, @@ -1096,6 +1100,7 @@ var ( `drop table if exists mo_catalog.mo_role_grant;`, `drop table if exists mo_catalog.mo_role_privs;`, `drop table if exists mo_catalog.mo_user_defined_function;`, + `drop table if exists mo_catalog.mo_function_revisions;`, `drop table if exists mo_catalog.mo_stored_procedure;`, `drop table if exists mo_catalog.mo_stages;`, `drop view if exists mo_catalog.mo_sessions;`, @@ -1145,6 +1150,34 @@ var ( comment) values ('%s','%s', '%s', '%s','%s', '%s');` initMoUserDefinedFunctionFormat = `insert into mo_catalog.mo_user_defined_function( + name, + owner, + args, + arg_types, + canonical_input_descriptor, + return_descriptor, + signature_key_schema_version, + signature_fingerprint, + retType, + body, + language, + db, + definer, + modified_time, + created_time, + type, + security_type, + comment, + character_set_client, + collation_connection, + database_collation, + sql_mode) values ("%s",%d,'%s','%s',"%s","%s",%d,"%s","%s","%s","%s","%s","%s","%s","%s","%s","%s","%s","%s","%s","%s","%s");` + + // SQL UDF creation keeps the pre-Python catalog write shape. During a + // rolling upgrade an ordinary SQL writer may still target a catalog that + // has not received the Python identity columns. Python creation is gated on + // the current catalog contract and uses initMoUserDefinedFunctionFormat. + initMoUserDefinedFunctionSQLFormat = `insert into mo_catalog.mo_user_defined_function( name, owner, args, @@ -1561,7 +1594,22 @@ const ( checkUdfWithDb = `select function_id,body from mo_catalog.mo_user_defined_function where db = "%s" order by function_id;` - checkUdfExistence = `select function_id from mo_catalog.mo_user_defined_function where name = "%s" and db = "%s" and arg_types = %s order by function_id;` + // SQL keeps this query on columns that existed before the Python identity + // fields. That lets ordinary SQL UDF creation continue during a rolling + // catalog upgrade while the Python path uses the current exact-descriptor + // query below after its readiness gate succeeds. + checkUdfExistence = `select function_id, args, language, arg_types from mo_catalog.mo_user_defined_function where name = "%s" and db = "%s" order by function_id;` + checkPythonUdfExistence = `select function_id, args, language, arg_types, canonical_input_descriptor from mo_catalog.mo_user_defined_function where name = "%s" and db = "%s" order by function_id;` + + // These schema probes are the write gate for the current Python catalog + // contract. They deliberately reference every column used by the Python + // writer. COUNT keeps one result row even when the catalog is empty; a + // literal LIMIT 0 is optimized away by BackgroundExec and does not expose a + // result-set schema. A frontend in a rolling upgrade must reject Python + // publication before it creates or changes a routine when the tenant has + // not reached this schema. + pythonUdfCatalogIdentitySchemaCheck = `select count(active_revision), count(namespace_version), count(canonical_input_descriptor), count(return_descriptor), count(signature_key_schema_version), count(signature_fingerprint) from mo_catalog.mo_user_defined_function;` + functionRevisionCatalogSchemaCheck = `select count(function_id), count(revision), count(namespace_version), count(name), count(args), count(arg_types), count(rettype), count(body), count(language), count(definition_schema_version), count(abi_contract), count(adapter_version), count(artifact_digest), count(environment_digest), count(sdk_version), count(null_policy), count(volatility), count(definition_fingerprint), count(created_time), count(security_type) from mo_catalog.mo_function_revisions;` checkStoredProcedureArgs = `select proc_id, args from mo_catalog.mo_stored_procedure where name = "%s" and db = "%s" order by proc_id;` @@ -1607,7 +1655,8 @@ const ( deleteUserFromMoUserGrantFormat = `delete from mo_catalog.mo_user_grant where user_id = %d;` // delete user defined function from mo_user_defined_function - deleteUserDefinedFunctionFormat = `delete from mo_catalog.mo_user_defined_function where function_id = %d;` + deleteUserDefinedFunctionFormat = `delete from mo_catalog.mo_user_defined_function where function_id = %d;` + deleteUserDefinedFunctionRevisionsFormat = `delete from mo_catalog.mo_function_revisions where function_id = %d;` // delete stored procedure from mo_user_defined_function deleteStoredProcedureFormat = `delete from mo_catalog.mo_stored_procedure where proc_id = %d;` @@ -1686,6 +1735,24 @@ var ( } ) +// deleteUserDefinedFunctionRevisionsIfPresent removes the immutable Python +// revisions belonging to a function identity. The revision table was added by +// the current catalog upgrade and is not part of the legacy SQL UDF contract. +// A mixed-version tenant must therefore still be able to drop an ordinary SQL +// UDF while that table is absent. Once the table exists, every error other than +// the explicit missing-table condition is returned so a failed revision +// cleanup cannot be hidden by deleting the identity row. +func deleteUserDefinedFunctionRevisionsIfPresent(ctx context.Context, bh BackgroundExec, functionID int64) error { + err := bh.Exec(ctx, fmt.Sprintf(deleteUserDefinedFunctionRevisionsFormat, functionID)) + if err == nil { + return nil + } + if moerr.IsMoErrCode(err, moerr.ErrNoSuchTable) || strings.Contains(strings.ToLower(err.Error()), "no such table") { + return nil + } + return err +} + func init() { tables := make([]string, 0, len(predefinedTables)) for tbl := range predefinedTables { @@ -5012,6 +5079,16 @@ func doDropFunction(ctx context.Context, ses *Session, df *tree.DropFunction, rm if !match { continue } + // The historical args column intentionally stores only logical + // type names. A current Python body carries the exact Arrow + // descriptors, so use those descriptors when selecting an + // overload for DROP. Otherwise two DECIMAL or bounded string + // overloads would be indistinguishable and DROP could remove the + // wrong immutable identity. A non-current body is left on the + // logical path so an old demo can still be explicitly removed. + if !pythonDropSignatureMatches(df.Args, argstr) { + continue + } handleArgMatch := func() (rtnErr error) { sql = fmt.Sprintf(deleteUserDefinedFunctionFormat, funcId) @@ -5019,6 +5096,10 @@ func doDropFunction(ctx context.Context, ses *Session, df *tree.DropFunction, rm if rtnErr != nil { return rtnErr } + rtnErr = deleteUserDefinedFunctionRevisionsIfPresent(ctx, bh, funcId) + if rtnErr != nil { + return rtnErr + } return rtnErr } err = handleArgMatch() @@ -5039,6 +5120,36 @@ func doDropFunction(ctx context.Context, ses *Session, df *tree.DropFunction, rm return moerr.NewNoUDFNoCtx(string(df.Name.Name.ObjectName)) } +// pythonDropSignatureMatches recognizes the current Python catalog body and +// compares its exact Arrow input descriptors with a DROP declaration. A +// body that is not the current Python contract returns true so the caller can +// retain the historical logical matching needed to explicitly remove an old +// demo definition; such a body is never admitted for execution. +func pythonDropSignatureMatches(args tree.FunctionArgs, rawBody string) bool { + body, err := function.DecodePythonRoutineBody(rawBody) + if err != nil { + return true + } + if len(body.ArgTypes) != len(args) { + return false + } + for index, arg := range args { + argDecl, ok := arg.(*tree.FunctionArgDecl) + if !ok || argDecl == nil { + return false + } + typ, err := plan2.GetFunctionTypeFromAst(argDecl.Type) + if err != nil { + return false + } + descriptor, err := function.NewPythonTypeDescriptor(typ) + if err != nil || descriptor != body.ArgTypes[index] { + return false + } + } + return true +} + func doDropFunctionWithDB(ctx context.Context, ses *Session, stmt tree.Statement, rm rmPkg) (err error) { var sql string var funcId int64 @@ -5088,6 +5199,10 @@ func doDropFunctionWithDB(ctx context.Context, ses *Session, stmt tree.Statement if rtnErr != nil { return rtnErr } + rtnErr = deleteUserDefinedFunctionRevisionsIfPresent(ctx, bh, funcId) + if rtnErr != nil { + return rtnErr + } return rtnErr } @@ -11669,19 +11784,127 @@ func Upload(ses FeSession, execCtx *ExecCtx, localPath string, storageDir string return ioVector.FilePath, nil } +func ensurePythonUdfCatalogReady(ctx context.Context, bh BackgroundExec) error { + probes := []struct { + query string + expectedCols uint64 + }{ + {query: pythonUdfCatalogIdentitySchemaCheck, expectedCols: 6}, + {query: functionRevisionCatalogSchemaCheck, expectedCols: 20}, + } + for _, probe := range probes { + query := probe.query + bh.ClearExecResultSet() + if err := bh.Exec(ctx, query); err != nil { + return moerr.NewNotSupportedNoCtxf( + "Python UDF catalog contract is not ready; upgrade the tenant before creating or replacing Python UDFs: %v", + err, + ) + } + results, err := getResultSet(ctx, bh) + if err != nil { + return moerr.NewNotSupportedNoCtxf( + "Python UDF catalog contract is not ready; catalog probe returned an invalid result: %v", + err, + ) + } + result, resultErr := exactlyOneCatalogRow(ctx, results, "Python UDF catalog schema probe") + if resultErr != nil { + return moerr.NewNotSupportedNoCtxf( + "Python UDF catalog contract is not ready; catalog probe returned an invalid shape: %v", + resultErr, + ) + } + if result.GetColumnCount() != probe.expectedCols { + return moerr.NewNotSupportedNoCtxf( + "Python UDF catalog contract is not ready; catalog probe returned %d columns, expected %d", + result.GetColumnCount(), probe.expectedCols, + ) + } + } + return nil +} + +// functionRevisionCatalogAvailable reports whether the current shared +// revision table can be used by the SQL UDF writer. Ordinary SQL UDFs remain +// writable during a rolling upgrade before v4_0_7 reaches every tenant; once +// the table is present, revision publication is part of the same caller-owned +// transaction as the legacy compatibility row. +func functionRevisionCatalogAvailable(ctx context.Context, bh BackgroundExec) (bool, error) { + bh.ClearExecResultSet() + if err := bh.Exec(ctx, functionRevisionCatalogSchemaCheck); err != nil { + if isMissingCatalogObjectError(err) { + return false, nil + } + return false, err + } + // The aggregate probe must return one row. Anything else indicates a broken + // executor/result contract and must reach the caller; only an explicitly + // missing catalog object is a supported rolling-upgrade path. + results, err := getResultSet(ctx, bh) + if err != nil { + return false, err + } + if _, err := exactlyOneCatalogRow(ctx, results, "function revision catalog schema probe"); err != nil { + return false, err + } + return true, nil +} + +func isMissingCatalogObjectError(err error) bool { + if err == nil { + return false + } + message := strings.ToLower(err.Error()) + return moerr.IsMoErrCode(err, moerr.ErrNoSuchTable) || + strings.Contains(message, "no such table") || + strings.Contains(message, "table does not exist") || + strings.Contains(message, "unknown column") +} + +func ensurePythonUdfRuntimeReady(ctx context.Context, ses *Session) error { + pu := getPuIfPresent(ses.GetService()) + if pu == nil || pu.UdfService == nil { + return moerr.NewNotSupportedNoCtx("Python UDF feature is disabled") + } + readiness, ok := pu.UdfService.(udf.RuntimeReadiness) + if !ok { + return moerr.NewNotSupportedNoCtx("Python UDF runtime does not expose the current contract") + } + return readiness.CheckLanguageReady(ctx, udf.LanguagePython) +} + +// canonicalPythonInputDescriptor is the shared overload key used by the +// catalog lookup and by the immutable revision metadata. Keeping this +// conversion at the create boundary prevents the logical SQL OID list from +// accidentally being used to match width/scale-sensitive Python signatures. +func canonicalPythonInputDescriptor( + args []function.PythonTypeDescriptor, + returnType *function.PythonTypeDescriptor, +) (string, error) { + inputDescriptor, _, _, err := function.PythonSignatureMetadata(args, returnType) + return inputDescriptor, err +} + func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.CreateFunction) (err error) { var retTypeStr string var dbName string var dbExists bool var checkExistence string var argsJson []byte - var argsCondition string + var logicalArgTypes string + var exactArgTypes string var fmtctx *tree.FmtCtx var argList []*function.Arg var typeList []string var erArray []ExecResult var pythonArgTypes []function.PythonTypeDescriptor var pythonReturnType *function.PythonTypeDescriptor + if strings.EqualFold(cf.Language, string(tree.PYTHON)) { + if err := ensurePythonUdfRuntimeReady(execCtx.reqCtx, ses); err != nil { + return err + } + } // a database must be selected or specified as qualifier when create a function if cf.Name.HasNoNameQualifier() { @@ -11708,6 +11931,11 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C defer func() { err = finishTxn(execCtx.reqCtx, bh, err) }() + if cf.Language == string(tree.PYTHON) { + if err = ensurePythonUdfCatalogReady(execCtx.reqCtx, bh); err != nil { + return err + } + } // Lock and authenticate the target database before the exact-signature // read. The lock stays held through persistence and commit. @@ -11772,11 +12000,21 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C if err != nil { return err } - argsCondition = fmt.Sprintf("'%s'", argTypes) + logicalArgTypes = argTypes + if cf.Language == string(tree.PYTHON) { + exactArgTypes, err = canonicalPythonInputDescriptor(pythonArgTypes, pythonReturnType) + if err != nil { + return err + } + } // validate duplicate function declaration bh.ClearExecResultSet() - checkExistence = fmt.Sprintf(checkUdfExistence, string(cf.Name.Name.ObjectName), dbName, argsCondition) + if cf.Language == string(tree.PYTHON) { + checkExistence = fmt.Sprintf(checkPythonUdfExistence, string(cf.Name.Name.ObjectName), dbName) + } else { + checkExistence = fmt.Sprintf(checkUdfExistence, string(cf.Name.Name.ObjectName), dbName) + } err = bh.Exec(execCtx.reqCtx, checkExistence) if err != nil { return err @@ -11787,7 +12025,14 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C return err } - if execResultArrayHasData(erArray) && !cf.Replace { + matchedIDs, err := matchUserDefinedFunctionCandidates(execCtx.reqCtx, erArray, string(cf.Language), logicalArgTypes, exactArgTypes) + if err != nil { + return err + } + if len(matchedIDs) > 1 { + return moerr.NewInvalidInputNoCtxf("function %s has multiple catalog identities for the same signature", string(cf.Name.Name.ObjectName)) + } + if len(matchedIDs) == 1 && !cf.Replace { return moerr.NewUDFAlreadyExistsNoCtx(string(cf.Name.Name.ObjectName)) } var body string @@ -11805,17 +12050,24 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C if nullPolicy == "" { nullPolicy = udf.NullCallHandler } + environmentDigest, digestErr := udf.PythonEnvironmentDigest() + if digestErr != nil { + return moerr.NewInvalidInputNoCtxf("Python UDF environment is not available: %v", digestErr) + } nb := function.PythonRoutineBody{ - Handler: cf.Handler, - Source: cf.Body, - Mode: mode, - NullPolicy: nullPolicy, - ABIContract: udf.PythonABIContract, - AdapterVersion: udf.PythonAdapterVersion, - SDKVersion: udf.PythonSDKVersion, - ArgTypes: pythonArgTypes, - ReturnType: pythonReturnType, + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: cf.Handler, + Source: cf.Body, + Mode: mode, + NullPolicy: nullPolicy, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + ArtifactDigest: udf.PythonInlineArtifactDigest(cf.Handler, cf.Body), + EnvironmentDigest: environmentDigest, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: pythonArgTypes, + ReturnType: pythonReturnType, } var byt []byte byt, err = json.Marshal(nb) @@ -11837,11 +12089,29 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C sqlMode: sessionSQLModeForParser(ses), dbName: dbName, } - if execResultArrayHasData(erArray) { // replace - id, err := erArray[0].GetInt64(execCtx.reqCtx, 0, 0) - if err != nil { + if strings.EqualFold(cf.Language, string(tree.PYTHON)) { + // The catalog revision stores the source for restore/inspection, while + // the executable plan carries only its immutable digest. Publish the + // account-scoped object before the catalog row becomes visible; a failed + // transaction can leave only an unreferenced object for later GC. + artifactStore, storeErr := pythonudf.NewFileArtifactStore( + getPu(ses.GetService()).FileService, + pythonudf.DefaultMaxArtifactBytes, + ) + if storeErr != nil { + return storeErr + } + if _, err = artifactStore.Publish( + execCtx.reqCtx, + uint64(tenant.GetTenantID()), + cf.Handler, + cf.Body, + ); err != nil { return err } + } + if len(matchedIDs) == 1 { // replace + id := matchedIDs[0] return persistUserDefinedFunction( execCtx.reqCtx, bh, tenant, ses.GetTenantInfo().GetDefaultRoleID(), definition, &id, ) @@ -11883,20 +12153,26 @@ func escapeSQLStringForDoubleQuotes(s string) string { // userDefinedFunctionDefinition is the function metadata kept outside // mo_tables. Callers control the transaction that persists it. type userDefinedFunctionDefinition struct { - name string - args string - argTypes string - retType string - body string - lang string - sqlMode string - dbName string -} - -// userDefinedFunctionArgumentTypes is the canonical identity of a function -// overload. Argument names do not participate in function resolution, while -// their ordered types do. Keep the zero-argument identity empty to match the -// legacy json_extract(args, '$[*].type') IS NULL representation. + name string + args string + argTypes string + canonicalInputDescriptor string + returnDescriptor string + signatureKeySchemaVersion int + signatureFingerprint string + retType string + body string + lang string + sqlMode string + dbName string +} + +// userDefinedFunctionArgumentTypes is the historical logical signature key +// shared by ordinary SQL routines and by the compatibility columns of the +// current Python catalog. Python's exact width/scale identity is stored in +// canonical_input_descriptor; this helper deliberately remains limited to +// ordered logical type names. Keep the zero-argument value empty to match the +// historical json_extract(args, '$[*].type') IS NULL representation. func userDefinedFunctionArgumentTypes(argumentTypes []string) (string, error) { if len(argumentTypes) == 0 { return "", nil @@ -11937,6 +12213,132 @@ func userDefinedFunctionArgumentTypesFromJSON(args string) (string, error) { return userDefinedFunctionArgumentTypes(types) } +// matchUserDefinedFunctionCandidates compares the current declaration with +// every same-name routine in the namespace. SQL retains its historical +// logical arg_types key; current Python rows additionally carry the exact +// canonical descriptor. Looking at the full candidate set is necessary now +// that Python width/scale overloads may share one logical OID sequence. +func matchUserDefinedFunctionCandidates( + ctx context.Context, + results []ExecResult, + language, logicalArgTypes, exactArgTypes string, +) ([]int64, error) { + result, err := candidateCatalogResultSet(results, "function catalog candidate lookup") + if err != nil { + return nil, err + } + if result == nil { + return nil, nil + } + if result.GetRowCount() == 0 { + return nil, nil + } + columnCount := result.GetColumnCount() + if columnCount < 4 { + return nil, moerr.NewInvalidInputNoCtx("UNSUPPORTED_ROUTINE_VERSION: malformed function catalog candidate") + } + matched := make([]int64, 0, 1) + for row := uint64(0); row < result.GetRowCount(); row++ { + functionID, err := result.GetInt64(ctx, row, 0) + if err != nil { + return nil, err + } + args, err := result.GetString(ctx, row, 1) + if err != nil { + return nil, err + } + existingLanguage, err := result.GetString(ctx, row, 2) + if err != nil { + return nil, err + } + storedArgTypes, err := result.GetString(ctx, row, 3) + if err != nil { + return nil, err + } + existingLogical := storedArgTypes + if parsed, parseErr := userDefinedFunctionArgumentTypesFromJSON(args); parseErr == nil { + existingLogical = parsed + } else if existingLogical == "" { + return nil, moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: function %d has malformed argument metadata: %v", functionID, parseErr, + ) + } + + isMatch := false + if strings.EqualFold(language, string(tree.PYTHON)) { + existingCanonical := "" + if columnCount >= 5 { + existingCanonical, err = result.GetString(ctx, row, 4) + if err != nil { + return nil, err + } + } + if strings.EqualFold(existingLanguage, string(tree.PYTHON)) && existingCanonical != "" { + isMatch = existingCanonical == exactArgTypes + } else { + // A legacy/partially upgraded Python row is rejected as the + // same logical identity. It cannot be silently replaced with a + // different exact descriptor. + isMatch = existingLogical == logicalArgTypes + } + } else { + // SQL and any unknown language still use the shared logical + // namespace until their own canonical descriptor contract is + // published. + isMatch = existingLogical == logicalArgTypes + } + if isMatch { + matched = append(matched, functionID) + } + } + return matched, nil +} + +func normalizePythonFunctionDefinition(definition userDefinedFunctionDefinition) (userDefinedFunctionDefinition, error) { + body, err := function.DecodePythonRoutineBody(definition.body) + if err != nil { + return userDefinedFunctionDefinition{}, moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: Python definition rejected before publication: %v", err, + ) + } + canonicalInput, returnDescriptor, signatureFingerprint, err := function.PythonSignatureMetadata(body.ArgTypes, body.ReturnType) + if err != nil { + return userDefinedFunctionDefinition{}, moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: Python signature rejected before publication: %v", err, + ) + } + if definition.canonicalInputDescriptor != "" && definition.canonicalInputDescriptor != canonicalInput { + return userDefinedFunctionDefinition{}, moerr.NewInvalidInputNoCtx("UNSUPPORTED_ROUTINE_VERSION: Python input descriptor does not match its definition") + } + if definition.returnDescriptor != "" && definition.returnDescriptor != returnDescriptor { + return userDefinedFunctionDefinition{}, moerr.NewInvalidInputNoCtx("UNSUPPORTED_ROUTINE_VERSION: Python return descriptor does not match its definition") + } + if definition.signatureKeySchemaVersion != 0 && definition.signatureKeySchemaVersion != udf.PythonSignatureKeySchemaVersion { + return userDefinedFunctionDefinition{}, moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: Python signature key schema %d is not supported", definition.signatureKeySchemaVersion, + ) + } + if definition.signatureFingerprint != "" && definition.signatureFingerprint != signatureFingerprint { + return userDefinedFunctionDefinition{}, moerr.NewInvalidInputNoCtx("UNSUPPORTED_ROUTINE_VERSION: Python signature fingerprint does not match its definition") + } + definition.canonicalInputDescriptor = canonicalInput + definition.returnDescriptor = returnDescriptor + definition.signatureKeySchemaVersion = udf.PythonSignatureKeySchemaVersion + definition.signatureFingerprint = signatureFingerprint + // Keep arg_types as the shared logical signature key. The exact Python + // descriptor belongs in canonical_input_descriptor and in the immutable + // revision row; mixing the two encodings makes shared SQL readers and + // upgrade paths depend on a language-specific workaround. + logicalArgTypes, err := userDefinedFunctionArgumentTypesFromJSON(definition.args) + if err != nil { + return userDefinedFunctionDefinition{}, moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: Python logical argument metadata is invalid: %v", err, + ) + } + definition.argTypes = logicalArgTypes + return definition, nil +} + // persistUserDefinedFunction writes function metadata into the caller-owned // transaction. A non-nil functionID replaces that existing definition. func persistUserDefinedFunction( @@ -11947,22 +12349,420 @@ func persistUserDefinedFunction( definition userDefinedFunctionDefinition, functionID *int64, ) error { - body := escapeSQLStringForDoubleQuotes(definition.body) sqlMode := plan2.EscapeFormat(definition.sqlMode) + securityType := "DEFINER" + if strings.EqualFold(definition.lang, string(tree.PYTHON)) { + // Python handlers run with the caller's execution frame in the current + // contract. They cannot declare DEFINER semantics; keeping this value + // in the shared catalog makes the security decision visible to readers + // and prevents a Python row from inheriting the SQL UDF default. + securityType = "INVOKER" + } + var revisionCatalogReady bool + if !strings.EqualFold(definition.lang, string(tree.PYTHON)) { + var err error + revisionCatalogReady, err = functionRevisionCatalogAvailable(ctx, bh) + if err != nil { + return err + } + } if functionID != nil { - return bh.Exec(ctx, fmt.Sprintf(updateMoUserDefinedFunctionFormat, + previousLanguage, err := readUserDefinedFunctionLanguage(ctx, bh, *functionID) + if err != nil { + return err + } + if previousLanguage == "" || !strings.EqualFold(previousLanguage, definition.lang) { + return moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: function identity %d cannot change language from %q to %q; use DROP and CREATE", + *functionID, previousLanguage, definition.lang, + ) + } + var previousRevision, previousNamespace uint64 + if strings.EqualFold(definition.lang, string(tree.PYTHON)) { + // Validate the current head and definition before touching the legacy + // compatibility row. A historical Python demo has no immutable + // revision and must be rejected without partially rewriting its body. + var readErr error + previousRevision, previousNamespace, readErr = readPythonRevisionHead(ctx, bh, *functionID) + if readErr != nil { + return readErr + } + if previousRevision == 0 || previousNamespace == 0 { + return moerr.NewInvalidInputNoCtx("UNSUPPORTED_ROUTINE_VERSION: legacy Python definition requires DROP and CREATE") + } + definition, err = normalizePythonFunctionDefinition(definition) + if err != nil { + return err + } + candidate, err := function.DecodePythonRoutineBody(definition.body) + if err != nil { + return moerr.NewInvalidInputNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition rejected before publication: %v", err) + } + previousBody, err := readPythonRevisionBody(ctx, bh, *functionID, previousRevision, previousNamespace) + if err != nil { + return err + } + previous, err := function.DecodePythonRoutineBody(previousBody) + if err != nil { + return moerr.NewInvalidInputNoCtxf("UNSUPPORTED_ROUTINE_VERSION: current Python revision %d is invalid: %v", previousRevision, err) + } + if !samePythonRoutineSignature(previous, candidate) { + return moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: Python REPLACE cannot change input or return descriptor; use DROP and CREATE", + ) + } + } else if revisionCatalogReady { + var readErr error + previousRevision, previousNamespace, readErr = readFunctionRevisionHead(ctx, bh, *functionID) + if readErr != nil { + return readErr + } + previousReturnType, returnErr := readUserDefinedFunctionReturnType(ctx, bh, *functionID) + if returnErr != nil { + return returnErr + } + if !strings.EqualFold(previousReturnType, definition.retType) { + return moerr.NewInvalidInputNoCtxf( + "SQL REPLACE cannot change return type from %q to %q; use DROP and CREATE", + previousReturnType, definition.retType, + ) + } + } + body := escapeSQLStringForDoubleQuotes(definition.body) + if err := bh.Exec(ctx, fmt.Sprintf(updateMoUserDefinedFunctionFormat, ownerRoleID, definition.args, definition.argTypes, definition.retType, body, definition.lang, - tenant.GetUser(), types.CurrentTimestamp().String2(time.UTC, 0), "FUNCTION", "DEFINER", "", "utf8mb4", "utf8mb4_0900_ai_ci", "utf8mb4_0900_ai_ci", sqlMode, - int32(*functionID))) - } - return bh.Exec(ctx, fmt.Sprintf(initMoUserDefinedFunctionFormat, - definition.name, - ownerRoleID, - definition.args, - definition.argTypes, definition.retType, body, definition.lang, definition.dbName, - tenant.GetUser(), types.CurrentTimestamp().String2(time.UTC, 0), types.CurrentTimestamp().String2(time.UTC, 0), "FUNCTION", "DEFINER", "", "utf8mb4", "utf8mb4_0900_ai_ci", "utf8mb4_0900_ai_ci", sqlMode)) + tenant.GetUser(), types.CurrentTimestamp().String2(time.UTC, 0), "FUNCTION", securityType, "", "utf8mb4", "utf8mb4_0900_ai_ci", "utf8mb4_0900_ai_ci", sqlMode, + int32(*functionID))); err != nil { + return err + } + if strings.EqualFold(definition.lang, string(tree.PYTHON)) { + nextRevision := previousRevision + 1 + nextNamespace := previousNamespace + 1 + if err := insertPythonRevision(ctx, bh, definition, *functionID, nextRevision, nextNamespace); err != nil { + return err + } + return activateFunctionRevision(ctx, bh, *functionID, nextRevision, nextNamespace) + } + if !revisionCatalogReady { + return nil + } + nextRevision := previousRevision + 1 + nextNamespace := previousNamespace + 1 + if previousRevision == 0 || previousNamespace == 0 { + nextRevision = 1 + nextNamespace = 1 + } + if err := insertSQLRevision(ctx, bh, definition, *functionID, nextRevision, nextNamespace); err != nil { + return err + } + return activateFunctionRevision(ctx, bh, *functionID, nextRevision, nextNamespace) + } + if strings.EqualFold(definition.lang, string(tree.PYTHON)) { + // A current Python definition must be valid before the base catalog row + // is created. The caller owns the transaction, but rejecting before the + // first write also keeps direct/background writers from leaving a + // partially published identity when validation fails. + var err error + definition, err = normalizePythonFunctionDefinition(definition) + if err != nil { + return err + } + } + body := escapeSQLStringForDoubleQuotes(definition.body) + created := types.CurrentTimestamp().String2(time.UTC, 0) + var insertSQL string + if strings.EqualFold(definition.lang, string(tree.PYTHON)) { + canonicalInputDescriptor := escapeSQLStringForDoubleQuotes(definition.canonicalInputDescriptor) + returnDescriptor := escapeSQLStringForDoubleQuotes(definition.returnDescriptor) + insertSQL = fmt.Sprintf(initMoUserDefinedFunctionFormat, + definition.name, + ownerRoleID, + definition.args, + definition.argTypes, canonicalInputDescriptor, returnDescriptor, definition.signatureKeySchemaVersion, + definition.signatureFingerprint, definition.retType, body, definition.lang, definition.dbName, + tenant.GetUser(), created, created, "FUNCTION", securityType, "", "utf8mb4", "utf8mb4_0900_ai_ci", "utf8mb4_0900_ai_ci", sqlMode) + } else { + // Keep ordinary SQL UDF creation independent of the Python catalog + // columns until the rolling upgrade has reached every writer. + insertSQL = fmt.Sprintf(initMoUserDefinedFunctionSQLFormat, + definition.name, + ownerRoleID, + definition.args, + definition.argTypes, definition.retType, body, definition.lang, definition.dbName, + tenant.GetUser(), created, created, "FUNCTION", "DEFINER", "", "utf8mb4", "utf8mb4_0900_ai_ci", "utf8mb4_0900_ai_ci", sqlMode) + } + if err := bh.Exec(ctx, insertSQL); err != nil { + return err + } + if strings.EqualFold(definition.lang, string(tree.PYTHON)) { + functionIDValue, err := findPersistedFunctionID(ctx, bh, definition) + if err != nil { + return err + } + if err := insertPythonRevision(ctx, bh, definition, functionIDValue, 1, 1); err != nil { + return err + } + return activateFunctionRevision(ctx, bh, functionIDValue, 1, 1) + } + if !revisionCatalogReady { + return nil + } + functionIDValue, err := findPersistedSQLFunctionID(ctx, bh, definition) + if err != nil { + return err + } + if err := insertSQLRevision(ctx, bh, definition, functionIDValue, 1, 1); err != nil { + return err + } + return activateFunctionRevision(ctx, bh, functionIDValue, 1, 1) +} + +func readUserDefinedFunctionLanguage(ctx context.Context, bh BackgroundExec, functionID int64) (string, error) { + bh.ClearExecResultSet() + if err := bh.Exec(ctx, fmt.Sprintf( + "select language from mo_catalog.mo_user_defined_function where function_id = %d;", + functionID, + )); err != nil { + return "", err + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return "", err + } + row, err := exactlyOneCatalogRow(ctx, rows, fmt.Sprintf("function identity %d while replacing", functionID)) + if err != nil { + return "", err + } + language, err := row.GetString(ctx, 0, 0) + if err != nil { + return "", err + } + return language, nil +} + +func readUserDefinedFunctionReturnType(ctx context.Context, bh BackgroundExec, functionID int64) (string, error) { + bh.ClearExecResultSet() + if err := bh.Exec(ctx, fmt.Sprintf( + "select rettype from mo_catalog.mo_user_defined_function where function_id = %d;", + functionID, + )); err != nil { + return "", err + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return "", err + } + row, err := exactlyOneCatalogRow(ctx, rows, fmt.Sprintf("function identity %d while checking its return type", functionID)) + if err != nil { + return "", err + } + return row.GetString(ctx, 0, 0) +} + +func readPythonRevisionBody(ctx context.Context, bh BackgroundExec, functionID int64, revision, namespace uint64) (string, error) { + bh.ClearExecResultSet() + if err := bh.Exec(ctx, fmt.Sprintf( + "select body from mo_catalog.mo_function_revisions where function_id = %d and revision = %d and namespace_version = %d;", + functionID, revision, namespace, + )); err != nil { + return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python revision %d is unavailable: %w", revision, err) + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return "", err + } + row, err := exactlyOneCatalogRow(ctx, rows, fmt.Sprintf("UNSUPPORTED_ROUTINE_VERSION: Python revision %d", revision)) + if err != nil { + return "", err + } + body, err := row.GetString(ctx, 0, 0) + if err != nil { + return "", err + } + return body, nil +} + +func samePythonRoutineSignature(left, right function.PythonRoutineBody) bool { + if len(left.ArgTypes) != len(right.ArgTypes) { + return false + } + for index := range left.ArgTypes { + if left.ArgTypes[index] != right.ArgTypes[index] { + return false + } + } + return left.ReturnType != nil && right.ReturnType != nil && *left.ReturnType == *right.ReturnType +} + +func readPythonRevisionHead(ctx context.Context, bh BackgroundExec, functionID int64) (uint64, uint64, error) { + bh.ClearExecResultSet() + if err := bh.Exec(ctx, fmt.Sprintf( + "select active_revision, namespace_version from mo_catalog.mo_user_defined_function where function_id = %d;", + functionID, + )); err != nil { + return 0, 0, err + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return 0, 0, err + } + row, err := exactlyOneCatalogRow(ctx, rows, fmt.Sprintf("function identity %d while publishing Python revision", functionID)) + if err != nil { + return 0, 0, err + } + revision, err := row.GetInt64(ctx, 0, 0) + if err != nil { + return 0, 0, err + } + namespace, err := row.GetInt64(ctx, 0, 1) + if err != nil { + return 0, 0, err + } + if revision < 0 || namespace < 0 { + return 0, 0, moerr.NewInvalidInputNoCtxf("function identity %d has invalid Python revision head", functionID) + } + return uint64(revision), uint64(namespace), nil +} + +func findPersistedFunctionID(ctx context.Context, bh BackgroundExec, definition userDefinedFunctionDefinition) (int64, error) { + bh.ClearExecResultSet() + query := fmt.Sprintf( + `select function_id from mo_catalog.mo_user_defined_function where name = "%s" and db = "%s" and canonical_input_descriptor = "%s" and language = '%s' order by function_id desc limit 1;`, + escapeSQLStringForDoubleQuotes(definition.name), + escapeSQLStringForDoubleQuotes(definition.dbName), + escapeSQLStringForDoubleQuotes(definition.canonicalInputDescriptor), + escapeSQLStringForDoubleQuotes(definition.lang), + ) + if err := bh.Exec(ctx, query); err != nil { + return 0, err + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return 0, err + } + row, err := exactlyOneCatalogRow(ctx, rows, "Python function identity after creation") + if err != nil { + return 0, err + } + return row.GetInt64(ctx, 0, 0) +} + +func findPersistedSQLFunctionID(ctx context.Context, bh BackgroundExec, definition userDefinedFunctionDefinition) (int64, error) { + bh.ClearExecResultSet() + query := fmt.Sprintf( + `select function_id from mo_catalog.mo_user_defined_function where name = "%s" and db = "%s" and arg_types = %s and language = '%s' order by function_id desc limit 1;`, + escapeSQLStringForDoubleQuotes(definition.name), + escapeSQLStringForDoubleQuotes(definition.dbName), + quoteSQLStringLiteral(definition.argTypes), + escapeSQLStringForDoubleQuotes(definition.lang), + ) + if err := bh.Exec(ctx, query); err != nil { + return 0, err + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return 0, err + } + row, err := exactlyOneCatalogRow(ctx, rows, "SQL function identity after creation") + if err != nil { + return 0, err + } + return row.GetInt64(ctx, 0, 0) +} + +func insertPythonRevision(ctx context.Context, bh BackgroundExec, definition userDefinedFunctionDefinition, functionID int64, revision, namespace uint64) error { + body, err := function.DecodePythonRoutineBody(definition.body) + if err != nil { + return moerr.NewInvalidInputNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition rejected before publication: %v", err) + } + fingerprint, err := function.PythonRoutineFingerprint(definition.body) + if err != nil { + return err + } + canonicalInput, _, _, err := function.PythonSignatureMetadata(body.ArgTypes, body.ReturnType) + if err != nil { + return moerr.NewInvalidInputNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python signature rejected before publication: %v", err) + } + if definition.canonicalInputDescriptor != "" && definition.canonicalInputDescriptor != canonicalInput { + return moerr.NewInvalidInputNoCtx("UNSUPPORTED_ROUTINE_VERSION: Python input descriptor does not match its definition") + } + quote := func(value string) string { return escapeSQLStringForDoubleQuotes(value) } + created := types.CurrentTimestamp().String2(time.UTC, 0) + sql := fmt.Sprintf(`insert into mo_catalog.mo_function_revisions( + function_id, revision, namespace_version, name, args, arg_types, rettype, body, + language, definition_schema_version, abi_contract, adapter_version, + artifact_digest, environment_digest, sdk_version, null_policy, volatility, + definition_fingerprint, created_time, security_type) values ( + %d, %d, %d, "%s", "%s", "%s", "%s", "%s", "%s", %d, "%s", "%s", "%s", "%s", "%s", "%s", "VOLATILE", "%s", "%s", "INVOKER");`, + functionID, revision, namespace, quote(definition.name), quote(definition.args), quote(canonicalInput), + quote(definition.retType), quote(definition.body), quote(definition.lang), body.DefinitionSchemaVersion, + quote(body.ABIContract), quote(body.AdapterVersion), quote(body.ArtifactDigest), quote(body.EnvironmentDigest), + quote(body.SDKVersion), quote(body.NullPolicy), quote(fingerprint), created, + ) + return bh.Exec(ctx, sql) +} + +func insertSQLRevision(ctx context.Context, bh BackgroundExec, definition userDefinedFunctionDefinition, functionID int64, revision, namespace uint64) error { + fingerprint, err := function.SQLRoutineFingerprint(definition.body, definition.argTypes, definition.retType) + if err != nil { + return moerr.NewInvalidInputNoCtxf("SQL definition rejected before publication: %v", err) + } + quote := func(value string) string { return escapeSQLStringForDoubleQuotes(value) } + created := types.CurrentTimestamp().String2(time.UTC, 0) + sql := fmt.Sprintf(`insert into mo_catalog.mo_function_revisions( + function_id, revision, namespace_version, name, args, arg_types, rettype, body, + language, definition_schema_version, abi_contract, adapter_version, + artifact_digest, environment_digest, sdk_version, null_policy, volatility, + definition_fingerprint, created_time, security_type) values ( + %d, %d, %d, "%s", "%s", "%s", "%s", "%s", "%s", %d, "", "", "", "", "", "%s", "VOLATILE", "%s", "%s", "DEFINER");`, + functionID, revision, namespace, quote(definition.name), quote(definition.args), + quote(definition.argTypes), quote(definition.retType), quote(definition.body), quote(definition.lang), + udf.SQLDefinitionSchemaVersion, quote(udf.NullCallHandler), quote(fingerprint), created, + ) + return bh.Exec(ctx, sql) +} + +func readFunctionRevisionHead(ctx context.Context, bh BackgroundExec, functionID int64) (uint64, uint64, error) { + bh.ClearExecResultSet() + if err := bh.Exec(ctx, fmt.Sprintf( + "select active_revision, namespace_version from mo_catalog.mo_user_defined_function where function_id = %d;", + functionID, + )); err != nil { + return 0, 0, err + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return 0, 0, err + } + row, err := exactlyOneCatalogRow(ctx, rows, fmt.Sprintf("function identity %d while publishing a revision", functionID)) + if err != nil { + return 0, 0, err + } + revision, err := row.GetInt64(ctx, 0, 0) + if err != nil { + return 0, 0, err + } + namespace, err := row.GetInt64(ctx, 0, 1) + if err != nil { + return 0, 0, err + } + if revision < 0 || namespace < 0 { + return 0, 0, moerr.NewInvalidInputNoCtxf("function identity %d has an invalid revision head", functionID) + } + return uint64(revision), uint64(namespace), nil +} + +func activateFunctionRevision(ctx context.Context, bh BackgroundExec, functionID int64, revision, namespace uint64) error { + return bh.Exec(ctx, fmt.Sprintf( + "update mo_catalog.mo_user_defined_function set active_revision = %d, namespace_version = %d where function_id = %d;", + revision, namespace, functionID, + )) +} + +func activatePythonRevision(ctx context.Context, bh BackgroundExec, functionID int64, revision, namespace uint64) error { + return activateFunctionRevision(ctx, bh, functionID, revision, namespace) } // storedProcedureDefinition is the procedure metadata kept outside mo_tables. diff --git a/pkg/frontend/authenticate_test.go b/pkg/frontend/authenticate_test.go index c3e7329ce3cc7..c18bfa485f13d 100644 --- a/pkg/frontend/authenticate_test.go +++ b/pkg/frontend/authenticate_test.go @@ -10645,6 +10645,30 @@ func Test_doDropFunctionIfExistsWithDifferentOverload(t *testing.T) { } } +func TestDeleteUserDefinedFunctionRevisionsIfPresent(t *testing.T) { + ctx := context.Background() + functionID := int64(91) + deleteSQL := fmt.Sprintf(deleteUserDefinedFunctionRevisionsFormat, functionID) + + t.Run("missing revision table is compatible with legacy SQL UDF drop", func(t *testing.T) { + bh := &backgroundExecTest{} + bh.init() + bh.sql2err[deleteSQL] = moerr.NewNoSuchTableNoCtx("mo_catalog", "mo_function_revisions") + + require.NoError(t, deleteUserDefinedFunctionRevisionsIfPresent(ctx, bh, functionID)) + require.Equal(t, []string{deleteSQL}, bh.executedSQLs) + }) + + t.Run("unexpected cleanup failure is not hidden", func(t *testing.T) { + bh := &backgroundExecTest{} + bh.init() + wantErr := errors.New("revision cleanup failed") + bh.sql2err[deleteSQL] = wantErr + + require.ErrorIs(t, deleteUserDefinedFunctionRevisionsIfPresent(ctx, bh, functionID), wantErr) + }) +} + func Test_doDropRole(t *testing.T) { convey.Convey("drop role succ", t, func() { ctrl := gomock.NewController(t) diff --git a/pkg/frontend/clone.go b/pkg/frontend/clone.go index 5612d2b73c685..1510d66faf4bc 100644 --- a/pkg/frontend/clone.go +++ b/pkg/frontend/clone.go @@ -1250,6 +1250,22 @@ func handleCloneDatabaseWithSource( } } } + for _, definition := range source.userDefinedFuncs { + if !strings.EqualFold(definition.lang, string(tree.PYTHON)) { + continue + } + // Database clone is a new Python publication in the target account. + // Apply the same runtime and catalog gates before creating the target + // database, so a disabled or partially upgraded node cannot leave a + // clone that contains an unrunnable routine. + if err = ensurePythonUdfRuntimeReady(reqCtx, ses); err != nil { + return + } + if err = ensurePythonUdfCatalogReady(reqCtx, bh); err != nil { + return + } + break + } fromAccountID := source.opAccountId if source.snapshot != nil && source.snapshot.Tenant != nil { fromAccountID = source.snapshot.Tenant.TenantID @@ -1499,6 +1515,7 @@ func handleCloneDatabaseWithSource( } if err = restoreCloneDatabaseUserDefinedFunctions( ctx1, bh, routineTenant, source.userDefinedFuncs, stmt.DstDatabase.String(), + getPu(ses.GetService()).FileService, ); err != nil { return } diff --git a/pkg/frontend/clone_database_source.go b/pkg/frontend/clone_database_source.go index 3bbbdfe570016..7e6beb995b6ae 100644 --- a/pkg/frontend/clone_database_source.go +++ b/pkg/frontend/clone_database_source.go @@ -25,13 +25,14 @@ import ( "github.com/matrixorigin/matrixone/pkg/catalog" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/fileservice" "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/sql/parsers" "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql" "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" "github.com/matrixorigin/matrixone/pkg/sql/plan/function" - "github.com/matrixorigin/matrixone/pkg/udf" + pythonudf "github.com/matrixorigin/matrixone/pkg/udf/python" ) type cloneDatabaseSource struct { @@ -709,17 +710,12 @@ func validateCloneUserDefinedFunctions(functions []userDefinedFunctionDefinition ) } if strings.EqualFold(definition.lang, string(tree.PYTHON)) { - var body function.PythonRoutineBody - if err := json.Unmarshal([]byte(definition.body), &body); err != nil || - body.Handler == "" || body.Source == "" || - (body.Mode != "SCALAR" && body.Mode != "VECTOR") || - (body.NullPolicy != udf.NullCallHandler && body.NullPolicy != udf.NullReturnNull) || - body.ABIContract != udf.PythonABIContract || body.AdapterVersion != udf.PythonAdapterVersion || - body.SDKVersion != udf.PythonSDKVersion { + if _, err := function.DecodePythonRoutineBody(definition.body); err != nil { return moerr.NewNotSupportedNoCtxf( - "CREATE DATABASE CLONE with incomplete %s function %s is not supported", + "CREATE DATABASE CLONE with unsupported %s function %s is not supported: %v", definition.lang, definition.name, + err, ) } } @@ -822,11 +818,35 @@ func restoreCloneDatabaseUserDefinedFunctions( tenant *TenantInfo, functions []userDefinedFunctionDefinition, dbName string, + artifactFileServices ...fileservice.FileService, ) error { - for _, function := range functions { - function.dbName = dbName + var artifactStore *pythonudf.FileArtifactStore + if len(artifactFileServices) > 0 && artifactFileServices[0] != nil { + var err error + artifactStore, err = pythonudf.NewFileArtifactStore( + artifactFileServices[0], + pythonudf.DefaultMaxArtifactBytes, + ) + if err != nil { + return err + } + } + for _, definition := range functions { + definition.dbName = dbName + if strings.EqualFold(definition.lang, string(tree.PYTHON)) { + if artifactStore == nil { + return moerr.NewNotSupportedNoCtx("Python artifact store is required to clone a current Python routine") + } + body, err := function.DecodePythonRoutineBody(definition.body) + if err != nil { + return moerr.NewInvalidInputNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python clone source is invalid: %v", err) + } + if _, err := artifactStore.Publish(ctx, uint64(tenant.GetTenantID()), body.Handler, body.Source); err != nil { + return err + } + } if err := persistUserDefinedFunction( - ctx, bh, tenant, tenant.GetDefaultRoleID(), function, nil, + ctx, bh, tenant, tenant.GetDefaultRoleID(), definition, nil, ); err != nil { return err } diff --git a/pkg/frontend/clone_database_source_test.go b/pkg/frontend/clone_database_source_test.go index 10f513fee0996..ccc37082884bb 100644 --- a/pkg/frontend/clone_database_source_test.go +++ b/pkg/frontend/clone_database_source_test.go @@ -122,6 +122,14 @@ type erroringBackgroundExec struct { err error } +func configureSQLFunctionIdentityLookup(bh *backgroundExecTest, functionID int64) { + bh.beforeExec = func(sql string) { + if strings.HasPrefix(sql, "select function_id from mo_catalog.mo_user_defined_function where name = ") { + bh.sql2result[sql] = newMrsForPasswordOfUser([][]interface{}{{functionID, nil, nil}}) + } + } +} + func (bt *erroringBackgroundExec) Exec(ctx context.Context, sql string) error { if err := bt.backgroundExecTest.Exec(ctx, sql); err != nil { return err @@ -246,7 +254,7 @@ func TestUdfCatalogLookupUsesSnapshot(t *testing.T) { require.NoError(t, err) require.Equal(t, uint32(7), accountID) require.Equal(t, - `select args, body, language, rettype, db, modified_time, sql_mode from mo_catalog.mo_user_defined_function {MO_TS = 42} where name = "f_snapshot" and db = "source_db";`, + `select function_id, args, body, language, rettype, db, modified_time, sql_mode from mo_catalog.mo_user_defined_function {MO_TS = 42} where name = "f_snapshot" and db = "source_db";`, sql, ) @@ -254,11 +262,25 @@ func TestUdfCatalogLookupUsesSnapshot(t *testing.T) { _, err = defines.GetAccountId(queryCtx) require.Error(t, err) require.Equal(t, - `select args, body, language, rettype, db, modified_time, sql_mode from mo_catalog.mo_user_defined_function where name = "f_live" and db = "live_db";`, + `select function_id, args, body, language, rettype, db, modified_time, sql_mode from mo_catalog.mo_user_defined_function where name = "f_live" and db = "live_db";`, sql, ) } +func TestPythonRevisionCatalogLookupUsesSameSnapshotForBothTables(t *testing.T) { + snapshot := &plan.Snapshot{TS: ×tamp.Timestamp{PhysicalTime: 99}} + query := pythonRevisionCatalogSQL(snapshot, 41) + require.Contains(t, query, "from mo_catalog.mo_user_defined_function {MO_TS = 99} f") + require.Contains(t, query, "join mo_catalog.mo_function_revisions {MO_TS = 99} r") + require.Contains(t, query, "r.namespace_version = f.namespace_version") + require.Contains(t, query, "where f.function_id = 41;") + + liveQuery := pythonRevisionCatalogSQL(nil, 41) + require.Contains(t, liveQuery, "from mo_catalog.mo_user_defined_function f") + require.Contains(t, liveQuery, "join mo_catalog.mo_function_revisions r") + require.Contains(t, liveQuery, "r.namespace_version = f.namespace_version") +} + func TestGetCloneDatabaseRoutineInfosRespectsSubscriptionBoundary(t *testing.T) { t.Run("database source collects functions and procedures", func(t *testing.T) { const dbName = "source_db" @@ -369,19 +391,26 @@ func TestRestoreCloneDatabaseUserDefinedFunctions(t *testing.T) { bh := &backgroundExecTest{} bh.init() + bh.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) + configureSQLFunctionIdentityLookup(bh, 1) require.NoError(t, restoreCloneDatabaseUserDefinedFunctions(ctx, bh, tenant, []userDefinedFunctionDefinition{function}, "target_db")) - require.Len(t, bh.executedSQLs, 1) - require.Contains(t, bh.executedSQLs[0], "insert into mo_catalog.mo_user_defined_function") - require.Contains(t, bh.executedSQLs[0], "\"f_answer\",2") - require.Contains(t, bh.executedSQLs[0], "\"target_db\"") - require.Contains(t, bh.executedSQLs[0], "\"root1\"") + require.Len(t, bh.executedSQLs, 5) + require.Equal(t, functionRevisionCatalogSchemaCheck, bh.executedSQLs[0]) + require.Contains(t, bh.executedSQLs[1], "insert into mo_catalog.mo_user_defined_function") + require.Contains(t, bh.executedSQLs[1], "\"f_answer\",2") + require.Contains(t, bh.executedSQLs[1], "\"target_db\"") + require.Contains(t, bh.executedSQLs[1], "\"root1\"") + require.Contains(t, bh.executedSQLs[2], "select function_id from mo_catalog.mo_user_defined_function") + require.Contains(t, bh.executedSQLs[3], "insert into mo_catalog.mo_function_revisions") + require.Contains(t, bh.executedSQLs[4], "update mo_catalog.mo_user_defined_function set active_revision") // SQL literal quoting is an implementation detail of EscapeFormat; preserve // the behavior under test rather than coupling this regression to its style. - require.Contains(t, bh.executedSQLs[0], "PIPES_AS_CONCAT") + require.Contains(t, bh.executedSQLs[1], "PIPES_AS_CONCAT") require.NotContains(t, bh.executedSQLs, "begin;") failingBase := &backgroundExecTest{} failingBase.init() + failingBase.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) wantErr := errors.New("function persistence failed") failing := &erroringBackgroundExec{backgroundExecTest: failingBase, err: wantErr} require.ErrorIs(t, restoreCloneDatabaseUserDefinedFunctions(ctx, failing, tenant, []userDefinedFunctionDefinition{function}, "target_db"), wantErr) diff --git a/pkg/frontend/clone_test.go b/pkg/frontend/clone_test.go index e492a59c90ac9..2db1bf9c920dc 100644 --- a/pkg/frontend/clone_test.go +++ b/pkg/frontend/clone_test.go @@ -985,6 +985,8 @@ func TestHandleCloneDatabaseWithSourceRestoresRoutines(t *testing.T) { t.Cleanup(ses.Close) bh := &backgroundExecTest{} bh.init() + bh.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) + configureSQLFunctionIdentityLookup(bh, 1) checkSQL := getSqlForCheckProcedureExistence("p_answer", "destination") bh.sql2result[checkSQL] = newMrsForPasswordOfUser(nil) @@ -993,11 +995,15 @@ func TestHandleCloneDatabaseWithSourceRestoresRoutines(t *testing.T) { ses, bh, newStatement(), newSource(), ) require.NoError(t, err) - require.Len(t, bh.executedSQLs, 4) + require.Len(t, bh.executedSQLs, 8) require.Equal(t, "create database `destination`", bh.executedSQLs[0]) - require.Contains(t, bh.executedSQLs[1], "insert into mo_catalog.mo_user_defined_function") - require.Equal(t, checkSQL, bh.executedSQLs[2]) - require.Contains(t, bh.executedSQLs[3], "insert into mo_catalog.mo_stored_procedure") + require.Equal(t, functionRevisionCatalogSchemaCheck, bh.executedSQLs[1]) + require.Contains(t, bh.executedSQLs[2], "insert into mo_catalog.mo_user_defined_function") + require.Contains(t, bh.executedSQLs[3], "select function_id from mo_catalog.mo_user_defined_function") + require.Contains(t, bh.executedSQLs[4], "insert into mo_catalog.mo_function_revisions") + require.Contains(t, bh.executedSQLs[5], "update mo_catalog.mo_user_defined_function set active_revision") + require.Equal(t, checkSQL, bh.executedSQLs[6]) + require.Contains(t, bh.executedSQLs[7], "insert into mo_catalog.mo_stored_procedure") }) t.Run("propagates procedure restoration failures", func(t *testing.T) { @@ -1006,6 +1012,8 @@ func TestHandleCloneDatabaseWithSourceRestoresRoutines(t *testing.T) { t.Cleanup(ses.Close) bh := &backgroundExecTest{} bh.init() + bh.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) + configureSQLFunctionIdentityLookup(bh, 1) checkSQL := getSqlForCheckProcedureExistence("p_answer", "destination") wantErr := errors.New("procedure lookup failed") bh.sql2err[checkSQL] = wantErr @@ -1015,10 +1023,14 @@ func TestHandleCloneDatabaseWithSourceRestoresRoutines(t *testing.T) { ses, bh, newStatement(), newSource(), ) require.ErrorIs(t, err, wantErr) - require.Len(t, bh.executedSQLs, 3) + require.Len(t, bh.executedSQLs, 7) require.Equal(t, "create database `destination`", bh.executedSQLs[0]) - require.Contains(t, bh.executedSQLs[1], "insert into mo_catalog.mo_user_defined_function") - require.Equal(t, checkSQL, bh.executedSQLs[2]) + require.Equal(t, functionRevisionCatalogSchemaCheck, bh.executedSQLs[1]) + require.Contains(t, bh.executedSQLs[2], "insert into mo_catalog.mo_user_defined_function") + require.Contains(t, bh.executedSQLs[3], "select function_id from mo_catalog.mo_user_defined_function") + require.Contains(t, bh.executedSQLs[4], "insert into mo_catalog.mo_function_revisions") + require.Contains(t, bh.executedSQLs[5], "update mo_catalog.mo_user_defined_function set active_revision") + require.Equal(t, checkSQL, bh.executedSQLs[6]) }) t.Run("rejects imported functions before target database creation", func(t *testing.T) { diff --git a/pkg/frontend/compiler_context.go b/pkg/frontend/compiler_context.go index dbd756b0a3b32..4842af33231a2 100644 --- a/pkg/frontend/compiler_context.go +++ b/pkg/frontend/compiler_context.go @@ -43,6 +43,7 @@ import ( plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" "github.com/matrixorigin/matrixone/pkg/sql/plan/function" "github.com/matrixorigin/matrixone/pkg/sql/util" + "github.com/matrixorigin/matrixone/pkg/udf" v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2" "github.com/matrixorigin/matrixone/pkg/util/sysview" "github.com/matrixorigin/matrixone/pkg/util/trace/impl/motrace/statistic" @@ -940,14 +941,18 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex if err != nil { return nil, err } + if len(erArray) > 1 || (len(erArray) == 1 && erArray[0] == nil) { + return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: UDF %s lookup returned %d result sets, expected one or an empty candidate result", name, len(erArray)) + } if execResultArrayHasData(erArray) { fromList := make([]types.Type, len(args)) for i, arg := range args { fromList[i] = types.Type{ - Oid: types.T(arg.Typ.Id), - Width: arg.Typ.Width, - Scale: arg.Typ.Scale, + Oid: types.T(arg.Typ.Id), + Charset: uint8(arg.Typ.Charset), + Width: arg.Typ.Width, + Scale: arg.Typ.Scale, } argTypeStr += strings.ToLower(fromList[i].String()) @@ -965,38 +970,72 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex matchedList := make([]*MatchUdf, 0) for i := uint64(0); i < erArray[0].GetRowCount(); i++ { - argstr, err = erArray[0].GetString(ctx, i, 0) + functionID, getErr := erArray[0].GetInt64(ctx, i, 0) + if getErr != nil { + return nil, getErr + } + argstr, err = erArray[0].GetString(ctx, i, 1) if err != nil { return nil, err } udf = &function.Udf{} - udf.Body, err = erArray[0].GetString(ctx, i, 1) + udf.Body, err = erArray[0].GetString(ctx, i, 2) if err != nil { return nil, err } - udf.Language, err = erArray[0].GetString(ctx, i, 2) + udf.Language, err = erArray[0].GetString(ctx, i, 3) if err != nil { return nil, err } - udf.RetType, err = erArray[0].GetString(ctx, i, 3) + udf.RetType, err = erArray[0].GetString(ctx, i, 4) if err != nil { return nil, err } - udf.Db, err = erArray[0].GetString(ctx, i, 4) + udf.Db, err = erArray[0].GetString(ctx, i, 5) if err != nil { return nil, err } - udf.ModifiedTime, err = erArray[0].GetString(ctx, i, 5) + udf.ModifiedTime, err = erArray[0].GetString(ctx, i, 6) if err != nil { return nil, err } udf.ModifiedTime = strings.ReplaceAll(udf.ModifiedTime, " ", "_") udf.ModifiedTime = strings.ReplaceAll(udf.ModifiedTime, ":", "-") - mode, getErr := erArray[0].GetString(ctx, i, 6) + mode, getErr := erArray[0].GetString(ctx, i, 7) if getErr != nil { return nil, getErr } udf.SQLMode = &mode + udf.FunctionID = functionID + if strings.EqualFold(udf.Language, string(tree.PYTHON)) { + revision, revisionErr := readPythonRevision(queryCtx, bh, functionID, tcc.GetSnapshot()) + if revisionErr != nil { + return nil, revisionErr + } + argstr = revision.Args + udf.Body = revision.Body + udf.Language = revision.Language + udf.RetType = revision.RetType + udf.Revision = revision.Revision + udf.NamespaceVersion = revision.NamespaceVersion + } else if strings.EqualFold(udf.Language, string(tree.SQL)) { + revision, found, revisionErr := readSQLRevision(queryCtx, bh, functionID, tcc.GetSnapshot()) + if revisionErr != nil { + return nil, revisionErr + } + if found { + argstr = revision.Args + udf.Body = revision.Body + udf.Language = revision.Language + udf.RetType = revision.RetType + udf.Revision = revision.Revision + udf.NamespaceVersion = revision.NamespaceVersion + udf.DefinitionFingerprint = revision.DefinitionFingerprint + udf.SemanticDefinitionSchemaVersion = int(revision.DefinitionSchema) + udf.Volatility = revision.Volatility + udf.NullPolicy = revision.NullPolicy + } + } if err = udf.LoadPythonTypeContract(); err != nil { return nil, err } @@ -1013,10 +1052,19 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex if err = udf.ValidatePythonTypeContract(); err != nil { return nil, err } + if err = udf.ValidatePythonCatalogSignature(); err != nil { + return nil, err + } toList := make([]types.T, len(args)) + pythonTargetTypes := make([]types.Type, 0) + if strings.EqualFold(udf.Language, string(tree.PYTHON)) { + pythonTargetTypes = udf.GetArgsType() + } for j := range argList { - if fromList[j].IsDecimal() && argList[j].Type == "decimal" { + if len(pythonTargetTypes) != 0 { + toList[j] = pythonTargetTypes[j].Oid + } else if fromList[j].IsDecimal() && argList[j].Type == "decimal" { toList[j] = fromList[j].Oid } else { toList[j] = types.Types[argList[j].Type] @@ -1024,6 +1072,9 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex } canCast, cost := function.UdfArgTypeMatch(fromList, toList) + if len(pythonTargetTypes) != 0 { + canCast, cost = function.PythonUdfArgTypeMatch(fromList, pythonTargetTypes) + } if !canCast { // mismatch continue } @@ -1051,7 +1102,26 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex } if matchNum == 1 { - matchedList[0].Udf.ArgsType = function.UdfArgTypeCast(fromList, matchedList[0].TypeList) + if strings.EqualFold(matchedList[0].Udf.Language, string(tree.PYTHON)) { + matchedList[0].Udf.ArgsType = function.PythonUdfArgTypeCast(fromList, matchedList[0].Udf.GetArgsType()) + if len(matchedList[0].Udf.ArgsType) != len(fromList) { + return nil, fmt.Errorf("python udf: argument descriptor count changed during resolution") + } + } else { + matchedList[0].Udf.ArgsType = function.UdfArgTypeCast(fromList, matchedList[0].TypeList) + } + if matchedList[0].Udf.Revision != 0 { + accountID, accountErr := tcc.GetAccountId() + if accountErr != nil { + return nil, accountErr + } + databaseID, databaseErr := tcc.GetDatabaseId(matchedList[0].Udf.Db, tcc.GetSnapshot()) + if databaseErr != nil { + return nil, fmt.Errorf("python routine database identity: %w", databaseErr) + } + matchedList[0].Udf.AccountID = uint64(accountID) + matchedList[0].Udf.DatabaseID = databaseID + } return matchedList[0].Udf, err } @@ -1081,13 +1151,407 @@ func udfCatalogLookup( } } return ctx, fmt.Sprintf( - `select args, body, language, rettype, db, modified_time, sql_mode from %s where name = "%s" and db = "%s";`, + `select function_id, args, body, language, rettype, db, modified_time, sql_mode from %s where name = "%s" and db = "%s";`, catalogTable, name, database, ) } +// exactlyOneCatalogResultSet is for catalog reads that must be interpreted +// atomically. A BackgroundExec result array is a transport shape, not a +// guarantee that a single SELECT produced one result set. Treating the first +// result set as authoritative would let a split or malformed reader hide +// catalog corruption from the planner/cache validator. +func exactlyOneCatalogResultSet(ctx context.Context, rows []ExecResult, label string) (ExecResult, error) { + if len(rows) != 1 || rows[0] == nil { + return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: %s returned %d result sets, expected exactly one", label, len(rows)) + } + return rows[0], nil +} + +// candidateCatalogResultSet is used only for a name/signature lookup. The +// execution engine represents a SELECT with no matching rows as an empty +// result-set slice, and that is the normal state before the first CREATE. +// Multiple result sets or a nil result remain malformed and fail closed. +func candidateCatalogResultSet(rows []ExecResult, label string) (ExecResult, error) { + if len(rows) == 0 { + return nil, nil + } + return exactlyOneCatalogResultSet(context.Background(), rows, label) +} + +// exactlyOneCatalogRow is for identity and revision point reads. A catalog +// query with a function_id/revision predicate is expected to return one +// logical row in one result set. Treating the first row as authoritative +// would turn duplicate or split result sets caused by corruption, restore, or +// a malformed reader into an arbitrary executable contract. +func exactlyOneCatalogRow(ctx context.Context, rows []ExecResult, label string) (ExecResult, error) { + result, err := exactlyOneCatalogResultSet(ctx, rows, label) + if err != nil { + return nil, err + } + rowCount := result.GetRowCount() + if rowCount != 1 { + return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: %s returned %d rows, expected exactly one", label, rowCount) + } + return result, nil +} + +type pythonRevisionCatalogRow struct { + Args string + ArgTypes string + Body string + Language string + RetType string + Revision uint64 + NamespaceVersion uint64 + CanonicalInputDescriptor string + ReturnDescriptor string + SignatureKeySchemaVersion int64 + SignatureFingerprint string + DefinitionSchema int64 + ABIContract string + AdapterVersion string + SDKVersion string + NullPolicy string + Volatility string + DefinitionFingerprint string + ArtifactDigest string + EnvironmentDigest string + SecurityType string +} + +type sqlRevisionCatalogRow struct { + Args string + ArgTypes string + Body string + Language string + RetType string + Revision uint64 + NamespaceVersion uint64 + DefinitionSchema int64 + DefinitionFingerprint string + Volatility string + NullPolicy string + SecurityType string +} + +// readSQLRevision resolves the current shared revision head without making a +// legacy SQL row look current. A missing v4_0_7 table/column is reported as +// found=false so ordinary SQL remains available during a rolling upgrade; +// once a head is published, every missing or malformed revision is a hard +// catalog error. +func readSQLRevision( + ctx context.Context, + bh BackgroundExec, + functionID int64, + snapshot *plan2.Snapshot, +) (sqlRevisionCatalogRow, bool, error) { + baseTable := "mo_catalog.mo_user_defined_function" + revisionTable := "mo_catalog.mo_function_revisions" + if snapshot != nil && snapshot.TS != nil { + suffix := fmt.Sprintf(" {MO_TS = %d}", snapshot.TS.PhysicalTime) + baseTable += suffix + revisionTable += suffix + } + + bh.ClearExecResultSet() + if err := bh.Exec(ctx, fmt.Sprintf( + "select active_revision, namespace_version, security_type from %s where function_id = %d;", + baseTable, functionID, + )); err != nil { + if isMissingCatalogObjectError(err) { + return sqlRevisionCatalogRow{}, false, nil + } + return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision head is unavailable: %w", functionID, err) + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + row, err := exactlyOneCatalogRow(ctx, rows, fmt.Sprintf("SQL function %d revision head", functionID)) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + activeRevision, err := row.GetInt64(ctx, 0, 0) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + namespaceVersion, err := row.GetInt64(ctx, 0, 1) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + baseSecurityType, err := row.GetString(ctx, 0, 2) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + if activeRevision == 0 && namespaceVersion == 0 { + return sqlRevisionCatalogRow{}, false, nil + } + if activeRevision <= 0 || namespaceVersion <= 0 { + return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d has an invalid revision head", functionID) + } + + bh.ClearExecResultSet() + if err := bh.Exec(ctx, fmt.Sprintf( + "select revision, args, arg_types, body, rettype, language, "+ + "definition_schema_version, definition_fingerprint, volatility, null_policy, security_type "+ + "from %s where function_id = %d and revision = %d and namespace_version = %d;", + revisionTable, functionID, activeRevision, namespaceVersion, + )); err != nil { + if isMissingCatalogObjectError(err) { + return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision table is unavailable: %w", functionID, err) + } + return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision is unavailable: %w", functionID, err) + } + rows, err = getResultSet(ctx, bh) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + row, err = exactlyOneCatalogRow(ctx, rows, fmt.Sprintf("SQL function %d active revision", functionID)) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + getString := func(column uint64) (string, error) { return row.GetString(ctx, 0, column) } + revisionValue, err := row.GetInt64(ctx, 0, 0) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + args, err := getString(1) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + argTypes, err := getString(2) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + body, err := getString(3) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + retType, err := getString(4) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + language, err := getString(5) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + definitionSchema, err := row.GetInt64(ctx, 0, 6) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + fingerprint, err := getString(7) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + volatility, err := getString(8) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + nullPolicy, err := getString(9) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + securityType, err := getString(10) + if err != nil { + return sqlRevisionCatalogRow{}, false, err + } + if revisionValue <= 0 || uint64(revisionValue) != uint64(activeRevision) || + !strings.EqualFold(language, string(tree.SQL)) || + definitionSchema != udf.SQLDefinitionSchemaVersion || + volatility != "VOLATILE" || nullPolicy != udf.NullCallHandler || + !strings.EqualFold(securityType, "DEFINER") || + !strings.EqualFold(baseSecurityType, securityType) { + return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision contract is not supported", functionID) + } + logicalArgTypes, err := userDefinedFunctionArgumentTypesFromJSON(args) + if err != nil || logicalArgTypes != argTypes { + return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision argument metadata is invalid", functionID) + } + expectedFingerprint, err := function.SQLRoutineFingerprint(body, argTypes, retType) + if err != nil || fingerprint == "" || fingerprint != expectedFingerprint { + return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision fingerprint mismatch", functionID) + } + return sqlRevisionCatalogRow{ + Args: args, ArgTypes: argTypes, Body: body, Language: language, RetType: retType, + Revision: uint64(revisionValue), NamespaceVersion: uint64(namespaceVersion), + DefinitionSchema: definitionSchema, DefinitionFingerprint: fingerprint, + Volatility: volatility, NullPolicy: nullPolicy, SecurityType: securityType, + }, true, nil +} + +func readPythonRevision(ctx context.Context, bh BackgroundExec, functionID int64, snapshot *plan2.Snapshot) (pythonRevisionCatalogRow, error) { + bh.ClearExecResultSet() + query := pythonRevisionCatalogSQL(snapshot, functionID) + if err := bh.Exec(ctx, query); err != nil { + return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python catalog revision is unavailable: %w", err) + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + row, err := exactlyOneCatalogRow(ctx, rows, fmt.Sprintf("Python function %d active revision", functionID)) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + activeRevision, err := row.GetInt64(ctx, 0, 0) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + namespaceVersion, err := row.GetInt64(ctx, 0, 1) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + revision, err := row.GetInt64(ctx, 0, 2) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + if activeRevision <= 0 || namespaceVersion <= 0 || revision != activeRevision { + return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d has an invalid revision head", functionID) + } + getString := func(column uint64) (string, error) { return row.GetString(ctx, 0, column) } + canonicalInput, err := getString(3) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + returnDescriptor, err := getString(4) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + signatureKeySchemaVersion, err := row.GetInt64(ctx, 0, 5) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + signatureFingerprint, err := getString(6) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + args, err := getString(7) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + argTypes, err := getString(8) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + body, err := getString(9) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + language, err := getString(10) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + retType, err := getString(11) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + definitionSchema, err := row.GetInt64(ctx, 0, 12) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + abi, err := getString(13) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + adapter, err := getString(14) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + sdk, err := getString(15) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + nullPolicy, err := getString(16) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + volatility, err := getString(17) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + fingerprint, err := getString(18) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + artifact, err := getString(19) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + environment, err := getString(20) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + securityType, err := getString(21) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + baseSecurityType, err := getString(22) + if err != nil { + return pythonRevisionCatalogRow{}, err + } + if !strings.EqualFold(language, string(tree.PYTHON)) || definitionSchema != udf.PythonDefinitionSchemaVersion || abi != udf.PythonABIContract || adapter != udf.PythonAdapterVersion || sdk != udf.PythonSDKVersion || volatility != "VOLATILE" || !strings.EqualFold(securityType, "INVOKER") || !strings.EqualFold(baseSecurityType, securityType) { + return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision contract is not supported", functionID) + } + bodyDefinition, err := function.DecodePythonRoutineBody(body) + if err != nil { + return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision body is invalid: %w", functionID, err) + } + if bodyDefinition.ABIContract != abi || bodyDefinition.AdapterVersion != adapter || bodyDefinition.SDKVersion != sdk || bodyDefinition.NullPolicy != nullPolicy || bodyDefinition.ArtifactDigest != artifact || bodyDefinition.EnvironmentDigest != environment { + return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision metadata does not match its definition", functionID) + } + actualFingerprint, err := function.PythonRoutineFingerprint(body) + if err != nil { + return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision fingerprint cannot be computed: %w", functionID, err) + } + if fingerprint == "" || fingerprint != actualFingerprint { + return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision fingerprint mismatch", functionID) + } + expectedInput, expectedReturn, expectedSignature, err := function.PythonSignatureMetadata(bodyDefinition.ArgTypes, bodyDefinition.ReturnType) + if err != nil { + return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d signature cannot be computed: %w", functionID, err) + } + if signatureKeySchemaVersion != udf.PythonSignatureKeySchemaVersion || + canonicalInput != expectedInput || returnDescriptor != expectedReturn || signatureFingerprint != expectedSignature { + return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d identity descriptor metadata mismatch", functionID) + } + if argTypes != expectedInput { + return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision argument descriptor mismatch", functionID) + } + return pythonRevisionCatalogRow{ + Args: args, ArgTypes: argTypes, Body: body, Language: language, RetType: retType, + Revision: uint64(revision), NamespaceVersion: uint64(namespaceVersion), + CanonicalInputDescriptor: canonicalInput, ReturnDescriptor: returnDescriptor, + SignatureKeySchemaVersion: signatureKeySchemaVersion, SignatureFingerprint: signatureFingerprint, + DefinitionSchema: definitionSchema, ABIContract: abi, AdapterVersion: adapter, + SDKVersion: sdk, NullPolicy: nullPolicy, Volatility: volatility, DefinitionFingerprint: fingerprint, + ArtifactDigest: artifact, EnvironmentDigest: environment, SecurityType: securityType, + }, nil +} + +func pythonRevisionCatalogSQL(snapshot *plan2.Snapshot, functionID int64) string { + userFunctionTable := "mo_catalog.mo_user_defined_function" + revisionTable := "mo_catalog.mo_function_revisions" + if snapshot != nil && snapshot.TS != nil { + userFunctionTable += fmt.Sprintf(" {MO_TS = %d}", snapshot.TS.PhysicalTime) + revisionTable += fmt.Sprintf(" {MO_TS = %d}", snapshot.TS.PhysicalTime) + } + return fmt.Sprintf(`select f.active_revision, f.namespace_version, r.revision, + f.canonical_input_descriptor, f.return_descriptor, + f.signature_key_schema_version, f.signature_fingerprint, + r.args, r.arg_types, r.body, r.language, r.rettype, r.definition_schema_version, + r.abi_contract, r.adapter_version, r.sdk_version, r.null_policy, r.volatility, + r.definition_fingerprint, r.artifact_digest, r.environment_digest, + r.security_type, f.security_type + from %s f + join %s r + on r.function_id = f.function_id and r.revision = f.active_revision + and r.namespace_version = f.namespace_version + where f.function_id = %d;`, userFunctionTable, revisionTable, functionID) +} + func (tcc *TxnCompilerContext) ResolveVariable(varName string, isSystemVar, isGlobalVar bool) (varValue interface{}, err error) { stats := statistic.StatsInfoFromContext(tcc.execCtx.reqCtx) start := time.Now() diff --git a/pkg/frontend/computation_wrapper.go b/pkg/frontend/computation_wrapper.go index 24eaae6c00388..507206ef59ec4 100644 --- a/pkg/frontend/computation_wrapper.go +++ b/pkg/frontend/computation_wrapper.go @@ -1429,6 +1429,11 @@ func initExecuteStmtParamWithResolverInSession( currentDDLVersion := owner.getDDLVersion() change := prepareStmt.tempTableVersion != currentTempTableVersion || prepareStmt.ddlVersion != currentDDLVersion + routineChanged, routineErr := validateRoutinePlanDependencies(reqCtx, executionSes, executionPlan) + if routineErr != nil { + return nil, nil, nil, "", false, routineErr + } + change = change || routineChanged var preparedMetadataTS timestamp.Timestamp if catalogCache != nil { preparedMetadataTS = catalogCache.GetPreparedMetadataTS() diff --git a/pkg/frontend/mysql_cmd_executor.go b/pkg/frontend/mysql_cmd_executor.go index 60643d846472d..69a3b96c73038 100644 --- a/pkg/frontend/mysql_cmd_executor.go +++ b/pkg/frontend/mysql_cmd_executor.go @@ -4545,6 +4545,13 @@ func cachedPlanForInput(ses *Session, input *UserInput) *cachedPlan { return nil } cached := ses.getCachedPlan(input.getHash()) + if cached != nil && !cachedRoutinePlanDependenciesCurrent(ses, cached) { + // A cached plan carries exact routine revisions. Do not let an entry + // survive a replace/drop or an integrity mismatch merely because the + // ordinary table/schema generation is unchanged. + ses.removeCachedPlan(input.getHash()) + return nil + } // SELECT ... INTO @var changes the type of a session variable as part of // execution. A cached SELECT-INTO plan can therefore never be reused: it // may have been bound against the variable's pre-assignment type, and the @@ -5957,8 +5964,12 @@ func checkCachedStatementPlan(ses FeSession, execCtx *ExecCtx) error { return err } } - if flag { - if err := rebuildStaleCachedStatements(ses, execCtx); err != nil { + routineChanged, err := validateRoutinePlanDependencies(execCtx.reqCtx, ses, execCtx.cw.Plan()) + if err != nil { + return err + } + if flag || routineChanged { + if err = rebuildStaleCachedStatements(ses, execCtx); err != nil { return err } } diff --git a/pkg/frontend/pitr.go b/pkg/frontend/pitr.go index 85aa006b8891e..28b99c1f7c420 100644 --- a/pkg/frontend/pitr.go +++ b/pkg/frontend/pitr.go @@ -1650,6 +1650,21 @@ func reCreateTableWithPitr( fmt.Sprintf(" {MO_TS = %d}", ts), accountID, accountID, + tblInfo.createSql, + ) + } + if isCurrentFunctionRevisionCatalog(tblInfo) { + accountID, accountErr := defines.GetAccountId(ctx) + if accountErr != nil { + return accountErr + } + return restoreFunctionRevisionCatalogWithCurrentSchema( + ctx, + bh, + fmt.Sprintf(" {MO_TS = %d}", ts), + accountID, + accountID, + tblInfo.createSql, ) } ctx, err = restoreDDLContext(ctx, tblInfo.dbName, tblInfo.tblName) diff --git a/pkg/frontend/predefined.go b/pkg/frontend/predefined.go index 8d4ac9ed27337..9f245587e951a 100644 --- a/pkg/frontend/predefined.go +++ b/pkg/frontend/predefined.go @@ -99,10 +99,16 @@ var ( MoCatalogMoUserDefinedFunctionDDL = fmt.Sprintf(`create table mo_catalog.mo_user_defined_function ( function_id int auto_increment, + active_revision bigint unsigned not null default 0, + namespace_version bigint unsigned not null default 0, name varchar(100), owner int unsigned, args json, arg_types varchar(%d) not null default '', + canonical_input_descriptor varchar(%d) not null default '', + return_descriptor varchar(%d) not null default '', + signature_key_schema_version int not null default 0, + signature_fingerprint varchar(128) not null default '', retType varchar(20), body text, language varchar(20), @@ -111,14 +117,38 @@ var ( modified_time timestamp, created_time timestamp, type varchar(10), - security_type varchar(10), + security_type varchar(10) not null default 'DEFINER', comment varchar(5000), character_set_client varchar(64), collation_connection varchar(64), database_collation varchar(64), sql_mode varchar(1024) not null default 'PIPES_AS_CONCAT', primary key(function_id), - unique key name_db_arg_types(name, db, arg_types) + unique key name_db_arg_types_descriptor(name, db, arg_types, canonical_input_descriptor) + )`, types.MaxStringSize, types.MaxStringSize, types.MaxStringSize) + + MoCatalogMoFunctionRevisionDDL = fmt.Sprintf(`create table mo_catalog.mo_function_revisions ( + function_id bigint unsigned not null, + revision bigint unsigned not null, + namespace_version bigint unsigned not null, + name varchar(100) not null, + args json not null, + arg_types varchar(%d) not null default '', + rettype varchar(20) not null, + body text not null, + language varchar(20) not null, + definition_schema_version int not null default 0, + abi_contract varchar(64) not null default '', + adapter_version varchar(64) not null default '', + artifact_digest varchar(128) not null default '', + environment_digest varchar(128) not null default '', + sdk_version varchar(64) not null default '', + null_policy varchar(64) not null default '', + volatility varchar(20) not null default 'VOLATILE', + definition_fingerprint varchar(128) not null default '', + created_time timestamp, + security_type varchar(10) not null default 'DEFINER', + primary key(function_id, revision) )`, types.MaxStringSize) MoCatalogMoMysqlCompatibilityModeDDL = `create table mo_catalog.mo_mysql_compatibility_mode ( diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go new file mode 100644 index 0000000000000..6d7c9fa549789 --- /dev/null +++ b/pkg/frontend/python_udf_catalog_test.go @@ -0,0 +1,945 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package frontend + +import ( + "context" + "encoding/json" + "fmt" + "strconv" + "strings" + "testing" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/config" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/fileservice" + "github.com/matrixorigin/matrixone/pkg/sql/parsers" + "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" + "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" + "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + "github.com/matrixorigin/matrixone/pkg/udf" + pythonudf "github.com/matrixorigin/matrixone/pkg/udf/python" + "github.com/stretchr/testify/require" +) + +func TestPersistPythonReplaceRejectsLegacyHeadBeforeWriting(t *testing.T) { + ctx := context.Background() + functionID := int64(41) + languageSQL := fmt.Sprintf( + "select language from mo_catalog.mo_user_defined_function where function_id = %d;", + functionID, + ) + headSQL := fmt.Sprintf( + "select active_revision, namespace_version from mo_catalog.mo_user_defined_function where function_id = %d;", + functionID, + ) + bh := &backgroundExecTestWithHistory{} + bh.init() + language := &MysqlResultSet{} + languageColumn := &MysqlColumn{} + languageColumn.SetName("language") + languageColumn.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + language.AddColumn(languageColumn) + language.AddRow([]interface{}{"python"}) + bh.sql2result[languageSQL] = language + head := &MysqlResultSet{} + for _, name := range []string{"active_revision", "namespace_version"} { + column := &MysqlColumn{} + column.SetName(name) + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + head.AddColumn(column) + } + head.AddRow([]interface{}{int64(0), int64(0)}) + bh.sql2result[headSQL] = head + + err := persistUserDefinedFunction(ctx, bh, nil, 7, userDefinedFunctionDefinition{ + name: "legacy_python", + args: "[]", + argTypes: "[]", + retType: "int", + body: "legacy demo body", + lang: "python", + dbName: "db1", + }, &functionID) + + require.ErrorContains(t, err, "UNSUPPORTED_ROUTINE_VERSION") + require.ErrorContains(t, err, "DROP and CREATE") + require.Equal(t, []string{languageSQL, headSQL}, bh.executedSqls) +} + +func TestPersistFunctionReplaceRejectsLanguageChangeBeforeWriting(t *testing.T) { + ctx := context.Background() + functionID := int64(42) + languageSQL := fmt.Sprintf( + "select language from mo_catalog.mo_user_defined_function where function_id = %d;", + functionID, + ) + b := &backgroundExecTestWithHistory{} + b.init() + language := &MysqlResultSet{} + column := &MysqlColumn{} + column.SetName("language") + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + language.AddColumn(column) + language.AddRow([]interface{}{"SQL"}) + b.sql2result[languageSQL] = language + + err := persistUserDefinedFunction(ctx, b, nil, 7, userDefinedFunctionDefinition{ + name: "cross_language", + lang: "python", + body: "not published", + }, &functionID) + + require.ErrorContains(t, err, "cannot change language") + require.ErrorContains(t, err, "DROP and CREATE") + require.Equal(t, []string{languageSQL}, b.executedSqls) +} + +func TestPersistPythonReplaceRejectsSignatureChangeBeforeWriting(t *testing.T) { + ctx := context.Background() + functionID := int64(43) + languageSQL := fmt.Sprintf( + "select language from mo_catalog.mo_user_defined_function where function_id = %d;", + functionID, + ) + headSQL := fmt.Sprintf( + "select active_revision, namespace_version from mo_catalog.mo_user_defined_function where function_id = %d;", + functionID, + ) + bodySQL := fmt.Sprintf( + "select body from mo_catalog.mo_function_revisions where function_id = %d and revision = %d and namespace_version = %d;", + functionID, 1, 1, + ) + b := &backgroundExecTestWithHistory{} + b.init() + b.sql2result[languageSQL] = singleStringResult("language", "python") + head := &MysqlResultSet{} + for _, name := range []string{"active_revision", "namespace_version"} { + column := &MysqlColumn{} + column.SetName(name) + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + head.AddColumn(column) + } + head.AddRow([]interface{}{int64(1), int64(1)}) + b.sql2result[headSQL] = head + previous := pythonCatalogTestBody(t, types.T_int64) + b.sql2result[bodySQL] = singleStringResult("body", previous) + candidate := pythonCatalogTestBody(t, types.T_int32) + + err := persistUserDefinedFunction(ctx, b, nil, 7, userDefinedFunctionDefinition{ + name: "current_python", + args: "[]", + argTypes: "[]", + retType: "int", + body: candidate, + lang: "python", + dbName: "db1", + }, &functionID) + + require.ErrorContains(t, err, "cannot change input or return descriptor") + require.Equal(t, []string{languageSQL, headSQL, bodySQL}, b.executedSqls) +} + +func singleStringResult(name, value string) *MysqlResultSet { + result := &MysqlResultSet{} + column := &MysqlColumn{} + column.SetName(name) + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + result.AddColumn(column) + result.AddRow([]interface{}{value}) + return result +} + +func singleInt64Result(name string, value int64) *MysqlResultSet { + result := &MysqlResultSet{} + column := &MysqlColumn{} + column.SetName(name) + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + result.AddColumn(column) + result.AddRow([]interface{}{value}) + return result +} + +func pythonCatalogTestBody(t *testing.T, oid types.T) string { + t.Helper() + descriptor, err := function.NewPythonTypeDescriptor(oid.ToType()) + require.NoError(t, err) + source := "def f(ctx, value): return value" + environment, err := udf.PythonEnvironmentDigest() + require.NoError(t, err) + body, err := json.Marshal(function.PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "f", + Source: source, + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + ArtifactDigest: udf.PythonInlineArtifactDigest("f", source), + EnvironmentDigest: environment, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []function.PythonTypeDescriptor{descriptor}, + ReturnType: &descriptor, + }) + require.NoError(t, err) + return string(body) +} + +func TestPersistPythonCreateRejectsMalformedDefinitionBeforeWriting(t *testing.T) { + bh := &backgroundExecTestWithHistory{} + bh.init() + err := persistUserDefinedFunction(context.Background(), bh, &TenantInfo{User: "owner"}, 7, userDefinedFunctionDefinition{ + name: "broken_python", + args: "[]", + argTypes: "[]", + retType: "int", + body: "not current python routine json", + lang: "python", + dbName: "db1", + }, nil) + + require.ErrorContains(t, err, "UNSUPPORTED_ROUTINE_VERSION") + require.Empty(t, bh.executedSqls) +} + +func TestPersistPythonCreateIdentityLookupIncludesLanguage(t *testing.T) { + definition := userDefinedFunctionDefinition{ + name: "python_identity", + dbName: "db1", + canonicalInputDescriptor: "{\"types\":[]}", + lang: "python", + } + query := fmt.Sprintf( + `select function_id from mo_catalog.mo_user_defined_function where name = "%s" and db = "%s" and canonical_input_descriptor = "%s" and language = '%s' order by function_id desc limit 1;`, + escapeSQLStringForDoubleQuotes(definition.name), + escapeSQLStringForDoubleQuotes(definition.dbName), + escapeSQLStringForDoubleQuotes(definition.canonicalInputDescriptor), + escapeSQLStringForDoubleQuotes(definition.lang), + ) + b := &backgroundExecTest{} + b.init() + b.sql2result[query] = singleInt64Result("function_id", 101) + + id, err := findPersistedFunctionID(context.Background(), b, definition) + require.NoError(t, err) + require.Equal(t, int64(101), id) + require.Equal(t, []string{query}, b.executedSQLs) + require.Contains(t, b.executedSQLs[0], "language = 'python'") +} + +func TestPersistSQLCreateKeepsRollingCatalogCompatibility(t *testing.T) { + bh := &backgroundExecTestWithHistory{} + bh.init() + bh.sql2err[functionRevisionCatalogSchemaCheck] = moerr.NewNoSuchTableNoCtx( + "mo_catalog", "mo_function_revisions") + + err := persistUserDefinedFunction(context.Background(), bh, &TenantInfo{User: "owner"}, 7, userDefinedFunctionDefinition{ + name: "sql_function", + args: `[{"name":"value","type":"bigint"}]`, + argTypes: `["bigint"]`, + retType: "bigint", + body: "select value + 1", + lang: string(tree.SQL), + dbName: "db1", + }, nil) + require.NoError(t, err) + require.Len(t, bh.executedSqls, 2) + require.Equal(t, functionRevisionCatalogSchemaCheck, bh.executedSqls[0]) + require.NotContains(t, bh.executedSqls[1], "canonical_input_descriptor") + require.NotContains(t, bh.executedSqls[1], "mo_function_revisions") +} + +func TestFunctionRevisionCatalogAvailablePropagatesMalformedProbeResult(t *testing.T) { + bh := &backgroundExecTest{} + bh.init() + + available, err := functionRevisionCatalogAvailable(context.Background(), bh) + + require.ErrorContains(t, err, "it is not the type of result set") + require.False(t, available) +} + +func TestFunctionRevisionCatalogAvailableRejectsSplitOrEmptyProbe(t *testing.T) { + for _, tc := range []struct { + name string + results []interface{} + }{ + {name: "empty", results: []interface{}{}}, + {name: "split", results: []interface{}{emptyCatalogProbeResult(20), emptyCatalogProbeResult(20)}}, + } { + t.Run(tc.name, func(t *testing.T) { + bh := &backgroundExecTestWithResults{results: tc.results} + bh.init() + available, err := functionRevisionCatalogAvailable(context.Background(), bh) + require.ErrorContains(t, err, "expected exactly one") + require.False(t, available) + }) + } +} + +type backgroundExecTestWithResults struct { + backgroundExecTest + results []interface{} +} + +func (bt *backgroundExecTestWithResults) GetExecResultSet() []interface{} { + return bt.results +} + +func TestExactlyOneCatalogRowRejectsDuplicateOrSplitPointReads(t *testing.T) { + one := singleStringResult("value", "current") + row, err := exactlyOneCatalogRow(context.Background(), []ExecResult{one}, "routine point read") + require.NoError(t, err) + require.Same(t, one, row) + + one.AddRow([]interface{}{"duplicate"}) + _, err = exactlyOneCatalogRow(context.Background(), []ExecResult{one}, "routine point read") + require.ErrorContains(t, err, "expected exactly one") + + _, err = exactlyOneCatalogRow(context.Background(), []ExecResult{singleStringResult("value", "one"), singleStringResult("value", "two")}, "routine point read") + require.ErrorContains(t, err, "result sets") +} + +func TestPersistSQLCreatePublishesSharedRevisionWhenCatalogIsReady(t *testing.T) { + bh := &backgroundExecTestWithHistory{} + bh.init() + bh.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) + definition := userDefinedFunctionDefinition{ + name: "sql_revision", + args: `[{"name":"value","type":"bigint"}]`, + argTypes: `["bigint"]`, + retType: "bigint", + body: "select value + 1", + lang: string(tree.SQL), + dbName: "db1", + } + findSQL := `select function_id from mo_catalog.mo_user_defined_function where name = "sql_revision" and db = "db1" and arg_types = '["bigint"]' and language = 'sql' order by function_id desc limit 1;` + bh.sql2result[findSQL] = singleInt64Result("function_id", 91) + + err := persistUserDefinedFunction(context.Background(), bh, &TenantInfo{User: "owner"}, 7, definition, nil) + require.NoError(t, err) + require.Len(t, bh.executedSqls, 5) + require.Equal(t, functionRevisionCatalogSchemaCheck, bh.executedSqls[0]) + require.Contains(t, bh.executedSqls[1], "insert into mo_catalog.mo_user_defined_function") + require.Equal(t, findSQL, bh.executedSqls[2]) + require.Contains(t, bh.executedSqls[3], "insert into mo_catalog.mo_function_revisions") + require.Contains(t, bh.executedSqls[3], `"sql_revision"`) + require.Contains(t, bh.executedSqls[3], `"select value + 1"`) + require.Contains(t, bh.executedSqls[4], "active_revision = 1, namespace_version = 1") +} + +func TestPersistPythonCreatePublishesInvokerSecurityType(t *testing.T) { + bh := &backgroundExecTestWithHistory{} + bh.init() + body := pythonCatalogTestBody(t, types.T_int64) + decoded, err := function.DecodePythonRoutineBody(body) + require.NoError(t, err) + canonicalInput, _, _, err := function.PythonSignatureMetadata(decoded.ArgTypes, decoded.ReturnType) + require.NoError(t, err) + definition := userDefinedFunctionDefinition{ + name: "python_invoker", + args: `[{"name":"value","type":"bigint"}]`, + argTypes: `["bigint"]`, + retType: "bigint", + body: body, + lang: string(tree.PYTHON), + dbName: "db1", + canonicalInputDescriptor: canonicalInput, + } + findSQL := fmt.Sprintf( + `select function_id from mo_catalog.mo_user_defined_function where name = "%s" and db = "%s" and canonical_input_descriptor = "%s" and language = '%s' order by function_id desc limit 1;`, + escapeSQLStringForDoubleQuotes(definition.name), + escapeSQLStringForDoubleQuotes(definition.dbName), + escapeSQLStringForDoubleQuotes(canonicalInput), + escapeSQLStringForDoubleQuotes(definition.lang), + ) + bh.sql2result[findSQL] = singleInt64Result("function_id", 94) + + err = persistUserDefinedFunction(context.Background(), bh, &TenantInfo{User: "owner"}, 7, definition, nil) + require.NoError(t, err) + require.GreaterOrEqual(t, len(bh.executedSqls), 1) + require.Contains(t, bh.executedSqls[0], `"FUNCTION","INVOKER"`) + for _, sql := range bh.executedSqls { + if strings.Contains(sql, "mo_function_revisions") { + require.Contains(t, sql, `"python_invoker"`) + } + } +} + +func TestPublishRestoredPythonArtifactsRepublishesExactAccountArtifact(t *testing.T) { + const ( + sid = "python-artifact-restore-test" + targetAccount = uint32(27) + ) + InitServerLevelVars(sid) + oldPU := getPuIfPresent(sid) + t.Cleanup(func() { setPu(sid, oldPU) }) + + fs, err := fileservice.NewMemoryFS(defines.SharedFileServiceName, fileservice.DisabledCacheConfig, nil) + require.NoError(t, err) + setPu(sid, &config.ParameterUnit{FileService: fs}) + + body := pythonCatalogTestBody(t, types.T_int64) + decoded, err := function.DecodePythonRoutineBody(body) + require.NoError(t, err) + const query = "select language, artifact_digest, body from mo_catalog.mo_function_revisions order by function_id, revision;" + bh := &backgroundExecTest{} + bh.init() + bh.sql2result[query] = newMrsForRestoreStringRows( + []string{"language", "artifact_digest", "body"}, + [][]interface{}{{"python", decoded.ArtifactDigest, body}}, + ) + + err = publishRestoredPythonArtifacts( + t.Context(), sid, + bh, + defines.AttachAccountId(t.Context(), targetAccount), targetAccount, + ) + require.NoError(t, err) + + store, err := pythonudf.NewFileArtifactStore(fs, pythonudf.DefaultMaxArtifactBytes) + require.NoError(t, err) + resolved, err := store.Resolve(t.Context(), uint64(targetAccount), decoded.Handler, decoded.ArtifactDigest) + require.NoError(t, err) + require.Equal(t, decoded.Source, resolved) + _, err = store.Resolve(t.Context(), uint64(targetAccount-1), decoded.Handler, decoded.ArtifactDigest) + require.ErrorContains(t, err, "unavailable") +} + +func TestPublishRestoredPythonArtifactsRejectsMissingArtifactStore(t *testing.T) { + const sid = "python-artifact-restore-missing-store-test" + InitServerLevelVars(sid) + oldPU := getPuIfPresent(sid) + t.Cleanup(func() { setPu(sid, oldPU) }) + setPu(sid, &config.ParameterUnit{}) + + body := pythonCatalogTestBody(t, types.T_int64) + decoded, err := function.DecodePythonRoutineBody(body) + require.NoError(t, err) + const query = "select language, artifact_digest, body from mo_catalog.mo_function_revisions order by function_id, revision;" + bh := &backgroundExecTest{} + bh.init() + bh.sql2result[query] = newMrsForRestoreStringRows( + []string{"language", "artifact_digest", "body"}, + [][]interface{}{{"python", decoded.ArtifactDigest, body}}, + ) + + err = publishRestoredPythonArtifacts( + t.Context(), sid, bh, + defines.AttachAccountId(t.Context(), 27), 27, + ) + require.ErrorContains(t, err, "artifact store is required") +} + +func TestPersistSQLReplacePublishesNextImmutableRevision(t *testing.T) { + bh := &backgroundExecTestWithHistory{} + bh.init() + bh.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) + functionID := int64(92) + bh.sql2result[fmt.Sprintf( + "select language from mo_catalog.mo_user_defined_function where function_id = %d;", functionID, + )] = singleStringResult("language", string(tree.SQL)) + bh.sql2result[fmt.Sprintf( + "select active_revision, namespace_version from mo_catalog.mo_user_defined_function where function_id = %d;", functionID, + )] = func() *MysqlResultSet { + result := &MysqlResultSet{} + for _, name := range []string{"active_revision", "namespace_version"} { + column := &MysqlColumn{} + column.SetName(name) + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + result.AddColumn(column) + } + result.AddRow([]interface{}{int64(2), int64(5)}) + return result + }() + bh.sql2result[fmt.Sprintf( + "select rettype from mo_catalog.mo_user_defined_function where function_id = %d;", functionID, + )] = singleStringResult("rettype", "bigint") + + err := persistUserDefinedFunction(context.Background(), bh, &TenantInfo{User: "owner"}, 7, userDefinedFunctionDefinition{ + name: "sql_revision", + args: `[{"name":"value","type":"bigint"}]`, + argTypes: `["bigint"]`, + retType: "bigint", + body: "select value + 2", + lang: string(tree.SQL), + dbName: "db1", + }, &functionID) + require.NoError(t, err) + require.Len(t, bh.executedSqls, 7) + require.Equal(t, functionRevisionCatalogSchemaCheck, bh.executedSqls[0]) + require.Contains(t, bh.executedSqls[4], "body = \"select value + 2\"") + require.Contains(t, bh.executedSqls[5], "function_id, revision, namespace_version") + require.Contains(t, bh.executedSqls[5], ", 3, 6,") + require.Contains(t, bh.executedSqls[6], "active_revision = 3, namespace_version = 6") +} + +func TestReadSQLRevisionBindsActiveHeadAndRejectsTampering(t *testing.T) { + const functionID = int64(93) + const args = `[{"name":"value","type":"bigint"}]` + const argTypes = `["bigint"]` + const body = "select value + 1" + const retType = "bigint" + fingerprint, err := function.SQLRoutineFingerprint(body, argTypes, retType) + require.NoError(t, err) + baseSQL := fmt.Sprintf("select active_revision, namespace_version, security_type from mo_catalog.mo_user_defined_function where function_id = %d;", functionID) + revisionSQL := fmt.Sprintf("select revision, args, arg_types, body, rettype, language, definition_schema_version, definition_fingerprint, volatility, null_policy, security_type from mo_catalog.mo_function_revisions where function_id = %d and revision = 1 and namespace_version = 1;", functionID) + newBase := func() *MysqlResultSet { + result := &MysqlResultSet{} + for _, name := range []string{"active_revision", "namespace_version", "security_type"} { + column := &MysqlColumn{} + column.SetName(name) + if name == "security_type" { + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + } else { + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + } + result.AddColumn(column) + } + result.AddRow([]interface{}{int64(1), int64(1), "DEFINER"}) + return result + } + newRevision := func(candidateBody, candidateFingerprint string) *MysqlResultSet { + result := &MysqlResultSet{} + for _, name := range []string{"revision", "args", "arg_types", "body", "rettype", "language", "definition_schema_version", "definition_fingerprint", "volatility", "null_policy", "security_type"} { + column := &MysqlColumn{} + column.SetName(name) + if name == "revision" || name == "definition_schema_version" { + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + } else { + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + } + result.AddColumn(column) + } + result.AddRow([]interface{}{int64(1), args, argTypes, candidateBody, retType, string(tree.SQL), int64(udf.SQLDefinitionSchemaVersion), candidateFingerprint, "VOLATILE", udf.NullCallHandler, "DEFINER"}) + return result + } + + bh := &backgroundExecTest{} + bh.init() + bh.sql2result[baseSQL] = newBase() + bh.sql2result[revisionSQL] = newRevision(body, fingerprint) + got, found, err := readSQLRevision(context.Background(), bh, functionID, nil) + require.NoError(t, err) + require.True(t, found) + require.Equal(t, uint64(1), got.Revision) + require.Equal(t, body, got.Body) + require.Equal(t, fingerprint, got.DefinitionFingerprint) + + bh.init() + bh.sql2result[baseSQL] = newBase() + bh.sql2result[revisionSQL] = newRevision(body, strings.Repeat("a", 64)) + _, found, err = readSQLRevision(context.Background(), bh, functionID, nil) + require.ErrorContains(t, err, "fingerprint mismatch") + require.False(t, found) +} + +func TestEnsurePythonUdfCatalogReadyRequiresCurrentSchema(t *testing.T) { + bh := &backgroundExecTestWithHistory{} + bh.init() + bh.sql2result[pythonUdfCatalogIdentitySchemaCheck] = emptyCatalogProbeResult(6) + bh.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) + require.NoError(t, ensurePythonUdfCatalogReady(context.Background(), bh)) + require.Equal(t, []string{ + pythonUdfCatalogIdentitySchemaCheck, + functionRevisionCatalogSchemaCheck, + }, bh.executedSqls) + + bh.init() + bh.sql2result[pythonUdfCatalogIdentitySchemaCheck] = emptyCatalogProbeResult(6) + wantErr := fmt.Errorf("missing current revision catalog") + bh.sql2err[functionRevisionCatalogSchemaCheck] = wantErr + err := ensurePythonUdfCatalogReady(context.Background(), bh) + require.ErrorContains(t, err, "Python UDF catalog contract is not ready") + require.ErrorContains(t, err, wantErr.Error()) + require.Equal(t, []string{ + pythonUdfCatalogIdentitySchemaCheck, + functionRevisionCatalogSchemaCheck, + }, bh.executedSqls) + + bh.init() + bh.sql2result[pythonUdfCatalogIdentitySchemaCheck] = emptyCatalogProbeResult(1) + bh.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) + err = ensurePythonUdfCatalogReady(context.Background(), bh) + require.ErrorContains(t, err, "catalog probe returned 1 columns, expected 6") +} + +func emptyCatalogProbeResult(columnCount int) *MysqlResultSet { + result := &MysqlResultSet{} + for index := 0; index < columnCount; index++ { + column := &MysqlColumn{} + column.SetName(fmt.Sprintf("column_%d", index)) + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + result.AddColumn(column) + } + values := make([]interface{}, columnCount) + for index := range values { + values[index] = int64(0) + } + result.AddRow(values) + return result +} + +func TestValidateRestoredPythonRevisionCatalogChecksCurrentContract(t *testing.T) { + body := pythonCatalogTestBody(t, types.T_int64) + fingerprint, err := function.PythonRoutineFingerprint(body) + require.NoError(t, err) + decodedBody, err := function.DecodePythonRoutineBody(body) + require.NoError(t, err) + inputDescriptor, _, _, err := function.PythonSignatureMetadata(decodedBody.ArgTypes, decodedBody.ReturnType) + require.NoError(t, err) + query := fmt.Sprintf( + "select %s from %s order by function_id, revision;", + functionRevisionCatalogColumns, + qualifiedTableName(moCatalog, "mo_function_revisions"), + ) + result := &MysqlResultSet{} + for index := 0; index < 20; index++ { + column := &MysqlColumn{} + column.SetName(fmt.Sprintf("column_%d", index)) + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + result.AddColumn(column) + } + result.AddRow([]interface{}{ + "44", "1", "1", "f", `[ {"name":"value","type":"bigint"} ]`, inputDescriptor, "bigint", body, + "python", "1", udf.PythonABIContract, udf.PythonAdapterVersion, + udf.PythonInlineArtifactDigest("f", "def f(ctx, value): return value"), + func() string { + value, digestErr := udf.PythonEnvironmentDigest() + require.NoError(t, digestErr) + return value + }(), + udf.PythonSDKVersion, udf.NullCallHandler, "VOLATILE", fingerprint, "2026-09-11 00:00:00", "INVOKER", + }) + + bh := &backgroundExecTest{} + bh.init() + bh.sql2result[query] = result + require.NoError(t, validateRestoredFunctionRevisionCatalog(context.Background(), bh, context.Background())) + + result.Data[0][17] = "stale-fingerprint" + bh.init() + bh.sql2result[query] = result + require.ErrorContains(t, + validateRestoredFunctionRevisionCatalog(context.Background(), bh, context.Background()), + "fingerprint mismatch", + ) +} + +func TestValidateRestoredSharedRevisionCatalogAcceptsSQLAndRejectsTampering(t *testing.T) { + args := `[ {"name":"value","type":"bigint"} ]` + argTypes, err := userDefinedFunctionArgumentTypesFromJSON(args) + require.NoError(t, err) + body := "select value + 1" + retType := "bigint" + fingerprint, err := function.SQLRoutineFingerprint(body, argTypes, retType) + require.NoError(t, err) + query := fmt.Sprintf( + "select %s from %s order by function_id, revision;", + functionRevisionCatalogColumns, + qualifiedTableName(moCatalog, "mo_function_revisions"), + ) + newResult := func(body, digest string) *MysqlResultSet { + result := &MysqlResultSet{} + for index := 0; index < 20; index++ { + column := &MysqlColumn{} + column.SetName(fmt.Sprintf("column_%d", index)) + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + result.AddColumn(column) + } + result.AddRow([]interface{}{ + "45", "1", "1", "f", args, argTypes, retType, body, + string(tree.SQL), strconv.Itoa(udf.SQLDefinitionSchemaVersion), "", "", "", "", "", + udf.NullCallHandler, "VOLATILE", digest, "2026-09-11 00:00:00", "DEFINER", + }) + return result + } + + bh := &backgroundExecTest{} + bh.init() + bh.sql2result[query] = newResult(body, fingerprint) + require.NoError(t, validateRestoredFunctionRevisionCatalog(context.Background(), bh, context.Background())) + + bh.init() + bh.sql2result[query] = newResult("select value + 2", fingerprint) + require.ErrorContains(t, + validateRestoredFunctionRevisionCatalog(context.Background(), bh, context.Background()), + "fingerprint mismatch", + ) +} + +func TestValidateRestoredPythonCatalogHeadsBindsIdentityToActiveRevision(t *testing.T) { + body := pythonCatalogTestBody(t, types.T_int64) + decoded, err := function.DecodePythonRoutineBody(body) + require.NoError(t, err) + input, output, signature, err := function.PythonSignatureMetadata(decoded.ArgTypes, decoded.ReturnType) + require.NoError(t, err) + fingerprint, err := function.PythonRoutineFingerprint(body) + require.NoError(t, err) + query := `select cast(f.function_id as char), cast(f.active_revision as char), cast(f.namespace_version as char), + cast(coalesce(r.revision, 0) as char), cast(coalesce(r.namespace_version, 0) as char), + f.canonical_input_descriptor, f.return_descriptor, + cast(f.signature_key_schema_version as char), f.signature_fingerprint, + coalesce(r.arg_types, ''), coalesce(r.rettype, ''), coalesce(r.body, ''), + lower(f.language), coalesce(r.definition_fingerprint, ''), + coalesce(r.security_type, ''), coalesce(f.security_type, '') + from mo_catalog.mo_user_defined_function f + left join mo_catalog.mo_function_revisions r + on r.function_id = f.function_id and r.revision = f.active_revision + and r.namespace_version = f.namespace_version + where lower(f.language) in ("python", "sql") + order by f.function_id;` + newResult := func() *MysqlResultSet { + result := &MysqlResultSet{} + for index := 0; index < 16; index++ { + column := &MysqlColumn{} + column.SetName(fmt.Sprintf("column_%d", index)) + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + result.AddColumn(column) + } + result.AddRow([]interface{}{ + "44", "2", "3", "2", "3", input, output, + fmt.Sprintf("%d", udf.PythonSignatureKeySchemaVersion), signature, + input, "bigint", body, string(tree.PYTHON), fingerprint, + "INVOKER", "INVOKER", + }) + return result + } + + b := &backgroundExecTest{} + b.init() + b.sql2result[query] = newResult() + require.NoError(t, validateRestoredFunctionCatalogHeads(context.Background(), b, context.Background())) + + mutated := newResult() + mutated.Data[0][1] = "1" + b.init() + b.sql2result[query] = mutated + require.ErrorContains(t, + validateRestoredFunctionCatalogHeads(context.Background(), b, context.Background()), + "active revision does not exist", + ) + + mutated = newResult() + mutated.Data[0][8] = "stale-signature" + b.init() + b.sql2result[query] = mutated + require.ErrorContains(t, + validateRestoredFunctionCatalogHeads(context.Background(), b, context.Background()), + "head identity does not match", + ) +} + +func TestValidateRestoredSharedCatalogHeadsChecksSQLRevision(t *testing.T) { + args := `[ {"name":"value","type":"bigint"} ]` + argTypes, err := userDefinedFunctionArgumentTypesFromJSON(args) + require.NoError(t, err) + body := "select value + 1" + retType := "bigint" + fingerprint, err := function.SQLRoutineFingerprint(body, argTypes, retType) + require.NoError(t, err) + query := `select cast(f.function_id as char), cast(f.active_revision as char), cast(f.namespace_version as char), + cast(coalesce(r.revision, 0) as char), cast(coalesce(r.namespace_version, 0) as char), + f.canonical_input_descriptor, f.return_descriptor, + cast(f.signature_key_schema_version as char), f.signature_fingerprint, + coalesce(r.arg_types, ''), coalesce(r.rettype, ''), coalesce(r.body, ''), + lower(f.language), coalesce(r.definition_fingerprint, ''), + coalesce(r.security_type, ''), coalesce(f.security_type, '') + from mo_catalog.mo_user_defined_function f + left join mo_catalog.mo_function_revisions r + on r.function_id = f.function_id and r.revision = f.active_revision + and r.namespace_version = f.namespace_version + where lower(f.language) in ("python", "sql") + order by f.function_id;` + newResult := func(body, digest string) *MysqlResultSet { + result := &MysqlResultSet{} + for index := 0; index < 16; index++ { + column := &MysqlColumn{} + column.SetName(fmt.Sprintf("column_%d", index)) + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + result.AddColumn(column) + } + result.AddRow([]interface{}{ + "45", "1", "1", "1", "1", "", "", "0", "", + argTypes, retType, body, string(tree.SQL), digest, + "DEFINER", "DEFINER", + }) + return result + } + + b := &backgroundExecTest{} + b.init() + b.sql2result[query] = newResult(body, fingerprint) + require.NoError(t, validateRestoredFunctionCatalogHeads(context.Background(), b, context.Background())) + + b.init() + b.sql2result[query] = newResult("select value + 2", fingerprint) + require.ErrorContains(t, + validateRestoredFunctionCatalogHeads(context.Background(), b, context.Background()), + "head fingerprint does not match", + ) +} + +func TestReadPythonRevisionRequiresPersistedIdentitySignature(t *testing.T) { + body := pythonCatalogTestBody(t, types.T_int64) + inputDescriptor, returnDescriptor, signatureFingerprint, err := func() (string, string, string, error) { + decoded, decodeErr := function.DecodePythonRoutineBody(body) + if decodeErr != nil { + return "", "", "", decodeErr + } + return function.PythonSignatureMetadata(decoded.ArgTypes, decoded.ReturnType) + }() + require.NoError(t, err) + fingerprint, err := function.PythonRoutineFingerprint(body) + require.NoError(t, err) + environment, err := udf.PythonEnvironmentDigest() + require.NoError(t, err) + query := pythonRevisionCatalogSQL(nil, 44) + result := &MysqlResultSet{} + for index := 0; index < 23; index++ { + column := &MysqlColumn{} + column.SetName(fmt.Sprintf("column_%d", index)) + if index == 0 || index == 1 || index == 2 || index == 5 || index == 12 { + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + } else { + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + } + result.AddColumn(column) + } + result.AddRow([]interface{}{ + int64(1), int64(1), int64(1), inputDescriptor, returnDescriptor, int64(udf.PythonSignatureKeySchemaVersion), signatureFingerprint, + `[{"name":"value","type":"bigint"}]`, inputDescriptor, body, "python", "bigint", int64(udf.PythonDefinitionSchemaVersion), + udf.PythonABIContract, udf.PythonAdapterVersion, udf.PythonSDKVersion, udf.NullCallHandler, "VOLATILE", fingerprint, + udf.PythonInlineArtifactDigest("f", "def f(ctx, value): return value"), environment, + "INVOKER", "INVOKER", + }) + bh := &backgroundExecTest{} + bh.init() + bh.sql2result[query] = result + revision, err := readPythonRevision(context.Background(), bh, 44, nil) + require.NoError(t, err) + require.Equal(t, uint64(1), revision.Revision) + require.Equal(t, inputDescriptor, revision.CanonicalInputDescriptor) + + result.Data[0][3] = "[]" + bh.init() + bh.sql2result[query] = result + _, err = readPythonRevision(context.Background(), bh, 44, nil) + require.ErrorContains(t, err, "identity descriptor metadata mismatch") + + result.Data[0][3] = inputDescriptor + result.Data[0][8] = "[]" + bh.init() + bh.sql2result[query] = result + _, err = readPythonRevision(context.Background(), bh, 44, nil) + require.ErrorContains(t, err, "revision argument descriptor mismatch") + + result.Data[0][8] = inputDescriptor + result.Data[0][21] = "DEFINER" + bh.init() + bh.sql2result[query] = result + _, err = readPythonRevision(context.Background(), bh, 44, nil) + require.ErrorContains(t, err, "revision contract is not supported") +} + +func TestMatchUserDefinedFunctionCandidatesUsesExactPythonDescriptor(t *testing.T) { + decimal2, err := function.NewPythonTypeDescriptor(types.New(types.T_decimal64, 18, 2)) + require.NoError(t, err) + decimal6, err := function.NewPythonTypeDescriptor(types.New(types.T_decimal64, 18, 6)) + require.NoError(t, err) + returnType, err := function.NewPythonTypeDescriptor(types.T_decimal64.ToType()) + require.NoError(t, err) + exact2, err := canonicalPythonInputDescriptor([]function.PythonTypeDescriptor{decimal2}, &returnType) + require.NoError(t, err) + exact6, err := canonicalPythonInputDescriptor([]function.PythonTypeDescriptor{decimal6}, &returnType) + require.NoError(t, err) + + result := &MysqlResultSet{} + for _, name := range []string{"function_id", "args", "language", "arg_types", "canonical_input_descriptor"} { + column := &MysqlColumn{} + column.SetName(name) + if name == "function_id" { + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + } else { + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + } + result.AddColumn(column) + } + result.AddRow([]interface{}{int64(51), `[{"name":"value","type":"decimal"}]`, "python", exact2, exact2}) + result.AddRow([]interface{}{int64(52), `[{"name":"value","type":"decimal"}]`, "python", exact6, exact6}) + result.AddRow([]interface{}{int64(53), `[{"name":"value","type":"decimal"}]`, "sql", `["decimal"]`, ""}) + + ids, err := matchUserDefinedFunctionCandidates(context.Background(), []ExecResult{result}, "python", `["decimal"]`, exact2) + require.NoError(t, err) + // A SQL routine with the same logical signature still occupies the shared + // namespace. The exact descriptor distinguishes the two Python overloads; + // it does not permit an ambiguous SQL/Python pair. + require.Equal(t, []int64{51, 53}, ids) + + ids, err = matchUserDefinedFunctionCandidates(context.Background(), []ExecResult{result}, "sql", `["decimal"]`, `["decimal"]`) + require.NoError(t, err) + require.Equal(t, []int64{51, 52, 53}, ids) +} + +func TestMatchUserDefinedFunctionCandidatesRejectsSplitResultSets(t *testing.T) { + result := emptyCatalogProbeResult(5) + _, err := matchUserDefinedFunctionCandidates( + context.Background(), + []ExecResult{result, result}, + string(tree.PYTHON), `[]`, `[]`, + ) + require.ErrorContains(t, err, "function catalog candidate lookup returned 2 result sets") +} + +func TestMatchUserDefinedFunctionCandidatesAcceptsEmptyLookup(t *testing.T) { + ids, err := matchUserDefinedFunctionCandidates( + context.Background(), nil, + string(tree.PYTHON), `[]`, `[]`, + ) + require.NoError(t, err) + require.Empty(t, ids) +} + +func TestPythonDropSignatureUsesExactDescriptor(t *testing.T) { + statement, err := parsers.ParseOne(context.Background(), dialect.MYSQL, "drop function db.f(decimal(18,2))", 1) + require.NoError(t, err) + defer statement.Free() + drop, ok := statement.(*tree.DropFunction) + require.True(t, ok) + + decimal2, err := function.NewPythonTypeDescriptor(types.New(types.T_decimal128, 18, 2)) + require.NoError(t, err) + decimal6, err := function.NewPythonTypeDescriptor(types.New(types.T_decimal128, 18, 6)) + require.NoError(t, err) + returnType, err := function.NewPythonTypeDescriptor(types.T_decimal64.ToType()) + require.NoError(t, err) + makeBody := func(argument function.PythonTypeDescriptor) string { + source := "def f(ctx, value): return value" + environment, environmentErr := udf.PythonEnvironmentDigest() + require.NoError(t, environmentErr) + body, bodyErr := json.Marshal(function.PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "f", + Source: source, + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + ArtifactDigest: udf.PythonInlineArtifactDigest("f", source), + EnvironmentDigest: environment, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []function.PythonTypeDescriptor{argument}, + ReturnType: &returnType, + }) + require.NoError(t, bodyErr) + return string(body) + } + + require.True(t, pythonDropSignatureMatches(drop.Args, makeBody(decimal2))) + require.False(t, pythonDropSignatureMatches(drop.Args, makeBody(decimal6))) +} diff --git a/pkg/frontend/routine_plan_validation.go b/pkg/frontend/routine_plan_validation.go new file mode 100644 index 0000000000000..0c411455bc538 --- /dev/null +++ b/pkg/frontend/routine_plan_validation.go @@ -0,0 +1,509 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package frontend + +import ( + "context" + "fmt" + "sort" + "strconv" + "strings" + + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/defines" + planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" + "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + "github.com/matrixorigin/matrixone/pkg/udf" +) + +const ( + // Keep dependency validation bounded before allocating or opening a catalog + // transaction. The entry limit protects the result/accounting side; the + // depth limit protects the plan traversal side when a malformed plan nests + // background queries without contributing many routine entries. + maxRoutinePlanDependencies = 1024 + maxRoutinePlanDependencyBytes = 1 << 20 + maxRoutinePlanQueryDepth = 64 +) + +type routinePlanCatalogState struct { + activeRevision uint64 + namespaceVersion uint64 + databaseID uint64 + revision uint64 + language string + volatility string + nullPolicy string + fingerprint string + artifactDigest string + environmentDigest string + securityType string + identityChecked bool + identityValid bool +} + +func cachedRoutinePlanDependenciesCurrent(ses *Session, cached *cachedPlan) bool { + if cached == nil { + return true + } + if ses == nil { + // A cached plan that carries a routine dependency must never be reused + // without the tenant-aware catalog reader that can validate its exact + // revision. Plans without such metadata remain ordinary cache entries. + for _, p := range cached.plans { + dependencies, err := routinePlanDependencies(p) + if err != nil || len(dependencies) != 0 { + return false + } + } + return true + } + ctx := context.Background() + if tcc := ses.GetTxnCompileCtx(); tcc != nil && tcc.execCtx != nil { + ctx = tcc.GetContext() + } + for _, p := range cached.plans { + changed, err := validateRoutinePlanDependencies(ctx, ses, p) + if err != nil || changed { + return false + } + } + return true +} + +func routinePlanDependencies(p *planpb.Plan) ([]*planpb.RoutinePlanDependency, error) { + if p == nil { + return nil, nil + } + query := p.GetQuery() + if query == nil { + return nil, nil + } + + type queryFrame struct { + query *planpb.Query + depth int + next int + } + initialCapacity := len(query.GetRoutineDependencies()) + if initialCapacity > maxRoutinePlanDependencies { + initialCapacity = maxRoutinePlanDependencies + } + dependencies := make([]*planpb.RoutinePlanDependency, 0, initialCapacity) + dependencyBytes := 0 + stack := []queryFrame{{query: query}} + active := map[*planpb.Query]struct{}{query: {}} + for len(stack) != 0 { + frameIndex := len(stack) - 1 + frame := &stack[frameIndex] + if frame.next == 0 { + frameDependencies := frame.query.GetRoutineDependencies() + if len(dependencies)+len(frameDependencies) > maxRoutinePlanDependencies { + return nil, fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) + } + for _, dependency := range frameDependencies { + dependencySize := 1 + if dependency != nil { + dependencySize = dependency.ProtoSize() + } + if dependencySize > maxRoutinePlanDependencyBytes-dependencyBytes { + return nil, fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine dependency bytes exceed %d", maxRoutinePlanDependencyBytes) + } + dependencyBytes += dependencySize + } + dependencies = append(dependencies, frameDependencies...) + } + backgroundQueries := frame.query.GetBackgroundQueries() + if frame.next >= len(backgroundQueries) { + delete(active, frame.query) + stack = stack[:frameIndex] + continue + } + background := backgroundQueries[frame.next] + frame.next++ + if background == nil { + continue + } + if frame.depth+1 > maxRoutinePlanQueryDepth { + return nil, fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine dependency query nesting exceeds %d", maxRoutinePlanQueryDepth) + } + if _, exists := active[background]; exists { + return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency query graph contains a cycle") + } + active[background] = struct{}{} + stack = append(stack, queryFrame{query: background, depth: frame.depth + 1}) + } + return dependencies, nil +} + +// validateRoutinePlanDependencies checks a plan against the current catalog +// publication. It is deliberately identity based: execution never resolves a +// routine by name or latest revision, while cache/prepared reuse is rejected +// when the active namespace has moved since the plan was bound. +func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *planpb.Plan) (changed bool, err error) { + dependencies, err := routinePlanDependencies(p) + if err != nil { + return false, err + } + if len(dependencies) == 0 { + return false, nil + } + if len(dependencies) > maxRoutinePlanDependencies { + return false, fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) + } + if ses == nil { + return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation has no session") + } + accountID := ses.GetAccountId() + ids := make([]uint64, 0, len(dependencies)) + seen := make(map[uint64]struct{}, len(dependencies)) + for _, dependency := range dependencies { + if err := validateRoutinePlanDependencyShape(dependency, accountID); err != nil { + return false, err + } + id := dependency.FunctionRef.FunctionId + if _, ok := seen[id]; !ok { + seen[id] = struct{}{} + ids = append(ids, id) + } + } + sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) + + if ctx == nil { + ctx = context.Background() + } + ctx = defines.AttachAccountId(ctx, accountID) + // Background execution is still part of the real SQL call path (for + // procedures, derived statements, restore and other frontend-owned work). + // Validate through the execution session so the catalog read carries the + // same tenant and transaction context as the plan. GetBackgroundExec is + // implemented for both client and background sessions; rejecting the latter + // here would make a valid typed routine fail only when a statement is + // executed through a nested frontend pipeline. + bh := ses.GetBackgroundExec(ctx) + defer bh.Close() + if err = bh.Exec(ctx, "begin;"); err != nil { + return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation could not start: %w", err) + } + defer func() { err = finishTxn(ctx, bh, err) }() + + bh.ClearExecResultSet() + query := routinePlanCatalogSQL(ids, accountID) + if err = bh.Exec(ctx, query); err != nil { + return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation failed: %w", err) + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return false, err + } + catalogResult, err := exactlyOneCatalogResultSet(ctx, rows, "routine dependency catalog") + if err != nil { + return false, err + } + states := make(map[uint64]routinePlanCatalogState, len(rows)) + if catalogResult.GetRowCount() != 0 { + for row := uint64(0); row < catalogResult.GetRowCount(); row++ { + id, getErr := catalogResult.GetUint64(ctx, row, 0) + if getErr != nil { + return false, getErr + } + activeRevision, getErr := catalogResult.GetUint64(ctx, row, 1) + if getErr != nil { + return false, getErr + } + namespaceVersion, getErr := catalogResult.GetUint64(ctx, row, 2) + if getErr != nil { + return false, getErr + } + databaseID, getErr := catalogResult.GetUint64(ctx, row, 3) + if getErr != nil { + return false, getErr + } + revision, getErr := catalogResult.GetUint64(ctx, row, 4) + if getErr != nil { + return false, getErr + } + language, getErr := catalogResult.GetString(ctx, row, 5) + if getErr != nil { + return false, getErr + } + volatility, getErr := catalogResult.GetString(ctx, row, 6) + if getErr != nil { + return false, getErr + } + fingerprint, getErr := catalogResult.GetString(ctx, row, 7) + if getErr != nil { + return false, getErr + } + artifactDigest, getErr := catalogResult.GetString(ctx, row, 8) + if getErr != nil { + return false, getErr + } + environmentDigest, getErr := catalogResult.GetString(ctx, row, 9) + if getErr != nil { + return false, getErr + } + canonicalInput, getErr := catalogResult.GetString(ctx, row, 10) + if getErr != nil { + return false, getErr + } + returnDescriptor, getErr := catalogResult.GetString(ctx, row, 11) + if getErr != nil { + return false, getErr + } + signatureKeySchemaVersion, getErr := catalogResult.GetInt64(ctx, row, 12) + if getErr != nil { + return false, getErr + } + signatureFingerprint, getErr := catalogResult.GetString(ctx, row, 13) + if getErr != nil { + return false, getErr + } + body, getErr := catalogResult.GetString(ctx, row, 14) + if getErr != nil { + return false, getErr + } + revisionArgTypes, getErr := catalogResult.GetString(ctx, row, 15) + if getErr != nil { + return false, getErr + } + revisionRetType, getErr := catalogResult.GetString(ctx, row, 16) + if getErr != nil { + return false, getErr + } + definitionSchema, getErr := catalogResult.GetInt64(ctx, row, 17) + if getErr != nil { + return false, getErr + } + revisionABI, getErr := catalogResult.GetString(ctx, row, 18) + if getErr != nil { + return false, getErr + } + revisionAdapter, getErr := catalogResult.GetString(ctx, row, 19) + if getErr != nil { + return false, getErr + } + revisionSDK, getErr := catalogResult.GetString(ctx, row, 20) + if getErr != nil { + return false, getErr + } + revisionNullPolicy, getErr := catalogResult.GetString(ctx, row, 21) + if getErr != nil { + return false, getErr + } + revisionSecurityType, getErr := catalogResult.GetString(ctx, row, 22) + if getErr != nil { + return false, getErr + } + baseSecurityType, getErr := catalogResult.GetString(ctx, row, 23) + if getErr != nil { + return false, getErr + } + if !strings.EqualFold(revisionSecurityType, baseSecurityType) { + return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine %d has inconsistent revision and identity security contracts", id) + } + if strings.EqualFold(language, udf.LanguagePython) && !strings.EqualFold(revisionSecurityType, "INVOKER") { + return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine catalog security type is not INVOKER") + } + if strings.EqualFold(language, udf.LanguageSQL) && !strings.EqualFold(revisionSecurityType, "DEFINER") { + return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL routine catalog security type is not DEFINER") + } + identityValid := routinePlanCatalogIdentityValidForLanguage( + language, + body, fingerprint, signatureKeySchemaVersion, canonicalInput, + returnDescriptor, signatureFingerprint, revisionArgTypes, + revisionRetType, definitionSchema, revisionABI, revisionAdapter, + revisionSDK, revisionNullPolicy, + ) + if _, duplicate := states[id]; duplicate { + return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine catalog returned duplicate state for function %d", id) + } + states[id] = routinePlanCatalogState{ + activeRevision: activeRevision, namespaceVersion: namespaceVersion, + databaseID: databaseID, + revision: revision, language: language, volatility: volatility, nullPolicy: revisionNullPolicy, fingerprint: fingerprint, + artifactDigest: artifactDigest, environmentDigest: environmentDigest, + securityType: revisionSecurityType, + identityChecked: true, identityValid: identityValid, + } + } + } + return routinePlanDependenciesChanged(dependencies, states), nil +} + +// routinePlanCatalogIdentityValid verifies the complete immutable revision +// contract before a cached plan can be reused. Keeping this check separate +// from the SQL row decoder makes the important tamper cases directly +// testable: changing source, a descriptor, an ABI field, or a legacy logical +// return type while retaining the old fingerprint must invalidate the plan. +func routinePlanCatalogIdentityValid( + rawBody, fingerprint string, + signatureKeySchemaVersion int64, + canonicalInput, returnDescriptor, signatureFingerprint, revisionArgTypes, + revisionRetType string, + definitionSchema int64, + revisionABI, revisionAdapter, revisionSDK, revisionNullPolicy string, +) bool { + return routinePlanCatalogIdentityValidForLanguage( + udf.LanguagePython, + rawBody, fingerprint, signatureKeySchemaVersion, canonicalInput, + returnDescriptor, signatureFingerprint, revisionArgTypes, revisionRetType, + definitionSchema, revisionABI, revisionAdapter, revisionSDK, revisionNullPolicy, + ) +} + +func routinePlanCatalogIdentityValidForLanguage( + language string, + rawBody, fingerprint string, + signatureKeySchemaVersion int64, + canonicalInput, returnDescriptor, signatureFingerprint, revisionArgTypes, + revisionRetType string, + definitionSchema int64, + revisionABI, revisionAdapter, revisionSDK, revisionNullPolicy string, +) bool { + if strings.EqualFold(language, udf.LanguageSQL) { + expectedFingerprint, err := function.SQLRoutineFingerprint(rawBody, revisionArgTypes, revisionRetType) + return err == nil && + fingerprint == expectedFingerprint && + definitionSchema == int64(udf.SQLDefinitionSchemaVersion) && + revisionABI == "" && revisionAdapter == "" && revisionSDK == "" && + revisionNullPolicy == udf.NullCallHandler + } + if !strings.EqualFold(language, udf.LanguagePython) { + return false + } + decoded, err := function.DecodePythonRoutineBody(rawBody) + if err != nil { + return false + } + expectedInput, expectedReturn, expectedFingerprint, err := function.PythonSignatureMetadata(decoded.ArgTypes, decoded.ReturnType) + if err != nil { + return false + } + bodyFingerprint, err := function.PythonRoutineBodyFingerprint(decoded) + if err != nil { + return false + } + return bodyFingerprint == fingerprint && + signatureKeySchemaVersion == udf.PythonSignatureKeySchemaVersion && + canonicalInput == expectedInput && returnDescriptor == expectedReturn && signatureFingerprint == expectedFingerprint && + revisionArgTypes == expectedInput && + routineRevisionMetadataMatches(decoded, definitionSchema, revisionABI, revisionAdapter, revisionSDK, revisionNullPolicy) && + routineRevisionReturnTypeMatches(revisionRetType, decoded.ReturnType.Type().Oid) +} + +func routinePlanCatalogSQL(ids []uint64, accountID uint32) string { + values := make([]string, len(ids)) + for i, id := range ids { + values[i] = strconv.FormatUint(id, 10) + } + return fmt.Sprintf(`select f.function_id, f.active_revision, f.namespace_version, d.dat_id, + r.revision, r.language, r.volatility, r.definition_fingerprint, r.artifact_digest, + r.environment_digest, f.canonical_input_descriptor, f.return_descriptor, + f.signature_key_schema_version, f.signature_fingerprint, r.body, r.arg_types, + r.rettype, r.definition_schema_version, r.abi_contract, r.adapter_version, + r.sdk_version, r.null_policy, r.security_type, f.security_type + from mo_catalog.mo_user_defined_function f + join mo_catalog.mo_database d on d.datname = f.db and d.account_id = %d + join mo_catalog.mo_function_revisions r + on r.function_id = f.function_id and r.revision = f.active_revision + and r.namespace_version = f.namespace_version + where f.function_id in (%s);`, accountID, strings.Join(values, ",")) +} + +func routineRevisionMetadataMatches( + body function.PythonRoutineBody, + definitionSchema int64, + abi, adapter, sdk, nullPolicy string, +) bool { + return definitionSchema == int64(udf.PythonDefinitionSchemaVersion) && + abi == udf.PythonABIContract && adapter == udf.PythonAdapterVersion && + sdk == udf.PythonSDKVersion && nullPolicy == body.NullPolicy && + body.ABIContract == abi && body.AdapterVersion == adapter && body.SDKVersion == sdk +} + +func routineRevisionReturnTypeMatches(rettype string, oid types.T) bool { + if strings.EqualFold(rettype, oid.String()) { + return true + } + return strings.EqualFold(rettype, "decimal") && (oid == types.T_decimal64 || oid == types.T_decimal128) +} + +func validateRoutinePlanDependencyShape(dependency *planpb.RoutinePlanDependency, accountID uint32) error { + if dependency == nil || dependency.FunctionRef == nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency has no FunctionRef") + } + ref := dependency.FunctionRef + if ref.FunctionId == 0 || ref.Revision == 0 || ref.NamespaceVersion == 0 || + ref.AccountId != uint64(accountID) || ref.DatabaseId == 0 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency has an invalid catalog identity") + } + if dependency.ContractVersion != udf.RoutinePlanContractVersion || + !udf.IsSHA256Digest(dependency.DefinitionFingerprint) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency contract is incomplete") + } + if dependency.Volatility == "" || dependency.NullPolicy == "" || !dependency.MayError || dependency.Leakproof { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency semantic contract is incomplete") + } + switch strings.ToLower(dependency.Language) { + case udf.LanguagePython: + if dependency.SecurityMode != "INVOKER" { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine plan dependency must use INVOKER security") + } + if !udf.IsSHA256Digest(dependency.ArtifactDigest) || !udf.IsSHA256Digest(dependency.EnvironmentDigest) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine plan dependency integrity is incomplete") + } + case udf.LanguageSQL: + if dependency.SecurityMode == "" { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL routine plan dependency has no security mode") + } + if dependency.ArtifactDigest != "" || dependency.EnvironmentDigest != "" { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL routine plan dependency has external integrity fields") + } + default: + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency language %q is unsupported", dependency.Language) + } + return nil +} + +func routinePlanDependenciesChanged( + dependencies []*planpb.RoutinePlanDependency, + states map[uint64]routinePlanCatalogState, +) bool { + for _, dependency := range dependencies { + if dependency == nil || dependency.FunctionRef == nil { + return true + } + ref := dependency.FunctionRef + state, ok := states[ref.FunctionId] + if !ok || state.activeRevision == 0 || state.revision == 0 { + return true + } + if state.identityChecked && !state.identityValid { + return true + } + expectedSecurityMode := dependency.SecurityMode + if expectedSecurityMode == "" { + return true + } + if state.activeRevision != ref.Revision || state.revision != ref.Revision || + state.databaseID != ref.DatabaseId || + state.namespaceVersion != ref.NamespaceVersion || + state.volatility != dependency.Volatility || + state.nullPolicy != dependency.NullPolicy || + !strings.EqualFold(state.securityType, dependency.SecurityMode) || + (dependency.Language == udf.LanguagePython && expectedSecurityMode != "INVOKER") || + (dependency.Language == udf.LanguageSQL && expectedSecurityMode == "") || + dependency.MayError != true || dependency.Leakproof || + !strings.EqualFold(state.language, dependency.Language) || + state.fingerprint != dependency.DefinitionFingerprint || + state.artifactDigest != dependency.ArtifactDigest || + state.environmentDigest != dependency.EnvironmentDigest { + return true + } + } + return false +} diff --git a/pkg/frontend/routine_plan_validation_test.go b/pkg/frontend/routine_plan_validation_test.go new file mode 100644 index 0000000000000..bcabf01f4dd7d --- /dev/null +++ b/pkg/frontend/routine_plan_validation_test.go @@ -0,0 +1,304 @@ +// Copyright 2026 Matrix Origin +// +// 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 frontend + +import ( + "context" + "encoding/json" + "strings" + "testing" + + "github.com/matrixorigin/matrixone/pkg/container/types" + planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" + sqlplan "github.com/matrixorigin/matrixone/pkg/sql/plan" + "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/stretchr/testify/require" +) + +func testRoutinePlanDependency() *planpb.RoutinePlanDependency { + return &planpb.RoutinePlanDependency{ + FunctionRef: &planpb.FunctionRef{ + FunctionId: 41, + Revision: 7, + NamespaceVersion: 12, + AccountId: 9, + DatabaseId: 8, + }, + Language: udf.LanguagePython, + ContractVersion: udf.PythonPlanContractVersion, + DefinitionFingerprint: strings.Repeat("a", 64), + ArtifactDigest: strings.Repeat("b", 64), + EnvironmentDigest: strings.Repeat("c", 64), + Volatility: "VOLATILE", + NullPolicy: udf.NullCallHandler, + MayError: true, + SecurityMode: "INVOKER", + Leakproof: false, + } +} + +func testRoutinePlanState() routinePlanCatalogState { + return routinePlanCatalogState{ + activeRevision: 7, + namespaceVersion: 12, + databaseID: 8, + revision: 7, + language: udf.LanguagePython, + volatility: "VOLATILE", + nullPolicy: udf.NullCallHandler, + fingerprint: strings.Repeat("a", 64), + artifactDigest: strings.Repeat("b", 64), + environmentDigest: strings.Repeat("c", 64), + securityType: "INVOKER", + } +} + +func TestRoutinePlanDependenciesChangedRequiresExactPublication(t *testing.T) { + dependency := testRoutinePlanDependency() + state := testRoutinePlanState() + + require.False(t, routinePlanDependenciesChanged( + []*planpb.RoutinePlanDependency{dependency}, + map[uint64]routinePlanCatalogState{41: state}, + )) + + cases := []struct { + name string + mutate func(*routinePlanCatalogState) + }{ + {name: "active revision", mutate: func(s *routinePlanCatalogState) { + s.activeRevision++ + }}, + {name: "namespace", mutate: func(s *routinePlanCatalogState) { + s.namespaceVersion++ + }}, + {name: "database", mutate: func(s *routinePlanCatalogState) { + s.databaseID++ + }}, + {name: "revision", mutate: func(s *routinePlanCatalogState) { + s.revision++ + }}, + {name: "fingerprint", mutate: func(s *routinePlanCatalogState) { + s.fingerprint = strings.Repeat("d", 64) + }}, + {name: "artifact", mutate: func(s *routinePlanCatalogState) { + s.artifactDigest = strings.Repeat("d", 64) + }}, + {name: "environment", mutate: func(s *routinePlanCatalogState) { + s.environmentDigest = strings.Repeat("d", 64) + }}, + {name: "security", mutate: func(s *routinePlanCatalogState) { + s.securityType = "DEFINER" + }}, + {name: "language", mutate: func(s *routinePlanCatalogState) { + s.language = "sql" + }}, + {name: "volatility", mutate: func(s *routinePlanCatalogState) { + s.volatility = "IMMUTABLE" + }}, + {name: "missing", mutate: func(s *routinePlanCatalogState) { + s.activeRevision = 0 + }}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + changedState := state + tc.mutate(&changedState) + states := map[uint64]routinePlanCatalogState{41: changedState} + if tc.name == "missing" { + states = map[uint64]routinePlanCatalogState{} + } + require.True(t, routinePlanDependenciesChanged( + []*planpb.RoutinePlanDependency{dependency}, states)) + }) + } +} + +func TestValidateRoutinePlanDependencyShapeRejectsCrossAccountAndUnknownContracts(t *testing.T) { + require.NoError(t, validateRoutinePlanDependencyShape(testRoutinePlanDependency(), 9)) + + cases := []struct { + name string + mutate func(*planpb.RoutinePlanDependency) + }{ + {name: "cross account", mutate: func(d *planpb.RoutinePlanDependency) { + d.FunctionRef.AccountId = 10 + }}, + {name: "missing database", mutate: func(d *planpb.RoutinePlanDependency) { + d.FunctionRef.DatabaseId = 0 + }}, + {name: "unknown contract", mutate: func(d *planpb.RoutinePlanDependency) { + d.ContractVersion++ + }}, + {name: "missing integrity", mutate: func(d *planpb.RoutinePlanDependency) { + d.ArtifactDigest = "" + }}, + {name: "malformed digest", mutate: func(d *planpb.RoutinePlanDependency) { + d.DefinitionFingerprint = "definition-fingerprint" + }}, + {name: "missing identity", mutate: func(d *planpb.RoutinePlanDependency) { + d.FunctionRef = nil + }}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + dependency := testRoutinePlanDependency() + tc.mutate(dependency) + require.ErrorContains(t, + validateRoutinePlanDependencyShape(dependency, 9), + "UNSUPPORTED_ROUTINE_VERSION") + }) + } +} + +func TestRoutinePlanDependenciesIncludesBackgroundQueries(t *testing.T) { + dependency := testRoutinePlanDependency() + plan := &planpb.Plan{ + Plan: &planpb.Plan_Query{Query: &planpb.Query{ + RoutineDependencies: []*planpb.RoutinePlanDependency{dependency}, + BackgroundQueries: []*planpb.Query{{ + RoutineDependencies: []*planpb.RoutinePlanDependency{testRoutinePlanDependency()}, + }}, + }}, + } + dependencies, err := routinePlanDependencies(plan) + require.NoError(t, err) + require.Len(t, dependencies, 2) + require.Same(t, dependency, dependencies[0]) + require.Equal(t, dependency, dependencies[0]) +} + +func TestRoutinePlanDependenciesRejectsUnboundedQueryGraph(t *testing.T) { + root := &planpb.Query{} + current := root + for depth := 0; depth < maxRoutinePlanQueryDepth+1; depth++ { + next := &planpb.Query{} + current.BackgroundQueries = []*planpb.Query{next} + current = next + } + + _, err := routinePlanDependencies(&planpb.Plan{ + Plan: &planpb.Plan_Query{Query: root}, + }) + require.ErrorContains(t, err, "query nesting exceeds") +} + +func TestRoutinePlanDependenciesRejectsOversizedClosureAndCycles(t *testing.T) { + root := &planpb.Query{} + root.RoutineDependencies = make([]*planpb.RoutinePlanDependency, maxRoutinePlanDependencies+1) + _, err := routinePlanDependencies(&planpb.Plan{ + Plan: &planpb.Plan_Query{Query: root}, + }) + require.ErrorContains(t, err, "dependency count exceeds") + + oversized := testRoutinePlanDependency() + oversized.DefinitionFingerprint = strings.Repeat("a", maxRoutinePlanDependencyBytes) + _, err = routinePlanDependencies(&planpb.Plan{ + Plan: &planpb.Plan_Query{Query: &planpb.Query{ + RoutineDependencies: []*planpb.RoutinePlanDependency{oversized}, + }}, + }) + require.ErrorContains(t, err, "dependency bytes exceed") + + cycle := &planpb.Query{} + cycle.BackgroundQueries = []*planpb.Query{cycle} + _, err = routinePlanDependencies(&planpb.Plan{ + Plan: &planpb.Plan_Query{Query: cycle}, + }) + require.ErrorContains(t, err, "graph contains a cycle") +} + +func TestCachedRoutinePlanWithDependencyRequiresCatalogSession(t *testing.T) { + plan := &planpb.Plan{Plan: &planpb.Plan_Query{Query: &planpb.Query{ + RoutineDependencies: []*planpb.RoutinePlanDependency{testRoutinePlanDependency()}, + }}} + plain := &cachedPlan{plans: []*sqlplan.Plan{{Plan: &planpb.Plan_Query{Query: &planpb.Query{}}}}} + withRoutine := &cachedPlan{plans: []*sqlplan.Plan{plan}} + require.True(t, cachedRoutinePlanDependenciesCurrent(nil, plain)) + require.False(t, cachedRoutinePlanDependenciesCurrent(nil, withRoutine)) +} + +func TestExactlyOneCatalogResultSetRequiresOneCompleteResultSet(t *testing.T) { + ctx := context.Background() + _, err := exactlyOneCatalogResultSet(ctx, nil, "routine dependency catalog") + require.ErrorContains(t, err, "expected exactly one") + + _, err = exactlyOneCatalogResultSet(ctx, []ExecResult{nil, nil}, "routine dependency catalog") + require.ErrorContains(t, err, "returned 2 result sets") + + result := singleInt64Result("function_id", 41) + got, err := exactlyOneCatalogResultSet(ctx, []ExecResult{result}, "routine dependency catalog") + require.NoError(t, err) + require.Same(t, result, got) +} + +func TestRoutinePlanCatalogIdentityRejectsTamperedRevisionBody(t *testing.T) { + raw := pythonCatalogTestBody(t, types.T_int64) + body, err := function.DecodePythonRoutineBody(raw) + require.NoError(t, err) + input, output, signature, err := function.PythonSignatureMetadata(body.ArgTypes, body.ReturnType) + require.NoError(t, err) + fingerprint, err := function.PythonRoutineBodyFingerprint(body) + require.NoError(t, err) + + valid := func(candidate string) bool { + return routinePlanCatalogIdentityValid( + candidate, fingerprint, udf.PythonSignatureKeySchemaVersion, + input, output, signature, input, "bigint", + udf.PythonDefinitionSchemaVersion, udf.PythonABIContract, + udf.PythonAdapterVersion, udf.PythonSDKVersion, udf.NullCallHandler, + ) + } + require.True(t, valid(raw)) + + body.Source = "def f(ctx, value): return value + 1" + tampered, err := json.Marshal(body) + require.NoError(t, err) + require.False(t, valid(string(tampered)), "retaining an old revision fingerprint must invalidate the cached plan") + + require.False(t, routinePlanCatalogIdentityValid( + raw, fingerprint, udf.PythonSignatureKeySchemaVersion, + input, output, signature, input+" ", "bigint", + udf.PythonDefinitionSchemaVersion, udf.PythonABIContract, + udf.PythonAdapterVersion, udf.PythonSDKVersion, udf.NullCallHandler, + )) +} + +func TestRoutinePlanCatalogIdentityAcceptsAndRejectsSQLRevision(t *testing.T) { + const ( + body = "select value + 1" + argTypes = "[\"bigint\"]" + retType = "bigint" + ) + fingerprint, err := function.SQLRoutineFingerprint(body, argTypes, retType) + require.NoError(t, err) + valid := func(candidateBody, candidateArgs, candidateReturn, candidateFingerprint string) bool { + return routinePlanCatalogIdentityValidForLanguage( + udf.LanguageSQL, + candidateBody, candidateFingerprint, 0, "", "", "", + candidateArgs, candidateReturn, udf.SQLDefinitionSchemaVersion, + "", "", "", udf.NullCallHandler, + ) + } + require.True(t, valid(body, argTypes, retType, fingerprint)) + require.False(t, valid("select value + 2", argTypes, retType, fingerprint)) + require.False(t, valid(body, argTypes, "int", fingerprint)) + require.False(t, valid(body, argTypes, retType, strings.Repeat("a", 64))) + require.False(t, routinePlanCatalogIdentityValidForLanguage( + "lua", body, fingerprint, 0, "", "", "", argTypes, retType, + udf.SQLDefinitionSchemaVersion, "", "", "", udf.NullCallHandler, + )) +} diff --git a/pkg/frontend/snapshot.go b/pkg/frontend/snapshot.go index 00b24f577a65d..1babc52d1ce32 100644 --- a/pkg/frontend/snapshot.go +++ b/pkg/frontend/snapshot.go @@ -126,6 +126,7 @@ var ( "mo_role_privs": systemCatalogRestoreRebuild, "mo_role_rule": systemCatalogRestoreCopy, "mo_user_defined_function": systemCatalogRestoreCopy, + "mo_function_revisions": systemCatalogRestoreCopy, "mo_stored_procedure": systemCatalogRestoreCopy, "mo_mysql_compatibility_mode": systemCatalogRestoreSkip, "mo_stages": systemCatalogRestoreCopy, @@ -2096,7 +2097,20 @@ func recreateTable( sourceSnapshot = fmt.Sprintf(" {SNAPSHOT = %s}", escapeSQLString(snapshotName)) } return restoreUserDefinedFunctionCatalogWithCurrentSchema( - ctx, bh, sourceSnapshot, curAccountID, toAccountId, + ctx, bh, sourceSnapshot, curAccountID, toAccountId, tblInfo.createSql, + ) + } + if isCurrentFunctionRevisionCatalog(tblInfo) { + curAccountID, accountErr := defines.GetAccountId(ctx) + if accountErr != nil { + return accountErr + } + sourceSnapshot := fmt.Sprintf(" {MO_TS = %d}", snapshotTs) + if curAccountID != toAccountId { + sourceSnapshot = fmt.Sprintf(" {SNAPSHOT = %s}", escapeSQLString(snapshotName)) + } + return restoreFunctionRevisionCatalogWithCurrentSchema( + ctx, bh, sourceSnapshot, curAccountID, toAccountId, tblInfo.createSql, ) } ctx, err = restoreDDLContext(ctx, tblInfo.dbName, tblInfo.tblName) diff --git a/pkg/frontend/snapshot_catalog_restore.go b/pkg/frontend/snapshot_catalog_restore.go index c7b78b5b35610..145fb0187623b 100644 --- a/pkg/frontend/snapshot_catalog_restore.go +++ b/pkg/frontend/snapshot_catalog_restore.go @@ -16,6 +16,7 @@ package frontend import ( "context" + "encoding/json" "fmt" "strconv" "strings" @@ -24,6 +25,9 @@ import ( "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/pubsub" "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + "github.com/matrixorigin/matrixone/pkg/udf" + pythonudf "github.com/matrixorigin/matrixone/pkg/udf/python" ) type systemCatalogRestorePolicy uint8 @@ -79,10 +83,27 @@ var systemCatalogPostRestoreHandlers = []systemCatalogPostRestoreHandler{ const rolePrivilegeRestoreInsertBatchSize = 256 -const userDefinedFunctionCatalogColumns = `function_id, name, owner, args, arg_types, retType, body, language, db, definer, modified_time, created_time, type, security_type, comment, character_set_client, collation_connection, database_collation, sql_mode` +const userDefinedFunctionCatalogColumns = `function_id, active_revision, namespace_version, name, owner, args, arg_types, canonical_input_descriptor, return_descriptor, signature_key_schema_version, signature_fingerprint, retType, body, language, db, definer, modified_time, created_time, type, security_type, comment, character_set_client, collation_connection, database_collation, sql_mode` -const userDefinedFunctionCatalogSourceColumns = `function_id, name, owner, args, ` + - catalog.UserDefinedFunctionArgumentTypesSQL + `, retType, body, language, db, definer, modified_time, created_time, type, security_type, comment, character_set_client, collation_connection, database_collation, sql_mode` +const userDefinedFunctionCatalogSourceColumns = `function_id, active_revision, namespace_version, name, owner, args, ` + + catalog.UserDefinedFunctionArgumentTypesSQL + `, canonical_input_descriptor, return_descriptor, signature_key_schema_version, signature_fingerprint, retType, body, language, db, definer, modified_time, created_time, type, security_type, comment, character_set_client, collation_connection, database_collation, sql_mode` + +// userDefinedFunctionCatalogRevisionSourceColumns preserves immutable heads +// from a snapshot that has the revision columns but predates the exact +// descriptor identity fields. Python rows from such a snapshot remain +// rejected by the current resolver because their identity metadata is absent; +// ordinary SQL rows retain their historical catalog behavior. +const userDefinedFunctionCatalogRevisionSourceColumns = `function_id, active_revision, namespace_version, name, owner, args, ` + + catalog.UserDefinedFunctionArgumentTypesSQL + `, '', '', 0, '', retType, body, language, db, definer, modified_time, created_time, type, security_type, comment, character_set_client, collation_connection, database_collation, sql_mode` + +// userDefinedFunctionCatalogLegacySourceColumns is used for snapshots whose +// historical table predates immutable revision heads. Such rows remain +// usable for existing SQL catalog behavior, while the new Python resolver +// rejects the zero revision and requires an explicit CREATE/replace. +const userDefinedFunctionCatalogLegacySourceColumns = `function_id, 0, 0, name, owner, args, ` + + catalog.UserDefinedFunctionArgumentTypesSQL + `, '', '', 0, '', retType, body, language, db, definer, modified_time, created_time, type, security_type, comment, character_set_client, collation_connection, database_collation, sql_mode` + +const functionRevisionCatalogColumns = `function_id, revision, namespace_version, name, args, arg_types, rettype, body, language, definition_schema_version, abi_contract, adapter_version, artifact_digest, environment_digest, sdk_version, null_policy, volatility, definition_fingerprint, created_time, security_type` // isCurrentSchemaUserDefinedFunctionCatalog identifies the catalog whose // schema is owned by the running binary. Restoring a historical CREATE TABLE @@ -92,6 +113,14 @@ func isCurrentSchemaUserDefinedFunctionCatalog(tblInfo *tableInfo) bool { return tblInfo != nil && tblInfo.dbName == moCatalog && tblInfo.tblName == "mo_user_defined_function" } +// isCurrentFunctionRevisionCatalog identifies the immutable shared revision +// catalog whose schema is owned by the running binary. A historical CREATE +// TABLE must never replace it: SQL and Python resolvers need every contract +// column to reject stale or partially restored definitions before execution. +func isCurrentFunctionRevisionCatalog(tblInfo *tableInfo) bool { + return tblInfo != nil && tblInfo.dbName == moCatalog && tblInfo.tblName == "mo_function_revisions" +} + // restoreUserDefinedFunctionCatalogWithCurrentSchema restores historical UDF // rows into the current catalog shape. The source may predate arg_types, so // the copy deliberately derives it from args through the same ByteJson SQL @@ -103,6 +132,7 @@ func restoreUserDefinedFunctionCatalogWithCurrentSchema( sourceSnapshot string, sourceAccount uint32, targetAccount uint32, + sourceCreateSQL string, ) error { targetCtx := defines.AttachAccountId(ctx, targetAccount) tableName := qualifiedTableName(moCatalog, "mo_user_defined_function") @@ -115,11 +145,22 @@ func restoreUserDefinedFunctionCatalogWithCurrentSchema( return err } + sourceColumns := userDefinedFunctionCatalogLegacySourceColumns + lowerCreateSQL := strings.ToLower(sourceCreateSQL) + if strings.Contains(lowerCreateSQL, "active_revision") && strings.Contains(lowerCreateSQL, "namespace_version") { + sourceColumns = userDefinedFunctionCatalogRevisionSourceColumns + if strings.Contains(lowerCreateSQL, "canonical_input_descriptor") && + strings.Contains(lowerCreateSQL, "return_descriptor") && + strings.Contains(lowerCreateSQL, "signature_key_schema_version") && + strings.Contains(lowerCreateSQL, "signature_fingerprint") { + sourceColumns = userDefinedFunctionCatalogSourceColumns + } + } copySQL := fmt.Sprintf( "insert into %s (%s) select %s from %s%s", tableName, userDefinedFunctionCatalogColumns, - userDefinedFunctionCatalogSourceColumns, + sourceColumns, tableName, sourceSnapshot, ) @@ -129,6 +170,285 @@ func restoreUserDefinedFunctionCatalogWithCurrentSchema( return bh.ExecRestore(targetCtx, copySQL, sourceAccount, targetAccount) } +// validateRestoredFunctionRevisionCatalog validates the shared immutable +// revision table. Each language owns a distinct typed implementation contract; +// accepting a SQL row as Python (or vice versa) would make restore fail for a +// valid mixed catalog or publish a row that the resolver cannot execute. +func validateRestoredFunctionRevisionCatalog( + ctx context.Context, + bh BackgroundExec, + targetCtx context.Context, +) error { + tableName := qualifiedTableName(moCatalog, "mo_function_revisions") + query := fmt.Sprintf( + "select %s from %s order by function_id, revision;", + functionRevisionCatalogColumns, + tableName, + ) + rows, err := getStringColsList(targetCtx, bh, query, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision catalog cannot be validated: %w", err) + } + for rowIndex, row := range rows { + if len(row) != 20 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision row %d has %d columns", rowIndex, len(row)) + } + functionID, err := strconv.ParseUint(row[0], 10, 64) + if err != nil || functionID == 0 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision row %d has an invalid function identity", rowIndex) + } + revision, err := strconv.ParseUint(row[1], 10, 64) + if err != nil || revision == 0 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has an invalid revision", functionID) + } + namespace, err := strconv.ParseUint(row[2], 10, 64) + if err != nil || namespace == 0 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has an invalid namespace version", functionID) + } + definitionSchema, err := strconv.Atoi(row[9]) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored function %d revision %d has an invalid definition schema", functionID, revision) + } + if strings.EqualFold(row[8], udf.LanguageSQL) { + if err := validateRestoredSQLFunctionRevision(functionID, revision, row, definitionSchema); err != nil { + return err + } + continue + } + if !strings.EqualFold(row[8], udf.LanguagePython) || + definitionSchema != udf.PythonDefinitionSchemaVersion || + row[10] != udf.PythonABIContract || + row[11] != udf.PythonAdapterVersion || + row[14] != udf.PythonSDKVersion || + !strings.EqualFold(row[16], "VOLATILE") || + !strings.EqualFold(row[19], "INVOKER") { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored function %d revision %d has an unsupported execution contract", functionID, revision) + } + + body, err := function.DecodePythonRoutineBody(row[7]) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d body is invalid: %w", functionID, revision, err) + } + if body.DefinitionSchemaVersion != definitionSchema || + body.ABIContract != row[10] || + body.AdapterVersion != row[11] || + body.ArtifactDigest != row[12] || + body.EnvironmentDigest != row[13] || + body.SDKVersion != row[14] || + body.NullPolicy != row[15] { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d metadata does not match its definition", functionID, revision) + } + fingerprint, err := function.PythonRoutineFingerprint(row[7]) + if err != nil || row[17] == "" || row[17] != fingerprint { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d fingerprint mismatch", functionID, revision) + } + // `args` retains the shared logical names while `arg_types` in the + // current Python revision is the exact descriptor identity used for + // overload selection. Validate both representations independently; + // comparing arg_types with the logical OID list would reject every + // current Python revision after restore. + if _, err := userDefinedFunctionArgumentTypesFromJSON(row[4]); err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d arguments are invalid: %w", functionID, revision, err) + } + var args []*function.Arg + if err := json.Unmarshal([]byte(row[4]), &args); err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d arguments are invalid: %w", functionID, revision, err) + } + routine := &function.Udf{ + Language: udf.LanguagePython, + Args: args, + RetType: row[6], + PythonArgTypes: append([]function.PythonTypeDescriptor(nil), body.ArgTypes...), + PythonReturnType: body.ReturnType, + } + if err := routine.ValidatePythonTypeContract(); err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d type contract mismatch: %w", functionID, revision, err) + } + if err := routine.ValidatePythonCatalogSignature(); err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d catalog signature mismatch: %w", functionID, revision, err) + } + expectedInput, _, _, err := function.PythonSignatureMetadata(body.ArgTypes, body.ReturnType) + if err != nil || row[5] != expectedInput { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d argument descriptor mismatch", functionID, revision) + } + } + return nil +} + +func validateRestoredSQLFunctionRevision(functionID, revision uint64, row []string, definitionSchema int) error { + if definitionSchema != udf.SQLDefinitionSchemaVersion || + row[10] != "" || row[11] != "" || row[12] != "" || row[13] != "" || row[14] != "" || + row[15] != udf.NullCallHandler || !strings.EqualFold(row[16], "VOLATILE") || + !strings.EqualFold(row[19], "DEFINER") { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d has an unsupported execution contract", functionID, revision) + } + logicalArgTypes, err := userDefinedFunctionArgumentTypesFromJSON(row[4]) + if err != nil || logicalArgTypes != row[5] { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d argument metadata is invalid", functionID, revision) + } + fingerprint, err := function.SQLRoutineFingerprint(row[7], row[5], row[6]) + if err != nil || row[17] == "" || row[17] != fingerprint { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d fingerprint mismatch", functionID, revision) + } + return nil +} + +// validateRestoredFunctionCatalogHeads checks the other half of the shared +// immutable publication. The revision validator proves each copied row is +// self-consistent; this check proves that the active head points at that exact +// row after restore. +func validateRestoredFunctionCatalogHeads( + ctx context.Context, + bh BackgroundExec, + targetCtx context.Context, +) error { + query := `select cast(f.function_id as char), cast(f.active_revision as char), cast(f.namespace_version as char), + cast(coalesce(r.revision, 0) as char), cast(coalesce(r.namespace_version, 0) as char), + f.canonical_input_descriptor, f.return_descriptor, + cast(f.signature_key_schema_version as char), f.signature_fingerprint, + coalesce(r.arg_types, ''), coalesce(r.rettype, ''), coalesce(r.body, ''), + lower(f.language), coalesce(r.definition_fingerprint, ''), + coalesce(r.security_type, ''), coalesce(f.security_type, '') + from mo_catalog.mo_user_defined_function f + left join mo_catalog.mo_function_revisions r + on r.function_id = f.function_id and r.revision = f.active_revision + and r.namespace_version = f.namespace_version + where lower(f.language) in ("python", "sql") + order by f.function_id;` + rows, err := getStringColsList(targetCtx, bh, query, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog heads cannot be validated: %w", err) + } + for rowIndex, row := range rows { + if len(row) != 16 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog head row %d has %d columns", rowIndex, len(row)) + } + functionID, err := strconv.ParseUint(row[0], 10, 64) + if err != nil || functionID == 0 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog head row %d has an invalid function identity", rowIndex) + } + activeRevision, err := strconv.ParseUint(row[1], 10, 64) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored routine function %d has an invalid active revision: %v", functionID, err) + } + namespaceVersion, err := strconv.ParseUint(row[2], 10, 64) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored routine function %d has an invalid namespace version: %v", functionID, err) + } + language := strings.ToLower(row[12]) + if language == udf.LanguageSQL && activeRevision == 0 && namespaceVersion == 0 { + // Legacy SQL rows predate the shared revision table and retain their + // old execution path. A current SQL head is validated below. + continue + } + if activeRevision == 0 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d has no active immutable revision", language, functionID) + } + if namespaceVersion == 0 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d has an invalid namespace version", language, functionID) + } + revision, err := strconv.ParseUint(row[3], 10, 64) + if err != nil || revision != activeRevision { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d active revision does not exist", language, functionID) + } + revisionNamespace, err := strconv.ParseUint(row[4], 10, 64) + if err != nil || revisionNamespace != namespaceVersion { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d head namespace does not match its revision", language, functionID) + } + if language == udf.LanguageSQL { + if row[10] == "" || row[11] == "" { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d has incomplete active revision", functionID) + } + if !strings.EqualFold(row[14], "DEFINER") || !strings.EqualFold(row[15], "DEFINER") { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d has inconsistent security contract", functionID) + } + expectedFingerprint, fingerprintErr := function.SQLRoutineFingerprint(row[11], row[9], row[10]) + if fingerprintErr != nil || row[13] == "" || row[13] != expectedFingerprint { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d head fingerprint does not match its active revision", functionID) + } + continue + } + if language != udf.LanguagePython { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored function %d has unsupported language %q", functionID, row[12]) + } + if row[5] == "" || row[6] == "" || row[7] == "" || row[8] == "" || row[9] == "" || row[10] == "" || row[11] == "" || row[13] == "" || + !strings.EqualFold(row[14], "INVOKER") || !strings.EqualFold(row[15], "INVOKER") || + !strings.EqualFold(row[14], row[15]) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has incomplete head identity", functionID) + } + body, err := function.DecodePythonRoutineBody(row[11]) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d head body is invalid: %w", functionID, err) + } + input, output, signature, err := function.PythonSignatureMetadata(body.ArgTypes, body.ReturnType) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d head signature is invalid: %w", functionID, err) + } + bodyFingerprint, fingerprintErr := function.PythonRoutineFingerprint(row[11]) + if fingerprintErr != nil || row[13] != bodyFingerprint || + row[5] != input || row[6] != output || row[7] != strconv.Itoa(udf.PythonSignatureKeySchemaVersion) || row[8] != signature || row[9] != input { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d head identity does not match its active revision", functionID) + } + } + return nil +} + +// restoreFunctionRevisionCatalogWithCurrentSchema restores only a revision +// table that already carries the current immutable shared contract. Older/demo +// revision tables are intentionally left empty after the current table is +// created. Their rows cannot be losslessly interpreted by the new resolver, and +// the corresponding active head will be rejected until the function is +// explicitly recreated with the current DDL. +func restoreFunctionRevisionCatalogWithCurrentSchema( + ctx context.Context, + bh BackgroundExec, + sourceSnapshot string, + sourceAccount uint32, + targetAccount uint32, + sourceCreateSQL string, +) error { + targetCtx := defines.AttachAccountId(ctx, targetAccount) + tableName := qualifiedTableName(moCatalog, "mo_function_revisions") + if err := bh.Exec(targetCtx, dropTableIfExistsSQL(moCatalog, "mo_function_revisions")); err != nil { + return err + } + if err := bh.Exec(targetCtx, MoCatalogMoFunctionRevisionDDL); err != nil { + return err + } + + // Requiring every current column makes the refusal stable for all older + // layouts. Checking the CREATE text also avoids querying a historical table + // with columns that only exist in the target schema. + lowerCreateSQL := strings.ToLower(sourceCreateSQL) + for _, column := range strings.Split(functionRevisionCatalogColumns, ", ") { + if !strings.Contains(lowerCreateSQL, strings.ToLower(column)) { + return nil + } + } + + copySQL := fmt.Sprintf( + "insert into %s (%s) select %s from %s%s", + tableName, + functionRevisionCatalogColumns, + functionRevisionCatalogColumns, + tableName, + sourceSnapshot, + ) + if sourceAccount == targetAccount { + if err := bh.Exec(targetCtx, copySQL); err != nil { + return err + } + } else if err := bh.ExecRestore(targetCtx, copySQL, sourceAccount, targetAccount); err != nil { + return err + } + // A current revision table is executable metadata. Validate the copied + // rows after the transport has completed so a backup/restore or cross + // account path cannot publish a row whose body, logical catalog columns, + // digest, or current ABI disagree. The resolver repeats this check at bind + // time; restore must fail early as well, before a bad head can be reused. + return validateRestoredFunctionRevisionCatalog(ctx, bh, targetCtx) +} + func restoreSystemCatalogsAfterObjects( ctx context.Context, sid string, @@ -153,6 +473,83 @@ func restoreSystemCatalogsAfterObjects( return err } } + if bh == nil { + return nil + } + if err := validateRestoredFunctionCatalogHeads( + ctx, + bh, + defines.AttachAccountId(ctx, targetAccount), + ); err != nil { + return err + } + return publishRestoredPythonArtifacts( + ctx, + sid, + bh, + defines.AttachAccountId(ctx, targetAccount), + targetAccount, + ) +} + +// publishRestoredPythonArtifacts rebuilds the account-scoped immutable +// artifact objects after a catalog restore. Catalog rows and FileService +// objects are separate persistence domains; copying only the revision table +// would leave a syntactically valid head that cannot execute after restore. +// This runs after all catalog identity/head checks, uses the exact restored +// revision body, and publishes write-once objects before restore returns. +func publishRestoredPythonArtifacts( + ctx context.Context, + sid string, + bh BackgroundExec, + targetCtx context.Context, + targetAccount uint32, +) error { + rows, err := getStringColsList( + targetCtx, + bh, + "select language, artifact_digest, body from mo_catalog.mo_function_revisions order by function_id, revision;", + 0, 1, 2, + ) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python artifacts cannot be inspected: %w", err) + } + needStore := false + for rowIndex, row := range rows { + if len(row) != 3 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored revision row %d has %d artifact columns", rowIndex, len(row)) + } + if strings.EqualFold(row[0], udf.LanguagePython) { + needStore = true + break + } + } + if !needStore { + return nil + } + pu := getPuIfPresent(sid) + if pu == nil || pu.FileService == nil { + return moerr.NewNotSupportedNoCtx("Python artifact store is required to restore a current Python revision") + } + store, err := pythonudf.NewFileArtifactStore(pu.FileService, pythonudf.DefaultMaxArtifactBytes) + if err != nil { + return err + } + for rowIndex, row := range rows { + if !strings.EqualFold(row[0], udf.LanguagePython) { + continue + } + body, decodeErr := function.DecodePythonRoutineBody(row[2]) + if decodeErr != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python artifact row %d is invalid: %w", rowIndex, decodeErr) + } + if body.ArtifactDigest != row[1] { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python artifact row %d digest does not match its revision", rowIndex) + } + if _, publishErr := store.Publish(ctx, uint64(targetAccount), body.Handler, body.Source); publishErr != nil { + return publishErr + } + } return nil } diff --git a/pkg/frontend/snapshot_restore_with_ts.go b/pkg/frontend/snapshot_restore_with_ts.go index 19e69dbc998d8..f51504ccae5dc 100644 --- a/pkg/frontend/snapshot_restore_with_ts.go +++ b/pkg/frontend/snapshot_restore_with_ts.go @@ -584,6 +584,17 @@ func recreateTableFromTS( fmt.Sprintf(" {MO_TS = %d}", snapshotTs), restoreAccount, toAccountId, + tblInfo.createSql, + ) + } + if isCurrentFunctionRevisionCatalog(tblInfo) { + return restoreFunctionRevisionCatalogWithCurrentSchema( + ctx, + bh, + fmt.Sprintf(" {MO_TS = %d}", snapshotTs), + restoreAccount, + toAccountId, + tblInfo.createSql, ) } ctx, err = restoreDDLContext(ctx, tblInfo.dbName, tblInfo.tblName) diff --git a/pkg/frontend/snapshot_test.go b/pkg/frontend/snapshot_test.go index e0087cc41637c..3eb50f00e7a9d 100644 --- a/pkg/frontend/snapshot_test.go +++ b/pkg/frontend/snapshot_test.go @@ -1849,6 +1849,20 @@ func TestRecreateUserDefinedFunctionCatalogPreservesCurrentSchema(t *testing.T) tblName: "mo_user_defined_function", createSql: legacyCreateSQL, } + currentUDFTable := &tableInfo{ + dbName: moCatalog, + tblName: "mo_user_defined_function", + createSql: MoCatalogMoUserDefinedFunctionDDL, + } + + t.Run("current schema preserves revision head", func(t *testing.T) { + bh := &backgroundExecTest{} + bh.init() + ctx := defines.AttachAccountId(t.Context(), sourceAccount) + require.NoError(t, recreateTable(ctx, "", bh, snapshotName, currentUDFTable, sourceAccount, snapshotTS)) + require.Contains(t, bh.executedSQLs[len(bh.executedSQLs)-1], + " select "+userDefinedFunctionCatalogSourceColumns+" from ") + }) t.Run("same account timestamp snapshot", func(t *testing.T) { bh := &backgroundExecTest{} @@ -1859,7 +1873,7 @@ func TestRecreateUserDefinedFunctionCatalogPreservesCurrentSchema(t *testing.T) dropTableIfExistsSQL(moCatalog, udfTable.tblName), MoCatalogMoUserDefinedFunctionDDL, "insert into `mo_catalog`.`mo_user_defined_function` (" + userDefinedFunctionCatalogColumns + - ") select " + userDefinedFunctionCatalogSourceColumns + + ") select " + userDefinedFunctionCatalogLegacySourceColumns + " from `mo_catalog`.`mo_user_defined_function` {MO_TS = 123}", }, bh.executedSQLs) require.NotContains(t, strings.Join(bh.executedSQLs, "\n"), legacyCreateSQL) @@ -1872,7 +1886,7 @@ func TestRecreateUserDefinedFunctionCatalogPreservesCurrentSchema(t *testing.T) require.NoError(t, recreateTable(ctx, "", bh, snapshotName, udfTable, targetAccount, snapshotTS, false)) require.Equal(t, "insert into `mo_catalog`.`mo_user_defined_function` ("+userDefinedFunctionCatalogColumns+ - ") select "+userDefinedFunctionCatalogSourceColumns+ + ") select "+userDefinedFunctionCatalogLegacySourceColumns+ " from `mo_catalog`.`mo_user_defined_function` {SNAPSHOT = 'udf_snapshot'}", bh.executedSQLs[len(bh.executedSQLs)-1], ) @@ -1887,7 +1901,7 @@ func TestRecreateUserDefinedFunctionCatalogPreservesCurrentSchema(t *testing.T) )) require.Equal(t, "insert into `mo_catalog`.`mo_user_defined_function` ("+userDefinedFunctionCatalogColumns+ - ") select "+userDefinedFunctionCatalogSourceColumns+ + ") select "+userDefinedFunctionCatalogLegacySourceColumns+ " from `mo_catalog`.`mo_user_defined_function` {MO_TS = 123}", bh.executedSQLs[len(bh.executedSQLs)-1], ) @@ -1901,7 +1915,7 @@ func TestRecreateUserDefinedFunctionCatalogPreservesCurrentSchema(t *testing.T) require.NoError(t, reCreateTableWithPitr(ctx, "", bh, "udf_pitr", snapshotTS, udfTable)) require.Equal(t, "insert into `mo_catalog`.`mo_user_defined_function` ("+userDefinedFunctionCatalogColumns+ - ") select "+userDefinedFunctionCatalogSourceColumns+ + ") select "+userDefinedFunctionCatalogLegacySourceColumns+ " from `mo_catalog`.`mo_user_defined_function` {MO_TS = 123}", bh.executedSQLs[len(bh.executedSQLs)-1], ) @@ -1909,6 +1923,105 @@ func TestRecreateUserDefinedFunctionCatalogPreservesCurrentSchema(t *testing.T) }) } +func TestRecreatePythonFunctionRevisionCatalogPreservesCurrentSchema(t *testing.T) { + const ( + sourceAccount = uint32(10) + targetAccount = uint32(20) + snapshotName = "python_revision_snapshot" + snapshotTS = int64(123) + ) + legacyCreateSQL := "create table mo_catalog.mo_function_revisions (function_id bigint, revision bigint, name varchar(100), body text)" + legacyTable := &tableInfo{ + dbName: moCatalog, + tblName: "mo_function_revisions", + createSql: legacyCreateSQL, + } + currentTable := &tableInfo{ + dbName: moCatalog, + tblName: "mo_function_revisions", + createSql: MoCatalogMoFunctionRevisionDDL, + } + copySQL := func(sourceSnapshot string) string { + return "insert into `mo_catalog`.`mo_function_revisions` (" + functionRevisionCatalogColumns + + ") select " + functionRevisionCatalogColumns + + " from `mo_catalog`.`mo_function_revisions`" + sourceSnapshot + } + validationSQL := fmt.Sprintf( + "select %s from %s order by function_id, revision;", + functionRevisionCatalogColumns, + qualifiedTableName(moCatalog, "mo_function_revisions"), + ) + + t.Run("same account current revision schema", func(t *testing.T) { + bh := &backgroundExecTest{} + bh.init() + bh.sql2result[validationSQL] = &MysqlResultSet{} + ctx := defines.AttachAccountId(t.Context(), sourceAccount) + require.NoError(t, recreateTable(ctx, "", bh, snapshotName, currentTable, sourceAccount, snapshotTS)) + require.Equal(t, []string{ + dropTableIfExistsSQL(moCatalog, currentTable.tblName), + MoCatalogMoFunctionRevisionDDL, + copySQL(" {MO_TS = 123}"), + validationSQL, + }, bh.executedSQLs) + }) + + t.Run("legacy revision rows are not copied", func(t *testing.T) { + bh := &backgroundExecTest{} + bh.init() + ctx := defines.AttachAccountId(t.Context(), sourceAccount) + require.NoError(t, recreateTable(ctx, "", bh, snapshotName, legacyTable, sourceAccount, snapshotTS)) + require.Equal(t, []string{ + dropTableIfExistsSQL(moCatalog, legacyTable.tblName), + MoCatalogMoFunctionRevisionDDL, + }, bh.executedSQLs) + require.NotContains(t, strings.Join(bh.executedSQLs, "\n"), legacyCreateSQL) + }) + + t.Run("cross account named snapshot", func(t *testing.T) { + bh := &backgroundExecTest{} + bh.init() + bh.sql2result[validationSQL] = &MysqlResultSet{} + ctx := defines.AttachAccountId(t.Context(), sourceAccount) + require.NoError(t, recreateTable(ctx, "", bh, snapshotName, currentTable, targetAccount, snapshotTS)) + require.Equal(t, []string{ + dropTableIfExistsSQL(moCatalog, currentTable.tblName), + MoCatalogMoFunctionRevisionDDL, + copySQL(" {SNAPSHOT = 'python_revision_snapshot'}"), + validationSQL, + }, bh.executedSQLs) + }) + + t.Run("cross account timestamp restore", func(t *testing.T) { + bh := &backgroundExecTest{} + bh.init() + bh.sql2result[validationSQL] = &MysqlResultSet{} + require.NoError(t, recreateTableFromTS( + t.Context(), "", bh, currentTable, snapshotTS, sourceAccount, targetAccount, + )) + require.Equal(t, []string{ + dropTableIfExistsSQL(moCatalog, currentTable.tblName), + MoCatalogMoFunctionRevisionDDL, + copySQL(" {MO_TS = 123}"), + validationSQL, + }, bh.executedSQLs) + }) + + t.Run("point in time recovery", func(t *testing.T) { + bh := &backgroundExecTest{} + bh.init() + bh.sql2result[validationSQL] = &MysqlResultSet{} + ctx := defines.AttachAccountId(t.Context(), sourceAccount) + require.NoError(t, reCreateTableWithPitr(ctx, "", bh, "python_revision_pitr", snapshotTS, currentTable)) + require.Equal(t, []string{ + dropTableIfExistsSQL(moCatalog, currentTable.tblName), + MoCatalogMoFunctionRevisionDDL, + copySQL(" {MO_TS = 123}"), + validationSQL, + }, bh.executedSQLs) + }) +} + func Test_fkTablesTopoSortWithTS(t *testing.T) { convey.Convey("fkTablesTopoSortWithTS ", t, func() { ctrl := gomock.NewController(t) diff --git a/pkg/pb/plan/collation_admission.pb.go b/pkg/pb/plan/collation_admission.pb.go index 277b56f7a1ae3..d95a178760bc7 100644 --- a/pkg/pb/plan/collation_admission.pb.go +++ b/pkg/pb/plan/collation_admission.pb.go @@ -206,6 +206,8 @@ func (v *legacyCollationVisitor) typed(owner any) (bool, error) { return true, v.walkRenameTable(p) case *ResultColDef: return true, v.walkResultColDef(p) + case *RoutineCall: + return true, v.walkRoutineCall(p) case *RowsetData: return true, v.walkRowsetData(p) case *RowsetExpr: @@ -947,6 +949,9 @@ func (v *legacyCollationVisitor) walkFunction(p *Function) error { return err } } + if err := v.walkRoutineCall(p.RoutineCall); err != nil { + return err + } return nil } func (v *legacyCollationVisitor) walkGeneratedCol(p *GeneratedCol) error { @@ -1463,6 +1468,20 @@ func (v *legacyCollationVisitor) walkResultColDef(p *ResultColDef) error { } return nil } +func (v *legacyCollationVisitor) walkRoutineCall(p *RoutineCall) error { + if p == nil { + return nil + } + for _, item0 := range p.ArgumentTypes { + if err := v.walkType(item0); err != nil { + return err + } + } + if err := v.walkType(&p.ReturnType); err != nil { + return err + } + return nil +} func (v *legacyCollationVisitor) walkRowsetData(p *RowsetData) error { if p == nil { return nil diff --git a/pkg/pb/plan/plan.pb.go b/pkg/pb/plan/plan.pb.go index 5e208cd952555..d95416fecf92f 100644 --- a/pkg/pb/plan/plan.pb.go +++ b/pkg/pb/plan/plan.pb.go @@ -3185,10 +3185,12 @@ type Function struct { // Planner provenance only. Explicit CAST syntax can share the legacy CAST // overload while optimizers still distinguish it from an implicit cast. // Older CNs safely ignore this unknown field and execute the legacy overload. - SyntaxExplicitCast bool `protobuf:"varint,5,opt,name=syntax_explicit_cast,json=syntaxExplicitCast,proto3" json:"syntax_explicit_cast,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + SyntaxExplicitCast bool `protobuf:"varint,5,opt,name=syntax_explicit_cast,json=syntaxExplicitCast,proto3" json:"syntax_explicit_cast,omitempty"` + // Typed routine metadata. Ordinary builtin Function values leave this nil. + RoutineCall *RoutineCall `protobuf:"bytes,6,opt,name=routine_call,json=routineCall,proto3" json:"routine_call,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Function) Reset() { *m = Function{} } @@ -3259,6 +3261,13 @@ func (m *Function) GetSyntaxExplicitCast() bool { return false } +func (m *Function) GetRoutineCall() *RoutineCall { + if m != nil { + return m.RoutineCall + } + return nil +} + // PreparedNumericMetadata is sparse planner provenance for a numeric overload // or runtime string domain that cannot be represented by Expr.Type alone. // It is kept behind one optional pointer on Expr because the metadata is rare; @@ -11436,11 +11445,16 @@ type Query struct { // Neither the View nor the UDF catalog table changes schema when that row is replaced. ViewMetadataDependsOnUdf bool `protobuf:"varint,17,opt,name=view_metadata_depends_on_udf,json=viewMetadataDependsOnUdf,proto3" json:"view_metadata_depends_on_udf,omitempty"` // Logical access paths, not grants or resolved security roles. - ViewReferences []*ViewReference `protobuf:"bytes,18,rep,name=view_references,json=viewReferences,proto3" json:"view_references,omitempty"` - Correlation *CorrelationSpec `protobuf:"bytes,19,opt,name=correlation,proto3" json:"correlation,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + ViewReferences []*ViewReference `protobuf:"bytes,18,rep,name=view_references,json=viewReferences,proto3" json:"view_references,omitempty"` + Correlation *CorrelationSpec `protobuf:"bytes,19,opt,name=correlation,proto3" json:"correlation,omitempty"` + // Exact routine revisions captured while binding this statement. The + // expression tree carries the call-site implementation, while this bounded + // envelope lets prepared and ordinary plan-cache reuse validate the shared + // catalog namespace without walking or reinterpreting user source. + RoutineDependencies []*RoutinePlanDependency `protobuf:"bytes,20,rep,name=routine_dependencies,json=routineDependencies,proto3" json:"routine_dependencies,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Query) Reset() { *m = Query{} } @@ -11609,6 +11623,13 @@ func (m *Query) GetCorrelation() *CorrelationSpec { return nil } +func (m *Query) GetRoutineDependencies() []*RoutinePlanDependency { + if m != nil { + return m.RoutineDependencies + } + return nil +} + type TransationControl struct { // TransationControl type TclType TransationControl_TclType `protobuf:"varint,1,opt,name=tcl_type,json=tclType,proto3,enum=plan.TransationControl_TclType" json:"tcl_type,omitempty"` @@ -17133,6 +17154,603 @@ func (m *ViewStep) GetSubscriptionName() string { return "" } +// FunctionRef is the exact catalog identity carried by an executable plan. +// A zero revision is invalid for external routines; the planner validates the +// complete call before a fragment is dispatched. +type FunctionRef struct { + FunctionId uint64 `protobuf:"varint,1,opt,name=function_id,json=functionId,proto3" json:"function_id,omitempty"` + Revision uint64 `protobuf:"varint,2,opt,name=revision,proto3" json:"revision,omitempty"` + NamespaceVersion uint64 `protobuf:"varint,3,opt,name=namespace_version,json=namespaceVersion,proto3" json:"namespace_version,omitempty"` + // Function identity is tenant/database scoped. These fields prevent a + // plan fragment from being interpreted in a different catalog namespace. + AccountId uint64 `protobuf:"varint,4,opt,name=account_id,json=accountId,proto3" json:"account_id,omitempty"` + DatabaseId uint64 `protobuf:"varint,5,opt,name=database_id,json=databaseId,proto3" json:"database_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FunctionRef) Reset() { *m = FunctionRef{} } +func (m *FunctionRef) String() string { return proto.CompactTextString(m) } +func (*FunctionRef) ProtoMessage() {} +func (*FunctionRef) Descriptor() ([]byte, []int) { + return fileDescriptor_2d655ab2f7683c23, []int{160} +} +func (m *FunctionRef) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *FunctionRef) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_FunctionRef.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *FunctionRef) XXX_Merge(src proto.Message) { + xxx_messageInfo_FunctionRef.Merge(m, src) +} +func (m *FunctionRef) XXX_Size() int { + return m.ProtoSize() +} +func (m *FunctionRef) XXX_DiscardUnknown() { + xxx_messageInfo_FunctionRef.DiscardUnknown(m) +} + +var xxx_messageInfo_FunctionRef proto.InternalMessageInfo + +func (m *FunctionRef) GetFunctionId() uint64 { + if m != nil { + return m.FunctionId + } + return 0 +} + +func (m *FunctionRef) GetRevision() uint64 { + if m != nil { + return m.Revision + } + return 0 +} + +func (m *FunctionRef) GetNamespaceVersion() uint64 { + if m != nil { + return m.NamespaceVersion + } + return 0 +} + +func (m *FunctionRef) GetAccountId() uint64 { + if m != nil { + return m.AccountId + } + return 0 +} + +func (m *FunctionRef) GetDatabaseId() uint64 { + if m != nil { + return m.DatabaseId + } + return 0 +} + +type SqlRoutineImplementation struct { + DefinitionFingerprint []byte `protobuf:"bytes,1,opt,name=definition_fingerprint,json=definitionFingerprint,proto3" json:"definition_fingerprint,omitempty"` + SemanticDefinitionSchemaVersion int32 `protobuf:"varint,2,opt,name=semantic_definition_schema_version,json=semanticDefinitionSchemaVersion,proto3" json:"semantic_definition_schema_version,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SqlRoutineImplementation) Reset() { *m = SqlRoutineImplementation{} } +func (m *SqlRoutineImplementation) String() string { return proto.CompactTextString(m) } +func (*SqlRoutineImplementation) ProtoMessage() {} +func (*SqlRoutineImplementation) Descriptor() ([]byte, []int) { + return fileDescriptor_2d655ab2f7683c23, []int{161} +} +func (m *SqlRoutineImplementation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SqlRoutineImplementation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SqlRoutineImplementation.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *SqlRoutineImplementation) XXX_Merge(src proto.Message) { + xxx_messageInfo_SqlRoutineImplementation.Merge(m, src) +} +func (m *SqlRoutineImplementation) XXX_Size() int { + return m.ProtoSize() +} +func (m *SqlRoutineImplementation) XXX_DiscardUnknown() { + xxx_messageInfo_SqlRoutineImplementation.DiscardUnknown(m) +} + +var xxx_messageInfo_SqlRoutineImplementation proto.InternalMessageInfo + +func (m *SqlRoutineImplementation) GetDefinitionFingerprint() []byte { + if m != nil { + return m.DefinitionFingerprint + } + return nil +} + +func (m *SqlRoutineImplementation) GetSemanticDefinitionSchemaVersion() int32 { + if m != nil { + return m.SemanticDefinitionSchemaVersion + } + return 0 +} + +type PythonRoutineImplementation struct { + Handler string `protobuf:"bytes,1,opt,name=handler,proto3" json:"handler,omitempty"` + // Source is retained only so an old serialized demo plan can be identified + // and rejected. A current executable plan must carry the immutable artifact + // digest and resolve the artifact through the runtime artifact store. + Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"` // Deprecated: Do not use. + AbiContract string `protobuf:"bytes,3,opt,name=abi_contract,json=abiContract,proto3" json:"abi_contract,omitempty"` + AdapterVersion string `protobuf:"bytes,4,opt,name=adapter_version,json=adapterVersion,proto3" json:"adapter_version,omitempty"` + ArtifactDigest string `protobuf:"bytes,5,opt,name=artifact_digest,json=artifactDigest,proto3" json:"artifact_digest,omitempty"` + EnvironmentDigest string `protobuf:"bytes,6,opt,name=environment_digest,json=environmentDigest,proto3" json:"environment_digest,omitempty"` + SdkVersion string `protobuf:"bytes,7,opt,name=sdk_version,json=sdkVersion,proto3" json:"sdk_version,omitempty"` + DefinitionSchemaVersion int32 `protobuf:"varint,8,opt,name=definition_schema_version,json=definitionSchemaVersion,proto3" json:"definition_schema_version,omitempty"` + Mode string `protobuf:"bytes,9,opt,name=mode,proto3" json:"mode,omitempty"` + NullPolicy string `protobuf:"bytes,10,opt,name=null_policy,json=nullPolicy,proto3" json:"null_policy,omitempty"` + DefinitionFingerprint string `protobuf:"bytes,11,opt,name=definition_fingerprint,json=definitionFingerprint,proto3" json:"definition_fingerprint,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *PythonRoutineImplementation) Reset() { *m = PythonRoutineImplementation{} } +func (m *PythonRoutineImplementation) String() string { return proto.CompactTextString(m) } +func (*PythonRoutineImplementation) ProtoMessage() {} +func (*PythonRoutineImplementation) Descriptor() ([]byte, []int) { + return fileDescriptor_2d655ab2f7683c23, []int{162} +} +func (m *PythonRoutineImplementation) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PythonRoutineImplementation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PythonRoutineImplementation.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PythonRoutineImplementation) XXX_Merge(src proto.Message) { + xxx_messageInfo_PythonRoutineImplementation.Merge(m, src) +} +func (m *PythonRoutineImplementation) XXX_Size() int { + return m.ProtoSize() +} +func (m *PythonRoutineImplementation) XXX_DiscardUnknown() { + xxx_messageInfo_PythonRoutineImplementation.DiscardUnknown(m) +} + +var xxx_messageInfo_PythonRoutineImplementation proto.InternalMessageInfo + +func (m *PythonRoutineImplementation) GetHandler() string { + if m != nil { + return m.Handler + } + return "" +} + +// Deprecated: Do not use. +func (m *PythonRoutineImplementation) GetSource() string { + if m != nil { + return m.Source + } + return "" +} + +func (m *PythonRoutineImplementation) GetAbiContract() string { + if m != nil { + return m.AbiContract + } + return "" +} + +func (m *PythonRoutineImplementation) GetAdapterVersion() string { + if m != nil { + return m.AdapterVersion + } + return "" +} + +func (m *PythonRoutineImplementation) GetArtifactDigest() string { + if m != nil { + return m.ArtifactDigest + } + return "" +} + +func (m *PythonRoutineImplementation) GetEnvironmentDigest() string { + if m != nil { + return m.EnvironmentDigest + } + return "" +} + +func (m *PythonRoutineImplementation) GetSdkVersion() string { + if m != nil { + return m.SdkVersion + } + return "" +} + +func (m *PythonRoutineImplementation) GetDefinitionSchemaVersion() int32 { + if m != nil { + return m.DefinitionSchemaVersion + } + return 0 +} + +func (m *PythonRoutineImplementation) GetMode() string { + if m != nil { + return m.Mode + } + return "" +} + +func (m *PythonRoutineImplementation) GetNullPolicy() string { + if m != nil { + return m.NullPolicy + } + return "" +} + +func (m *PythonRoutineImplementation) GetDefinitionFingerprint() string { + if m != nil { + return m.DefinitionFingerprint + } + return "" +} + +// RoutineCall is the common typed call envelope for SQL and external +// language routines. Function.Args remains the normal expression argument +// list so existing expression traversal and CASE/selection ownership stay +// intact; this field carries only immutable routine identity and semantics. +type RoutineCall struct { + ContractVersion int32 `protobuf:"varint,1,opt,name=contract_version,json=contractVersion,proto3" json:"contract_version,omitempty"` + FunctionRef *FunctionRef `protobuf:"bytes,2,opt,name=function_ref,json=functionRef,proto3" json:"function_ref,omitempty"` + Language string `protobuf:"bytes,3,opt,name=language,proto3" json:"language,omitempty"` + ArgumentTypes []*Type `protobuf:"bytes,4,rep,name=argument_types,json=argumentTypes,proto3" json:"argument_types,omitempty"` + ReturnType Type `protobuf:"bytes,5,opt,name=return_type,json=returnType,proto3" json:"return_type"` + Volatility string `protobuf:"bytes,6,opt,name=volatility,proto3" json:"volatility,omitempty"` + NullPolicy string `protobuf:"bytes,7,opt,name=null_policy,json=nullPolicy,proto3" json:"null_policy,omitempty"` + // Types that are valid to be assigned to Implementation: + // + // *RoutineCall_Sql + // *RoutineCall_Python + Implementation isRoutineCall_Implementation `protobuf_oneof:"implementation"` + // Reserved from the current executable contract. Statement identity, + // session values, and group fences are created at execution time; keeping + // them in a prepared plan would allow stale state to cross executions. + Context map[string]string `protobuf:"bytes,10,rep,name=context,proto3" json:"context,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // Deprecated: Do not use. + // These fields are the common semantic contract. They must survive SQL + // lowering and expression/plan cloning; the optimizer may only move a + // routine call when the attached contract permits it. + CallsiteId string `protobuf:"bytes,11,opt,name=callsite_id,json=callsiteId,proto3" json:"callsite_id,omitempty"` + MayError bool `protobuf:"varint,12,opt,name=may_error,json=mayError,proto3" json:"may_error,omitempty"` + SecurityMode string `protobuf:"bytes,13,opt,name=security_mode,json=securityMode,proto3" json:"security_mode,omitempty"` + Leakproof bool `protobuf:"varint,14,opt,name=leakproof,proto3" json:"leakproof,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RoutineCall) Reset() { *m = RoutineCall{} } +func (m *RoutineCall) String() string { return proto.CompactTextString(m) } +func (*RoutineCall) ProtoMessage() {} +func (*RoutineCall) Descriptor() ([]byte, []int) { + return fileDescriptor_2d655ab2f7683c23, []int{163} +} +func (m *RoutineCall) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RoutineCall) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RoutineCall.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RoutineCall) XXX_Merge(src proto.Message) { + xxx_messageInfo_RoutineCall.Merge(m, src) +} +func (m *RoutineCall) XXX_Size() int { + return m.ProtoSize() +} +func (m *RoutineCall) XXX_DiscardUnknown() { + xxx_messageInfo_RoutineCall.DiscardUnknown(m) +} + +var xxx_messageInfo_RoutineCall proto.InternalMessageInfo + +type isRoutineCall_Implementation interface { + isRoutineCall_Implementation() + MarshalTo([]byte) (int, error) + ProtoSize() int +} + +type RoutineCall_Sql struct { + Sql *SqlRoutineImplementation `protobuf:"bytes,8,opt,name=sql,proto3,oneof" json:"sql,omitempty"` +} +type RoutineCall_Python struct { + Python *PythonRoutineImplementation `protobuf:"bytes,9,opt,name=python,proto3,oneof" json:"python,omitempty"` +} + +func (*RoutineCall_Sql) isRoutineCall_Implementation() {} +func (*RoutineCall_Python) isRoutineCall_Implementation() {} + +func (m *RoutineCall) GetImplementation() isRoutineCall_Implementation { + if m != nil { + return m.Implementation + } + return nil +} + +func (m *RoutineCall) GetContractVersion() int32 { + if m != nil { + return m.ContractVersion + } + return 0 +} + +func (m *RoutineCall) GetFunctionRef() *FunctionRef { + if m != nil { + return m.FunctionRef + } + return nil +} + +func (m *RoutineCall) GetLanguage() string { + if m != nil { + return m.Language + } + return "" +} + +func (m *RoutineCall) GetArgumentTypes() []*Type { + if m != nil { + return m.ArgumentTypes + } + return nil +} + +func (m *RoutineCall) GetReturnType() Type { + if m != nil { + return m.ReturnType + } + return Type{} +} + +func (m *RoutineCall) GetVolatility() string { + if m != nil { + return m.Volatility + } + return "" +} + +func (m *RoutineCall) GetNullPolicy() string { + if m != nil { + return m.NullPolicy + } + return "" +} + +func (m *RoutineCall) GetSql() *SqlRoutineImplementation { + if x, ok := m.GetImplementation().(*RoutineCall_Sql); ok { + return x.Sql + } + return nil +} + +func (m *RoutineCall) GetPython() *PythonRoutineImplementation { + if x, ok := m.GetImplementation().(*RoutineCall_Python); ok { + return x.Python + } + return nil +} + +// Deprecated: Do not use. +func (m *RoutineCall) GetContext() map[string]string { + if m != nil { + return m.Context + } + return nil +} + +func (m *RoutineCall) GetCallsiteId() string { + if m != nil { + return m.CallsiteId + } + return "" +} + +func (m *RoutineCall) GetMayError() bool { + if m != nil { + return m.MayError + } + return false +} + +func (m *RoutineCall) GetSecurityMode() string { + if m != nil { + return m.SecurityMode + } + return "" +} + +func (m *RoutineCall) GetLeakproof() bool { + if m != nil { + return m.Leakproof + } + return false +} + +// XXX_OneofWrappers is for the internal use of the proto package. +func (*RoutineCall) XXX_OneofWrappers() []interface{} { + return []interface{}{ + (*RoutineCall_Sql)(nil), + (*RoutineCall_Python)(nil), + } +} + +// RoutinePlanDependency is the shared cache/prepared-plan validation envelope +// for a resolved routine closure. FunctionRef is the executable identity; +// the integrity fields prove that the implementation attached to the plan is +// the same immutable revision that the resolver admitted. +type RoutinePlanDependency struct { + FunctionRef *FunctionRef `protobuf:"bytes,1,opt,name=function_ref,json=functionRef,proto3" json:"function_ref,omitempty"` + Language string `protobuf:"bytes,2,opt,name=language,proto3" json:"language,omitempty"` + ContractVersion int32 `protobuf:"varint,3,opt,name=contract_version,json=contractVersion,proto3" json:"contract_version,omitempty"` + DefinitionFingerprint string `protobuf:"bytes,4,opt,name=definition_fingerprint,json=definitionFingerprint,proto3" json:"definition_fingerprint,omitempty"` + ArtifactDigest string `protobuf:"bytes,5,opt,name=artifact_digest,json=artifactDigest,proto3" json:"artifact_digest,omitempty"` + EnvironmentDigest string `protobuf:"bytes,6,opt,name=environment_digest,json=environmentDigest,proto3" json:"environment_digest,omitempty"` + Volatility string `protobuf:"bytes,7,opt,name=volatility,proto3" json:"volatility,omitempty"` + NullPolicy string `protobuf:"bytes,8,opt,name=null_policy,json=nullPolicy,proto3" json:"null_policy,omitempty"` + MayError bool `protobuf:"varint,9,opt,name=may_error,json=mayError,proto3" json:"may_error,omitempty"` + SecurityMode string `protobuf:"bytes,10,opt,name=security_mode,json=securityMode,proto3" json:"security_mode,omitempty"` + Leakproof bool `protobuf:"varint,11,opt,name=leakproof,proto3" json:"leakproof,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RoutinePlanDependency) Reset() { *m = RoutinePlanDependency{} } +func (m *RoutinePlanDependency) String() string { return proto.CompactTextString(m) } +func (*RoutinePlanDependency) ProtoMessage() {} +func (*RoutinePlanDependency) Descriptor() ([]byte, []int) { + return fileDescriptor_2d655ab2f7683c23, []int{164} +} +func (m *RoutinePlanDependency) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RoutinePlanDependency) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RoutinePlanDependency.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RoutinePlanDependency) XXX_Merge(src proto.Message) { + xxx_messageInfo_RoutinePlanDependency.Merge(m, src) +} +func (m *RoutinePlanDependency) XXX_Size() int { + return m.ProtoSize() +} +func (m *RoutinePlanDependency) XXX_DiscardUnknown() { + xxx_messageInfo_RoutinePlanDependency.DiscardUnknown(m) +} + +var xxx_messageInfo_RoutinePlanDependency proto.InternalMessageInfo + +func (m *RoutinePlanDependency) GetFunctionRef() *FunctionRef { + if m != nil { + return m.FunctionRef + } + return nil +} + +func (m *RoutinePlanDependency) GetLanguage() string { + if m != nil { + return m.Language + } + return "" +} + +func (m *RoutinePlanDependency) GetContractVersion() int32 { + if m != nil { + return m.ContractVersion + } + return 0 +} + +func (m *RoutinePlanDependency) GetDefinitionFingerprint() string { + if m != nil { + return m.DefinitionFingerprint + } + return "" +} + +func (m *RoutinePlanDependency) GetArtifactDigest() string { + if m != nil { + return m.ArtifactDigest + } + return "" +} + +func (m *RoutinePlanDependency) GetEnvironmentDigest() string { + if m != nil { + return m.EnvironmentDigest + } + return "" +} + +func (m *RoutinePlanDependency) GetVolatility() string { + if m != nil { + return m.Volatility + } + return "" +} + +func (m *RoutinePlanDependency) GetNullPolicy() string { + if m != nil { + return m.NullPolicy + } + return "" +} + +func (m *RoutinePlanDependency) GetMayError() bool { + if m != nil { + return m.MayError + } + return false +} + +func (m *RoutinePlanDependency) GetSecurityMode() string { + if m != nil { + return m.SecurityMode + } + return "" +} + +func (m *RoutinePlanDependency) GetLeakproof() bool { + if m != nil { + return m.Leakproof + } + return false +} + // A zero version represents a legacy database without a persisted default. // Names are derived display values; identity/revision own the effective domain. type DatabaseDefaults struct { @@ -17151,7 +17769,7 @@ func (m *DatabaseDefaults) Reset() { *m = DatabaseDefaults{} } func (m *DatabaseDefaults) String() string { return proto.CompactTextString(m) } func (*DatabaseDefaults) ProtoMessage() {} func (*DatabaseDefaults) Descriptor() ([]byte, []int) { - return fileDescriptor_2d655ab2f7683c23, []int{160} + return fileDescriptor_2d655ab2f7683c23, []int{165} } func (m *DatabaseDefaults) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -17432,1178 +18050,1225 @@ func init() { proto.RegisterType((*UnresolvedIndexHint)(nil), "plan.UnresolvedIndexHint") proto.RegisterType((*ViewReference)(nil), "plan.ViewReference") proto.RegisterType((*ViewStep)(nil), "plan.ViewStep") + proto.RegisterType((*FunctionRef)(nil), "plan.FunctionRef") + proto.RegisterType((*SqlRoutineImplementation)(nil), "plan.SqlRoutineImplementation") + proto.RegisterType((*PythonRoutineImplementation)(nil), "plan.PythonRoutineImplementation") + proto.RegisterType((*RoutineCall)(nil), "plan.RoutineCall") + proto.RegisterMapType((map[string]string)(nil), "plan.RoutineCall.ContextEntry") + proto.RegisterType((*RoutinePlanDependency)(nil), "plan.RoutinePlanDependency") proto.RegisterType((*DatabaseDefaults)(nil), "plan.DatabaseDefaults") } func init() { proto.RegisterFile("plan.proto", fileDescriptor_2d655ab2f7683c23) } var fileDescriptor_2d655ab2f7683c23 = []byte{ - // 18633 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0xfd, 0x6b, 0x8c, 0x1b, 0xd9, - 0x92, 0x20, 0x06, 0x8b, 0x45, 0x56, 0x15, 0x19, 0x7c, 0x54, 0xd6, 0x51, 0x49, 0xa2, 0xd4, 0x6a, - 0x49, 0x9d, 0xfd, 0x52, 0xab, 0xbb, 0xd5, 0xdd, 0x52, 0x3f, 0xd4, 0x77, 0xee, 0xcc, 0xbd, 0x2c, - 0x16, 0x4b, 0xa2, 0xc4, 0x22, 0xeb, 0x26, 0x59, 0x52, 0xf7, 0x9d, 0x9d, 0x2f, 0x91, 0xc5, 0xcc, - 0xaa, 0xca, 0xae, 0x64, 0x26, 0x3b, 0x33, 0xa9, 0xaa, 0xba, 0xd8, 0x0f, 0xbe, 0x30, 0x60, 0xaf, - 0xc7, 0x36, 0x16, 0x0b, 0x0c, 0xbc, 0x80, 0x61, 0xc0, 0x1e, 0x1b, 0x58, 0x18, 0x58, 0xfb, 0x8f, - 0x17, 0x0b, 0xaf, 0x1f, 0xb0, 0x8d, 0xb5, 0x7f, 0x78, 0xfc, 0x80, 0x31, 0xf6, 0xc2, 0x5e, 0xdb, - 0x6b, 0xac, 0xed, 0x99, 0x1f, 0xfe, 0x69, 0x18, 0x7e, 0x00, 0xde, 0x3f, 0x36, 0x22, 0xe2, 0x9c, - 0x7c, 0x90, 0x54, 0x3f, 0xee, 0xcc, 0x00, 0xfe, 0x53, 0xc5, 0x13, 0x11, 0xe7, 0xe4, 0x79, 0xc6, - 0x89, 0x88, 0x13, 0x27, 0x0e, 0xc0, 0xd4, 0xb3, 0xfc, 0xfb, 0xd3, 0x30, 0x88, 0x03, 0x51, 0xc2, - 0xdf, 0x37, 0x3e, 0x3c, 0x76, 0xe3, 0x93, 0xd9, 0xe1, 0xfd, 0x71, 0x30, 0xf9, 0xe8, 0x38, 0x38, - 0x0e, 0x3e, 0x22, 0xe4, 0xe1, 0xec, 0x88, 0x52, 0x94, 0xa0, 0x5f, 0x9c, 0xe9, 0x06, 0x78, 0xc1, - 0xf8, 0x54, 0xfe, 0xde, 0x88, 0xdd, 0x89, 0x13, 0xc5, 0xd6, 0x64, 0xca, 0x00, 0xfd, 0x3f, 0x2d, - 0x42, 0x69, 0x74, 0x31, 0x75, 0x44, 0x03, 0x56, 0x5c, 0xbb, 0x59, 0xb8, 0x53, 0xb8, 0xbb, 0x6a, - 0xac, 0xb8, 0xb6, 0xb8, 0x03, 0x55, 0x3f, 0x88, 0xfb, 0x33, 0xcf, 0xb3, 0x0e, 0x3d, 0xa7, 0xb9, - 0x72, 0xa7, 0x70, 0xb7, 0x6c, 0x64, 0x41, 0xe2, 0x35, 0xa8, 0x58, 0xb3, 0x38, 0x30, 0x5d, 0x7f, - 0x1c, 0x36, 0x8b, 0x84, 0x2f, 0x23, 0xa0, 0xeb, 0x8f, 0x43, 0xb1, 0x05, 0xab, 0x67, 0xae, 0x1d, - 0x9f, 0x34, 0x4b, 0x54, 0x22, 0x27, 0x10, 0x1a, 0x8d, 0x2d, 0xcf, 0x69, 0xae, 0x32, 0x94, 0x12, - 0x08, 0x8d, 0xe9, 0x23, 0x6b, 0x77, 0x0a, 0x77, 0x2b, 0x06, 0x27, 0xc4, 0x2d, 0x00, 0xc7, 0x9f, - 0x4d, 0x5e, 0x5a, 0xde, 0xcc, 0x89, 0x9a, 0xeb, 0x84, 0xca, 0x40, 0x44, 0x13, 0xd6, 0xc7, 0x27, - 0x56, 0x18, 0x39, 0x71, 0xb3, 0x7c, 0xa7, 0x70, 0xb7, 0x6e, 0xa8, 0x24, 0x56, 0x6c, 0x6a, 0xd9, - 0x66, 0x34, 0xb5, 0xc6, 0x4e, 0xb3, 0xc2, 0x15, 0x9b, 0x5a, 0xf6, 0x10, 0xd3, 0xe2, 0x33, 0xb8, - 0x3a, 0x0e, 0x3c, 0xcf, 0x8a, 0xdd, 0xc0, 0x37, 0xc7, 0x81, 0x13, 0x8e, 0xdd, 0x43, 0xd7, 0x73, - 0xe3, 0x8b, 0x26, 0x50, 0x29, 0x57, 0x12, 0x6c, 0x3b, 0x83, 0x14, 0x3f, 0x85, 0x1b, 0xcb, 0xb3, - 0x99, 0x58, 0x81, 0x2a, 0x7d, 0xa4, 0xb9, 0x34, 0xeb, 0xd0, 0x89, 0xc5, 0x23, 0x48, 0x71, 0xe6, - 0xc4, 0x09, 0x8f, 0x1d, 0x73, 0x1c, 0xf8, 0x47, 0x9e, 0x3b, 0x8e, 0x9b, 0x35, 0xca, 0x9b, 0x56, - 0x6a, 0x0f, 0xd1, 0x6d, 0x89, 0x15, 0xef, 0xc3, 0x66, 0x9a, 0xf3, 0xa5, 0x13, 0x46, 0x6e, 0xe0, - 0x37, 0xeb, 0x54, 0x53, 0x2d, 0x41, 0x3c, 0x67, 0xb8, 0xfe, 0x33, 0xa8, 0x4c, 0xa2, 0xe3, 0x27, - 0x8e, 0x65, 0x3b, 0xa1, 0xb8, 0x06, 0xeb, 0x93, 0xe8, 0xd8, 0x8c, 0xad, 0x63, 0x39, 0xaa, 0x6b, - 0x93, 0xe8, 0x78, 0x64, 0x1d, 0x8b, 0xeb, 0x50, 0x26, 0xc4, 0xc5, 0x94, 0x87, 0x75, 0xd5, 0x40, - 0x42, 0x9c, 0x04, 0xfa, 0x1f, 0xaf, 0xc3, 0x7a, 0xcf, 0x8d, 0x9d, 0xd0, 0xf2, 0xc4, 0x55, 0x58, - 0x73, 0x23, 0x7f, 0xe6, 0x79, 0x94, 0xbd, 0x6c, 0xc8, 0x94, 0xb8, 0x0a, 0xab, 0xee, 0xa3, 0x97, - 0x96, 0xc7, 0x79, 0x9f, 0x5c, 0x32, 0x38, 0x29, 0x9a, 0xb0, 0xe6, 0x7e, 0xf2, 0x39, 0x22, 0x8a, - 0x12, 0x21, 0xd3, 0x84, 0x79, 0xf8, 0x00, 0x31, 0xa5, 0x04, 0x43, 0x69, 0xc2, 0x7c, 0xfe, 0x29, - 0x62, 0x70, 0x42, 0x14, 0x09, 0x43, 0x69, 0xfc, 0xca, 0x8c, 0xbe, 0x82, 0x73, 0xa2, 0x8e, 0x5f, - 0x99, 0xa9, 0xaf, 0xcc, 0xf8, 0x2b, 0xeb, 0x12, 0x21, 0xd3, 0x84, 0xe1, 0xaf, 0x94, 0x13, 0x4c, - 0xf2, 0x95, 0x19, 0x7f, 0x05, 0x27, 0x43, 0x89, 0x30, 0xfc, 0x95, 0x2d, 0x28, 0xd9, 0x08, 0xc7, - 0xa1, 0x2f, 0x3c, 0xb9, 0x64, 0x50, 0x0a, 0xa1, 0x11, 0x42, 0x71, 0x54, 0x2b, 0x08, 0x8d, 0x24, - 0xf4, 0x10, 0xa1, 0x34, 0x5e, 0x08, 0x3d, 0x94, 0xd0, 0x23, 0x84, 0xe2, 0x90, 0xac, 0x20, 0x14, - 0x53, 0xe2, 0x06, 0xac, 0xdb, 0x56, 0xec, 0x20, 0xa2, 0x21, 0x9b, 0xac, 0x00, 0x88, 0xc3, 0x45, - 0x88, 0xb8, 0x0d, 0xd9, 0x68, 0x05, 0x10, 0x3a, 0x54, 0x91, 0x4c, 0xe1, 0x35, 0x89, 0xcf, 0x02, - 0xc5, 0x67, 0x50, 0xb3, 0x9d, 0xb1, 0x3b, 0xb1, 0x3c, 0x6e, 0xd3, 0xe6, 0x9d, 0xc2, 0xdd, 0xea, - 0x83, 0x8d, 0xfb, 0xc4, 0x26, 0x12, 0xcc, 0x93, 0x4b, 0x46, 0x8e, 0x4c, 0x3c, 0x82, 0xba, 0x4c, - 0x7f, 0xf2, 0x80, 0x3a, 0x56, 0x50, 0x3e, 0x2d, 0x97, 0xef, 0x93, 0x07, 0x8f, 0x9e, 0x5c, 0x32, - 0xf2, 0x84, 0xe2, 0x2d, 0xa8, 0x25, 0x5c, 0x03, 0x33, 0x5e, 0x96, 0xb5, 0xca, 0x41, 0xb1, 0x59, - 0xdf, 0x44, 0x81, 0x8f, 0x04, 0x5b, 0xb2, 0xdf, 0x14, 0x40, 0xdc, 0x01, 0xb0, 0x9d, 0x23, 0x6b, - 0xe6, 0xc5, 0x88, 0xbe, 0x22, 0x3b, 0x30, 0x03, 0x13, 0xb7, 0xa0, 0x32, 0x9b, 0x62, 0x2b, 0x9f, - 0x5b, 0x5e, 0xf3, 0xaa, 0x24, 0x48, 0x41, 0x58, 0x3a, 0x2e, 0x7d, 0xc4, 0x5e, 0x93, 0xa3, 0xab, - 0x00, 0x38, 0xbc, 0x2f, 0x9d, 0x31, 0xa2, 0x9a, 0xf2, 0xc3, 0x32, 0x8d, 0x8c, 0xc5, 0x8d, 0xb6, - 0x5d, 0xbf, 0x79, 0x9d, 0x66, 0x30, 0x27, 0xc4, 0x4d, 0x28, 0x46, 0xe1, 0xb8, 0x79, 0x83, 0xda, - 0x0f, 0xdc, 0xfe, 0xce, 0xf9, 0x34, 0x34, 0x10, 0x2c, 0xde, 0x84, 0xba, 0x1b, 0x99, 0x91, 0x13, - 0xba, 0x96, 0xe7, 0xfe, 0xca, 0xb1, 0x9b, 0xaf, 0x51, 0xde, 0x9a, 0x1b, 0x0d, 0x13, 0x98, 0xf8, - 0x09, 0xd4, 0x3c, 0x5e, 0x26, 0xe6, 0x51, 0x10, 0x4e, 0x9a, 0x37, 0xef, 0x14, 0xee, 0x36, 0x1e, - 0x5c, 0xe3, 0xb2, 0x86, 0x71, 0xe8, 0xfa, 0xc7, 0x72, 0x19, 0xed, 0x06, 0xe1, 0xc4, 0xa8, 0x7a, - 0x69, 0x02, 0x3f, 0x10, 0x11, 0x85, 0x19, 0x05, 0xb3, 0x70, 0xec, 0x34, 0x5f, 0xa7, 0xd5, 0x5c, - 0x63, 0xe0, 0x90, 0x60, 0xe2, 0x67, 0x70, 0x53, 0x0e, 0x82, 0xa9, 0x3e, 0x14, 0x3a, 0xdf, 0xce, - 0xdc, 0xd0, 0x89, 0xcc, 0x97, 0x8f, 0x1e, 0x34, 0x6f, 0x51, 0xa5, 0xae, 0x4b, 0x1a, 0xf9, 0x2d, - 0x43, 0x52, 0x3c, 0x7f, 0xf4, 0x60, 0x7b, 0x1d, 0x56, 0x89, 0x4f, 0xea, 0x37, 0xa1, 0xbc, 0x6f, - 0x85, 0xd6, 0xc4, 0x70, 0x8e, 0x84, 0x06, 0xc5, 0x69, 0x10, 0x49, 0x76, 0x80, 0x3f, 0xf5, 0xbf, - 0x0c, 0x6b, 0xcf, 0xad, 0x10, 0x71, 0x02, 0x4a, 0xbe, 0x35, 0x71, 0x08, 0x59, 0x31, 0xe8, 0x37, - 0xb2, 0x80, 0xe8, 0x22, 0x8a, 0x9d, 0x89, 0x64, 0xff, 0x32, 0x85, 0xf0, 0x63, 0x2f, 0x38, 0x94, - 0x4b, 0xbd, 0x6c, 0xc8, 0x94, 0xb8, 0x0f, 0x97, 0x0f, 0x83, 0x99, 0x6f, 0x9b, 0xb2, 0x81, 0x76, - 0x30, 0xb1, 0x5c, 0x9f, 0x56, 0x7d, 0xdd, 0xd8, 0x24, 0x14, 0x77, 0xce, 0x0e, 0x21, 0xf4, 0x7f, - 0xbc, 0x00, 0x6b, 0xed, 0xc0, 0xc3, 0xcf, 0x5f, 0x83, 0xf5, 0xd0, 0xf1, 0xcc, 0xb4, 0x7a, 0x6b, - 0xa1, 0xe3, 0xed, 0x07, 0x11, 0x22, 0xc6, 0x01, 0x23, 0x98, 0x59, 0xad, 0x8d, 0x03, 0x42, 0xa8, - 0x0a, 0x17, 0x33, 0x15, 0xbe, 0x0e, 0xe5, 0xf8, 0xd0, 0x33, 0x09, 0x5e, 0x22, 0xf8, 0x7a, 0x7c, - 0xe8, 0xf5, 0x11, 0x75, 0x0d, 0xd6, 0xed, 0x43, 0xc6, 0xac, 0x12, 0x66, 0xcd, 0x3e, 0x44, 0x84, - 0xfe, 0x25, 0x54, 0x0c, 0xeb, 0x4c, 0x56, 0xe3, 0x0a, 0xac, 0x61, 0x01, 0x72, 0x27, 0x2c, 0x19, - 0xab, 0xf1, 0xa1, 0xd7, 0xb5, 0x11, 0x8c, 0x95, 0x70, 0x6d, 0xaa, 0x43, 0xc9, 0x58, 0x1d, 0x07, - 0x5e, 0xd7, 0xd6, 0x47, 0x00, 0xed, 0x20, 0x0c, 0x7f, 0xe3, 0x26, 0x6c, 0xc1, 0xaa, 0xed, 0x4c, - 0xe3, 0x13, 0xe6, 0x98, 0x06, 0x27, 0xf4, 0x7b, 0x50, 0xc6, 0xe9, 0xd8, 0x73, 0xa3, 0x58, 0xdc, - 0x82, 0x92, 0xe7, 0x46, 0x71, 0xb3, 0x70, 0xa7, 0x38, 0x37, 0x59, 0x09, 0xae, 0xdf, 0x81, 0xf2, - 0x9e, 0x75, 0xfe, 0x1c, 0x47, 0x1a, 0x4b, 0xa3, 0x21, 0x97, 0x43, 0x28, 0xc7, 0xbf, 0x06, 0x30, - 0xb2, 0xc2, 0x63, 0x27, 0x26, 0x06, 0xff, 0xbf, 0x17, 0xa0, 0x3a, 0x9c, 0x1d, 0x7e, 0x3b, 0x73, - 0xc2, 0x0b, 0xac, 0xf3, 0x5d, 0x28, 0xc6, 0x17, 0x53, 0xca, 0xd1, 0x78, 0x70, 0x55, 0xce, 0xdf, - 0x14, 0x7f, 0x1f, 0x33, 0x19, 0x48, 0x82, 0x8d, 0xf0, 0x03, 0xdb, 0x51, 0x7d, 0xb0, 0x6a, 0xac, - 0x61, 0xb2, 0x6b, 0xa3, 0xe0, 0x10, 0x4c, 0xe5, 0x28, 0xac, 0x04, 0x53, 0x71, 0x07, 0x56, 0xc7, - 0x27, 0xae, 0x67, 0xd3, 0x00, 0xe4, 0xeb, 0xcc, 0x08, 0x1c, 0xa5, 0x30, 0x38, 0x33, 0x23, 0xf7, - 0x57, 0x4a, 0x10, 0x58, 0x0f, 0x83, 0xb3, 0xa1, 0xfb, 0x2b, 0x47, 0x1f, 0x49, 0x69, 0x04, 0x60, - 0x6d, 0xd8, 0x6e, 0xf5, 0x5a, 0x86, 0x76, 0x09, 0x7f, 0x77, 0xbe, 0xea, 0x0e, 0x47, 0x43, 0xad, - 0x20, 0x1a, 0x00, 0xfd, 0xc1, 0xc8, 0x94, 0xe9, 0x15, 0xb1, 0x06, 0x2b, 0xdd, 0xbe, 0x56, 0x44, - 0x1a, 0x84, 0x77, 0xfb, 0x5a, 0x49, 0xac, 0x43, 0xb1, 0xd5, 0xff, 0x5a, 0x5b, 0xa5, 0x1f, 0xbd, - 0x9e, 0xb6, 0xa6, 0xff, 0xa3, 0x15, 0xa8, 0x0c, 0x0e, 0xbf, 0x71, 0xc6, 0x31, 0xb6, 0x19, 0x67, - 0xb5, 0x13, 0xbe, 0x74, 0x42, 0x6a, 0x76, 0xd1, 0x90, 0x29, 0x6c, 0x88, 0x7d, 0x48, 0x8d, 0x2b, - 0x1a, 0x2b, 0xf6, 0x21, 0xd1, 0x8d, 0x4f, 0x9c, 0x89, 0x45, 0x8d, 0x43, 0x3a, 0x4a, 0xe1, 0x2a, - 0x0a, 0x0e, 0xbf, 0xa1, 0xe6, 0x15, 0x0d, 0xfc, 0x29, 0x6e, 0x43, 0x95, 0xcb, 0xc8, 0xce, 0x2f, - 0x60, 0xd0, 0xfc, 0xe4, 0x5b, 0xcb, 0x4e, 0x3e, 0xca, 0x49, 0xa5, 0x32, 0x52, 0x4a, 0x39, 0x0c, - 0xea, 0xcb, 0x19, 0x1d, 0x1c, 0x7e, 0xc3, 0xd8, 0x32, 0xcf, 0xe8, 0xe0, 0xf0, 0x1b, 0x42, 0xbd, - 0x0f, 0x9b, 0xd1, 0xec, 0x30, 0x1a, 0x87, 0xee, 0x94, 0xa4, 0x03, 0xa2, 0xa9, 0x10, 0x8d, 0x96, - 0x45, 0x10, 0xf1, 0x5d, 0x28, 0x4f, 0x67, 0x87, 0xa6, 0xeb, 0x1f, 0x05, 0xb4, 0xdb, 0x55, 0x1f, - 0xd4, 0x79, 0x60, 0xf6, 0x67, 0x87, 0x5d, 0xff, 0x28, 0x30, 0xd6, 0xa7, 0xfc, 0x43, 0xe8, 0x50, - 0xf7, 0x83, 0xd8, 0x44, 0xa1, 0xd1, 0x9c, 0x38, 0xb1, 0x25, 0x85, 0x1b, 0x14, 0xfd, 0x7a, 0xc1, - 0xf8, 0x74, 0xcf, 0x89, 0x2d, 0x71, 0x0f, 0xca, 0x91, 0x6f, 0x4d, 0xa3, 0x93, 0x80, 0xe5, 0x97, - 0xea, 0x83, 0x86, 0x9c, 0x3b, 0x12, 0x6a, 0x24, 0x78, 0xfd, 0x1d, 0x58, 0x97, 0xdf, 0x40, 0xc1, - 0x2c, 0x76, 0x7c, 0xcb, 0x8f, 0xcd, 0x44, 0xd4, 0x2c, 0x33, 0xa0, 0x6b, 0xeb, 0x7f, 0xbb, 0x00, - 0xda, 0x30, 0x53, 0x6d, 0xfa, 0xd0, 0x32, 0xae, 0xf4, 0x3a, 0x80, 0x35, 0x1e, 0x07, 0x33, 0x2e, - 0x86, 0x27, 0x63, 0x45, 0x42, 0xba, 0x76, 0xb6, 0xaf, 0x8b, 0xb9, 0xbe, 0x7e, 0x03, 0x6a, 0x2a, - 0x5f, 0x86, 0x41, 0x54, 0x25, 0x4c, 0xf5, 0x76, 0x34, 0xcb, 0x71, 0x89, 0xf5, 0x68, 0xc6, 0xb9, - 0xaf, 0xc2, 0x1a, 0xc9, 0xa5, 0x91, 0x1a, 0x41, 0x4e, 0xe9, 0x7f, 0xbf, 0x00, 0xf5, 0xae, 0x6f, - 0x3b, 0xe7, 0xc3, 0xb1, 0xe5, 0xab, 0x0e, 0x74, 0x23, 0xd3, 0x45, 0x98, 0x19, 0x8d, 0x2d, 0x5f, - 0xca, 0x4f, 0x55, 0x37, 0x4a, 0xe8, 0xb0, 0x0d, 0x4c, 0x40, 0x9f, 0x5a, 0xa1, 0x12, 0x2b, 0x04, - 0xa1, 0x8f, 0xbd, 0x03, 0x1b, 0x87, 0x8e, 0x17, 0xf8, 0xc7, 0x66, 0x1c, 0x98, 0x2c, 0x1b, 0x73, - 0x5b, 0xea, 0x0c, 0x1e, 0x05, 0x23, 0x92, 0x91, 0xb7, 0x60, 0x75, 0x6a, 0x85, 0x71, 0xd4, 0x2c, - 0xdd, 0x29, 0xe2, 0x92, 0xa7, 0x04, 0x76, 0xb3, 0x1b, 0x99, 0x33, 0xdf, 0xfd, 0x76, 0xc6, 0xcd, - 0x28, 0x1b, 0x65, 0x37, 0x3a, 0xa0, 0xb4, 0xb8, 0x0b, 0x1a, 0x7f, 0x99, 0x8a, 0xcd, 0xce, 0xc9, - 0x06, 0xc1, 0xa9, 0x60, 0x62, 0x8c, 0xff, 0x62, 0x11, 0xca, 0xbb, 0x33, 0x7f, 0x8c, 0x83, 0x21, - 0xde, 0x84, 0xd2, 0xd1, 0xcc, 0x1f, 0x53, 0x5b, 0x12, 0x69, 0x23, 0x59, 0x53, 0x06, 0x21, 0x91, - 0x5b, 0x59, 0xe1, 0x31, 0x72, 0xb9, 0x05, 0x6e, 0x85, 0x70, 0x1a, 0xb9, 0xe3, 0x63, 0x12, 0x7d, - 0xdd, 0x63, 0x6a, 0x51, 0xcd, 0xa8, 0x58, 0xc7, 0xc7, 0x6d, 0x02, 0x88, 0x16, 0x6c, 0xa4, 0x68, - 0x96, 0x4f, 0x4b, 0xc4, 0x98, 0xae, 0x73, 0x49, 0xad, 0xe3, 0xe3, 0xd0, 0x39, 0xb6, 0x62, 0x87, - 0xe9, 0x89, 0x37, 0xd5, 0x93, 0xec, 0xc4, 0x37, 0x3e, 0x86, 0xad, 0xe8, 0xc2, 0x8f, 0xad, 0x73, - 0xd3, 0x39, 0x9f, 0x7a, 0xee, 0xd8, 0x8d, 0xcd, 0xb1, 0x15, 0xc5, 0xb2, 0x17, 0x04, 0xe3, 0x3a, - 0x12, 0xd5, 0xb6, 0xa2, 0x58, 0xff, 0xb7, 0x0a, 0xdc, 0xca, 0x5d, 0xcf, 0x3a, 0x16, 0x65, 0x28, - 0xf5, 0x07, 0xfd, 0x8e, 0x76, 0x49, 0xd4, 0xa0, 0xdc, 0xed, 0x8f, 0x3a, 0x46, 0xbf, 0xd5, 0xd3, - 0x0a, 0xc4, 0x8e, 0x46, 0xad, 0xed, 0x5e, 0x47, 0x5b, 0x41, 0xcc, 0xf3, 0x41, 0xaf, 0x35, 0xea, - 0xf6, 0x3a, 0x5a, 0x89, 0x31, 0x46, 0xb7, 0x3d, 0xd2, 0xca, 0x42, 0x83, 0xda, 0xbe, 0x31, 0xd8, - 0x39, 0x68, 0x77, 0xcc, 0xfe, 0x41, 0xaf, 0xa7, 0x69, 0xe2, 0x32, 0x6c, 0x24, 0x90, 0x01, 0x03, - 0xef, 0x60, 0x96, 0xe7, 0x2d, 0xa3, 0x65, 0x3c, 0xd6, 0x7e, 0x2e, 0xca, 0x50, 0x6c, 0x3d, 0x7e, - 0xac, 0xfd, 0x1a, 0x39, 0x5b, 0xe5, 0x45, 0xb7, 0x6f, 0x3e, 0x6f, 0xf5, 0x0e, 0x3a, 0xda, 0xaf, - 0x57, 0x54, 0x7a, 0x60, 0xec, 0x74, 0x0c, 0xed, 0xd7, 0x25, 0xb1, 0x09, 0xb5, 0x5f, 0x0e, 0xfa, - 0x9d, 0xbd, 0xd6, 0xfe, 0x3e, 0x55, 0xe4, 0xd7, 0x65, 0xfd, 0x3f, 0x59, 0x85, 0x6b, 0xfb, 0xa1, - 0x33, 0xb5, 0x42, 0xc7, 0xee, 0xcf, 0x26, 0x4e, 0xe8, 0x8e, 0x71, 0xd1, 0xd8, 0x56, 0x6c, 0x89, - 0x1b, 0x50, 0x3e, 0xb2, 0x3c, 0xef, 0xd0, 0x1a, 0x9f, 0xca, 0xf9, 0x97, 0xa4, 0x59, 0x3f, 0x0a, - 0xad, 0x49, 0x66, 0x47, 0x2a, 0x13, 0x00, 0xf7, 0xa4, 0x77, 0x61, 0x43, 0x11, 0x2a, 0x01, 0x85, - 0x37, 0xf9, 0x86, 0x02, 0x4b, 0x11, 0xe5, 0x33, 0xb8, 0x36, 0x47, 0x68, 0xaa, 0x0d, 0x82, 0x75, - 0xbe, 0xad, 0x7c, 0x86, 0x3e, 0x6f, 0x17, 0x4b, 0xb2, 0xa9, 0xcd, 0x71, 0x75, 0x59, 0xb6, 0x36, - 0x6f, 0x95, 0x9f, 0xc3, 0xb5, 0x69, 0x18, 0xbc, 0x74, 0x51, 0xcf, 0x21, 0x61, 0x28, 0x9a, 0x79, - 0x72, 0x6c, 0xd7, 0xa8, 0x7a, 0x57, 0x32, 0x68, 0x83, 0xb0, 0x38, 0xbc, 0xaf, 0xc8, 0x37, 0x75, - 0x9c, 0x90, 0x98, 0xed, 0xb2, 0x7c, 0xfb, 0x8e, 0x13, 0x8a, 0x1d, 0xb8, 0xfd, 0x8a, 0x7c, 0x34, - 0x31, 0xb1, 0x95, 0x65, 0xaa, 0xee, 0x6b, 0x4b, 0xf3, 0xe3, 0x64, 0xec, 0xda, 0xa2, 0x05, 0xaf, - 0xbf, 0xaa, 0x14, 0xd6, 0x8e, 0x2b, 0x54, 0xc6, 0x8d, 0xa5, 0x65, 0xbc, 0x20, 0x95, 0xf9, 0x3b, - 0x8a, 0x60, 0x55, 0x1a, 0xbe, 0xa3, 0x88, 0x21, 0xe9, 0xd7, 0x3f, 0x85, 0xad, 0x9c, 0x40, 0xa6, - 0xc6, 0xb5, 0xba, 0xb0, 0x41, 0x8b, 0x28, 0x23, 0x9e, 0xc9, 0x71, 0xbe, 0x0f, 0x97, 0xdd, 0x23, - 0xd4, 0xfc, 0xcc, 0x71, 0x30, 0x99, 0xa0, 0x16, 0x4a, 0x42, 0x06, 0xab, 0xad, 0x9b, 0x8c, 0x6a, - 0x13, 0x86, 0xc5, 0x90, 0x4f, 0xe1, 0xea, 0x34, 0x0c, 0x90, 0x31, 0x38, 0x76, 0x3e, 0x4b, 0x9d, - 0xb2, 0x6c, 0x25, 0xd8, 0x4c, 0x2e, 0xfd, 0x5f, 0x5a, 0x83, 0x12, 0x56, 0x41, 0xe8, 0xa9, 0x44, - 0x92, 0xd4, 0x0d, 0x7b, 0x73, 0xbb, 0xf4, 0x47, 0xff, 0xf0, 0xf6, 0x25, 0x96, 0x45, 0xde, 0x80, - 0xa2, 0xe7, 0xc6, 0x34, 0x75, 0x93, 0x7d, 0x4c, 0xca, 0xc0, 0x4f, 0x2e, 0x19, 0x88, 0x13, 0xb7, - 0xa0, 0xc0, 0x42, 0x49, 0xb2, 0x35, 0x29, 0x29, 0xf8, 0xc9, 0x25, 0xa3, 0x30, 0x15, 0x37, 0xa1, - 0xf0, 0x52, 0x4a, 0x28, 0x35, 0xc6, 0xb3, 0x1c, 0x8c, 0xd8, 0x97, 0xe2, 0x0e, 0x14, 0xc7, 0x01, - 0x2b, 0xa5, 0x09, 0x9e, 0xa5, 0x3c, 0x2c, 0x7f, 0x1c, 0x78, 0xe2, 0x4d, 0x28, 0x86, 0xd6, 0x19, - 0xcd, 0xbd, 0x84, 0x1d, 0x26, 0x62, 0x24, 0x12, 0x85, 0xd6, 0x19, 0x56, 0xe2, 0x88, 0xa6, 0x59, - 0x52, 0x09, 0xc5, 0x4f, 0xf1, 0x33, 0x47, 0xe2, 0x0e, 0x14, 0xce, 0x68, 0x1a, 0x25, 0x7a, 0xd8, - 0x0b, 0xd7, 0xb7, 0x83, 0xb3, 0xe1, 0xd4, 0x19, 0x23, 0xc5, 0x99, 0x78, 0x1b, 0x8a, 0xd1, 0xec, - 0x90, 0xa6, 0x49, 0xf5, 0xc1, 0xe6, 0x82, 0x7c, 0x86, 0x1f, 0x8a, 0x66, 0x87, 0xe2, 0x1d, 0x28, - 0x8d, 0x83, 0x30, 0x94, 0x3b, 0xbb, 0xa6, 0x2a, 0xac, 0x44, 0x53, 0xd4, 0x4b, 0x11, 0x8f, 0x1f, - 0x8c, 0xe5, 0xb0, 0x4b, 0xa2, 0x54, 0x36, 0xc4, 0x0f, 0xc6, 0xe2, 0x2d, 0x29, 0x70, 0xe6, 0x76, - 0x75, 0x25, 0x8e, 0x62, 0x39, 0x88, 0xc5, 0x41, 0x9a, 0x58, 0xe7, 0x34, 0xa0, 0x09, 0x91, 0x92, - 0x43, 0xb1, 0x4e, 0x13, 0xeb, 0x5c, 0xbc, 0x05, 0xc5, 0x97, 0xce, 0x98, 0xf4, 0xdf, 0xe4, 0x6b, - 0x72, 0x90, 0x9e, 0x53, 0xf3, 0x10, 0x4d, 0xfb, 0x4a, 0xe0, 0xd9, 0xa4, 0x0a, 0x27, 0x63, 0xb9, - 0x1b, 0x78, 0xf6, 0x73, 0x1a, 0x4b, 0x42, 0x8a, 0x87, 0x50, 0xb1, 0x9d, 0xa9, 0xe3, 0xdb, 0x8e, - 0x1f, 0x93, 0x92, 0x57, 0x7d, 0x70, 0x99, 0x29, 0x77, 0x14, 0x18, 0xab, 0x88, 0x2a, 0x63, 0x42, - 0x27, 0xde, 0x87, 0x52, 0xe4, 0x05, 0x31, 0xe9, 0x7e, 0xd5, 0x07, 0x57, 0xd2, 0x3e, 0x71, 0xd8, - 0x68, 0x32, 0xf4, 0x02, 0x6a, 0x10, 0x12, 0xa1, 0x80, 0x6f, 0xcd, 0xce, 0x71, 0x55, 0x6b, 0x2c, - 0x8a, 0x5b, 0xb3, 0xf3, 0xae, 0x8d, 0xa2, 0x9e, 0x6f, 0xbf, 0x24, 0x15, 0xbb, 0x60, 0xe0, 0x4f, - 0x71, 0x07, 0x45, 0x3d, 0xcf, 0x19, 0xc7, 0xee, 0x4b, 0x37, 0xbe, 0x20, 0x25, 0xba, 0x60, 0x64, - 0x41, 0xe2, 0x09, 0x68, 0x53, 0xc9, 0x94, 0x4d, 0x9f, 0xb9, 0x32, 0xa9, 0xcc, 0xd5, 0x07, 0xaf, - 0xcb, 0x89, 0xb8, 0x9c, 0x65, 0x1b, 0x1b, 0xd3, 0x3c, 0x62, 0x7b, 0x0d, 0x4a, 0xce, 0xf9, 0x34, - 0x7c, 0x5a, 0x2a, 0x6f, 0x69, 0x4d, 0xfd, 0x29, 0x6c, 0xcc, 0xd5, 0x1e, 0xf7, 0xd3, 0x69, 0x18, - 0x1c, 0x23, 0x2b, 0x97, 0x02, 0x55, 0xdd, 0xa8, 0x48, 0x48, 0xd7, 0x16, 0x4d, 0x58, 0x0f, 0x42, - 0xdb, 0xf5, 0xa5, 0xad, 0xa6, 0x6e, 0xa8, 0xa4, 0xfe, 0x57, 0x57, 0xa0, 0x9e, 0xeb, 0xba, 0xef, - 0x2b, 0xea, 0x4d, 0xa8, 0x07, 0xe3, 0xf1, 0x2c, 0x0c, 0x1d, 0x7f, 0x9c, 0xe8, 0x00, 0x75, 0xa3, - 0x96, 0x02, 0xbb, 0x24, 0xd7, 0x47, 0xb1, 0x75, 0x4c, 0xf8, 0x22, 0x7f, 0x90, 0xd2, 0x5d, 0x5b, - 0x7c, 0x8c, 0xba, 0x91, 0x3d, 0x1b, 0x3b, 0xa1, 0xdc, 0xd2, 0x5f, 0xa5, 0x6b, 0x28, 0x32, 0xa1, - 0xc3, 0x9a, 0xeb, 0x4f, 0x67, 0x31, 0x6e, 0x0b, 0xf3, 0xd2, 0x84, 0xc4, 0xa0, 0x26, 0xef, 0x9d, - 0xa0, 0x40, 0x36, 0x4f, 0x80, 0x60, 0x71, 0x0f, 0x60, 0x1c, 0x4c, 0xa6, 0x56, 0xe8, 0x46, 0x81, - 0x2f, 0x97, 0x61, 0x96, 0x28, 0x83, 0xd5, 0xff, 0xf9, 0x02, 0x88, 0x4c, 0xef, 0xee, 0x73, 0xc3, - 0x71, 0xa7, 0x0c, 0x83, 0x20, 0xa6, 0x8d, 0x4d, 0x09, 0xac, 0x08, 0xc0, 0xbd, 0x4c, 0x7c, 0x02, - 0x55, 0xaa, 0x07, 0x6d, 0x08, 0x73, 0x42, 0x4f, 0x86, 0x63, 0x01, 0x11, 0x21, 0x20, 0x12, 0x0f, - 0xa1, 0x16, 0xcc, 0xe2, 0x34, 0x4f, 0xf1, 0x15, 0x79, 0xaa, 0x4c, 0x45, 0x99, 0xf4, 0xff, 0xad, - 0x00, 0x5a, 0x76, 0xe4, 0xb1, 0x4b, 0x71, 0xbc, 0x82, 0x33, 0x1f, 0x35, 0x8e, 0xb4, 0x6a, 0x15, - 0x82, 0x50, 0xdd, 0x3e, 0x82, 0xd2, 0xa9, 0xeb, 0xf3, 0x30, 0x35, 0x1e, 0xbc, 0xb6, 0x38, 0xf9, - 0xb1, 0x90, 0xfb, 0xcf, 0x5c, 0xdf, 0x36, 0x88, 0x90, 0xcc, 0x1e, 0x13, 0x1c, 0x3b, 0x65, 0x63, - 0xe4, 0x01, 0xac, 0x11, 0x50, 0xd9, 0x17, 0x4f, 0xa0, 0x84, 0x59, 0x44, 0x05, 0x56, 0xbb, 0xfd, - 0xfd, 0x83, 0x91, 0x76, 0x49, 0xd4, 0xa1, 0xf2, 0x74, 0xd0, 0xed, 0x9b, 0xfb, 0xad, 0xae, 0xa1, - 0x15, 0x10, 0xf3, 0xd8, 0x18, 0x1c, 0xec, 0x6b, 0x2b, 0x28, 0x0d, 0xbd, 0xe8, 0xf6, 0x77, 0x06, - 0x2f, 0xcc, 0x61, 0x67, 0x74, 0xb0, 0xaf, 0x15, 0x51, 0x79, 0x93, 0x10, 0x63, 0xf0, 0x42, 0x2b, - 0x61, 0xba, 0x35, 0x1c, 0x76, 0x1f, 0xf7, 0xf7, 0x3a, 0xfd, 0x91, 0xb6, 0x8a, 0x99, 0x8d, 0xc1, - 0xc1, 0xa8, 0xa3, 0xad, 0xe9, 0xff, 0x43, 0x21, 0x3f, 0xdb, 0xa7, 0xce, 0x18, 0xa7, 0xb3, 0xaa, - 0x1c, 0xcf, 0x4f, 0x95, 0x44, 0x99, 0x96, 0xf6, 0x35, 0xd9, 0xb7, 0x51, 0xec, 0x4c, 0xa5, 0x5c, - 0xd3, 0x40, 0xf8, 0x80, 0xc0, 0xc3, 0xd8, 0x99, 0x92, 0xbe, 0x15, 0x3b, 0x53, 0x93, 0x7a, 0x8a, - 0xfb, 0xbf, 0x6e, 0x00, 0x82, 0x06, 0x04, 0x11, 0x9f, 0x42, 0x59, 0xce, 0x7a, 0x16, 0xaa, 0xab, - 0x0f, 0x9a, 0x0b, 0x9d, 0x27, 0x67, 0x87, 0x91, 0x50, 0x8a, 0xfb, 0xb0, 0x46, 0x33, 0x5d, 0x4d, - 0xd6, 0xab, 0xcb, 0x3b, 0xdc, 0x90, 0x54, 0xfa, 0x13, 0x58, 0x97, 0x3c, 0x6e, 0xc1, 0xee, 0x7e, - 0x1d, 0xca, 0x6e, 0x84, 0x32, 0x70, 0x14, 0x4b, 0xab, 0xcb, 0xba, 0x1b, 0xb5, 0x31, 0x89, 0xca, - 0x10, 0x32, 0x0a, 0x29, 0x38, 0xd3, 0x6f, 0xfd, 0xdf, 0x2b, 0x00, 0xa4, 0x5c, 0x15, 0x19, 0x96, - 0xe7, 0xf8, 0xca, 0xc2, 0xe3, 0x39, 0x7e, 0x92, 0x69, 0x25, 0xcd, 0xb4, 0x68, 0xe3, 0x2a, 0x2e, - 0xb1, 0x71, 0x2d, 0xd8, 0xa9, 0x4a, 0xbf, 0x81, 0x9d, 0x6a, 0xf5, 0x7b, 0xec, 0x54, 0xfa, 0x75, - 0x64, 0xed, 0xd2, 0x4c, 0x29, 0x6a, 0x50, 0xb0, 0xa4, 0x52, 0x5e, 0xb0, 0xf4, 0xbb, 0x00, 0xa9, - 0x21, 0x32, 0x8f, 0xc3, 0x94, 0x52, 0xd5, 0x0b, 0x87, 0xfa, 0x4f, 0xa1, 0x26, 0x45, 0xbe, 0xc0, - 0xdb, 0x71, 0x8e, 0xc4, 0x07, 0x00, 0x49, 0x3a, 0x92, 0xb6, 0x93, 0x74, 0x17, 0xdf, 0x71, 0x8e, - 0x8c, 0x0c, 0x5e, 0xff, 0x5f, 0x56, 0xc9, 0x0a, 0xb5, 0xc3, 0xe6, 0x1f, 0x69, 0xe7, 0x29, 0x64, - 0xec, 0x3c, 0x89, 0x16, 0xba, 0x92, 0xb7, 0x8d, 0x9d, 0xb8, 0xb6, 0xed, 0xf8, 0xca, 0x06, 0xc6, - 0x29, 0xdc, 0xf6, 0x2c, 0xef, 0x58, 0x72, 0x39, 0xa1, 0x3e, 0x3a, 0x99, 0x86, 0x4e, 0x14, 0xb1, - 0x35, 0xc5, 0xf2, 0x8e, 0x95, 0x94, 0xb3, 0xfa, 0x5d, 0x52, 0xce, 0x75, 0x28, 0xa3, 0x22, 0x4e, - 0x26, 0x78, 0x96, 0x71, 0xd7, 0xe5, 0xf1, 0x8b, 0x78, 0x17, 0xd6, 0xa5, 0xf1, 0x54, 0xf2, 0xb5, - 0xba, 0xda, 0x0e, 0x09, 0x68, 0x28, 0x2c, 0x1d, 0x92, 0x04, 0x93, 0x09, 0xee, 0x9b, 0xd2, 0x7a, - 0x20, 0x93, 0xe2, 0x7d, 0xa8, 0x04, 0xbe, 0xc9, 0x16, 0x56, 0x29, 0x5f, 0xc8, 0x8d, 0x7c, 0xe0, - 0x1f, 0x10, 0xd4, 0x28, 0x07, 0xf2, 0x17, 0x56, 0xc5, 0x0b, 0xce, 0xcc, 0xb1, 0x15, 0xda, 0x24, - 0x63, 0x94, 0x8d, 0x75, 0x2f, 0x38, 0x6b, 0x5b, 0xa1, 0xcd, 0xd6, 0x94, 0x6f, 0xfd, 0xd9, 0x84, - 0xe4, 0x8a, 0xba, 0x21, 0x53, 0xe2, 0x26, 0x54, 0xc6, 0xde, 0x2c, 0x8a, 0x9d, 0x70, 0xfb, 0x42, - 0x0a, 0x8b, 0x29, 0x00, 0xeb, 0x35, 0x0d, 0xdd, 0x89, 0x15, 0x5e, 0x48, 0xa9, 0x50, 0x25, 0x49, - 0xa5, 0x3d, 0x75, 0xed, 0x73, 0x36, 0x9c, 0x1b, 0x9c, 0x40, 0xfa, 0x13, 0x3a, 0xd6, 0x88, 0x48, - 0x52, 0x28, 0x1b, 0x2a, 0x49, 0xe3, 0x40, 0x3f, 0x69, 0xe7, 0xae, 0x18, 0x32, 0x95, 0x33, 0x05, - 0x6e, 0xbe, 0xd2, 0x14, 0x28, 0xe6, 0xad, 0x31, 0x41, 0xe8, 0x1e, 0xbb, 0xd2, 0x96, 0x72, 0x99, - 0xad, 0x31, 0x0c, 0x22, 0x82, 0x2f, 0xa0, 0x7e, 0xec, 0xf8, 0x4e, 0x68, 0xb1, 0x6c, 0xcb, 0xa6, - 0xee, 0xaa, 0x1a, 0xe6, 0xc7, 0x0a, 0x85, 0x52, 0x57, 0xed, 0x38, 0x93, 0xc2, 0x5a, 0x4a, 0x7d, - 0xfc, 0x0a, 0xcf, 0x16, 0x4e, 0xa1, 0xa2, 0x2f, 0xbf, 0x98, 0x54, 0xf6, 0x2a, 0x2b, 0xfa, 0x0c, - 0x1e, 0xc9, 0x2a, 0xef, 0x80, 0x50, 0x2a, 0x4f, 0xe0, 0xcd, 0x26, 0xbe, 0x49, 0xdc, 0xfd, 0x5a, - 0x76, 0x2b, 0x4d, 0x66, 0xf4, 0x6c, 0xe2, 0x13, 0x63, 0xd7, 0xc2, 0x39, 0x88, 0xfe, 0x2d, 0xac, - 0xcb, 0x19, 0x82, 0xaa, 0x3a, 0xca, 0x16, 0x79, 0x39, 0x9b, 0x55, 0x75, 0x84, 0xd3, 0x86, 0xcf, - 0x15, 0xe3, 0xf5, 0x2e, 0xe7, 0x7e, 0x8d, 0x81, 0x6c, 0xc5, 0x15, 0x6f, 0x40, 0x8d, 0x14, 0x03, - 0x4b, 0x9e, 0xa0, 0x15, 0xa5, 0xa5, 0x68, 0xe6, 0x79, 0x2d, 0x06, 0xe9, 0x03, 0x28, 0xab, 0xf9, - 0xf4, 0xe7, 0xf2, 0x4d, 0x7d, 0x0a, 0xb5, 0x6c, 0x3f, 0xff, 0xf9, 0x34, 0x84, 0x2d, 0x26, 0x51, - 0x1c, 0x84, 0x09, 0x33, 0x2c, 0xbb, 0xd1, 0x90, 0xd2, 0xfa, 0x1f, 0xae, 0x40, 0x95, 0x2c, 0x37, - 0x03, 0xb2, 0x4b, 0x89, 0x0f, 0x40, 0x8c, 0x43, 0xc7, 0x8a, 0x1d, 0xd3, 0x39, 0x8f, 0x43, 0x4b, - 0xda, 0x67, 0x58, 0xc9, 0xd6, 0x18, 0xd3, 0x41, 0x04, 0x9b, 0x68, 0x6e, 0x43, 0x75, 0x6a, 0x85, - 0x91, 0xb2, 0x0d, 0xf2, 0xd7, 0x81, 0x41, 0xd2, 0x32, 0xa7, 0xf9, 0x24, 0x77, 0xc5, 0xc1, 0xa9, - 0xe3, 0xb3, 0x55, 0x94, 0xed, 0xc1, 0x0d, 0x82, 0x8f, 0x10, 0x3c, 0x74, 0x7f, 0x85, 0x7a, 0x1c, - 0xa0, 0x8a, 0x27, 0x3b, 0x9b, 0x39, 0xcc, 0x4d, 0x6e, 0x70, 0xa6, 0x7e, 0xf7, 0x9f, 0x27, 0x34, - 0x46, 0x86, 0x5e, 0xff, 0x25, 0x40, 0x8a, 0x11, 0x37, 0xe0, 0xea, 0xf3, 0xee, 0xb0, 0xbb, 0xdd, - 0xed, 0x75, 0x47, 0x5f, 0x9b, 0x07, 0xfd, 0xe1, 0x7e, 0xa7, 0xdd, 0xdd, 0xed, 0x76, 0x76, 0xb4, - 0x4b, 0xe2, 0x2a, 0x88, 0x0c, 0x8e, 0x7e, 0xf6, 0x3a, 0x5a, 0x41, 0x34, 0x61, 0x2b, 0x03, 0xef, - 0xf6, 0x15, 0x66, 0x45, 0xff, 0xef, 0x0b, 0x50, 0xdf, 0xe7, 0x05, 0xfc, 0xcc, 0xb9, 0xd8, 0xe1, - 0xe3, 0x84, 0xb1, 0x62, 0xbe, 0x25, 0x83, 0x7e, 0x8b, 0x5b, 0x50, 0x9d, 0x9e, 0x3a, 0x17, 0x66, - 0xce, 0x94, 0x5e, 0x41, 0x50, 0x9b, 0xd8, 0xec, 0x7b, 0xb0, 0x16, 0x50, 0x13, 0xa4, 0xe2, 0xb6, - 0xb9, 0xd0, 0x36, 0x43, 0x12, 0x08, 0x1d, 0xea, 0x49, 0x51, 0x59, 0x63, 0x9e, 0x2c, 0x8c, 0x3a, - 0x76, 0x0b, 0x56, 0x11, 0xc5, 0x7b, 0x72, 0xc5, 0xe0, 0x84, 0xf8, 0x18, 0xea, 0x28, 0xf7, 0x99, - 0x2a, 0xbb, 0x54, 0xe1, 0xf2, 0xdb, 0x43, 0x15, 0x49, 0xf6, 0xb9, 0x2c, 0xfd, 0xff, 0x2a, 0x42, - 0x99, 0xea, 0x20, 0x77, 0x08, 0xd7, 0x3e, 0x57, 0x3b, 0x44, 0xc5, 0x58, 0x75, 0x6d, 0x54, 0x14, - 0xbe, 0xc7, 0x9e, 0x97, 0xd8, 0xe9, 0x8a, 0x59, 0x3b, 0x5d, 0xca, 0x14, 0x4a, 0x39, 0xa6, 0xb0, - 0xcc, 0x44, 0xb7, 0xba, 0xcc, 0x44, 0x87, 0x93, 0x8b, 0x69, 0x9c, 0x73, 0x37, 0xb1, 0x84, 0x00, - 0x81, 0x3a, 0x08, 0xc9, 0xf2, 0xff, 0xf5, 0x3c, 0xff, 0x47, 0x69, 0x0a, 0xa7, 0x83, 0xc7, 0x76, - 0xe5, 0xb2, 0xa1, 0x92, 0x99, 0x61, 0xa8, 0x7c, 0xdf, 0x30, 0x24, 0xcd, 0xb6, 0xbc, 0x63, 0xb6, - 0x2b, 0xab, 0x66, 0xb7, 0xbc, 0xe3, 0x40, 0x7c, 0x02, 0x57, 0x52, 0xb4, 0x6c, 0x0d, 0x99, 0xf5, - 0xe8, 0x64, 0xd5, 0x10, 0x09, 0x25, 0xb5, 0x88, 0x0c, 0x78, 0xf7, 0x60, 0x33, 0x93, 0x85, 0xac, - 0x52, 0x11, 0x6d, 0x1f, 0x15, 0x63, 0x23, 0x21, 0x27, 0x55, 0x3e, 0x12, 0xef, 0x61, 0x3f, 0x8d, - 0xbd, 0x99, 0xcd, 0xcc, 0x78, 0x36, 0xf1, 0xa3, 0x66, 0x9d, 0x3a, 0x78, 0x43, 0xc1, 0x99, 0xf9, - 0x91, 0xe5, 0x11, 0xc7, 0xfb, 0x28, 0x08, 0x27, 0x56, 0x4c, 0x5b, 0x48, 0xdd, 0xa8, 0x9c, 0x3a, - 0x17, 0xbb, 0x04, 0x78, 0x5a, 0x2a, 0x37, 0xb4, 0x0d, 0xa3, 0x91, 0xae, 0x16, 0x33, 0x72, 0x62, - 0xfd, 0xf7, 0x57, 0xa1, 0xbe, 0x1b, 0x84, 0x8e, 0x7b, 0xec, 0xa7, 0xb3, 0x7a, 0xc1, 0x1c, 0xad, - 0x66, 0xfa, 0x4a, 0x66, 0xa6, 0xdf, 0x86, 0xea, 0x11, 0x67, 0x44, 0xbe, 0x4e, 0xd3, 0xb9, 0x64, - 0x80, 0x04, 0x8d, 0x0e, 0x3d, 0xe4, 0x9c, 0x8a, 0x80, 0x32, 0x97, 0x28, 0xb3, 0xca, 0x84, 0x62, - 0x89, 0xf8, 0x09, 0x6d, 0xd0, 0xb6, 0xe3, 0x39, 0x31, 0x0f, 0x7f, 0x43, 0x29, 0x90, 0xb9, 0x3a, - 0xdd, 0x37, 0x9c, 0xa3, 0x16, 0xd9, 0x14, 0x70, 0xbf, 0xde, 0x21, 0x72, 0x99, 0x57, 0x6e, 0xee, - 0x6b, 0x3f, 0x30, 0xaf, 0xe4, 0xd2, 0x0f, 0xe0, 0x4a, 0xe8, 0x1c, 0x39, 0xa4, 0xd4, 0xd9, 0x66, - 0x66, 0x56, 0xf3, 0x04, 0xba, 0x9c, 0x22, 0xbb, 0xc9, 0xfc, 0xde, 0x03, 0x2d, 0xa9, 0xab, 0xc9, - 0x9c, 0x95, 0x66, 0x55, 0xe3, 0xc1, 0x9b, 0xdf, 0xf9, 0xd9, 0x01, 0x91, 0x1a, 0x0d, 0x55, 0x71, - 0x4e, 0xcb, 0xe2, 0xb8, 0xfa, 0xaa, 0xb8, 0xca, 0x8f, 0x2a, 0x8e, 0xdb, 0xc2, 0x69, 0x7d, 0x04, - 0x95, 0x84, 0x44, 0xd4, 0xa0, 0x6c, 0x74, 0xa4, 0xc9, 0xf6, 0x92, 0xa8, 0xc2, 0x7a, 0xbb, 0x35, - 0x6c, 0xb7, 0x76, 0x90, 0xbf, 0xd5, 0xa0, 0x3c, 0xec, 0x8c, 0xd8, 0x4c, 0xbb, 0x22, 0x36, 0xa0, - 0x8a, 0xa9, 0x9d, 0xce, 0x6e, 0xeb, 0xa0, 0x37, 0xd2, 0x8a, 0xa8, 0xea, 0xf4, 0x07, 0x66, 0xab, - 0x3d, 0xea, 0x0e, 0xfa, 0x5a, 0x49, 0xf7, 0x60, 0x63, 0xee, 0xc3, 0xc8, 0x54, 0x19, 0x6d, 0x0e, - 0x8c, 0xee, 0xe3, 0x6e, 0xdf, 0xec, 0x7c, 0xb5, 0xdf, 0xeb, 0xb6, 0xbb, 0xf8, 0xa5, 0xeb, 0x70, - 0x25, 0x8f, 0x53, 0x05, 0x17, 0x84, 0x0e, 0xb7, 0xf2, 0xa8, 0x5e, 0xe7, 0x71, 0xab, 0xfd, 0xb5, - 0xd9, 0xda, 0xdb, 0xee, 0x3e, 0x3e, 0x18, 0x1c, 0x0c, 0xb5, 0x15, 0xdd, 0x84, 0x72, 0xfb, 0xc4, - 0x19, 0x9f, 0xbe, 0x6a, 0x16, 0xd2, 0xa9, 0x9b, 0x33, 0x3e, 0x95, 0x46, 0xb1, 0xb9, 0x53, 0x37, - 0x67, 0x7c, 0x4a, 0x1a, 0xa3, 0xdc, 0x08, 0xbf, 0xf5, 0xe4, 0x71, 0x42, 0x45, 0xee, 0x82, 0xdf, - 0x7a, 0x7a, 0x07, 0x2a, 0xfb, 0x56, 0x18, 0xbb, 0xd4, 0x49, 0x8f, 0xa0, 0x9e, 0x24, 0x76, 0x9c, - 0x23, 0x25, 0x43, 0x8b, 0xc4, 0x92, 0x96, 0xa0, 0x8c, 0x3c, 0xa1, 0xfe, 0x01, 0xd4, 0xb2, 0x00, - 0x54, 0xd1, 0x6d, 0xe7, 0x68, 0xc9, 0xee, 0x8c, 0x60, 0xfd, 0x39, 0xd4, 0xda, 0x4a, 0x26, 0x7c, - 0x55, 0xcb, 0x1e, 0x40, 0x83, 0x18, 0xf6, 0xf8, 0x50, 0x71, 0xec, 0x95, 0x25, 0x1c, 0xbb, 0x86, - 0x34, 0xed, 0x43, 0xc9, 0xb2, 0x3f, 0x83, 0xea, 0x7e, 0x18, 0x4c, 0x9d, 0x30, 0xa6, 0x62, 0x35, - 0x28, 0x9e, 0x3a, 0x17, 0xb2, 0x54, 0xfc, 0x99, 0x9e, 0x95, 0xae, 0x64, 0xcf, 0x4a, 0x1f, 0x40, - 0x59, 0x65, 0xfb, 0xc1, 0x79, 0x7e, 0x86, 0x3b, 0x1f, 0xe5, 0x71, 0x9d, 0x08, 0x3f, 0x76, 0x9f, - 0x2c, 0x29, 0x12, 0x20, 0x3b, 0x4e, 0x99, 0x20, 0x65, 0xe1, 0x46, 0x86, 0x42, 0x7f, 0x1d, 0xd6, - 0x9f, 0xbb, 0xce, 0x99, 0x6c, 0xfe, 0x4b, 0xd7, 0x39, 0x53, 0xcd, 0xc7, 0xdf, 0xfa, 0x5f, 0xab, - 0x42, 0x99, 0xd8, 0xe3, 0xce, 0xab, 0x8f, 0xa7, 0x7f, 0x8c, 0x7e, 0x72, 0x47, 0xb2, 0xab, 0xd2, - 0x12, 0xad, 0x88, 0x99, 0xd7, 0xeb, 0x00, 0x19, 0x56, 0xcd, 0x1b, 0x4f, 0x25, 0x4e, 0x38, 0x34, - 0x0a, 0xf6, 0x24, 0xe4, 0xe0, 0x34, 0xe2, 0x93, 0xa3, 0x14, 0x20, 0xee, 0xb3, 0xd8, 0x4d, 0x67, - 0x45, 0xeb, 0x59, 0x4b, 0x1d, 0xb5, 0x41, 0x99, 0x3f, 0x49, 0x16, 0xc7, 0x44, 0x56, 0xa9, 0x2f, - 0xe7, 0x95, 0xfa, 0x77, 0xa1, 0x84, 0x7b, 0xb4, 0x34, 0x57, 0x5e, 0x56, 0x3d, 0x98, 0x11, 0x32, - 0x0c, 0x22, 0x10, 0x77, 0x61, 0x9d, 0xb8, 0x94, 0x83, 0x1b, 0x45, 0xa6, 0xb7, 0xd5, 0x9e, 0x6d, - 0x28, 0xb4, 0x78, 0x0f, 0x56, 0x8f, 0x4e, 0x9d, 0x0b, 0xde, 0x25, 0x92, 0x32, 0x73, 0xcc, 0xc4, - 0x60, 0x0a, 0xf1, 0x16, 0x34, 0x42, 0xe7, 0xc8, 0xa4, 0x03, 0x6b, 0xe4, 0xe1, 0x51, 0xb3, 0x41, - 0x2c, 0xba, 0x16, 0x3a, 0x47, 0x6d, 0x04, 0x8e, 0x0e, 0xbd, 0x48, 0xbc, 0x03, 0x6b, 0xb4, 0xb8, - 0x50, 0x2b, 0xc9, 0x7c, 0x59, 0xad, 0x54, 0x43, 0x62, 0xc5, 0x27, 0x00, 0x52, 0xf7, 0x31, 0x0f, - 0x2f, 0x48, 0xc2, 0x4f, 0x16, 0x53, 0x76, 0xfe, 0x67, 0x35, 0xa4, 0x77, 0x61, 0x15, 0x27, 0x49, - 0xd4, 0xbc, 0x46, 0x25, 0x6f, 0xe6, 0x67, 0x10, 0xd5, 0x94, 0xf0, 0xe2, 0x2e, 0x94, 0x71, 0xa2, - 0xd0, 0xaa, 0x6e, 0x66, 0x95, 0x41, 0x39, 0xab, 0x70, 0x63, 0x77, 0xce, 0x86, 0xdf, 0x7a, 0xe2, - 0x1e, 0x94, 0x6c, 0x5c, 0xcc, 0xd7, 0xb3, 0x36, 0x0a, 0x35, 0xb7, 0x50, 0x77, 0x24, 0xfd, 0x94, - 0x68, 0xc4, 0x13, 0x68, 0xe0, 0x34, 0x7a, 0x40, 0xb2, 0x1a, 0x76, 0x5f, 0xf3, 0x06, 0xe5, 0x7a, - 0x63, 0x2e, 0x57, 0x5f, 0x12, 0x51, 0x67, 0x77, 0xfc, 0x38, 0xbc, 0x30, 0xea, 0x7e, 0x16, 0x26, - 0x6e, 0x40, 0xd9, 0x8d, 0x7a, 0xc1, 0xf8, 0x34, 0xf1, 0xa5, 0x49, 0xd2, 0xe2, 0x4b, 0xa8, 0xd3, - 0xc4, 0xc2, 0x24, 0x7e, 0x5c, 0x3a, 0xd2, 0x64, 0xa7, 0x8c, 0x42, 0x19, 0x79, 0x4a, 0xdc, 0x41, - 0xdd, 0xc8, 0x8c, 0x9d, 0xc9, 0x34, 0x08, 0x51, 0x8d, 0x7c, 0x5d, 0x1d, 0xb2, 0x8e, 0x14, 0x08, - 0xe5, 0xa8, 0xc4, 0x41, 0xd1, 0x0c, 0x8e, 0x8e, 0x22, 0x27, 0x26, 0xc7, 0x99, 0x92, 0xd1, 0x50, - 0x7e, 0x8a, 0x03, 0x82, 0x92, 0x1c, 0x13, 0x99, 0xf6, 0x85, 0x6f, 0x4d, 0xdc, 0x71, 0xf3, 0x36, - 0x6b, 0xab, 0x6e, 0xb4, 0xc3, 0x80, 0xac, 0xc2, 0x78, 0x27, 0xa7, 0x30, 0x5e, 0x86, 0x55, 0xfb, - 0x10, 0x97, 0xe3, 0x1b, 0x54, 0x6c, 0xc9, 0x3e, 0xec, 0xda, 0xe2, 0x43, 0x3a, 0x5e, 0x63, 0x16, - 0xd8, 0xd4, 0xb3, 0x07, 0x04, 0x09, 0x67, 0x34, 0x52, 0x0a, 0x71, 0x07, 0xaa, 0xbb, 0x8e, 0x15, - 0xcf, 0x42, 0x67, 0xd7, 0xb3, 0x8e, 0x9b, 0x6f, 0x52, 0x49, 0x59, 0x10, 0xd6, 0xce, 0x0b, 0x8e, - 0xdd, 0xb1, 0x45, 0x2b, 0xff, 0x2d, 0x16, 0x9b, 0x25, 0x44, 0xda, 0x66, 0x89, 0x8d, 0x5b, 0x52, - 0x16, 0x7e, 0x3b, 0xab, 0xe1, 0x58, 0x9e, 0x3a, 0x51, 0x4e, 0xfb, 0xc2, 0x99, 0x06, 0xe3, 0x93, - 0xe6, 0x3b, 0xb4, 0xde, 0xea, 0xaa, 0x2b, 0x3a, 0x08, 0x14, 0xef, 0xc2, 0x86, 0xb4, 0x1d, 0x98, - 0xca, 0xbb, 0xf2, 0x5d, 0xa2, 0x6b, 0x48, 0x70, 0x5b, 0x3a, 0x59, 0xea, 0x50, 0xe7, 0x02, 0x6d, - 0x73, 0x6c, 0x8d, 0x4f, 0x9c, 0xe6, 0x5d, 0xae, 0x38, 0x15, 0x67, 0xb7, 0x11, 0x34, 0x27, 0x75, - 0xbd, 0x37, 0x27, 0x75, 0x2d, 0xf7, 0x6d, 0xbc, 0xb7, 0xdc, 0xb7, 0xf1, 0xc6, 0x63, 0xd2, 0x5d, - 0x69, 0xe8, 0x3f, 0x9b, 0xe3, 0xb0, 0x39, 0xfe, 0x90, 0x61, 0xc5, 0x4f, 0x2e, 0x65, 0x19, 0xed, - 0xf6, 0x2a, 0x6d, 0x45, 0x37, 0x7e, 0x0e, 0x62, 0x71, 0xd2, 0x7e, 0x1f, 0xbb, 0x5f, 0x95, 0xec, - 0xfe, 0x27, 0x2b, 0x8f, 0x0a, 0xfa, 0x3f, 0x53, 0x80, 0x7a, 0x8e, 0x9d, 0x2d, 0xdd, 0xb7, 0x58, - 0xe6, 0xb7, 0x26, 0xd2, 0xf2, 0xc6, 0x09, 0xa5, 0x69, 0xba, 0xfe, 0xb1, 0xe7, 0x64, 0x34, 0x4d, - 0x4a, 0x3f, 0x2d, 0x95, 0x4b, 0xda, 0xea, 0xd3, 0x52, 0x79, 0x55, 0x5b, 0x33, 0x2e, 0x1f, 0xcd, - 0x3c, 0x2f, 0x76, 0xce, 0x63, 0x75, 0x4a, 0x1a, 0x3a, 0x47, 0x86, 0x48, 0x80, 0x2c, 0x97, 0x85, - 0xce, 0x91, 0xfe, 0x5f, 0x14, 0xa1, 0xf6, 0xc4, 0x8a, 0x4e, 0xf6, 0xac, 0xe9, 0x30, 0xb6, 0xe2, - 0x08, 0x57, 0xc6, 0x89, 0x15, 0x9d, 0x4c, 0xac, 0x29, 0x2b, 0x93, 0x05, 0x3e, 0xa3, 0x90, 0x30, - 0xd2, 0x24, 0x6f, 0x40, 0x19, 0x93, 0x03, 0x7f, 0xff, 0x99, 0x34, 0x32, 0x26, 0x69, 0xe4, 0xc8, - 0xd1, 0xc9, 0xec, 0xe8, 0x28, 0xa9, 0x9f, 0x4a, 0x8a, 0xb7, 0xa0, 0x2e, 0x7f, 0x92, 0xbe, 0x76, - 0x2e, 0xcf, 0x79, 0xf3, 0x40, 0xf1, 0x10, 0xaa, 0x12, 0x30, 0x52, 0xfb, 0x47, 0x23, 0x39, 0xba, - 0x4a, 0x11, 0x46, 0x96, 0x4a, 0xfc, 0x02, 0xae, 0x64, 0x92, 0xbb, 0x41, 0xb8, 0x37, 0xf3, 0x62, - 0xb7, 0xdd, 0x97, 0xc2, 0xeb, 0x6b, 0x0b, 0xd9, 0x53, 0x12, 0x63, 0x79, 0xce, 0x7c, 0x6d, 0xf7, - 0x5c, 0x3e, 0x01, 0x28, 0x1a, 0x79, 0xe0, 0x1c, 0x95, 0x75, 0x4e, 0xbb, 0x50, 0x9e, 0xca, 0x3a, - 0x47, 0x3e, 0x25, 0x01, 0x7b, 0x4e, 0x7c, 0x12, 0xd8, 0x52, 0x1a, 0xbd, 0x9c, 0xab, 0x16, 0xa3, - 0x8c, 0x3c, 0x25, 0x76, 0xa7, 0x3f, 0xf3, 0xbc, 0xb1, 0x1f, 0x93, 0x7e, 0x54, 0x34, 0x54, 0x12, - 0x77, 0xe8, 0xd0, 0xf2, 0x8f, 0x9d, 0xa8, 0x59, 0xbd, 0x53, 0xbc, 0x5b, 0x30, 0x64, 0x4a, 0xff, - 0x1b, 0x2b, 0xb0, 0xca, 0x23, 0xf9, 0x1a, 0x54, 0x0e, 0xc9, 0x0f, 0xc7, 0x9f, 0x4d, 0xd4, 0xf1, - 0x03, 0x01, 0xfa, 0xb3, 0x09, 0xeb, 0x1d, 0xd2, 0x48, 0x5c, 0x30, 0xe8, 0x37, 0x16, 0x19, 0xcc, - 0x62, 0xfc, 0x56, 0x91, 0xa0, 0x32, 0x85, 0x95, 0x08, 0x83, 0x33, 0x9a, 0x0d, 0x25, 0x42, 0xa8, - 0x24, 0xb9, 0xe4, 0xd0, 0x66, 0x8f, 0x99, 0x56, 0x09, 0x57, 0x26, 0x40, 0xdb, 0x8f, 0xe7, 0x0f, - 0xbb, 0xd6, 0x16, 0x0f, 0xbb, 0x6e, 0x01, 0x6a, 0x35, 0x63, 0x67, 0xe0, 0x3b, 0xed, 0xbe, 0x3c, - 0x51, 0xcf, 0x40, 0x70, 0x59, 0xd9, 0xc1, 0x54, 0x1e, 0x95, 0xe3, 0x4f, 0xf1, 0x79, 0x32, 0x3b, - 0xa9, 0x8d, 0x52, 0xc7, 0x94, 0x9b, 0x61, 0x76, 0x1e, 0x1b, 0x39, 0x3a, 0x2c, 0x09, 0x77, 0x38, - 0xd6, 0x31, 0xf1, 0xa7, 0xde, 0x01, 0x30, 0x82, 0xb3, 0xc8, 0xe1, 0x03, 0xac, 0x6b, 0xd4, 0xc4, - 0x9c, 0xf7, 0x5d, 0x70, 0xb6, 0x1f, 0x44, 0x89, 0x81, 0x68, 0x65, 0xb9, 0x81, 0x48, 0xff, 0x08, - 0xd6, 0x51, 0xfc, 0xb1, 0x62, 0x4b, 0xbc, 0x25, 0x6d, 0xe5, 0x2c, 0xb4, 0xc9, 0x33, 0xcb, 0xf4, - 0x1b, 0xd2, 0xe4, 0xde, 0x53, 0xdf, 0xa5, 0x3c, 0x6f, 0x64, 0x0c, 0x1d, 0xc9, 0xd6, 0x2b, 0x0b, - 0x94, 0x02, 0x15, 0x9d, 0x22, 0x9d, 0x99, 0xe4, 0x66, 0xa4, 0xfc, 0x2d, 0xc2, 0xe0, 0xac, 0x8d, - 0x69, 0xfd, 0x1f, 0x14, 0xa0, 0x3a, 0x08, 0x6d, 0xdc, 0xf3, 0xe9, 0x94, 0xe3, 0xfb, 0xec, 0x59, - 0x28, 0x7e, 0x29, 0xde, 0xa8, 0x0c, 0x0d, 0x09, 0x40, 0x7c, 0x02, 0xa5, 0x23, 0xdc, 0x45, 0x8a, - 0x59, 0x9d, 0x2f, 0x53, 0xbc, 0xfa, 0x8d, 0xfb, 0x8a, 0x41, 0xa4, 0xfa, 0xef, 0x26, 0xdf, 0xa7, - 0xcd, 0x26, 0xeb, 0xf8, 0x72, 0x89, 0x5c, 0xe8, 0x86, 0x6d, 0xad, 0x20, 0xca, 0x50, 0xda, 0xe9, - 0x0c, 0xdb, 0xac, 0x17, 0xa1, 0x86, 0x34, 0x34, 0x77, 0xbb, 0xc6, 0x70, 0xc4, 0xc7, 0x38, 0x0c, - 0xe8, 0xb5, 0x86, 0x23, 0xad, 0x2c, 0x00, 0xd6, 0x0e, 0xfa, 0xdd, 0x5f, 0x1c, 0x74, 0x34, 0x4d, - 0xff, 0x7b, 0x05, 0x80, 0xf4, 0x4c, 0x5b, 0xbc, 0x0f, 0xd5, 0x33, 0x4a, 0x99, 0x19, 0x67, 0xa2, - 0xdc, 0x99, 0x1c, 0xa3, 0x49, 0x34, 0xfc, 0x10, 0x6a, 0xc9, 0x2e, 0x89, 0x62, 0xd3, 0xa2, 0x57, - 0x51, 0x35, 0xc1, 0x6f, 0x5f, 0x88, 0x0f, 0xa0, 0x1c, 0x60, 0x3b, 0x90, 0xb4, 0x98, 0x95, 0x99, - 0x32, 0xcd, 0xa7, 0x13, 0x50, 0x25, 0x5e, 0x1d, 0x85, 0xca, 0x70, 0x94, 0x90, 0xee, 0x22, 0xa8, - 0xed, 0x59, 0xb3, 0xc8, 0x31, 0x18, 0x9f, 0xb0, 0xf6, 0xd5, 0x94, 0xb5, 0xeb, 0xbf, 0x84, 0xc6, - 0xd0, 0x9a, 0x4c, 0x79, 0x03, 0xa0, 0x86, 0x09, 0x28, 0xe1, 0x9c, 0x90, 0x53, 0x8f, 0x7e, 0xe3, - 0xa2, 0xdb, 0x77, 0xc2, 0xb1, 0xe3, 0xab, 0x35, 0xaa, 0x92, 0xc8, 0x7e, 0x0f, 0x70, 0x0b, 0x30, - 0x82, 0x33, 0xb5, 0x07, 0xa8, 0xb4, 0xfe, 0xaf, 0x17, 0xa0, 0x9a, 0xa9, 0x86, 0xf8, 0x08, 0x4a, - 0x24, 0x87, 0x17, 0xb2, 0x8c, 0x30, 0x43, 0xc0, 0xbf, 0x59, 0x72, 0x43, 0x42, 0xf1, 0x0e, 0xac, - 0x46, 0xb1, 0x15, 0x2a, 0xf7, 0x08, 0x2d, 0x93, 0x63, 0x3b, 0x98, 0xf9, 0xb6, 0xc1, 0x68, 0xa1, - 0x43, 0xd1, 0xf1, 0x6d, 0x69, 0x6a, 0x5b, 0xa4, 0x42, 0xa4, 0x7e, 0x07, 0x2a, 0x49, 0xf1, 0x38, - 0x05, 0x8c, 0xc1, 0x8b, 0xa1, 0x76, 0x89, 0x0e, 0xea, 0x5a, 0xfd, 0xc7, 0x1d, 0xad, 0xa0, 0xff, - 0xed, 0x02, 0x40, 0x9a, 0x4b, 0xdc, 0xcf, 0xd5, 0xf6, 0xc6, 0x7c, 0xa9, 0xf7, 0xe9, 0x6f, 0xa6, - 0xb2, 0x37, 0xa1, 0x32, 0xf3, 0x09, 0xe8, 0xd8, 0x72, 0x27, 0x4a, 0x01, 0xa8, 0x3c, 0xaa, 0xfb, - 0x04, 0x73, 0xca, 0xe3, 0x4b, 0xcb, 0xd3, 0x7f, 0x02, 0x95, 0xa4, 0x38, 0x54, 0xce, 0x77, 0x07, - 0xbd, 0xde, 0xe0, 0x45, 0xb7, 0xff, 0x98, 0x8f, 0x25, 0xf7, 0x8d, 0x4e, 0xbb, 0xb3, 0x83, 0xc9, - 0x02, 0xce, 0xd9, 0xf6, 0x81, 0x61, 0x74, 0xfa, 0x23, 0x3a, 0x7a, 0x5c, 0xd1, 0xff, 0x4a, 0x01, - 0xea, 0x03, 0xcf, 0x6e, 0x07, 0x5e, 0xdb, 0x9a, 0xa2, 0xa0, 0x25, 0x7e, 0x06, 0x9b, 0x87, 0x33, - 0x14, 0xf6, 0xa7, 0x9e, 0x35, 0x76, 0x4e, 0x02, 0xcf, 0x76, 0xd4, 0x22, 0xcc, 0x39, 0x80, 0xc8, - 0x13, 0x1a, 0x8d, 0x88, 0xf7, 0x53, 0x5a, 0xf1, 0x19, 0xd4, 0xa6, 0x61, 0x70, 0xe8, 0xa8, 0xe3, - 0xb2, 0x95, 0x57, 0xe6, 0xad, 0x12, 0x1d, 0x9f, 0xa0, 0xe9, 0xff, 0xf1, 0x2a, 0xd4, 0x76, 0x1c, - 0x7b, 0x36, 0x7d, 0x1a, 0xb8, 0x7e, 0x3b, 0x3e, 0x17, 0x9f, 0x42, 0x2d, 0xf0, 0xc8, 0xa0, 0x65, - 0x66, 0x5c, 0x7f, 0x97, 0x95, 0x03, 0x01, 0xb5, 0x80, 0x1c, 0x85, 0x3f, 0x84, 0xcb, 0xd2, 0x5e, - 0xc2, 0xd6, 0xd5, 0x73, 0xce, 0x8c, 0x6b, 0x66, 0xd5, 0xd0, 0x18, 0xc5, 0x1b, 0x34, 0x91, 0xff, - 0x16, 0x6c, 0x65, 0xc8, 0x91, 0xb1, 0x30, 0x7d, 0x71, 0x61, 0x8d, 0x6d, 0x26, 0x79, 0x13, 0xa7, - 0xe4, 0xa7, 0xb0, 0xa5, 0x6a, 0x38, 0xe6, 0xde, 0xe3, 0xcc, 0xa5, 0xac, 0x56, 0x95, 0xeb, 0x5d, - 0x59, 0xe1, 0xcd, 0x20, 0x0b, 0xa4, 0xb2, 0x3e, 0x81, 0x2b, 0x36, 0xb6, 0xde, 0xe4, 0xce, 0x3f, - 0x75, 0x9c, 0xa9, 0xe9, 0x65, 0x3c, 0xf6, 0x08, 0xb9, 0x8d, 0xb8, 0x67, 0x8e, 0x33, 0xed, 0x59, - 0x51, 0x2c, 0x1e, 0xc1, 0xa6, 0x75, 0x74, 0xc4, 0xfe, 0x45, 0xb8, 0x8d, 0x2d, 0xb5, 0xe2, 0x1a, - 0xce, 0x91, 0xb1, 0xa1, 0xc8, 0x70, 0x39, 0xb6, 0x03, 0x4f, 0x3c, 0x86, 0xeb, 0xd3, 0x93, 0x8b, - 0x88, 0x24, 0xe9, 0xf1, 0x09, 0xee, 0xb6, 0x99, 0x12, 0xd6, 0x97, 0x94, 0x70, 0x55, 0x91, 0xb7, - 0x99, 0x5a, 0x15, 0xf4, 0x08, 0xae, 0xab, 0xee, 0x43, 0x05, 0x2f, 0xdf, 0xe7, 0x65, 0xea, 0xf3, - 0x2b, 0xb2, 0xdf, 0x10, 0x9f, 0xe9, 0xf8, 0xbb, 0xa0, 0xb1, 0x0b, 0xea, 0x11, 0x39, 0xca, 0xe3, - 0xd7, 0xe5, 0x15, 0xa5, 0x06, 0xc1, 0x77, 0x69, 0xf1, 0x21, 0xfb, 0xb8, 0x0b, 0x9a, 0x33, 0x71, - 0x63, 0xd3, 0x22, 0x11, 0x93, 0x29, 0xf9, 0xec, 0xad, 0x81, 0x70, 0x69, 0xb7, 0x43, 0xca, 0xcf, - 0x41, 0x93, 0x44, 0x47, 0xa4, 0x04, 0x60, 0x6b, 0xaa, 0x4b, 0x5a, 0xd3, 0x60, 0xaa, 0x5d, 0x24, - 0xc2, 0x56, 0xec, 0x81, 0x50, 0x46, 0x48, 0x32, 0xad, 0xb0, 0x26, 0xcb, 0x3a, 0xb4, 0x74, 0xb9, - 0x1c, 0xec, 0x3c, 0x3b, 0x48, 0xf5, 0x63, 0x6a, 0x8c, 0x5a, 0x00, 0x47, 0x79, 0x70, 0xa4, 0xff, - 0x87, 0x6b, 0x50, 0x61, 0xbb, 0x1b, 0x4e, 0xe3, 0xbb, 0xb0, 0x1e, 0x1c, 0x7e, 0x83, 0x12, 0xea, - 0xab, 0x7c, 0x46, 0xd7, 0x82, 0xc3, 0x6f, 0x0c, 0xe7, 0x48, 0xbc, 0xaf, 0x44, 0x10, 0xdb, 0x39, - 0x92, 0xab, 0xa6, 0x91, 0xd7, 0x32, 0xa5, 0x48, 0xb2, 0xe3, 0x1c, 0xa1, 0x74, 0xe9, 0xfa, 0x91, - 0x13, 0xc6, 0x6c, 0x37, 0x5d, 0x7f, 0xf5, 0xe2, 0x60, 0x32, 0x32, 0xa5, 0x3e, 0x84, 0xaa, 0xb4, - 0x4d, 0x52, 0xa6, 0xf2, 0xab, 0x33, 0x31, 0x19, 0x65, 0xfa, 0x12, 0x1a, 0xe9, 0xf6, 0x43, 0xf9, - 0x2a, 0xaf, 0xcc, 0x57, 0x4f, 0x28, 0x29, 0xeb, 0x03, 0xb8, 0x1a, 0x9d, 0xba, 0x53, 0x53, 0xd6, - 0x34, 0xf0, 0xe9, 0x10, 0xd7, 0x9c, 0x9e, 0xca, 0x01, 0x14, 0x88, 0xed, 0x12, 0x72, 0xe0, 0xf7, - 0x67, 0x9e, 0xb7, 0x7f, 0x2a, 0xde, 0x83, 0x4d, 0x49, 0x3e, 0x4d, 0xe6, 0x13, 0x8d, 0xe2, 0xaa, - 0xd1, 0x60, 0xc4, 0xbe, 0x9c, 0x47, 0xe2, 0x0b, 0x68, 0xf2, 0x1c, 0x92, 0x8d, 0xe2, 0x69, 0xce, - 0x33, 0x84, 0x4f, 0x5a, 0xaf, 0x10, 0x9e, 0x6d, 0xaa, 0x2d, 0xc2, 0xd2, 0x44, 0xf9, 0x18, 0xb6, - 0xdc, 0x63, 0x3f, 0x08, 0x55, 0x16, 0x39, 0xfd, 0xe5, 0x11, 0xac, 0x60, 0x5c, 0x2b, 0xb3, 0x68, - 0xb0, 0x25, 0x72, 0x79, 0x5e, 0x98, 0x31, 0xb9, 0x8a, 0x61, 0x0e, 0x54, 0x43, 0x1b, 0xd9, 0xf5, - 0x79, 0xc1, 0x6e, 0x64, 0x46, 0x70, 0xd6, 0xb5, 0x71, 0x49, 0x4b, 0x52, 0xb5, 0x46, 0xe2, 0x73, - 0x6a, 0xcd, 0x06, 0xb5, 0x46, 0x30, 0x32, 0x99, 0x29, 0xd8, 0xa2, 0x9f, 0x83, 0x58, 0x58, 0xd2, - 0x51, 0x53, 0x7b, 0x65, 0x7f, 0x6b, 0x73, 0x2b, 0x9b, 0xd6, 0xc0, 0xc2, 0x8a, 0xde, 0x5c, 0xb6, - 0x06, 0xc6, 0xf9, 0x95, 0xdc, 0x81, 0x66, 0xfe, 0xcb, 0x67, 0x8e, 0x7b, 0x7c, 0x42, 0xb3, 0x4b, - 0xde, 0x90, 0xca, 0xe7, 0xbf, 0x92, 0xfd, 0xf2, 0x0b, 0xa2, 0xfd, 0x5e, 0xce, 0x72, 0xf9, 0x87, - 0x73, 0x16, 0xfd, 0xdf, 0x28, 0x40, 0x85, 0x67, 0x06, 0x2e, 0xa2, 0x37, 0xa0, 0xf8, 0x1d, 0x0b, - 0x08, 0x71, 0xe2, 0x1e, 0x6c, 0x5a, 0xb6, 0x3d, 0x37, 0xa0, 0xbc, 0x93, 0x6e, 0x58, 0xb6, 0x9d, - 0x1b, 0xcd, 0xbb, 0xa0, 0xb9, 0x91, 0xa9, 0x2c, 0x51, 0xa9, 0x5f, 0x79, 0xd9, 0x68, 0xb8, 0x91, - 0x34, 0x44, 0xf1, 0xa9, 0x65, 0x6e, 0x4d, 0x96, 0xbe, 0x7b, 0x4d, 0xea, 0x02, 0xc0, 0x70, 0x68, - 0xdb, 0x6c, 0xc7, 0xe7, 0x4f, 0x4b, 0xe5, 0x82, 0x06, 0xfa, 0x7f, 0x56, 0x85, 0x6a, 0xcb, 0xb7, - 0xbc, 0x8b, 0x5f, 0x39, 0xe4, 0x14, 0x4f, 0x27, 0x45, 0xd3, 0x99, 0x9c, 0xa5, 0xec, 0xc7, 0x51, - 0x21, 0x08, 0xd5, 0xec, 0x36, 0x48, 0x97, 0xa7, 0xb4, 0xfe, 0x45, 0x03, 0x18, 0x44, 0x04, 0x49, - 0xfe, 0xe4, 0x7c, 0x54, 0xe5, 0x27, 0x85, 0x36, 0xcd, 0x9f, 0x28, 0x39, 0x49, 0x7e, 0x22, 0x78, - 0x13, 0xea, 0xb1, 0x3b, 0xa1, 0x6b, 0x97, 0xd1, 0x6c, 0xe2, 0xd8, 0x7c, 0xe1, 0x90, 0xef, 0xb0, - 0xb5, 0x25, 0x0c, 0x4b, 0x99, 0x38, 0x93, 0x20, 0xbc, 0xe0, 0x52, 0xd6, 0xb8, 0x14, 0x06, 0x51, - 0x29, 0x1f, 0x80, 0x38, 0xb3, 0xdc, 0xd8, 0xcc, 0x17, 0xc5, 0x8a, 0xa5, 0x86, 0x98, 0x51, 0xb6, - 0xb8, 0xab, 0xb0, 0x66, 0xbb, 0xd1, 0x69, 0x77, 0x20, 0x95, 0x4a, 0x99, 0xc2, 0xb6, 0x44, 0x63, - 0x0b, 0x65, 0xda, 0xd8, 0x61, 0xee, 0x5f, 0x34, 0x2a, 0x08, 0xd9, 0x46, 0x00, 0xca, 0x44, 0xbe, - 0x13, 0x9f, 0x05, 0x21, 0xe6, 0x64, 0x9d, 0x31, 0x05, 0xa0, 0xec, 0x88, 0xa4, 0xf8, 0x21, 0x62, - 0x0f, 0x45, 0x23, 0x49, 0xa3, 0x36, 0xc6, 0xac, 0x82, 0xb0, 0x35, 0xae, 0x7e, 0x0a, 0x11, 0x6f, - 0x41, 0x83, 0xaa, 0x4f, 0x3a, 0x25, 0xb6, 0x81, 0x56, 0x7e, 0xd1, 0xa8, 0x21, 0x94, 0x2c, 0x6b, - 0x48, 0xf5, 0x25, 0x5c, 0xcf, 0xb5, 0xcf, 0xb4, 0xc2, 0xd0, 0xba, 0x30, 0x27, 0xd6, 0x37, 0x41, - 0x48, 0x56, 0xd0, 0xa2, 0x71, 0x35, 0xdb, 0x6d, 0x2d, 0x44, 0xef, 0x21, 0xf6, 0x95, 0x59, 0x5d, - 0x3f, 0x08, 0xc9, 0x44, 0xba, 0x34, 0x2b, 0x62, 0xc9, 0x9e, 0x47, 0x03, 0x4c, 0x0a, 0x6e, 0xc4, - 0x77, 0x1f, 0x0d, 0xf6, 0xb0, 0xdb, 0x26, 0x10, 0xaa, 0x78, 0xd1, 0x43, 0xde, 0x63, 0x37, 0xe5, - 0x8d, 0x9c, 0x87, 0xb4, 0xa9, 0x32, 0xe2, 0xc4, 0xb1, 0x6c, 0x5a, 0xb3, 0x84, 0x78, 0xe2, 0x58, - 0x74, 0x6f, 0x2b, 0x7a, 0x68, 0x4e, 0x67, 0x31, 0x5f, 0x5a, 0x34, 0x56, 0xa3, 0x87, 0xfb, 0xb3, - 0x58, 0x82, 0x8f, 0x9d, 0x98, 0xfc, 0x37, 0x08, 0xfc, 0x98, 0xef, 0x0d, 0x47, 0x0f, 0xd5, 0x89, - 0xdb, 0x15, 0xd9, 0xb7, 0x0f, 0xe5, 0x91, 0x9a, 0x0e, 0xf5, 0x04, 0x69, 0x4e, 0x66, 0x7c, 0x4b, - 0xb1, 0x68, 0x54, 0x15, 0xc1, 0xde, 0xcc, 0xc3, 0x81, 0x25, 0x5b, 0x98, 0x19, 0x62, 0x55, 0xae, - 0xf1, 0xd0, 0x11, 0xc4, 0xc0, 0xda, 0xbc, 0x06, 0x9c, 0x30, 0x4f, 0x5c, 0x76, 0x63, 0x2d, 0x1a, - 0x65, 0x02, 0x3c, 0x71, 0x63, 0x5c, 0xc7, 0x8c, 0x94, 0x33, 0x90, 0x8a, 0xb8, 0x4e, 0x44, 0x1b, - 0x84, 0xd8, 0x23, 0x38, 0x15, 0x84, 0x42, 0x44, 0x96, 0x16, 0xcb, 0xbb, 0x41, 0xa4, 0x8d, 0x0c, - 0x29, 0x96, 0xfa, 0x0e, 0x70, 0x66, 0x13, 0xa7, 0x1e, 0x97, 0xf9, 0x1a, 0x1b, 0x38, 0x08, 0xbc, - 0xe3, 0x46, 0xa7, 0x54, 0xe2, 0x5b, 0xd0, 0xc8, 0xd0, 0x61, 0x79, 0x37, 0x79, 0x66, 0x24, 0x64, - 0xb9, 0x3a, 0x86, 0xce, 0x24, 0x88, 0x65, 0x33, 0x5f, 0xcf, 0xd4, 0xd1, 0x20, 0x78, 0xbe, 0x8e, - 0x92, 0x16, 0xcb, 0xbc, 0x95, 0xa9, 0x23, 0x93, 0x62, 0xa9, 0x6f, 0x40, 0xed, 0x2c, 0x74, 0xe3, - 0xd8, 0x91, 0x42, 0xce, 0x6d, 0xee, 0x58, 0x09, 0xa3, 0xd5, 0xff, 0x06, 0xd4, 0xb8, 0xe7, 0x25, - 0x7f, 0xbb, 0xc3, 0x24, 0x12, 0xa6, 0x18, 0x84, 0xec, 0x8d, 0x89, 0xeb, 0x93, 0x3d, 0xb6, 0x68, - 0x54, 0x18, 0xb2, 0xe7, 0xfa, 0x59, 0xb4, 0x75, 0x4e, 0x56, 0xd9, 0x14, 0x6d, 0x9d, 0xd3, 0x92, - 0x9c, 0xba, 0x9e, 0xc7, 0x0b, 0xff, 0x4d, 0xb9, 0x24, 0x11, 0x42, 0xeb, 0x3e, 0x41, 0xd3, 0xd7, - 0xdf, 0xca, 0xa0, 0xe9, 0xdb, 0x38, 0x71, 0x08, 0x8d, 0x9f, 0x7e, 0x5b, 0x4e, 0x1c, 0x04, 0xe0, - 0x97, 0x53, 0xa4, 0x75, 0x4e, 0x36, 0xd7, 0x04, 0x69, 0x9d, 0x4b, 0xbe, 0x45, 0x3b, 0x05, 0xe6, - 0x7d, 0x37, 0xe1, 0x5b, 0x08, 0xc2, 0xdc, 0x59, 0x02, 0xeb, 0x9c, 0x8c, 0xac, 0x19, 0x02, 0xeb, - 0x9c, 0x8c, 0x0b, 0x8e, 0x65, 0x73, 0xc5, 0xdf, 0xe3, 0xe2, 0x11, 0x40, 0xf5, 0xbe, 0x03, 0xb5, - 0xe8, 0xa1, 0x99, 0xe2, 0xef, 0x71, 0xf6, 0xe8, 0xa1, 0xa1, 0x28, 0xde, 0x82, 0x46, 0x32, 0x35, - 0x98, 0xe6, 0x7d, 0x1e, 0x78, 0x5b, 0x4e, 0x0d, 0xba, 0x96, 0xf7, 0xeb, 0x02, 0xdc, 0xe0, 0x33, - 0x4e, 0x62, 0xff, 0x7b, 0x4e, 0x14, 0x59, 0xc7, 0xce, 0x6e, 0x10, 0xee, 0xce, 0x7e, 0xf5, 0xab, - 0x0b, 0x71, 0x17, 0x36, 0xf6, 0xad, 0xd0, 0xf1, 0xe3, 0xc4, 0x33, 0x41, 0x5a, 0x42, 0xe7, 0xc1, - 0xe2, 0x11, 0x68, 0x0c, 0xe2, 0xdb, 0x48, 0x6d, 0x75, 0x70, 0x3e, 0x7f, 0x12, 0xb5, 0x40, 0xa5, - 0xff, 0x83, 0x02, 0x54, 0x76, 0xdc, 0x28, 0x36, 0x70, 0xbb, 0x14, 0x5f, 0x82, 0xe6, 0x05, 0x67, - 0xa8, 0xec, 0x93, 0x18, 0x9d, 0xd1, 0x39, 0xe5, 0x2e, 0x99, 0x2a, 0x9a, 0x0d, 0x22, 0x4c, 0x35, - 0xc5, 0x2f, 0x41, 0x9b, 0x4d, 0xa7, 0xf9, 0xac, 0x2b, 0xaf, 0xc8, 0x4a, 0x84, 0x69, 0xd6, 0xf7, - 0xa1, 0x9a, 0xf9, 0xea, 0x12, 0xbd, 0x14, 0xd2, 0x6f, 0x21, 0x71, 0xe6, 0x3b, 0x4b, 0x6e, 0x43, - 0x42, 0x5a, 0xba, 0xfe, 0x6f, 0xae, 0x80, 0x46, 0xd6, 0x68, 0x83, 0xbc, 0xd7, 0xc8, 0xc1, 0x21, - 0x67, 0xd1, 0x28, 0x7c, 0xaf, 0x45, 0xe3, 0x0e, 0xac, 0x7a, 0xee, 0x24, 0xb9, 0x16, 0x91, 0x3b, - 0x01, 0x26, 0x04, 0x8e, 0x75, 0x10, 0xba, 0xc7, 0x64, 0x7b, 0xc9, 0x5e, 0x90, 0xa3, 0x93, 0x82, - 0xdd, 0x99, 0x3f, 0xa6, 0x21, 0xba, 0x0f, 0x60, 0xbb, 0x51, 0x6c, 0x92, 0x35, 0x52, 0x56, 0x5b, - 0xf6, 0x4c, 0xd2, 0xff, 0x46, 0xc5, 0x4e, 0x86, 0xe2, 0x2e, 0x68, 0x19, 0x39, 0xd9, 0x4f, 0x0c, - 0x89, 0xab, 0x46, 0x2a, 0x3f, 0xb7, 0xfd, 0xb6, 0x1f, 0x2f, 0x50, 0xa2, 0x4c, 0xb8, 0xb6, 0x40, - 0x89, 0xf2, 0xe0, 0x5d, 0xd0, 0x82, 0x97, 0x4e, 0x68, 0x1e, 0x39, 0xf1, 0xf8, 0xc4, 0xe4, 0x66, - 0xad, 0xf3, 0xc9, 0x0d, 0xc2, 0x77, 0x11, 0xdc, 0x43, 0xa8, 0x7e, 0x0e, 0x97, 0xa9, 0xdf, 0x9e, - 0xd0, 0xe9, 0x26, 0x4d, 0x34, 0x79, 0x9b, 0x39, 0x0c, 0xbc, 0xc4, 0x20, 0x8f, 0xbf, 0xc5, 0xbb, - 0x80, 0x1a, 0x87, 0x33, 0x56, 0x3d, 0xb4, 0x54, 0x21, 0x71, 0xc6, 0xd8, 0x4f, 0xab, 0xa9, 0x6c, - 0xb4, 0x28, 0xf8, 0x30, 0x52, 0xff, 0x3f, 0xd7, 0x60, 0x83, 0x2f, 0xf4, 0x39, 0x56, 0x38, 0x3e, - 0xa1, 0x6b, 0x7d, 0x0f, 0xa0, 0x26, 0xad, 0xf5, 0xa9, 0x53, 0xd8, 0x92, 0x0f, 0x55, 0x99, 0x88, - 0x45, 0xad, 0x47, 0xa0, 0x65, 0xf3, 0x7c, 0x87, 0x16, 0xd4, 0xc8, 0x64, 0x43, 0x5d, 0xe8, 0x2d, - 0x58, 0xe5, 0xa3, 0xb9, 0x5c, 0x3d, 0x93, 0x63, 0x4f, 0x46, 0x8a, 0xdf, 0x81, 0x3a, 0x1f, 0xfd, - 0x9a, 0xf2, 0xfe, 0x62, 0x29, 0xab, 0xe0, 0x2d, 0xe9, 0x3c, 0xa3, 0x76, 0x92, 0xa6, 0x23, 0xf1, - 0x11, 0xd4, 0xc9, 0x45, 0xdf, 0x9c, 0x5a, 0x17, 0x5e, 0x60, 0xd9, 0x79, 0xa7, 0x55, 0x9a, 0x5f, - 0x35, 0x22, 0xd8, 0x67, 0xbc, 0x78, 0x1f, 0x36, 0x71, 0x76, 0x58, 0xfe, 0xd8, 0xa1, 0xa9, 0x46, - 0x96, 0x4a, 0x3e, 0x28, 0xd6, 0x14, 0x22, 0x39, 0x39, 0xf9, 0x2d, 0xa8, 0xd8, 0x6e, 0xe8, 0x30, - 0xd1, 0xfa, 0x0f, 0xb1, 0x5a, 0xa6, 0xf4, 0xe2, 0x21, 0xee, 0x6e, 0xbe, 0xed, 0x92, 0x96, 0xc1, - 0xb3, 0xa4, 0xbc, 0x50, 0xb9, 0x46, 0x42, 0x42, 0x33, 0x46, 0x7c, 0x4e, 0x1c, 0x8f, 0xab, 0xc7, - 0x73, 0xbc, 0xb2, 0x7c, 0x8e, 0xd7, 0x15, 0x19, 0xcf, 0xf3, 0xf7, 0xa1, 0x3a, 0x0d, 0x1d, 0xf3, - 0xc8, 0xf5, 0x62, 0x27, 0x44, 0x55, 0x7c, 0xde, 0x52, 0x02, 0xd3, 0xd0, 0xd9, 0x65, 0xec, 0x52, - 0xd7, 0xa4, 0xea, 0x72, 0xd7, 0xa4, 0x87, 0x50, 0x27, 0x69, 0x30, 0xb9, 0x50, 0xab, 0x2d, 0xbd, - 0x50, 0x5b, 0x43, 0x22, 0x95, 0x12, 0x0f, 0xe1, 0xea, 0x34, 0x88, 0x62, 0x59, 0x1b, 0x33, 0x5d, - 0x2c, 0x24, 0x19, 0x95, 0x8d, 0xcb, 0x88, 0xe5, 0xca, 0x0c, 0xd4, 0x82, 0x11, 0x9f, 0x03, 0x49, - 0x99, 0x26, 0x4a, 0x92, 0x52, 0xb9, 0xc9, 0xce, 0x82, 0x74, 0x1e, 0xbf, 0x08, 0xc2, 0x53, 0x16, - 0x2b, 0xf1, 0x17, 0x5d, 0x9c, 0xf5, 0x8e, 0x03, 0x93, 0x9d, 0xbe, 0x22, 0x92, 0xa5, 0x6a, 0x46, - 0x15, 0x61, 0xec, 0x0f, 0x86, 0xed, 0x05, 0x22, 0x71, 0xce, 0xa7, 0x61, 0xd4, 0xdc, 0x5a, 0xe8, - 0x9b, 0x0a, 0x62, 0xf1, 0x57, 0x44, 0x27, 0x91, 0x8a, 0xd4, 0x64, 0x07, 0xbd, 0x2b, 0xd4, 0x33, - 0x75, 0x45, 0x83, 0x6c, 0x28, 0x7a, 0x5a, 0x2a, 0xd7, 0xb4, 0xfa, 0xd3, 0x52, 0xb9, 0xae, 0x35, - 0xd8, 0x3f, 0xeb, 0x69, 0xa9, 0xbc, 0xa1, 0x69, 0xfa, 0xdf, 0xfa, 0x10, 0x4a, 0x74, 0xc7, 0xe1, - 0x63, 0xa8, 0xd0, 0x85, 0xc3, 0x0c, 0xf3, 0x97, 0xb6, 0x27, 0x44, 0xd3, 0x1f, 0xe2, 0xe2, 0x65, - 0x5f, 0xfe, 0x7a, 0xf5, 0x1d, 0xf6, 0x37, 0xc8, 0x66, 0x4a, 0xfe, 0x79, 0xd8, 0x2b, 0x55, 0x15, - 0xc8, 0xc1, 0x8a, 0x23, 0x83, 0x31, 0x28, 0x77, 0x93, 0x33, 0x40, 0xe8, 0xf8, 0xb4, 0x82, 0x56, - 0x8d, 0x24, 0x4d, 0x96, 0x6a, 0xbe, 0xd4, 0xc6, 0xd2, 0xe9, 0xea, 0x12, 0x4b, 0x35, 0xe3, 0x49, - 0x5c, 0xfd, 0x18, 0x2a, 0xdf, 0x04, 0xae, 0xcf, 0x15, 0x5f, 0x5b, 0xa8, 0xf8, 0xd3, 0xc0, 0xf5, - 0xb9, 0xe2, 0xdf, 0xc8, 0x5f, 0xe2, 0x4d, 0x58, 0x0f, 0x7c, 0x2e, 0x7b, 0x7d, 0xf1, 0x36, 0x4c, - 0xe0, 0xf7, 0xf8, 0x52, 0x56, 0xdd, 0x8d, 0xcc, 0x90, 0xd4, 0x57, 0xcc, 0x29, 0xfd, 0xfa, 0xaa, - 0x6e, 0x64, 0x20, 0x0c, 0x8b, 0xc5, 0x49, 0x2c, 0xa7, 0x0c, 0x15, 0x56, 0x59, 0x9c, 0xc4, 0x8c, - 0xa6, 0x02, 0xdf, 0x86, 0xf2, 0x71, 0x18, 0x90, 0xf2, 0xbf, 0x64, 0xba, 0xaf, 0x13, 0x6e, 0xfb, - 0x02, 0x55, 0x2b, 0xfa, 0xe9, 0xfa, 0xc7, 0x26, 0x1d, 0x3e, 0xe0, 0x44, 0x2f, 0x1b, 0x35, 0x05, - 0xa4, 0x63, 0x85, 0xb7, 0xa1, 0x6c, 0x1d, 0x1f, 0x9b, 0xf2, 0x6e, 0xd9, 0x42, 0x59, 0xd6, 0xf1, - 0x31, 0x7d, 0xf2, 0x3e, 0xd4, 0xcf, 0x5c, 0xdf, 0x8c, 0xa6, 0xce, 0x98, 0x69, 0xeb, 0x8b, 0x5d, - 0x79, 0xe6, 0xd2, 0x7d, 0x10, 0xa2, 0xcf, 0x6e, 0x91, 0x8d, 0x1f, 0xbe, 0x45, 0x6e, 0xbc, 0x6a, - 0x8b, 0xd4, 0x61, 0x4d, 0x3a, 0x0a, 0x68, 0x0b, 0x24, 0x12, 0x23, 0x3e, 0x81, 0x6a, 0x68, 0xf9, - 0xa7, 0x72, 0x39, 0x34, 0xbf, 0xce, 0x1a, 0xd0, 0x0d, 0xcb, 0x3f, 0x95, 0x3e, 0x92, 0x10, 0x26, - 0xbf, 0xf3, 0xea, 0xf4, 0xe6, 0xf7, 0x98, 0xb8, 0x32, 0x96, 0x33, 0xf1, 0xdd, 0x96, 0xb3, 0xcf, - 0xc8, 0x44, 0xe5, 0xf8, 0xb1, 0xa9, 0x32, 0x5c, 0x5e, 0x9e, 0xa1, 0xc6, 0x64, 0x03, 0xce, 0x86, - 0x0d, 0xa0, 0x03, 0x2c, 0x93, 0x4e, 0xbb, 0xb6, 0x72, 0x0d, 0x48, 0x4e, 0xb6, 0x0c, 0x08, 0xd3, - 0x53, 0xae, 0x16, 0x6c, 0xa4, 0x17, 0xda, 0x39, 0x8a, 0xc0, 0x95, 0xec, 0xb9, 0x7b, 0xee, 0x06, - 0xbc, 0x32, 0x8a, 0xb9, 0xb9, 0x6b, 0xf1, 0x6f, 0x42, 0x9d, 0xfd, 0xa5, 0x15, 0x1b, 0x61, 0x47, - 0xf7, 0x1a, 0x01, 0x15, 0x1f, 0x41, 0xe1, 0x43, 0x5a, 0xea, 0xe2, 0x73, 0xd2, 0xa0, 0x52, 0xc6, - 0xcc, 0xa6, 0xb9, 0xf8, 0xdc, 0xa8, 0xd8, 0xea, 0x27, 0xb2, 0xa6, 0x43, 0xd7, 0xb7, 0x71, 0xea, - 0xc5, 0xd6, 0x71, 0xd4, 0x6c, 0xd2, 0xca, 0xac, 0x4a, 0xd8, 0xc8, 0x3a, 0x8e, 0xc4, 0xa7, 0x50, - 0xb3, 0xd8, 0x10, 0xc1, 0xf5, 0xbe, 0x9e, 0x3d, 0xf0, 0xc9, 0x98, 0x28, 0x8c, 0xaa, 0x95, 0xb1, - 0x57, 0x7c, 0x01, 0x42, 0xf9, 0x31, 0x65, 0xcc, 0xe3, 0x37, 0x16, 0x66, 0xe3, 0x86, 0x74, 0x64, - 0x4a, 0x8c, 0xe3, 0xb7, 0x41, 0xee, 0xee, 0x7c, 0x0d, 0xe9, 0x35, 0xaa, 0x10, 0x30, 0x88, 0xae, - 0x20, 0x7d, 0x01, 0xf5, 0xbc, 0x05, 0xe6, 0xe6, 0x12, 0x77, 0x20, 0xde, 0x8b, 0x6b, 0xe3, 0xac, - 0x4d, 0xe6, 0x4d, 0x0e, 0xcc, 0x40, 0xda, 0x13, 0x65, 0x64, 0x97, 0x97, 0x9a, 0x1f, 0xc4, 0x6d, - 0x05, 0xc3, 0x0e, 0x54, 0xf6, 0xd1, 0xf8, 0x9c, 0x14, 0xae, 0xa4, 0x03, 0x13, 0xb3, 0x92, 0x51, - 0x71, 0x13, 0x0b, 0xd3, 0x0e, 0x08, 0xe5, 0x4a, 0x80, 0x82, 0x27, 0x7b, 0xdc, 0x92, 0x7e, 0x95, - 0x78, 0x08, 0xcd, 0xcb, 0xa5, 0x06, 0x7b, 0x27, 0x67, 0x25, 0xd5, 0x47, 0xd0, 0xc0, 0xbd, 0x31, - 0xf3, 0x65, 0x3d, 0xdb, 0xa8, 0xfd, 0xd0, 0x49, 0x3f, 0x5e, 0x9b, 0x66, 0x52, 0xe2, 0x67, 0xb0, - 0x99, 0xc9, 0x39, 0x3b, 0xa5, 0xcc, 0x6f, 0x52, 0xe6, 0xad, 0xb9, 0xcc, 0x07, 0xa7, 0x98, 0xbd, - 0x31, 0xcd, 0xa5, 0xc5, 0x16, 0xac, 0x76, 0xa3, 0x8e, 0x6f, 0x93, 0xde, 0x55, 0x36, 0x38, 0x21, - 0x1e, 0x42, 0x8d, 0x8d, 0x1c, 0x64, 0x6b, 0x8c, 0x9a, 0xef, 0x64, 0x4f, 0x74, 0xc9, 0xd2, 0xc1, - 0x06, 0xcb, 0xaa, 0x97, 0xfc, 0x8e, 0xc4, 0xe7, 0xb0, 0xc9, 0xc7, 0xed, 0x59, 0x16, 0xf9, 0xee, - 0xe2, 0x90, 0x13, 0xd1, 0x6e, 0xca, 0x27, 0x0d, 0xb8, 0x1e, 0xce, 0x7c, 0x32, 0x7c, 0xc8, 0x9c, - 0x7c, 0x10, 0x44, 0xf9, 0xef, 0x52, 0x7e, 0x19, 0x1a, 0xc8, 0x60, 0x32, 0xce, 0x4b, 0xbc, 0xe9, - 0x6a, 0x98, 0x05, 0xed, 0x63, 0xbe, 0x57, 0x94, 0xc9, 0x07, 0x24, 0x54, 0xe6, 0x7b, 0x3f, 0xa6, - 0x4c, 0x3a, 0x3c, 0xa1, 0x32, 0x05, 0x94, 0x66, 0x33, 0xd7, 0x26, 0x2d, 0xb0, 0x66, 0xd0, 0x6f, - 0xf1, 0x36, 0x34, 0x42, 0x67, 0x3c, 0x0b, 0x23, 0xf7, 0xa5, 0x63, 0x46, 0xae, 0x7f, 0x4a, 0xfa, - 0x5f, 0xd9, 0xa8, 0x27, 0xd0, 0xa1, 0xeb, 0x9f, 0x22, 0xcb, 0x70, 0xce, 0x63, 0x27, 0xf4, 0x39, - 0xa2, 0xc5, 0x07, 0x59, 0x96, 0xd1, 0x21, 0x04, 0xae, 0x73, 0x03, 0x9c, 0xe4, 0xf7, 0xdc, 0xc8, - 0x46, 0x3c, 0xb2, 0xf7, 0x7f, 0xd0, 0xc8, 0x0e, 0x69, 0x64, 0xdf, 0x81, 0xb2, 0xeb, 0xc7, 0x4e, - 0xf8, 0xd2, 0xf2, 0x9a, 0x1f, 0x2d, 0x70, 0xe3, 0x04, 0x27, 0xde, 0x82, 0xf5, 0xc8, 0x73, 0x71, - 0xbd, 0x37, 0x3f, 0x5e, 0x20, 0x53, 0x28, 0x71, 0x17, 0x2a, 0x49, 0xbc, 0xaa, 0xe6, 0x27, 0x0b, - 0x74, 0x29, 0x52, 0xdc, 0x82, 0xd2, 0x19, 0x4e, 0xa8, 0x07, 0x8b, 0x27, 0xf0, 0x08, 0xc7, 0xed, - 0xfb, 0x08, 0xf5, 0x79, 0xda, 0xbe, 0x1f, 0x2e, 0x6c, 0xdf, 0xbb, 0xae, 0xe7, 0xf1, 0xf6, 0x7d, - 0x24, 0x7f, 0xe1, 0xe6, 0x47, 0x39, 0xb0, 0x25, 0x9f, 0x2e, 0x6e, 0x7e, 0x88, 0x7b, 0x4e, 0x91, - 0xbd, 0xaa, 0x11, 0x1d, 0x2b, 0xf3, 0xe9, 0xf8, 0x67, 0xd9, 0xbe, 0xca, 0x9f, 0x37, 0x1b, 0x10, - 0x25, 0x69, 0xf1, 0x3a, 0xc8, 0x53, 0x73, 0x52, 0xa8, 0x3e, 0xe7, 0xab, 0xa0, 0x0c, 0x41, 0x5d, - 0xea, 0x63, 0xa8, 0x2b, 0x7f, 0x68, 0x12, 0xc0, 0x9a, 0x5f, 0x2c, 0xd4, 0x20, 0x4f, 0x20, 0x76, - 0xa0, 0x76, 0x84, 0x7a, 0xfd, 0x84, 0xd5, 0xfc, 0xe6, 0x23, 0xaa, 0xc8, 0x1d, 0xb5, 0xb1, 0xbe, - 0xca, 0x0c, 0x60, 0xe4, 0x72, 0x89, 0xfb, 0x20, 0xdc, 0x23, 0x1e, 0xcf, 0xdd, 0x30, 0x98, 0xb0, - 0x2a, 0xdf, 0xfc, 0x52, 0x1e, 0x35, 0x2c, 0x60, 0xc8, 0xc7, 0xc6, 0xf1, 0x6d, 0x73, 0x12, 0x49, - 0x31, 0xe1, 0x27, 0x54, 0x4f, 0xc9, 0xbc, 0x92, 0xb8, 0x76, 0xea, 0x0c, 0x15, 0x69, 0xf7, 0x22, - 0x96, 0x1a, 0xbe, 0x04, 0x9c, 0xae, 0x2f, 0xd3, 0xac, 0xbf, 0xf5, 0x9d, 0x59, 0x91, 0x56, 0x65, - 0x7d, 0x04, 0x0d, 0x3e, 0xe0, 0x20, 0x89, 0x0c, 0xa7, 0xe8, 0x4f, 0xb3, 0x9c, 0x2b, 0x7b, 0x32, - 0x6b, 0xd4, 0xec, 0xec, 0x39, 0xed, 0x17, 0xb0, 0x91, 0x39, 0xdf, 0xa0, 0xcf, 0xfe, 0x76, 0xf6, - 0xb3, 0xc9, 0x01, 0x87, 0x51, 0x9f, 0xa9, 0x9f, 0xf4, 0xc9, 0x05, 0x81, 0xff, 0x77, 0x7e, 0x80, - 0xc0, 0xff, 0x26, 0xa4, 0x2b, 0xd2, 0x1c, 0xc7, 0x4e, 0xf3, 0x67, 0xcc, 0xfc, 0x13, 0x60, 0x3b, - 0x76, 0xc4, 0x43, 0x00, 0x6b, 0x3a, 0xf5, 0x2e, 0x78, 0x6a, 0xfe, 0x9c, 0xa6, 0xe6, 0x56, 0x66, - 0x6a, 0xb6, 0x10, 0x49, 0x73, 0xb3, 0x62, 0xa9, 0x9f, 0xa8, 0xb3, 0x92, 0x2a, 0x61, 0x4f, 0x3c, - 0x6a, 0x7f, 0x2b, 0xbb, 0xb6, 0xf7, 0x83, 0x28, 0xde, 0x99, 0x78, 0xd8, 0x0a, 0x98, 0x26, 0xbf, - 0x45, 0x0f, 0x2e, 0x07, 0xbe, 0x69, 0xcf, 0xa6, 0x9e, 0x3b, 0xc6, 0x1e, 0xe0, 0x83, 0xc5, 0xe6, - 0x76, 0xf6, 0x4a, 0x12, 0x7d, 0x71, 0xe0, 0xef, 0x28, 0x22, 0x79, 0x60, 0xb9, 0x19, 0xcc, 0x83, - 0xc8, 0x06, 0x45, 0x63, 0x90, 0xdc, 0xe6, 0x69, 0xb3, 0x68, 0x40, 0x50, 0x75, 0x9d, 0xe7, 0x11, - 0x6c, 0xa4, 0x54, 0x7c, 0x7d, 0x7a, 0xe7, 0x15, 0xd7, 0xa7, 0xeb, 0x2a, 0x23, 0xdf, 0xba, 0xc6, - 0xbe, 0x0b, 0x3c, 0x6f, 0x36, 0x95, 0xac, 0xb4, 0xd9, 0x91, 0x7d, 0x47, 0x40, 0xe6, 0x92, 0x19, - 0x33, 0x9d, 0x33, 0x69, 0xee, 0x66, 0xcd, 0x74, 0xce, 0x44, 0xb4, 0xa1, 0x49, 0xac, 0x58, 0xae, - 0xb3, 0x9c, 0x5b, 0x4a, 0x77, 0x61, 0x39, 0x5d, 0x41, 0x5a, 0xf6, 0x7a, 0xd9, 0xcf, 0x38, 0xa8, - 0xfc, 0x1c, 0x5e, 0x5f, 0x5e, 0x88, 0x8a, 0x7f, 0xf2, 0x94, 0x64, 0x85, 0xeb, 0x4b, 0x72, 0xcb, - 0x20, 0x28, 0x3f, 0x81, 0xfa, 0xb1, 0x45, 0xad, 0xf0, 0xcc, 0x49, 0x60, 0x3b, 0xcd, 0x67, 0xd9, - 0x0b, 0x80, 0xd4, 0xe1, 0x8f, 0x2d, 0x6c, 0x90, 0xb7, 0x17, 0xd8, 0x8e, 0x51, 0x3d, 0x4e, 0x13, - 0xe2, 0x11, 0x34, 0xd3, 0x09, 0x34, 0xf3, 0xf1, 0xbb, 0xa8, 0xdf, 0xba, 0xfe, 0x38, 0x6e, 0xf6, - 0x38, 0x04, 0x65, 0x82, 0x3f, 0x40, 0xf4, 0x8e, 0xc4, 0x8a, 0x36, 0x68, 0xb4, 0xb0, 0xe5, 0x0e, - 0x14, 0xb9, 0xb6, 0xd3, 0xdc, 0xcb, 0xc6, 0xe5, 0x61, 0xb6, 0x87, 0x24, 0xb4, 0xd7, 0x0c, 0x5d, - 0xdb, 0x31, 0x1a, 0x47, 0xb9, 0xb4, 0x78, 0x0f, 0x36, 0x95, 0x2e, 0x61, 0x9e, 0x58, 0xd1, 0x89, - 0x79, 0xea, 0x5c, 0x34, 0xfb, 0xd4, 0xe0, 0x86, 0x54, 0x24, 0x9e, 0x58, 0xd1, 0xc9, 0x33, 0xe7, - 0x42, 0xdc, 0x83, 0x4d, 0xb9, 0xe5, 0xb9, 0x91, 0x79, 0x68, 0x85, 0xa1, 0xeb, 0x84, 0xcd, 0x01, - 0x9f, 0x68, 0x31, 0xa2, 0x1b, 0x6d, 0x33, 0x58, 0x7c, 0x00, 0x22, 0x3b, 0x18, 0xd2, 0xc7, 0x6a, - 0x9f, 0x78, 0xa0, 0x96, 0xf1, 0x0e, 0x22, 0x5f, 0x2b, 0xf1, 0x31, 0x34, 0x92, 0xfe, 0x63, 0x1f, - 0x99, 0x5f, 0x2c, 0xda, 0x32, 0x64, 0xa7, 0x0d, 0xc9, 0x49, 0xe6, 0x03, 0xa8, 0x25, 0x39, 0x1c, - 0xdf, 0x6e, 0x1a, 0x8b, 0x56, 0x3c, 0x49, 0x8f, 0x3b, 0xc3, 0x67, 0x70, 0x8d, 0xa7, 0x28, 0x9f, - 0x64, 0x9c, 0x3a, 0x17, 0x49, 0x18, 0xa6, 0x21, 0xc7, 0x3e, 0x21, 0x74, 0x17, 0xb1, 0xcf, 0x9c, - 0x8b, 0x28, 0xe1, 0x7c, 0xd7, 0xe9, 0xa4, 0x7f, 0x2c, 0xaf, 0x09, 0xb3, 0x95, 0x5b, 0xb6, 0x65, - 0xc4, 0x63, 0x83, 0x04, 0xed, 0x04, 0x6f, 0x48, 0xef, 0x31, 0xd1, 0x52, 0xd7, 0xa5, 0x22, 0x52, - 0xde, 0x79, 0x77, 0x3e, 0xc8, 0x46, 0xbc, 0x98, 0x53, 0xed, 0xe5, 0x2d, 0xaa, 0x8c, 0xcd, 0xea, - 0x31, 0xdc, 0x48, 0x8e, 0x2e, 0x9d, 0x6f, 0x67, 0x16, 0x5d, 0x7f, 0x3a, 0x75, 0x2e, 0x98, 0xa5, - 0xbd, 0x58, 0x98, 0xdd, 0xd7, 0x14, 0x75, 0x47, 0x12, 0x3f, 0x73, 0x2e, 0x88, 0xaf, 0xbd, 0x05, - 0x0d, 0x2b, 0x0a, 0x8e, 0xa4, 0x06, 0x3a, 0x0e, 0xbc, 0xe6, 0x73, 0x1a, 0x87, 0x1a, 0x42, 0x0d, - 0x75, 0x52, 0xda, 0x87, 0xcb, 0xe9, 0x88, 0xa1, 0xc6, 0x1f, 0xba, 0xf1, 0xc9, 0xa4, 0xf9, 0xcb, - 0xac, 0xe9, 0x87, 0x26, 0x54, 0x32, 0xf9, 0x5b, 0x8a, 0xc8, 0x48, 0xc7, 0x3a, 0x81, 0x89, 0x47, - 0x70, 0x3d, 0x2d, 0x2f, 0x0e, 0xa6, 0xa6, 0x6f, 0x9e, 0xb9, 0xf1, 0x89, 0x49, 0xbe, 0xc1, 0xbf, - 0x2b, 0x43, 0xfc, 0x28, 0x82, 0x51, 0x30, 0xed, 0xbf, 0x70, 0xe3, 0x93, 0x91, 0xeb, 0x44, 0x62, - 0x1b, 0x6e, 0x59, 0xb6, 0x35, 0x8d, 0x71, 0x41, 0x60, 0xc6, 0x24, 0x2c, 0x51, 0xe0, 0x9b, 0xce, - 0x64, 0x1a, 0x5f, 0x34, 0xff, 0x12, 0x65, 0xbf, 0xa1, 0xa8, 0x46, 0xc1, 0x74, 0x57, 0xd2, 0x0c, - 0xfc, 0x0e, 0x52, 0x88, 0x87, 0x70, 0xf5, 0xa5, 0x33, 0x8e, 0x83, 0xd0, 0x64, 0x1b, 0x99, 0x14, - 0xfd, 0x5d, 0xbb, 0xf9, 0x7b, 0xd4, 0xf6, 0xcb, 0x8c, 0xfd, 0x05, 0x22, 0xd9, 0xe1, 0xa7, 0x6b, - 0xa3, 0x36, 0x48, 0x1e, 0xfb, 0x53, 0x2b, 0x3e, 0x69, 0xfe, 0xff, 0xb2, 0x17, 0x07, 0x9e, 0xbb, - 0xce, 0x19, 0x2a, 0x09, 0x06, 0xb9, 0xf4, 0xef, 0x5b, 0xf1, 0x89, 0x78, 0xa0, 0xd8, 0x1e, 0x0e, - 0x09, 0x9b, 0x57, 0xcc, 0xc5, 0x0d, 0x9c, 0x48, 0x9e, 0x39, 0x17, 0xb4, 0x81, 0xeb, 0x7f, 0x75, - 0x0d, 0xca, 0xca, 0xfc, 0x21, 0xaa, 0xb0, 0x7e, 0xd0, 0x7f, 0xd6, 0x1f, 0xbc, 0xe8, 0x73, 0x2c, - 0xbd, 0xd6, 0x70, 0xd8, 0x31, 0x46, 0x9a, 0x2d, 0x1a, 0x00, 0x14, 0x6d, 0xca, 0x1c, 0xb6, 0x5b, - 0x7d, 0x8e, 0xad, 0x47, 0x31, 0xae, 0x38, 0xbd, 0x22, 0x36, 0xa1, 0xbe, 0x7b, 0xd0, 0xe7, 0x8b, - 0x49, 0x04, 0x2a, 0x22, 0xa8, 0xf3, 0x15, 0x3b, 0x07, 0x32, 0xa8, 0x84, 0xa0, 0xbd, 0xd6, 0xa8, - 0x63, 0x74, 0x15, 0x68, 0x55, 0x5c, 0x81, 0xcd, 0x84, 0x4a, 0x95, 0xa0, 0xad, 0x23, 0xb8, 0xdb, - 0xdf, 0xe9, 0x7c, 0x65, 0x0e, 0x3b, 0x2d, 0xa3, 0xfd, 0x84, 0xa9, 0xcb, 0x58, 0xbf, 0x7d, 0x63, - 0xf0, 0xb4, 0xd3, 0x1e, 0x69, 0x40, 0xfe, 0x86, 0x8f, 0x1f, 0x6b, 0x55, 0x51, 0x83, 0xf2, 0x4e, - 0x77, 0x38, 0xea, 0xf6, 0xdb, 0x23, 0xad, 0x86, 0xd5, 0xde, 0xed, 0xf6, 0x46, 0x1d, 0x43, 0xab, - 0x8b, 0x32, 0x94, 0x9e, 0x0e, 0xba, 0x7d, 0xad, 0x41, 0xb1, 0xb7, 0x5a, 0x7b, 0xfb, 0xbd, 0x8e, - 0xb6, 0x81, 0xd0, 0xe1, 0xc0, 0x18, 0x69, 0x1a, 0x42, 0x39, 0xca, 0x84, 0xb6, 0x29, 0x2a, 0xb0, - 0x7a, 0xd0, 0xc7, 0xaf, 0x0b, 0x51, 0x87, 0x0a, 0xfd, 0x34, 0x5b, 0xbd, 0x9e, 0x76, 0x39, 0xe3, - 0xa4, 0xb8, 0x85, 0x28, 0x72, 0x79, 0x1c, 0x62, 0x1d, 0xae, 0x60, 0x8b, 0x92, 0x24, 0x51, 0x5f, - 0xc5, 0x72, 0xf6, 0xba, 0xfd, 0x83, 0xa1, 0x76, 0x0d, 0x89, 0xe9, 0x27, 0x61, 0x9a, 0x58, 0x4e, - 0xb7, 0x4f, 0x1d, 0x7a, 0x0b, 0x7f, 0xef, 0x74, 0x7a, 0x9d, 0x51, 0x47, 0xbb, 0x8d, 0xad, 0xea, - 0x0d, 0xda, 0xcf, 0xcc, 0xc1, 0xbe, 0xf6, 0x06, 0xf6, 0xec, 0xbe, 0xd1, 0x31, 0x25, 0xe1, 0x9b, - 0x42, 0x83, 0xda, 0xee, 0xc1, 0x2f, 0x7f, 0xf9, 0xb5, 0x29, 0x1b, 0xf5, 0x36, 0x7e, 0x33, 0xa5, - 0x30, 0x0f, 0x9e, 0x69, 0xef, 0xcc, 0x81, 0x86, 0xcf, 0xb4, 0x77, 0xb1, 0x53, 0x54, 0x5f, 0x6b, - 0x77, 0x91, 0xc0, 0xe8, 0xb4, 0x0f, 0x8c, 0x61, 0xf7, 0x79, 0xc7, 0x6c, 0x8f, 0x3a, 0xda, 0x7b, - 0xd4, 0x0b, 0xdd, 0xfe, 0x33, 0xed, 0x1e, 0x56, 0x13, 0x7f, 0x71, 0x27, 0xbf, 0x2f, 0x04, 0x34, - 0x52, 0x5a, 0x82, 0x7d, 0x80, 0x24, 0xdb, 0xc6, 0xa0, 0xb5, 0xd3, 0x6e, 0x0d, 0x47, 0xda, 0x87, - 0xd8, 0xc6, 0xe1, 0x7e, 0xaf, 0x3b, 0xd2, 0xee, 0x63, 0x43, 0x1e, 0xb7, 0x46, 0x4f, 0x3a, 0x86, - 0xf6, 0x91, 0xd8, 0x80, 0xea, 0xa8, 0xbb, 0xd7, 0x31, 0x65, 0x9f, 0x3e, 0xc0, 0x6f, 0xec, 0x76, - 0x7b, 0x3d, 0xed, 0x21, 0x39, 0xd9, 0xb5, 0x8c, 0x51, 0x97, 0xc6, 0xf7, 0x53, 0x2c, 0xa0, 0xb5, - 0xbf, 0xdf, 0xfb, 0x5a, 0xfb, 0x0c, 0x1b, 0xb8, 0x77, 0xd0, 0x1b, 0x75, 0xcd, 0x83, 0xfd, 0x9d, - 0xd6, 0xa8, 0xa3, 0x7d, 0x4e, 0xa3, 0x3c, 0x18, 0x8e, 0x76, 0xf6, 0x7a, 0xda, 0x17, 0x54, 0x26, - 0xcd, 0xb4, 0x76, 0x6f, 0xd0, 0xef, 0x68, 0x8f, 0x90, 0xbe, 0xb5, 0xd3, 0xda, 0x1f, 0x61, 0xed, - 0x46, 0x83, 0x7d, 0xed, 0x4b, 0xb1, 0x05, 0xda, 0xf3, 0x4e, 0x7b, 0x34, 0x30, 0xcc, 0x5f, 0x1c, - 0x74, 0x8c, 0xaf, 0x09, 0xfa, 0x13, 0x71, 0x0d, 0x2e, 0xe7, 0xa0, 0xc3, 0xc1, 0x81, 0xd1, 0xee, - 0x68, 0xbf, 0xa5, 0x97, 0xca, 0x6b, 0xda, 0x9a, 0x5e, 0x2a, 0xdf, 0xd1, 0xee, 0xe8, 0xa5, 0xb2, - 0xae, 0xe9, 0xf7, 0xaa, 0x8c, 0xa3, 0xc6, 0xea, 0x7f, 0xbd, 0x00, 0x65, 0x65, 0x56, 0xe3, 0xe8, - 0x25, 0xfd, 0x8e, 0xa1, 0x5d, 0xc2, 0xb6, 0xf4, 0x3a, 0xbb, 0x23, 0x0e, 0x5c, 0x62, 0x74, 0x1f, - 0x3f, 0x19, 0x69, 0x2b, 0xf8, 0x73, 0x70, 0x80, 0xc3, 0x52, 0xa4, 0xfe, 0xec, 0xec, 0x75, 0xb5, - 0x12, 0xfe, 0x6a, 0xf5, 0x47, 0x5d, 0x6d, 0x95, 0x66, 0x5d, 0xb7, 0xff, 0xb8, 0xd7, 0xd1, 0xd6, - 0x10, 0xba, 0xd7, 0x32, 0x9e, 0x69, 0xeb, 0x5c, 0xe8, 0x4e, 0xe7, 0x2b, 0xad, 0x2c, 0xd6, 0x60, - 0xa5, 0xf7, 0x40, 0xab, 0x20, 0x68, 0xa7, 0xb3, 0x73, 0xb0, 0xaf, 0x01, 0xe5, 0x1e, 0x0e, 0x76, - 0xb5, 0x2a, 0xf6, 0x19, 0xfe, 0x32, 0xe9, 0xb3, 0x35, 0xfd, 0x2e, 0xac, 0xb7, 0x8e, 0x8f, 0x69, - 0x83, 0xc6, 0x7e, 0x3d, 0xe8, 0xf5, 0x78, 0x91, 0x6e, 0x0f, 0x46, 0xa3, 0xc1, 0x9e, 0x56, 0xc0, - 0x05, 0x81, 0x4d, 0x5f, 0xd1, 0xbb, 0x50, 0x56, 0x9a, 0x45, 0x26, 0x4c, 0x5d, 0x19, 0x4a, 0xfb, - 0x46, 0xe7, 0x39, 0x3b, 0xe8, 0xf6, 0x3b, 0x5f, 0x61, 0xfd, 0xf1, 0x17, 0x16, 0x54, 0xc4, 0x1a, - 0x70, 0x3c, 0x39, 0x8a, 0x53, 0xd7, 0xeb, 0xf6, 0x3b, 0x2d, 0x43, 0x5b, 0xd5, 0x1f, 0x41, 0x35, - 0x23, 0x26, 0xe0, 0x3c, 0x7a, 0xdc, 0xda, 0xc7, 0xb9, 0xd8, 0x33, 0x65, 0xb1, 0x57, 0x41, 0x24, - 0xa0, 0x74, 0x88, 0x0b, 0xfa, 0x67, 0xb0, 0xb9, 0x20, 0xd1, 0x51, 0xc5, 0x5b, 0x5d, 0x59, 0xf1, - 0xee, 0xe3, 0xfe, 0xc0, 0xe8, 0x70, 0xc8, 0x3c, 0x39, 0xf8, 0x2b, 0xfa, 0xfb, 0x50, 0x49, 0x44, - 0x4f, 0x5c, 0x0c, 0x6d, 0x63, 0x30, 0x1c, 0xf2, 0x5c, 0xb9, 0x84, 0x69, 0xea, 0x6e, 0x4e, 0x17, - 0x74, 0x17, 0x1a, 0x79, 0x59, 0x42, 0xdc, 0x81, 0x9b, 0xbc, 0x5c, 0xb6, 0x0f, 0xba, 0xbd, 0x1d, - 0x73, 0xd8, 0xdd, 0xe9, 0xcc, 0xdd, 0x58, 0xbf, 0x01, 0x57, 0x17, 0x28, 0x38, 0x5e, 0x5f, 0x41, - 0x5c, 0x87, 0x2b, 0x0b, 0x38, 0x5a, 0x24, 0x2b, 0xfa, 0x3e, 0x88, 0xc5, 0x5d, 0x46, 0xdc, 0x84, - 0x66, 0xd2, 0x66, 0xb3, 0xd5, 0x7b, 0x3c, 0x30, 0xba, 0xa3, 0x27, 0x7b, 0x26, 0xb1, 0x97, 0x4b, - 0xaf, 0xc2, 0x3e, 0x69, 0x0d, 0x9f, 0x68, 0x85, 0xa7, 0xa5, 0xf2, 0x6d, 0xed, 0xce, 0xd3, 0x52, - 0xf9, 0x2d, 0xed, 0xed, 0xa7, 0xa5, 0xf2, 0x63, 0xed, 0xc9, 0xd3, 0x52, 0xf9, 0x89, 0xd6, 0xd5, - 0x87, 0xb0, 0xa9, 0x44, 0x79, 0x8a, 0x0d, 0x40, 0x36, 0xa6, 0x2d, 0x58, 0xed, 0x39, 0x2f, 0x1d, - 0x4f, 0x5d, 0x25, 0xa7, 0x04, 0x42, 0x07, 0x87, 0xdf, 0x74, 0x93, 0x50, 0xb3, 0x94, 0x40, 0xdd, - 0xbd, 0x9f, 0x89, 0x76, 0x4b, 0x01, 0x1a, 0xff, 0xb9, 0x02, 0x94, 0x13, 0x05, 0xe1, 0x2d, 0x58, - 0x19, 0x0d, 0xe5, 0x81, 0xd3, 0xd6, 0xfd, 0x34, 0xcc, 0xfb, 0x48, 0xfd, 0x32, 0x56, 0x46, 0x43, - 0xf1, 0x01, 0xac, 0x71, 0xc0, 0x4d, 0x79, 0xc4, 0xb4, 0x95, 0x57, 0x3a, 0x46, 0x84, 0x33, 0x24, - 0x8d, 0xf8, 0x0c, 0x2a, 0x49, 0x6d, 0xa5, 0x69, 0xfc, 0x5a, 0x3e, 0x43, 0x82, 0x36, 0x52, 0x4a, - 0xbd, 0x07, 0x8d, 0x7c, 0x81, 0xe2, 0x16, 0x00, 0x17, 0x99, 0x39, 0x1b, 0xce, 0x40, 0xc4, 0x0d, - 0x50, 0x71, 0x40, 0x77, 0x64, 0x64, 0xa9, 0x24, 0xad, 0xff, 0x6b, 0xab, 0x00, 0xa9, 0x89, 0x01, - 0x3b, 0x22, 0x31, 0xf8, 0xaf, 0x4a, 0x2f, 0xe2, 0xd7, 0xa0, 0xe2, 0x05, 0x96, 0x9d, 0x0d, 0x69, - 0x5e, 0x46, 0x00, 0xcd, 0xb7, 0x6c, 0xd4, 0x9c, 0x8a, 0x0c, 0x80, 0x73, 0x15, 0xd6, 0xe4, 0xa5, - 0x24, 0x8e, 0x1b, 0x20, 0x53, 0x14, 0x18, 0x87, 0x9c, 0xe0, 0x6c, 0xd3, 0x73, 0x7d, 0x87, 0x43, - 0x12, 0x96, 0x8c, 0x9a, 0x04, 0xf6, 0x10, 0x26, 0x6e, 0x43, 0xd5, 0xf1, 0xc7, 0x5e, 0x80, 0x72, - 0xda, 0x21, 0xdf, 0x8a, 0xa8, 0x19, 0xa0, 0x40, 0xdb, 0x17, 0xdc, 0xda, 0x70, 0xe2, 0xfa, 0x56, - 0x2c, 0xbd, 0x83, 0xa8, 0xb5, 0x0a, 0x82, 0xd5, 0xfd, 0x26, 0x0a, 0xa4, 0xfd, 0x9f, 0xc3, 0xb2, - 0x94, 0x11, 0x40, 0xd5, 0x7d, 0x1d, 0xc0, 0x89, 0xc6, 0xd6, 0x94, 0x0b, 0xaf, 0x70, 0x8c, 0x4c, - 0x09, 0xd9, 0xbe, 0x10, 0x3d, 0x68, 0x8c, 0x0e, 0x51, 0xb3, 0x09, 0x76, 0xac, 0xd8, 0x6a, 0x07, - 0x9e, 0xb4, 0xcc, 0xbf, 0x35, 0x6f, 0x8b, 0xb9, 0x9f, 0x27, 0xe3, 0xab, 0x79, 0x73, 0x79, 0xc5, - 0xa7, 0x50, 0x73, 0xc7, 0xce, 0xa1, 0x13, 0x1e, 0xb3, 0xe4, 0x58, 0xcd, 0x5d, 0xf8, 0x67, 0x0c, - 0x49, 0x8d, 0x55, 0x37, 0x4d, 0xa0, 0xc6, 0x38, 0x09, 0xfc, 0xe3, 0xc0, 0x3e, 0xe4, 0x5c, 0xb5, - 0xac, 0x95, 0x71, 0x0f, 0x31, 0x9c, 0x47, 0x12, 0x51, 0x9e, 0xdf, 0x86, 0x0d, 0xec, 0xf9, 0x28, - 0x0e, 0x1d, 0x6b, 0xc2, 0xd9, 0xea, 0xd9, 0x19, 0x88, 0x35, 0x1a, 0x12, 0x92, 0xf2, 0x36, 0x52, - 0x62, 0xca, 0xfe, 0x69, 0x7a, 0x5f, 0x9e, 0xf2, 0x36, 0x72, 0x5e, 0xfb, 0x8c, 0xe1, 0x8f, 0x1e, - 0xa5, 0x09, 0x71, 0x1f, 0xe0, 0xd4, 0x3a, 0x3a, 0xb5, 0x38, 0xcf, 0x46, 0xb6, 0x9a, 0xcf, 0x10, - 0x4e, 0x39, 0x2a, 0xa7, 0xea, 0xe7, 0x8d, 0x16, 0x5c, 0x5e, 0xd2, 0x6b, 0x3f, 0xea, 0x6e, 0xd8, - 0xdf, 0x2c, 0x40, 0x23, 0xdf, 0x96, 0xb9, 0x78, 0xc3, 0x95, 0x24, 0xde, 0xb0, 0x80, 0xd2, 0x34, - 0x08, 0xd5, 0x8d, 0x10, 0xfa, 0x9d, 0x3e, 0x85, 0x50, 0xcc, 0x3e, 0x85, 0xd0, 0x84, 0xf5, 0xd0, - 0xe1, 0xeb, 0xdd, 0x1c, 0x29, 0x42, 0x25, 0x71, 0xc2, 0x4e, 0x67, 0xd1, 0x89, 0x63, 0x2b, 0xd5, - 0x96, 0xaf, 0x29, 0xd4, 0x18, 0x28, 0x55, 0xdb, 0x6b, 0xb0, 0x6e, 0x4d, 0x5d, 0xd2, 0xb8, 0x64, - 0xec, 0x5a, 0x6b, 0xea, 0x3e, 0x73, 0x2e, 0xf4, 0x5f, 0x41, 0x35, 0xd3, 0x77, 0x58, 0x21, 0x0a, - 0x2b, 0x23, 0x0f, 0xcd, 0x29, 0x2e, 0xd8, 0x55, 0x58, 0x93, 0xe1, 0x5a, 0xf9, 0xae, 0x89, 0x4c, - 0xe1, 0x87, 0xd5, 0x3d, 0x41, 0x92, 0x7c, 0x95, 0x2b, 0x81, 0x04, 0x92, 0xc0, 0x8b, 0xcb, 0x1a, - 0x2b, 0x62, 0x07, 0x67, 0xbe, 0xac, 0x78, 0x92, 0xd6, 0xff, 0x83, 0x15, 0xa8, 0x24, 0x83, 0x80, - 0x2d, 0x3c, 0x0c, 0x83, 0x53, 0x27, 0x8c, 0xe4, 0xd7, 0x55, 0x92, 0x7a, 0x24, 0x98, 0xba, 0x63, - 0x75, 0xeb, 0x9a, 0x12, 0xe2, 0x66, 0xf6, 0x8e, 0x25, 0x47, 0x4b, 0xc9, 0x5c, 0xa9, 0xbc, 0x05, - 0x60, 0xcd, 0xe2, 0x60, 0x1c, 0x4c, 0x26, 0x6e, 0x2c, 0xbf, 0x9c, 0x81, 0x60, 0x99, 0xa4, 0x73, - 0xca, 0xde, 0xe2, 0x44, 0x86, 0x29, 0xac, 0xe5, 0x98, 0xc2, 0x4d, 0xa8, 0x44, 0xce, 0xd4, 0x0a, - 0xad, 0x38, 0x08, 0xe5, 0x6a, 0x4e, 0x01, 0x32, 0xe8, 0x5d, 0x18, 0xab, 0x88, 0xa0, 0x45, 0x0a, - 0x7a, 0x17, 0xc6, 0x5d, 0x5b, 0xdc, 0xa1, 0xab, 0x4e, 0x66, 0x82, 0x66, 0x3f, 0x6f, 0x38, 0xb1, - 0xa2, 0xa1, 0xa4, 0x10, 0x50, 0x22, 0x9f, 0x1b, 0xf6, 0xf2, 0xa3, 0xdf, 0xe2, 0x5d, 0xa0, 0x47, - 0x3a, 0x82, 0x59, 0x6c, 0x46, 0xce, 0x38, 0xf0, 0xed, 0x48, 0xfa, 0xf9, 0x35, 0x24, 0x78, 0xc8, - 0x50, 0xfd, 0x3f, 0x5f, 0x81, 0x6a, 0x66, 0x8d, 0x92, 0x8b, 0x93, 0x35, 0xa5, 0x63, 0xb8, 0xe4, - 0x82, 0x78, 0x45, 0x42, 0x38, 0x44, 0xc9, 0xd8, 0x8a, 0x2d, 0x2f, 0x38, 0xce, 0x04, 0x5f, 0x91, - 0x90, 0xae, 0x4d, 0x5e, 0x87, 0xd6, 0xc4, 0xe1, 0x47, 0x33, 0x64, 0x74, 0x80, 0x04, 0x90, 0xce, - 0xcb, 0x52, 0x76, 0x5e, 0x6a, 0xec, 0x9e, 0xca, 0xbd, 0x48, 0xde, 0xa8, 0xb7, 0xa1, 0xaa, 0xcc, - 0x5a, 0xf8, 0x15, 0xe9, 0x41, 0xa9, 0x40, 0x5d, 0x5b, 0xbc, 0x03, 0xe9, 0x13, 0x24, 0xa6, 0x15, - 0x99, 0xc1, 0x91, 0xba, 0x97, 0x97, 0x80, 0x5b, 0xd1, 0xe0, 0x28, 0x71, 0x6b, 0x22, 0x33, 0x87, - 0xe4, 0x91, 0x08, 0x20, 0x89, 0xe5, 0x3e, 0x5c, 0x4e, 0x43, 0x8c, 0x1e, 0xb9, 0x8e, 0x67, 0x9b, - 0xae, 0xcd, 0xfe, 0xd9, 0xab, 0xc6, 0x66, 0x82, 0xda, 0x45, 0x4c, 0xd7, 0x26, 0x03, 0x90, 0xb4, - 0x28, 0xd8, 0xee, 0xb1, 0x13, 0xc5, 0xf2, 0x16, 0x59, 0x8d, 0x81, 0x3b, 0x04, 0xd3, 0xff, 0xef, - 0x35, 0xa8, 0x24, 0xcc, 0xeb, 0xfb, 0x3a, 0xf3, 0x4d, 0xa8, 0x8f, 0x03, 0xdf, 0x67, 0x3f, 0x84, - 0xb4, 0x3f, 0x6b, 0x29, 0x90, 0x2e, 0x02, 0x8b, 0x0c, 0x51, 0x36, 0xb0, 0x5e, 0xc9, 0xd8, 0x4c, - 0x31, 0xf2, 0x86, 0x2b, 0xae, 0x16, 0xe4, 0x7a, 0x87, 0x56, 0xa4, 0xba, 0x39, 0x49, 0xe3, 0x8c, - 0x1e, 0x07, 0x9e, 0x27, 0xfd, 0x24, 0x64, 0x80, 0xf1, 0x14, 0x22, 0x1e, 0x50, 0x88, 0x79, 0x72, - 0x33, 0x58, 0xcb, 0x46, 0xad, 0xa3, 0x06, 0xb1, 0xa7, 0xc1, 0x1e, 0x57, 0xde, 0x50, 0x84, 0xe2, - 0x67, 0xa0, 0x49, 0xde, 0x31, 0x0d, 0x1d, 0x9b, 0x24, 0x3a, 0x79, 0x09, 0x62, 0x2b, 0x93, 0x79, - 0x5f, 0xe1, 0x8c, 0x0d, 0xa6, 0x4e, 0x00, 0x38, 0x53, 0xd3, 0x61, 0x40, 0x65, 0x96, 0x5d, 0xeb, - 0x2b, 0x46, 0x23, 0x01, 0xa3, 0x0a, 0x1b, 0x89, 0x4f, 0xe1, 0x6a, 0xe8, 0x44, 0xae, 0x3d, 0xb3, - 0x3c, 0x33, 0x3f, 0x10, 0x1c, 0xae, 0x7c, 0x4b, 0x61, 0x77, 0x33, 0x03, 0x82, 0xc5, 0x4f, 0xac, - 0x73, 0x3a, 0x91, 0xf2, 0x3c, 0xc7, 0x73, 0xa3, 0x89, 0x8c, 0x75, 0xdb, 0x98, 0x58, 0xe7, 0xfb, - 0x29, 0x94, 0x6e, 0x3c, 0x4d, 0x3d, 0x77, 0x2e, 0xb2, 0x29, 0x8f, 0x25, 0xc2, 0x0d, 0x46, 0x0b, - 0x1d, 0xea, 0x58, 0x20, 0x19, 0x5f, 0x13, 0x67, 0xf9, 0xa2, 0x51, 0x9d, 0x58, 0x74, 0x4a, 0x49, - 0xae, 0x7c, 0x6f, 0x41, 0x23, 0xa1, 0x61, 0xff, 0x5c, 0xe9, 0x22, 0x2b, 0x89, 0xd8, 0x45, 0x97, - 0xaa, 0xc6, 0xb3, 0x43, 0x0d, 0x6b, 0x83, 0xdd, 0x93, 0x24, 0x58, 0x8d, 0xe9, 0x75, 0xe0, 0x73, - 0x5d, 0x9c, 0x22, 0x1b, 0x44, 0xb1, 0x4e, 0x69, 0x5e, 0x09, 0xb3, 0xc8, 0x51, 0x86, 0x03, 0x62, - 0xbc, 0x1c, 0x7b, 0xb4, 0x8e, 0x60, 0x62, 0xa0, 0x14, 0x6c, 0xf1, 0x2e, 0x68, 0x44, 0xa7, 0x8e, - 0x81, 0xa2, 0xc0, 0xa7, 0x23, 0xe4, 0x9a, 0xd1, 0x40, 0xb8, 0x3c, 0xe4, 0x89, 0x02, 0x5f, 0x7c, - 0x01, 0x4d, 0xa2, 0x9c, 0xba, 0x53, 0x07, 0xc5, 0x17, 0x93, 0xa3, 0x71, 0x52, 0x0e, 0x71, 0xa7, - 0x78, 0xb7, 0x66, 0x5c, 0x41, 0xfc, 0xbe, 0x44, 0x53, 0x48, 0x42, 0xca, 0x78, 0x0f, 0x36, 0x33, - 0x55, 0x91, 0x43, 0xc3, 0xd1, 0xcf, 0x36, 0x92, 0xca, 0xc8, 0x51, 0xf9, 0x18, 0xb6, 0xa4, 0x07, - 0x8b, 0x24, 0xe7, 0xe9, 0x44, 0xa7, 0xc8, 0x65, 0x43, 0x48, 0x1c, 0xe5, 0xe0, 0x79, 0x27, 0xde, - 0x80, 0x1a, 0x99, 0x53, 0x64, 0xec, 0x62, 0x19, 0x01, 0xad, 0x4a, 0x30, 0x0e, 0x5a, 0xa6, 0xff, - 0xb5, 0x02, 0x88, 0xc5, 0xa9, 0xfa, 0xaa, 0x70, 0x3b, 0x64, 0x37, 0x91, 0xb1, 0x2e, 0xf0, 0xb7, - 0x78, 0x0f, 0xd6, 0x27, 0x01, 0x8b, 0x53, 0xc5, 0x57, 0x44, 0xd4, 0x5b, 0x9b, 0x04, 0x24, 0x5e, - 0xbd, 0x0b, 0x1b, 0xe3, 0xc0, 0x97, 0x83, 0xc6, 0xdc, 0x85, 0xd7, 0x5a, 0x23, 0x05, 0x23, 0x8f, - 0xd1, 0xff, 0xfd, 0x02, 0x34, 0xf2, 0x0b, 0x40, 0xbc, 0x43, 0x2f, 0x1d, 0xe4, 0xde, 0x4a, 0xc8, - 0x53, 0x0c, 0xa6, 0xf4, 0x02, 0xc2, 0xb2, 0x2a, 0xbe, 0x0e, 0x40, 0x42, 0x02, 0x8f, 0x86, 0x0c, - 0x7d, 0x4e, 0x10, 0x1a, 0x81, 0xdb, 0x50, 0xe5, 0x67, 0x8d, 0x18, 0x5f, 0xa2, 0xd1, 0xe2, 0x1c, - 0x11, 0x11, 0x7c, 0x9c, 0x71, 0x3f, 0x61, 0xf7, 0x92, 0xe5, 0x8b, 0x34, 0xa1, 0xd2, 0xff, 0x4e, - 0x01, 0x20, 0x5d, 0x03, 0x38, 0x13, 0x4f, 0x9d, 0x0b, 0xb6, 0x39, 0xc9, 0x2d, 0xf6, 0xd4, 0xb9, - 0xd8, 0x97, 0x75, 0x93, 0x6e, 0x8d, 0x91, 0xbc, 0x53, 0x5a, 0x33, 0x2a, 0xec, 0xc9, 0x18, 0x71, - 0x90, 0x27, 0xe9, 0xc8, 0x98, 0xa9, 0x3a, 0xfb, 0x2e, 0x46, 0x14, 0xa7, 0x63, 0x83, 0x73, 0xd3, - 0xd0, 0x47, 0xee, 0x4b, 0x15, 0xce, 0x8a, 0x1d, 0x2f, 0xbb, 0x0a, 0x8a, 0x84, 0x5c, 0x4e, 0x4a, - 0xc8, 0x97, 0xbc, 0xd8, 0xcd, 0x32, 0x21, 0xd4, 0x3d, 0x25, 0xf0, 0xb7, 0xe2, 0x98, 0x36, 0xd8, - 0xe4, 0x5c, 0xa0, 0xa0, 0x62, 0x58, 0xf1, 0x91, 0xc0, 0x6b, 0x74, 0x17, 0x56, 0xc6, 0xa7, 0x90, - 0x72, 0x7f, 0x12, 0x77, 0xe2, 0x1d, 0x1c, 0x69, 0x4f, 0x6d, 0x0f, 0x89, 0x9f, 0xdc, 0xaa, 0x51, - 0x1f, 0x07, 0x1e, 0x6f, 0x0d, 0x08, 0xd4, 0xff, 0xcb, 0x55, 0x80, 0xf4, 0x44, 0x38, 0xb7, 0x62, - 0x0b, 0xf9, 0x15, 0xfb, 0x00, 0xae, 0xca, 0x28, 0x85, 0xc9, 0x85, 0x2f, 0xd7, 0x37, 0x0f, 0x2d, - 0x25, 0xc2, 0x09, 0x89, 0xe5, 0x6b, 0x3a, 0x5d, 0x7f, 0xdb, 0x8a, 0xc5, 0x23, 0xe4, 0x91, 0x69, - 0x9e, 0xf8, 0x62, 0xfa, 0xca, 0x29, 0x5a, 0x4f, 0xb3, 0x8f, 0x2e, 0xa6, 0xe2, 0x63, 0x8a, 0xc3, - 0x14, 0x3a, 0xd1, 0x89, 0x19, 0x47, 0xd9, 0x8f, 0xf1, 0xad, 0xfb, 0x4d, 0x89, 0x1c, 0x45, 0xc9, - 0xb7, 0x3e, 0x86, 0x2b, 0x92, 0x49, 0xcc, 0x55, 0x8f, 0xdd, 0x31, 0xa5, 0x55, 0x3d, 0x5b, 0x3b, - 0x1a, 0x79, 0x3a, 0x26, 0x57, 0xcf, 0x6f, 0x95, 0x71, 0xe4, 0xb1, 0x33, 0xe4, 0xf3, 0x02, 0x74, - 0xd6, 0x2d, 0x25, 0x17, 0x4e, 0x08, 0x1d, 0x4a, 0xb8, 0x42, 0x88, 0x19, 0x37, 0x1e, 0x34, 0xee, - 0xd3, 0xf3, 0x62, 0xf4, 0x34, 0x44, 0x60, 0x3b, 0x06, 0xe1, 0xc4, 0x87, 0xb8, 0x43, 0xa7, 0xcd, - 0x56, 0xef, 0xa2, 0x54, 0xa5, 0x61, 0x3e, 0x69, 0xa8, 0xc1, 0x2f, 0xa4, 0xbc, 0x0f, 0x22, 0x53, - 0x73, 0x45, 0x5d, 0x23, 0xea, 0x8d, 0xa4, 0xda, 0x92, 0xf8, 0x5d, 0xa0, 0x2a, 0xa6, 0x57, 0x97, - 0xe6, 0x0e, 0x86, 0x11, 0x29, 0xaf, 0x3b, 0x5d, 0x49, 0x5b, 0x67, 0x5a, 0xb1, 0x19, 0x9f, 0x38, - 0x64, 0xc5, 0xe7, 0xbb, 0x4b, 0x9b, 0x49, 0x43, 0x5b, 0xf1, 0xe8, 0xc4, 0xe9, 0x10, 0xaf, 0x4d, - 0x5c, 0x6f, 0x36, 0xbe, 0xdb, 0xf5, 0xe6, 0x73, 0x68, 0xe6, 0x0f, 0x70, 0x32, 0xdd, 0xcd, 0x6c, - 0x7c, 0x2b, 0x7b, 0x27, 0x2c, 0xe9, 0xf1, 0x7b, 0xb0, 0x89, 0x32, 0x61, 0x2e, 0xaf, 0xf4, 0xd9, - 0xdb, 0x38, 0xb1, 0xa2, 0xec, 0x89, 0x0f, 0xbb, 0xab, 0x99, 0x67, 0x96, 0x1b, 0x93, 0x23, 0x50, - 0xd9, 0x58, 0xf3, 0x83, 0x17, 0x96, 0xcb, 0x3e, 0x26, 0xa7, 0xee, 0x94, 0xee, 0x71, 0x38, 0x36, - 0x71, 0xea, 0xb2, 0x01, 0x08, 0xe2, 0xb8, 0x2a, 0xfa, 0x3f, 0xb1, 0x0e, 0x8d, 0xfc, 0xe9, 0x3a, - 0x47, 0x82, 0x63, 0x09, 0xa1, 0x40, 0x72, 0x52, 0x22, 0x07, 0xbc, 0x06, 0x15, 0xbe, 0x72, 0x86, - 0x6c, 0x5c, 0x3d, 0x07, 0x70, 0x2a, 0x99, 0xf7, 0x7b, 0xb0, 0x3e, 0x3d, 0xfd, 0x1e, 0xd6, 0x3a, - 0xe5, 0x88, 0x2c, 0xef, 0xc1, 0xfa, 0xec, 0x34, 0x7d, 0xb6, 0x61, 0x29, 0xe9, 0xec, 0x54, 0xfa, - 0x60, 0x5f, 0x97, 0x7e, 0x01, 0xf2, 0x3e, 0xda, 0x64, 0xe6, 0xc5, 0xae, 0x49, 0x56, 0x6c, 0xc9, - 0x14, 0xae, 0x32, 0x41, 0x97, 0xf0, 0x14, 0xd3, 0x81, 0xce, 0x62, 0xb1, 0xed, 0x32, 0x0e, 0x54, - 0x22, 0xed, 0xac, 0x1a, 0xc0, 0x71, 0x9f, 0xa8, 0x39, 0xef, 0x81, 0xa6, 0xde, 0x56, 0x4b, 0xa8, - 0xd6, 0x89, 0x6a, 0x43, 0xc1, 0x15, 0xe9, 0xdb, 0xd0, 0x90, 0xb7, 0x86, 0x14, 0x21, 0x07, 0x2a, - 0xa8, 0x33, 0x54, 0x91, 0x7d, 0x0e, 0xd7, 0x02, 0xfb, 0x74, 0xa6, 0x2e, 0xc0, 0x59, 0xe1, 0xa1, - 0x1b, 0x87, 0x56, 0x12, 0x21, 0xaf, 0x6c, 0x5c, 0x41, 0x34, 0xf3, 0x8f, 0x56, 0x8a, 0xc4, 0xe2, - 0x65, 0x16, 0x55, 0x3c, 0x50, 0x3d, 0xea, 0x0c, 0x55, 0xc5, 0x7f, 0x0a, 0x57, 0x93, 0xd0, 0x2c, - 0xce, 0xc4, 0xf1, 0x63, 0x33, 0x74, 0xc8, 0x63, 0x4d, 0xbe, 0xbc, 0xb2, 0xa5, 0x22, 0xb4, 0x10, - 0xd2, 0x60, 0x9c, 0x78, 0x00, 0x57, 0xe6, 0x72, 0xc9, 0x11, 0xe4, 0x55, 0x73, 0x39, 0x97, 0x49, - 0x0e, 0x66, 0x07, 0x6e, 0xcf, 0xe5, 0xc9, 0x45, 0x33, 0xc5, 0xdc, 0x75, 0xca, 0x7d, 0x33, 0x97, - 0x3b, 0x1b, 0x6f, 0x13, 0x8b, 0xf9, 0x02, 0x9a, 0x73, 0xc5, 0xe0, 0x88, 0x30, 0x8b, 0xe5, 0xa8, - 0xad, 0x57, 0x72, 0xf9, 0x9f, 0x39, 0x17, 0xcc, 0x92, 0x7f, 0x06, 0x37, 0xe7, 0x32, 0xe6, 0xba, - 0x5f, 0x5e, 0x10, 0xbc, 0x9e, 0xcb, 0x3c, 0xc8, 0x0c, 0x05, 0x4e, 0x55, 0xfc, 0x14, 0x7b, 0x8d, - 0x6a, 0x24, 0x6b, 0xe2, 0xae, 0x46, 0x0e, 0xa3, 0xc8, 0x17, 0x10, 0xc9, 0x47, 0xc3, 0x9b, 0xf3, - 0x47, 0xc3, 0x44, 0xc8, 0xe7, 0xc1, 0xef, 0xc0, 0x86, 0x22, 0xe4, 0x43, 0xb6, 0x88, 0xc4, 0xa3, - 0x55, 0xa3, 0x2e, 0x49, 0xe8, 0x6c, 0x2d, 0x12, 0x3f, 0x87, 0x2d, 0xa4, 0xb3, 0x5d, 0xeb, 0xd8, - 0x0f, 0xa2, 0xd8, 0x1d, 0xcb, 0xf3, 0x97, 0xcb, 0xd9, 0x23, 0x1b, 0xe5, 0xf8, 0x65, 0x88, 0x53, - 0xe7, 0x62, 0x27, 0x21, 0xe5, 0x83, 0x98, 0x3f, 0x58, 0x85, 0x5a, 0xd6, 0xf9, 0xe9, 0x87, 0x5c, - 0xe8, 0xfb, 0x51, 0xd7, 0x61, 0xa5, 0x8a, 0x49, 0xbd, 0x8a, 0x9c, 0xa4, 0x98, 0xa8, 0x98, 0xad, - 0x59, 0x8c, 0xd2, 0x14, 0xa9, 0x7d, 0x81, 0xa7, 0xc2, 0x1f, 0xf1, 0xde, 0x81, 0xbb, 0xa6, 0x8c, - 0x7c, 0xf4, 0xb1, 0x8c, 0xae, 0x36, 0x55, 0xc7, 0x4b, 0xcb, 0xdc, 0xbb, 0x55, 0x34, 0x4c, 0x0a, - 0xb4, 0xf1, 0x00, 0x36, 0xd2, 0x58, 0x56, 0x9c, 0x65, 0x6d, 0x21, 0x4b, 0x3d, 0x09, 0x64, 0x25, - 0x1f, 0x75, 0xa8, 0xbb, 0x91, 0x19, 0x78, 0xb6, 0x8a, 0x49, 0xb8, 0xae, 0x5c, 0x53, 0x07, 0x9e, - 0x2d, 0xe3, 0x0e, 0x32, 0x8d, 0xef, 0x9c, 0x29, 0x9a, 0xc4, 0x7d, 0xb5, 0xef, 0x9c, 0x49, 0x9a, - 0xfb, 0x70, 0x19, 0x9b, 0x2b, 0x57, 0x15, 0x07, 0x22, 0x09, 0x42, 0xb9, 0x0a, 0x91, 0xb1, 0xf2, - 0x22, 0x1c, 0x4a, 0x44, 0xe6, 0x2a, 0x6a, 0x18, 0x9c, 0x99, 0xfe, 0x6c, 0x72, 0xc8, 0x5b, 0x8c, - 0x54, 0x24, 0xe4, 0x55, 0x54, 0x23, 0x38, 0xeb, 0x13, 0x0a, 0xfb, 0xeb, 0x1e, 0x6c, 0xaa, 0x75, - 0x3e, 0xa6, 0xa3, 0x41, 0x75, 0x9b, 0x7a, 0xd5, 0xd8, 0x60, 0x44, 0x8b, 0xe0, 0x48, 0xfb, 0x5e, - 0x42, 0xcb, 0x97, 0x62, 0x89, 0x96, 0xd7, 0x5f, 0x23, 0x4e, 0x6f, 0xc4, 0x22, 0x69, 0x1b, 0x6e, - 0xc5, 0xa1, 0x35, 0x3e, 0x35, 0x5f, 0xb5, 0x00, 0xe5, 0x25, 0xdc, 0xd7, 0x88, 0xaa, 0xb5, 0x74, - 0xf9, 0xfd, 0x90, 0xf5, 0xdb, 0xf8, 0xfe, 0xf5, 0xab, 0xff, 0x7e, 0x09, 0x36, 0x17, 0xbc, 0xc6, - 0x50, 0x99, 0x4f, 0xdf, 0x8a, 0xc4, 0x9f, 0x28, 0xb8, 0x4f, 0xac, 0x78, 0x7c, 0x82, 0xfa, 0xe1, - 0x91, 0x7b, 0xae, 0xde, 0x00, 0x25, 0xd8, 0x3e, 0x81, 0x90, 0x1b, 0xb3, 0x4c, 0xc7, 0x7e, 0xb5, - 0x2c, 0x60, 0xb1, 0xb8, 0xc8, 0xde, 0xf6, 0x2a, 0x9c, 0x49, 0xe9, 0x15, 0xe1, 0x4c, 0x6e, 0x40, - 0xc5, 0x0f, 0xe8, 0x8a, 0xf4, 0xf4, 0x54, 0x72, 0xfe, 0x75, 0x3f, 0x88, 0x07, 0xfe, 0xfe, 0x29, - 0xb2, 0xb8, 0x59, 0x44, 0x97, 0xdc, 0x0e, 0x9d, 0x30, 0x3a, 0x71, 0x13, 0xff, 0x0d, 0x16, 0x54, - 0x2e, 0xcf, 0x22, 0x67, 0x2f, 0xc1, 0x49, 0x5b, 0x57, 0x0b, 0x6a, 0x34, 0x93, 0xfd, 0x71, 0x40, - 0x1e, 0x61, 0x7c, 0xa5, 0xe0, 0xd6, 0x12, 0x57, 0xb9, 0x67, 0xce, 0x45, 0x47, 0x52, 0x19, 0xb8, - 0xa5, 0xa8, 0x84, 0x78, 0x8f, 0xc2, 0x4b, 0x1d, 0x3a, 0xa9, 0x7d, 0x36, 0xcf, 0x48, 0x2a, 0x84, - 0xa5, 0x7d, 0xec, 0x19, 0x5c, 0xe7, 0xcd, 0x68, 0x32, 0x0d, 0x7c, 0x1c, 0x8f, 0x34, 0x63, 0x94, - 0x77, 0xae, 0xce, 0x6c, 0x82, 0x57, 0x69, 0xb3, 0x92, 0x39, 0xf6, 0x55, 0x59, 0xe4, 0x43, 0xcf, - 0x1e, 0x16, 0xd4, 0x61, 0xb0, 0xe8, 0xa2, 0x46, 0x58, 0x5a, 0x4f, 0xef, 0x81, 0x16, 0x8d, 0x2d, - 0xcf, 0x0a, 0x33, 0xaa, 0x3b, 0x6f, 0x16, 0x1b, 0x0c, 0x4f, 0x95, 0x96, 0xd7, 0x01, 0x26, 0xb3, - 0x28, 0x36, 0xc9, 0xe1, 0x47, 0x05, 0xe2, 0x46, 0x08, 0x9d, 0xc8, 0xe8, 0x37, 0x61, 0xad, 0x9b, - 0x78, 0x07, 0x26, 0xf1, 0x26, 0x8a, 0xf2, 0x79, 0xb9, 0x00, 0x2a, 0xec, 0x7a, 0xb2, 0x67, 0x4d, - 0xc5, 0x3d, 0x28, 0x4e, 0xac, 0xa9, 0xbc, 0x89, 0x94, 0x44, 0xc5, 0x97, 0xd8, 0xfb, 0x7b, 0xd6, - 0x94, 0x6d, 0xcc, 0x48, 0x74, 0xe3, 0x73, 0x28, 0x2b, 0xc0, 0x8f, 0x32, 0x9f, 0xfe, 0x37, 0x2b, - 0x50, 0xd9, 0xc9, 0x7a, 0xf7, 0xa2, 0x1e, 0x1e, 0x87, 0x33, 0x9f, 0x9a, 0x28, 0x1f, 0xd2, 0x1a, - 0x5b, 0xfe, 0x48, 0x82, 0x14, 0x43, 0x5d, 0xf9, 0x0e, 0x86, 0x7a, 0x13, 0x40, 0x2e, 0x4f, 0xd7, - 0x56, 0x3a, 0x40, 0x39, 0xc4, 0x85, 0xd9, 0xb5, 0xcf, 0x97, 0xdf, 0x9f, 0x2e, 0xfd, 0xf0, 0xfb, - 0xd3, 0xab, 0x4b, 0xef, 0x4f, 0xbf, 0x93, 0x8a, 0xfd, 0xb4, 0x37, 0xda, 0xe7, 0xf2, 0xa9, 0x1f, - 0x25, 0xe4, 0xe3, 0x9e, 0x68, 0x9f, 0x8b, 0x9f, 0x40, 0x43, 0xb5, 0x4e, 0x96, 0x07, 0xb9, 0xa0, - 0x89, 0x12, 0xc7, 0xee, 0xc0, 0xf5, 0x38, 0x9b, 0xcc, 0x6f, 0x14, 0xd5, 0xef, 0xb9, 0xa3, 0xfd, - 0x2f, 0x17, 0x40, 0x48, 0x67, 0xae, 0xdd, 0x99, 0xe7, 0x8d, 0x9c, 0x73, 0xda, 0x8f, 0xee, 0xc1, - 0x66, 0xee, 0xf2, 0x51, 0x46, 0xcb, 0xda, 0xc8, 0xdc, 0x36, 0x52, 0x81, 0xaa, 0x17, 0xc2, 0x12, - 0xaf, 0x2c, 0x0d, 0x4b, 0xbc, 0x3c, 0xdc, 0xf1, 0x6d, 0xa8, 0x66, 0x83, 0xfa, 0xb2, 0xda, 0x4d, - 0xd7, 0x46, 0x38, 0x9e, 0xaf, 0xfe, 0xdf, 0xad, 0x00, 0xa4, 0x0e, 0x67, 0x7f, 0xde, 0x97, 0xdf, - 0x97, 0x0c, 0x49, 0x71, 0xd9, 0x90, 0xdc, 0x05, 0x2d, 0x4b, 0x97, 0x89, 0x2e, 0xdd, 0x48, 0x09, - 0x95, 0xfa, 0xe9, 0x46, 0xd9, 0x08, 0xbd, 0x14, 0xcb, 0x4d, 0xde, 0x17, 0x66, 0x24, 0x0b, 0xb1, - 0x92, 0x61, 0x95, 0xdd, 0x88, 0x25, 0x01, 0x92, 0x7f, 0x55, 0x4e, 0x72, 0x57, 0x09, 0x66, 0x71, - 0x72, 0xb3, 0x68, 0x5d, 0xca, 0xbf, 0xb2, 0xa4, 0x17, 0x8c, 0x56, 0x37, 0x8b, 0x3e, 0x83, 0xca, - 0xd1, 0xcc, 0xf3, 0xcc, 0xd8, 0x39, 0x57, 0xb7, 0x9d, 0x9a, 0x39, 0x5f, 0xbd, 0xcc, 0xf0, 0x1a, - 0xe5, 0x23, 0x99, 0xd0, 0xff, 0x68, 0x1d, 0x56, 0xd9, 0x28, 0xff, 0x39, 0x54, 0xa2, 0x78, 0x12, - 0x67, 0xaf, 0xcd, 0x48, 0x3f, 0x2e, 0xc2, 0xd3, 0xad, 0x17, 0xda, 0x36, 0x58, 0x6a, 0x42, 0x5a, - 0xe2, 0x75, 0x5b, 0xb0, 0x1a, 0xc5, 0xce, 0x34, 0x92, 0x31, 0x65, 0x38, 0x21, 0xee, 0xc0, 0xaa, - 0x1f, 0xd8, 0xf3, 0x4f, 0x99, 0xf4, 0x51, 0x13, 0x64, 0x84, 0xd0, 0x61, 0x2d, 0x19, 0xf1, 0x85, - 0xab, 0x2b, 0x8c, 0xa1, 0x78, 0x74, 0x8e, 0x85, 0xdc, 0x57, 0x45, 0xeb, 0x4e, 0xd2, 0xa8, 0xb8, - 0xd0, 0x59, 0x9e, 0x75, 0xac, 0x5e, 0x41, 0x90, 0x49, 0x71, 0x07, 0xaa, 0xf8, 0xf3, 0x45, 0xe8, - 0xc6, 0xce, 0xf0, 0xa1, 0x92, 0x29, 0x32, 0x20, 0x71, 0x0b, 0xc0, 0x76, 0x62, 0x67, 0x1c, 0x0f, - 0xbf, 0xf5, 0x94, 0x71, 0x32, 0x03, 0x11, 0x3f, 0x01, 0x71, 0x68, 0x8d, 0x4f, 0x8f, 0x43, 0xba, - 0x0a, 0xfa, 0xed, 0xcc, 0x09, 0xdd, 0x84, 0x71, 0x57, 0x33, 0x9d, 0x62, 0x6c, 0xa6, 0x64, 0xbf, - 0x60, 0x2a, 0x71, 0x15, 0xd6, 0x26, 0xd6, 0xf9, 0x4e, 0x30, 0x95, 0xd6, 0x7b, 0x99, 0x12, 0x0f, - 0xe1, 0x2a, 0xca, 0x28, 0xd9, 0xc8, 0x2a, 0xd2, 0x3d, 0x92, 0x39, 0x34, 0x4a, 0x30, 0x69, 0x48, - 0x15, 0x79, 0x86, 0xbe, 0x0d, 0x5b, 0xca, 0x38, 0xaf, 0x5e, 0x30, 0x1a, 0xbb, 0x49, 0x40, 0xd3, - 0x85, 0xc9, 0x7f, 0x59, 0x12, 0xef, 0x64, 0x68, 0xc5, 0x9b, 0x50, 0xc7, 0x0f, 0x87, 0x4e, 0x3c, - 0x0b, 0x7d, 0xdc, 0xfb, 0x58, 0xa2, 0x40, 0x01, 0xd1, 0x50, 0x30, 0xf6, 0xf7, 0x96, 0x09, 0xbe, - 0xa1, 0xc0, 0x12, 0x43, 0x3d, 0x81, 0xd2, 0x25, 0x85, 0x87, 0x70, 0x95, 0x3d, 0x49, 0xa3, 0x6f, - 0x3d, 0x29, 0x67, 0x99, 0xe9, 0xd5, 0x99, 0xb2, 0x71, 0x99, 0xb0, 0xc3, 0x6f, 0x3d, 0x16, 0xb5, - 0x78, 0xaf, 0x1f, 0xc0, 0xd5, 0x99, 0x1f, 0x3a, 0x51, 0xe0, 0xbd, 0x4c, 0x22, 0x47, 0x9f, 0xb8, - 0x28, 0x5e, 0x6b, 0xd9, 0x2b, 0x87, 0x07, 0x09, 0x8d, 0xbc, 0x7c, 0xe8, 0xc7, 0xc6, 0xd6, 0x6c, - 0x11, 0x18, 0x89, 0xdf, 0x81, 0x9b, 0xe4, 0x28, 0x35, 0x91, 0x4f, 0x24, 0xc9, 0xbe, 0x89, 0x50, - 0x5c, 0x98, 0xd9, 0x47, 0x52, 0x6f, 0x6e, 0x22, 0x8d, 0x7a, 0x45, 0x89, 0x7b, 0x24, 0x1a, 0xf8, - 0x07, 0xf6, 0x91, 0xf8, 0x29, 0x6c, 0x50, 0xfe, 0x24, 0x64, 0x35, 0x0b, 0xfa, 0x09, 0x7b, 0x7d, - 0xee, 0x3a, 0x67, 0x86, 0xc2, 0x19, 0x8d, 0x97, 0xd9, 0x64, 0x24, 0xbe, 0x80, 0xea, 0x38, 0x7d, - 0xc0, 0x45, 0x5e, 0xad, 0x59, 0xf2, 0x8e, 0xd4, 0xd4, 0x19, 0x1b, 0x59, 0x4a, 0xfd, 0xf7, 0xa0, - 0x9e, 0x5b, 0x44, 0x0b, 0x2e, 0x58, 0xc3, 0x4e, 0xaf, 0xd3, 0x1e, 0xb1, 0x93, 0x84, 0x74, 0x0a, - 0x5a, 0xc9, 0x78, 0x0f, 0x95, 0x32, 0xce, 0x13, 0xf4, 0x2a, 0xce, 0x5e, 0xc7, 0x78, 0xdc, 0x21, - 0xff, 0x96, 0xa2, 0x56, 0xd4, 0xff, 0x95, 0x15, 0xd8, 0x1c, 0x85, 0x96, 0x1f, 0xc9, 0xa7, 0xc6, - 0xfd, 0x38, 0x0c, 0x3c, 0xf1, 0x13, 0x28, 0xc7, 0x63, 0x2f, 0xbb, 0xaa, 0x6f, 0xab, 0x3d, 0x64, - 0x8e, 0xf4, 0xfe, 0x68, 0xcc, 0x0e, 0xea, 0xeb, 0x31, 0xff, 0x10, 0x1f, 0xc2, 0xea, 0xa1, 0x73, - 0xec, 0xfa, 0x72, 0x1b, 0xbd, 0x32, 0x9f, 0x71, 0x1b, 0x91, 0x4f, 0x2e, 0x19, 0x4c, 0x25, 0x3e, - 0x86, 0x35, 0x79, 0xb4, 0x56, 0xcc, 0xde, 0x13, 0xc9, 0x7e, 0x08, 0xb1, 0x4f, 0x2e, 0x19, 0x92, - 0x4e, 0x7c, 0x0e, 0xe5, 0x30, 0x90, 0xaf, 0x11, 0x96, 0xb2, 0x3c, 0x2b, 0xcd, 0x63, 0x48, 0xfc, - 0x93, 0x4b, 0x46, 0x42, 0xab, 0xdf, 0x87, 0x75, 0x59, 0x59, 0xec, 0x86, 0xed, 0xce, 0xe3, 0xae, - 0xec, 0xc1, 0xf6, 0x60, 0x6f, 0xaf, 0x3b, 0xe2, 0x98, 0xdd, 0xc6, 0xa0, 0xd7, 0xdb, 0x6e, 0xb5, - 0x9f, 0x69, 0x2b, 0xdb, 0x65, 0x58, 0xe3, 0xb5, 0xa6, 0xff, 0x93, 0x05, 0xd8, 0x98, 0x6b, 0x80, - 0x78, 0x04, 0xa5, 0x89, 0x7a, 0x2d, 0xa9, 0xa1, 0x4e, 0xcc, 0xe7, 0x88, 0x32, 0x69, 0x36, 0x67, - 0x61, 0x0e, 0xfd, 0x4b, 0x68, 0xe4, 0xe1, 0x19, 0x17, 0x9c, 0x3a, 0x54, 0x8c, 0x4e, 0x6b, 0xc7, - 0x1c, 0xf4, 0x7b, 0x5f, 0xb3, 0x17, 0x1d, 0x25, 0x5f, 0x18, 0x5d, 0xf2, 0x7d, 0xf9, 0x5d, 0xd0, - 0xe6, 0x3b, 0x46, 0x3c, 0x86, 0x0d, 0x14, 0x19, 0x3d, 0x87, 0x9d, 0x16, 0xd3, 0x21, 0xbb, 0xb5, - 0xa4, 0x27, 0x25, 0x19, 0x5f, 0x48, 0x1f, 0xe7, 0xd2, 0xfa, 0xef, 0x81, 0x58, 0xec, 0xc1, 0x3f, - 0xbf, 0xe2, 0xff, 0x8f, 0x02, 0x94, 0xf6, 0x3d, 0xcb, 0x17, 0x6f, 0xc2, 0x2a, 0x9f, 0xf2, 0x16, - 0xb2, 0xf7, 0x23, 0x89, 0x35, 0xe2, 0xb4, 0x20, 0x9c, 0x78, 0x1f, 0x8a, 0xf1, 0x58, 0x45, 0xe7, - 0xbe, 0xf6, 0x8a, 0xc9, 0xf7, 0xe4, 0x92, 0x81, 0x54, 0xe2, 0x2e, 0x14, 0x6d, 0x5b, 0x85, 0x76, - 0xcb, 0xf8, 0x00, 0xec, 0x38, 0x47, 0xae, 0xef, 0xca, 0x27, 0xf2, 0x90, 0x44, 0xbc, 0x0d, 0x45, - 0x7b, 0xec, 0xe5, 0xe3, 0xf4, 0xf1, 0xf1, 0x7c, 0x52, 0xa0, 0x3d, 0xf6, 0x50, 0x7d, 0x8c, 0xc3, - 0x0b, 0x33, 0x9c, 0xf9, 0x14, 0xd9, 0x44, 0xbd, 0x26, 0x59, 0x45, 0x91, 0x74, 0x46, 0xe1, 0x51, - 0x22, 0x19, 0xe6, 0x57, 0x3e, 0xb3, 0xa6, 0xcc, 0x9d, 0x6e, 0x24, 0x1f, 0x64, 0xdb, 0x5e, 0x83, - 0x12, 0x96, 0xae, 0x7f, 0x40, 0xaf, 0x00, 0xcd, 0x26, 0x3e, 0xee, 0x5d, 0x52, 0xaf, 0x5a, 0x7c, - 0x80, 0x59, 0x62, 0xf4, 0x7f, 0x58, 0x84, 0x6a, 0xa6, 0x3e, 0xe2, 0x53, 0x28, 0xdb, 0xf9, 0x85, - 0x78, 0x7d, 0xa1, 0xd2, 0xf7, 0x77, 0xd4, 0x12, 0xb4, 0xe5, 0xf4, 0xa6, 0xdb, 0x0f, 0xb1, 0xf9, - 0xd2, 0x0a, 0x5d, 0xbe, 0xa5, 0xbd, 0x92, 0xbd, 0x86, 0x30, 0x74, 0xe2, 0xe7, 0x0a, 0xf3, 0xe4, - 0x92, 0x51, 0x8b, 0x32, 0x69, 0x32, 0xd1, 0xc9, 0x26, 0x15, 0x73, 0x2f, 0xfb, 0x32, 0xf0, 0xc9, - 0x25, 0x43, 0xe1, 0x91, 0xd4, 0x39, 0x77, 0xc6, 0xb3, 0x58, 0x99, 0xe8, 0xea, 0xaa, 0x41, 0x04, - 0xa4, 0x57, 0xd5, 0xf9, 0xa7, 0x78, 0x80, 0x5b, 0xa7, 0xe5, 0x79, 0x01, 0x49, 0xde, 0xab, 0xd9, - 0x93, 0xb5, 0x9d, 0x04, 0xce, 0xaf, 0xb8, 0xab, 0x94, 0x78, 0x07, 0x56, 0x83, 0xf8, 0xc4, 0x51, - 0x06, 0x01, 0xf5, 0x9e, 0x10, 0x82, 0x76, 0xda, 0x3d, 0x9c, 0x29, 0x84, 0xd6, 0xff, 0xb0, 0x00, - 0xeb, 0xb2, 0x07, 0xc4, 0x26, 0xd4, 0x87, 0x9d, 0x91, 0xf9, 0xbc, 0x65, 0x74, 0x5b, 0xdb, 0xbd, - 0x8e, 0x0c, 0x2f, 0xf8, 0xd8, 0x68, 0xf5, 0x25, 0x83, 0x34, 0x3a, 0xcf, 0x07, 0xcf, 0x3a, 0xec, - 0xd7, 0xb6, 0xd3, 0xe9, 0x7f, 0xad, 0x15, 0xd9, 0x65, 0xb4, 0xb3, 0xdf, 0x32, 0x90, 0x57, 0x56, - 0x61, 0xbd, 0xf3, 0x55, 0xa7, 0x7d, 0x40, 0xcc, 0xb2, 0x01, 0xb0, 0xd3, 0x69, 0xf5, 0x7a, 0x83, - 0x36, 0x32, 0xcf, 0x35, 0x21, 0xa0, 0xd1, 0x36, 0x3a, 0xad, 0x51, 0xc7, 0x6c, 0xb5, 0xdb, 0x83, - 0x83, 0xfe, 0x48, 0x5b, 0xc7, 0x2f, 0xb6, 0x7a, 0xa3, 0x8e, 0x91, 0x80, 0xe8, 0xe5, 0xd6, 0x1d, - 0x63, 0xb0, 0x9f, 0x40, 0x2a, 0xdb, 0x15, 0x58, 0x1f, 0xf3, 0x58, 0xe9, 0xff, 0xee, 0x26, 0xbb, - 0x74, 0xa4, 0x53, 0x53, 0x7c, 0x01, 0x65, 0xdb, 0xce, 0x8d, 0xf1, 0xcd, 0x65, 0x53, 0xf8, 0xfe, - 0x8e, 0xad, 0x86, 0x99, 0x7f, 0x88, 0x37, 0xd4, 0x42, 0x5a, 0x59, 0x58, 0x48, 0x6a, 0x19, 0xfd, - 0x0c, 0x36, 0xe4, 0xf3, 0x32, 0xc9, 0x69, 0x70, 0x6e, 0x95, 0xb4, 0x09, 0xb9, 0x23, 0x71, 0x4f, - 0x2e, 0x19, 0x8d, 0x71, 0x0e, 0x22, 0x7e, 0x0a, 0x0d, 0x8b, 0xcf, 0x58, 0xb3, 0xa7, 0xc9, 0xc9, - 0xa6, 0xd7, 0xa2, 0x23, 0xd6, 0x34, 0x7b, 0xdd, 0xca, 0x02, 0x70, 0x22, 0xda, 0x61, 0x30, 0x4d, - 0x33, 0xaf, 0xe6, 0xee, 0xc3, 0x84, 0xc1, 0x34, 0x93, 0xb7, 0x66, 0x67, 0xd2, 0xe2, 0x73, 0xa8, - 0xc9, 0x9a, 0xa7, 0xe7, 0x09, 0xc9, 0x92, 0xe5, 0x6a, 0x93, 0x8e, 0xf0, 0xe4, 0x92, 0x51, 0x1d, - 0xa7, 0x49, 0xf1, 0x10, 0x15, 0x83, 0x54, 0xa3, 0x5a, 0xcf, 0xce, 0x35, 0xaa, 0xad, 0xca, 0x05, - 0x56, 0x92, 0x12, 0x1f, 0x03, 0x50, 0x3d, 0x39, 0x4f, 0x39, 0x77, 0x53, 0x34, 0x0c, 0xa6, 0x2a, - 0x4b, 0xc5, 0x56, 0x89, 0x4c, 0xf5, 0xd8, 0x54, 0x59, 0x59, 0xac, 0x1e, 0xcb, 0x1e, 0x49, 0xf5, - 0xd8, 0x6a, 0x99, 0x54, 0x8f, 0xb3, 0xc1, 0x42, 0xf5, 0x54, 0x2e, 0xae, 0x1e, 0x67, 0x52, 0xd5, - 0xe3, 0x3c, 0xd5, 0xf9, 0xea, 0xa9, 0x2c, 0x54, 0x3d, 0xce, 0xf1, 0xd3, 0x05, 0x55, 0xb0, 0xf6, - 0x4a, 0x55, 0x10, 0x87, 0x2d, 0xaf, 0x0c, 0xfe, 0x14, 0x1a, 0xd1, 0x49, 0x70, 0x96, 0x61, 0x20, - 0xf5, 0x6c, 0xee, 0xe1, 0x49, 0x70, 0x96, 0xe5, 0x20, 0xf5, 0x28, 0x0b, 0xc0, 0xda, 0x72, 0x13, - 0xe9, 0xf9, 0x81, 0x46, 0xb6, 0xb6, 0xd4, 0x42, 0x14, 0x94, 0xb0, 0xb6, 0x96, 0x4a, 0x60, 0xa7, - 0xa4, 0x67, 0x2b, 0x91, 0x3c, 0x2d, 0xc9, 0xdd, 0xaf, 0x94, 0x5f, 0x82, 0xe4, 0x94, 0x25, 0xc2, - 0xb9, 0x35, 0xf3, 0xb3, 0xd9, 0xb4, 0xec, 0xdc, 0x3a, 0xf0, 0x73, 0x19, 0x6b, 0x4c, 0x2a, 0xb3, - 0xa6, 0xab, 0x22, 0x72, 0xbe, 0x9d, 0xa1, 0x80, 0x26, 0xef, 0x51, 0xe7, 0x56, 0xc5, 0x50, 0xe2, - 0xd2, 0x55, 0xa1, 0x20, 0xc9, 0xbc, 0x4e, 0xb2, 0x8b, 0xf9, 0x79, 0x9d, 0xc9, 0x4c, 0xf3, 0x3a, - 0xc9, 0x9a, 0x2c, 0xa8, 0x24, 0xef, 0xe5, 0x85, 0x05, 0x95, 0xc9, 0xcc, 0x0b, 0x2a, 0xc9, 0xfd, - 0x10, 0xe4, 0x6c, 0xe2, 0xce, 0xcd, 0xdd, 0xb6, 0xe6, 0x5a, 0xcb, 0xde, 0x85, 0x71, 0x92, 0xc2, - 0xb9, 0x1a, 0x3a, 0xa8, 0x7a, 0xca, 0xa9, 0x70, 0x25, 0x3b, 0x57, 0x0d, 0xc2, 0x24, 0x4b, 0x29, - 0x4c, 0x93, 0x99, 0x8f, 0x4d, 0xdd, 0x38, 0x6c, 0xda, 0x8b, 0x1f, 0xdb, 0x77, 0xe3, 0x30, 0xfd, - 0x18, 0xa6, 0xc4, 0x87, 0x40, 0xd3, 0x90, 0xb3, 0x38, 0x59, 0xd6, 0x8d, 0xdd, 0x22, 0x33, 0x94, - 0x6d, 0xf9, 0x1b, 0x27, 0x8b, 0xfc, 0xc6, 0xd8, 0x1e, 0x37, 0x8f, 0xb2, 0x93, 0x85, 0x3f, 0xd1, - 0xde, 0x69, 0xe3, 0x64, 0x61, 0xa2, 0xb6, 0x3d, 0x16, 0xf7, 0x80, 0x72, 0x13, 0xfd, 0x71, 0xee, - 0xbd, 0xba, 0x30, 0x98, 0x32, 0xf5, 0x3a, 0x12, 0x20, 0x2d, 0xb6, 0xc0, 0x0b, 0x7c, 0xd5, 0xf0, - 0x93, 0x5c, 0x0b, 0x10, 0x91, 0x30, 0x83, 0x71, 0x92, 0xd2, 0xff, 0xe9, 0x35, 0x58, 0x97, 0xbc, - 0x56, 0x5c, 0x86, 0x0d, 0xc9, 0xf2, 0x77, 0x5a, 0xa3, 0xd6, 0x76, 0x6b, 0x88, 0x42, 0x9a, 0x80, - 0x06, 0xf3, 0xfc, 0x04, 0x56, 0xc0, 0x7d, 0x80, 0x98, 0x7e, 0x02, 0xa2, 0x37, 0x2b, 0x65, 0x5e, - 0xf6, 0x1e, 0x2e, 0x8a, 0x0d, 0xa8, 0x72, 0x46, 0x06, 0x50, 0xb4, 0x63, 0xca, 0xc5, 0xe9, 0xd5, - 0x4c, 0x16, 0xf6, 0xff, 0x5e, 0x4b, 0xb3, 0x30, 0x60, 0x3d, 0xc9, 0xa2, 0x1c, 0xc4, 0x05, 0x34, - 0x46, 0xc6, 0x41, 0xbf, 0x9d, 0x7e, 0xa7, 0x42, 0x11, 0x6a, 0xb9, 0x98, 0xe7, 0xdd, 0xce, 0x0b, - 0x0d, 0xe8, 0x71, 0x4c, 0x2a, 0x85, 0xd2, 0xe4, 0x38, 0x4e, 0x85, 0x50, 0xb2, 0x26, 0xae, 0xc1, - 0xe5, 0xe1, 0x93, 0xc1, 0x0b, 0x93, 0x33, 0x25, 0x4d, 0xa8, 0x8b, 0x2d, 0xd0, 0x32, 0x08, 0x2e, - 0xbe, 0x81, 0x9f, 0x24, 0xa8, 0x22, 0x1c, 0x6a, 0x1b, 0xf4, 0xc0, 0x0d, 0xc2, 0x46, 0xbc, 0xef, - 0x6a, 0xd8, 0x14, 0xce, 0x3a, 0xe8, 0x1d, 0xec, 0xf5, 0x87, 0xda, 0x26, 0x56, 0x82, 0x20, 0x5c, - 0x73, 0x91, 0x14, 0x93, 0xee, 0xd6, 0x97, 0x69, 0x03, 0x47, 0xd8, 0x8b, 0x96, 0xd1, 0xef, 0xf6, - 0x1f, 0x0f, 0xb5, 0xad, 0xa4, 0xe4, 0x8e, 0x61, 0x0c, 0x8c, 0xa1, 0x76, 0x25, 0x01, 0x0c, 0x47, - 0xad, 0xd1, 0xc1, 0x50, 0xbb, 0x9a, 0xd4, 0x72, 0xdf, 0x18, 0xb4, 0x3b, 0xc3, 0x61, 0xaf, 0x3b, - 0x1c, 0x69, 0xd7, 0xc4, 0x15, 0xd8, 0x4c, 0x6b, 0xa4, 0x88, 0x9b, 0x99, 0x8a, 0x1a, 0x8f, 0x3b, - 0x23, 0xed, 0x7a, 0x52, 0x8d, 0xf6, 0xa0, 0xd7, 0x6b, 0x91, 0x6b, 0xfa, 0x0d, 0x24, 0xa2, 0x0b, - 0x17, 0xb2, 0x35, 0xaf, 0x61, 0xbd, 0x0e, 0xfa, 0x59, 0xd0, 0xcd, 0xcc, 0xd4, 0x18, 0x76, 0x7e, - 0x71, 0xd0, 0xe9, 0xb7, 0x3b, 0xda, 0xeb, 0xe9, 0xd4, 0x48, 0x60, 0xb7, 0x92, 0xa9, 0x91, 0x80, - 0x6e, 0x27, 0xdf, 0x54, 0xa0, 0xa1, 0x76, 0x27, 0xe9, 0xb0, 0x83, 0xfd, 0xc7, 0x46, 0x6b, 0xa7, - 0xa3, 0xe9, 0x08, 0x31, 0x3a, 0xfd, 0xd6, 0x9e, 0x1a, 0xd8, 0x37, 0x33, 0x03, 0xbb, 0xdf, 0x1d, - 0x19, 0xda, 0x5b, 0xc9, 0x40, 0x52, 0xf2, 0x6d, 0xf1, 0x1a, 0x5c, 0xcb, 0x4e, 0x39, 0xf3, 0x45, - 0x77, 0xf4, 0x44, 0xde, 0x8b, 0x78, 0x87, 0x7d, 0xe5, 0x09, 0xd9, 0xde, 0x69, 0xf3, 0x05, 0x10, - 0xca, 0x8b, 0xa9, 0xbb, 0x7a, 0xa9, 0xfc, 0x86, 0xf6, 0xc6, 0xbd, 0x0d, 0xd9, 0x15, 0xfd, 0x3e, - 0xdd, 0x8c, 0x18, 0x6e, 0xd7, 0x50, 0x72, 0x53, 0x22, 0x88, 0xfe, 0x14, 0xc4, 0x70, 0x76, 0x18, - 0x8d, 0x43, 0x97, 0x42, 0x2c, 0xc8, 0x80, 0x14, 0x02, 0x4a, 0x47, 0x61, 0x30, 0x51, 0x9e, 0x35, - 0xf8, 0x5b, 0xdc, 0x81, 0xea, 0x74, 0x76, 0x48, 0xae, 0xfd, 0x69, 0x6c, 0xf1, 0x2c, 0x48, 0xff, - 0x9f, 0x0b, 0xd0, 0xc8, 0x8b, 0x1f, 0x74, 0x6a, 0x73, 0x64, 0xfa, 0x41, 0xcc, 0x4f, 0x90, 0x45, - 0xca, 0x46, 0xeb, 0x1e, 0xf5, 0x83, 0x98, 0xde, 0x20, 0x8b, 0x72, 0x8e, 0x6d, 0x2b, 0x73, 0x8e, - 0x6d, 0x5d, 0xb8, 0x1c, 0x65, 0xaa, 0x67, 0xe6, 0x1e, 0x80, 0x6b, 0x26, 0x8f, 0x04, 0xcf, 0xd5, - 0xdf, 0x10, 0xd1, 0x62, 0x9b, 0x64, 0x84, 0xf8, 0x52, 0x12, 0x21, 0x5e, 0x3c, 0x80, 0xb2, 0xf4, - 0x47, 0x8d, 0xa4, 0x18, 0x73, 0x35, 0x15, 0xd3, 0xf0, 0xf3, 0xf2, 0x35, 0xc4, 0xc8, 0x48, 0xe8, - 0xf4, 0xbf, 0x0c, 0xf5, 0x9c, 0x84, 0x44, 0x86, 0xbc, 0xa3, 0x7c, 0xeb, 0xca, 0xee, 0xd1, 0x0f, - 0x68, 0x5a, 0xf6, 0xeb, 0xc5, 0x1f, 0xf8, 0xf5, 0xbf, 0x59, 0x80, 0x5a, 0x56, 0xc6, 0xfa, 0xcd, - 0xbf, 0x7e, 0x1b, 0xaa, 0xea, 0xb7, 0x7a, 0x8f, 0xb9, 0x64, 0x80, 0x02, 0x91, 0x77, 0x6a, 0x95, - 0x0f, 0xda, 0x76, 0x4f, 0x87, 0x49, 0xb7, 0x65, 0x41, 0xe4, 0x74, 0x78, 0xe2, 0x8c, 0x4f, 0x77, - 0x9f, 0x21, 0x81, 0x72, 0x3a, 0x4c, 0x20, 0xfa, 0x6d, 0xa8, 0xec, 0x9e, 0xaa, 0xeb, 0xb9, 0xd9, - 0x07, 0xff, 0x2a, 0x1c, 0xf8, 0x5e, 0xff, 0x3b, 0x05, 0x68, 0xa4, 0xa6, 0x2e, 0xba, 0xf3, 0xd0, - 0x80, 0x15, 0xfb, 0x50, 0x4e, 0xbb, 0x15, 0xfb, 0x30, 0x75, 0x2c, 0x5d, 0xc9, 0x3a, 0x96, 0xbe, - 0x29, 0x0b, 0x2b, 0x66, 0x37, 0x97, 0xe4, 0x5b, 0x32, 0xac, 0xfe, 0x43, 0xa8, 0xe1, 0x7f, 0xb2, - 0xd8, 0x84, 0x8e, 0x9d, 0x0f, 0x55, 0x96, 0x12, 0xe7, 0x88, 0x48, 0x9b, 0x94, 0x2e, 0xab, 0xaf, - 0x78, 0x00, 0x88, 0x1e, 0xa6, 0xfa, 0x47, 0xab, 0x50, 0xcd, 0x48, 0xac, 0x3f, 0x68, 0x9a, 0xdf, - 0x84, 0x4a, 0xfa, 0x1c, 0x8d, 0x8c, 0x65, 0x9e, 0x00, 0x72, 0x63, 0x55, 0x9c, 0x1b, 0x2b, 0xf2, - 0xef, 0xa6, 0x00, 0xaa, 0xa9, 0x7f, 0x37, 0x25, 0xf3, 0x36, 0xfe, 0xd5, 0xef, 0x39, 0x0c, 0xfe, - 0x04, 0x6a, 0x19, 0x03, 0xbd, 0xf2, 0x04, 0x9d, 0xa7, 0xaf, 0xa6, 0xc6, 0xfa, 0x48, 0x5c, 0x81, - 0xb5, 0xa3, 0x53, 0xd3, 0x3e, 0x64, 0x17, 0x89, 0x8a, 0xb1, 0x7a, 0x74, 0xba, 0x73, 0x48, 0x2e, - 0x21, 0x47, 0x89, 0x90, 0xc6, 0x66, 0xd3, 0xf2, 0x91, 0x12, 0xc5, 0xee, 0xc2, 0xfa, 0xd1, 0x69, - 0x36, 0x22, 0xf2, 0x42, 0x97, 0xaf, 0x1d, 0x9d, 0x52, 0x50, 0xde, 0x8f, 0x60, 0x4b, 0x4a, 0x0a, - 0x56, 0xa4, 0xac, 0x88, 0xb8, 0x44, 0xf9, 0xf9, 0xbf, 0x4d, 0xc6, 0xb5, 0x22, 0xb6, 0x21, 0xe2, - 0x8c, 0xd3, 0xa1, 0x96, 0x99, 0x80, 0x6c, 0xfe, 0xac, 0x18, 0x39, 0x98, 0x78, 0x04, 0xb5, 0xa3, - 0x53, 0x1e, 0xd0, 0x51, 0xb0, 0xe7, 0xc8, 0x08, 0x41, 0x5b, 0xf3, 0x43, 0x49, 0x97, 0x52, 0x72, - 0x94, 0xe2, 0x2a, 0xac, 0x19, 0xd6, 0xd9, 0xf0, 0x17, 0x3d, 0x12, 0x57, 0x2b, 0x86, 0x4c, 0x89, - 0x36, 0x5c, 0xc9, 0xd8, 0x2d, 0x8f, 0x4e, 0x4d, 0x8e, 0x96, 0xa3, 0xcc, 0x96, 0x8b, 0xd6, 0xd7, - 0x94, 0x7a, 0xf7, 0x94, 0x03, 0x15, 0x46, 0xe2, 0x0b, 0xd8, 0x38, 0x3a, 0xa5, 0xd3, 0x02, 0x53, - 0x46, 0x9f, 0x91, 0x02, 0xea, 0x46, 0xea, 0x20, 0x25, 0x8f, 0x71, 0x8e, 0x4e, 0xb1, 0x97, 0xb6, - 0x99, 0x4a, 0xb4, 0x61, 0x33, 0x59, 0xa8, 0x09, 0xbf, 0x10, 0xdf, 0xc9, 0x2f, 0x34, 0x7b, 0x0e, - 0x22, 0x3a, 0x70, 0x7b, 0x1c, 0x5b, 0x91, 0xc9, 0xda, 0x3b, 0x32, 0xd2, 0x69, 0x18, 0xc4, 0xc1, - 0x38, 0xf0, 0x12, 0x07, 0x55, 0x8e, 0x80, 0x7a, 0x13, 0xc9, 0x3a, 0x8a, 0x6a, 0x5f, 0x12, 0x49, - 0x77, 0x55, 0x8e, 0xb3, 0xa5, 0xff, 0x47, 0x05, 0x68, 0xa4, 0x7a, 0x17, 0xb2, 0x23, 0x71, 0x8f, - 0xdf, 0x2b, 0x66, 0x5d, 0xb7, 0x39, 0xaf, 0x9a, 0x21, 0xc9, 0xfd, 0xd1, 0xc5, 0x94, 0xdf, 0x2d, - 0x5e, 0xf6, 0x1a, 0xd9, 0xb2, 0xb3, 0xa3, 0xe2, 0xb2, 0xb3, 0x23, 0xfd, 0x31, 0x14, 0x47, 0x17, - 0x53, 0xb6, 0xf1, 0xa1, 0x18, 0xc2, 0xf6, 0x00, 0x16, 0x40, 0xe8, 0x3a, 0xdc, 0xb3, 0xce, 0xd7, - 0xfc, 0x0a, 0xc5, 0xbe, 0xd1, 0xdd, 0x6b, 0x19, 0x5f, 0x9b, 0x08, 0x20, 0x41, 0x6d, 0x77, 0x60, - 0x74, 0xba, 0x8f, 0xfb, 0x04, 0x28, 0x91, 0x05, 0x30, 0xad, 0x62, 0xcb, 0xb6, 0x77, 0x4f, 0xb3, - 0x0f, 0x39, 0x15, 0x72, 0x0f, 0x39, 0x25, 0x6f, 0x9e, 0x65, 0xdf, 0xef, 0x8c, 0x93, 0x03, 0x2d, - 0x91, 0xf0, 0xa3, 0x84, 0xb9, 0x89, 0x77, 0xa1, 0x74, 0x74, 0xea, 0x5c, 0xe4, 0x95, 0xeb, 0x3c, - 0x2b, 0x21, 0x02, 0xfd, 0x4f, 0x0a, 0x20, 0x72, 0x15, 0x61, 0x7d, 0xef, 0x37, 0xad, 0xcb, 0x17, - 0xd0, 0x54, 0x4f, 0x06, 0x13, 0x55, 0xe6, 0xb0, 0x4a, 0x76, 0xe9, 0x95, 0x20, 0x8d, 0xd1, 0x91, - 0x3e, 0x98, 0x26, 0x3e, 0x02, 0x7e, 0x9a, 0x93, 0x6e, 0x73, 0x95, 0x5e, 0xa1, 0x9b, 0x1b, 0x29, - 0x4d, 0xfa, 0x16, 0x67, 0xf6, 0x8d, 0x51, 0x3e, 0xe7, 0xda, 0x48, 0x47, 0x8d, 0xb8, 0x9f, 0xfe, - 0xd7, 0x0b, 0x70, 0x39, 0x3f, 0x21, 0xfe, 0x6c, 0xad, 0xcc, 0x3f, 0xa8, 0x5a, 0x9c, 0x7f, 0x50, - 0x75, 0xd9, 0x7c, 0x2a, 0x2d, 0x9d, 0x4f, 0x7f, 0xa5, 0x00, 0x5b, 0x99, 0xde, 0x4f, 0x35, 0xf4, - 0xbf, 0xa0, 0x9a, 0x65, 0xde, 0x55, 0x2d, 0xe5, 0xde, 0x55, 0xd5, 0xff, 0x7e, 0x01, 0xae, 0xce, - 0xd5, 0xc4, 0x70, 0xfe, 0x42, 0xeb, 0x92, 0x7f, 0x7f, 0x95, 0xce, 0xda, 0xd4, 0x4b, 0x0d, 0xc8, - 0x0b, 0x44, 0xfe, 0x41, 0x55, 0xf2, 0x02, 0x78, 0x5d, 0x3e, 0xe8, 0x63, 0x46, 0x17, 0xfe, 0x58, - 0x0e, 0x76, 0x85, 0x20, 0xc3, 0x0b, 0x7f, 0x8c, 0xdb, 0xf5, 0xc4, 0x09, 0x8f, 0x95, 0xf1, 0x94, - 0x13, 0xfa, 0xbf, 0x5d, 0x80, 0xeb, 0x73, 0x2d, 0x6b, 0xcd, 0xe2, 0x40, 0x3a, 0xed, 0xfc, 0x05, - 0x35, 0xee, 0x36, 0xd0, 0x5b, 0x63, 0xca, 0x5b, 0x28, 0x73, 0xcb, 0x47, 0x7e, 0x57, 0x83, 0xa2, - 0x6d, 0x5d, 0xc8, 0x40, 0xdf, 0xf8, 0x13, 0x97, 0xf1, 0x49, 0x30, 0x0b, 0xe5, 0xb5, 0x14, 0xfa, - 0xad, 0x7f, 0x0a, 0x9b, 0x69, 0xd5, 0xdb, 0xf2, 0x71, 0xdc, 0xdb, 0x50, 0xf5, 0x9d, 0x33, 0x53, - 0x3d, 0x9d, 0x2b, 0x2f, 0x2c, 0xfa, 0xce, 0x99, 0x24, 0xd0, 0x77, 0xb3, 0x1c, 0x92, 0xaa, 0x73, - 0x1d, 0xca, 0x81, 0x67, 0xe7, 0xdc, 0x94, 0x03, 0xcf, 0x56, 0x28, 0x2c, 0x2d, 0xd3, 0xca, 0x75, - 0xdf, 0x39, 0xa3, 0xd9, 0x79, 0x26, 0xcb, 0x69, 0xd9, 0xca, 0xb9, 0x6e, 0x99, 0xcf, 0xfb, 0x75, - 0x28, 0x4f, 0xc3, 0x5c, 0x37, 0xad, 0x4f, 0x43, 0xfe, 0xec, 0x5b, 0xf2, 0x3a, 0xe4, 0xab, 0x9c, - 0x33, 0xf9, 0x82, 0xa4, 0x06, 0xc5, 0x69, 0x10, 0x49, 0xef, 0x2f, 0xfc, 0xa9, 0x7f, 0x26, 0x99, - 0x23, 0x69, 0xe0, 0xfc, 0x65, 0x0d, 0x8a, 0xae, 0x7d, 0x4e, 0x1f, 0xae, 0x1b, 0xf8, 0x93, 0x24, - 0x6a, 0xe7, 0x5b, 0x79, 0x23, 0x13, 0x7f, 0xea, 0xdb, 0x50, 0x35, 0x72, 0xe6, 0x86, 0x5a, 0xc6, - 0x72, 0x17, 0xe5, 0x1f, 0x4e, 0x4a, 0x3b, 0xc8, 0xa8, 0xa6, 0x86, 0xbb, 0x48, 0x8f, 0x24, 0x3b, - 0x7c, 0x6e, 0x85, 0xe3, 0x13, 0x2b, 0xec, 0x39, 0xfe, 0x71, 0x7c, 0x82, 0x5d, 0x2e, 0x9f, 0x36, - 0xcf, 0x34, 0x1f, 0x18, 0xa4, 0xa6, 0x03, 0xf6, 0xa2, 0x47, 0xe4, 0xd2, 0x73, 0xa4, 0xe2, 0x3b, - 0x67, 0x32, 0xff, 0xeb, 0x00, 0xd8, 0xff, 0x12, 0x2d, 0xaf, 0x84, 0x05, 0x9e, 0xcd, 0x68, 0x7d, - 0x53, 0xb6, 0x57, 0x06, 0xaa, 0xdf, 0x71, 0x8e, 0x74, 0x4f, 0x8e, 0x3c, 0x37, 0x48, 0x76, 0xc2, - 0x6f, 0x34, 0x8c, 0xe2, 0x0d, 0xa8, 0x29, 0xdb, 0x10, 0xbd, 0xd5, 0xc5, 0x9f, 0xaf, 0x2a, 0x58, - 0x7f, 0x36, 0xd1, 0xff, 0x9d, 0x12, 0xd4, 0x5a, 0xec, 0xc8, 0x3c, 0xbd, 0x18, 0x4c, 0x63, 0xf1, - 0x7b, 0x70, 0x85, 0x9c, 0x78, 0x39, 0x40, 0x08, 0xf9, 0x0f, 0xb3, 0xff, 0x2b, 0x77, 0xe2, 0xbd, - 0x4c, 0x27, 0xca, 0x2c, 0xf7, 0x87, 0xa7, 0xee, 0x94, 0x63, 0x86, 0x74, 0xed, 0x73, 0x72, 0x87, - 0x65, 0x97, 0x1b, 0x7a, 0x4f, 0x22, 0x8f, 0xa0, 0x78, 0xe5, 0x58, 0xfc, 0xf4, 0x54, 0x16, 0x2b, - 0xbd, 0xb7, 0x10, 0xb8, 0x7f, 0xca, 0x34, 0xa9, 0xaf, 0xdb, 0xc2, 0xb6, 0x2c, 0x7d, 0xdd, 0xd2, - 0xf9, 0x3d, 0x84, 0x4d, 0xf9, 0xa6, 0x05, 0xbd, 0xa5, 0x69, 0x8e, 0x83, 0xe9, 0x85, 0x3c, 0xd1, - 0x7f, 0xf7, 0x15, 0x55, 0xed, 0x32, 0x29, 0x82, 0xb8, 0x9e, 0x1b, 0x51, 0x1e, 0x2a, 0x9e, 0x83, - 0xc0, 0x2e, 0x9d, 0x7a, 0x33, 0xdc, 0xcf, 0xd4, 0x2b, 0x9e, 0x7c, 0xbf, 0xe1, 0xee, 0x92, 0x52, - 0xfb, 0xce, 0xd9, 0x3e, 0xd1, 0xca, 0x42, 0xb8, 0x58, 0xcd, 0x9f, 0x03, 0xdf, 0xe8, 0xc0, 0xb5, - 0x57, 0xf4, 0xd5, 0xf7, 0x79, 0x23, 0x95, 0x33, 0xde, 0x48, 0x37, 0xb6, 0x61, 0x6b, 0x59, 0x3b, - 0x7e, 0x54, 0x19, 0x6d, 0xb8, 0xb2, 0xb4, 0xd6, 0x3f, 0xa6, 0x10, 0xfd, 0xaf, 0x34, 0x00, 0xd2, - 0xe5, 0x94, 0xd3, 0x25, 0x0a, 0x73, 0xba, 0xc4, 0x8f, 0x72, 0x1f, 0xfd, 0x14, 0x1a, 0x38, 0x8e, - 0x99, 0xc8, 0xc3, 0xcb, 0x43, 0x1e, 0xd7, 0x90, 0x6a, 0x94, 0x06, 0xa8, 0x5c, 0x74, 0x83, 0x2a, - 0x2d, 0x75, 0x83, 0xfa, 0x04, 0xd6, 0xf9, 0x3c, 0x56, 0x0d, 0xea, 0xb5, 0x79, 0xd6, 0x70, 0x5f, - 0x86, 0x85, 0x52, 0x74, 0xa2, 0x03, 0x8d, 0x24, 0x2a, 0x4c, 0x36, 0x42, 0xea, 0xad, 0xc5, 0x9c, - 0x8a, 0x8c, 0x9f, 0x07, 0xb5, 0xb2, 0xc9, 0x8c, 0xea, 0x11, 0x4f, 0xe4, 0x21, 0x01, 0xa9, 0x1e, - 0xeb, 0x59, 0xd5, 0x63, 0x34, 0xe1, 0xa3, 0x01, 0x54, 0x3d, 0x3e, 0x84, 0xcb, 0xd2, 0x25, 0x1d, - 0x33, 0x90, 0xb7, 0x01, 0xd2, 0xf3, 0xd5, 0x43, 0x4d, 0x3e, 0xa2, 0x30, 0x21, 0xc5, 0x1c, 0xc9, - 0xbf, 0x82, 0x2d, 0x7e, 0xe7, 0xc3, 0x8c, 0x0f, 0xe9, 0xc5, 0x9d, 0xae, 0x6d, 0x4e, 0xac, 0xa9, - 0xd4, 0x88, 0xde, 0x5d, 0xa8, 0x2c, 0x3f, 0xf3, 0x31, 0x3a, 0xf4, 0xe8, 0x32, 0x40, 0xe2, 0x2c, - 0xb7, 0x39, 0x9e, 0x87, 0xcf, 0xf9, 0xac, 0xc0, 0x82, 0xcf, 0xca, 0xbc, 0x8e, 0x54, 0x5d, 0xa2, - 0x23, 0xa5, 0x9a, 0x4e, 0x2d, 0xa7, 0xe9, 0x7c, 0x00, 0xeb, 0x32, 0xd2, 0xa6, 0x3c, 0x1e, 0x10, - 0x8b, 0x8b, 0xcc, 0x50, 0x24, 0xf8, 0x25, 0xe5, 0x41, 0x45, 0x81, 0xda, 0x1b, 0xfc, 0xa5, 0x2c, - 0x4c, 0x6c, 0x4b, 0xdb, 0x78, 0x72, 0x71, 0x41, 0x1e, 0x05, 0xdc, 0xc8, 0x14, 0x9c, 0xe0, 0xa4, - 0xf1, 0x66, 0x2e, 0xc7, 0x8d, 0x3f, 0x58, 0x87, 0x35, 0xe9, 0x07, 0x73, 0x0f, 0x4a, 0x76, 0x28, - 0x2f, 0x59, 0x25, 0x4a, 0x5d, 0x5e, 0xae, 0x7c, 0x72, 0xc9, 0x20, 0x1a, 0x71, 0x1f, 0xd6, 0x2c, - 0x1b, 0xf5, 0xb5, 0xbc, 0xdb, 0xc2, 0x9c, 0xcc, 0xff, 0xe4, 0x92, 0xb1, 0x6a, 0x91, 0xf0, 0xff, - 0x05, 0x54, 0x90, 0x3e, 0x1b, 0x32, 0xbb, 0xb9, 0x24, 0x8b, 0x3a, 0x9a, 0x29, 0x5b, 0x4a, 0x52, - 0xff, 0xed, 0xfc, 0x01, 0x50, 0x69, 0xa1, 0x81, 0x73, 0xa2, 0xe5, 0xdc, 0x51, 0xd0, 0xef, 0x00, - 0x9f, 0x08, 0x24, 0xe2, 0xc4, 0x6a, 0xf6, 0x84, 0x7c, 0x41, 0xf8, 0x78, 0x72, 0xc9, 0xe0, 0x4d, - 0x55, 0x09, 0x23, 0x9f, 0xa9, 0xc3, 0x19, 0x62, 0xcf, 0x6b, 0xcb, 0x7b, 0x06, 0x79, 0x74, 0x72, - 0x42, 0x43, 0x0c, 0x1b, 0xb3, 0xd9, 0x89, 0x5f, 0xf0, 0xfa, 0x42, 0xb6, 0x44, 0xe4, 0xa0, 0x6c, - 0x89, 0xfc, 0xf1, 0x08, 0xaa, 0x6c, 0xab, 0xe7, 0x7c, 0xe5, 0x85, 0xae, 0x4d, 0x25, 0x06, 0x3a, - 0xfd, 0x4d, 0xe5, 0x87, 0xb6, 0x6a, 0x67, 0xe8, 0x64, 0x0f, 0xd8, 0x6e, 0x2e, 0xed, 0x28, 0x23, - 0x39, 0x6b, 0xe3, 0xc6, 0x1a, 0x9c, 0x47, 0xf4, 0x60, 0x4b, 0x9e, 0x44, 0xb1, 0x74, 0xa0, 0x36, - 0x74, 0x58, 0x18, 0xaf, 0x9c, 0xf8, 0xf0, 0xe4, 0x92, 0x21, 0xac, 0x45, 0xa1, 0xa2, 0x0d, 0x9b, - 0xaa, 0x4a, 0xb4, 0xed, 0x67, 0x5c, 0x25, 0xb3, 0x4d, 0x4a, 0x85, 0x82, 0x27, 0x97, 0x8c, 0x0d, - 0x2b, 0x0f, 0x12, 0x5d, 0xb8, 0xac, 0x0a, 0x21, 0xf5, 0x3e, 0x73, 0xcf, 0x22, 0x3f, 0x8a, 0x59, - 0x41, 0xe2, 0xc9, 0x25, 0x63, 0xd3, 0x5a, 0x90, 0x2e, 0xf6, 0x54, 0x7d, 0xb2, 0x92, 0x2b, 0xaf, - 0xc4, 0xdb, 0x4b, 0xbb, 0x29, 0x15, 0xa3, 0x93, 0x9a, 0x65, 0x24, 0xeb, 0x5f, 0xa8, 0xce, 0xca, - 0x7b, 0x85, 0xcb, 0x03, 0xbc, 0xd7, 0x17, 0x4a, 0xcc, 0x3a, 0x85, 0x27, 0x3d, 0x96, 0x83, 0xa6, - 0x1e, 0x34, 0x37, 0x0c, 0xb8, 0xba, 0x9c, 0x69, 0x65, 0x77, 0xae, 0x12, 0xef, 0x5c, 0x7a, 0x76, - 0xe7, 0x9a, 0x7f, 0xcb, 0x21, 0xb3, 0x8f, 0xfd, 0x1c, 0xea, 0x39, 0xae, 0x2d, 0xaa, 0xb0, 0xae, - 0xde, 0xc1, 0xa7, 0x60, 0x36, 0xed, 0xc1, 0xfe, 0xd7, 0x5a, 0x01, 0xc1, 0xdd, 0xfe, 0x70, 0xd4, - 0xea, 0x8f, 0xb4, 0x15, 0x4e, 0xec, 0xf7, 0x5a, 0xed, 0x8e, 0x56, 0xd4, 0xff, 0x6e, 0x11, 0x2a, - 0xc9, 0xf9, 0xee, 0x6f, 0x6e, 0x1d, 0x5d, 0x1e, 0x67, 0x61, 0x4e, 0xe1, 0xe5, 0x6b, 0x26, 0x25, - 0x15, 0xb6, 0x3d, 0xab, 0x56, 0x46, 0x8b, 0x61, 0x7c, 0x57, 0x7f, 0x60, 0x18, 0xdf, 0xec, 0x05, - 0xc3, 0xb5, 0xfc, 0x05, 0xc3, 0xdb, 0xa0, 0xc2, 0x57, 0xe0, 0xae, 0x42, 0x26, 0xb9, 0x12, 0x3d, - 0xa7, 0x8a, 0xa0, 0xd1, 0xa1, 0x87, 0x7c, 0xdd, 0x8d, 0x9e, 0xbb, 0xce, 0x99, 0xbc, 0xf2, 0x20, - 0x53, 0xf9, 0x4d, 0x1f, 0xbe, 0x67, 0xd3, 0xff, 0x21, 0x1b, 0xc8, 0x03, 0xd8, 0x3a, 0x3a, 0x4d, - 0xde, 0x39, 0x4f, 0x8d, 0x6d, 0x35, 0xaa, 0xd2, 0x52, 0x9c, 0x78, 0x17, 0xd6, 0x62, 0x75, 0xf4, - 0x5c, 0x5c, 0x72, 0x1a, 0x6f, 0x48, 0xb4, 0xfe, 0x07, 0x05, 0x80, 0xf4, 0xe4, 0xf3, 0xcf, 0x7c, - 0x84, 0x90, 0xb1, 0x9e, 0x16, 0xbf, 0xc3, 0x7a, 0xfa, 0x7d, 0xaf, 0x58, 0x7d, 0x0b, 0x95, 0xe4, - 0xac, 0xfb, 0x37, 0x9f, 0x58, 0x3f, 0xea, 0x93, 0xff, 0x7f, 0x75, 0x9c, 0x92, 0x1c, 0x16, 0xff, - 0x59, 0xfb, 0x22, 0xf7, 0xf9, 0xe2, 0xf7, 0x7c, 0xfe, 0x9c, 0xcf, 0x1a, 0x92, 0x8f, 0xff, 0x39, - 0xaf, 0xa6, 0xec, 0x44, 0x2f, 0xe5, 0x26, 0xba, 0x3e, 0x93, 0x87, 0x2c, 0x7f, 0xf6, 0x4f, 0xff, - 0xa8, 0x06, 0xff, 0xaf, 0x05, 0x65, 0xd5, 0x4f, 0x9e, 0xa6, 0x7f, 0xa5, 0x1c, 0xbd, 0xfc, 0x60, - 0xe2, 0xc7, 0x7c, 0xee, 0x3b, 0x2d, 0x75, 0xa5, 0xef, 0xb2, 0xd4, 0xbd, 0xab, 0x1e, 0xf6, 0x58, - 0x7d, 0x95, 0x95, 0x4e, 0xbe, 0xed, 0x71, 0x1b, 0xaa, 0x59, 0xdb, 0x1c, 0x1b, 0x65, 0xd8, 0xa8, - 0xc2, 0x66, 0x39, 0x5d, 0xea, 0x0d, 0xdc, 0xde, 0x2d, 0x55, 0xae, 0x0c, 0x38, 0x45, 0x09, 0xfd, - 0x2f, 0x31, 0x47, 0xfd, 0x4d, 0xbb, 0xe4, 0xbb, 0xcd, 0x34, 0xfa, 0xff, 0x53, 0x80, 0x7a, 0xce, - 0x77, 0xe5, 0x37, 0xf8, 0xc4, 0x52, 0xbe, 0x5c, 0xfc, 0xff, 0x10, 0x5f, 0xce, 0xdd, 0x04, 0x28, - 0xe7, 0x6f, 0x02, 0x20, 0xbb, 0xab, 0xe5, 0xb4, 0xa2, 0x65, 0xfa, 0x53, 0x61, 0xa9, 0xfe, 0x74, - 0x0b, 0xc0, 0x1a, 0xd3, 0x15, 0xc5, 0xee, 0x0e, 0x3b, 0xde, 0xd7, 0x8d, 0x0c, 0x44, 0x7c, 0x09, - 0xd7, 0xa5, 0xd1, 0x84, 0xfb, 0x27, 0x38, 0x32, 0x15, 0xd6, 0x96, 0x46, 0x88, 0xab, 0x4c, 0x40, - 0xa3, 0x3b, 0x38, 0x6a, 0x29, 0xac, 0xde, 0x85, 0x7a, 0xce, 0x29, 0x08, 0xf7, 0x96, 0x63, 0x2f, - 0x38, 0xb4, 0x3c, 0x59, 0x17, 0x99, 0x12, 0x77, 0x60, 0xf5, 0xec, 0xc4, 0x09, 0x9d, 0x25, 0xef, - 0x2f, 0x33, 0x42, 0xff, 0x29, 0xd4, 0xb2, 0x0e, 0x8a, 0xe2, 0x03, 0x58, 0x75, 0x63, 0x67, 0xa2, - 0xcc, 0x41, 0x57, 0x17, 0x7d, 0x18, 0xbb, 0xb1, 0x33, 0x31, 0x98, 0x48, 0xff, 0xc3, 0x02, 0x68, - 0xf3, 0x38, 0x8a, 0x99, 0x74, 0x11, 0xc5, 0xce, 0x44, 0x55, 0x86, 0x53, 0x99, 0x4a, 0xae, 0xe4, - 0x2a, 0xa9, 0xac, 0x66, 0xc5, 0x8c, 0xd5, 0xec, 0x8e, 0x12, 0x4a, 0x16, 0xef, 0x9e, 0x31, 0x42, - 0xbc, 0x03, 0xe5, 0xd0, 0xa1, 0x68, 0x4c, 0xcb, 0x5e, 0xb5, 0x49, 0x70, 0xfa, 0xef, 0x17, 0x60, - 0x5d, 0x7a, 0x53, 0x2e, 0xb5, 0xcf, 0xbd, 0x07, 0xeb, 0xd1, 0xf8, 0xc4, 0x99, 0x58, 0xea, 0x31, - 0xab, 0x85, 0x23, 0x23, 0x85, 0x17, 0xb7, 0xd8, 0xc7, 0x34, 0x6f, 0xaf, 0xdb, 0xf7, 0x2c, 0xdf, - 0x20, 0x38, 0x4e, 0x35, 0xb6, 0xd3, 0xf2, 0x1d, 0x32, 0x7e, 0x69, 0x04, 0x08, 0x44, 0xb7, 0xc4, - 0xf4, 0xdf, 0x86, 0x75, 0xe9, 0xad, 0xb9, 0xb4, 0x2a, 0xb7, 0xa0, 0x64, 0x85, 0xc7, 0xd1, 0x92, - 0xc1, 0x22, 0xb8, 0x7e, 0x07, 0x20, 0x75, 0xdf, 0x5c, 0x56, 0x82, 0x7e, 0x0f, 0xca, 0xca, 0x63, - 0x13, 0xe7, 0x5f, 0xfa, 0x69, 0x79, 0x6f, 0x3c, 0x5b, 0x19, 0x0f, 0xea, 0x34, 0x51, 0x7b, 0xc1, - 0xf8, 0x94, 0x8e, 0x0c, 0x3e, 0x02, 0xba, 0x7e, 0x3f, 0x5a, 0x78, 0x92, 0x25, 0x21, 0xe3, 0x5b, - 0x25, 0x8a, 0x48, 0xdc, 0x83, 0x84, 0x5f, 0x7e, 0x9f, 0xb5, 0x42, 0x6f, 0xa9, 0x40, 0x0d, 0x34, - 0xcb, 0x1e, 0x4a, 0xeb, 0x71, 0x8f, 0x9e, 0x0b, 0x2c, 0x64, 0xfd, 0xfa, 0x73, 0x75, 0x32, 0x32, - 0x64, 0x7a, 0x03, 0x6a, 0x59, 0x37, 0x33, 0xbd, 0x05, 0x9b, 0xea, 0xe6, 0x80, 0x7a, 0xa8, 0x82, - 0xe7, 0x2f, 0xfe, 0xc8, 0xcf, 0xdf, 0x79, 0x3a, 0x83, 0x89, 0xf4, 0xbf, 0x5b, 0x02, 0x6d, 0x1e, - 0xf7, 0x5d, 0x41, 0x2b, 0x6e, 0x43, 0x95, 0xdf, 0x99, 0xca, 0x5a, 0x12, 0x81, 0x41, 0x99, 0x6b, - 0x45, 0xfc, 0x06, 0x93, 0x7a, 0x1e, 0xdc, 0x8d, 0xf8, 0x8d, 0x26, 0x71, 0x8d, 0x23, 0x14, 0x78, - 0xc1, 0x98, 0xa6, 0x75, 0x8d, 0x02, 0x12, 0xf4, 0x82, 0x31, 0xc5, 0xc2, 0x90, 0x06, 0x0f, 0x76, - 0x76, 0xa8, 0x19, 0x65, 0x69, 0xe5, 0xa0, 0xf3, 0x5c, 0x79, 0xd9, 0x28, 0x8e, 0x64, 0xc0, 0xba, - 0x32, 0x03, 0x46, 0x91, 0x7a, 0x39, 0x7f, 0xec, 0xc7, 0x32, 0x14, 0xd3, 0x5a, 0x18, 0x9c, 0xb5, - 0x7d, 0x0a, 0x85, 0x41, 0xef, 0xd6, 0x22, 0x46, 0x86, 0xb6, 0xc2, 0x34, 0xa2, 0x28, 0xfe, 0x11, - 0x47, 0x23, 0xe6, 0x57, 0xe3, 0x2a, 0xf2, 0xb9, 0x40, 0x09, 0x4c, 0x1e, 0xe5, 0xe4, 0xfd, 0x2f, - 0x13, 0xe4, 0x0a, 0x18, 0x44, 0x04, 0xd7, 0xa1, 0xfc, 0xab, 0xc0, 0x77, 0xc8, 0x70, 0x52, 0xa5, - 0x5a, 0xad, 0x63, 0x7a, 0xcf, 0x9a, 0xe2, 0x46, 0xe0, 0x51, 0x6c, 0x44, 0xbe, 0x4e, 0xcb, 0x09, - 0xfd, 0xbf, 0x2e, 0xc0, 0xd6, 0x7c, 0x5f, 0xd3, 0x34, 0xaa, 0x41, 0xb9, 0x3d, 0xe8, 0x99, 0xfd, - 0xd6, 0x5e, 0x47, 0xbb, 0x24, 0x36, 0xa0, 0x3a, 0xd8, 0x7e, 0xda, 0x69, 0x8f, 0x18, 0x50, 0xa0, - 0x08, 0xaf, 0x43, 0xf3, 0x49, 0x77, 0x67, 0xa7, 0xd3, 0x67, 0x8d, 0x62, 0xb0, 0xfd, 0xd4, 0xec, - 0x0d, 0xda, 0x5a, 0x11, 0x71, 0xca, 0x01, 0x67, 0xa8, 0x95, 0xc8, 0x3d, 0x87, 0xae, 0x61, 0x60, - 0x72, 0x95, 0xef, 0x17, 0xbc, 0x18, 0x9a, 0xed, 0xfe, 0x48, 0x5b, 0xc3, 0x54, 0xff, 0xa0, 0xd7, - 0xa3, 0x14, 0x39, 0x12, 0xb7, 0x07, 0x7b, 0xfb, 0x46, 0x67, 0x38, 0x34, 0x87, 0xdd, 0x5f, 0x76, - 0xb4, 0x32, 0x7d, 0xd9, 0xe8, 0x3e, 0xee, 0xf6, 0x19, 0x50, 0x11, 0xeb, 0x50, 0xdc, 0xeb, 0xf6, - 0x39, 0xb2, 0xed, 0x5e, 0xeb, 0x2b, 0xad, 0x8a, 0x3f, 0x86, 0x07, 0x7b, 0x5a, 0x4d, 0x54, 0x60, - 0xb5, 0xd7, 0x79, 0xde, 0xe9, 0x69, 0x75, 0xfd, 0x7f, 0x2c, 0x2a, 0x89, 0x98, 0x3c, 0xec, 0x7e, - 0x88, 0x14, 0xb8, 0xec, 0x94, 0x35, 0xe9, 0xb4, 0x62, 0xa6, 0xd3, 0xe8, 0xf9, 0x26, 0x66, 0xfb, - 0xd9, 0x73, 0xb2, 0xaa, 0x84, 0xd1, 0x94, 0x7b, 0x13, 0xea, 0xc9, 0x19, 0x74, 0xe6, 0xb5, 0xfb, - 0x9a, 0x02, 0x2e, 0x39, 0xae, 0x59, 0x5b, 0x72, 0x5c, 0x33, 0x75, 0x63, 0x54, 0xdc, 0x91, 0xe7, - 0xf2, 0x4c, 0xaa, 0x20, 0xe4, 0x39, 0xf1, 0xda, 0xd7, 0x80, 0x12, 0xe6, 0xcc, 0x97, 0xaf, 0x74, - 0x55, 0x8c, 0x32, 0x02, 0x0e, 0x7c, 0x0e, 0x68, 0x91, 0x75, 0x56, 0xa9, 0x2c, 0x38, 0xab, 0x64, - 0x37, 0x67, 0xc8, 0x6f, 0xce, 0xaf, 0x27, 0x7b, 0x24, 0x22, 0xab, 0x74, 0x56, 0x51, 0x49, 0x76, - 0x41, 0xf1, 0x01, 0x88, 0xf1, 0x2c, 0xa4, 0x47, 0x72, 0x32, 0x64, 0x35, 0x22, 0xd3, 0x24, 0x26, - 0xd9, 0x15, 0x29, 0x3c, 0x50, 0x9e, 0x9a, 0xd4, 0xf3, 0x8a, 0xd1, 0xc8, 0x93, 0x8a, 0xfb, 0x70, - 0x59, 0xce, 0xed, 0x5c, 0xdf, 0xca, 0xc8, 0x22, 0x8c, 0x6a, 0xa5, 0x3d, 0xac, 0xff, 0x16, 0x94, - 0x95, 0x33, 0xe5, 0x77, 0x0b, 0xbb, 0x4b, 0xc6, 0x55, 0xff, 0x5b, 0x2b, 0x50, 0x49, 0x5c, 0x2b, - 0x7f, 0xd0, 0xec, 0x78, 0x0d, 0xe5, 0xd4, 0xe8, 0x34, 0xcb, 0x62, 0xca, 0x08, 0x50, 0x23, 0x25, - 0x2f, 0x7d, 0xce, 0x42, 0x57, 0x49, 0x6c, 0x0c, 0x39, 0x08, 0x5d, 0x8a, 0x84, 0xef, 0xfa, 0x99, - 0x48, 0x1e, 0x15, 0xa3, 0x8c, 0x00, 0x5a, 0x68, 0xd7, 0x81, 0x7e, 0x53, 0x4e, 0x9e, 0x24, 0xeb, - 0x98, 0xc6, 0x7c, 0x57, 0x13, 0xfd, 0x4f, 0xc6, 0xcf, 0x8b, 0x13, 0xc1, 0x42, 0x7a, 0x75, 0xb1, - 0x8f, 0x89, 0x4c, 0xe1, 0x77, 0x28, 0xea, 0x14, 0xd5, 0x51, 0xce, 0x08, 0x04, 0xa8, 0x3a, 0x66, - 0x86, 0xab, 0x32, 0x3f, 0xaa, 0xf3, 0x73, 0x1a, 0x16, 0xe6, 0xb4, 0x1e, 0xc3, 0xba, 0x74, 0x2f, - 0xfd, 0xee, 0x0e, 0xff, 0xce, 0xae, 0xd2, 0xa0, 0x68, 0x79, 0x2a, 0xac, 0x02, 0xfe, 0x9c, 0xab, - 0x58, 0x69, 0xae, 0x62, 0xfa, 0xbf, 0xba, 0x02, 0x90, 0xba, 0xa9, 0x8a, 0x0f, 0xe7, 0x5c, 0xe2, - 0x0b, 0x0b, 0xdb, 0xfe, 0x9c, 0x27, 0xfc, 0xdc, 0xd3, 0x10, 0x2b, 0x3f, 0xe0, 0x69, 0x88, 0x07, - 0x50, 0x8f, 0xc2, 0xf1, 0xf7, 0xda, 0xf0, 0xab, 0x51, 0x38, 0x4e, 0x4c, 0xf8, 0x1f, 0x01, 0x26, - 0xe9, 0xd9, 0xa8, 0x54, 0x51, 0x5d, 0x90, 0x5a, 0x2a, 0x51, 0x38, 0x1e, 0x1c, 0x7e, 0xb3, 0xc3, - 0x37, 0x6d, 0xed, 0x28, 0x36, 0x97, 0x71, 0x89, 0x0d, 0x3b, 0x8a, 0x77, 0xb2, 0x8c, 0xe2, 0x2d, - 0x68, 0x20, 0xed, 0x02, 0xb3, 0xa8, 0xd9, 0x51, 0x7a, 0xa0, 0xa4, 0xff, 0x53, 0xea, 0x60, 0x7e, - 0xce, 0x3c, 0x2c, 0x3e, 0x97, 0x8a, 0x78, 0x46, 0x88, 0x68, 0x2e, 0xb3, 0x26, 0xf3, 0x65, 0xfc, - 0x84, 0x54, 0x3c, 0x82, 0x7a, 0x82, 0xdb, 0x71, 0x8e, 0x94, 0x0c, 0xa4, 0xde, 0x20, 0xca, 0xa0, - 0x8c, 0x3c, 0xa1, 0xfe, 0x08, 0x20, 0x7d, 0xb8, 0x0b, 0x57, 0x60, 0x72, 0x4d, 0xac, 0xc2, 0x17, - 0xc0, 0x70, 0x0e, 0xfb, 0x74, 0xb7, 0x5f, 0x3e, 0x4d, 0x2d, 0x53, 0xfa, 0x23, 0xb8, 0xf6, 0x0a, - 0xfb, 0x9a, 0x3a, 0xaf, 0x94, 0x81, 0x37, 0x64, 0x04, 0x41, 0xdf, 0x39, 0xe3, 0xc0, 0x1b, 0xba, - 0x0f, 0x97, 0x97, 0x3c, 0xae, 0x2f, 0xee, 0x90, 0x53, 0x1b, 0x9d, 0x06, 0x26, 0xb7, 0xf1, 0x57, - 0xe9, 0x1c, 0xb4, 0x6b, 0xf3, 0xf3, 0x21, 0x9f, 0xc1, 0x86, 0xe3, 0xb9, 0xc7, 0xee, 0xa1, 0x4b, - 0x91, 0xfa, 0xc7, 0x81, 0xb7, 0x60, 0x75, 0xa3, 0x87, 0xce, 0x33, 0x44, 0xed, 0xc0, 0xd3, 0xff, - 0xd9, 0x82, 0x7c, 0x29, 0x33, 0xff, 0xcc, 0x1f, 0xbf, 0x94, 0x29, 0x9f, 0xe4, 0x2e, 0x18, 0xf4, - 0x1b, 0x5b, 0x2b, 0x5f, 0x61, 0x96, 0xcf, 0xe4, 0x71, 0x4a, 0x7c, 0x04, 0x5b, 0x32, 0xda, 0x3d, - 0x85, 0xc6, 0x33, 0xa7, 0x4e, 0x68, 0x86, 0xc1, 0x19, 0x4d, 0xb8, 0x82, 0xb1, 0xc9, 0x38, 0x8a, - 0x90, 0xb7, 0xef, 0x84, 0x46, 0x70, 0x26, 0x9a, 0x24, 0xad, 0x38, 0xe3, 0x58, 0x9d, 0x3d, 0xab, - 0xa4, 0xfe, 0xbb, 0x70, 0x79, 0xc9, 0x3d, 0x50, 0xf1, 0xb6, 0xd2, 0xff, 0x5e, 0x71, 0xeb, 0x7b, - 0xa9, 0xce, 0xb9, 0x32, 0xaf, 0x73, 0xf6, 0xa1, 0x9e, 0xbb, 0xda, 0x99, 0x8f, 0xb8, 0x5f, 0xfa, - 0xee, 0x88, 0xfb, 0xf4, 0x80, 0xf9, 0xca, 0xd3, 0x52, 0x79, 0x45, 0x2b, 0x3e, 0x2d, 0x95, 0x8b, - 0x5a, 0x49, 0xff, 0x1b, 0x05, 0x28, 0x2b, 0xc2, 0xc5, 0xbd, 0xb2, 0xb0, 0x64, 0xaf, 0x7c, 0x4d, - 0x7e, 0x30, 0xcb, 0x54, 0x10, 0x40, 0xc8, 0x7b, 0x50, 0x4e, 0x16, 0x78, 0x71, 0xe9, 0x02, 0x4f, - 0xf0, 0xe2, 0x7d, 0xd8, 0xcc, 0xf9, 0xc7, 0x66, 0x76, 0x70, 0x2d, 0x8b, 0xa0, 0x76, 0xff, 0x49, - 0x01, 0xb4, 0x79, 0x67, 0xb1, 0xf9, 0xbd, 0xb5, 0xb0, 0xb0, 0xb7, 0xa2, 0x2c, 0x77, 0x62, 0x85, - 0xd6, 0x98, 0xaf, 0x38, 0xc4, 0xb2, 0xbe, 0xb5, 0x04, 0x38, 0x74, 0x28, 0x08, 0xea, 0x38, 0xf0, - 0xe4, 0x55, 0x58, 0xb9, 0x65, 0x24, 0x00, 0x72, 0x7a, 0x91, 0x6e, 0x66, 0xd2, 0xd2, 0x23, 0x93, - 0x14, 0xc2, 0x41, 0x91, 0xe1, 0xe7, 0x57, 0x89, 0x61, 0x56, 0x13, 0x98, 0x0a, 0x93, 0xa9, 0x48, - 0x42, 0xe7, 0xa5, 0x1b, 0xa9, 0x07, 0x43, 0xeb, 0xc6, 0x66, 0x82, 0x31, 0x24, 0xe2, 0xde, 0xbf, - 0x50, 0x80, 0xcd, 0x61, 0x1c, 0xba, 0xfe, 0x71, 0xcf, 0x8d, 0x9d, 0xd0, 0xf2, 0x76, 0x83, 0x70, - 0x42, 0xfe, 0xf0, 0x23, 0xa3, 0xdb, 0x7f, 0x6c, 0xf6, 0xba, 0xa3, 0x8e, 0xd1, 0x4a, 0x42, 0x99, - 0x2f, 0x22, 0x46, 0x9d, 0xaf, 0x46, 0x5a, 0x41, 0xbc, 0x05, 0x77, 0xe6, 0x10, 0xdb, 0xdd, 0x7e, - 0xcb, 0xf8, 0xda, 0xec, 0xf6, 0x47, 0xc6, 0x60, 0xe7, 0xa0, 0xdd, 0x31, 0xb4, 0x15, 0x71, 0x15, - 0xc4, 0x1c, 0xd5, 0x93, 0xce, 0x57, 0x5a, 0x71, 0x09, 0x7c, 0xbb, 0x3b, 0xd2, 0x4a, 0xf7, 0xf6, - 0xe0, 0x72, 0xeb, 0xf8, 0x38, 0x74, 0x8e, 0x71, 0xb3, 0xa6, 0x50, 0xb9, 0xea, 0x52, 0x42, 0xeb, - 0xf1, 0x63, 0xb3, 0x3d, 0xe8, 0xef, 0x76, 0x1f, 0xab, 0xaa, 0xbd, 0x01, 0xaf, 0x67, 0x80, 0x8f, - 0x8d, 0xc1, 0xc1, 0x3e, 0x26, 0xda, 0xad, 0x91, 0x39, 0x30, 0x76, 0x3a, 0x86, 0x56, 0xb8, 0xf7, - 0x06, 0xd4, 0xd4, 0xab, 0x1f, 0x49, 0xe4, 0xf7, 0xc0, 0x77, 0xb4, 0x4b, 0x28, 0x46, 0xf6, 0x7e, - 0xf5, 0xa9, 0x56, 0xb8, 0x17, 0x82, 0xc6, 0x51, 0x14, 0xf9, 0x8c, 0x81, 0x62, 0x46, 0xde, 0x82, - 0x1b, 0x46, 0x67, 0x78, 0xd0, 0x1b, 0x49, 0x5f, 0x7e, 0xf3, 0x59, 0xb7, 0xbf, 0x63, 0xa6, 0x77, - 0x90, 0x5f, 0x87, 0xeb, 0x4b, 0xf0, 0xc3, 0xd1, 0xc0, 0xe8, 0xec, 0x68, 0x05, 0x71, 0x1b, 0x5e, - 0x5b, 0x82, 0x46, 0x59, 0xf7, 0x60, 0xd4, 0xd9, 0xd1, 0x56, 0xee, 0xe9, 0x50, 0x1d, 0x9e, 0xcc, - 0x8e, 0x8e, 0x3c, 0x47, 0xd5, 0xea, 0x89, 0x15, 0x9d, 0xb0, 0xab, 0x1e, 0xbd, 0x96, 0xaa, 0x15, - 0xee, 0xbd, 0x03, 0x75, 0x49, 0xb3, 0xe7, 0xc4, 0x27, 0x81, 0x2d, 0x00, 0xd6, 0xfa, 0x41, 0x38, - 0xb1, 0x3c, 0x49, 0xe7, 0xcc, 0x22, 0xa4, 0xfb, 0x08, 0xae, 0x64, 0xca, 0xda, 0x0d, 0x42, 0x0a, - 0xf6, 0xd5, 0xee, 0xd3, 0x45, 0x69, 0x77, 0x32, 0xf5, 0x1c, 0xbe, 0xf2, 0xfb, 0xe4, 0xe2, 0x30, - 0x74, 0x6d, 0xad, 0x70, 0xef, 0x11, 0x54, 0xd2, 0x27, 0x99, 0xe9, 0x59, 0x87, 0xed, 0xc1, 0x41, - 0x7f, 0x87, 0x02, 0xc1, 0xd3, 0x53, 0x0e, 0xed, 0xde, 0xc1, 0xb0, 0xfb, 0x5c, 0xca, 0xfd, 0x9d, - 0xaf, 0x54, 0x72, 0xe5, 0xde, 0xef, 0x17, 0x54, 0x64, 0x41, 0x55, 0xed, 0xde, 0xa0, 0xb5, 0xc3, - 0x0a, 0x43, 0xf2, 0x62, 0xc5, 0x68, 0x5b, 0x2b, 0x20, 0x40, 0xf6, 0x80, 0x7c, 0x0c, 0xa3, 0x01, - 0xd0, 0x6d, 0x77, 0xb6, 0x3b, 0xc6, 0x63, 0x24, 0x28, 0x62, 0x7a, 0x6f, 0xd0, 0x7f, 0x3c, 0xd8, - 0xd9, 0xc6, 0x34, 0x3d, 0x83, 0xb1, 0xd3, 0x1a, 0xb5, 0x86, 0x23, 0xa3, 0xd3, 0xda, 0x43, 0x10, - 0xdd, 0x45, 0x54, 0x1e, 0x89, 0xa3, 0x6d, 0x56, 0x1e, 0x9e, 0xb5, 0x76, 0x9f, 0xb5, 0x30, 0xb5, - 0x7e, 0xef, 0xbf, 0x5a, 0x01, 0x6d, 0x3e, 0x7a, 0xa4, 0x78, 0x0d, 0xae, 0x51, 0xa9, 0xe6, 0xbe, - 0xd1, 0xd9, 0xe9, 0xb6, 0xf9, 0x56, 0xc9, 0xf3, 0x56, 0xaf, 0xbb, 0xc3, 0x33, 0x79, 0x1e, 0xd9, - 0xea, 0xef, 0x70, 0x84, 0xfb, 0x79, 0x44, 0xe7, 0x17, 0x07, 0xad, 0x9e, 0xb6, 0x82, 0x03, 0x3d, - 0x8f, 0xea, 0x0f, 0x46, 0x12, 0x5d, 0x14, 0x4d, 0xd8, 0x9a, 0x47, 0xf7, 0x3a, 0x43, 0x54, 0x83, - 0x6e, 0xc1, 0x8d, 0x65, 0x18, 0x99, 0x73, 0x75, 0x59, 0x4d, 0x1f, 0x93, 0x16, 0x65, 0x68, 0x6b, - 0x38, 0xb1, 0x5f, 0x81, 0x94, 0xf9, 0xd7, 0x71, 0xfd, 0x2c, 0xb6, 0x54, 0x2b, 0x2f, 0xed, 0x81, - 0xa1, 0x49, 0xef, 0x19, 0x54, 0x70, 0x5e, 0x2e, 0x43, 0x0e, 0x46, 0x4c, 0x00, 0xf7, 0xfe, 0x5e, - 0x01, 0x9a, 0xaf, 0x0a, 0xf2, 0x23, 0x74, 0xb8, 0x65, 0x1c, 0xf4, 0xe9, 0x31, 0x0b, 0x7e, 0x77, - 0xc3, 0x7c, 0xd6, 0xf9, 0x7a, 0xee, 0x21, 0x01, 0x5c, 0x18, 0x8b, 0x34, 0x46, 0xeb, 0x85, 0xf9, - 0xfc, 0x13, 0xad, 0x20, 0xde, 0x87, 0x77, 0x97, 0xa0, 0x77, 0x7b, 0x83, 0xd6, 0xc8, 0xfc, 0x65, - 0xc7, 0x18, 0x98, 0xed, 0xde, 0x60, 0xd8, 0xd9, 0x41, 0xe2, 0x15, 0x71, 0x07, 0x6e, 0x2e, 0x21, - 0x1e, 0xf2, 0x53, 0x29, 0xcf, 0x3f, 0xd1, 0x8a, 0xe2, 0x6d, 0x78, 0xe3, 0xd5, 0x14, 0xbb, 0xa8, - 0x68, 0x3e, 0xff, 0x44, 0x2b, 0xdd, 0xfb, 0x39, 0x34, 0x5f, 0x75, 0x65, 0x1b, 0x17, 0x52, 0xfb, - 0x49, 0x8b, 0xae, 0xc5, 0xa3, 0x72, 0x3a, 0x30, 0x39, 0x45, 0x47, 0x68, 0x46, 0xa7, 0xd7, 0xa1, - 0x7b, 0x4d, 0xf7, 0x7e, 0x5d, 0xc8, 0x18, 0x6a, 0xd4, 0xb5, 0xdb, 0x04, 0x20, 0x39, 0x4a, 0x16, - 0x64, 0x38, 0x96, 0xad, 0x15, 0x70, 0x94, 0x72, 0xa0, 0x5e, 0x30, 0xb6, 0x3c, 0x6d, 0x85, 0x6e, - 0x30, 0x29, 0x38, 0xc5, 0xda, 0xd0, 0x8a, 0xd8, 0x75, 0x09, 0xac, 0x17, 0x9c, 0xed, 0x87, 0x6e, - 0x10, 0xba, 0xf1, 0x05, 0xa3, 0x4b, 0xf7, 0xfe, 0x31, 0xe9, 0xf5, 0x95, 0x13, 0xdf, 0xf0, 0x03, - 0x2d, 0xdb, 0x4e, 0x61, 0xa4, 0x31, 0xf0, 0x5c, 0x27, 0x75, 0x69, 0x0e, 0x51, 0xc0, 0xf9, 0xa1, - 0xac, 0xc9, 0xf3, 0xc8, 0x15, 0x44, 0x1a, 0x0e, 0xdd, 0x7d, 0x59, 0x40, 0x16, 0xb7, 0x9f, 0xfd, - 0xd1, 0x9f, 0xdc, 0x2a, 0xfc, 0xf1, 0x9f, 0xdc, 0x2a, 0xfc, 0x4f, 0x7f, 0x72, 0xeb, 0xd2, 0x5f, - 0xfb, 0xd3, 0x5b, 0x85, 0x3f, 0xfc, 0xd3, 0x5b, 0x85, 0x3f, 0xfe, 0xd3, 0x5b, 0x85, 0xff, 0xf6, - 0x4f, 0x6f, 0x15, 0x7e, 0xf9, 0xe1, 0xb1, 0x1b, 0x9f, 0xcc, 0x0e, 0xef, 0x8f, 0x83, 0xc9, 0x47, - 0x13, 0x2b, 0x0e, 0xdd, 0x73, 0xd6, 0xe1, 0x54, 0xc2, 0x77, 0x3e, 0x9a, 0x9e, 0x1e, 0x7f, 0x34, - 0x3d, 0xfc, 0x08, 0x77, 0xea, 0xc3, 0x35, 0x72, 0xaf, 0x7e, 0xf8, 0xff, 0x06, 0x00, 0x00, 0xff, - 0xff, 0x9d, 0x11, 0xe8, 0x0f, 0x9d, 0xbf, 0x00, 0x00, + // 19294 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0xbd, 0x6d, 0x8c, 0x1c, 0xd9, + 0x96, 0x20, 0xe4, 0xac, 0xcc, 0xaa, 0xca, 0x3c, 0xf9, 0x51, 0x51, 0xd7, 0x65, 0x3b, 0xed, 0x76, + 0xdb, 0xee, 0x68, 0x77, 0xb7, 0xdb, 0xdd, 0xed, 0xee, 0xb6, 0xfb, 0xc3, 0xdd, 0xef, 0xcd, 0xbc, + 0x97, 0x95, 0x95, 0xe5, 0x4a, 0x3b, 0x2b, 0xb3, 0x5e, 0x64, 0x96, 0xdd, 0xfd, 0x66, 0x87, 0x50, + 0x54, 0x66, 0x54, 0x55, 0x74, 0x45, 0x46, 0x64, 0x47, 0x44, 0xba, 0xaa, 0x9e, 0x16, 0xf1, 0x84, + 0x04, 0xcb, 0x00, 0x5a, 0xad, 0xb4, 0x62, 0x05, 0x42, 0x82, 0x01, 0x69, 0x85, 0xb4, 0x20, 0x21, + 0x56, 0x2b, 0x86, 0x0f, 0xf1, 0xb1, 0x80, 0xc4, 0xf2, 0x21, 0x34, 0xb0, 0xc0, 0x02, 0x8b, 0x16, + 0x98, 0xf9, 0xc1, 0x4f, 0x84, 0xf8, 0x90, 0xd8, 0x3f, 0xa0, 0x73, 0xce, 0xbd, 0xf1, 0x91, 0x99, + 0x65, 0x77, 0xbf, 0x99, 0x91, 0xf8, 0x53, 0x95, 0xf7, 0x9c, 0x73, 0x6f, 0xdc, 0xcf, 0x73, 0xcf, + 0x39, 0xf7, 0xdc, 0x73, 0x01, 0x26, 0xae, 0xe5, 0x3d, 0x98, 0x04, 0x7e, 0xe4, 0x8b, 0x02, 0xfe, + 0xbe, 0xf1, 0xd1, 0x91, 0x13, 0x1d, 0x4f, 0x0f, 0x1e, 0x0c, 0xfd, 0xf1, 0xc7, 0x47, 0xfe, 0x91, + 0xff, 0x31, 0x21, 0x0f, 0xa6, 0x87, 0x94, 0xa2, 0x04, 0xfd, 0xe2, 0x4c, 0x37, 0xc0, 0xf5, 0x87, + 0x27, 0xf2, 0xf7, 0x5a, 0xe4, 0x8c, 0xed, 0x30, 0xb2, 0xc6, 0x13, 0x06, 0xe8, 0xff, 0x69, 0x1e, + 0x0a, 0x83, 0xf3, 0x89, 0x2d, 0x6a, 0xb0, 0xe4, 0x8c, 0xea, 0xb9, 0x3b, 0xb9, 0x7b, 0xcb, 0xc6, + 0x92, 0x33, 0x12, 0x77, 0xa0, 0xec, 0xf9, 0x51, 0x77, 0xea, 0xba, 0xd6, 0x81, 0x6b, 0xd7, 0x97, + 0xee, 0xe4, 0xee, 0x15, 0x8d, 0x34, 0x48, 0xbc, 0x01, 0x25, 0x6b, 0x1a, 0xf9, 0xa6, 0xe3, 0x0d, + 0x83, 0x7a, 0x9e, 0xf0, 0x45, 0x04, 0xb4, 0xbd, 0x61, 0x20, 0x36, 0x60, 0xf9, 0xd4, 0x19, 0x45, + 0xc7, 0xf5, 0x02, 0x95, 0xc8, 0x09, 0x84, 0x86, 0x43, 0xcb, 0xb5, 0xeb, 0xcb, 0x0c, 0xa5, 0x04, + 0x42, 0x23, 0xfa, 0xc8, 0xca, 0x9d, 0xdc, 0xbd, 0x92, 0xc1, 0x09, 0x71, 0x0b, 0xc0, 0xf6, 0xa6, + 0xe3, 0x97, 0x96, 0x3b, 0xb5, 0xc3, 0xfa, 0x2a, 0xa1, 0x52, 0x10, 0x51, 0x87, 0xd5, 0xe1, 0xb1, + 0x15, 0x84, 0x76, 0x54, 0x2f, 0xde, 0xc9, 0xdd, 0xab, 0x1a, 0x2a, 0x89, 0x15, 0x9b, 0x58, 0x23, + 0x33, 0x9c, 0x58, 0x43, 0xbb, 0x5e, 0xe2, 0x8a, 0x4d, 0xac, 0x51, 0x1f, 0xd3, 0xe2, 0x73, 0xb8, + 0x3a, 0xf4, 0x5d, 0xd7, 0x8a, 0x1c, 0xdf, 0x33, 0x87, 0xbe, 0x1d, 0x0c, 0x9d, 0x03, 0xc7, 0x75, + 0xa2, 0xf3, 0x3a, 0x50, 0x29, 0x57, 0x62, 0x6c, 0x33, 0x85, 0x14, 0x3f, 0x85, 0x1b, 0x8b, 0xb3, + 0x99, 0x58, 0x81, 0x32, 0x7d, 0xa4, 0xbe, 0x30, 0x6b, 0xdf, 0x8e, 0xc4, 0x63, 0x48, 0x70, 0xe6, + 0xd8, 0x0e, 0x8e, 0x6c, 0x73, 0xe8, 0x7b, 0x87, 0xae, 0x33, 0x8c, 0xea, 0x15, 0xca, 0x9b, 0x54, + 0x6a, 0x17, 0xd1, 0x4d, 0x89, 0x15, 0x1f, 0xc0, 0x7a, 0x92, 0xf3, 0xa5, 0x1d, 0x84, 0x8e, 0xef, + 0xd5, 0xab, 0x54, 0x53, 0x2d, 0x46, 0x3c, 0x67, 0xb8, 0xfe, 0x33, 0x28, 0x8d, 0xc3, 0xa3, 0x1d, + 0xdb, 0x1a, 0xd9, 0x81, 0xb8, 0x06, 0xab, 0xe3, 0xf0, 0xc8, 0x8c, 0xac, 0x23, 0x39, 0xaa, 0x2b, + 0xe3, 0xf0, 0x68, 0x60, 0x1d, 0x89, 0xeb, 0x50, 0x24, 0xc4, 0xf9, 0x84, 0x87, 0x75, 0xd9, 0x40, + 0x42, 0x9c, 0x04, 0xfa, 0x1f, 0xae, 0xc2, 0x6a, 0xc7, 0x89, 0xec, 0xc0, 0x72, 0xc5, 0x55, 0x58, + 0x71, 0x42, 0x6f, 0xea, 0xba, 0x94, 0xbd, 0x68, 0xc8, 0x94, 0xb8, 0x0a, 0xcb, 0xce, 0xe3, 0x97, + 0x96, 0xcb, 0x79, 0x77, 0x2e, 0x19, 0x9c, 0x14, 0x75, 0x58, 0x71, 0x3e, 0xfd, 0x02, 0x11, 0x79, + 0x89, 0x90, 0x69, 0xc2, 0x3c, 0x7a, 0x88, 0x98, 0x42, 0x8c, 0xa1, 0x34, 0x61, 0xbe, 0xf8, 0x0c, + 0x31, 0x38, 0x21, 0xf2, 0x84, 0xa1, 0x34, 0x7e, 0x65, 0x4a, 0x5f, 0xc1, 0x39, 0x51, 0xc5, 0xaf, + 0x4c, 0xd5, 0x57, 0xa6, 0xfc, 0x95, 0x55, 0x89, 0x90, 0x69, 0xc2, 0xf0, 0x57, 0x8a, 0x31, 0x26, + 0xfe, 0xca, 0x94, 0xbf, 0x82, 0x93, 0xa1, 0x40, 0x18, 0xfe, 0xca, 0x06, 0x14, 0x46, 0x08, 0xc7, + 0xa1, 0xcf, 0xed, 0x5c, 0x32, 0x28, 0x85, 0xd0, 0x10, 0xa1, 0x38, 0xaa, 0x25, 0x84, 0x86, 0x12, + 0x7a, 0x80, 0x50, 0x1a, 0x2f, 0x84, 0x1e, 0x48, 0xe8, 0x21, 0x42, 0x71, 0x48, 0x96, 0x10, 0x8a, + 0x29, 0x71, 0x03, 0x56, 0x47, 0x56, 0x64, 0x23, 0xa2, 0x26, 0x9b, 0xac, 0x00, 0x88, 0xc3, 0x45, + 0x88, 0xb8, 0x35, 0xd9, 0x68, 0x05, 0x10, 0x3a, 0x94, 0x91, 0x4c, 0xe1, 0x35, 0x89, 0x4f, 0x03, + 0xc5, 0xe7, 0x50, 0x19, 0xd9, 0x43, 0x67, 0x6c, 0xb9, 0xdc, 0xa6, 0xf5, 0x3b, 0xb9, 0x7b, 0xe5, + 0x87, 0x6b, 0x0f, 0x88, 0x4d, 0xc4, 0x98, 0x9d, 0x4b, 0x46, 0x86, 0x4c, 0x3c, 0x86, 0xaa, 0x4c, + 0x7f, 0xfa, 0x90, 0x3a, 0x56, 0x50, 0x3e, 0x2d, 0x93, 0xef, 0xd3, 0x87, 0x8f, 0x77, 0x2e, 0x19, + 0x59, 0x42, 0x71, 0x17, 0x2a, 0x31, 0xd7, 0xc0, 0x8c, 0x97, 0x65, 0xad, 0x32, 0x50, 0x6c, 0xd6, + 0x77, 0xa1, 0xef, 0x21, 0xc1, 0x86, 0xec, 0x37, 0x05, 0x10, 0x77, 0x00, 0x46, 0xf6, 0xa1, 0x35, + 0x75, 0x23, 0x44, 0x5f, 0x91, 0x1d, 0x98, 0x82, 0x89, 0x5b, 0x50, 0x9a, 0x4e, 0xb0, 0x95, 0xcf, + 0x2d, 0xb7, 0x7e, 0x55, 0x12, 0x24, 0x20, 0x2c, 0x1d, 0x97, 0x3e, 0x62, 0xaf, 0xc9, 0xd1, 0x55, + 0x00, 0x1c, 0xde, 0x97, 0xf6, 0x10, 0x51, 0x75, 0xf9, 0x61, 0x99, 0x46, 0xc6, 0xe2, 0x84, 0x9b, + 0x8e, 0x57, 0xbf, 0x4e, 0x33, 0x98, 0x13, 0xe2, 0x26, 0xe4, 0xc3, 0x60, 0x58, 0xbf, 0x41, 0xed, + 0x07, 0x6e, 0x7f, 0xeb, 0x6c, 0x12, 0x18, 0x08, 0x16, 0x6f, 0x43, 0xd5, 0x09, 0xcd, 0xd0, 0x0e, + 0x1c, 0xcb, 0x75, 0x7e, 0x65, 0x8f, 0xea, 0x6f, 0x50, 0xde, 0x8a, 0x13, 0xf6, 0x63, 0x98, 0xf8, + 0x1a, 0x2a, 0x2e, 0x2f, 0x13, 0xf3, 0xd0, 0x0f, 0xc6, 0xf5, 0x9b, 0x77, 0x72, 0xf7, 0x6a, 0x0f, + 0xaf, 0x71, 0x59, 0xfd, 0x28, 0x70, 0xbc, 0x23, 0xb9, 0x8c, 0xb6, 0xfd, 0x60, 0x6c, 0x94, 0xdd, + 0x24, 0x81, 0x1f, 0x08, 0x89, 0xc2, 0x0c, 0xfd, 0x69, 0x30, 0xb4, 0xeb, 0x6f, 0xd2, 0x6a, 0xae, + 0x30, 0xb0, 0x4f, 0x30, 0xf1, 0x33, 0xb8, 0x29, 0x07, 0xc1, 0x54, 0x1f, 0x0a, 0xec, 0xef, 0xa7, + 0x4e, 0x60, 0x87, 0xe6, 0xcb, 0xc7, 0x0f, 0xeb, 0xb7, 0xa8, 0x52, 0xd7, 0x25, 0x8d, 0xfc, 0x96, + 0x21, 0x29, 0x9e, 0x3f, 0x7e, 0xb8, 0xb9, 0x0a, 0xcb, 0xc4, 0x27, 0xf5, 0x9b, 0x50, 0xdc, 0xb3, + 0x02, 0x6b, 0x6c, 0xd8, 0x87, 0x42, 0x83, 0xfc, 0xc4, 0x0f, 0x25, 0x3b, 0xc0, 0x9f, 0xfa, 0x9f, + 0x87, 0x95, 0xe7, 0x56, 0x80, 0x38, 0x01, 0x05, 0xcf, 0x1a, 0xdb, 0x84, 0x2c, 0x19, 0xf4, 0x1b, + 0x59, 0x40, 0x78, 0x1e, 0x46, 0xf6, 0x58, 0xb2, 0x7f, 0x99, 0x42, 0xf8, 0x91, 0xeb, 0x1f, 0xc8, + 0xa5, 0x5e, 0x34, 0x64, 0x4a, 0x3c, 0x80, 0xcb, 0x07, 0xfe, 0xd4, 0x1b, 0x99, 0xb2, 0x81, 0x23, + 0x7f, 0x6c, 0x39, 0x1e, 0xad, 0xfa, 0xaa, 0xb1, 0x4e, 0x28, 0xee, 0x9c, 0x2d, 0x42, 0xe8, 0xff, + 0x70, 0x0e, 0x56, 0x9a, 0xbe, 0x8b, 0x9f, 0xbf, 0x06, 0xab, 0x81, 0xed, 0x9a, 0x49, 0xf5, 0x56, + 0x02, 0xdb, 0xdd, 0xf3, 0x43, 0x44, 0x0c, 0x7d, 0x46, 0x30, 0xb3, 0x5a, 0x19, 0xfa, 0x84, 0x50, + 0x15, 0xce, 0xa7, 0x2a, 0x7c, 0x1d, 0x8a, 0xd1, 0x81, 0x6b, 0x12, 0xbc, 0x40, 0xf0, 0xd5, 0xe8, + 0xc0, 0xed, 0x22, 0xea, 0x1a, 0xac, 0x8e, 0x0e, 0x18, 0xb3, 0x4c, 0x98, 0x95, 0xd1, 0x01, 0x22, + 0xf4, 0xaf, 0xa0, 0x64, 0x58, 0xa7, 0xb2, 0x1a, 0x57, 0x60, 0x05, 0x0b, 0x90, 0x3b, 0x61, 0xc1, + 0x58, 0x8e, 0x0e, 0xdc, 0xf6, 0x08, 0xc1, 0x58, 0x09, 0x67, 0x44, 0x75, 0x28, 0x18, 0xcb, 0x43, + 0xdf, 0x6d, 0x8f, 0xf4, 0x01, 0x40, 0xd3, 0x0f, 0x82, 0xdf, 0xb8, 0x09, 0x1b, 0xb0, 0x3c, 0xb2, + 0x27, 0xd1, 0x31, 0x73, 0x4c, 0x83, 0x13, 0xfa, 0x7d, 0x28, 0xe2, 0x74, 0xec, 0x38, 0x61, 0x24, + 0x6e, 0x41, 0xc1, 0x75, 0xc2, 0xa8, 0x9e, 0xbb, 0x93, 0x9f, 0x99, 0xac, 0x04, 0xd7, 0xef, 0x40, + 0x71, 0xd7, 0x3a, 0x7b, 0x8e, 0x23, 0x8d, 0xa5, 0xd1, 0x90, 0xcb, 0x21, 0x94, 0xe3, 0x5f, 0x01, + 0x18, 0x58, 0xc1, 0x91, 0x1d, 0x11, 0x83, 0xff, 0x3f, 0x72, 0x50, 0xee, 0x4f, 0x0f, 0xbe, 0x9f, + 0xda, 0xc1, 0x39, 0xd6, 0xf9, 0x1e, 0xe4, 0xa3, 0xf3, 0x09, 0xe5, 0xa8, 0x3d, 0xbc, 0x2a, 0xe7, + 0x6f, 0x82, 0x7f, 0x80, 0x99, 0x0c, 0x24, 0xc1, 0x46, 0x78, 0xfe, 0xc8, 0x56, 0x7d, 0xb0, 0x6c, + 0xac, 0x60, 0xb2, 0x3d, 0x42, 0xc1, 0xc1, 0x9f, 0xc8, 0x51, 0x58, 0xf2, 0x27, 0xe2, 0x0e, 0x2c, + 0x0f, 0x8f, 0x1d, 0x77, 0x44, 0x03, 0x90, 0xad, 0x33, 0x23, 0x70, 0x94, 0x02, 0xff, 0xd4, 0x0c, + 0x9d, 0x5f, 0x29, 0x41, 0x60, 0x35, 0xf0, 0x4f, 0xfb, 0xce, 0xaf, 0x6c, 0x7d, 0x20, 0xa5, 0x11, + 0x80, 0x95, 0x7e, 0xb3, 0xd1, 0x69, 0x18, 0xda, 0x25, 0xfc, 0xdd, 0xfa, 0xa6, 0xdd, 0x1f, 0xf4, + 0xb5, 0x9c, 0xa8, 0x01, 0x74, 0x7b, 0x03, 0x53, 0xa6, 0x97, 0xc4, 0x0a, 0x2c, 0xb5, 0xbb, 0x5a, + 0x1e, 0x69, 0x10, 0xde, 0xee, 0x6a, 0x05, 0xb1, 0x0a, 0xf9, 0x46, 0xf7, 0x5b, 0x6d, 0x99, 0x7e, + 0x74, 0x3a, 0xda, 0x8a, 0xfe, 0xf7, 0x97, 0xa0, 0xd4, 0x3b, 0xf8, 0xce, 0x1e, 0x46, 0xd8, 0x66, + 0x9c, 0xd5, 0x76, 0xf0, 0xd2, 0x0e, 0xa8, 0xd9, 0x79, 0x43, 0xa6, 0xb0, 0x21, 0xa3, 0x03, 0x6a, + 0x5c, 0xde, 0x58, 0x1a, 0x1d, 0x10, 0xdd, 0xf0, 0xd8, 0x1e, 0x5b, 0xd4, 0x38, 0xa4, 0xa3, 0x14, + 0xae, 0x22, 0xff, 0xe0, 0x3b, 0x6a, 0x5e, 0xde, 0xc0, 0x9f, 0xe2, 0x36, 0x94, 0xb9, 0x8c, 0xf4, + 0xfc, 0x02, 0x06, 0xcd, 0x4e, 0xbe, 0x95, 0xf4, 0xe4, 0xa3, 0x9c, 0x54, 0x2a, 0x23, 0xa5, 0x94, + 0xc3, 0xa0, 0xae, 0x9c, 0xd1, 0xfe, 0xc1, 0x77, 0x8c, 0x2d, 0xf2, 0x8c, 0xf6, 0x0f, 0xbe, 0x23, + 0xd4, 0x07, 0xb0, 0x1e, 0x4e, 0x0f, 0xc2, 0x61, 0xe0, 0x4c, 0x48, 0x3a, 0x20, 0x9a, 0x12, 0xd1, + 0x68, 0x69, 0x04, 0x11, 0xdf, 0x83, 0xe2, 0x64, 0x7a, 0x60, 0x3a, 0xde, 0xa1, 0x4f, 0xbb, 0x5d, + 0xf9, 0x61, 0x95, 0x07, 0x66, 0x6f, 0x7a, 0xd0, 0xf6, 0x0e, 0x7d, 0x63, 0x75, 0xc2, 0x3f, 0x84, + 0x0e, 0x55, 0xcf, 0x8f, 0x4c, 0x14, 0x1a, 0xcd, 0xb1, 0x1d, 0x59, 0x52, 0xb8, 0x41, 0xd1, 0xaf, + 0xe3, 0x0f, 0x4f, 0x76, 0xed, 0xc8, 0x12, 0xf7, 0xa1, 0x18, 0x7a, 0xd6, 0x24, 0x3c, 0xf6, 0x59, + 0x7e, 0x29, 0x3f, 0xac, 0xc9, 0xb9, 0x23, 0xa1, 0x46, 0x8c, 0xd7, 0xdf, 0x85, 0x55, 0xf9, 0x0d, + 0x14, 0xcc, 0x22, 0xdb, 0xb3, 0xbc, 0xc8, 0x8c, 0x45, 0xcd, 0x22, 0x03, 0xda, 0x23, 0xfd, 0x6f, + 0xe4, 0x40, 0xeb, 0xa7, 0xaa, 0x4d, 0x1f, 0x5a, 0xc4, 0x95, 0xde, 0x04, 0xb0, 0x86, 0x43, 0x7f, + 0xca, 0xc5, 0xf0, 0x64, 0x2c, 0x49, 0x48, 0x7b, 0x94, 0xee, 0xeb, 0x7c, 0xa6, 0xaf, 0xdf, 0x82, + 0x8a, 0xca, 0x97, 0x62, 0x10, 0x65, 0x09, 0x53, 0xbd, 0x1d, 0x4e, 0x33, 0x5c, 0x62, 0x35, 0x9c, + 0x72, 0xee, 0xab, 0xb0, 0x42, 0x72, 0x69, 0xa8, 0x46, 0x90, 0x53, 0xfa, 0xdf, 0xc9, 0x41, 0xb5, + 0xed, 0x8d, 0xec, 0xb3, 0xfe, 0xd0, 0xf2, 0x54, 0x07, 0x3a, 0xa1, 0xe9, 0x20, 0xcc, 0x0c, 0x87, + 0x96, 0x27, 0xe5, 0xa7, 0xb2, 0x13, 0xc6, 0x74, 0xd8, 0x06, 0x26, 0xa0, 0x4f, 0x2d, 0x51, 0x89, + 0x25, 0x82, 0xd0, 0xc7, 0xde, 0x85, 0xb5, 0x03, 0xdb, 0xf5, 0xbd, 0x23, 0x33, 0xf2, 0x4d, 0x96, + 0x8d, 0xb9, 0x2d, 0x55, 0x06, 0x0f, 0xfc, 0x01, 0xc9, 0xc8, 0x1b, 0xb0, 0x3c, 0xb1, 0x82, 0x28, + 0xac, 0x17, 0xee, 0xe4, 0x71, 0xc9, 0x53, 0x02, 0xbb, 0xd9, 0x09, 0xcd, 0xa9, 0xe7, 0x7c, 0x3f, + 0xe5, 0x66, 0x14, 0x8d, 0xa2, 0x13, 0xee, 0x53, 0x5a, 0xdc, 0x03, 0x8d, 0xbf, 0x4c, 0xc5, 0xa6, + 0xe7, 0x64, 0x8d, 0xe0, 0x54, 0x30, 0x31, 0xc6, 0xff, 0x3a, 0x0f, 0xc5, 0xed, 0xa9, 0x37, 0xc4, + 0xc1, 0x10, 0x6f, 0x43, 0xe1, 0x70, 0xea, 0x0d, 0xa9, 0x2d, 0xb1, 0xb4, 0x11, 0xaf, 0x29, 0x83, + 0x90, 0xc8, 0xad, 0xac, 0xe0, 0x08, 0xb9, 0xdc, 0x1c, 0xb7, 0x42, 0x38, 0x8d, 0xdc, 0xd1, 0x11, + 0x89, 0xbe, 0xce, 0x11, 0xb5, 0xa8, 0x62, 0x94, 0xac, 0xa3, 0xa3, 0x26, 0x01, 0x44, 0x03, 0xd6, + 0x12, 0x34, 0xcb, 0xa7, 0x05, 0x62, 0x4c, 0xd7, 0xb9, 0xa4, 0xc6, 0xd1, 0x51, 0x60, 0x1f, 0x59, + 0x91, 0xcd, 0xf4, 0xc4, 0x9b, 0xaa, 0x71, 0x76, 0xe2, 0x1b, 0x9f, 0xc0, 0x46, 0x78, 0xee, 0x45, + 0xd6, 0x99, 0x69, 0x9f, 0x4d, 0x5c, 0x67, 0xe8, 0x44, 0xe6, 0xd0, 0x0a, 0x23, 0xd9, 0x0b, 0x82, + 0x71, 0x2d, 0x89, 0x6a, 0x5a, 0x61, 0x24, 0x3e, 0x83, 0x4a, 0xe0, 0x4f, 0x23, 0xc7, 0xb3, 0xcd, + 0xa1, 0xe5, 0xb2, 0xbc, 0x59, 0x7e, 0xb8, 0xce, 0x5f, 0x34, 0x18, 0xd3, 0xb4, 0x5c, 0xd7, 0x28, + 0x07, 0x49, 0x42, 0xff, 0x37, 0x72, 0xdc, 0x37, 0xdb, 0xae, 0x75, 0x24, 0x8a, 0x50, 0xe8, 0xf6, + 0xba, 0x2d, 0xed, 0x92, 0xa8, 0x40, 0xb1, 0xdd, 0x1d, 0xb4, 0x8c, 0x6e, 0xa3, 0xa3, 0xe5, 0x88, + 0x89, 0x0d, 0x1a, 0x9b, 0x9d, 0x96, 0xb6, 0x84, 0x98, 0xe7, 0xbd, 0x4e, 0x63, 0xd0, 0xee, 0xb4, + 0xb4, 0x02, 0x63, 0x8c, 0x76, 0x73, 0xa0, 0x15, 0x85, 0x06, 0x95, 0x3d, 0xa3, 0xb7, 0xb5, 0xdf, + 0x6c, 0x99, 0xdd, 0xfd, 0x4e, 0x47, 0xd3, 0xc4, 0x65, 0x58, 0x8b, 0x21, 0x3d, 0x06, 0xde, 0xc1, + 0x2c, 0xcf, 0x1b, 0x46, 0xc3, 0x78, 0xa2, 0xfd, 0x5c, 0x14, 0x21, 0xdf, 0x78, 0xf2, 0x44, 0xfb, + 0x35, 0xf2, 0xc3, 0xd2, 0x8b, 0x76, 0xd7, 0x7c, 0xde, 0xe8, 0xec, 0xb7, 0xb4, 0x5f, 0x2f, 0xa9, + 0x74, 0xcf, 0xd8, 0x6a, 0x19, 0xda, 0xaf, 0x0b, 0x62, 0x1d, 0x2a, 0xbf, 0xec, 0x75, 0x5b, 0xbb, + 0x8d, 0xbd, 0x3d, 0xaa, 0xc8, 0xaf, 0x8b, 0xfa, 0x7f, 0xb2, 0x0c, 0xd7, 0xf6, 0x02, 0x7b, 0x62, + 0x05, 0xf6, 0xa8, 0x3b, 0x1d, 0xdb, 0x81, 0x33, 0xc4, 0xa5, 0x36, 0xb2, 0x22, 0x4b, 0xdc, 0x80, + 0xe2, 0xa1, 0xe5, 0xba, 0x07, 0xd6, 0xf0, 0x44, 0xce, 0xda, 0x38, 0xcd, 0x5a, 0x55, 0x60, 0x8d, + 0x53, 0xfb, 0x58, 0x91, 0x00, 0xb8, 0x93, 0xbd, 0x07, 0x6b, 0x8a, 0x50, 0x89, 0x35, 0x2c, 0x1a, + 0xd4, 0x14, 0x58, 0x0a, 0x36, 0x9f, 0xc3, 0xb5, 0x19, 0x42, 0x53, 0x6d, 0x2b, 0xac, 0x29, 0x6e, + 0x64, 0x33, 0x74, 0x79, 0x93, 0x59, 0x90, 0x4d, 0x6d, 0xa9, 0xcb, 0x8b, 0xb2, 0x35, 0x79, 0x83, + 0xfd, 0x02, 0xae, 0x4d, 0x02, 0xff, 0xa5, 0x83, 0xda, 0x11, 0x89, 0x50, 0xe1, 0xd4, 0x95, 0x33, + 0x62, 0x85, 0xaa, 0x77, 0x25, 0x85, 0x36, 0x08, 0x4b, 0x93, 0x62, 0x71, 0xbe, 0x89, 0x6d, 0x07, + 0xc4, 0xa2, 0x17, 0xe5, 0xdb, 0xb3, 0xed, 0x40, 0x6c, 0xc1, 0xed, 0x0b, 0xf2, 0xd1, 0x74, 0xc6, + 0x56, 0x16, 0xa9, 0xba, 0x6f, 0x2c, 0xcc, 0x8f, 0x53, 0xb8, 0x3d, 0x12, 0x0d, 0x78, 0xf3, 0xa2, + 0x52, 0x58, 0xa7, 0x2e, 0x51, 0x19, 0x37, 0x16, 0x96, 0xf1, 0x82, 0x14, 0xed, 0x57, 0x14, 0xc1, + 0x0a, 0x38, 0xbc, 0xa2, 0x88, 0x3e, 0x69, 0xe5, 0x3f, 0x85, 0x8d, 0x8c, 0x18, 0xa7, 0xc6, 0xb5, + 0x3c, 0xb7, 0xad, 0x8b, 0x30, 0x25, 0xd4, 0xc9, 0x71, 0x7e, 0x00, 0x97, 0x9d, 0x43, 0xd4, 0x17, + 0xcd, 0xa1, 0x3f, 0x1e, 0xa3, 0xee, 0x4a, 0xa2, 0x09, 0x2b, 0xbb, 0xeb, 0x8c, 0x6a, 0x12, 0x86, + 0x85, 0x97, 0xcf, 0xe0, 0xea, 0x24, 0xf0, 0x91, 0x9d, 0xd8, 0xa3, 0x6c, 0x96, 0x2a, 0x65, 0xd9, + 0x88, 0xb1, 0xa9, 0x5c, 0xfa, 0x3f, 0xbf, 0x02, 0x05, 0xac, 0x82, 0xd0, 0x13, 0x39, 0x26, 0xae, + 0x1b, 0xf6, 0xe6, 0x66, 0xe1, 0x6f, 0xfd, 0xbd, 0xdb, 0x97, 0x58, 0x82, 0x79, 0x0b, 0xf2, 0xae, + 0x13, 0xd1, 0xd4, 0x8d, 0x77, 0x3f, 0x29, 0x39, 0xef, 0x5c, 0x32, 0x10, 0x27, 0x6e, 0x41, 0x8e, + 0x45, 0x99, 0x78, 0x43, 0x53, 0xb2, 0xf3, 0xce, 0x25, 0x23, 0x37, 0x11, 0x37, 0x21, 0xf7, 0x52, + 0xca, 0x35, 0x15, 0xc6, 0xb3, 0xf4, 0x8c, 0xd8, 0x97, 0xe2, 0x0e, 0xe4, 0x87, 0x3e, 0xab, 0xb2, + 0x31, 0x9e, 0x65, 0x43, 0x2c, 0x7f, 0xe8, 0xbb, 0xe2, 0x6d, 0xc8, 0x07, 0xd6, 0xa9, 0xe4, 0x31, + 0x92, 0x89, 0xc6, 0xc2, 0x27, 0x12, 0x05, 0xd6, 0x29, 0x56, 0xe2, 0x90, 0xa6, 0x59, 0x5c, 0x09, + 0xc5, 0x85, 0xf1, 0x33, 0x87, 0xe2, 0x0e, 0xe4, 0x4e, 0x69, 0x1a, 0xc5, 0xda, 0xdb, 0x0b, 0xc7, + 0x1b, 0xf9, 0xa7, 0xfd, 0x89, 0x3d, 0x44, 0x8a, 0x53, 0xf1, 0x0e, 0xe4, 0xc3, 0xe9, 0x01, 0x4d, + 0x93, 0x98, 0x95, 0xa5, 0xa4, 0x3a, 0xfc, 0x50, 0x38, 0x3d, 0x10, 0xef, 0x42, 0x61, 0xe8, 0x07, + 0x81, 0x94, 0x07, 0x34, 0x55, 0x61, 0x25, 0xd0, 0xa2, 0x36, 0x8b, 0x78, 0xfc, 0x60, 0x24, 0x87, + 0x5d, 0x12, 0x25, 0x12, 0x25, 0x7e, 0x30, 0x12, 0x77, 0xa5, 0x98, 0x9a, 0x91, 0x05, 0x94, 0x10, + 0x8b, 0xe5, 0x20, 0x16, 0x07, 0x69, 0x6c, 0x9d, 0xd1, 0x80, 0xc6, 0x44, 0x4a, 0x7a, 0xc5, 0x3a, + 0x8d, 0xad, 0x33, 0x71, 0x17, 0xf2, 0x2f, 0xed, 0x21, 0x69, 0xcd, 0xf1, 0xd7, 0xe4, 0x20, 0x3d, + 0xa7, 0xe6, 0x21, 0x9a, 0x76, 0x23, 0xdf, 0x1d, 0x91, 0x02, 0x1d, 0x8f, 0xe5, 0xb6, 0xef, 0x8e, + 0x9e, 0xd3, 0x58, 0x12, 0x52, 0x3c, 0x82, 0xd2, 0xc8, 0x9e, 0xd8, 0xde, 0xc8, 0xf6, 0x22, 0x52, + 0x0d, 0xcb, 0x0f, 0x2f, 0x33, 0xe5, 0x96, 0x02, 0x63, 0x15, 0x51, 0xd1, 0x8c, 0xe9, 0xc4, 0x07, + 0x50, 0x08, 0x5d, 0x3f, 0x22, 0x8d, 0xb1, 0xfc, 0xf0, 0x4a, 0xd2, 0x27, 0x36, 0x9b, 0x5a, 0xfa, + 0xae, 0x4f, 0x0d, 0x42, 0x22, 0x54, 0x0b, 0xac, 0xe9, 0x19, 0xae, 0x6a, 0x8d, 0x05, 0x78, 0x6b, + 0x7a, 0xd6, 0x1e, 0xa1, 0x80, 0xe8, 0x8d, 0x5e, 0x92, 0x62, 0x9e, 0x33, 0xf0, 0xa7, 0xb8, 0x83, + 0x02, 0xa2, 0x6b, 0x0f, 0x23, 0xe7, 0xa5, 0x13, 0x9d, 0x93, 0xea, 0x9d, 0x33, 0xd2, 0x20, 0xb1, + 0x03, 0xda, 0x44, 0x32, 0x65, 0xd3, 0x63, 0xae, 0x4c, 0x8a, 0x76, 0xf9, 0xe1, 0x9b, 0x72, 0x22, + 0x2e, 0x66, 0xd9, 0xc6, 0xda, 0x24, 0x8b, 0xd8, 0x5c, 0x81, 0x82, 0x7d, 0x36, 0x09, 0x9e, 0x16, + 0x8a, 0x1b, 0x5a, 0x5d, 0x7f, 0x0a, 0x6b, 0x33, 0xb5, 0xc7, 0x5d, 0x78, 0x12, 0xf8, 0x47, 0xc8, + 0xca, 0xa5, 0x18, 0x56, 0x35, 0x4a, 0x12, 0xd2, 0x1e, 0x89, 0x3a, 0xac, 0xfa, 0xc1, 0xc8, 0xf1, + 0xa4, 0x85, 0xa7, 0x6a, 0xa8, 0xa4, 0xfe, 0x17, 0x97, 0xa0, 0x9a, 0xe9, 0xba, 0xd7, 0x15, 0xf5, + 0x36, 0x54, 0xfd, 0xe1, 0x70, 0x1a, 0x04, 0xb6, 0x37, 0x8c, 0x35, 0x87, 0xaa, 0x51, 0x49, 0x80, + 0x6d, 0xd2, 0x06, 0xc2, 0xc8, 0x3a, 0x22, 0x7c, 0x9e, 0x3f, 0x48, 0xe9, 0xf6, 0x48, 0x7c, 0x82, + 0x1a, 0xd5, 0x68, 0x3a, 0xb4, 0x03, 0x29, 0x08, 0x5c, 0xa4, 0xa1, 0x28, 0x32, 0xa1, 0xc3, 0x8a, + 0xe3, 0x4d, 0xa6, 0x11, 0x6e, 0x0b, 0xb3, 0x32, 0x88, 0xc4, 0xa0, 0xfe, 0xef, 0x1e, 0xa3, 0x18, + 0x37, 0x4b, 0x80, 0x60, 0x71, 0x1f, 0x60, 0xe8, 0x8f, 0x27, 0x56, 0xe0, 0x84, 0xbe, 0x27, 0x97, + 0x61, 0x9a, 0x28, 0x85, 0xd5, 0xff, 0x99, 0x1c, 0x88, 0x54, 0xef, 0xee, 0x71, 0xc3, 0x71, 0xa7, + 0x0c, 0x7c, 0x3f, 0xa2, 0x8d, 0x4d, 0x89, 0xb9, 0x08, 0xc0, 0xbd, 0x4c, 0x7c, 0x0a, 0x65, 0xaa, + 0x07, 0x6d, 0x08, 0x33, 0xa2, 0x52, 0x8a, 0x63, 0x01, 0x11, 0x21, 0x20, 0x14, 0x8f, 0xa0, 0xe2, + 0x4f, 0xa3, 0x24, 0x4f, 0xfe, 0x82, 0x3c, 0x65, 0xa6, 0xa2, 0x4c, 0xfa, 0xff, 0x9e, 0x03, 0x2d, + 0x3d, 0xf2, 0xd8, 0xa5, 0x38, 0x5e, 0xfe, 0xa9, 0x87, 0x7a, 0x4a, 0x52, 0xb5, 0x12, 0x41, 0xa8, + 0x6e, 0x1f, 0x43, 0xe1, 0xc4, 0xf1, 0x78, 0x98, 0x6a, 0x0f, 0xdf, 0x98, 0x9f, 0xfc, 0x58, 0xc8, + 0x83, 0x67, 0x8e, 0x37, 0x32, 0x88, 0x90, 0x8c, 0x25, 0x63, 0x1c, 0x3b, 0x65, 0x99, 0xe4, 0x01, + 0xac, 0x10, 0x50, 0x59, 0x25, 0x8f, 0xa1, 0x80, 0x59, 0x44, 0x09, 0x96, 0xdb, 0xdd, 0xbd, 0xfd, + 0x81, 0x76, 0x49, 0x54, 0xa1, 0xf4, 0xb4, 0xd7, 0xee, 0x9a, 0x7b, 0x8d, 0xb6, 0xa1, 0xe5, 0x10, + 0xf3, 0xc4, 0xe8, 0xed, 0xef, 0x69, 0x4b, 0x28, 0x0d, 0xbd, 0x68, 0x77, 0xb7, 0x7a, 0x2f, 0xcc, + 0x7e, 0x6b, 0xb0, 0xbf, 0xa7, 0xe5, 0x51, 0xe5, 0x93, 0x10, 0xa3, 0xf7, 0x42, 0x2b, 0x60, 0xba, + 0xd1, 0xef, 0xb7, 0x9f, 0x74, 0x77, 0x5b, 0xdd, 0x81, 0xb6, 0x8c, 0x99, 0x8d, 0xde, 0xfe, 0xa0, + 0xa5, 0xad, 0xe8, 0xff, 0x63, 0x2e, 0x3b, 0xdb, 0x27, 0xf6, 0x10, 0xa7, 0xb3, 0xaa, 0x1c, 0xcf, + 0x4f, 0x95, 0x44, 0x49, 0x98, 0xf6, 0x35, 0xd9, 0xb7, 0x61, 0x64, 0x4f, 0xa4, 0x5c, 0x53, 0x43, + 0x78, 0x8f, 0xc0, 0xfd, 0xc8, 0x9e, 0x90, 0x96, 0x16, 0xd9, 0x13, 0x93, 0x7a, 0x8a, 0xfb, 0xbf, + 0x6a, 0x00, 0x82, 0x7a, 0x04, 0x11, 0x9f, 0x41, 0x51, 0xce, 0x7a, 0x16, 0xc5, 0xcb, 0x0f, 0xeb, + 0x73, 0x9d, 0x27, 0x67, 0x87, 0x11, 0x53, 0x8a, 0x07, 0xb0, 0x42, 0x33, 0x5d, 0x4d, 0xd6, 0xab, + 0x8b, 0x3b, 0xdc, 0x90, 0x54, 0xfa, 0x0e, 0xac, 0x4a, 0x1e, 0x37, 0x67, 0xad, 0xbf, 0x0e, 0x45, + 0x27, 0x44, 0xc9, 0x39, 0x8c, 0xa4, 0xad, 0x66, 0xd5, 0x09, 0x9b, 0x98, 0x44, 0x15, 0x0a, 0x19, + 0x85, 0x14, 0xb7, 0xe9, 0xb7, 0xfe, 0xef, 0xe4, 0x00, 0x12, 0xae, 0x8a, 0x0c, 0xcb, 0xb5, 0x3d, + 0x65, 0x17, 0x72, 0x6d, 0x2f, 0xce, 0xb4, 0x94, 0x64, 0x9a, 0xb7, 0x8c, 0xe5, 0x17, 0x58, 0xc6, + 0xe6, 0xac, 0x5b, 0x85, 0xdf, 0xc0, 0xba, 0xb5, 0xfc, 0x1a, 0xeb, 0x96, 0x7e, 0x1d, 0x59, 0xbb, + 0x34, 0x6e, 0x8a, 0x0a, 0xe4, 0x2c, 0xa9, 0xca, 0xe7, 0x2c, 0xfd, 0x1e, 0x40, 0x62, 0xbe, 0xcc, + 0xe2, 0x30, 0xa5, 0x14, 0xfc, 0xdc, 0x81, 0xfe, 0x53, 0xa8, 0x48, 0x91, 0xcf, 0x77, 0xb7, 0xec, + 0x43, 0xf1, 0x21, 0x40, 0x9c, 0x0e, 0xa5, 0xc5, 0x25, 0xd9, 0xc5, 0xb7, 0xec, 0x43, 0x23, 0x85, + 0xd7, 0xff, 0xd7, 0x65, 0xb2, 0x5d, 0x6d, 0xb1, 0xd1, 0x48, 0x5a, 0x87, 0x72, 0x29, 0xeb, 0x50, + 0xac, 0xbb, 0x2e, 0x65, 0x2d, 0x6a, 0xc7, 0xce, 0x68, 0x64, 0x7b, 0xca, 0x72, 0xc6, 0x29, 0xdc, + 0xf6, 0x2c, 0xf7, 0x48, 0x72, 0x39, 0xa1, 0x3e, 0x3a, 0x9e, 0x04, 0x76, 0x18, 0xb2, 0x0d, 0xc6, + 0x72, 0x8f, 0x94, 0x94, 0xb3, 0xfc, 0x2a, 0x29, 0xe7, 0x3a, 0x14, 0x51, 0x7d, 0x27, 0xc3, 0x3d, + 0xcb, 0xb8, 0xab, 0xf2, 0xd0, 0x46, 0xbc, 0x07, 0xab, 0xd2, 0xe4, 0x2a, 0xf9, 0x5a, 0x55, 0x6d, + 0x87, 0x04, 0x34, 0x14, 0x96, 0x8e, 0x56, 0xfc, 0xf1, 0x18, 0xf7, 0x4d, 0x69, 0x73, 0x90, 0x49, + 0xf1, 0x01, 0x94, 0x7c, 0xcf, 0x64, 0xbb, 0xac, 0x94, 0x2f, 0xe4, 0x46, 0xde, 0xf3, 0xf6, 0x09, + 0x6a, 0x14, 0x7d, 0xf9, 0x0b, 0xab, 0xe2, 0xfa, 0xa7, 0xe6, 0xd0, 0x0a, 0x46, 0x24, 0x63, 0x14, + 0x8d, 0x55, 0xd7, 0x3f, 0x6d, 0x5a, 0xc1, 0x88, 0x6d, 0x30, 0xdf, 0x7b, 0xd3, 0x31, 0xc9, 0x15, + 0x55, 0x43, 0xa6, 0xc4, 0x4d, 0x28, 0x0d, 0xdd, 0x69, 0x18, 0xd9, 0xc1, 0xe6, 0xb9, 0x14, 0x16, + 0x13, 0x00, 0xd6, 0x6b, 0x12, 0x38, 0x63, 0x2b, 0x38, 0x97, 0x52, 0xa1, 0x4a, 0x92, 0x22, 0x7c, + 0xe2, 0x8c, 0xce, 0xd8, 0xdc, 0x6e, 0x70, 0x02, 0xe9, 0x8f, 0xe9, 0x30, 0x24, 0x24, 0x49, 0xa1, + 0x68, 0xa8, 0x24, 0x8d, 0x03, 0xfd, 0xa4, 0x9d, 0xbb, 0x64, 0xc8, 0x54, 0xc6, 0x80, 0xb8, 0x7e, + 0xa1, 0x01, 0x51, 0xcc, 0xda, 0x70, 0xfc, 0xc0, 0x39, 0x72, 0xa4, 0x05, 0xe6, 0x32, 0xdb, 0x70, + 0x18, 0x44, 0x04, 0x5f, 0x42, 0xf5, 0xc8, 0xf6, 0xec, 0xc0, 0x62, 0xd9, 0x96, 0x0d, 0xe4, 0x65, + 0x35, 0xcc, 0x4f, 0x14, 0x0a, 0xa5, 0xae, 0xca, 0x51, 0x2a, 0x85, 0xb5, 0x94, 0x5a, 0xfc, 0x15, + 0x9e, 0x2d, 0x9c, 0x12, 0xef, 0xc2, 0x9a, 0xfc, 0x62, 0x5c, 0xd9, 0xab, 0x6c, 0x1e, 0x60, 0xf0, + 0x40, 0x56, 0x79, 0x0b, 0x84, 0x52, 0x79, 0x7c, 0x77, 0x3a, 0xf6, 0x4c, 0xe2, 0xee, 0xd7, 0xd2, + 0x5b, 0x69, 0x3c, 0xa3, 0xa7, 0x63, 0x8f, 0x18, 0xbb, 0x16, 0xcc, 0x40, 0xf4, 0xef, 0x61, 0x55, + 0xce, 0x10, 0x54, 0xf0, 0x51, 0xb6, 0xc8, 0xca, 0xd9, 0xac, 0xe0, 0x23, 0x9c, 0x36, 0x7c, 0xae, + 0x18, 0xaf, 0x77, 0x39, 0xf7, 0x2b, 0x0c, 0x64, 0xdb, 0xaf, 0x78, 0x0b, 0x2a, 0xa4, 0x18, 0x58, + 0xf2, 0xdc, 0x2d, 0x2f, 0xed, 0x4b, 0x53, 0xd7, 0x6d, 0x30, 0x48, 0xef, 0x41, 0x51, 0xcd, 0xa7, + 0x3f, 0x95, 0x6f, 0xea, 0x13, 0xa8, 0xa4, 0xfb, 0xf9, 0x4f, 0xa7, 0x21, 0x6c, 0x67, 0x09, 0x23, + 0x3f, 0x88, 0x99, 0x61, 0xd1, 0x09, 0xfb, 0x94, 0xd6, 0x7f, 0x7f, 0x09, 0xca, 0x64, 0xef, 0xe9, + 0x91, 0x35, 0x4b, 0x7c, 0x08, 0x62, 0x18, 0xd8, 0x56, 0x64, 0x9b, 0xf6, 0x59, 0x14, 0x58, 0xd2, + 0xaa, 0xc3, 0x4a, 0xb6, 0xc6, 0x98, 0x16, 0x22, 0xd8, 0xb0, 0x73, 0x1b, 0xca, 0x13, 0x2b, 0x08, + 0x95, 0x45, 0x91, 0xbf, 0x0e, 0x0c, 0x92, 0xf6, 0x3c, 0xcd, 0x23, 0xb9, 0x2b, 0xf2, 0x4f, 0x6c, + 0x8f, 0x6d, 0xa9, 0x6c, 0x45, 0xae, 0x11, 0x7c, 0x80, 0xe0, 0xbe, 0xf3, 0x2b, 0xd4, 0xe3, 0x00, + 0x55, 0x3c, 0xd9, 0xd9, 0xcc, 0x61, 0x6e, 0x72, 0x83, 0x53, 0xf5, 0x7b, 0xf0, 0x3c, 0xa6, 0x31, + 0x52, 0xf4, 0xfa, 0x2f, 0x01, 0x12, 0x8c, 0xb8, 0x01, 0x57, 0x9f, 0xb7, 0xfb, 0xed, 0xcd, 0x76, + 0xa7, 0x3d, 0xf8, 0xd6, 0xdc, 0xef, 0xf6, 0xf7, 0x5a, 0xcd, 0xf6, 0x76, 0xbb, 0xb5, 0xa5, 0x5d, + 0x12, 0x57, 0x41, 0xa4, 0x70, 0xf4, 0xb3, 0xd3, 0xd2, 0x72, 0xa2, 0x0e, 0x1b, 0x29, 0x78, 0xbb, + 0xab, 0x30, 0x4b, 0xfa, 0xff, 0x90, 0x83, 0xea, 0x1e, 0x2f, 0xe0, 0x67, 0xf6, 0xf9, 0x16, 0x1f, + 0x42, 0x0c, 0x15, 0xf3, 0x2d, 0x18, 0xf4, 0x5b, 0xdc, 0x82, 0xf2, 0xe4, 0xc4, 0x3e, 0x37, 0x33, + 0x06, 0xf8, 0x12, 0x82, 0x9a, 0xc4, 0x66, 0xdf, 0x87, 0x15, 0x9f, 0x9a, 0x20, 0x15, 0xb7, 0xf5, + 0xb9, 0xb6, 0x19, 0x92, 0x40, 0xe8, 0x50, 0x8d, 0x8b, 0x4a, 0x9b, 0x00, 0x65, 0x61, 0xd4, 0xb1, + 0x1b, 0xb0, 0x8c, 0x28, 0xde, 0x93, 0x4b, 0x06, 0x27, 0xc4, 0x27, 0x50, 0x45, 0xb9, 0xcf, 0x54, + 0xd9, 0xa5, 0x0a, 0x97, 0xdd, 0x1e, 0xca, 0x48, 0xb2, 0xc7, 0x65, 0xe9, 0xff, 0x77, 0x1e, 0x8a, + 0x54, 0x07, 0xb9, 0x43, 0x38, 0xa3, 0x33, 0xb5, 0x43, 0x94, 0x8c, 0x65, 0x67, 0x84, 0x8a, 0xc2, + 0x6b, 0xac, 0x80, 0xb1, 0x75, 0x2f, 0x9f, 0xb6, 0xee, 0x25, 0x4c, 0xa1, 0x90, 0x61, 0x0a, 0x8b, + 0x0c, 0x7b, 0xcb, 0x8b, 0x0c, 0x7b, 0x38, 0xb9, 0x98, 0xc6, 0x3e, 0x73, 0x62, 0x4b, 0x08, 0x10, + 0xa8, 0x85, 0x90, 0x34, 0xff, 0x5f, 0xcd, 0xf2, 0x7f, 0x94, 0xa6, 0x70, 0x3a, 0xb8, 0x6c, 0x8d, + 0x2e, 0x1a, 0x2a, 0x99, 0x1a, 0x86, 0xd2, 0xeb, 0x86, 0x21, 0x6e, 0xb6, 0xe5, 0x1e, 0xb1, 0x35, + 0x5a, 0x35, 0xbb, 0xe1, 0x1e, 0xf9, 0xe2, 0x53, 0xb8, 0x92, 0xa0, 0x65, 0x6b, 0xc8, 0x18, 0x48, + 0xe7, 0xb1, 0x86, 0x88, 0x29, 0xa9, 0x45, 0x64, 0xf6, 0xbb, 0x0f, 0xeb, 0xa9, 0x2c, 0x64, 0x95, + 0x0a, 0x69, 0xfb, 0x28, 0x19, 0x6b, 0x31, 0x39, 0xa9, 0xf2, 0xa1, 0x78, 0x1f, 0xfb, 0x69, 0xe8, + 0x4e, 0x47, 0xcc, 0x8c, 0xa7, 0x63, 0x2f, 0xac, 0x57, 0xa9, 0x83, 0xd7, 0x14, 0x9c, 0x99, 0x1f, + 0xd9, 0x2b, 0x71, 0xbc, 0x0f, 0xfd, 0x60, 0x6c, 0x45, 0xb4, 0x85, 0x54, 0x8d, 0xd2, 0x89, 0x7d, + 0xbe, 0x4d, 0x80, 0xa7, 0x85, 0x62, 0x4d, 0x5b, 0x33, 0x6a, 0xc9, 0x6a, 0x31, 0x43, 0x3b, 0xd2, + 0x7f, 0x6f, 0x19, 0xaa, 0xdb, 0x7e, 0x60, 0x3b, 0x47, 0x5e, 0x32, 0xab, 0xe7, 0x8c, 0xd8, 0x6a, + 0xa6, 0x2f, 0xa5, 0x66, 0xfa, 0x6d, 0x28, 0x1f, 0x72, 0x46, 0xe4, 0xeb, 0x34, 0x9d, 0x0b, 0x06, + 0x48, 0xd0, 0xe0, 0xc0, 0x45, 0xce, 0xa9, 0x08, 0x28, 0x73, 0x81, 0x32, 0xab, 0x4c, 0x28, 0x96, + 0x88, 0xaf, 0x69, 0x83, 0x1e, 0xd9, 0xae, 0x1d, 0xf1, 0xf0, 0xd7, 0x94, 0x02, 0x99, 0xa9, 0xd3, + 0x03, 0xc3, 0x3e, 0x6c, 0x90, 0x4d, 0x01, 0xf7, 0xeb, 0x2d, 0x22, 0x97, 0x79, 0xe5, 0xe6, 0xbe, + 0xf2, 0x03, 0xf3, 0x4a, 0x2e, 0xfd, 0x10, 0xae, 0x04, 0xf6, 0xa1, 0x4d, 0x4a, 0xdd, 0xc8, 0x4c, + 0xcd, 0x6a, 0x9e, 0x40, 0x97, 0x13, 0x64, 0x3b, 0x9e, 0xdf, 0xbb, 0xa0, 0xc5, 0x75, 0x35, 0x99, + 0xb3, 0xd2, 0xac, 0xaa, 0x3d, 0x7c, 0xfb, 0x95, 0x9f, 0xed, 0x11, 0xa9, 0x51, 0x53, 0x15, 0xe7, + 0xb4, 0x2c, 0x8e, 0xab, 0xaf, 0x8a, 0x2b, 0xfd, 0xa8, 0xe2, 0xb8, 0x2d, 0x9c, 0xd6, 0x07, 0x50, + 0x8a, 0x49, 0x44, 0x05, 0x8a, 0x46, 0x4b, 0x9a, 0x6c, 0x2f, 0x89, 0x32, 0xac, 0x36, 0x1b, 0xfd, + 0x66, 0x63, 0x0b, 0xf9, 0x5b, 0x05, 0x8a, 0xfd, 0xd6, 0x80, 0xcd, 0xb4, 0x4b, 0x62, 0x0d, 0xca, + 0x98, 0xda, 0x6a, 0x6d, 0x37, 0xf6, 0x3b, 0x03, 0x2d, 0x8f, 0xaa, 0x4e, 0xb7, 0x67, 0x36, 0x9a, + 0x83, 0x76, 0xaf, 0xab, 0x15, 0x74, 0x17, 0xd6, 0x66, 0x3e, 0x8c, 0x4c, 0x95, 0xd1, 0x66, 0xcf, + 0x68, 0x3f, 0x69, 0x77, 0xcd, 0xd6, 0x37, 0x7b, 0x9d, 0x76, 0xb3, 0x8d, 0x5f, 0xba, 0x0e, 0x57, + 0xb2, 0x38, 0x55, 0x70, 0x4e, 0xe8, 0x70, 0x2b, 0x8b, 0xea, 0xb4, 0x9e, 0x34, 0x9a, 0xdf, 0x9a, + 0x8d, 0xdd, 0xcd, 0xf6, 0x93, 0xfd, 0xde, 0x7e, 0x5f, 0x5b, 0xd2, 0x4d, 0x28, 0x36, 0x8f, 0xed, + 0xe1, 0xc9, 0x45, 0xb3, 0x90, 0xce, 0xea, 0xec, 0xe1, 0x89, 0x34, 0x8a, 0xcd, 0x9c, 0xd5, 0xd9, + 0xc3, 0x13, 0xd2, 0x18, 0xe5, 0x46, 0xf8, 0xbd, 0x2b, 0x0f, 0x21, 0x4a, 0x72, 0x17, 0xfc, 0xde, + 0xd5, 0x5b, 0x50, 0xda, 0xb3, 0x82, 0xc8, 0xa1, 0x4e, 0x7a, 0x0c, 0xd5, 0x38, 0xb1, 0x65, 0x1f, + 0x2a, 0x19, 0x5a, 0xc4, 0x96, 0xb4, 0x18, 0x65, 0x64, 0x09, 0xf5, 0x0f, 0xa1, 0x92, 0x06, 0xa0, + 0x8a, 0x3e, 0xb2, 0x0f, 0x17, 0xec, 0xce, 0x08, 0xd6, 0x9f, 0x43, 0xa5, 0xa9, 0x64, 0xc2, 0x8b, + 0x5a, 0xf6, 0x10, 0x6a, 0xc4, 0xb0, 0x87, 0x07, 0x8a, 0x63, 0x2f, 0x2d, 0xe0, 0xd8, 0x15, 0xa4, + 0x69, 0x1e, 0x48, 0x96, 0xfd, 0x39, 0x94, 0xf7, 0x02, 0x7f, 0x62, 0x07, 0x11, 0x15, 0xab, 0x41, + 0xfe, 0xc4, 0x3e, 0x97, 0xa5, 0xe2, 0xcf, 0xe4, 0x84, 0x75, 0x29, 0x7d, 0xc2, 0xfa, 0x10, 0x8a, + 0x2a, 0xdb, 0x0f, 0xce, 0xf3, 0x33, 0xdc, 0xf9, 0x28, 0x8f, 0x63, 0x87, 0xf8, 0xb1, 0x07, 0x64, + 0x49, 0x91, 0x00, 0xd9, 0x71, 0xca, 0x04, 0x29, 0x0b, 0x37, 0x52, 0x14, 0xfa, 0x9b, 0xb0, 0xfa, + 0xdc, 0xb1, 0x4f, 0x65, 0xf3, 0x5f, 0x3a, 0xf6, 0xa9, 0x6a, 0x3e, 0xfe, 0xd6, 0xff, 0x52, 0x19, + 0x8a, 0xc4, 0x1e, 0xb7, 0x2e, 0x3e, 0xd4, 0xfe, 0x31, 0xfa, 0xc9, 0x1d, 0xc9, 0xae, 0x0a, 0x0b, + 0xb4, 0x22, 0x66, 0x5e, 0x6f, 0x02, 0xa4, 0x58, 0x35, 0x6f, 0x3c, 0xa5, 0x28, 0xe6, 0xd0, 0x28, + 0xd8, 0x93, 0x90, 0x83, 0xd3, 0x88, 0xcf, 0x9b, 0x12, 0x80, 0x78, 0xc0, 0x62, 0x37, 0x9d, 0x30, + 0xad, 0xa6, 0x2d, 0x75, 0xd4, 0x06, 0x65, 0xfe, 0x24, 0x59, 0x1c, 0x13, 0x69, 0xa5, 0xbe, 0x98, + 0x55, 0xea, 0xdf, 0x83, 0x02, 0xee, 0xd1, 0xd2, 0x5c, 0x79, 0x59, 0xf5, 0x60, 0x4a, 0xc8, 0x30, + 0x88, 0x40, 0xdc, 0x83, 0x55, 0xe2, 0x52, 0x36, 0x6e, 0x14, 0xa9, 0xde, 0x56, 0x7b, 0xb6, 0xa1, + 0xd0, 0xe2, 0x7d, 0x58, 0x3e, 0x3c, 0xb1, 0xcf, 0x79, 0x97, 0x88, 0xcb, 0xcc, 0x30, 0x13, 0x83, + 0x29, 0xc4, 0x5d, 0xa8, 0x05, 0xf6, 0xa1, 0x49, 0xc7, 0xdc, 0xc8, 0xc3, 0xc3, 0x7a, 0x8d, 0x58, + 0x74, 0x25, 0xb0, 0x0f, 0x9b, 0x08, 0x1c, 0x1c, 0xb8, 0xa1, 0x78, 0x17, 0x56, 0x68, 0x71, 0xa1, + 0x56, 0x92, 0xfa, 0xb2, 0x5a, 0xa9, 0x86, 0xc4, 0x8a, 0x4f, 0x01, 0xa4, 0xee, 0x63, 0x1e, 0x9c, + 0x93, 0x84, 0x1f, 0x2f, 0xa6, 0xf4, 0xfc, 0x4f, 0x6b, 0x48, 0xef, 0xc1, 0x32, 0x4e, 0x92, 0xb0, + 0x7e, 0x8d, 0x4a, 0x5e, 0xcf, 0xce, 0x20, 0xaa, 0x29, 0xe1, 0xc5, 0x3d, 0x28, 0xe2, 0x44, 0xa1, + 0x55, 0x5d, 0x4f, 0x2b, 0x83, 0x72, 0x56, 0xe1, 0xc6, 0x6e, 0x9f, 0xf6, 0xbf, 0x77, 0xc5, 0x7d, + 0x28, 0x8c, 0x70, 0x31, 0x5f, 0x4f, 0xdb, 0x28, 0xd4, 0xdc, 0x42, 0xdd, 0x91, 0xf4, 0x53, 0xa2, + 0x11, 0x3b, 0x50, 0xc3, 0x69, 0xf4, 0x90, 0x64, 0x35, 0xec, 0xbe, 0xfa, 0x0d, 0xca, 0xf5, 0xd6, + 0x4c, 0xae, 0xae, 0x24, 0xa2, 0xce, 0x6e, 0x79, 0x51, 0x70, 0x6e, 0x54, 0xbd, 0x34, 0x4c, 0xdc, + 0x80, 0xa2, 0x13, 0x76, 0xfc, 0xe1, 0x49, 0xec, 0x81, 0x13, 0xa7, 0xc5, 0x57, 0x50, 0xa5, 0x89, + 0x85, 0x49, 0xfc, 0xb8, 0x74, 0xbf, 0x49, 0x4f, 0x19, 0x85, 0x32, 0xb2, 0x94, 0xb8, 0x83, 0x3a, + 0xa1, 0x19, 0xd9, 0xe3, 0x89, 0x1f, 0xa0, 0x1a, 0xf9, 0xa6, 0x3a, 0x9a, 0x1d, 0x28, 0x10, 0xca, + 0x51, 0xb1, 0x5b, 0xa3, 0xe9, 0x1f, 0x1e, 0x86, 0x76, 0x44, 0xee, 0x36, 0x05, 0xa3, 0xa6, 0xbc, + 0x1b, 0x7b, 0x04, 0x25, 0x39, 0x26, 0x34, 0x47, 0xe7, 0x9e, 0x35, 0x76, 0x86, 0xf5, 0xdb, 0xac, + 0xad, 0x3a, 0xe1, 0x16, 0x03, 0xd2, 0x0a, 0xe3, 0x9d, 0x8c, 0xc2, 0x78, 0x19, 0x96, 0x47, 0x07, + 0xb8, 0x1c, 0xdf, 0xa2, 0x62, 0x0b, 0xa3, 0x83, 0xf6, 0x48, 0x7c, 0x44, 0xc7, 0x6b, 0xcc, 0x02, + 0xeb, 0x7a, 0xfa, 0x80, 0x20, 0xe6, 0x8c, 0x46, 0x42, 0x21, 0xee, 0x40, 0x79, 0xdb, 0xb6, 0xa2, + 0x69, 0x60, 0x6f, 0xbb, 0xd6, 0x51, 0xfd, 0x6d, 0x2a, 0x29, 0x0d, 0xc2, 0xda, 0xb9, 0xfe, 0x91, + 0x33, 0xb4, 0x68, 0xe5, 0xdf, 0x65, 0xb1, 0x59, 0x42, 0xa4, 0x6d, 0x96, 0xd8, 0xb8, 0x25, 0x65, + 0xe1, 0x77, 0xd2, 0x1a, 0x8e, 0xe5, 0xaa, 0x73, 0xe8, 0xa4, 0x2f, 0xec, 0x89, 0x3f, 0x3c, 0xae, + 0xbf, 0x4b, 0xeb, 0xad, 0xaa, 0xba, 0xa2, 0x85, 0x40, 0xf1, 0x1e, 0xac, 0x49, 0xdb, 0x81, 0xa9, + 0x7c, 0x32, 0xdf, 0x23, 0xba, 0x9a, 0x04, 0x37, 0xa5, 0x6b, 0xa6, 0x0e, 0x55, 0x2e, 0x70, 0x64, + 0x0e, 0xad, 0xe1, 0xb1, 0x5d, 0xbf, 0xc7, 0x15, 0xa7, 0xe2, 0x46, 0x4d, 0x04, 0xcd, 0x48, 0x5d, + 0xef, 0xcf, 0x48, 0x5d, 0x8b, 0x3d, 0x22, 0xef, 0x2f, 0xf6, 0x88, 0xbc, 0xf1, 0x84, 0x74, 0x57, + 0x1a, 0xfa, 0xcf, 0x67, 0x38, 0x6c, 0x86, 0x3f, 0xa4, 0x58, 0xf1, 0xce, 0xa5, 0x34, 0xa3, 0xdd, + 0x5c, 0xa6, 0xad, 0xe8, 0xc6, 0xcf, 0x41, 0xcc, 0x4f, 0xda, 0xd7, 0xb1, 0xfb, 0x65, 0xc9, 0xee, + 0xbf, 0x5e, 0x7a, 0x9c, 0xd3, 0xff, 0x89, 0x1c, 0x54, 0x33, 0xec, 0x6c, 0xe1, 0xbe, 0xc5, 0x32, + 0xbf, 0x35, 0x96, 0x96, 0x37, 0x4e, 0x28, 0x4d, 0xd3, 0xf1, 0x8e, 0x5c, 0x3b, 0xa5, 0x69, 0x52, + 0xfa, 0x69, 0xa1, 0x58, 0xd0, 0x96, 0x9f, 0x16, 0x8a, 0xcb, 0xda, 0x8a, 0x71, 0xf9, 0x70, 0xea, + 0xba, 0x91, 0x7d, 0x16, 0xa9, 0x53, 0xd2, 0xc0, 0x3e, 0x34, 0x44, 0x0c, 0x64, 0xb9, 0x2c, 0xb0, + 0x0f, 0xf5, 0xff, 0x22, 0x0f, 0x95, 0x1d, 0x2b, 0x3c, 0xde, 0xb5, 0x26, 0xfd, 0xc8, 0x8a, 0x42, + 0x5c, 0x19, 0xc7, 0x56, 0x78, 0x3c, 0xb6, 0x26, 0xac, 0x4c, 0xe6, 0xf8, 0x8c, 0x42, 0xc2, 0x48, + 0x93, 0xbc, 0x01, 0x45, 0x4c, 0xf6, 0xbc, 0xbd, 0x67, 0xd2, 0xc8, 0x18, 0xa7, 0x91, 0x23, 0x87, + 0xc7, 0xd3, 0xc3, 0xc3, 0xb8, 0x7e, 0x2a, 0x29, 0xee, 0x42, 0x55, 0xfe, 0x24, 0x7d, 0xed, 0x4c, + 0x9e, 0xf3, 0x66, 0x81, 0xe2, 0x11, 0x94, 0x25, 0x60, 0xa0, 0xf6, 0x8f, 0x5a, 0x7c, 0x74, 0x95, + 0x20, 0x8c, 0x34, 0x95, 0xf8, 0x05, 0x5c, 0x49, 0x25, 0xb7, 0xfd, 0x60, 0x77, 0xea, 0x46, 0x4e, + 0xb3, 0x2b, 0x85, 0xd7, 0x37, 0xe6, 0xb2, 0x27, 0x24, 0xc6, 0xe2, 0x9c, 0xd9, 0xda, 0xee, 0x3a, + 0x7c, 0x02, 0x90, 0x37, 0xb2, 0xc0, 0x19, 0x2a, 0xeb, 0x8c, 0x76, 0xa1, 0x2c, 0x95, 0x75, 0x86, + 0x7c, 0x4a, 0x02, 0x76, 0xed, 0xe8, 0xd8, 0x1f, 0x49, 0x69, 0xf4, 0x72, 0xa6, 0x5a, 0x8c, 0x32, + 0xb2, 0x94, 0xd8, 0x9d, 0xde, 0xd4, 0x75, 0x87, 0x5e, 0x44, 0xfa, 0x51, 0xde, 0x50, 0x49, 0xdc, + 0xa1, 0x03, 0xcb, 0x3b, 0xb2, 0xc3, 0x7a, 0xf9, 0x4e, 0xfe, 0x5e, 0xce, 0x90, 0x29, 0xfd, 0xaf, + 0x2e, 0xc1, 0x32, 0x8f, 0xe4, 0x1b, 0x50, 0x3a, 0x20, 0xef, 0x1d, 0x6f, 0x3a, 0x56, 0xc7, 0x0f, + 0x04, 0xe8, 0x4e, 0xc7, 0xac, 0x77, 0x48, 0x23, 0x71, 0xce, 0xa0, 0xdf, 0x58, 0xa4, 0x3f, 0x8d, + 0xf0, 0x5b, 0x79, 0x82, 0xca, 0x14, 0x56, 0x22, 0xf0, 0x4f, 0x69, 0x36, 0x14, 0x08, 0xa1, 0x92, + 0xe4, 0xc8, 0x43, 0x9b, 0x3d, 0x66, 0x5a, 0x26, 0x5c, 0x91, 0x00, 0x4d, 0x2f, 0x9a, 0x3d, 0xec, + 0x5a, 0x99, 0x3f, 0xec, 0xba, 0x05, 0xa8, 0xd5, 0x0c, 0xed, 0x9e, 0x67, 0x37, 0xbb, 0xf2, 0x44, + 0x3d, 0x05, 0xc1, 0x65, 0x35, 0xf2, 0x27, 0xf2, 0xa8, 0x1c, 0x7f, 0x8a, 0x2f, 0xe2, 0xd9, 0x49, + 0x6d, 0x94, 0x3a, 0xa6, 0xdc, 0x0c, 0xd3, 0xf3, 0xd8, 0xc8, 0xd0, 0x61, 0x49, 0xb8, 0xc3, 0xb1, + 0x8e, 0x89, 0x3f, 0xf5, 0x16, 0x80, 0xe1, 0x9f, 0x86, 0x36, 0x1f, 0x60, 0x5d, 0xa3, 0x26, 0x66, + 0x7c, 0xf6, 0xfc, 0xd3, 0x3d, 0x3f, 0x8c, 0x0d, 0x44, 0x4b, 0x8b, 0x0d, 0x44, 0xfa, 0xc7, 0xb0, + 0x8a, 0xe2, 0x8f, 0x15, 0x59, 0xe2, 0xae, 0xb4, 0x95, 0xb3, 0xd0, 0xa6, 0x29, 0xcf, 0x11, 0xf5, + 0x0d, 0x69, 0x72, 0xef, 0xa8, 0xef, 0x52, 0x9e, 0xb7, 0x52, 0x86, 0x8e, 0x78, 0xeb, 0x95, 0x05, + 0x4a, 0x81, 0x8a, 0x4e, 0x91, 0x4e, 0x4d, 0x72, 0x4e, 0x52, 0xfe, 0x16, 0x81, 0x7f, 0xda, 0xc4, + 0xb4, 0xfe, 0x77, 0x73, 0x50, 0xee, 0x05, 0x23, 0xdc, 0xf3, 0xe9, 0x94, 0xe3, 0x75, 0xf6, 0x2c, + 0x14, 0xbf, 0x14, 0x6f, 0x54, 0x86, 0x86, 0x18, 0x20, 0x3e, 0x85, 0xc2, 0x21, 0xee, 0x22, 0xf9, + 0xb4, 0xce, 0x97, 0x2a, 0x5e, 0xfd, 0xc6, 0x7d, 0xc5, 0x20, 0x52, 0xfd, 0x77, 0xe2, 0xef, 0xd3, + 0x66, 0x93, 0x76, 0x7c, 0xb9, 0x44, 0x8e, 0x77, 0xfd, 0xa6, 0x96, 0x13, 0x45, 0x28, 0x6c, 0xb5, + 0xfa, 0x4d, 0xd6, 0x8b, 0x50, 0x43, 0xea, 0x9b, 0xdb, 0x6d, 0xa3, 0x3f, 0xe0, 0x63, 0x1c, 0x06, + 0x74, 0x1a, 0xfd, 0x81, 0x56, 0x14, 0x00, 0x2b, 0xfb, 0xdd, 0xf6, 0x2f, 0xf6, 0x5b, 0x9a, 0xa6, + 0xff, 0xed, 0x1c, 0x40, 0x72, 0xa6, 0x2d, 0x3e, 0x80, 0xf2, 0x29, 0xa5, 0xcc, 0x94, 0x0b, 0x52, + 0xe6, 0x4c, 0x8e, 0xd1, 0x24, 0x1a, 0x7e, 0x04, 0x95, 0x78, 0x97, 0x44, 0xb1, 0x69, 0xde, 0x17, + 0xa9, 0x1c, 0xe3, 0x37, 0xcf, 0xc5, 0x87, 0x50, 0xf4, 0xb1, 0x1d, 0x48, 0x9a, 0x4f, 0xcb, 0x4c, + 0xa9, 0xe6, 0xd3, 0x09, 0xa8, 0x12, 0xaf, 0x0e, 0x03, 0x65, 0x38, 0x8a, 0x49, 0xb7, 0x11, 0xd4, + 0x74, 0xad, 0x69, 0x68, 0x1b, 0x8c, 0x8f, 0x59, 0xfb, 0x72, 0xc2, 0xda, 0xf5, 0x5f, 0x42, 0xad, + 0x6f, 0x8d, 0x27, 0xbc, 0x01, 0x50, 0xc3, 0x04, 0x14, 0x70, 0x4e, 0xc8, 0xa9, 0x47, 0xbf, 0x71, + 0xd1, 0xed, 0xd9, 0xc1, 0xd0, 0xf6, 0xd4, 0x1a, 0x55, 0x49, 0x64, 0xbf, 0xfb, 0xb8, 0x05, 0x18, + 0xfe, 0xa9, 0xda, 0x03, 0x54, 0x5a, 0xff, 0x57, 0x72, 0x50, 0x4e, 0x55, 0x43, 0x7c, 0x0c, 0x05, + 0x92, 0xc3, 0x73, 0x69, 0x46, 0x98, 0x22, 0xe0, 0xdf, 0x2c, 0xb9, 0x21, 0xa1, 0x78, 0x17, 0x96, + 0xc3, 0xc8, 0x0a, 0x94, 0x7b, 0x84, 0x96, 0xca, 0xb1, 0xe9, 0x4f, 0xbd, 0x91, 0xc1, 0x68, 0xa1, + 0x43, 0xde, 0xf6, 0x46, 0xd2, 0xd4, 0x36, 0x4f, 0x85, 0x48, 0xfd, 0x0e, 0x94, 0xe2, 0xe2, 0x71, + 0x0a, 0x18, 0xbd, 0x17, 0x7d, 0xed, 0x12, 0x1d, 0xd4, 0x35, 0xba, 0x4f, 0x5a, 0x5a, 0x4e, 0xff, + 0x1b, 0x39, 0x80, 0x24, 0x97, 0x78, 0x90, 0xa9, 0xed, 0x8d, 0xd9, 0x52, 0x1f, 0xd0, 0xdf, 0x54, + 0x65, 0x6f, 0x42, 0x69, 0xea, 0x11, 0xd0, 0x1e, 0xc9, 0x9d, 0x28, 0x01, 0xa0, 0xf2, 0xa8, 0x6e, + 0x21, 0xcc, 0x28, 0x8f, 0x2f, 0x2d, 0x57, 0xff, 0x1a, 0x4a, 0x71, 0x71, 0xa8, 0x9c, 0x6f, 0xf7, + 0x3a, 0x9d, 0xde, 0x8b, 0x76, 0xf7, 0x09, 0x1f, 0x4b, 0xee, 0x19, 0xad, 0x66, 0x6b, 0x0b, 0x93, + 0x39, 0x9c, 0xb3, 0xcd, 0x7d, 0xc3, 0x68, 0x75, 0x07, 0x74, 0xf4, 0xb8, 0xa4, 0xff, 0x85, 0x1c, + 0x54, 0x7b, 0xee, 0xa8, 0xe9, 0xbb, 0x4d, 0x6b, 0x82, 0x82, 0x96, 0xf8, 0x19, 0xac, 0x1f, 0x4c, + 0x51, 0xd8, 0x9f, 0xb8, 0xd6, 0xd0, 0x3e, 0xf6, 0xdd, 0x91, 0xad, 0x16, 0x61, 0xc6, 0x01, 0x44, + 0x9e, 0xd0, 0x68, 0x44, 0xbc, 0x97, 0xd0, 0x8a, 0xcf, 0xa1, 0x32, 0x09, 0xfc, 0x03, 0x5b, 0x1d, + 0x97, 0x2d, 0x5d, 0x98, 0xb7, 0x4c, 0x74, 0x7c, 0x82, 0xa6, 0xff, 0xc7, 0xcb, 0x50, 0xd9, 0xb2, + 0x47, 0xd3, 0xc9, 0x53, 0xdf, 0xf1, 0x9a, 0xd1, 0x99, 0xf8, 0x0c, 0x2a, 0xbe, 0x4b, 0x06, 0x2d, + 0x33, 0xe5, 0x30, 0xbc, 0xa8, 0x1c, 0xf0, 0xa9, 0x05, 0xe4, 0x5e, 0xfc, 0x11, 0x5c, 0x96, 0xf6, + 0x12, 0xb6, 0xae, 0x9e, 0x71, 0x66, 0x5c, 0x33, 0xcb, 0x86, 0xc6, 0x28, 0xde, 0xa0, 0x89, 0xfc, + 0x27, 0xb0, 0x91, 0x22, 0x47, 0xc6, 0xc2, 0xf4, 0xf9, 0xb9, 0x35, 0xb6, 0x1e, 0xe7, 0x8d, 0x5d, + 0x99, 0x9f, 0xc2, 0x86, 0xaa, 0xe1, 0x90, 0x7b, 0x8f, 0x33, 0x17, 0xd2, 0x5a, 0x55, 0xa6, 0x77, + 0x65, 0x85, 0xd7, 0xfd, 0x34, 0x90, 0xca, 0xfa, 0x14, 0xae, 0x8c, 0xb0, 0xf5, 0x26, 0x77, 0xfe, + 0x89, 0x6d, 0x4f, 0x4c, 0x37, 0xe5, 0xe7, 0x47, 0xc8, 0x4d, 0xc4, 0x3d, 0xb3, 0xed, 0x49, 0xc7, + 0x0a, 0x23, 0xf1, 0x18, 0xd6, 0xad, 0xc3, 0x43, 0xf6, 0x2f, 0xc2, 0x6d, 0x6c, 0xa1, 0x15, 0xd7, + 0xb0, 0x0f, 0x8d, 0x35, 0x45, 0x86, 0xcb, 0xb1, 0xe9, 0xbb, 0xe2, 0x09, 0x5c, 0x9f, 0x1c, 0x9f, + 0x87, 0x24, 0x49, 0x0f, 0x8f, 0x71, 0xb7, 0x4d, 0x95, 0xb0, 0xba, 0xa0, 0x84, 0xab, 0x8a, 0xbc, + 0xc9, 0xd4, 0xaa, 0xa0, 0xc7, 0x70, 0x5d, 0x75, 0x1f, 0x2a, 0x78, 0xd9, 0x3e, 0x2f, 0x52, 0x9f, + 0x5f, 0x91, 0xfd, 0x86, 0xf8, 0x54, 0xc7, 0xdf, 0x03, 0x8d, 0x1d, 0x57, 0x0f, 0xc9, 0xbd, 0x1e, + 0xbf, 0x2e, 0x2f, 0x36, 0xd5, 0x08, 0xbe, 0x4d, 0x8b, 0x0f, 0xd9, 0xc7, 0x3d, 0xd0, 0xec, 0xb1, + 0x13, 0x99, 0x16, 0x89, 0x98, 0x4c, 0xc9, 0x67, 0x6f, 0x35, 0x84, 0x4b, 0xbb, 0x1d, 0x52, 0x7e, + 0x01, 0x9a, 0x24, 0x3a, 0x24, 0x25, 0x00, 0x5b, 0x53, 0x5e, 0xd0, 0x9a, 0x1a, 0x53, 0x6d, 0x23, + 0x11, 0xb6, 0x62, 0x17, 0x84, 0x32, 0x42, 0x92, 0x69, 0x85, 0x35, 0x59, 0xd6, 0xa1, 0xa5, 0xa3, + 0x66, 0x6f, 0xeb, 0xd9, 0x7e, 0xa2, 0x1f, 0x53, 0x63, 0xd4, 0x02, 0x38, 0xcc, 0x82, 0x43, 0xfd, + 0x3f, 0x58, 0x81, 0x12, 0xdb, 0xdd, 0x70, 0x1a, 0xdf, 0x83, 0x55, 0xff, 0xe0, 0x3b, 0x94, 0x50, + 0x2f, 0xf2, 0x34, 0x5d, 0xf1, 0x0f, 0xbe, 0x33, 0xec, 0x43, 0xf1, 0x81, 0x12, 0x41, 0x46, 0xf6, + 0xa1, 0x5c, 0x35, 0xb5, 0xac, 0x96, 0x29, 0x45, 0x92, 0x2d, 0xfb, 0x10, 0xa5, 0x4b, 0xc7, 0x0b, + 0xed, 0x20, 0x62, 0xbb, 0xe9, 0xea, 0xc5, 0x8b, 0x83, 0xc9, 0xc8, 0x94, 0xfa, 0x08, 0xca, 0xd2, + 0x36, 0x49, 0x99, 0x8a, 0x17, 0x67, 0x62, 0x32, 0xca, 0xf4, 0x15, 0xd4, 0x92, 0xed, 0x87, 0xf2, + 0x95, 0x2e, 0xcc, 0x57, 0x8d, 0x29, 0x29, 0xeb, 0x43, 0xb8, 0x1a, 0x9e, 0x38, 0x13, 0x53, 0xd6, + 0xd4, 0xf7, 0xe8, 0x10, 0xd7, 0x9c, 0x9c, 0xc8, 0x01, 0x14, 0x88, 0x6d, 0x13, 0xb2, 0xe7, 0x75, + 0xa7, 0xae, 0xbb, 0x77, 0x22, 0xde, 0x87, 0x75, 0x49, 0x3e, 0x89, 0xe7, 0x13, 0x8d, 0xe2, 0xb2, + 0x51, 0x63, 0xc4, 0x9e, 0x9c, 0x47, 0xe2, 0x4b, 0xa8, 0xf3, 0x1c, 0x92, 0x8d, 0xe2, 0x69, 0xce, + 0x33, 0x84, 0x4f, 0x5a, 0xaf, 0x10, 0x9e, 0x6d, 0xaa, 0x0d, 0xc2, 0xd2, 0x44, 0xf9, 0x04, 0x36, + 0x9c, 0x23, 0xcf, 0x0f, 0x54, 0x16, 0x39, 0xfd, 0xe5, 0x11, 0xac, 0x60, 0x5c, 0x23, 0xb5, 0x68, + 0xb0, 0x25, 0x72, 0x79, 0x9e, 0x9b, 0x11, 0xb9, 0x8a, 0x61, 0x0e, 0x54, 0x43, 0x6b, 0xe9, 0xf5, + 0x79, 0xce, 0x6e, 0x64, 0x86, 0x7f, 0xda, 0x1e, 0xe1, 0x92, 0x96, 0xa4, 0x6a, 0x8d, 0x44, 0x67, + 0xd4, 0x9a, 0x35, 0x6a, 0x8d, 0x60, 0x64, 0x3c, 0x53, 0xb0, 0x45, 0x3f, 0x07, 0x31, 0xb7, 0xa4, + 0xc3, 0xba, 0x76, 0x61, 0x7f, 0x6b, 0x33, 0x2b, 0x9b, 0xd6, 0xc0, 0xdc, 0x8a, 0x5e, 0x5f, 0xb4, + 0x06, 0x86, 0xd9, 0x95, 0xdc, 0x82, 0x7a, 0xf6, 0xcb, 0xa7, 0xb6, 0x73, 0x74, 0x4c, 0xb3, 0x4b, + 0xde, 0xab, 0xca, 0xe6, 0xbf, 0x92, 0xfe, 0xf2, 0x0b, 0xa2, 0x7d, 0x2d, 0x67, 0xb9, 0xfc, 0xc3, + 0x39, 0x8b, 0xfe, 0xaf, 0xe5, 0xa0, 0xc4, 0x33, 0x03, 0x17, 0xd1, 0x5b, 0x90, 0x7f, 0xc5, 0x02, + 0x42, 0x9c, 0xb8, 0x0f, 0xeb, 0xd6, 0x68, 0x34, 0x33, 0xa0, 0xbc, 0x93, 0xae, 0x59, 0xa3, 0x51, + 0x66, 0x34, 0xef, 0x81, 0xe6, 0x84, 0xa6, 0xb2, 0x44, 0x25, 0xde, 0xe8, 0x45, 0xa3, 0xe6, 0x84, + 0xd2, 0x10, 0xc5, 0xa7, 0x96, 0x99, 0x35, 0x59, 0x78, 0xf5, 0x9a, 0xd4, 0x05, 0x80, 0x61, 0xd3, + 0xb6, 0xd9, 0x8c, 0xce, 0x9e, 0x16, 0x8a, 0x39, 0x0d, 0xf4, 0xff, 0xac, 0x0c, 0xe5, 0x86, 0x67, + 0xb9, 0xe7, 0xbf, 0xb2, 0xc9, 0x95, 0x9e, 0x4e, 0x8a, 0x26, 0x53, 0x39, 0x4b, 0xd9, 0x8f, 0xa3, + 0x44, 0x10, 0xaa, 0xd9, 0x6d, 0x90, 0x2e, 0x4f, 0x49, 0xfd, 0xf3, 0x06, 0x30, 0x88, 0x08, 0xe2, + 0xfc, 0xf1, 0xf9, 0xa8, 0xca, 0x4f, 0x0a, 0x6d, 0x92, 0x3f, 0x56, 0x72, 0xe2, 0xfc, 0x44, 0xf0, + 0x36, 0x54, 0x23, 0x67, 0x4c, 0x97, 0x35, 0xc3, 0xe9, 0xd8, 0x1e, 0xf1, 0x35, 0x45, 0xbe, 0xf9, + 0xd6, 0x94, 0x30, 0x2c, 0x65, 0x6c, 0x8f, 0xfd, 0xe0, 0x9c, 0x4b, 0x59, 0xe1, 0x52, 0x18, 0x44, + 0xa5, 0x7c, 0x08, 0xe2, 0xd4, 0x72, 0x22, 0x33, 0x5b, 0x14, 0x2b, 0x96, 0x1a, 0x62, 0x06, 0xe9, + 0xe2, 0xae, 0xc2, 0xca, 0xc8, 0x09, 0x4f, 0xda, 0x3d, 0xa9, 0x54, 0xca, 0x14, 0xb6, 0x25, 0x1c, + 0x5a, 0x28, 0xd3, 0x46, 0x36, 0x73, 0xff, 0xbc, 0x51, 0x42, 0xc8, 0x26, 0x02, 0x50, 0x26, 0xf2, + 0xec, 0xe8, 0xd4, 0x0f, 0x30, 0x27, 0xeb, 0x8c, 0x09, 0x00, 0x65, 0x47, 0x24, 0xc5, 0x0f, 0x11, + 0x7b, 0xc8, 0x1b, 0x71, 0x1a, 0xb5, 0x31, 0x66, 0x15, 0x84, 0xad, 0x70, 0xf5, 0x13, 0x88, 0xb8, + 0x0b, 0x35, 0xaa, 0x3e, 0xe9, 0x94, 0xd8, 0x06, 0x5a, 0xf9, 0x79, 0xa3, 0x82, 0x50, 0xb2, 0xac, + 0x21, 0xd5, 0x57, 0x70, 0x3d, 0xd3, 0x3e, 0xd3, 0x0a, 0x02, 0xeb, 0xdc, 0x1c, 0x5b, 0xdf, 0xf9, + 0x01, 0x59, 0x41, 0xf3, 0xc6, 0xd5, 0x74, 0xb7, 0x35, 0x10, 0xbd, 0x8b, 0xd8, 0x0b, 0xb3, 0x3a, + 0x9e, 0x1f, 0x90, 0x89, 0x74, 0x61, 0x56, 0xc4, 0x92, 0x3d, 0x8f, 0x06, 0x98, 0x14, 0xdc, 0x90, + 0x6f, 0x4c, 0x1a, 0xec, 0x61, 0xb7, 0x49, 0x20, 0x54, 0xf1, 0xc2, 0x47, 0xbc, 0xc7, 0xae, 0xcb, + 0x7b, 0x3c, 0x8f, 0x68, 0x53, 0x65, 0xc4, 0xb1, 0x6d, 0x8d, 0x68, 0xcd, 0x12, 0x62, 0xc7, 0xb6, + 0xe8, 0xb6, 0x57, 0xf8, 0xc8, 0x9c, 0x4c, 0x23, 0xbe, 0xea, 0x68, 0x2c, 0x87, 0x8f, 0xf6, 0xa6, + 0x91, 0x04, 0x1f, 0xd9, 0x11, 0xf9, 0x6f, 0x10, 0xf8, 0x09, 0xdf, 0x36, 0x0e, 0x1f, 0xa9, 0x13, + 0xb7, 0x2b, 0xb2, 0x6f, 0x1f, 0xc9, 0x23, 0x35, 0x1d, 0xaa, 0x31, 0xd2, 0x1c, 0x4f, 0xf9, 0x6e, + 0x63, 0xde, 0x28, 0x2b, 0x82, 0xdd, 0xa9, 0x8b, 0x03, 0x4b, 0xb6, 0x30, 0x33, 0xc0, 0xaa, 0x5c, + 0xe3, 0xa1, 0x23, 0x88, 0x81, 0xb5, 0x79, 0x03, 0x38, 0x61, 0x1e, 0x3b, 0xec, 0xc6, 0x9a, 0x37, + 0x8a, 0x04, 0xd8, 0x71, 0x22, 0x5c, 0xc7, 0x8c, 0x94, 0x33, 0x90, 0x8a, 0xb8, 0x4e, 0x44, 0x6b, + 0x84, 0xd8, 0x25, 0x38, 0x15, 0x84, 0x42, 0x44, 0x9a, 0x16, 0xcb, 0xbb, 0x41, 0xa4, 0xb5, 0x14, + 0x29, 0x96, 0xfa, 0x2e, 0x70, 0x66, 0x13, 0xa7, 0x1e, 0x97, 0xf9, 0x06, 0x1b, 0x38, 0x08, 0xbc, + 0xe5, 0x84, 0x27, 0x54, 0xe2, 0x5d, 0xa8, 0xa5, 0xe8, 0xb0, 0xbc, 0x9b, 0x3c, 0x33, 0x62, 0xb2, + 0x4c, 0x1d, 0x03, 0x7b, 0xec, 0x47, 0xb2, 0x99, 0x6f, 0xa6, 0xea, 0x68, 0x10, 0x3c, 0x5b, 0x47, + 0x49, 0x8b, 0x65, 0xde, 0x4a, 0xd5, 0x91, 0x49, 0xb1, 0xd4, 0xb7, 0xa0, 0x72, 0x1a, 0x38, 0x51, + 0x64, 0x4b, 0x21, 0xe7, 0x36, 0x77, 0xac, 0x84, 0xd1, 0xea, 0x7f, 0x0b, 0x2a, 0xdc, 0xf3, 0x92, + 0xbf, 0xdd, 0x61, 0x12, 0x09, 0x53, 0x0c, 0x42, 0xf6, 0xc6, 0xd8, 0xf1, 0xc8, 0x1e, 0x9b, 0x37, + 0x4a, 0x0c, 0xd9, 0x75, 0xbc, 0x34, 0xda, 0x3a, 0x23, 0xab, 0x6c, 0x82, 0xb6, 0xce, 0x68, 0x49, + 0x4e, 0x1c, 0xd7, 0xe5, 0x85, 0xff, 0xb6, 0x5c, 0x92, 0x08, 0xa1, 0x75, 0x1f, 0xa3, 0xe9, 0xeb, + 0x77, 0x53, 0x68, 0xfa, 0x36, 0x4e, 0x1c, 0x42, 0xe3, 0xa7, 0xdf, 0x91, 0x13, 0x07, 0x01, 0xf8, + 0xe5, 0x04, 0x69, 0x9d, 0x91, 0xcd, 0x35, 0x46, 0x5a, 0x67, 0x92, 0x6f, 0xd1, 0x4e, 0x81, 0x79, + 0xdf, 0x8b, 0xf9, 0x16, 0x82, 0x30, 0x77, 0x9a, 0xc0, 0x3a, 0x23, 0x23, 0x6b, 0x8a, 0xc0, 0x3a, + 0x23, 0xe3, 0x82, 0x6d, 0x8d, 0xb8, 0xe2, 0xef, 0x73, 0xf1, 0x08, 0xa0, 0x7a, 0xdf, 0x81, 0x4a, + 0xf8, 0xc8, 0x4c, 0xf0, 0xf7, 0x39, 0x7b, 0xf8, 0xc8, 0x50, 0x14, 0x77, 0xa1, 0x16, 0x4f, 0x0d, + 0xa6, 0xf9, 0x80, 0x07, 0x7e, 0x24, 0xa7, 0x06, 0x5d, 0xe6, 0xfb, 0x75, 0x0e, 0x6e, 0xf0, 0x19, + 0x27, 0xb1, 0xff, 0x5d, 0x3b, 0x0c, 0xad, 0x23, 0x7b, 0xdb, 0x0f, 0xb6, 0xa7, 0xbf, 0xfa, 0xd5, + 0xb9, 0xb8, 0x07, 0x6b, 0x7b, 0x56, 0x60, 0x7b, 0x51, 0xec, 0x99, 0x20, 0x2d, 0xa1, 0xb3, 0x60, + 0xf1, 0x18, 0x34, 0x06, 0xf1, 0x1d, 0xa6, 0xa6, 0x3a, 0x38, 0x9f, 0x3d, 0x89, 0x9a, 0xa3, 0xd2, + 0xff, 0x6e, 0x0e, 0x4a, 0x5b, 0x4e, 0x18, 0x19, 0xb8, 0x5d, 0x8a, 0xaf, 0x40, 0x73, 0xfd, 0x53, + 0x54, 0xf6, 0x49, 0x8c, 0x4e, 0xe9, 0x9c, 0x72, 0x97, 0x4c, 0x14, 0xcd, 0x1a, 0x11, 0x26, 0x9a, + 0xe2, 0x57, 0xa0, 0x4d, 0x27, 0x93, 0x6c, 0xd6, 0xa5, 0x0b, 0xb2, 0x12, 0x61, 0x92, 0xf5, 0x03, + 0x28, 0xa7, 0xbe, 0xba, 0x40, 0x2f, 0x85, 0xe4, 0x5b, 0x48, 0x9c, 0xfa, 0xce, 0x82, 0x3b, 0x94, + 0x90, 0x94, 0xae, 0xff, 0xeb, 0x4b, 0xa0, 0x91, 0x35, 0xda, 0x20, 0xef, 0x35, 0x72, 0x70, 0xc8, + 0x58, 0x34, 0x72, 0xaf, 0xb5, 0x68, 0xdc, 0x81, 0x65, 0xd7, 0x19, 0xc7, 0xd7, 0x22, 0x32, 0x27, + 0xc0, 0x84, 0xc0, 0xb1, 0xf6, 0x03, 0xe7, 0x88, 0x6c, 0x2f, 0xe9, 0x6b, 0x75, 0x74, 0x52, 0xb0, + 0x3d, 0xf5, 0x86, 0x34, 0x44, 0x0f, 0x00, 0x46, 0x4e, 0x18, 0x99, 0x64, 0x8d, 0x94, 0xd5, 0x96, + 0x3d, 0x13, 0xf7, 0xbf, 0x51, 0x1a, 0xc5, 0x43, 0x71, 0x0f, 0xb4, 0x94, 0x9c, 0xec, 0xc5, 0x86, + 0xc4, 0x65, 0x23, 0x91, 0x9f, 0x9b, 0x5e, 0xd3, 0x8b, 0xe6, 0x28, 0x51, 0x26, 0x5c, 0x99, 0xa3, + 0x44, 0x79, 0xf0, 0x1e, 0x68, 0xfe, 0x4b, 0x3b, 0x30, 0x0f, 0xed, 0x68, 0x78, 0x6c, 0x72, 0xb3, + 0x56, 0xf9, 0xe4, 0x06, 0xe1, 0xdb, 0x08, 0xee, 0x20, 0x54, 0x3f, 0x83, 0xcb, 0xd4, 0x6f, 0x3b, + 0x74, 0xba, 0x49, 0x13, 0x4d, 0xde, 0x81, 0x0e, 0x7c, 0x37, 0x36, 0xc8, 0xe3, 0x6f, 0xf1, 0x1e, + 0xa0, 0xc6, 0x61, 0x0f, 0x55, 0x0f, 0x2d, 0x54, 0x48, 0xec, 0x21, 0xf6, 0xd3, 0x72, 0x22, 0x1b, + 0xcd, 0x0b, 0x3e, 0x8c, 0xd4, 0xff, 0xaf, 0x15, 0x58, 0xe3, 0x6b, 0x80, 0xb6, 0x15, 0x0c, 0x8f, + 0xe9, 0x32, 0xe0, 0x43, 0xa8, 0x48, 0x6b, 0x7d, 0xe2, 0x14, 0xb6, 0xe0, 0x43, 0x65, 0x26, 0x62, + 0x51, 0xeb, 0x31, 0x68, 0xe9, 0x3c, 0xaf, 0xd0, 0x82, 0x6a, 0xa9, 0x6c, 0xa8, 0x0b, 0xdd, 0x85, + 0x65, 0x3e, 0x9a, 0xcb, 0xd4, 0x33, 0x3e, 0xf6, 0x64, 0xa4, 0xf8, 0x6d, 0xa8, 0xf2, 0xd1, 0xaf, + 0x29, 0x6f, 0x3d, 0x16, 0xd2, 0x0a, 0xde, 0x82, 0xce, 0x33, 0x2a, 0xc7, 0x49, 0x3a, 0x14, 0x1f, + 0x43, 0x95, 0x5c, 0xf4, 0xcd, 0x89, 0x75, 0xee, 0xfa, 0xd6, 0x28, 0xeb, 0xb4, 0x4a, 0xf3, 0xab, + 0x42, 0x04, 0x7b, 0x8c, 0x17, 0x1f, 0xc0, 0x3a, 0xce, 0x0e, 0xcb, 0x1b, 0xda, 0x34, 0xd5, 0xc8, + 0x52, 0xc9, 0x07, 0xc5, 0x9a, 0x42, 0xc4, 0x27, 0x27, 0x3f, 0x81, 0xd2, 0xc8, 0x09, 0x6c, 0x26, + 0x5a, 0xfd, 0x21, 0x56, 0xcb, 0x84, 0x5e, 0x3c, 0xc2, 0xdd, 0xcd, 0x1b, 0x39, 0xa4, 0x65, 0xf0, + 0x2c, 0x29, 0xce, 0x55, 0xae, 0x16, 0x93, 0xd0, 0x8c, 0x11, 0x5f, 0x10, 0xc7, 0xe3, 0xea, 0xf1, + 0x1c, 0x2f, 0x2d, 0x9e, 0xe3, 0x55, 0x45, 0xc6, 0xf3, 0xfc, 0x03, 0x28, 0x4f, 0x02, 0xdb, 0x3c, + 0x74, 0xdc, 0xc8, 0x0e, 0x50, 0x15, 0x9f, 0xb5, 0x94, 0xc0, 0x24, 0xb0, 0xb7, 0x19, 0xbb, 0xd0, + 0x35, 0xa9, 0xbc, 0xd8, 0x35, 0xe9, 0x11, 0x54, 0x49, 0x1a, 0x8c, 0xaf, 0xe1, 0x6a, 0x0b, 0xaf, + 0xe1, 0x56, 0x90, 0x48, 0xa5, 0xc4, 0x23, 0xb8, 0x3a, 0xf1, 0xc3, 0x48, 0xd6, 0xc6, 0x4c, 0x16, + 0x0b, 0x49, 0x46, 0x45, 0xe3, 0x32, 0x62, 0xb9, 0x32, 0x3d, 0xb5, 0x60, 0xc4, 0x17, 0x40, 0x52, + 0xa6, 0x89, 0x92, 0xa4, 0x54, 0x6e, 0xd2, 0xb3, 0x20, 0x99, 0xc7, 0x2f, 0xfc, 0xe0, 0x84, 0xc5, + 0x4a, 0xfc, 0x45, 0xd7, 0x6d, 0xdd, 0x23, 0xdf, 0x64, 0xa7, 0xaf, 0x90, 0x64, 0xa9, 0x8a, 0x51, + 0x46, 0x18, 0xfb, 0x83, 0x61, 0x7b, 0x81, 0x48, 0xec, 0xb3, 0x49, 0x10, 0xd6, 0x37, 0xe6, 0xfa, + 0xa6, 0x84, 0x58, 0xfc, 0x15, 0xd2, 0x49, 0xa4, 0x22, 0x35, 0xd9, 0x41, 0xef, 0x0a, 0xf5, 0x4c, + 0x55, 0xd1, 0x20, 0x1b, 0x0a, 0x9f, 0x16, 0x8a, 0x15, 0xad, 0xfa, 0xb4, 0x50, 0xac, 0x6a, 0x35, + 0xf6, 0xcf, 0x7a, 0x5a, 0x28, 0xae, 0x69, 0x9a, 0xfe, 0xd7, 0x3f, 0x82, 0x02, 0xdd, 0x71, 0xf8, + 0x04, 0x4a, 0x74, 0xe1, 0x30, 0xc5, 0xfc, 0xa5, 0xed, 0x09, 0xd1, 0xf4, 0x87, 0xb8, 0x78, 0xd1, + 0x93, 0xbf, 0x2e, 0xbe, 0xf9, 0xfe, 0x16, 0xd9, 0x4c, 0xc9, 0x3f, 0x0f, 0x7b, 0xa5, 0xac, 0xc2, + 0x3f, 0x58, 0x51, 0x68, 0x30, 0x06, 0xe5, 0x6e, 0x72, 0x06, 0x08, 0x6c, 0x8f, 0x56, 0xd0, 0xb2, + 0x11, 0xa7, 0xc9, 0x52, 0xcd, 0x97, 0xda, 0x58, 0x3a, 0x5d, 0x5e, 0x60, 0xa9, 0x66, 0x3c, 0x89, + 0xab, 0x9f, 0x40, 0xe9, 0x3b, 0xdf, 0xf1, 0xb8, 0xe2, 0x2b, 0x73, 0x15, 0x7f, 0xea, 0x3b, 0x1e, + 0x57, 0xfc, 0x3b, 0xf9, 0x4b, 0xbc, 0x0d, 0xab, 0xbe, 0xc7, 0x65, 0xaf, 0xce, 0xdf, 0x86, 0xf1, + 0xbd, 0x0e, 0x5f, 0xca, 0xaa, 0x3a, 0xa1, 0x19, 0x90, 0xfa, 0x8a, 0x39, 0xa5, 0x5f, 0x5f, 0xd9, + 0x09, 0x0d, 0x84, 0x61, 0xb1, 0x38, 0x89, 0xe5, 0x94, 0xa1, 0xc2, 0x4a, 0xf3, 0x93, 0x98, 0xd1, + 0x54, 0xe0, 0x3b, 0x50, 0x3c, 0x0a, 0x7c, 0x52, 0xfe, 0x17, 0x4c, 0xf7, 0x55, 0xc2, 0x6d, 0x9e, + 0xa3, 0x6a, 0x45, 0x3f, 0x1d, 0xef, 0xc8, 0xa4, 0xc3, 0x07, 0x9c, 0xe8, 0x45, 0xa3, 0xa2, 0x80, + 0x74, 0xac, 0xf0, 0x0e, 0x14, 0xad, 0xa3, 0x23, 0x53, 0xde, 0x2d, 0x9b, 0x2b, 0xcb, 0x3a, 0x3a, + 0xa2, 0x4f, 0x3e, 0x80, 0xea, 0xa9, 0xe3, 0x99, 0xe1, 0xc4, 0x1e, 0x32, 0x6d, 0x75, 0xbe, 0x2b, + 0x4f, 0x1d, 0xba, 0x0f, 0x42, 0xf4, 0xe9, 0x2d, 0xb2, 0xf6, 0xc3, 0xb7, 0xc8, 0xb5, 0x8b, 0xb6, + 0x48, 0x1d, 0x56, 0xa4, 0xa3, 0x80, 0x36, 0x47, 0x22, 0x31, 0xe2, 0x53, 0x28, 0x07, 0x96, 0x77, + 0x22, 0x97, 0x43, 0xfd, 0xdb, 0xb4, 0x01, 0xdd, 0xb0, 0xbc, 0x13, 0xe9, 0x23, 0x09, 0x41, 0xfc, + 0x3b, 0xab, 0x4e, 0xaf, 0xbf, 0xc6, 0xc4, 0x95, 0xb2, 0x9c, 0x89, 0x57, 0x5b, 0xce, 0x3e, 0x27, + 0x13, 0x95, 0xed, 0x45, 0xa6, 0xca, 0x70, 0x79, 0x71, 0x86, 0x0a, 0x93, 0xf5, 0x38, 0x1b, 0x36, + 0x80, 0x0e, 0xb0, 0x4c, 0x3a, 0xed, 0xda, 0xc8, 0x34, 0x20, 0x3e, 0xd9, 0x32, 0x20, 0x48, 0x4e, + 0xb9, 0x1a, 0xb0, 0x96, 0x5c, 0x83, 0xe7, 0xd8, 0x03, 0x57, 0xd2, 0xe7, 0xee, 0x99, 0x7b, 0xf3, + 0xca, 0x28, 0xe6, 0x64, 0x2e, 0xd3, 0xbf, 0x0d, 0x55, 0xf6, 0x97, 0x56, 0x6c, 0x84, 0x1d, 0xdd, + 0x2b, 0x04, 0x54, 0x7c, 0x04, 0x85, 0x0f, 0x69, 0xa9, 0x8b, 0xce, 0x48, 0x83, 0x4a, 0x18, 0x33, + 0x9b, 0xe6, 0xa2, 0x33, 0xa3, 0x34, 0x52, 0x3f, 0x91, 0x35, 0x1d, 0x38, 0xde, 0x08, 0xa7, 0x5e, + 0x64, 0x1d, 0x85, 0xf5, 0x3a, 0xad, 0xcc, 0xb2, 0x84, 0x0d, 0xac, 0xa3, 0x50, 0x7c, 0x06, 0x15, + 0x8b, 0x0d, 0x11, 0x5c, 0xef, 0xeb, 0xe9, 0x03, 0x9f, 0x94, 0x89, 0xc2, 0x28, 0x5b, 0x29, 0x7b, + 0xc5, 0x97, 0x20, 0x94, 0x1f, 0x53, 0xca, 0x3c, 0x7e, 0x63, 0x6e, 0x36, 0xae, 0x49, 0x47, 0xa6, + 0xd8, 0x38, 0x7e, 0x1b, 0xe4, 0xee, 0xce, 0xd7, 0x90, 0xde, 0xa0, 0x0a, 0x01, 0x83, 0xe8, 0x0a, + 0xd2, 0x97, 0x50, 0xcd, 0x5a, 0x60, 0x6e, 0x2e, 0x70, 0x07, 0xe2, 0xbd, 0xb8, 0x32, 0x4c, 0xdb, + 0x64, 0xde, 0xe6, 0x70, 0x0e, 0xa4, 0x3d, 0x51, 0x46, 0x76, 0x79, 0xa9, 0x78, 0x7e, 0xd4, 0x54, + 0x30, 0xec, 0x40, 0x65, 0x1f, 0x8d, 0xce, 0x48, 0xe1, 0x8a, 0x3b, 0x30, 0x36, 0x2b, 0x19, 0x25, + 0x27, 0xb6, 0x30, 0x6d, 0x81, 0x50, 0xae, 0x04, 0x28, 0x78, 0xb2, 0xc7, 0x2d, 0xe9, 0x57, 0xb1, + 0x87, 0xd0, 0xac, 0x5c, 0x6a, 0xb0, 0x77, 0x72, 0x5a, 0x52, 0x7d, 0x0c, 0x35, 0xdc, 0x1b, 0x53, + 0x5f, 0xd6, 0xd3, 0x8d, 0xda, 0x0b, 0xec, 0xe4, 0xe3, 0x95, 0x49, 0x2a, 0x25, 0x7e, 0x06, 0xeb, + 0xa9, 0x9c, 0xd3, 0x13, 0xca, 0xfc, 0x36, 0x65, 0xde, 0x98, 0xc9, 0xbc, 0x7f, 0x82, 0xd9, 0x6b, + 0x93, 0x4c, 0x5a, 0x6c, 0xc0, 0x72, 0x3b, 0x6c, 0x79, 0x23, 0xd2, 0xbb, 0x8a, 0x06, 0x27, 0xc4, + 0x23, 0xa8, 0xb0, 0x91, 0x83, 0x6c, 0x8d, 0x61, 0xfd, 0xdd, 0xf4, 0x89, 0x2e, 0x59, 0x3a, 0xd8, + 0x60, 0x59, 0x76, 0xe3, 0xdf, 0xa1, 0xf8, 0x02, 0xd6, 0xf9, 0xb8, 0x3d, 0xcd, 0x22, 0xdf, 0x9b, + 0x1f, 0x72, 0x22, 0xda, 0x4e, 0xf8, 0xa4, 0x01, 0xd7, 0x83, 0xa9, 0x47, 0x86, 0x0f, 0x99, 0x93, + 0x0f, 0x82, 0x28, 0xff, 0x3d, 0xca, 0x2f, 0x03, 0x0a, 0x19, 0x4c, 0xc6, 0x79, 0x89, 0x37, 0x5d, + 0x0d, 0xd2, 0xa0, 0x3d, 0xcc, 0x77, 0x41, 0x99, 0x7c, 0x40, 0x42, 0x65, 0xbe, 0xff, 0x63, 0xca, + 0xa4, 0xc3, 0x13, 0x2a, 0x53, 0x40, 0x61, 0x3a, 0x75, 0x46, 0xa4, 0x05, 0x56, 0x0c, 0xfa, 0x2d, + 0xde, 0x81, 0x5a, 0x60, 0x0f, 0xa7, 0x41, 0xe8, 0xbc, 0xb4, 0xcd, 0xd0, 0xf1, 0x4e, 0x48, 0xff, + 0x2b, 0x1a, 0xd5, 0x18, 0xda, 0x77, 0xbc, 0x13, 0x64, 0x19, 0xf6, 0x59, 0x64, 0x07, 0x1e, 0xc7, + 0xc1, 0xf8, 0x30, 0xcd, 0x32, 0x5a, 0x84, 0xc0, 0x75, 0x6e, 0x80, 0x1d, 0xff, 0x9e, 0x19, 0xd9, + 0x90, 0x47, 0xf6, 0xc1, 0x0f, 0x1a, 0xd9, 0x3e, 0x8d, 0xec, 0xbb, 0x50, 0x74, 0xbc, 0xc8, 0x0e, + 0x5e, 0x5a, 0x6e, 0xfd, 0xe3, 0x39, 0x6e, 0x1c, 0xe3, 0xc4, 0x5d, 0x58, 0x0d, 0x5d, 0x07, 0xd7, + 0x7b, 0xfd, 0x93, 0x39, 0x32, 0x85, 0x12, 0xf7, 0xa0, 0x14, 0x47, 0xb9, 0xaa, 0x7f, 0x3a, 0x47, + 0x97, 0x20, 0xc5, 0x2d, 0x28, 0x9c, 0xe2, 0x84, 0x7a, 0x38, 0x7f, 0x02, 0x8f, 0x70, 0xdc, 0xbe, + 0x0f, 0x51, 0x9f, 0xa7, 0xed, 0xfb, 0xd1, 0xdc, 0xf6, 0xbd, 0xed, 0xb8, 0x2e, 0x6f, 0xdf, 0x87, + 0xf2, 0x17, 0x6e, 0x7e, 0x94, 0x03, 0x5b, 0xf2, 0xd9, 0xfc, 0xe6, 0x87, 0xb8, 0xe7, 0x14, 0x0f, + 0xac, 0x1c, 0xd2, 0xb1, 0x32, 0x9f, 0x8e, 0x7f, 0x9e, 0xee, 0xab, 0xec, 0x79, 0xb3, 0x01, 0x61, + 0x9c, 0x16, 0x6f, 0x82, 0x3c, 0x35, 0x27, 0x85, 0xea, 0x0b, 0xbe, 0x0a, 0xca, 0x10, 0xd4, 0xa5, + 0x3e, 0x81, 0xaa, 0xf2, 0x87, 0x26, 0x01, 0xac, 0xfe, 0xe5, 0x5c, 0x0d, 0xb2, 0x04, 0x62, 0x0b, + 0x2a, 0x87, 0xa8, 0xd7, 0x8f, 0x59, 0xcd, 0xaf, 0x3f, 0xa6, 0x8a, 0xdc, 0x51, 0x1b, 0xeb, 0x45, + 0x66, 0x00, 0x23, 0x93, 0x4b, 0x3c, 0x00, 0xe1, 0x1c, 0xf2, 0x78, 0x6e, 0x07, 0xfe, 0x98, 0x55, + 0xf9, 0xfa, 0x57, 0xf2, 0xa8, 0x61, 0x0e, 0x43, 0x3e, 0x36, 0xb6, 0x37, 0x32, 0xc7, 0xa1, 0x14, + 0x13, 0xbe, 0xa6, 0x7a, 0x4a, 0xe6, 0x15, 0x47, 0xc3, 0x53, 0x67, 0xa8, 0x48, 0xbb, 0x1b, 0xb2, + 0xd4, 0xf0, 0x15, 0xe0, 0x74, 0x7d, 0x99, 0x64, 0xfd, 0xc9, 0x2b, 0xb3, 0x22, 0xad, 0xca, 0xfa, + 0x18, 0x6a, 0x7c, 0xc0, 0x41, 0x12, 0x19, 0x4e, 0xd1, 0x9f, 0xa6, 0x39, 0x57, 0xfa, 0x64, 0xd6, + 0xa8, 0x8c, 0xd2, 0xe7, 0xb4, 0x5f, 0xc2, 0x5a, 0xea, 0x7c, 0x83, 0x3e, 0xfb, 0x5b, 0xe9, 0xcf, + 0xc6, 0x07, 0x1c, 0x46, 0x75, 0xaa, 0x7e, 0xd2, 0x27, 0xe7, 0x04, 0xfe, 0xdf, 0xfe, 0x01, 0x02, + 0xff, 0xdb, 0x90, 0xac, 0x48, 0x73, 0x18, 0xd9, 0xf5, 0x9f, 0x31, 0xf3, 0x8f, 0x81, 0xcd, 0xc8, + 0x16, 0x8f, 0x00, 0xac, 0xc9, 0xc4, 0x3d, 0xe7, 0xa9, 0xf9, 0x73, 0x9a, 0x9a, 0x1b, 0xa9, 0xa9, + 0xd9, 0x40, 0x24, 0xcd, 0xcd, 0x92, 0xa5, 0x7e, 0xa2, 0xce, 0x4a, 0xaa, 0xc4, 0x68, 0xec, 0x52, + 0xfb, 0x1b, 0xe9, 0xb5, 0xbd, 0xe7, 0x87, 0xd1, 0xd6, 0xd8, 0xc5, 0x56, 0xc0, 0x24, 0xfe, 0x2d, + 0x3a, 0x70, 0xd9, 0xf7, 0xcc, 0xd1, 0x74, 0xe2, 0x3a, 0x43, 0xec, 0x01, 0x3e, 0x58, 0xac, 0x6f, + 0xa6, 0xaf, 0x24, 0xd1, 0x17, 0x7b, 0xde, 0x96, 0x22, 0x92, 0x07, 0x96, 0xeb, 0xfe, 0x2c, 0x88, + 0x6c, 0x50, 0x34, 0x06, 0xf1, 0x6d, 0x9e, 0x26, 0x8b, 0x06, 0x04, 0x55, 0xd7, 0x79, 0x1e, 0xc3, + 0x5a, 0x42, 0xc5, 0xd7, 0xa7, 0xb7, 0x2e, 0xb8, 0x3e, 0x5d, 0x55, 0x19, 0xf9, 0xd6, 0x35, 0xf6, + 0x9d, 0xef, 0xba, 0xd3, 0x89, 0x64, 0xa5, 0xf5, 0x96, 0xec, 0x3b, 0x02, 0x32, 0x97, 0x4c, 0x99, + 0xe9, 0xec, 0x71, 0x7d, 0x3b, 0x6d, 0xa6, 0xb3, 0xc7, 0xa2, 0x09, 0x75, 0x62, 0xc5, 0x72, 0x9d, + 0x65, 0xdc, 0x52, 0xda, 0x73, 0xcb, 0xe9, 0x0a, 0xd2, 0xb2, 0xd7, 0xcb, 0x5e, 0xca, 0x41, 0xe5, + 0xe7, 0xf0, 0xe6, 0xe2, 0x42, 0x54, 0xfc, 0x93, 0xa7, 0x24, 0x2b, 0x5c, 0x5f, 0x90, 0x5b, 0x06, + 0x41, 0xf9, 0x1a, 0xaa, 0x47, 0x16, 0xb5, 0xc2, 0x35, 0xc7, 0xfe, 0xc8, 0xae, 0x3f, 0x4b, 0x5f, + 0x00, 0xa4, 0x0e, 0x7f, 0x62, 0x61, 0x83, 0xdc, 0x5d, 0x7f, 0x64, 0x1b, 0xe5, 0xa3, 0x24, 0x21, + 0x1e, 0x43, 0x3d, 0x99, 0x40, 0x53, 0x0f, 0xbf, 0x8b, 0xfa, 0xad, 0xe3, 0x0d, 0xa3, 0x7a, 0x87, + 0x03, 0x57, 0xc6, 0xf8, 0x7d, 0x44, 0x6f, 0x49, 0xac, 0x68, 0x82, 0x46, 0x0b, 0x5b, 0xee, 0x40, + 0xa1, 0x33, 0xb2, 0xeb, 0xbb, 0xe9, 0x68, 0x3e, 0xcc, 0xf6, 0x90, 0x84, 0xf6, 0x9a, 0xbe, 0x33, + 0xb2, 0x8d, 0xda, 0x61, 0x26, 0x2d, 0xde, 0x87, 0x75, 0xa5, 0x4b, 0x98, 0xc7, 0x56, 0x78, 0x6c, + 0x9e, 0xd8, 0xe7, 0xf5, 0x2e, 0x35, 0xb8, 0x26, 0x15, 0x89, 0x1d, 0x2b, 0x3c, 0x7e, 0x66, 0x9f, + 0x8b, 0xfb, 0xb0, 0x2e, 0xb7, 0x3c, 0x27, 0x34, 0x0f, 0xac, 0x20, 0x70, 0xec, 0xa0, 0xde, 0xe3, + 0x13, 0x2d, 0x46, 0xb4, 0xc3, 0x4d, 0x06, 0x8b, 0x0f, 0x41, 0xa4, 0x07, 0x43, 0xfa, 0x58, 0xed, + 0x11, 0x0f, 0xd4, 0x52, 0xde, 0x41, 0xe4, 0x6b, 0x25, 0x3e, 0x81, 0x5a, 0xdc, 0x7f, 0xec, 0x23, + 0xf3, 0x8b, 0x79, 0x5b, 0x86, 0xec, 0xb4, 0x3e, 0x39, 0xc9, 0x7c, 0x08, 0x95, 0x38, 0x87, 0xed, + 0x8d, 0xea, 0xc6, 0xbc, 0x15, 0x4f, 0xd2, 0xe3, 0xce, 0xf0, 0x39, 0x5c, 0xe3, 0x29, 0xca, 0x27, + 0x19, 0x27, 0xf6, 0x79, 0x1c, 0xbc, 0xa9, 0xcf, 0xb1, 0x4f, 0x08, 0xdd, 0x46, 0xec, 0x33, 0xfb, + 0x3c, 0x8c, 0x39, 0xdf, 0x75, 0x3a, 0xe9, 0x1f, 0xca, 0x6b, 0xc2, 0x6c, 0xe5, 0x96, 0x6d, 0x19, + 0xf0, 0xd8, 0x20, 0x41, 0x33, 0xc6, 0x1b, 0xd2, 0x7b, 0x4c, 0x34, 0xd4, 0x75, 0xa9, 0x90, 0x94, + 0x77, 0xde, 0x9d, 0xf7, 0xd3, 0x11, 0x2f, 0x66, 0x54, 0x7b, 0x79, 0x8b, 0x2a, 0x65, 0xb3, 0x7a, + 0x02, 0x37, 0xe2, 0xa3, 0x4b, 0xfb, 0xfb, 0xa9, 0x45, 0xd7, 0x9f, 0x4e, 0xec, 0x73, 0x66, 0x69, + 0x2f, 0xe6, 0x66, 0xf7, 0x35, 0x45, 0xdd, 0x92, 0xc4, 0xcf, 0xec, 0x73, 0xe2, 0x6b, 0x77, 0xa1, + 0x66, 0x85, 0xfe, 0xa1, 0xd4, 0x40, 0x87, 0xbe, 0x5b, 0x7f, 0x4e, 0xe3, 0x50, 0x41, 0xa8, 0xa1, + 0x4e, 0x4a, 0xbb, 0x70, 0x39, 0x19, 0x31, 0xd4, 0xf8, 0x03, 0x27, 0x3a, 0x1e, 0xd7, 0x7f, 0x99, + 0x36, 0xfd, 0xd0, 0x84, 0x8a, 0x27, 0x7f, 0x43, 0x11, 0x19, 0xc9, 0x58, 0xc7, 0x30, 0xf1, 0x18, + 0xae, 0x27, 0xe5, 0x45, 0xfe, 0xc4, 0xf4, 0xcc, 0x53, 0x27, 0x3a, 0x36, 0xc9, 0x37, 0xf8, 0x77, + 0x64, 0x88, 0x1f, 0x45, 0x30, 0xf0, 0x27, 0xdd, 0x17, 0x4e, 0x74, 0x3c, 0x70, 0xec, 0x50, 0x6c, + 0xc2, 0x2d, 0x6b, 0x64, 0x4d, 0x22, 0x5c, 0x10, 0x98, 0x31, 0x0e, 0x4b, 0xe4, 0x7b, 0xa6, 0x3d, + 0x9e, 0x44, 0xe7, 0xf5, 0x3f, 0x47, 0xd9, 0x6f, 0x28, 0xaa, 0x81, 0x3f, 0xd9, 0x96, 0x34, 0x3d, + 0xaf, 0x85, 0x14, 0xe2, 0x11, 0x5c, 0x7d, 0x69, 0x0f, 0x23, 0x3f, 0x30, 0xd9, 0x46, 0x26, 0x45, + 0x7f, 0x67, 0x54, 0xff, 0x5d, 0x6a, 0xfb, 0x65, 0xc6, 0xfe, 0x02, 0x91, 0xec, 0xf0, 0xd3, 0x1e, + 0xa1, 0x36, 0x48, 0x1e, 0xfb, 0x13, 0x2b, 0x3a, 0xae, 0xff, 0x03, 0xe9, 0x8b, 0x03, 0xcf, 0x1d, + 0xfb, 0x14, 0x95, 0x04, 0x83, 0x5c, 0xfa, 0xf7, 0xac, 0xe8, 0x58, 0x3c, 0x54, 0x6c, 0x0f, 0x87, + 0x84, 0xcd, 0x2b, 0xe6, 0xfc, 0x06, 0x4e, 0x24, 0xcf, 0xec, 0x73, 0xda, 0xc0, 0xf5, 0xbf, 0xb8, + 0x02, 0x45, 0x65, 0xfe, 0x10, 0x65, 0x58, 0xdd, 0xef, 0x3e, 0xeb, 0xf6, 0x5e, 0x74, 0x39, 0x02, + 0x5f, 0xa3, 0xdf, 0x6f, 0x19, 0x03, 0x6d, 0x24, 0x6a, 0x00, 0x14, 0x6d, 0xca, 0xec, 0x37, 0x1b, + 0x5d, 0x8e, 0xc8, 0x47, 0x31, 0xae, 0x38, 0xbd, 0x24, 0xd6, 0xa1, 0xba, 0xbd, 0xdf, 0xe5, 0x8b, + 0x49, 0x04, 0xca, 0x23, 0xa8, 0xf5, 0x0d, 0x3b, 0x07, 0x32, 0xa8, 0x80, 0xa0, 0xdd, 0xc6, 0xa0, + 0x65, 0xb4, 0x15, 0x68, 0x59, 0x5c, 0x81, 0xf5, 0x98, 0x4a, 0x95, 0xa0, 0xad, 0x22, 0xb8, 0xdd, + 0xdd, 0x6a, 0x7d, 0x63, 0xf6, 0x5b, 0x0d, 0xa3, 0xb9, 0xc3, 0xd4, 0x45, 0xac, 0xdf, 0x9e, 0xd1, + 0x7b, 0xda, 0x6a, 0x0e, 0x34, 0x20, 0x7f, 0xc3, 0x27, 0x4f, 0xb4, 0xb2, 0xa8, 0x40, 0x71, 0xab, + 0xdd, 0x1f, 0xb4, 0xbb, 0xcd, 0x81, 0x56, 0xc1, 0x6a, 0x6f, 0xb7, 0x3b, 0x83, 0x96, 0xa1, 0x55, + 0x45, 0x11, 0x0a, 0x4f, 0x7b, 0xed, 0xae, 0x56, 0xa3, 0xd8, 0x5b, 0x8d, 0xdd, 0xbd, 0x4e, 0x4b, + 0x5b, 0x43, 0x68, 0xbf, 0x67, 0x0c, 0x34, 0x0d, 0xa1, 0x1c, 0x65, 0x42, 0x5b, 0x17, 0x25, 0x58, + 0xde, 0xef, 0xe2, 0xd7, 0x85, 0xa8, 0x42, 0x89, 0x7e, 0x9a, 0x8d, 0x4e, 0x47, 0xbb, 0x9c, 0x72, + 0x52, 0xdc, 0x40, 0x14, 0xb9, 0x3c, 0xf6, 0xb1, 0x0e, 0x57, 0xb0, 0x45, 0x71, 0x92, 0xa8, 0xaf, + 0x62, 0x39, 0xbb, 0xed, 0xee, 0x7e, 0x5f, 0xbb, 0x86, 0xc4, 0xf4, 0x93, 0x30, 0x75, 0x2c, 0xa7, + 0xdd, 0xa5, 0x0e, 0xbd, 0x85, 0xbf, 0xb7, 0x5a, 0x9d, 0xd6, 0xa0, 0xa5, 0xdd, 0xc6, 0x56, 0x75, + 0x7a, 0xcd, 0x67, 0x66, 0x6f, 0x4f, 0x7b, 0x0b, 0x7b, 0x76, 0xcf, 0x68, 0x99, 0x92, 0xf0, 0x6d, + 0xa1, 0x41, 0x65, 0x7b, 0xff, 0x97, 0xbf, 0xfc, 0xd6, 0x94, 0x8d, 0x7a, 0x07, 0xbf, 0x99, 0x50, + 0x98, 0xfb, 0xcf, 0xb4, 0x77, 0x67, 0x40, 0xfd, 0x67, 0xda, 0x7b, 0xd8, 0x29, 0xaa, 0xaf, 0xb5, + 0x7b, 0x48, 0x60, 0xb4, 0x9a, 0xfb, 0x46, 0xbf, 0xfd, 0xbc, 0x65, 0x36, 0x07, 0x2d, 0xed, 0x7d, + 0xea, 0x85, 0x76, 0xf7, 0x99, 0x76, 0x1f, 0xab, 0x89, 0xbf, 0xb8, 0x93, 0x3f, 0x10, 0x02, 0x6a, + 0x09, 0x2d, 0xc1, 0x3e, 0x44, 0x92, 0x4d, 0xa3, 0xd7, 0xd8, 0x6a, 0x36, 0xfa, 0x03, 0xed, 0x23, + 0x6c, 0x63, 0x7f, 0xaf, 0xd3, 0x1e, 0x68, 0x0f, 0xb0, 0x21, 0x4f, 0x1a, 0x83, 0x9d, 0x96, 0xa1, + 0x7d, 0x2c, 0xd6, 0xa0, 0x3c, 0x68, 0xef, 0xb6, 0x4c, 0xd9, 0xa7, 0x0f, 0xf1, 0x1b, 0xdb, 0xed, + 0x4e, 0x47, 0x7b, 0x44, 0x4e, 0x76, 0x0d, 0x63, 0xd0, 0xa6, 0xf1, 0xfd, 0x0c, 0x0b, 0x68, 0xec, + 0xed, 0x75, 0xbe, 0xd5, 0x3e, 0xc7, 0x06, 0xee, 0xee, 0x77, 0x06, 0x6d, 0x73, 0x7f, 0x6f, 0xab, + 0x31, 0x68, 0x69, 0x5f, 0xd0, 0x28, 0xf7, 0xfa, 0x83, 0xad, 0xdd, 0x8e, 0xf6, 0x25, 0x95, 0x49, + 0x33, 0xad, 0xd9, 0xe9, 0x75, 0x5b, 0xda, 0x63, 0xa4, 0x6f, 0x6c, 0x35, 0xf6, 0x06, 0x58, 0xbb, + 0x41, 0x6f, 0x4f, 0xfb, 0x4a, 0x6c, 0x80, 0xf6, 0xbc, 0xd5, 0x1c, 0xf4, 0x0c, 0xf3, 0x17, 0xfb, + 0x2d, 0xe3, 0x5b, 0x82, 0x7e, 0x2d, 0xae, 0xc1, 0xe5, 0x0c, 0xb4, 0xdf, 0xdb, 0x37, 0x9a, 0x2d, + 0xed, 0x27, 0x7a, 0xa1, 0xb8, 0xa2, 0xad, 0xe8, 0x85, 0xe2, 0x1d, 0xed, 0x8e, 0x5e, 0x28, 0xea, + 0x9a, 0x7e, 0xbf, 0xcc, 0x38, 0x6a, 0xac, 0xfe, 0x57, 0x72, 0x50, 0x54, 0x66, 0x35, 0x8e, 0x5e, + 0xd2, 0x6d, 0x19, 0xda, 0x25, 0x6c, 0x4b, 0xa7, 0xb5, 0x3d, 0xe0, 0xc0, 0x25, 0x46, 0xfb, 0xc9, + 0xce, 0x40, 0x5b, 0xc2, 0x9f, 0xbd, 0x7d, 0x1c, 0x96, 0x3c, 0xf5, 0x67, 0x6b, 0xb7, 0xad, 0x15, + 0xf0, 0x57, 0xa3, 0x3b, 0x68, 0x6b, 0xcb, 0x34, 0xeb, 0xda, 0xdd, 0x27, 0x9d, 0x96, 0xb6, 0x82, + 0xd0, 0xdd, 0x86, 0xf1, 0x4c, 0x5b, 0xe5, 0x42, 0xb7, 0x5a, 0xdf, 0x68, 0x45, 0xb1, 0x02, 0x4b, + 0x9d, 0x87, 0x5a, 0x09, 0x41, 0x5b, 0xad, 0xad, 0xfd, 0x3d, 0x0d, 0x28, 0x77, 0xbf, 0xb7, 0xad, + 0x95, 0xb1, 0xcf, 0xf0, 0x97, 0x49, 0x9f, 0xad, 0xe8, 0xf7, 0x60, 0xb5, 0x71, 0x74, 0x44, 0x1b, + 0x34, 0xf6, 0xeb, 0x7e, 0xa7, 0xc3, 0x8b, 0x74, 0xb3, 0x37, 0x18, 0xf4, 0x76, 0xb5, 0x1c, 0x2e, + 0x08, 0x6c, 0xfa, 0x92, 0xde, 0x86, 0xa2, 0xd2, 0x2c, 0x52, 0x61, 0xea, 0x8a, 0x50, 0xd8, 0x33, + 0x5a, 0xcf, 0xd9, 0x41, 0xb7, 0xdb, 0xfa, 0x06, 0xeb, 0x8f, 0xbf, 0xb0, 0xa0, 0x3c, 0xd6, 0x80, + 0xe3, 0xc9, 0x51, 0x9c, 0xba, 0x4e, 0xbb, 0xdb, 0x6a, 0x18, 0xda, 0xb2, 0xfe, 0x18, 0xca, 0x29, + 0x31, 0x01, 0xe7, 0xd1, 0x93, 0xc6, 0x1e, 0xce, 0xc5, 0x8e, 0x29, 0x8b, 0xbd, 0x0a, 0x22, 0x06, + 0x25, 0x43, 0x9c, 0xd3, 0x3f, 0x87, 0xf5, 0x39, 0x89, 0x8e, 0x2a, 0xde, 0x68, 0xcb, 0x8a, 0xb7, + 0x9f, 0x74, 0x7b, 0x46, 0x8b, 0x43, 0xe6, 0xc9, 0xc1, 0x5f, 0xd2, 0x3f, 0x80, 0x52, 0x2c, 0x7a, + 0xe2, 0x62, 0x68, 0x1a, 0xbd, 0x7e, 0x9f, 0xe7, 0xca, 0x25, 0x4c, 0x53, 0x77, 0x73, 0x3a, 0xa7, + 0x3b, 0x50, 0xcb, 0xca, 0x12, 0xe2, 0x0e, 0xdc, 0xe4, 0xe5, 0xb2, 0xb9, 0xdf, 0xee, 0x6c, 0x99, + 0xfd, 0xf6, 0x56, 0x6b, 0xe6, 0xc6, 0xfa, 0x0d, 0xb8, 0x3a, 0x47, 0xc1, 0xf1, 0xfa, 0x72, 0xe2, + 0x3a, 0x5c, 0x99, 0xc3, 0xd1, 0x22, 0x59, 0xd2, 0xf7, 0x40, 0xcc, 0xef, 0x32, 0xe2, 0x26, 0xd4, + 0xe3, 0x36, 0x9b, 0x8d, 0xce, 0x93, 0x9e, 0xd1, 0x1e, 0xec, 0xec, 0x9a, 0xc4, 0x5e, 0x2e, 0x5d, + 0x84, 0xdd, 0x69, 0xf4, 0x77, 0xb4, 0xdc, 0xd3, 0x42, 0xf1, 0xb6, 0x76, 0xe7, 0x69, 0xa1, 0x78, + 0x57, 0x7b, 0xe7, 0x69, 0xa1, 0xf8, 0x44, 0xdb, 0x79, 0x5a, 0x28, 0xee, 0x68, 0x6d, 0xbd, 0x0f, + 0xeb, 0x4a, 0x94, 0xa7, 0xd8, 0x00, 0x64, 0x63, 0xda, 0x80, 0xe5, 0x8e, 0xfd, 0xd2, 0x76, 0xd5, + 0x55, 0x72, 0x4a, 0x20, 0xb4, 0x77, 0xf0, 0x5d, 0x3b, 0x0e, 0x50, 0x4b, 0x09, 0xd4, 0xdd, 0xbb, + 0xa9, 0x18, 0xb9, 0x14, 0xd6, 0xf1, 0x9f, 0xca, 0x41, 0x31, 0x56, 0x10, 0xee, 0xc2, 0xd2, 0xa0, + 0x2f, 0x0f, 0x9c, 0x36, 0x1e, 0x24, 0xc1, 0xe1, 0x07, 0xea, 0x97, 0xb1, 0x34, 0xe8, 0x8b, 0x0f, + 0x61, 0x85, 0xc3, 0x74, 0xca, 0x23, 0xa6, 0x8d, 0xac, 0xd2, 0x31, 0x20, 0x9c, 0x21, 0x69, 0xc4, + 0xe7, 0x50, 0x8a, 0x6b, 0x2b, 0x4d, 0xe3, 0xd7, 0xb2, 0x19, 0x62, 0xb4, 0x91, 0x50, 0xea, 0x1d, + 0xa8, 0x65, 0x0b, 0x14, 0xb7, 0x00, 0xb8, 0xc8, 0xd4, 0xd9, 0x70, 0x0a, 0x22, 0x6e, 0x80, 0x8a, + 0x1e, 0xba, 0x25, 0x23, 0x4b, 0xc5, 0x69, 0xfd, 0x5f, 0x5e, 0x06, 0x48, 0x4c, 0x0c, 0xd8, 0x11, + 0xb1, 0xc1, 0x7f, 0x59, 0x7a, 0x11, 0xbf, 0x01, 0x25, 0xd7, 0xb7, 0x46, 0xe9, 0x40, 0xe8, 0x45, + 0x04, 0xd0, 0x7c, 0x4b, 0x47, 0xcd, 0x29, 0xc9, 0x00, 0x38, 0x57, 0x61, 0x45, 0x5e, 0x4a, 0xe2, + 0xb8, 0x01, 0x32, 0x45, 0x81, 0x71, 0xc8, 0x09, 0x6e, 0x64, 0xba, 0x8e, 0x67, 0x73, 0x48, 0xc2, + 0x82, 0x51, 0x91, 0xc0, 0x0e, 0xc2, 0xc4, 0x6d, 0x28, 0xdb, 0xde, 0xd0, 0xf5, 0x51, 0x4e, 0x3b, + 0xe0, 0x5b, 0x11, 0x15, 0x03, 0x14, 0x68, 0xf3, 0x9c, 0x5b, 0x1b, 0x8c, 0x1d, 0xcf, 0x8a, 0xa4, + 0x77, 0x10, 0xb5, 0x56, 0x41, 0xb0, 0xba, 0xdf, 0x85, 0xbe, 0xb4, 0xff, 0x73, 0x58, 0x96, 0x22, + 0x02, 0xa8, 0xba, 0x6f, 0x02, 0xd8, 0xe1, 0xd0, 0x9a, 0x70, 0xe1, 0x25, 0x8e, 0xac, 0x29, 0x21, + 0x9b, 0xe7, 0xa2, 0x03, 0xb5, 0xc1, 0x01, 0x6a, 0x36, 0xfe, 0x96, 0x15, 0x59, 0x4d, 0xdf, 0x95, + 0x96, 0xf9, 0xbb, 0xb3, 0xb6, 0x98, 0x07, 0x59, 0x32, 0xbe, 0x9a, 0x37, 0x93, 0x57, 0x7c, 0x06, + 0x15, 0x67, 0x68, 0x1f, 0xd8, 0xc1, 0x11, 0x4b, 0x8e, 0xe5, 0xcc, 0x85, 0x7f, 0xc6, 0x90, 0xd4, + 0x58, 0x76, 0x92, 0x04, 0x6a, 0x8c, 0x63, 0xdf, 0x3b, 0xf2, 0x47, 0x07, 0x9c, 0xab, 0x92, 0xb6, + 0x32, 0xee, 0x22, 0x86, 0xf3, 0x48, 0x22, 0xca, 0xf3, 0x5b, 0xb0, 0x86, 0x3d, 0x1f, 0x46, 0x81, + 0x6d, 0x8d, 0x39, 0x5b, 0x35, 0x3d, 0x03, 0xb1, 0x46, 0x7d, 0x42, 0x52, 0xde, 0x5a, 0x42, 0x4c, + 0xd9, 0x3f, 0x4b, 0xee, 0xcb, 0x53, 0xde, 0x5a, 0xc6, 0x6b, 0x9f, 0x31, 0xfc, 0xd1, 0xc3, 0x24, + 0x21, 0x1e, 0x00, 0x9c, 0x58, 0x87, 0x27, 0x16, 0xe7, 0x59, 0x4b, 0x57, 0xf3, 0x19, 0xc2, 0x29, + 0x47, 0xe9, 0x44, 0xfd, 0xbc, 0xd1, 0x80, 0xcb, 0x0b, 0x7a, 0xed, 0x47, 0xdd, 0x0d, 0xfb, 0x6b, + 0x39, 0xa8, 0x65, 0xdb, 0x32, 0x13, 0xa5, 0xb8, 0x14, 0x47, 0x29, 0x16, 0x50, 0x98, 0xf8, 0x81, + 0xba, 0x11, 0x42, 0xbf, 0x93, 0x07, 0x14, 0xf2, 0xe9, 0x07, 0x14, 0xea, 0xb0, 0x1a, 0xd8, 0x7c, + 0xbd, 0x9b, 0x23, 0x45, 0xa8, 0x24, 0x4e, 0xd8, 0xc9, 0x34, 0x3c, 0xb6, 0x47, 0x4a, 0xb5, 0xe5, + 0x6b, 0x0a, 0x15, 0x06, 0x4a, 0xd5, 0xf6, 0x1a, 0xac, 0x5a, 0x13, 0x87, 0x34, 0x2e, 0x19, 0xf1, + 0xd6, 0x9a, 0x38, 0xcf, 0xec, 0x73, 0xfd, 0x57, 0x50, 0x4e, 0xf5, 0x1d, 0x56, 0x88, 0xc2, 0xca, + 0xc8, 0x43, 0x73, 0x8a, 0x0b, 0x76, 0x15, 0x56, 0x64, 0x90, 0x57, 0xbe, 0x6b, 0x22, 0x53, 0xf8, + 0x61, 0x75, 0x4f, 0x90, 0x24, 0x5f, 0xe5, 0x4a, 0x20, 0x81, 0x24, 0xf0, 0xe2, 0xb2, 0xc6, 0x8a, + 0x8c, 0xfc, 0x53, 0x4f, 0x56, 0x3c, 0x4e, 0xeb, 0xff, 0xde, 0x12, 0x94, 0xe2, 0x41, 0xc0, 0x16, + 0x1e, 0x04, 0xfe, 0x89, 0x1d, 0x84, 0xf2, 0xeb, 0x2a, 0x49, 0x3d, 0xe2, 0x4f, 0x9c, 0xa1, 0xba, + 0x75, 0x4d, 0x09, 0x71, 0x33, 0x7d, 0xc7, 0x92, 0xa3, 0xa5, 0xa4, 0xae, 0x54, 0xde, 0x02, 0xb0, + 0xa6, 0x91, 0x3f, 0xf4, 0xc7, 0x63, 0x27, 0x92, 0x5f, 0x4e, 0x41, 0xb0, 0x4c, 0xd2, 0x39, 0x65, + 0x6f, 0x71, 0x22, 0xc5, 0x14, 0x56, 0x32, 0x4c, 0xe1, 0x26, 0x94, 0x42, 0x7b, 0x62, 0x05, 0x56, + 0xe4, 0x07, 0x72, 0x35, 0x27, 0x00, 0x19, 0xf4, 0x2e, 0x88, 0x54, 0x44, 0xd0, 0x3c, 0x05, 0xbd, + 0x0b, 0xa2, 0xf6, 0x48, 0xdc, 0xa1, 0xab, 0x4e, 0x66, 0x8c, 0x66, 0x3f, 0x6f, 0x38, 0xb6, 0xc2, + 0xbe, 0xa4, 0x10, 0x50, 0x20, 0x9f, 0x1b, 0xf6, 0xf2, 0xa3, 0xdf, 0xe2, 0x3d, 0xa0, 0xa7, 0x3d, + 0xfc, 0x69, 0x64, 0x86, 0xf6, 0xd0, 0xf7, 0x46, 0xa1, 0xf4, 0xf3, 0xab, 0x49, 0x70, 0x9f, 0xa1, + 0xfa, 0x7f, 0xbe, 0x04, 0xe5, 0xd4, 0x1a, 0x25, 0x17, 0x27, 0x6b, 0x42, 0xc7, 0x70, 0xf1, 0x05, + 0xf1, 0x92, 0x84, 0x70, 0x88, 0x92, 0xa1, 0x15, 0x59, 0xae, 0x7f, 0x94, 0x0a, 0xbe, 0x22, 0x21, + 0xed, 0x11, 0x79, 0x1d, 0x5a, 0x63, 0x9b, 0x9f, 0xda, 0x90, 0xd1, 0x01, 0x62, 0x40, 0x32, 0x2f, + 0x0b, 0xe9, 0x79, 0xa9, 0xb1, 0x7b, 0x2a, 0xf7, 0x22, 0x79, 0xa3, 0xde, 0x86, 0xb2, 0x32, 0x6b, + 0xe1, 0x57, 0xa4, 0x07, 0xa5, 0x02, 0xb5, 0x47, 0xe2, 0x5d, 0x48, 0x1e, 0x2e, 0x31, 0xad, 0xd0, + 0xf4, 0x0f, 0xd5, 0xbd, 0xbc, 0x18, 0xdc, 0x08, 0x7b, 0x87, 0xb1, 0x5b, 0x13, 0x99, 0x39, 0x24, + 0x8f, 0x44, 0x00, 0x49, 0x2c, 0x0f, 0xe0, 0x72, 0x12, 0x62, 0xf4, 0xd0, 0xb1, 0xdd, 0x91, 0xe9, + 0x8c, 0xd8, 0x3f, 0x7b, 0xd9, 0x58, 0x8f, 0x51, 0xdb, 0x88, 0x69, 0x8f, 0xc8, 0x00, 0x24, 0x2d, + 0x0a, 0x23, 0xe7, 0xc8, 0x0e, 0x23, 0x79, 0x8b, 0xac, 0xc2, 0xc0, 0x2d, 0x82, 0xe9, 0xff, 0xcf, + 0x0a, 0x94, 0x62, 0xe6, 0xf5, 0xba, 0xce, 0x7c, 0x1b, 0xaa, 0x43, 0xdf, 0xf3, 0xd8, 0x0f, 0x21, + 0xe9, 0xcf, 0x4a, 0x02, 0xa4, 0x8b, 0xc0, 0x22, 0x45, 0x94, 0x0e, 0xac, 0x57, 0x30, 0xd6, 0x13, + 0x8c, 0xbc, 0xe1, 0x8a, 0xab, 0x05, 0xb9, 0xde, 0x81, 0x15, 0xaa, 0x6e, 0x8e, 0xd3, 0x38, 0xa3, + 0x87, 0xbe, 0xeb, 0x4a, 0x3f, 0x09, 0x19, 0x96, 0x3c, 0x81, 0x88, 0x87, 0x14, 0x98, 0x9e, 0xdc, + 0x0c, 0x56, 0xd2, 0x51, 0xeb, 0xa8, 0x41, 0xec, 0x69, 0xb0, 0xcb, 0x95, 0x37, 0x14, 0xa1, 0xf8, + 0x19, 0x68, 0x92, 0x77, 0x4c, 0x02, 0x7b, 0x44, 0x12, 0x9d, 0xbc, 0x04, 0xb1, 0x91, 0xca, 0xbc, + 0xa7, 0x70, 0xc6, 0x1a, 0x53, 0xc7, 0x00, 0x9c, 0xa9, 0xc9, 0x30, 0xa0, 0x32, 0xcb, 0xae, 0xf5, + 0x25, 0xa3, 0x16, 0x83, 0x51, 0x85, 0x0d, 0xc5, 0x67, 0x70, 0x35, 0xb0, 0x43, 0x67, 0x34, 0xb5, + 0x5c, 0x33, 0x3b, 0x10, 0x1c, 0xe4, 0x7c, 0x43, 0x61, 0xb7, 0x53, 0x03, 0x82, 0xc5, 0x8f, 0xad, + 0x33, 0x3a, 0x91, 0x72, 0x5d, 0xdb, 0x75, 0xc2, 0xb1, 0x8c, 0x75, 0x5b, 0x1b, 0x5b, 0x67, 0x7b, + 0x09, 0x94, 0x6e, 0x3c, 0x4d, 0x5c, 0x67, 0x26, 0xb2, 0x29, 0x8f, 0x25, 0xc2, 0x0d, 0x46, 0x0b, + 0x1d, 0xaa, 0x58, 0x20, 0x19, 0x5f, 0x63, 0x67, 0xf9, 0xbc, 0x51, 0x1e, 0x5b, 0x74, 0x4a, 0x49, + 0xae, 0x7c, 0x77, 0xa1, 0x16, 0xd3, 0xb0, 0x7f, 0xae, 0x74, 0x91, 0x95, 0x44, 0xec, 0xa2, 0x4b, + 0x55, 0xe3, 0xd9, 0xa1, 0x86, 0xb5, 0xc6, 0xee, 0x49, 0x12, 0xac, 0xc6, 0xf4, 0x3a, 0xf0, 0xb9, + 0x2e, 0x4e, 0x91, 0x35, 0xa2, 0x58, 0xa5, 0x34, 0xaf, 0x84, 0x69, 0x68, 0x2b, 0xc3, 0x01, 0x31, + 0x5e, 0x8e, 0x3d, 0x5a, 0x45, 0x30, 0x31, 0x50, 0x0a, 0xb6, 0x78, 0x0f, 0x34, 0xa2, 0x53, 0xc7, + 0x40, 0xa1, 0xef, 0xd1, 0x11, 0x72, 0xc5, 0xa8, 0x21, 0x5c, 0x1e, 0xf2, 0x84, 0xbe, 0x27, 0xbe, + 0x84, 0x3a, 0x51, 0x4e, 0x9c, 0x89, 0x8d, 0xe2, 0x8b, 0xc9, 0xd1, 0x38, 0x29, 0x87, 0xb8, 0x93, + 0xbf, 0x57, 0x31, 0xae, 0x20, 0x7e, 0x4f, 0xa2, 0x29, 0x24, 0x21, 0x65, 0xbc, 0x0f, 0xeb, 0xa9, + 0xaa, 0xc8, 0xa1, 0xe1, 0xe8, 0x67, 0x6b, 0x71, 0x65, 0xe4, 0xa8, 0x7c, 0x02, 0x1b, 0xd2, 0x83, + 0x45, 0x92, 0xf3, 0x74, 0xa2, 0x53, 0xe4, 0xa2, 0x21, 0x24, 0x8e, 0x72, 0xf0, 0xbc, 0x13, 0x6f, + 0x41, 0x85, 0xcc, 0x29, 0x32, 0x76, 0xb1, 0x8c, 0x80, 0x56, 0x26, 0x18, 0x07, 0x2d, 0xd3, 0xff, + 0x52, 0x0e, 0xc4, 0xfc, 0x54, 0xbd, 0x28, 0xdc, 0x0e, 0xd9, 0x4d, 0x64, 0xac, 0x0b, 0xfc, 0x2d, + 0xde, 0x87, 0xd5, 0xb1, 0xcf, 0xe2, 0x54, 0xfe, 0x82, 0x88, 0x7a, 0x2b, 0x63, 0x9f, 0xc4, 0xab, + 0xf7, 0x60, 0x6d, 0xe8, 0x7b, 0x72, 0xd0, 0x98, 0xbb, 0xf0, 0x5a, 0xab, 0x25, 0x60, 0xe4, 0x31, + 0xfa, 0xbf, 0x9b, 0x83, 0x5a, 0x76, 0x01, 0x88, 0x77, 0xe9, 0x7d, 0x84, 0xcc, 0x0b, 0x0b, 0x59, + 0x8a, 0xde, 0x84, 0xde, 0x4d, 0x58, 0x54, 0xc5, 0x37, 0x01, 0x48, 0x48, 0xe0, 0xd1, 0x90, 0x01, + 0xd3, 0x09, 0x42, 0x23, 0x70, 0x1b, 0xca, 0xfc, 0x18, 0x12, 0xe3, 0x0b, 0x34, 0x5a, 0x9c, 0x23, + 0x24, 0x82, 0x4f, 0x52, 0xee, 0x27, 0xec, 0x5e, 0xb2, 0x78, 0x91, 0xc6, 0x54, 0xfa, 0x1f, 0xe4, + 0x00, 0x92, 0x35, 0x80, 0x33, 0xf1, 0xc4, 0x3e, 0x67, 0x9b, 0x93, 0xdc, 0x62, 0x4f, 0xec, 0xf3, + 0x3d, 0x59, 0x37, 0xe9, 0xd6, 0x18, 0xca, 0x3b, 0xa5, 0x15, 0xa3, 0xc4, 0x9e, 0x8c, 0x21, 0x07, + 0x79, 0x92, 0x8e, 0x8c, 0xa9, 0xaa, 0xb3, 0xef, 0x62, 0x48, 0x71, 0x3a, 0xd6, 0x38, 0x37, 0x0d, + 0x7d, 0xe8, 0xbc, 0x54, 0xe1, 0xac, 0xd8, 0xf1, 0xb2, 0xad, 0xa0, 0x48, 0xc8, 0xe5, 0x24, 0x84, + 0x7c, 0xc9, 0x8b, 0xdd, 0x2c, 0x63, 0x42, 0xdd, 0x55, 0x02, 0x7f, 0x23, 0x8a, 0x68, 0x83, 0x8d, + 0xcf, 0x05, 0x72, 0x2a, 0x86, 0x15, 0x1f, 0x09, 0xbc, 0x41, 0x77, 0x61, 0x65, 0x7c, 0x0a, 0x29, + 0xf7, 0xc7, 0x71, 0x27, 0xde, 0xc5, 0x91, 0x76, 0xd5, 0xf6, 0x10, 0xfb, 0xc9, 0x2d, 0x1b, 0xd5, + 0xa1, 0xef, 0xf2, 0xd6, 0x80, 0x40, 0xfd, 0xbf, 0x5c, 0x06, 0x48, 0x4e, 0x84, 0x33, 0x2b, 0x36, + 0x97, 0x5d, 0xb1, 0x0f, 0xe1, 0xaa, 0x8c, 0x52, 0x18, 0x5f, 0xf8, 0x72, 0x3c, 0xf3, 0xc0, 0x52, + 0x22, 0x9c, 0x90, 0x58, 0xbe, 0xa6, 0xd3, 0xf6, 0x36, 0xad, 0x48, 0x3c, 0x46, 0x1e, 0x99, 0xe4, + 0x89, 0xce, 0x27, 0x17, 0x4e, 0xd1, 0x6a, 0x92, 0x7d, 0x70, 0x3e, 0x11, 0x9f, 0x50, 0x1c, 0xa6, + 0xc0, 0x0e, 0x8f, 0xcd, 0x28, 0x4c, 0x7f, 0x8c, 0x6f, 0xdd, 0xaf, 0x4b, 0xe4, 0x20, 0x8c, 0xbf, + 0xf5, 0x09, 0x5c, 0x91, 0x4c, 0x62, 0xa6, 0x7a, 0xec, 0x8e, 0x29, 0xad, 0xea, 0xe9, 0xda, 0xd1, + 0xc8, 0xd3, 0x31, 0xb9, 0x7a, 0xb4, 0xab, 0x88, 0x23, 0x8f, 0x9d, 0x21, 0x1f, 0x25, 0xa0, 0xb3, + 0x6e, 0x29, 0xb9, 0x70, 0x42, 0xe8, 0x50, 0xc0, 0x15, 0x42, 0xcc, 0xb8, 0xf6, 0xb0, 0xf6, 0x80, + 0x1e, 0x25, 0xa3, 0x07, 0x25, 0xfc, 0x91, 0x6d, 0x10, 0x4e, 0x7c, 0x84, 0x3b, 0x74, 0xd2, 0x6c, + 0xf5, 0x9a, 0x4a, 0x59, 0x1a, 0xe6, 0xe3, 0x86, 0x1a, 0xfc, 0xae, 0xca, 0x07, 0x20, 0x52, 0x35, + 0x57, 0xd4, 0x15, 0xa2, 0x5e, 0x8b, 0xab, 0x2d, 0x89, 0xdf, 0x03, 0xaa, 0x62, 0x72, 0x75, 0x69, + 0xe6, 0x60, 0x18, 0x91, 0xf2, 0xba, 0xd3, 0x95, 0xa4, 0x75, 0xa6, 0x15, 0x99, 0xd1, 0xb1, 0x4d, + 0x56, 0x7c, 0xbe, 0xbb, 0xb4, 0x1e, 0x37, 0xb4, 0x11, 0x0d, 0x8e, 0xed, 0x16, 0xf1, 0xda, 0xd8, + 0xf5, 0x66, 0xed, 0xd5, 0xae, 0x37, 0x5f, 0x40, 0x3d, 0x7b, 0x80, 0x93, 0xea, 0x6e, 0x66, 0xe3, + 0x1b, 0xe9, 0x3b, 0x61, 0x71, 0x8f, 0xdf, 0x87, 0x75, 0x94, 0x09, 0x33, 0x79, 0xa5, 0xcf, 0xde, + 0xda, 0xb1, 0x15, 0xa6, 0x4f, 0x7c, 0xd8, 0x5d, 0xcd, 0x3c, 0xb5, 0x9c, 0x88, 0x1c, 0x81, 0x8a, + 0xc6, 0x8a, 0xe7, 0xbf, 0xb0, 0x1c, 0xf6, 0x31, 0x39, 0x71, 0x26, 0x74, 0x8f, 0xc3, 0x1e, 0x11, + 0xa7, 0x2e, 0x1a, 0x80, 0x20, 0x8e, 0xab, 0xa2, 0xff, 0x23, 0xab, 0x50, 0xcb, 0x9e, 0xae, 0x73, + 0x24, 0x38, 0x96, 0x10, 0x72, 0x24, 0x27, 0xc5, 0x72, 0xc0, 0x1b, 0x50, 0xe2, 0x2b, 0x67, 0xc8, + 0xc6, 0xd5, 0x73, 0x00, 0x27, 0x92, 0x79, 0xbf, 0x0f, 0xab, 0x93, 0x93, 0xd7, 0xb0, 0xd6, 0x09, + 0x47, 0x64, 0x79, 0x1f, 0x56, 0xa7, 0x27, 0xc9, 0x63, 0x0f, 0x0b, 0x49, 0xa7, 0x27, 0xd2, 0x07, + 0xfb, 0xba, 0xf4, 0x0b, 0x90, 0xf7, 0xd1, 0xc6, 0x53, 0x37, 0x72, 0x4c, 0xb2, 0x62, 0x4b, 0xa6, + 0x70, 0x95, 0x09, 0xda, 0x84, 0xa7, 0x98, 0x0e, 0x74, 0x16, 0x8b, 0x6d, 0x97, 0x71, 0xa0, 0x62, + 0x69, 0x67, 0xd9, 0x00, 0x8e, 0xfb, 0x44, 0xcd, 0x79, 0x1f, 0x34, 0xf5, 0x22, 0x5b, 0x4c, 0xb5, + 0x4a, 0x54, 0x6b, 0x0a, 0xae, 0x48, 0xdf, 0x81, 0x9a, 0xbc, 0x35, 0xa4, 0x08, 0x39, 0x50, 0x41, + 0x95, 0xa1, 0x8a, 0xec, 0x0b, 0xb8, 0xe6, 0x8f, 0x4e, 0xa6, 0xea, 0x02, 0x9c, 0x15, 0x1c, 0x38, + 0x51, 0x60, 0xc5, 0x11, 0xf2, 0x8a, 0xc6, 0x15, 0x44, 0x33, 0xff, 0x68, 0x24, 0x48, 0x2c, 0x5e, + 0x66, 0x51, 0xc5, 0x03, 0xd5, 0xa3, 0xca, 0x50, 0x55, 0xfc, 0x67, 0x70, 0x35, 0x0e, 0xcd, 0x62, + 0x8f, 0x6d, 0x2f, 0x32, 0x03, 0x9b, 0x3c, 0xd6, 0xe4, 0x7b, 0x2d, 0x1b, 0x2a, 0x42, 0x0b, 0x21, + 0x0d, 0xc6, 0x89, 0x87, 0x70, 0x65, 0x26, 0x97, 0x1c, 0x41, 0x5e, 0x35, 0x97, 0x33, 0x99, 0xe4, + 0x60, 0xb6, 0xe0, 0xf6, 0x4c, 0x9e, 0x4c, 0x34, 0x53, 0xcc, 0x5d, 0xa5, 0xdc, 0x37, 0x33, 0xb9, + 0xd3, 0xf1, 0x36, 0xb1, 0x98, 0x2f, 0xa1, 0x3e, 0x53, 0x0c, 0x8e, 0x08, 0xb3, 0x58, 0x8e, 0xda, + 0x7a, 0x25, 0x93, 0xff, 0x99, 0x7d, 0xce, 0x2c, 0xf9, 0x67, 0x70, 0x73, 0x26, 0x63, 0xa6, 0xfb, + 0xe5, 0x05, 0xc1, 0xeb, 0x99, 0xcc, 0xbd, 0xd4, 0x50, 0xe0, 0x54, 0xc5, 0x4f, 0xb1, 0xd7, 0xa8, + 0x46, 0xb2, 0x26, 0xee, 0x6a, 0xe4, 0x30, 0x8a, 0x7c, 0x01, 0x91, 0x7c, 0x34, 0xbc, 0x3e, 0x7b, + 0x34, 0x4c, 0x84, 0x7c, 0x1e, 0xfc, 0x2e, 0xac, 0x29, 0x42, 0x3e, 0x64, 0x0b, 0x49, 0x3c, 0x5a, + 0x36, 0xaa, 0x92, 0x84, 0xce, 0xd6, 0x42, 0xf1, 0x73, 0xd8, 0x40, 0xba, 0x91, 0x63, 0x1d, 0x79, + 0x7e, 0x18, 0x39, 0x43, 0x79, 0xfe, 0x72, 0x39, 0x7d, 0x64, 0xa3, 0x1c, 0xbf, 0x0c, 0x71, 0x62, + 0x9f, 0x6f, 0xc5, 0xa4, 0x7c, 0x10, 0xf3, 0x97, 0x97, 0xa1, 0x92, 0x76, 0x7e, 0xfa, 0x21, 0x17, + 0xfa, 0x7e, 0xd4, 0x75, 0x58, 0xa9, 0x62, 0x52, 0xaf, 0x22, 0x27, 0xc9, 0xc7, 0x2a, 0x66, 0x63, + 0x1a, 0xa1, 0x34, 0x45, 0x6a, 0x9f, 0xef, 0xaa, 0xf0, 0x47, 0xbc, 0x77, 0xe0, 0xae, 0x29, 0x23, + 0x1f, 0x7d, 0x22, 0xa3, 0xab, 0x4d, 0xd4, 0xf1, 0xd2, 0x22, 0xf7, 0x6e, 0x15, 0x0d, 0x93, 0x02, + 0x6d, 0x3c, 0x84, 0xb5, 0x24, 0x96, 0x15, 0x67, 0x59, 0x99, 0xcb, 0x52, 0x8d, 0x03, 0x59, 0xc9, + 0x47, 0x1d, 0xaa, 0x4e, 0x68, 0xfa, 0xee, 0x48, 0xc5, 0x24, 0x5c, 0x55, 0xae, 0xa9, 0x3d, 0x77, + 0x24, 0xe3, 0x0e, 0x32, 0x8d, 0x67, 0x9f, 0x2a, 0x9a, 0xd8, 0x7d, 0xb5, 0x6b, 0x9f, 0x4a, 0x9a, + 0x07, 0x70, 0x19, 0x9b, 0x2b, 0x57, 0x15, 0x07, 0x22, 0xf1, 0x03, 0xb9, 0x0a, 0x91, 0xb1, 0xf2, + 0x22, 0xec, 0x4b, 0x44, 0xea, 0x2a, 0x6a, 0xe0, 0x9f, 0x9a, 0xde, 0x74, 0x7c, 0xc0, 0x5b, 0x8c, + 0x54, 0x24, 0xe4, 0x55, 0x54, 0xc3, 0x3f, 0xed, 0x12, 0x0a, 0xfb, 0xeb, 0x3e, 0xac, 0xab, 0x75, + 0x3e, 0xa4, 0xa3, 0x41, 0x75, 0x9b, 0x7a, 0xd9, 0x58, 0x63, 0x44, 0x83, 0xe0, 0x48, 0xfb, 0x7e, + 0x4c, 0xcb, 0x97, 0x62, 0x89, 0x96, 0xd7, 0x5f, 0x2d, 0x4a, 0x6e, 0xc4, 0x22, 0x69, 0x13, 0x6e, + 0x45, 0x81, 0x35, 0x3c, 0x31, 0x2f, 0x5a, 0x80, 0xf2, 0x12, 0xee, 0x1b, 0x44, 0xd5, 0x58, 0xb8, + 0xfc, 0x7e, 0xc8, 0xfa, 0xad, 0xbd, 0x7e, 0xfd, 0xea, 0xbf, 0x57, 0x80, 0xf5, 0x39, 0xaf, 0x31, + 0x54, 0xe6, 0x93, 0x17, 0x26, 0xf1, 0x27, 0x0a, 0xee, 0x63, 0x2b, 0x1a, 0x1e, 0xa3, 0x7e, 0x78, + 0xe8, 0x9c, 0xa9, 0x97, 0x43, 0x09, 0xb6, 0x47, 0x20, 0xe4, 0xc6, 0x2c, 0xd3, 0xb1, 0x5f, 0x2d, + 0x0b, 0x58, 0x2c, 0x2e, 0xb2, 0xb7, 0xbd, 0x0a, 0x67, 0x52, 0xb8, 0x20, 0x9c, 0xc9, 0x0d, 0x28, + 0x79, 0x3e, 0x5d, 0x91, 0x9e, 0x9c, 0x48, 0xce, 0xbf, 0xea, 0xf9, 0x51, 0xcf, 0xdb, 0x3b, 0x41, + 0x16, 0x37, 0x0d, 0xe9, 0x92, 0xdb, 0x81, 0x1d, 0x84, 0xc7, 0x4e, 0xec, 0xbf, 0xc1, 0x82, 0xca, + 0xe5, 0x69, 0x68, 0xef, 0xc6, 0x38, 0x69, 0xeb, 0x6a, 0x40, 0x85, 0x66, 0xb2, 0x37, 0xf4, 0xc9, + 0x23, 0x8c, 0xaf, 0x14, 0xdc, 0x5a, 0xe0, 0x2a, 0xf7, 0xcc, 0x3e, 0x6f, 0x49, 0x2a, 0x03, 0xb7, + 0x14, 0x95, 0x10, 0xef, 0x53, 0x78, 0xa9, 0x03, 0x3b, 0xb1, 0xcf, 0x66, 0x19, 0x49, 0x89, 0xb0, + 0xb4, 0x8f, 0x3d, 0x83, 0xeb, 0xbc, 0x19, 0x8d, 0x27, 0xbe, 0x87, 0xe3, 0x91, 0x64, 0x0c, 0xb3, + 0xce, 0xd5, 0xa9, 0x4d, 0xf0, 0x2a, 0x6d, 0x56, 0x32, 0xc7, 0x9e, 0x2a, 0x8b, 0x7c, 0xe8, 0xd9, + 0xc3, 0x82, 0x3a, 0x0c, 0xe6, 0x5d, 0xd4, 0x08, 0x4b, 0xeb, 0xe9, 0x7d, 0xd0, 0xc2, 0xa1, 0xe5, + 0x5a, 0x41, 0x4a, 0x75, 0xe7, 0xcd, 0x62, 0x8d, 0xe1, 0x89, 0xd2, 0xf2, 0x26, 0xc0, 0x78, 0x1a, + 0x46, 0x26, 0x39, 0xfc, 0xa8, 0x40, 0xdc, 0x08, 0xa1, 0x13, 0x19, 0xfd, 0x26, 0xac, 0xb4, 0x63, + 0xef, 0xc0, 0x38, 0xde, 0x44, 0x5e, 0x3e, 0x4a, 0xe7, 0x43, 0x89, 0x5d, 0x4f, 0x76, 0xad, 0x89, + 0xb8, 0x0f, 0xf9, 0xb1, 0x35, 0x91, 0x37, 0x91, 0xe2, 0xa8, 0xf8, 0x12, 0xfb, 0x60, 0xd7, 0x9a, + 0xb0, 0x8d, 0x19, 0x89, 0x6e, 0x7c, 0x01, 0x45, 0x05, 0xf8, 0x51, 0xe6, 0xd3, 0xff, 0x76, 0x09, + 0x4a, 0x5b, 0x69, 0xef, 0x5e, 0xd4, 0xc3, 0xa3, 0x60, 0xea, 0x51, 0x13, 0xe5, 0xf3, 0x5b, 0x43, + 0xcb, 0x1b, 0x48, 0x90, 0x62, 0xa8, 0x4b, 0xaf, 0x60, 0xa8, 0x37, 0x01, 0xe4, 0xf2, 0x74, 0x46, + 0x4a, 0x07, 0x28, 0x06, 0xb8, 0x30, 0xdb, 0xa3, 0xb3, 0xc5, 0xf7, 0xa7, 0x0b, 0x3f, 0xfc, 0xfe, + 0xf4, 0xf2, 0xc2, 0xfb, 0xd3, 0xef, 0x26, 0x62, 0x3f, 0xed, 0x8d, 0xa3, 0x33, 0xf9, 0xd4, 0x8f, + 0x12, 0xf2, 0x71, 0x4f, 0x1c, 0x9d, 0x89, 0xaf, 0xa1, 0xa6, 0x5a, 0x27, 0xcb, 0x83, 0x4c, 0xd0, + 0x44, 0x89, 0x63, 0x77, 0xe0, 0x6a, 0x94, 0x4e, 0x66, 0x37, 0x8a, 0xf2, 0x6b, 0xee, 0x68, 0xff, + 0x0b, 0x39, 0x10, 0xd2, 0x99, 0x6b, 0x7b, 0xea, 0xba, 0x03, 0xfb, 0x8c, 0xf6, 0xa3, 0xfb, 0xb0, + 0x9e, 0xb9, 0x7c, 0x94, 0xd2, 0xb2, 0xd6, 0x52, 0xb7, 0x8d, 0x54, 0xa0, 0xea, 0xb9, 0xb0, 0xc4, + 0x4b, 0x0b, 0xc3, 0x12, 0x2f, 0x0e, 0x77, 0x7c, 0x1b, 0xca, 0xe9, 0xa0, 0xbe, 0xac, 0x76, 0xd3, + 0xb5, 0x11, 0x8e, 0xe7, 0xab, 0xff, 0xf7, 0x4b, 0x00, 0x89, 0xc3, 0xd9, 0x9f, 0xf6, 0xe5, 0xf7, + 0x05, 0x43, 0x92, 0x5f, 0x34, 0x24, 0xf7, 0x40, 0x4b, 0xd3, 0xa5, 0xa2, 0x4b, 0xd7, 0x12, 0x42, + 0xa5, 0x7e, 0x3a, 0x61, 0x3a, 0x42, 0x2f, 0xc5, 0x72, 0x93, 0xf7, 0x85, 0x19, 0xc9, 0x42, 0xac, + 0x64, 0x58, 0x45, 0x27, 0x64, 0x49, 0x80, 0xe4, 0x5f, 0x95, 0x93, 0xdc, 0x55, 0xfc, 0x69, 0x14, + 0xdf, 0x2c, 0x5a, 0x95, 0xf2, 0xaf, 0x2c, 0xe9, 0x05, 0xa3, 0xd5, 0xcd, 0xa2, 0xcf, 0xa1, 0x74, + 0x38, 0x75, 0x5d, 0x33, 0xb2, 0xcf, 0xd4, 0x6d, 0xa7, 0x7a, 0xc6, 0x57, 0x2f, 0x35, 0xbc, 0x46, + 0xf1, 0x50, 0x26, 0xf4, 0x7f, 0xba, 0x08, 0xcb, 0x6c, 0x94, 0xff, 0x02, 0x4a, 0x61, 0x34, 0x8e, + 0xd2, 0xd7, 0x66, 0xa4, 0x1f, 0x17, 0xe1, 0xe9, 0xd6, 0x0b, 0x6d, 0x1b, 0x2c, 0x35, 0x21, 0x2d, + 0xf1, 0xba, 0x0d, 0x58, 0x0e, 0x23, 0x7b, 0x12, 0xca, 0x98, 0x32, 0x9c, 0x10, 0x77, 0x60, 0xd9, + 0xf3, 0x47, 0xb3, 0x4f, 0x99, 0x74, 0x51, 0x13, 0x64, 0x84, 0xd0, 0x61, 0x25, 0x1e, 0xf1, 0xb9, + 0xab, 0x2b, 0x8c, 0xa1, 0x78, 0x74, 0xb6, 0x85, 0xdc, 0x57, 0x45, 0xeb, 0x8e, 0xd3, 0xa8, 0xb8, + 0xd0, 0x59, 0x9e, 0x75, 0xa4, 0x5e, 0x41, 0x90, 0x49, 0x71, 0x07, 0xca, 0xf8, 0xf3, 0x45, 0xe0, + 0x44, 0x76, 0xff, 0x91, 0x92, 0x29, 0x52, 0x20, 0x71, 0x0b, 0x60, 0x64, 0x47, 0xf6, 0x30, 0xea, + 0x7f, 0xef, 0x2a, 0xe3, 0x64, 0x0a, 0x22, 0xbe, 0x06, 0x71, 0x60, 0x0d, 0x4f, 0x8e, 0x02, 0xba, + 0x0a, 0xfa, 0xfd, 0xd4, 0x0e, 0x9c, 0x98, 0x71, 0x97, 0x53, 0x9d, 0x62, 0xac, 0x27, 0x64, 0xbf, + 0x60, 0x2a, 0x71, 0x15, 0x56, 0xc6, 0xd6, 0xd9, 0x96, 0x3f, 0x91, 0xd6, 0x7b, 0x99, 0x12, 0x8f, + 0xe0, 0x2a, 0xca, 0x28, 0xe9, 0xc8, 0x2a, 0xd2, 0x3d, 0x92, 0x39, 0x34, 0x4a, 0x30, 0x49, 0x48, + 0x15, 0x79, 0x86, 0xbe, 0x09, 0x1b, 0xca, 0x38, 0xaf, 0x5e, 0x30, 0x1a, 0x3a, 0x71, 0x40, 0xd3, + 0xb9, 0xc9, 0x7f, 0x59, 0x12, 0x6f, 0xa5, 0x68, 0xc5, 0xdb, 0x50, 0xc5, 0x0f, 0x07, 0x76, 0x34, + 0x0d, 0x3c, 0xdc, 0xfb, 0x58, 0xa2, 0x40, 0x01, 0xd1, 0x50, 0x30, 0xf6, 0xf7, 0x96, 0x09, 0xbe, + 0xa1, 0xc0, 0x12, 0x43, 0x35, 0x86, 0xd2, 0x25, 0x85, 0x47, 0x70, 0x95, 0x3d, 0x49, 0xc3, 0xef, + 0x5d, 0x29, 0x67, 0x99, 0xc9, 0xd5, 0x99, 0xa2, 0x71, 0x99, 0xb0, 0xfd, 0xef, 0x5d, 0x16, 0xb5, + 0x78, 0xaf, 0xef, 0xc1, 0xd5, 0xa9, 0x17, 0xd8, 0xa1, 0xef, 0xbe, 0x8c, 0x23, 0x47, 0x1f, 0x3b, + 0x28, 0x5e, 0x6b, 0xe9, 0x2b, 0x87, 0xfb, 0x31, 0x8d, 0xbc, 0x7c, 0xe8, 0x45, 0xc6, 0xc6, 0x74, + 0x1e, 0x18, 0x8a, 0xdf, 0x86, 0x9b, 0xe4, 0x28, 0x35, 0x96, 0x4f, 0x24, 0xc9, 0xbe, 0x09, 0x51, + 0x5c, 0x98, 0x8e, 0x0e, 0xa5, 0xde, 0x5c, 0x47, 0x1a, 0xf5, 0x8a, 0x12, 0xf7, 0x48, 0xd8, 0xf3, + 0xf6, 0x47, 0x87, 0xe2, 0xa7, 0xb0, 0x46, 0xf9, 0xe3, 0x90, 0xd5, 0x2c, 0xe8, 0xc7, 0xec, 0xf5, + 0xb9, 0x63, 0x9f, 0x1a, 0x0a, 0x67, 0xd4, 0x5e, 0xa6, 0x93, 0xa1, 0xf8, 0x12, 0xca, 0xc3, 0xe4, + 0x01, 0x17, 0x79, 0xb5, 0x66, 0xc1, 0x3b, 0x52, 0x13, 0x7b, 0x68, 0xa4, 0x29, 0x45, 0x17, 0x36, + 0xd4, 0x43, 0x84, 0x99, 0xc1, 0xe4, 0x6b, 0x71, 0x6f, 0x64, 0x1e, 0x24, 0xdc, 0x73, 0x2d, 0x2f, + 0x1e, 0xc5, 0x73, 0xe3, 0xb2, 0xcc, 0x98, 0x1e, 0x58, 0xfd, 0x77, 0xa1, 0x9a, 0x59, 0x94, 0x73, + 0x2e, 0x5d, 0xfd, 0x56, 0xa7, 0xd5, 0x1c, 0xb0, 0xd3, 0x85, 0x74, 0x32, 0x5a, 0x4a, 0x79, 0x23, + 0x15, 0x52, 0xce, 0x18, 0xf4, 0xca, 0xce, 0x6e, 0xcb, 0x78, 0xd2, 0x22, 0x7f, 0x99, 0xbc, 0x96, + 0xd7, 0xff, 0xc5, 0x25, 0x58, 0x1f, 0x04, 0x96, 0x17, 0xca, 0x07, 0xcf, 0xbd, 0x28, 0xf0, 0x5d, + 0xf1, 0x35, 0x14, 0xa3, 0xa1, 0x9b, 0xe6, 0x12, 0xb7, 0xd5, 0x9e, 0x34, 0x43, 0xfa, 0x60, 0x30, + 0x64, 0x87, 0xf7, 0xd5, 0x88, 0x7f, 0x88, 0x8f, 0x60, 0xf9, 0xc0, 0x3e, 0x72, 0x3c, 0xb9, 0x2d, + 0x5f, 0x99, 0xcd, 0xb8, 0x89, 0xc8, 0x9d, 0x4b, 0x06, 0x53, 0x89, 0x4f, 0x60, 0x45, 0x1e, 0xd5, + 0xe5, 0xd3, 0xf7, 0x4e, 0xd2, 0x1f, 0x42, 0xec, 0xce, 0x25, 0x43, 0xd2, 0x89, 0x2f, 0xa0, 0x18, + 0xf8, 0xf2, 0x75, 0xc3, 0x42, 0x9a, 0x07, 0x26, 0x79, 0x0c, 0x89, 0xdf, 0xb9, 0x64, 0xc4, 0xb4, + 0xfa, 0x03, 0x58, 0x95, 0x95, 0xc5, 0x6e, 0xd8, 0x6c, 0x3d, 0x69, 0xcb, 0x1e, 0x6c, 0xf6, 0x76, + 0x77, 0xdb, 0x03, 0x8e, 0x01, 0x6e, 0xf4, 0x3a, 0x9d, 0xcd, 0x46, 0xf3, 0x99, 0xb6, 0xb4, 0x59, + 0x84, 0x15, 0x5e, 0xbb, 0xfa, 0x3f, 0x9a, 0x83, 0xb5, 0x99, 0x06, 0x88, 0xc7, 0x50, 0x18, 0xab, + 0xd7, 0x97, 0x6a, 0xea, 0x04, 0x7e, 0x86, 0x28, 0x95, 0x66, 0xf3, 0x18, 0xe6, 0xd0, 0xbf, 0x82, + 0x5a, 0x16, 0x9e, 0x72, 0xe9, 0xa9, 0x42, 0xc9, 0x68, 0x35, 0xb6, 0xcc, 0x5e, 0xb7, 0xf3, 0x2d, + 0x7b, 0xe5, 0x51, 0xf2, 0x85, 0xd1, 0x26, 0x5f, 0x9a, 0xdf, 0x01, 0x6d, 0xb6, 0x63, 0xc4, 0x13, + 0x58, 0x43, 0x11, 0xd4, 0xb5, 0xd9, 0x09, 0x32, 0x19, 0xb2, 0x5b, 0x0b, 0x7a, 0x52, 0x92, 0xf1, + 0x05, 0xf7, 0x61, 0x26, 0xad, 0xff, 0x2e, 0x88, 0xf9, 0x1e, 0xfc, 0xd3, 0x2b, 0xfe, 0xff, 0xcc, + 0x41, 0x01, 0x27, 0xbc, 0x78, 0x1b, 0x96, 0xf9, 0xd4, 0x38, 0x97, 0xbe, 0x6f, 0x49, 0xac, 0x16, + 0xa7, 0x05, 0xe1, 0xc4, 0x07, 0x90, 0x8f, 0x86, 0x2a, 0xda, 0xf7, 0xb5, 0x0b, 0x26, 0xdf, 0xce, + 0x25, 0x03, 0xa9, 0xc4, 0x3d, 0xc8, 0x8f, 0x46, 0x2a, 0x54, 0x5c, 0xca, 0xa7, 0x60, 0xcb, 0x3e, + 0x74, 0x3c, 0x47, 0x3e, 0xb9, 0x87, 0x24, 0xe2, 0x1d, 0xc8, 0x8f, 0x86, 0x6e, 0x36, 0xee, 0x1f, + 0x1f, 0xf7, 0xc7, 0x05, 0x8e, 0x86, 0x2e, 0xaa, 0xa3, 0x51, 0x70, 0x6e, 0x06, 0x53, 0x8f, 0x22, + 0xa5, 0xa8, 0xd7, 0x29, 0xcb, 0x28, 0xe2, 0x4e, 0x29, 0xdc, 0x4a, 0x28, 0xc3, 0x06, 0xcb, 0x67, + 0xdb, 0x94, 0xf9, 0xd4, 0x09, 0xe5, 0x03, 0x6f, 0x9b, 0x2b, 0x50, 0xc0, 0xd2, 0xf5, 0x0f, 0xe9, + 0x55, 0xa1, 0xe9, 0xd8, 0xc3, 0xbd, 0x50, 0xea, 0x69, 0xf3, 0xcf, 0x40, 0x4b, 0x8c, 0xfe, 0xf7, + 0xf2, 0x50, 0x4e, 0xd5, 0x47, 0x7c, 0x06, 0xc5, 0x51, 0x76, 0x21, 0x5e, 0x9f, 0xab, 0xf4, 0x83, + 0x2d, 0xb5, 0x04, 0x47, 0x72, 0x7a, 0xd3, 0x6d, 0x8a, 0xc8, 0x7c, 0x69, 0x05, 0x0e, 0xdf, 0xfa, + 0x5e, 0x4a, 0x5f, 0x6b, 0xe8, 0xdb, 0xd1, 0x73, 0x85, 0xd9, 0xb9, 0x64, 0x54, 0xc2, 0x54, 0x9a, + 0x4c, 0x7e, 0xb2, 0x49, 0xf9, 0xcc, 0xfb, 0xc2, 0x0c, 0xdc, 0xb9, 0x64, 0x28, 0x3c, 0x92, 0xda, + 0x67, 0xf6, 0x70, 0x1a, 0x29, 0x93, 0x5f, 0x55, 0x35, 0x88, 0x80, 0xf4, 0xb6, 0x3b, 0xff, 0x14, + 0x0f, 0x71, 0x2b, 0xb6, 0x5c, 0xd7, 0x27, 0x49, 0x7e, 0x39, 0x7d, 0x52, 0xb7, 0x15, 0xc3, 0xf9, + 0x2d, 0x79, 0x95, 0x12, 0xef, 0xc2, 0xb2, 0x1f, 0x1d, 0xdb, 0xca, 0xc0, 0xa0, 0xde, 0x27, 0x42, + 0xd0, 0x56, 0xb3, 0x83, 0x33, 0x85, 0xd0, 0xfa, 0xef, 0xe7, 0x60, 0x55, 0xf6, 0x80, 0x58, 0x87, + 0x6a, 0xbf, 0x35, 0x30, 0x9f, 0x37, 0x8c, 0x76, 0x63, 0xb3, 0xd3, 0x92, 0xe1, 0x0a, 0x9f, 0x18, + 0x8d, 0xae, 0x64, 0x90, 0x46, 0xeb, 0x79, 0xef, 0x59, 0x8b, 0xfd, 0xe4, 0xb6, 0x5a, 0xdd, 0x6f, + 0xb5, 0x3c, 0xbb, 0xa0, 0xb6, 0xf6, 0x1a, 0x06, 0xf2, 0xca, 0x32, 0xac, 0xb6, 0xbe, 0x69, 0x35, + 0xf7, 0x89, 0x59, 0xd6, 0x00, 0xb6, 0x5a, 0x8d, 0x4e, 0xa7, 0xd7, 0x44, 0xe6, 0xb9, 0x22, 0x04, + 0xd4, 0x9a, 0x46, 0xab, 0x31, 0x68, 0x99, 0x8d, 0x66, 0xb3, 0xb7, 0xdf, 0x1d, 0x68, 0xab, 0xf8, + 0xc5, 0x46, 0x67, 0xd0, 0x32, 0x62, 0x10, 0xbd, 0x04, 0xbb, 0x65, 0xf4, 0xf6, 0x62, 0x48, 0x69, + 0xb3, 0x04, 0xab, 0x43, 0x1e, 0x2b, 0xfd, 0xdf, 0x5e, 0x67, 0x17, 0x91, 0x64, 0x6a, 0x8a, 0x2f, + 0xa1, 0x38, 0x1a, 0x65, 0xc6, 0xf8, 0xe6, 0xa2, 0x29, 0xfc, 0x60, 0x6b, 0xa4, 0x86, 0x99, 0x7f, + 0x88, 0xb7, 0xd4, 0x42, 0x5a, 0x9a, 0x5b, 0x48, 0x6a, 0x19, 0xfd, 0x0c, 0xd6, 0xe4, 0x73, 0x35, + 0xf1, 0xe9, 0x72, 0x66, 0x95, 0x34, 0x09, 0xb9, 0x25, 0x71, 0x3b, 0x97, 0x8c, 0xda, 0x30, 0x03, + 0x11, 0x3f, 0x85, 0x9a, 0xc5, 0x67, 0xb6, 0xe9, 0xd3, 0xe9, 0x78, 0x13, 0x6d, 0xd0, 0x91, 0x6d, + 0x92, 0xbd, 0x6a, 0xa5, 0x01, 0x38, 0x11, 0x47, 0x81, 0x3f, 0x49, 0x32, 0x2f, 0x67, 0xee, 0xd7, + 0x04, 0xfe, 0x24, 0x95, 0xb7, 0x32, 0x4a, 0xa5, 0xc5, 0x17, 0x50, 0x91, 0x35, 0x4f, 0xce, 0x27, + 0xe2, 0x25, 0xcb, 0xd5, 0x26, 0x9d, 0x63, 0xe7, 0x92, 0x51, 0x1e, 0x26, 0x49, 0xf1, 0x08, 0x15, + 0x8d, 0x44, 0x43, 0x5b, 0x4d, 0xcf, 0x35, 0xaa, 0xad, 0xca, 0x05, 0x56, 0x9c, 0x12, 0x9f, 0x00, + 0x50, 0x3d, 0x39, 0x4f, 0x31, 0x73, 0xf3, 0x34, 0xf0, 0x27, 0x2a, 0x4b, 0x69, 0xa4, 0x12, 0xa9, + 0xea, 0xb1, 0xe9, 0xb3, 0x34, 0x5f, 0x3d, 0x96, 0x65, 0xe2, 0xea, 0xb1, 0x15, 0x34, 0xae, 0x1e, + 0x67, 0x83, 0xb9, 0xea, 0xa9, 0x5c, 0x5c, 0x3d, 0xce, 0xa4, 0xaa, 0xc7, 0x79, 0xca, 0xb3, 0xd5, + 0x53, 0x59, 0xa8, 0x7a, 0x9c, 0xe3, 0xa7, 0x73, 0xaa, 0x65, 0xe5, 0x42, 0xd5, 0x12, 0x87, 0x2d, + 0xab, 0x5c, 0xfe, 0x14, 0x6a, 0xe1, 0xb1, 0x7f, 0x9a, 0x62, 0x20, 0xd5, 0x74, 0xee, 0xfe, 0xb1, + 0x7f, 0x9a, 0xe6, 0x20, 0xd5, 0x30, 0x0d, 0xc0, 0xda, 0x72, 0x13, 0xe9, 0x39, 0x83, 0x5a, 0xba, + 0xb6, 0xd4, 0x42, 0x14, 0xbc, 0xb0, 0xb6, 0x96, 0x4a, 0x60, 0xa7, 0x24, 0x67, 0x35, 0xa1, 0x3c, + 0x7d, 0xc9, 0xdc, 0xd7, 0x94, 0x5f, 0x82, 0xf8, 0xd4, 0x26, 0xc4, 0xb9, 0x35, 0xf5, 0xd2, 0xd9, + 0xb4, 0xf4, 0xdc, 0xda, 0xf7, 0x32, 0x19, 0x2b, 0x4c, 0x2a, 0xb3, 0x26, 0xab, 0x22, 0xb4, 0xbf, + 0x9f, 0xa2, 0xc0, 0x27, 0xef, 0x65, 0x67, 0x56, 0x45, 0x5f, 0xe2, 0x92, 0x55, 0xa1, 0x20, 0xf1, + 0xbc, 0x8e, 0xb3, 0x8b, 0xd9, 0x79, 0x9d, 0xca, 0x4c, 0xf3, 0x3a, 0xce, 0x1a, 0x2f, 0xa8, 0x38, + 0xef, 0xe5, 0xb9, 0x05, 0x95, 0xca, 0xcc, 0x0b, 0x2a, 0xce, 0xfd, 0x08, 0xe4, 0x6c, 0xe2, 0xce, + 0xcd, 0xdc, 0xde, 0xe6, 0x5a, 0xcb, 0xde, 0x85, 0x61, 0x9c, 0xc2, 0xb9, 0x1a, 0xd8, 0xa8, 0xca, + 0xca, 0xa9, 0x70, 0x25, 0xf3, 0x36, 0x36, 0x61, 0xe2, 0xa5, 0x14, 0x24, 0xc9, 0xd4, 0xc7, 0x26, + 0x4e, 0x14, 0xd4, 0x47, 0xf3, 0x1f, 0xdb, 0x73, 0xa2, 0x20, 0xf9, 0x18, 0xa6, 0xc4, 0x47, 0x40, + 0xd3, 0x90, 0xb3, 0xd8, 0x69, 0xd6, 0x8d, 0xdd, 0x22, 0x33, 0x14, 0x47, 0xf2, 0x37, 0x4e, 0x16, + 0xf9, 0x8d, 0xe1, 0x68, 0x58, 0x3f, 0x4c, 0x4f, 0x16, 0xfe, 0x44, 0x73, 0xab, 0x89, 0x93, 0x85, + 0x89, 0x9a, 0xa3, 0xa1, 0xb8, 0x0f, 0x94, 0x9b, 0xe8, 0x8f, 0x32, 0xef, 0xdf, 0x05, 0xfe, 0x84, + 0xa9, 0x57, 0x91, 0x00, 0x69, 0xb1, 0x05, 0xae, 0xef, 0xa9, 0x86, 0x1f, 0x67, 0x5a, 0x80, 0x88, + 0x98, 0x19, 0x0c, 0xe3, 0x94, 0xfe, 0x8f, 0xaf, 0xc0, 0xaa, 0xe4, 0xb5, 0xe2, 0x32, 0xac, 0x49, + 0x96, 0xbf, 0xd5, 0x18, 0x34, 0x36, 0x1b, 0x7d, 0x14, 0xd2, 0x04, 0xd4, 0x98, 0xe7, 0xc7, 0xb0, + 0x1c, 0xee, 0x03, 0xc4, 0xf4, 0x63, 0x10, 0xbd, 0x81, 0x29, 0xf3, 0xb2, 0x37, 0x72, 0x5e, 0xac, + 0x41, 0x99, 0x33, 0x32, 0x80, 0xa2, 0x27, 0x53, 0x2e, 0x4e, 0x2f, 0xa7, 0xb2, 0xb0, 0x3f, 0xf9, + 0x4a, 0x92, 0x85, 0x01, 0xab, 0x71, 0x16, 0xe5, 0x70, 0x2e, 0xa0, 0x36, 0x30, 0xf6, 0xbb, 0xcd, + 0xe4, 0x3b, 0x25, 0x8a, 0x78, 0xcb, 0xc5, 0x3c, 0x6f, 0xb7, 0x5e, 0x68, 0x40, 0x8f, 0x6d, 0x52, + 0x29, 0x94, 0x26, 0x47, 0x74, 0x2a, 0x84, 0x92, 0x15, 0x71, 0x0d, 0x2e, 0xf7, 0x77, 0x7a, 0x2f, + 0x4c, 0xce, 0x14, 0x37, 0xa1, 0x2a, 0x36, 0x40, 0x4b, 0x21, 0xb8, 0xf8, 0x1a, 0x7e, 0x92, 0xa0, + 0x8a, 0xb0, 0xaf, 0xad, 0xd1, 0x83, 0x39, 0x08, 0x1b, 0xf0, 0xbe, 0xab, 0x61, 0x53, 0x38, 0x6b, + 0xaf, 0xb3, 0xbf, 0xdb, 0xed, 0x6b, 0xeb, 0x58, 0x09, 0x82, 0x70, 0xcd, 0x45, 0x5c, 0x4c, 0xb2, + 0x5b, 0x5f, 0xa6, 0x0d, 0x1c, 0x61, 0x2f, 0x1a, 0x46, 0xb7, 0xdd, 0x7d, 0xd2, 0xd7, 0x36, 0xe2, + 0x92, 0x5b, 0x86, 0xd1, 0x33, 0xfa, 0xda, 0x95, 0x18, 0xd0, 0x1f, 0x34, 0x06, 0xfb, 0x7d, 0xed, + 0x6a, 0x5c, 0xcb, 0x3d, 0xa3, 0xd7, 0x6c, 0xf5, 0xfb, 0x9d, 0x76, 0x7f, 0xa0, 0x5d, 0x13, 0x57, + 0x60, 0x3d, 0xa9, 0x91, 0x22, 0xae, 0xa7, 0x2a, 0x6a, 0x3c, 0x69, 0x0d, 0xb4, 0xeb, 0x71, 0x35, + 0x9a, 0xbd, 0x4e, 0xa7, 0x41, 0xae, 0xee, 0x37, 0x90, 0x88, 0x2e, 0x70, 0xc8, 0xd6, 0xbc, 0x81, + 0xf5, 0xda, 0xef, 0xa6, 0x41, 0x37, 0x53, 0x53, 0xa3, 0xdf, 0xfa, 0xc5, 0x7e, 0xab, 0xdb, 0x6c, + 0x69, 0x6f, 0x26, 0x53, 0x23, 0x86, 0xdd, 0x8a, 0xa7, 0x46, 0x0c, 0xba, 0x1d, 0x7f, 0x53, 0x81, + 0xfa, 0xda, 0x9d, 0xb8, 0xc3, 0xf6, 0xf7, 0x9e, 0x18, 0x8d, 0xad, 0x96, 0xa6, 0x23, 0xc4, 0x68, + 0x75, 0x1b, 0xbb, 0x6a, 0x60, 0xdf, 0x4e, 0x0d, 0xec, 0x5e, 0x7b, 0x60, 0x68, 0x77, 0xe3, 0x81, + 0xa4, 0xe4, 0x3b, 0xe2, 0x0d, 0xb8, 0x96, 0x9e, 0x72, 0xe6, 0x8b, 0xf6, 0x60, 0x47, 0xde, 0xb3, + 0x78, 0x97, 0x7d, 0xef, 0x09, 0xd9, 0xdc, 0x6a, 0xf2, 0x85, 0x12, 0xca, 0x8b, 0xa9, 0x7b, 0x7a, + 0xa1, 0xf8, 0x96, 0xf6, 0xd6, 0xfd, 0x35, 0xd9, 0x15, 0xdd, 0x2e, 0xdd, 0xb4, 0xe8, 0x6f, 0x56, + 0x50, 0x72, 0x53, 0x22, 0x88, 0xfe, 0x14, 0x44, 0x7f, 0x7a, 0x10, 0x0e, 0x03, 0x87, 0x42, 0x36, + 0xc8, 0x00, 0x17, 0x02, 0x0a, 0x87, 0x81, 0x3f, 0x56, 0x9e, 0x3a, 0xf8, 0x5b, 0xdc, 0x81, 0xf2, + 0x64, 0x7a, 0x40, 0x57, 0x05, 0x92, 0x58, 0xe5, 0x69, 0x90, 0xfe, 0xbf, 0xe4, 0xa0, 0x96, 0x15, + 0x3f, 0xe8, 0x14, 0xe8, 0xd0, 0xf4, 0xfc, 0x88, 0x9f, 0x34, 0x0b, 0x95, 0xcd, 0xd7, 0x39, 0xec, + 0xfa, 0x11, 0xbd, 0x69, 0x16, 0x66, 0x1c, 0xe5, 0x96, 0x66, 0x1c, 0xe5, 0xda, 0x70, 0x39, 0x4c, + 0x55, 0xcf, 0xcc, 0x3c, 0x28, 0x57, 0x8f, 0x1f, 0x1d, 0x9e, 0xa9, 0xbf, 0x21, 0xc2, 0xf9, 0x36, + 0xc9, 0x88, 0xf3, 0x85, 0x38, 0xe2, 0xbc, 0x78, 0x08, 0x45, 0xe9, 0xdf, 0x1a, 0x4a, 0x31, 0xe6, + 0x6a, 0x22, 0xa6, 0xe1, 0xe7, 0xe5, 0xeb, 0x8a, 0xa1, 0x11, 0xd3, 0xe9, 0x7f, 0x1e, 0xaa, 0x19, + 0x09, 0x89, 0x0c, 0x83, 0x87, 0xd9, 0xd6, 0x15, 0x9d, 0xc3, 0x1f, 0xd0, 0xb4, 0xf4, 0xd7, 0xf3, + 0x3f, 0xf0, 0xeb, 0x7f, 0x2d, 0x07, 0x95, 0xb4, 0x8c, 0xf5, 0x9b, 0x7f, 0xfd, 0x36, 0x94, 0xd5, + 0x6f, 0xf5, 0xbe, 0x73, 0xc1, 0x00, 0x05, 0x22, 0x6f, 0xd7, 0x32, 0x1f, 0xdc, 0x6d, 0x9f, 0xf4, + 0xe3, 0x6e, 0x4b, 0x83, 0xc8, 0x89, 0xf1, 0xd8, 0x1e, 0x9e, 0x6c, 0x3f, 0x43, 0x02, 0xe5, 0xc4, + 0x18, 0x43, 0xf4, 0xdb, 0x50, 0xda, 0x3e, 0x51, 0xd7, 0x7d, 0xd3, 0x0f, 0x08, 0x96, 0x38, 0x90, + 0xbe, 0xfe, 0x07, 0x39, 0xa8, 0x25, 0xa6, 0x33, 0xba, 0x43, 0x51, 0x83, 0xa5, 0xd1, 0x81, 0x9c, + 0x76, 0x4b, 0xa3, 0x83, 0xc4, 0x51, 0x75, 0x29, 0xed, 0xa8, 0xfa, 0xb6, 0x2c, 0x2c, 0x9f, 0xde, + 0x5c, 0xe2, 0x6f, 0xc9, 0x30, 0xfd, 0x8f, 0xa0, 0x82, 0xff, 0xc9, 0x02, 0x14, 0xd8, 0xa3, 0x6c, + 0xe8, 0xb3, 0x84, 0x38, 0x43, 0x44, 0xda, 0xa4, 0x74, 0x81, 0xbd, 0xe0, 0x41, 0x21, 0x7a, 0xe8, + 0xea, 0xef, 0x2f, 0x43, 0x39, 0x25, 0xb1, 0xfe, 0xa0, 0x69, 0x7e, 0x13, 0x4a, 0xc9, 0xf3, 0x36, + 0x32, 0x36, 0x7a, 0x0c, 0xc8, 0x8c, 0x55, 0x7e, 0x66, 0xac, 0xc8, 0x5f, 0x9c, 0x02, 0xb2, 0x26, + 0xfe, 0xe2, 0x94, 0xcc, 0x9e, 0x19, 0x2c, 0xbf, 0xe6, 0x70, 0xf9, 0x53, 0xa8, 0xa4, 0x0c, 0xfe, + 0xca, 0xb3, 0x74, 0x96, 0xbe, 0x9c, 0x18, 0xff, 0x43, 0x71, 0x05, 0x56, 0x0e, 0x4f, 0xcc, 0xd1, + 0x01, 0xbb, 0x5c, 0x94, 0x8c, 0xe5, 0xc3, 0x93, 0xad, 0x03, 0x72, 0x31, 0x39, 0x8c, 0x85, 0x34, + 0x36, 0xc3, 0x16, 0x0f, 0x95, 0x28, 0x76, 0x0f, 0x56, 0x0f, 0x4f, 0xd2, 0x11, 0x96, 0xe7, 0xba, + 0x7c, 0xe5, 0xf0, 0x84, 0x82, 0xfc, 0x7e, 0x0c, 0x1b, 0x52, 0x52, 0xb0, 0x42, 0x65, 0x95, 0xc4, + 0x25, 0xca, 0xcf, 0x09, 0xae, 0x33, 0xae, 0x11, 0xb2, 0x4d, 0x12, 0x67, 0x9c, 0x0e, 0x95, 0xd4, + 0x04, 0x64, 0x73, 0x6a, 0xc9, 0xc8, 0xc0, 0xc4, 0x63, 0xa8, 0x1c, 0x9e, 0xf0, 0x80, 0x0e, 0xfc, + 0x5d, 0x5b, 0x46, 0x1c, 0xda, 0x98, 0x1d, 0x4a, 0xba, 0xe4, 0x92, 0xa1, 0x14, 0x57, 0x61, 0xc5, + 0xb0, 0x4e, 0xfb, 0xbf, 0xe8, 0x90, 0xb8, 0x5a, 0x32, 0x64, 0x4a, 0x34, 0xe1, 0x4a, 0xca, 0x0e, + 0x7a, 0x78, 0x62, 0x72, 0xf4, 0x1d, 0x65, 0x06, 0x9d, 0xb7, 0xe6, 0x26, 0xd4, 0xdb, 0x27, 0x1c, + 0xf8, 0x30, 0x14, 0x5f, 0xc2, 0xda, 0xe1, 0x09, 0x9d, 0x3e, 0x98, 0x32, 0x9a, 0x8d, 0x14, 0x50, + 0xd7, 0x12, 0x87, 0x2b, 0x79, 0x2c, 0x74, 0x78, 0x82, 0xbd, 0xb4, 0xc9, 0x54, 0xa2, 0x09, 0xeb, + 0xf1, 0x42, 0x8d, 0xf9, 0x85, 0x78, 0x25, 0xbf, 0xd0, 0x46, 0x33, 0x10, 0xd1, 0x82, 0xdb, 0xc3, + 0xc8, 0x0a, 0x4d, 0xd6, 0xde, 0x91, 0x91, 0x4e, 0x02, 0x3f, 0xf2, 0x87, 0xbe, 0x1b, 0x3b, 0xbc, + 0x72, 0x44, 0xd5, 0x9b, 0x48, 0xd6, 0x52, 0x54, 0x7b, 0x92, 0x48, 0xba, 0xbf, 0x72, 0xdc, 0x2e, + 0xfd, 0x3f, 0xcc, 0x41, 0x2d, 0xd1, 0xbb, 0x90, 0x1d, 0x89, 0xfb, 0xfc, 0xfe, 0x31, 0xeb, 0xba, + 0xf5, 0x59, 0xd5, 0x0c, 0x49, 0x1e, 0x0c, 0xce, 0x27, 0xfc, 0x0e, 0xf2, 0xa2, 0xd7, 0xcd, 0x16, + 0x9d, 0x45, 0xe5, 0x17, 0x9d, 0x45, 0xe9, 0x4f, 0x20, 0x3f, 0x38, 0x9f, 0xb0, 0x8d, 0x0f, 0xc5, + 0x10, 0xb6, 0x07, 0xb0, 0x00, 0x42, 0xd7, 0xeb, 0x9e, 0xb5, 0xbe, 0xe5, 0x57, 0x2d, 0xf6, 0x8c, + 0xf6, 0x6e, 0xc3, 0xf8, 0xd6, 0x44, 0x00, 0x09, 0x6a, 0xdb, 0x3d, 0xa3, 0xd5, 0x7e, 0xd2, 0x25, + 0x40, 0x81, 0x2c, 0x80, 0x49, 0x15, 0x1b, 0xa3, 0xd1, 0xf6, 0x49, 0xfa, 0x61, 0xa8, 0x5c, 0xe6, + 0x61, 0xa8, 0xf8, 0x0d, 0xb5, 0xf4, 0x7b, 0xa0, 0x51, 0x7c, 0x40, 0x26, 0x62, 0x7e, 0x14, 0x33, + 0x37, 0xf1, 0x1e, 0x14, 0x0e, 0x4f, 0xec, 0xf3, 0xac, 0x72, 0x9d, 0x65, 0x25, 0x44, 0xa0, 0xff, + 0x51, 0x0e, 0x44, 0xa6, 0x22, 0xac, 0xef, 0xfd, 0xa6, 0x75, 0xf9, 0x12, 0xea, 0xea, 0x09, 0x62, + 0xa2, 0x4a, 0x1d, 0x7e, 0xc9, 0x2e, 0xbd, 0xe2, 0x27, 0x31, 0x3f, 0x92, 0x07, 0xd8, 0xc4, 0xc7, + 0xc0, 0x4f, 0x7d, 0xd2, 0xed, 0xb0, 0xc2, 0x05, 0xba, 0xb9, 0x91, 0xd0, 0x24, 0x6f, 0x7b, 0xa6, + 0xdf, 0x2c, 0xe5, 0x73, 0xb3, 0xb5, 0x64, 0xd4, 0x88, 0xfb, 0xe9, 0x7f, 0x25, 0x07, 0x97, 0xb3, + 0x13, 0xe2, 0x4f, 0xd6, 0xca, 0xec, 0x03, 0xad, 0xf9, 0xd9, 0x07, 0x5a, 0x17, 0xcd, 0xa7, 0xc2, + 0xc2, 0xf9, 0xf4, 0x17, 0x72, 0xb0, 0x91, 0xea, 0xfd, 0x44, 0x43, 0xff, 0x33, 0xaa, 0x59, 0xea, + 0x9d, 0xd6, 0x42, 0xe6, 0x9d, 0x56, 0xfd, 0xef, 0xe4, 0xe0, 0xea, 0x4c, 0x4d, 0x0c, 0xfb, 0xcf, + 0xb4, 0x2e, 0xd9, 0xf7, 0x5c, 0xe9, 0xec, 0x4e, 0xbd, 0xfc, 0x80, 0xbc, 0x40, 0x64, 0x1f, 0x68, + 0x25, 0xaf, 0x82, 0x37, 0xe5, 0x03, 0x41, 0x66, 0x78, 0xee, 0x0d, 0xe5, 0x60, 0x97, 0x08, 0xd2, + 0x3f, 0xf7, 0x86, 0xb8, 0x5d, 0x8f, 0xed, 0xe0, 0x48, 0x19, 0x4f, 0x39, 0xa1, 0xff, 0x9b, 0x39, + 0xb8, 0x3e, 0xd3, 0xb2, 0xc6, 0x34, 0xf2, 0xa5, 0x13, 0xd0, 0x9f, 0x51, 0xe3, 0x6e, 0x03, 0xbd, + 0x5d, 0xa6, 0xbc, 0x8f, 0x52, 0xb7, 0x86, 0xe4, 0x77, 0x35, 0xc8, 0x8f, 0xac, 0x73, 0x19, 0x38, + 0x1c, 0x7f, 0xe2, 0x32, 0x3e, 0xf6, 0xa7, 0x81, 0xbc, 0xe6, 0x42, 0xbf, 0xf5, 0xcf, 0x60, 0x3d, + 0xa9, 0x7a, 0x53, 0x3e, 0xb6, 0x7b, 0x1b, 0xca, 0x9e, 0x7d, 0x6a, 0xaa, 0xa7, 0x78, 0xe5, 0x05, + 0x48, 0xcf, 0x3e, 0x95, 0x04, 0xfa, 0x76, 0x9a, 0x43, 0x52, 0x75, 0xae, 0x43, 0xd1, 0x77, 0x47, + 0x19, 0xb7, 0x67, 0xdf, 0x1d, 0x29, 0x14, 0x96, 0x96, 0x6a, 0xe5, 0xaa, 0x67, 0x9f, 0xd2, 0xec, + 0x3c, 0x95, 0xe5, 0x34, 0x46, 0xca, 0x59, 0x6f, 0x91, 0x0f, 0xfd, 0x75, 0x28, 0x4e, 0x82, 0x4c, + 0x37, 0xad, 0x4e, 0x02, 0xfe, 0xec, 0x5d, 0x79, 0xbd, 0xf2, 0x22, 0x67, 0x4f, 0xbe, 0x70, 0xa9, + 0x41, 0x7e, 0xe2, 0x87, 0xd2, 0x9b, 0x0c, 0x7f, 0xea, 0x9f, 0x4b, 0xe6, 0x48, 0x1a, 0x38, 0x7f, + 0x59, 0x83, 0xbc, 0x33, 0x3a, 0xa3, 0x0f, 0x57, 0x0d, 0xfc, 0x49, 0x12, 0xb5, 0xfd, 0xbd, 0xbc, + 0xe1, 0x89, 0x3f, 0xf5, 0x4d, 0x28, 0x1b, 0x19, 0x73, 0x43, 0x25, 0x65, 0xb9, 0x0b, 0xb3, 0x0f, + 0x31, 0x25, 0x1d, 0x64, 0x94, 0x13, 0xc3, 0x5d, 0xa8, 0x87, 0x92, 0x1d, 0x3e, 0xb7, 0x82, 0xe1, + 0xb1, 0x15, 0x74, 0x6c, 0xef, 0x28, 0x3a, 0xc6, 0x2e, 0x97, 0x4f, 0xa5, 0xa7, 0x9a, 0x0f, 0x0c, + 0x52, 0xd3, 0x01, 0x7b, 0xd1, 0x25, 0x72, 0xe9, 0x89, 0x52, 0xf2, 0xec, 0x53, 0x99, 0xff, 0x4d, + 0x00, 0xec, 0x7f, 0x89, 0x96, 0x57, 0xcc, 0x7c, 0x77, 0xc4, 0x68, 0x7d, 0x5d, 0xb6, 0x57, 0x06, + 0xbe, 0xdf, 0xb2, 0x0f, 0x75, 0x57, 0x8e, 0x3c, 0x37, 0x48, 0x76, 0xc2, 0x6f, 0x34, 0x8c, 0xe2, + 0x2d, 0xa8, 0x28, 0xdb, 0x10, 0xbd, 0xfd, 0xc5, 0x9f, 0x2f, 0x2b, 0x58, 0x77, 0x3a, 0xd6, 0xff, + 0xad, 0x02, 0x54, 0x1a, 0xec, 0x18, 0x3d, 0x39, 0xef, 0x4d, 0x22, 0xf1, 0xbb, 0x70, 0x85, 0x9c, + 0x82, 0x39, 0xe0, 0x08, 0xf9, 0x23, 0xb3, 0x3f, 0x2d, 0x77, 0xe2, 0xfd, 0x54, 0x27, 0xca, 0x2c, + 0x0f, 0xfa, 0x27, 0xce, 0x84, 0x63, 0x90, 0xb4, 0x47, 0x67, 0xe4, 0x5e, 0xcb, 0x2e, 0x3c, 0xf4, + 0x3e, 0x45, 0x16, 0x41, 0xf1, 0xcf, 0xb1, 0xf8, 0xc9, 0x89, 0x2c, 0x56, 0x7a, 0x83, 0x21, 0x70, + 0xef, 0x84, 0x69, 0x12, 0xdf, 0xb9, 0xb9, 0x6d, 0x59, 0xfa, 0xce, 0x25, 0xf3, 0xbb, 0x0f, 0xeb, + 0xf2, 0x8d, 0x0c, 0x7a, 0x9b, 0xd3, 0x1c, 0xfa, 0x93, 0x73, 0xe9, 0x21, 0xf0, 0xde, 0x05, 0x55, + 0x6d, 0x33, 0x29, 0x82, 0xb8, 0x9e, 0x6b, 0x61, 0x16, 0x2a, 0x9e, 0x83, 0xc0, 0x2e, 0x9d, 0xb8, + 0x53, 0xdc, 0xcf, 0xd4, 0xab, 0xa0, 0x7c, 0x5f, 0xe2, 0xde, 0x82, 0x52, 0xbb, 0xf6, 0xe9, 0x1e, + 0xd1, 0xca, 0x42, 0xb8, 0x58, 0xcd, 0x9b, 0x01, 0xdf, 0x68, 0xc1, 0xb5, 0x0b, 0xfa, 0xea, 0x75, + 0xde, 0x4d, 0xc5, 0x94, 0x77, 0xd3, 0x8d, 0x4d, 0xd8, 0x58, 0xd4, 0x8e, 0x1f, 0x55, 0x46, 0x13, + 0xae, 0x2c, 0xac, 0xf5, 0x8f, 0x29, 0x44, 0xff, 0x0b, 0x35, 0x80, 0x64, 0x39, 0x65, 0x74, 0x89, + 0xdc, 0x8c, 0x2e, 0xf1, 0xa3, 0xdc, 0x51, 0x3f, 0x83, 0x1a, 0x8e, 0x63, 0x2a, 0x92, 0xf1, 0xe2, + 0x10, 0xca, 0x15, 0xa4, 0x1a, 0x24, 0x01, 0x2f, 0xe7, 0xdd, 0xaa, 0x0a, 0x0b, 0xdd, 0xaa, 0x3e, + 0x85, 0x55, 0x3e, 0x8f, 0x55, 0x83, 0x7a, 0x6d, 0x96, 0x35, 0x3c, 0x90, 0x61, 0xa6, 0x14, 0x9d, + 0x68, 0x41, 0x2d, 0x8e, 0x32, 0x93, 0x8e, 0xb8, 0x7a, 0x6b, 0x3e, 0xa7, 0x22, 0xe3, 0xe7, 0x46, + 0xad, 0x74, 0x32, 0xa5, 0x7a, 0x44, 0x63, 0x79, 0x48, 0x40, 0xaa, 0xc7, 0x6a, 0x5a, 0xf5, 0x18, + 0x8c, 0xf9, 0x68, 0x00, 0x55, 0x8f, 0x8f, 0xe0, 0xb2, 0x74, 0x71, 0xc7, 0x0c, 0xe4, 0xbd, 0x80, + 0xf4, 0x7c, 0x95, 0x51, 0x93, 0x8f, 0x32, 0x8c, 0x49, 0x31, 0x47, 0xf2, 0x6f, 0x60, 0x83, 0xdf, + 0x0d, 0x31, 0xa3, 0x03, 0x7a, 0xc1, 0xa7, 0x3d, 0x32, 0xc7, 0xd6, 0x44, 0x6a, 0x44, 0xef, 0xcd, + 0x55, 0x96, 0x9f, 0x0d, 0x19, 0x1c, 0xb8, 0x74, 0xb9, 0x20, 0x76, 0xbe, 0x5b, 0x1f, 0xce, 0xc2, + 0x67, 0x7c, 0x60, 0x60, 0xce, 0x07, 0x66, 0x56, 0x47, 0x2a, 0x2f, 0xd0, 0x91, 0x12, 0x4d, 0xa7, + 0x92, 0xd1, 0x74, 0x3e, 0x84, 0x55, 0x19, 0xb9, 0x53, 0x1e, 0x0f, 0x88, 0xf9, 0x45, 0x66, 0x28, + 0x12, 0xfc, 0x92, 0xf2, 0xc8, 0xa2, 0xc0, 0xef, 0x35, 0xfe, 0x52, 0x1a, 0x26, 0x36, 0xa5, 0x6d, + 0x3c, 0xbe, 0x08, 0x21, 0x8f, 0x02, 0x6e, 0xa4, 0x0a, 0x8e, 0x71, 0xd2, 0x78, 0x33, 0x93, 0xe3, + 0xc6, 0x5f, 0x5e, 0x85, 0x15, 0xe9, 0x57, 0x73, 0x1f, 0x0a, 0xa3, 0x40, 0x5e, 0xda, 0x8a, 0x95, + 0xba, 0xac, 0x5c, 0xb9, 0x73, 0xc9, 0x20, 0x1a, 0xf1, 0x00, 0x56, 0xac, 0x11, 0xea, 0x6b, 0x59, + 0xb7, 0x85, 0x19, 0x99, 0x7f, 0xe7, 0x92, 0xb1, 0x6c, 0x91, 0xf0, 0xff, 0x25, 0x94, 0x90, 0x3e, + 0x1d, 0x82, 0xbb, 0xbe, 0x20, 0x8b, 0x3a, 0x9a, 0x29, 0x5a, 0x4a, 0x52, 0xff, 0xad, 0xec, 0x01, + 0x50, 0x61, 0xae, 0x81, 0x33, 0xa2, 0xe5, 0xcc, 0x51, 0xd0, 0x6f, 0x03, 0x9f, 0x08, 0xc4, 0xe2, + 0xc4, 0x72, 0xfa, 0x84, 0x7c, 0x4e, 0xf8, 0xd8, 0xb9, 0x64, 0xf0, 0xa6, 0xaa, 0x84, 0x91, 0xcf, + 0xd5, 0xe1, 0x0c, 0xb1, 0xe7, 0x95, 0xc5, 0x3d, 0x83, 0x3c, 0x3a, 0x3e, 0xa1, 0x21, 0x86, 0x8d, + 0xd9, 0x46, 0xb1, 0x9f, 0xf1, 0xea, 0x5c, 0xb6, 0x58, 0xe4, 0xa0, 0x6c, 0xb1, 0xfc, 0xf1, 0x18, + 0xca, 0x6c, 0xab, 0xe7, 0x7c, 0xc5, 0xb9, 0xae, 0x4d, 0x24, 0x06, 0x3a, 0xfd, 0x4d, 0xe4, 0x87, + 0xa6, 0x6a, 0x67, 0x60, 0xa7, 0x0f, 0xd8, 0x6e, 0x2e, 0xec, 0x28, 0x23, 0x3e, 0x6b, 0xe3, 0xc6, + 0x1a, 0x9c, 0x47, 0x74, 0x60, 0x43, 0x9e, 0x44, 0xb1, 0x74, 0xa0, 0x36, 0x74, 0x98, 0x1b, 0xaf, + 0x8c, 0xf8, 0xb0, 0x73, 0xc9, 0x10, 0xd6, 0xbc, 0x50, 0xd1, 0x84, 0x75, 0x55, 0x25, 0xda, 0xf6, + 0x53, 0xae, 0x97, 0xe9, 0x26, 0x25, 0x42, 0xc1, 0xce, 0x25, 0x63, 0xcd, 0xca, 0x82, 0x44, 0x1b, + 0x2e, 0xab, 0x42, 0x48, 0xbd, 0x4f, 0xdd, 0xdb, 0xc8, 0x8e, 0x62, 0x5a, 0x90, 0xd8, 0xb9, 0x64, + 0xac, 0x5b, 0x73, 0xd2, 0xc5, 0xae, 0xaa, 0x4f, 0x5a, 0x72, 0xe5, 0x95, 0x78, 0x7b, 0x61, 0x37, + 0x25, 0x62, 0x74, 0x5c, 0xb3, 0x94, 0x64, 0xfd, 0x0b, 0xd5, 0x59, 0x59, 0x2f, 0x73, 0x79, 0x80, + 0xf7, 0xe6, 0x5c, 0x89, 0x69, 0x27, 0xf3, 0xb8, 0xc7, 0x32, 0xd0, 0xc4, 0x83, 0xe6, 0x86, 0x01, + 0x57, 0x17, 0x33, 0xad, 0xf4, 0xce, 0x55, 0xe0, 0x9d, 0x4b, 0x4f, 0xef, 0x5c, 0xb3, 0x6f, 0x43, + 0xa4, 0xf6, 0xb1, 0x9f, 0x43, 0x35, 0xc3, 0xb5, 0x45, 0x19, 0x56, 0xd5, 0xbb, 0xfa, 0x14, 0x1c, + 0xa7, 0xd9, 0xdb, 0xfb, 0x56, 0xcb, 0x21, 0xb8, 0xdd, 0xed, 0x0f, 0x1a, 0xdd, 0x81, 0xb6, 0xc4, + 0x89, 0xbd, 0x4e, 0xa3, 0xd9, 0xd2, 0xf2, 0xfa, 0xdf, 0xcc, 0x43, 0x29, 0x3e, 0xdf, 0xfd, 0xcd, + 0xad, 0xa3, 0x8b, 0xe3, 0x36, 0xcc, 0x28, 0xbc, 0x7c, 0x6d, 0xa5, 0xa0, 0xc2, 0xc0, 0xa7, 0xd5, + 0xca, 0x70, 0x3e, 0x2c, 0xf0, 0xf2, 0x0f, 0x0c, 0x0b, 0x9c, 0xbe, 0xb0, 0xb8, 0x92, 0xbd, 0xb0, + 0x78, 0x1b, 0x54, 0x38, 0x0c, 0xdc, 0x55, 0xc8, 0x24, 0x57, 0xa0, 0xe7, 0x59, 0x11, 0x34, 0x38, + 0x70, 0x91, 0xaf, 0x3b, 0xe1, 0x73, 0xc7, 0x3e, 0x95, 0x57, 0x28, 0x64, 0x2a, 0xbb, 0xe9, 0xc3, + 0x6b, 0x36, 0xfd, 0x1f, 0xb2, 0x81, 0x3c, 0x84, 0x8d, 0xc3, 0x93, 0xf8, 0xdd, 0xf4, 0xc4, 0xd8, + 0x56, 0xa1, 0x2a, 0x2d, 0xc4, 0x89, 0xf7, 0x60, 0x25, 0x52, 0x47, 0xcf, 0xf9, 0x05, 0xa7, 0xf1, + 0x86, 0x44, 0xeb, 0x7f, 0x39, 0x07, 0x90, 0x9c, 0x7c, 0xfe, 0x89, 0x8f, 0x10, 0x52, 0xd6, 0xd3, + 0xfc, 0x2b, 0xac, 0xa7, 0xaf, 0x7b, 0x15, 0xeb, 0x7b, 0x28, 0xc5, 0x67, 0xdd, 0xbf, 0xf9, 0xc4, + 0xfa, 0x51, 0x9f, 0xfc, 0x07, 0xd5, 0x71, 0x4a, 0x7c, 0x58, 0xfc, 0x27, 0xed, 0x8b, 0xcc, 0xe7, + 0xf3, 0xaf, 0xf9, 0xfc, 0x19, 0x9f, 0x35, 0xc4, 0x1f, 0xff, 0x53, 0x5e, 0x4d, 0xe9, 0x89, 0x5e, + 0xc8, 0x4c, 0x74, 0x7d, 0x2a, 0x0f, 0x59, 0xfe, 0xe4, 0x9f, 0xfe, 0x51, 0x0d, 0xfe, 0xdf, 0x72, + 0xca, 0xaa, 0x1f, 0x3f, 0x75, 0x7f, 0xa1, 0x1c, 0xbd, 0xf8, 0x60, 0xe2, 0xc7, 0x7c, 0xee, 0x95, + 0x96, 0xba, 0xc2, 0xab, 0x2c, 0x75, 0xef, 0xa9, 0x87, 0x42, 0x96, 0x2f, 0xb2, 0xd2, 0xc9, 0xb7, + 0x42, 0x6e, 0x43, 0x39, 0x6d, 0x9b, 0x63, 0xa3, 0x0c, 0x1b, 0x55, 0xd8, 0x2c, 0xa7, 0x4b, 0xbd, + 0x81, 0xdb, 0xbb, 0xa1, 0xca, 0x95, 0x01, 0xac, 0x28, 0xa1, 0xff, 0x39, 0xe6, 0xa8, 0xbf, 0x69, + 0x97, 0xbc, 0xda, 0x4c, 0xa3, 0xff, 0xbf, 0x39, 0xa8, 0x66, 0x7c, 0x57, 0x7e, 0x83, 0x4f, 0x2c, + 0xe4, 0xcb, 0xf9, 0xff, 0x1f, 0xf1, 0xe5, 0xcc, 0xcd, 0x82, 0x62, 0xf6, 0x66, 0x01, 0xb2, 0xbb, + 0x4a, 0x46, 0x2b, 0x5a, 0xa4, 0x3f, 0xe5, 0x16, 0xea, 0x4f, 0xb7, 0x00, 0xac, 0x21, 0x5d, 0x79, + 0x6c, 0x6f, 0xb1, 0x23, 0x7f, 0xd5, 0x48, 0x41, 0xc4, 0x57, 0x70, 0x5d, 0x1a, 0x4d, 0xb8, 0x7f, + 0xfc, 0x43, 0x53, 0x61, 0x47, 0xd2, 0x08, 0x71, 0x95, 0x09, 0x68, 0x74, 0x7b, 0x87, 0x0d, 0x85, + 0xd5, 0xdb, 0x50, 0xcd, 0x38, 0x05, 0xe1, 0xde, 0x72, 0xe4, 0xfa, 0x07, 0x96, 0x2b, 0xeb, 0x22, + 0x53, 0xe2, 0x0e, 0x2c, 0x9f, 0x1e, 0xdb, 0x81, 0xbd, 0xe0, 0x3d, 0x67, 0x46, 0xe8, 0x3f, 0x85, + 0x4a, 0xda, 0x41, 0x51, 0x7c, 0x08, 0xcb, 0x4e, 0x64, 0x8f, 0x95, 0x39, 0xe8, 0xea, 0xbc, 0x0f, + 0x63, 0x3b, 0xb2, 0xc7, 0x06, 0x13, 0xe9, 0xbf, 0x9f, 0x03, 0x6d, 0x16, 0x47, 0x31, 0x98, 0xce, + 0xc3, 0xc8, 0x1e, 0xab, 0xca, 0x70, 0x2a, 0x55, 0xc9, 0xa5, 0x4c, 0x25, 0x95, 0xd5, 0x2c, 0x9f, + 0xb2, 0x9a, 0xdd, 0x51, 0x42, 0xc9, 0xfc, 0x5d, 0x36, 0x46, 0x88, 0x77, 0xa1, 0x18, 0xd8, 0x14, + 0xdd, 0x69, 0xd1, 0x2b, 0x39, 0x31, 0x4e, 0xff, 0xbd, 0x1c, 0xac, 0x4a, 0x6f, 0xca, 0x85, 0xf6, + 0xb9, 0xf7, 0x61, 0x35, 0x1c, 0x1e, 0xdb, 0x63, 0x4b, 0x3d, 0x8e, 0x35, 0x77, 0x64, 0xa4, 0xf0, + 0xe2, 0x16, 0xfb, 0x98, 0x66, 0xed, 0x75, 0x7b, 0xae, 0xe5, 0x19, 0x04, 0xc7, 0xa9, 0xc6, 0x76, + 0x5a, 0xbe, 0x93, 0xc6, 0x2f, 0x97, 0x00, 0x81, 0xe8, 0xd6, 0x99, 0xfe, 0x5b, 0xb0, 0x2a, 0xbd, + 0x35, 0x17, 0x56, 0xe5, 0x16, 0x14, 0xac, 0xe0, 0x28, 0x5c, 0x30, 0x58, 0x04, 0xd7, 0xef, 0x00, + 0x24, 0xee, 0x9b, 0x8b, 0x4a, 0xd0, 0xef, 0x43, 0x51, 0x79, 0x6c, 0xe2, 0xfc, 0x4b, 0x3e, 0x2d, + 0xef, 0xa1, 0xa7, 0x2b, 0xe3, 0x42, 0x95, 0x26, 0x6a, 0xc7, 0x1f, 0x9e, 0xd0, 0x91, 0xc1, 0xc7, + 0x40, 0xd7, 0xf9, 0x07, 0x73, 0x4f, 0xbc, 0xc4, 0x64, 0x7c, 0x4b, 0x45, 0x11, 0x89, 0xfb, 0x10, + 0xf3, 0xcb, 0xd7, 0x59, 0x2b, 0xf4, 0x86, 0x0a, 0xfc, 0x40, 0xb3, 0xec, 0x91, 0xb4, 0x1e, 0x77, + 0xe8, 0xf9, 0xc1, 0x5c, 0xfa, 0x9e, 0x40, 0xa6, 0x4e, 0x46, 0x8a, 0x4c, 0xaf, 0x41, 0x25, 0xed, + 0x66, 0xa6, 0x37, 0x60, 0x5d, 0xdd, 0x44, 0x50, 0x0f, 0x5f, 0xf0, 0xfc, 0xc5, 0x1f, 0xd9, 0xf9, + 0x3b, 0x4b, 0x67, 0x30, 0x91, 0xfe, 0x37, 0x0b, 0xa0, 0xcd, 0xe2, 0x5e, 0x15, 0x04, 0xe3, 0x36, + 0x94, 0xf9, 0xdd, 0xaa, 0xb4, 0x25, 0x11, 0x18, 0x94, 0xba, 0xa6, 0xc4, 0x6f, 0x3a, 0xa9, 0xe7, + 0xc6, 0x9d, 0x90, 0xdf, 0x7c, 0x12, 0xd7, 0x38, 0xe2, 0x81, 0xeb, 0x0f, 0x69, 0x5a, 0x57, 0x28, + 0xc0, 0x41, 0xc7, 0x1f, 0x52, 0x6c, 0x0d, 0x69, 0xf0, 0x60, 0x67, 0x87, 0x8a, 0x51, 0x94, 0x56, + 0x0e, 0x3a, 0xcf, 0x95, 0x97, 0x97, 0xa2, 0x50, 0x06, 0xc0, 0x2b, 0x32, 0x60, 0x10, 0xaa, 0x97, + 0xf8, 0x87, 0x5e, 0x24, 0x43, 0x3b, 0xad, 0x04, 0xfe, 0x69, 0xd3, 0xa3, 0xd0, 0x1a, 0xf4, 0x0e, + 0x2e, 0x62, 0x64, 0xa8, 0x2c, 0x4c, 0x23, 0x8a, 0xe2, 0x29, 0x71, 0x74, 0x63, 0x7e, 0x85, 0xae, + 0x24, 0x9f, 0x1f, 0x94, 0xc0, 0xf8, 0x91, 0x4f, 0xde, 0xff, 0x52, 0x41, 0xb3, 0x80, 0x41, 0x44, + 0x70, 0x1d, 0x8a, 0xbf, 0xf2, 0x3d, 0x9b, 0x0c, 0x27, 0x65, 0xaa, 0xd5, 0x2a, 0xa6, 0x77, 0xad, + 0x09, 0x6e, 0x04, 0x2e, 0xc5, 0x5a, 0xe4, 0xeb, 0xb9, 0x9c, 0xd0, 0xff, 0x9b, 0x1c, 0x6c, 0xcc, + 0xf6, 0x35, 0x4d, 0xa3, 0x0a, 0x14, 0x9b, 0xbd, 0x8e, 0xd9, 0x6d, 0xec, 0xb6, 0xb4, 0x4b, 0x62, + 0x0d, 0xca, 0xbd, 0xcd, 0xa7, 0xad, 0xe6, 0x80, 0x01, 0x39, 0x8a, 0x18, 0xdb, 0x37, 0x77, 0xda, + 0x5b, 0x5b, 0xad, 0x2e, 0x6b, 0x14, 0xbd, 0xcd, 0xa7, 0x66, 0xa7, 0xd7, 0xd4, 0xf2, 0x88, 0x53, + 0x0e, 0x38, 0x7d, 0xad, 0x40, 0xee, 0x39, 0x74, 0x0d, 0x03, 0x93, 0xcb, 0x7c, 0xbf, 0xe0, 0x45, + 0xdf, 0x6c, 0x76, 0x07, 0xda, 0x0a, 0xa6, 0xba, 0xfb, 0x9d, 0x0e, 0xa5, 0xc8, 0x91, 0xb8, 0xd9, + 0xdb, 0xdd, 0x33, 0x5a, 0xfd, 0xbe, 0xd9, 0x6f, 0xff, 0xb2, 0xa5, 0x15, 0xe9, 0xcb, 0x46, 0xfb, + 0x49, 0xbb, 0xcb, 0x80, 0x92, 0x58, 0x85, 0xfc, 0x6e, 0xbb, 0xcb, 0x91, 0x72, 0x77, 0x1b, 0xdf, + 0x68, 0x65, 0xfc, 0xd1, 0xdf, 0xdf, 0xd5, 0x2a, 0xa2, 0x04, 0xcb, 0x9d, 0xd6, 0xf3, 0x56, 0x47, + 0xab, 0xea, 0xff, 0x53, 0x5e, 0x49, 0xc4, 0xe4, 0x61, 0xf7, 0x43, 0xa4, 0xc0, 0x45, 0xa7, 0xac, + 0x71, 0xa7, 0xe5, 0x53, 0x9d, 0x46, 0xcf, 0x41, 0x31, 0xdb, 0x4f, 0x9f, 0x93, 0x95, 0x25, 0x8c, + 0xa6, 0xdc, 0xdb, 0x50, 0x8d, 0xcf, 0xa0, 0x53, 0xaf, 0xe7, 0x57, 0x14, 0x70, 0xc1, 0x71, 0xcd, + 0xca, 0x82, 0xe3, 0x9a, 0x89, 0x13, 0xa1, 0xe2, 0x8e, 0x3c, 0x97, 0x67, 0x52, 0x09, 0x21, 0xcf, + 0x89, 0xd7, 0xbe, 0x01, 0x94, 0x30, 0xa7, 0x9e, 0x7c, 0xf5, 0xab, 0x64, 0x14, 0x11, 0xb0, 0xef, + 0x71, 0x80, 0x8c, 0xb4, 0xb3, 0x4a, 0x69, 0xce, 0x59, 0x25, 0xbd, 0x39, 0x43, 0x76, 0x73, 0x7e, + 0x33, 0xde, 0x23, 0x11, 0x59, 0xa6, 0xb3, 0x8a, 0x52, 0xbc, 0x0b, 0x8a, 0x0f, 0x41, 0x0c, 0xa7, + 0x01, 0x3d, 0xba, 0x93, 0x22, 0xab, 0x10, 0x99, 0x26, 0x31, 0xf1, 0xae, 0x48, 0xe1, 0x86, 0xb2, + 0xd4, 0xa4, 0x9e, 0x97, 0x8c, 0x5a, 0x96, 0x54, 0x3c, 0x80, 0xcb, 0x72, 0x6e, 0x67, 0xfa, 0x56, + 0x46, 0x2a, 0x61, 0x54, 0x23, 0xe9, 0x61, 0xfd, 0x27, 0x50, 0x54, 0xce, 0x94, 0xaf, 0x16, 0x76, + 0x17, 0x8c, 0xab, 0xfe, 0xd7, 0x97, 0xa0, 0x14, 0xbb, 0x56, 0xfe, 0xa0, 0xd9, 0xf1, 0x06, 0xca, + 0xa9, 0xe1, 0x49, 0x9a, 0xc5, 0x14, 0x11, 0xa0, 0x46, 0x4a, 0x5e, 0x22, 0x9d, 0x06, 0x8e, 0x92, + 0xd8, 0x18, 0xb2, 0x1f, 0x38, 0x14, 0x59, 0xdf, 0xf1, 0x52, 0x91, 0x41, 0x4a, 0x46, 0x11, 0x01, + 0xb4, 0xd0, 0xae, 0x03, 0xfd, 0xa6, 0x9c, 0x3c, 0x49, 0x56, 0x31, 0x8d, 0xf9, 0xae, 0xc6, 0xfa, + 0x9f, 0x8c, 0xc7, 0x17, 0xc5, 0x82, 0x85, 0xf4, 0xea, 0x62, 0x1f, 0x13, 0x99, 0xc2, 0xef, 0x50, + 0x14, 0x2b, 0xaa, 0xa3, 0x9c, 0x11, 0x08, 0x50, 0x75, 0x4c, 0x0d, 0x57, 0x69, 0x76, 0x54, 0x67, + 0xe7, 0x34, 0xcc, 0xcd, 0x69, 0x3d, 0x82, 0x55, 0xe9, 0x5e, 0xfa, 0xea, 0x0e, 0x7f, 0x65, 0x57, + 0x69, 0x90, 0xb7, 0x5c, 0x15, 0xa6, 0x01, 0x7f, 0xce, 0x54, 0xac, 0x30, 0x53, 0x31, 0xfd, 0x5f, + 0x5a, 0x02, 0x48, 0xdc, 0x54, 0xc5, 0x47, 0x33, 0x2e, 0xf1, 0xb9, 0xb9, 0x6d, 0x7f, 0xc6, 0x13, + 0x7e, 0xe6, 0xa9, 0x89, 0xa5, 0x1f, 0xf0, 0xd4, 0xc4, 0x43, 0xa8, 0x86, 0xc1, 0xf0, 0xb5, 0x36, + 0xfc, 0x72, 0x18, 0x0c, 0x63, 0x13, 0xfe, 0xc7, 0x80, 0x49, 0x7a, 0x86, 0x2a, 0x51, 0x54, 0xe7, + 0xa4, 0x96, 0x52, 0x18, 0x0c, 0x7b, 0x07, 0xdf, 0x6d, 0xf1, 0xcd, 0xdd, 0x51, 0x18, 0x99, 0x8b, + 0xb8, 0xc4, 0xda, 0x28, 0x8c, 0xb6, 0xd2, 0x8c, 0xe2, 0x2e, 0xd4, 0x90, 0x76, 0x8e, 0x59, 0x54, + 0x46, 0x61, 0x72, 0xa0, 0xa4, 0xff, 0x63, 0xea, 0x60, 0x7e, 0xc6, 0x3c, 0x2c, 0xbe, 0x90, 0x8a, + 0x78, 0x4a, 0x88, 0xa8, 0x2f, 0xb2, 0x26, 0xf3, 0xe5, 0xfe, 0x98, 0x54, 0x3c, 0x86, 0x6a, 0x8c, + 0xdb, 0xb2, 0x0f, 0x95, 0x0c, 0xa4, 0xde, 0x34, 0x4a, 0xa1, 0x8c, 0x2c, 0xa1, 0xfe, 0x18, 0x20, + 0x79, 0x08, 0x0c, 0x57, 0x60, 0x7c, 0x4d, 0xac, 0xc4, 0x17, 0xc0, 0x70, 0x0e, 0x7b, 0x14, 0x2b, + 0x40, 0x3e, 0x75, 0x2d, 0x53, 0xfa, 0x63, 0xb8, 0x76, 0x81, 0x7d, 0x4d, 0x9d, 0x57, 0xca, 0x40, + 0x1e, 0x32, 0x22, 0xa1, 0x67, 0x9f, 0x72, 0x20, 0x0f, 0xdd, 0x83, 0xcb, 0x0b, 0x1e, 0xeb, 0x17, + 0x77, 0xc8, 0xa9, 0x8d, 0x4e, 0x03, 0xe3, 0xdb, 0xfd, 0xcb, 0x74, 0x0e, 0xda, 0x1e, 0xf1, 0x73, + 0x24, 0x9f, 0xc3, 0x9a, 0xed, 0x3a, 0x47, 0xce, 0x81, 0x43, 0x91, 0xff, 0x87, 0xbe, 0x3b, 0x67, + 0x75, 0xa3, 0x87, 0xd3, 0x53, 0x44, 0x4d, 0xdf, 0xd5, 0xff, 0xc9, 0x9c, 0x7c, 0x79, 0x33, 0xfb, + 0x6c, 0x20, 0xbf, 0xbc, 0x29, 0x9f, 0xf8, 0xce, 0x19, 0xf4, 0x1b, 0x5b, 0x2b, 0x5f, 0x75, 0x96, + 0xcf, 0xee, 0x71, 0x4a, 0x7c, 0x0c, 0x1b, 0x32, 0x7a, 0x3e, 0x85, 0xda, 0x33, 0x27, 0x76, 0x60, + 0x06, 0xfe, 0x29, 0x4d, 0xb8, 0x9c, 0xb1, 0xce, 0x38, 0x8a, 0xb8, 0xb7, 0x67, 0x07, 0x86, 0x7f, + 0x2a, 0xea, 0x24, 0xad, 0xd8, 0xc3, 0x48, 0x9d, 0x3d, 0xab, 0xa4, 0xfe, 0x3b, 0x70, 0x79, 0xc1, + 0xbd, 0x52, 0xf1, 0x8e, 0xd2, 0xff, 0x2e, 0xb8, 0x45, 0xbe, 0x50, 0xe7, 0x5c, 0x9a, 0xd5, 0x39, + 0xbb, 0x50, 0xcd, 0x5c, 0x15, 0xcd, 0x46, 0xf0, 0x2f, 0xbc, 0x3a, 0x82, 0x3f, 0x3d, 0x88, 0xbe, + 0xf4, 0xb4, 0x50, 0x5c, 0xd2, 0xf2, 0x4f, 0x0b, 0xc5, 0xbc, 0x56, 0xd0, 0xff, 0x6a, 0x0e, 0x8a, + 0x8a, 0x70, 0x7e, 0xaf, 0xcc, 0x2d, 0xd8, 0x2b, 0xdf, 0x90, 0x1f, 0x4c, 0x33, 0x15, 0x04, 0x10, + 0xf2, 0x3e, 0x14, 0xe3, 0x05, 0x9e, 0x5f, 0xb8, 0xc0, 0x63, 0xbc, 0xf8, 0x00, 0xd6, 0x33, 0xfe, + 0xb1, 0xa9, 0x1d, 0x5c, 0x4b, 0x23, 0xa8, 0xdd, 0x7f, 0x90, 0x83, 0xb2, 0x7a, 0xa9, 0xd3, 0xe0, + 0xe8, 0x9e, 0xea, 0x41, 0xcf, 0x24, 0x3c, 0x1a, 0x28, 0x50, 0x7b, 0x84, 0xaa, 0x78, 0x60, 0xbf, + 0x74, 0x42, 0xe5, 0xef, 0x5b, 0x30, 0xe2, 0x34, 0x7e, 0x39, 0x8e, 0x27, 0x3a, 0x13, 0x0c, 0x53, + 0x8b, 0x11, 0x2a, 0x6e, 0xe2, 0x3c, 0x57, 0x2c, 0xa4, 0xd9, 0xf5, 0xcc, 0xfe, 0xbe, 0x3c, 0xbb, + 0xbf, 0xeb, 0xff, 0x5c, 0x0e, 0xea, 0xfd, 0xef, 0x5d, 0x79, 0xc9, 0xb6, 0x3d, 0x9e, 0xb8, 0xb4, + 0x88, 0xf8, 0x7e, 0xee, 0xe7, 0x70, 0x35, 0x71, 0x68, 0x36, 0x0f, 0x1d, 0xef, 0xc8, 0x0e, 0x26, + 0x81, 0x23, 0x1d, 0x33, 0x2a, 0xc6, 0x95, 0x04, 0xbb, 0x9d, 0x20, 0xc5, 0x33, 0xd0, 0x43, 0x7b, + 0x6c, 0x79, 0x91, 0x33, 0x34, 0x53, 0xf9, 0x59, 0x13, 0x8b, 0x5b, 0xc4, 0x33, 0xfc, 0xb6, 0xa2, + 0x4c, 0x2e, 0x6f, 0xf5, 0x89, 0x4e, 0x36, 0x50, 0xff, 0xf7, 0xf3, 0xf0, 0xc6, 0xde, 0x79, 0x74, + 0xec, 0x7b, 0x8b, 0xeb, 0x58, 0x87, 0xd5, 0x63, 0xcb, 0x1b, 0xb9, 0x71, 0xd4, 0x60, 0x95, 0x14, + 0x37, 0x60, 0x85, 0xf7, 0x56, 0x9e, 0x07, 0x9b, 0x4b, 0xf5, 0x9c, 0x21, 0x21, 0xb4, 0x8d, 0x1d, + 0x38, 0x26, 0xdd, 0x34, 0xb3, 0x86, 0x91, 0xdc, 0x8b, 0xcb, 0xd6, 0x81, 0xd3, 0x94, 0x20, 0x94, + 0x48, 0xe8, 0x3d, 0x0b, 0x3b, 0x88, 0xab, 0x2c, 0x1d, 0x9d, 0x24, 0x58, 0x0d, 0x01, 0x12, 0x06, + 0x91, 0x73, 0x68, 0x0d, 0x23, 0x15, 0x12, 0x72, 0x59, 0x12, 0x4a, 0xb0, 0x8c, 0x08, 0xf9, 0x11, + 0x08, 0xdb, 0x7b, 0xe9, 0x04, 0xbe, 0x47, 0x21, 0x69, 0x24, 0x2d, 0xb3, 0xe8, 0xf5, 0x14, 0x46, + 0x92, 0xdf, 0x86, 0x72, 0x38, 0x3a, 0x89, 0x3f, 0x2e, 0xc3, 0x63, 0x87, 0xa3, 0x13, 0xf5, 0xe1, + 0xaf, 0xe1, 0xfa, 0xc5, 0xdd, 0xcb, 0x01, 0xba, 0xae, 0x8d, 0x16, 0x77, 0x6b, 0xcc, 0x6b, 0x4b, + 0x29, 0x5e, 0x7b, 0x1b, 0xca, 0xa4, 0x76, 0x4c, 0x7c, 0xd7, 0x19, 0x9e, 0xcb, 0xad, 0x1d, 0x10, + 0xb4, 0x47, 0x90, 0x57, 0xcc, 0x07, 0x76, 0x2c, 0x5d, 0x3c, 0x1f, 0xf4, 0x7f, 0x75, 0x19, 0xca, + 0x72, 0xf0, 0x9a, 0xb8, 0x93, 0x73, 0xe0, 0x31, 0xea, 0xe5, 0xb8, 0xba, 0x1c, 0x4d, 0x67, 0x4d, + 0xc1, 0x55, 0x35, 0x3f, 0x83, 0x4a, 0xbc, 0x90, 0x92, 0xf0, 0x25, 0x2a, 0x9c, 0x75, 0xb2, 0xe2, + 0x8c, 0x78, 0xbd, 0xe1, 0xf2, 0xbb, 0x01, 0x45, 0xd7, 0xf2, 0x8e, 0xa6, 0xd6, 0x51, 0xec, 0xf2, + 0xab, 0xd2, 0xe2, 0x53, 0xa8, 0x59, 0xc1, 0xd1, 0x94, 0x46, 0x20, 0x51, 0xf5, 0xb3, 0x81, 0x6b, + 0xaa, 0x8a, 0x82, 0xe3, 0xcd, 0x7c, 0x0a, 0x65, 0xbe, 0xf4, 0xcf, 0x92, 0xd9, 0xf2, 0x05, 0x1e, + 0x3f, 0xc0, 0x44, 0xb4, 0x25, 0xde, 0x02, 0x78, 0xe9, 0xbb, 0x56, 0x44, 0xbb, 0x80, 0x1c, 0xe2, + 0x14, 0x64, 0xb6, 0xab, 0x57, 0xe7, 0xba, 0xfa, 0x21, 0xfb, 0xd4, 0xf3, 0x29, 0xa0, 0x3c, 0x82, + 0xbf, 0x68, 0x9d, 0xee, 0x5c, 0x62, 0xaf, 0xfb, 0x9f, 0xc0, 0xca, 0x84, 0x56, 0x8a, 0x3c, 0x00, + 0x7c, 0x4b, 0x6e, 0xc0, 0x17, 0xaf, 0x9e, 0x9d, 0x4b, 0x86, 0xcc, 0x22, 0x7e, 0xca, 0xf7, 0x2e, + 0xed, 0xb3, 0x48, 0x06, 0x4a, 0xbf, 0x95, 0xb9, 0x7e, 0x8f, 0x03, 0xf7, 0xa0, 0xc9, 0x04, 0x74, + 0x18, 0x45, 0xcb, 0x49, 0x65, 0x21, 0x27, 0x22, 0xcb, 0x75, 0x43, 0x27, 0xb2, 0x95, 0x32, 0x50, + 0x32, 0x40, 0x81, 0xda, 0x14, 0xca, 0x7d, 0x6c, 0x9d, 0x9b, 0x76, 0x10, 0xf8, 0x81, 0x0c, 0xae, + 0x53, 0x1c, 0x5b, 0xe7, 0x2d, 0x4c, 0x23, 0x67, 0x0f, 0xed, 0xe1, 0x34, 0xc0, 0x6d, 0x95, 0x66, + 0x25, 0x8b, 0xfe, 0x15, 0x05, 0xa4, 0x8b, 0xdf, 0x37, 0xa1, 0xe4, 0xda, 0xd6, 0xc9, 0x24, 0xf0, + 0xfd, 0x43, 0x29, 0xee, 0x27, 0x80, 0x1b, 0x5f, 0x43, 0x25, 0x5d, 0xbb, 0xd7, 0x39, 0x79, 0x94, + 0x52, 0x87, 0x63, 0x9b, 0x1a, 0xd4, 0x9c, 0x4c, 0xb7, 0xe8, 0xff, 0x51, 0x1e, 0xae, 0x2c, 0x8c, + 0x3b, 0x30, 0x37, 0x21, 0x73, 0x3f, 0x7a, 0x42, 0x2e, 0xcd, 0x4c, 0xc8, 0x45, 0xab, 0x21, 0xbf, + 0x78, 0x35, 0x5c, 0xbc, 0xfe, 0x0a, 0xaf, 0x58, 0x7f, 0x7f, 0x66, 0x0c, 0x2a, 0x3b, 0xc9, 0x57, + 0x5f, 0x37, 0xc9, 0x8b, 0x73, 0x93, 0x3c, 0x33, 0x29, 0x4a, 0xaf, 0x9b, 0x14, 0xf0, 0xba, 0x49, + 0x51, 0x9e, 0x99, 0x14, 0xfa, 0x1f, 0xe5, 0x40, 0x9b, 0xf5, 0xe1, 0x9e, 0xdd, 0x12, 0x73, 0x73, + 0x2a, 0xef, 0xdb, 0x50, 0x1d, 0x1e, 0x5b, 0xd8, 0xef, 0x74, 0xf3, 0x30, 0x92, 0x23, 0x56, 0x89, + 0x81, 0x7d, 0x9b, 0x62, 0x9d, 0x0f, 0x7d, 0x57, 0x46, 0xbc, 0x90, 0x9a, 0x5c, 0x0c, 0x20, 0x5f, + 0xd4, 0xd4, 0x9e, 0x51, 0x30, 0x54, 0x92, 0x22, 0x35, 0x29, 0x32, 0xb5, 0x23, 0x57, 0x8d, 0x72, + 0x0c, 0x53, 0xd1, 0xb0, 0x15, 0x49, 0x2c, 0x25, 0xac, 0x10, 0xe1, 0x7a, 0x8c, 0x31, 0x24, 0xe2, + 0xfe, 0x3f, 0x9b, 0x83, 0xf5, 0x7e, 0x14, 0x38, 0xde, 0x51, 0xc7, 0x89, 0xec, 0xc0, 0x72, 0xb7, + 0xfd, 0x60, 0x4c, 0xd7, 0xd4, 0x06, 0x46, 0xbb, 0xfb, 0xc4, 0xec, 0xb4, 0x07, 0x2d, 0xa3, 0x11, + 0xbf, 0x58, 0x32, 0x8f, 0x18, 0xb4, 0xbe, 0x19, 0x68, 0x39, 0x71, 0x17, 0xee, 0xcc, 0x20, 0x36, + 0xdb, 0xdd, 0x86, 0xf1, 0xad, 0xd9, 0xee, 0x0e, 0x8c, 0xde, 0xd6, 0x7e, 0xb3, 0x65, 0x68, 0x4b, + 0xe2, 0x2a, 0x88, 0x19, 0xaa, 0x9d, 0xd6, 0x37, 0x5a, 0x7e, 0x01, 0x7c, 0xb3, 0x3d, 0xd0, 0x0a, + 0xf7, 0x77, 0xe1, 0x72, 0xe3, 0xe8, 0x28, 0xb0, 0x8f, 0x50, 0x87, 0xa6, 0x88, 0xf8, 0xea, 0xae, + 0x60, 0xe3, 0xc9, 0x13, 0xb3, 0xd9, 0xeb, 0x6e, 0xb7, 0x9f, 0xa8, 0xaa, 0xbd, 0x05, 0x6f, 0xa6, + 0x80, 0x4f, 0x8c, 0xde, 0xfe, 0x1e, 0x26, 0x9a, 0x8d, 0x81, 0xd9, 0x33, 0xb6, 0x5a, 0x86, 0x96, + 0xbb, 0xff, 0x16, 0x2e, 0x73, 0xb6, 0x74, 0xc5, 0x0f, 0xbc, 0xf8, 0x9e, 0xad, 0x5d, 0x12, 0xab, + 0x90, 0xef, 0xfc, 0xea, 0x33, 0x2d, 0x77, 0x3f, 0x00, 0x8d, 0x83, 0x25, 0xf3, 0xd1, 0x3f, 0x85, + 0x86, 0xbe, 0x05, 0x37, 0x8c, 0x56, 0x7f, 0xbf, 0x33, 0x90, 0x57, 0xec, 0xcc, 0x67, 0xed, 0xee, + 0x96, 0x99, 0x84, 0x06, 0x79, 0x13, 0xae, 0x2f, 0xc0, 0xf7, 0x07, 0x3d, 0xa3, 0xb5, 0xa5, 0xe5, + 0xc4, 0x6d, 0x78, 0x63, 0x01, 0xba, 0xd9, 0xdb, 0xdd, 0xdb, 0x1f, 0xb4, 0xb6, 0xb4, 0xa5, 0xfb, + 0x3a, 0x94, 0xfb, 0xc7, 0xd3, 0xc3, 0x43, 0xd7, 0x56, 0xb5, 0xda, 0xb1, 0xc2, 0x63, 0xf6, 0xa0, + 0xa7, 0x47, 0xd1, 0xb5, 0xdc, 0xfd, 0x77, 0xa1, 0x2a, 0x69, 0x76, 0xed, 0xe8, 0xd8, 0x1f, 0x09, + 0x80, 0x95, 0xae, 0x1f, 0x8c, 0x2d, 0x57, 0xd2, 0xd9, 0xd3, 0x10, 0xe9, 0x3e, 0x86, 0x2b, 0xa9, + 0xb2, 0xb6, 0xfd, 0x80, 0x62, 0x7a, 0x36, 0xbb, 0x14, 0xbf, 0x84, 0xf8, 0x14, 0x47, 0xe2, 0xd8, + 0x39, 0x3f, 0x08, 0x9c, 0x91, 0x96, 0xbb, 0xff, 0x18, 0x4a, 0x9b, 0xfe, 0xd4, 0xe3, 0x47, 0x3c, + 0xe8, 0xf5, 0xa6, 0xcd, 0xde, 0x7e, 0x77, 0x8b, 0xde, 0x7b, 0xa1, 0x17, 0x9b, 0x9a, 0x9d, 0xfd, + 0x7e, 0xfb, 0xb9, 0x34, 0xc7, 0xb5, 0xbe, 0x51, 0xc9, 0xa5, 0xfb, 0xbf, 0x97, 0x53, 0x01, 0x84, + 0x55, 0xb5, 0x3b, 0xbd, 0xc6, 0x16, 0xdb, 0xf1, 0xe2, 0x87, 0xa9, 0x06, 0x9b, 0x5a, 0x0e, 0x01, + 0xb2, 0x07, 0xe4, 0x9b, 0x57, 0x35, 0x80, 0x76, 0xb3, 0xb5, 0xd9, 0x32, 0x9e, 0x20, 0x41, 0x1e, + 0xd3, 0xbb, 0xbd, 0xee, 0x93, 0xde, 0xd6, 0x26, 0xa6, 0xe9, 0xb5, 0xab, 0xad, 0xc6, 0xa0, 0xd1, + 0x1f, 0x18, 0xad, 0xc6, 0x2e, 0x82, 0x28, 0x44, 0x80, 0xba, 0x28, 0x30, 0xd8, 0x64, 0x9b, 0xde, + 0xb3, 0xc6, 0xf6, 0xb3, 0x06, 0xa6, 0x56, 0xef, 0xff, 0x57, 0x4b, 0xa0, 0xcd, 0x06, 0x89, 0x16, + 0x6f, 0xc0, 0x35, 0x2a, 0xd5, 0xdc, 0x33, 0x5a, 0x5b, 0xed, 0x26, 0x5f, 0xf6, 0x7c, 0xde, 0xe8, + 0xb4, 0xb7, 0x78, 0x26, 0xcf, 0x22, 0x1b, 0xdd, 0x2d, 0x7e, 0xc8, 0x66, 0x16, 0xd1, 0xfa, 0xc5, + 0x7e, 0xa3, 0xa3, 0x2d, 0xe1, 0x40, 0xcf, 0xa2, 0xba, 0xbd, 0x81, 0x44, 0xe7, 0x45, 0x1d, 0x36, + 0x66, 0xd1, 0x9d, 0x56, 0xbf, 0xaf, 0x15, 0x70, 0x06, 0x2d, 0xc2, 0xc8, 0x9c, 0xcb, 0x8b, 0x6a, + 0xfa, 0x84, 0x8c, 0x9b, 0x86, 0xb6, 0x82, 0x13, 0xfb, 0x02, 0xa4, 0xcc, 0xbf, 0x8a, 0xeb, 0x67, + 0xbe, 0xa5, 0x5a, 0x71, 0x61, 0x0f, 0xf4, 0x4d, 0x7a, 0xb6, 0xa8, 0x84, 0xf3, 0x72, 0x11, 0xb2, + 0x37, 0x60, 0x02, 0xb8, 0xff, 0xb7, 0x73, 0x50, 0xbf, 0x28, 0x96, 0x9f, 0xd0, 0xe1, 0x96, 0xb1, + 0xdf, 0xa5, 0x37, 0xab, 0xf8, 0x79, 0x2d, 0xf3, 0x59, 0xeb, 0xdb, 0x99, 0xf7, 0x82, 0x70, 0x61, + 0xcc, 0xd3, 0x18, 0x8d, 0x17, 0xe6, 0xf3, 0x4f, 0xb5, 0x9c, 0xf8, 0x00, 0xde, 0x5b, 0x80, 0xde, + 0xee, 0xf4, 0x1a, 0x03, 0xf3, 0x97, 0x2d, 0xa3, 0x67, 0x36, 0x3b, 0xbd, 0x7e, 0x6b, 0x0b, 0x89, + 0x97, 0xc4, 0x1d, 0xb8, 0xb9, 0x80, 0xb8, 0xcf, 0x2f, 0xa2, 0x3d, 0xff, 0x54, 0xcb, 0x8b, 0x77, + 0xe0, 0xad, 0x8b, 0x29, 0xb6, 0xf7, 0x3b, 0x44, 0x56, 0xb8, 0xff, 0x73, 0xa8, 0x5f, 0x14, 0x49, + 0x05, 0x17, 0x52, 0x73, 0xa7, 0x41, 0xd1, 0x6a, 0x2a, 0x50, 0xec, 0xf6, 0x4c, 0x4e, 0x91, 0x67, + 0x8b, 0xd1, 0xea, 0xb4, 0xe8, 0xba, 0xf1, 0xfd, 0x5f, 0xe7, 0x52, 0xe7, 0x27, 0x2a, 0x1a, 0x46, + 0x0c, 0x90, 0x1c, 0x25, 0x0d, 0x32, 0x6c, 0x6b, 0xa4, 0xe5, 0x70, 0x94, 0x32, 0xa0, 0x8e, 0x3f, + 0xb4, 0x5c, 0x6d, 0x89, 0x2e, 0x16, 0x2b, 0x38, 0x85, 0xd4, 0xd2, 0xf2, 0xd8, 0x75, 0x31, 0xac, + 0xe3, 0x9f, 0xee, 0x05, 0x8e, 0x8f, 0xdb, 0x16, 0xa3, 0x0b, 0xf7, 0xff, 0x21, 0xe9, 0x8c, 0x9d, + 0xb1, 0xaa, 0xe0, 0x07, 0x1a, 0xa3, 0x51, 0x02, 0x23, 0x43, 0x1e, 0xcf, 0x75, 0xb2, 0x62, 0xce, + 0x20, 0x72, 0x38, 0x3f, 0xd4, 0x21, 0xef, 0x2c, 0x72, 0x09, 0x91, 0x86, 0x4d, 0x32, 0xc1, 0x1c, + 0x32, 0xbf, 0xf9, 0xec, 0x6f, 0xfd, 0xd1, 0xad, 0xdc, 0x1f, 0xfe, 0xd1, 0xad, 0xdc, 0xff, 0xfc, + 0x47, 0xb7, 0x2e, 0xfd, 0xa5, 0x3f, 0xbe, 0x95, 0xfb, 0xfd, 0x3f, 0xbe, 0x95, 0xfb, 0xc3, 0x3f, + 0xbe, 0x95, 0xfb, 0xef, 0xfe, 0xf8, 0x56, 0xee, 0x97, 0x1f, 0x1d, 0x39, 0xd1, 0xf1, 0xf4, 0xe0, + 0xc1, 0xd0, 0x1f, 0x7f, 0x3c, 0xb6, 0xa2, 0xc0, 0x39, 0x63, 0xd3, 0xaa, 0x4a, 0x78, 0xf6, 0xc7, + 0x93, 0x93, 0xa3, 0x8f, 0x27, 0x07, 0x1f, 0xa3, 0xe4, 0x73, 0xb0, 0x42, 0xb7, 0x9e, 0x1e, 0xfd, + 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x60, 0xde, 0x28, 0xe5, 0xba, 0xc7, 0x00, 0x00, } func (m *Type) Marshal() (dAtA []byte, err error) { @@ -19916,6 +20581,18 @@ func (m *Function) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.RoutineCall != nil { + { + size, err := m.RoutineCall.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPlan(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + } if m.SyntaxExplicitCast { i-- if m.SyntaxExplicitCast { @@ -20798,20 +21475,20 @@ func (m *CorrelationSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { } } if len(m.StepOwners) > 0 { - dAtA29 := make([]byte, len(m.StepOwners)*10) - var j28 int + dAtA30 := make([]byte, len(m.StepOwners)*10) + var j29 int for _, num := range m.StepOwners { for num >= 1<<7 { - dAtA29[j28] = uint8(uint64(num)&0x7f | 0x80) + dAtA30[j29] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j28++ + j29++ } - dAtA29[j28] = uint8(num) - j28++ + dAtA30[j29] = uint8(num) + j29++ } - i -= j28 - copy(dAtA[i:], dAtA29[:j28]) - i = encodeVarintPlan(dAtA, i, uint64(j28)) + i -= j29 + copy(dAtA[i:], dAtA30[:j29]) + i = encodeVarintPlan(dAtA, i, uint64(j29)) i-- dAtA[i] = 0x1a } @@ -21566,20 +22243,20 @@ func (m *PrimaryKeyDef) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x10 } if len(m.Cols) > 0 { - dAtA40 := make([]byte, len(m.Cols)*10) - var j39 int + dAtA41 := make([]byte, len(m.Cols)*10) + var j40 int for _, num := range m.Cols { for num >= 1<<7 { - dAtA40[j39] = uint8(uint64(num)&0x7f | 0x80) + dAtA41[j40] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j39++ + j40++ } - dAtA40[j39] = uint8(num) - j39++ + dAtA41[j40] = uint8(num) + j40++ } - i -= j39 - copy(dAtA[i:], dAtA40[:j39]) - i = encodeVarintPlan(dAtA, i, uint64(j39)) + i -= j40 + copy(dAtA[i:], dAtA41[:j40]) + i = encodeVarintPlan(dAtA, i, uint64(j40)) i-- dAtA[i] = 0xa } @@ -21779,20 +22456,20 @@ func (m *ForeignKeyDef) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x28 } if len(m.ForeignCols) > 0 { - dAtA43 := make([]byte, len(m.ForeignCols)*10) - var j42 int + dAtA44 := make([]byte, len(m.ForeignCols)*10) + var j43 int for _, num := range m.ForeignCols { for num >= 1<<7 { - dAtA43[j42] = uint8(uint64(num)&0x7f | 0x80) + dAtA44[j43] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j42++ + j43++ } - dAtA43[j42] = uint8(num) - j42++ + dAtA44[j43] = uint8(num) + j43++ } - i -= j42 - copy(dAtA[i:], dAtA43[:j42]) - i = encodeVarintPlan(dAtA, i, uint64(j42)) + i -= j43 + copy(dAtA[i:], dAtA44[:j43]) + i = encodeVarintPlan(dAtA, i, uint64(j43)) i-- dAtA[i] = 0x22 } @@ -21802,20 +22479,20 @@ func (m *ForeignKeyDef) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x18 } if len(m.Cols) > 0 { - dAtA45 := make([]byte, len(m.Cols)*10) - var j44 int + dAtA46 := make([]byte, len(m.Cols)*10) + var j45 int for _, num := range m.Cols { for num >= 1<<7 { - dAtA45[j44] = uint8(uint64(num)&0x7f | 0x80) + dAtA46[j45] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j44++ + j45++ } - dAtA45[j44] = uint8(num) - j44++ + dAtA46[j45] = uint8(num) + j45++ } - i -= j44 - copy(dAtA[i:], dAtA45[:j44]) - i = encodeVarintPlan(dAtA, i, uint64(j44)) + i -= j45 + copy(dAtA[i:], dAtA46[:j45]) + i = encodeVarintPlan(dAtA, i, uint64(j45)) i-- dAtA[i] = 0x12 } @@ -22421,20 +23098,20 @@ func (m *TableDef) MarshalToSizedBuffer(dAtA []byte) (int, error) { } } if len(m.RefChildTbls) > 0 { - dAtA53 := make([]byte, len(m.RefChildTbls)*10) - var j52 int + dAtA54 := make([]byte, len(m.RefChildTbls)*10) + var j53 int for _, num := range m.RefChildTbls { for num >= 1<<7 { - dAtA53[j52] = uint8(uint64(num)&0x7f | 0x80) + dAtA54[j53] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j52++ + j53++ } - dAtA53[j52] = uint8(num) - j52++ + dAtA54[j53] = uint8(num) + j53++ } - i -= j52 - copy(dAtA[i:], dAtA53[:j52]) - i = encodeVarintPlan(dAtA, i, uint64(j52)) + i -= j53 + copy(dAtA[i:], dAtA54[:j53]) + i = encodeVarintPlan(dAtA, i, uint64(j53)) i-- dAtA[i] = 0x72 } @@ -22682,9 +23359,9 @@ func (m *HashMapStats) MarshalToSizedBuffer(dAtA []byte) (int, error) { } if len(m.Ranges) > 0 { for iNdEx := len(m.Ranges) - 1; iNdEx >= 0; iNdEx-- { - f57 := math.Float64bits(float64(m.Ranges[iNdEx])) + f58 := math.Float64bits(float64(m.Ranges[iNdEx])) i -= 8 - encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(f57)) + encoding_binary.LittleEndian.PutUint64(dAtA[i:], uint64(f58)) } i = encodeVarintPlan(dAtA, i, uint64(len(m.Ranges)*8)) i-- @@ -23394,21 +24071,21 @@ func (m *DedupJoinCtx) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x48 } if len(m.UpdateCheckColIdxList) > 0 { - dAtA70 := make([]byte, len(m.UpdateCheckColIdxList)*10) - var j69 int + dAtA71 := make([]byte, len(m.UpdateCheckColIdxList)*10) + var j70 int for _, num1 := range m.UpdateCheckColIdxList { num := uint64(num1) for num >= 1<<7 { - dAtA70[j69] = uint8(uint64(num)&0x7f | 0x80) + dAtA71[j70] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j69++ + j70++ } - dAtA70[j69] = uint8(num) - j69++ + dAtA71[j70] = uint8(num) + j70++ } - i -= j69 - copy(dAtA[i:], dAtA70[:j69]) - i = encodeVarintPlan(dAtA, i, uint64(j69)) + i -= j70 + copy(dAtA[i:], dAtA71[:j70]) + i = encodeVarintPlan(dAtA, i, uint64(j70)) i-- dAtA[i] = 0x42 } @@ -23475,21 +24152,21 @@ func (m *DedupJoinCtx) MarshalToSizedBuffer(dAtA []byte) (int, error) { } } if len(m.UpdateColIdxList) > 0 { - dAtA74 := make([]byte, len(m.UpdateColIdxList)*10) - var j73 int + dAtA75 := make([]byte, len(m.UpdateColIdxList)*10) + var j74 int for _, num1 := range m.UpdateColIdxList { num := uint64(num1) for num >= 1<<7 { - dAtA74[j73] = uint8(uint64(num)&0x7f | 0x80) + dAtA75[j74] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j73++ + j74++ } - dAtA74[j73] = uint8(num) - j73++ + dAtA75[j74] = uint8(num) + j74++ } - i -= j73 - copy(dAtA[i:], dAtA74[:j73]) - i = encodeVarintPlan(dAtA, i, uint64(j73)) + i -= j74 + copy(dAtA[i:], dAtA75[:j74]) + i = encodeVarintPlan(dAtA, i, uint64(j74)) i-- dAtA[i] = 0x12 } @@ -24030,40 +24707,40 @@ func (m *AnalyzeInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x80 } if len(m.TimeConsumedArrayMinor) > 0 { - dAtA83 := make([]byte, len(m.TimeConsumedArrayMinor)*10) - var j82 int + dAtA84 := make([]byte, len(m.TimeConsumedArrayMinor)*10) + var j83 int for _, num1 := range m.TimeConsumedArrayMinor { num := uint64(num1) for num >= 1<<7 { - dAtA83[j82] = uint8(uint64(num)&0x7f | 0x80) + dAtA84[j83] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j82++ + j83++ } - dAtA83[j82] = uint8(num) - j82++ + dAtA84[j83] = uint8(num) + j83++ } - i -= j82 - copy(dAtA[i:], dAtA83[:j82]) - i = encodeVarintPlan(dAtA, i, uint64(j82)) + i -= j83 + copy(dAtA[i:], dAtA84[:j83]) + i = encodeVarintPlan(dAtA, i, uint64(j83)) i-- dAtA[i] = 0x7a } if len(m.TimeConsumedArrayMajor) > 0 { - dAtA85 := make([]byte, len(m.TimeConsumedArrayMajor)*10) - var j84 int + dAtA86 := make([]byte, len(m.TimeConsumedArrayMajor)*10) + var j85 int for _, num1 := range m.TimeConsumedArrayMajor { num := uint64(num1) for num >= 1<<7 { - dAtA85[j84] = uint8(uint64(num)&0x7f | 0x80) + dAtA86[j85] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j84++ + j85++ } - dAtA85[j84] = uint8(num) - j84++ + dAtA86[j85] = uint8(num) + j85++ } - i -= j84 - copy(dAtA[i:], dAtA85[:j84]) - i = encodeVarintPlan(dAtA, i, uint64(j84)) + i -= j85 + copy(dAtA[i:], dAtA86[:j85]) + i = encodeVarintPlan(dAtA, i, uint64(j85)) i-- dAtA[i] = 0x72 } @@ -24830,21 +25507,21 @@ func (m *Node) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0xf8 } if len(m.GroupByHashKey) > 0 { - dAtA105 := make([]byte, len(m.GroupByHashKey)*10) - var j104 int + dAtA106 := make([]byte, len(m.GroupByHashKey)*10) + var j105 int for _, num1 := range m.GroupByHashKey { num := uint64(num1) for num >= 1<<7 { - dAtA105[j104] = uint8(uint64(num)&0x7f | 0x80) + dAtA106[j105] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j104++ + j105++ } - dAtA105[j104] = uint8(num) - j104++ + dAtA106[j105] = uint8(num) + j105++ } - i -= j104 - copy(dAtA[i:], dAtA105[:j104]) - i = encodeVarintPlan(dAtA, i, uint64(j104)) + i -= j105 + copy(dAtA[i:], dAtA106[:j105]) + i = encodeVarintPlan(dAtA, i, uint64(j105)) i-- dAtA[i] = 0x4 i-- @@ -24877,21 +25554,21 @@ func (m *Node) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0xd8 } if len(m.TimeWindowPartitionColPos) > 0 { - dAtA107 := make([]byte, len(m.TimeWindowPartitionColPos)*10) - var j106 int + dAtA108 := make([]byte, len(m.TimeWindowPartitionColPos)*10) + var j107 int for _, num1 := range m.TimeWindowPartitionColPos { num := uint64(num1) for num >= 1<<7 { - dAtA107[j106] = uint8(uint64(num)&0x7f | 0x80) + dAtA108[j107] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j106++ + j107++ } - dAtA107[j106] = uint8(num) - j106++ + dAtA108[j107] = uint8(num) + j107++ } - i -= j106 - copy(dAtA[i:], dAtA107[:j106]) - i = encodeVarintPlan(dAtA, i, uint64(j106)) + i -= j107 + copy(dAtA[i:], dAtA108[:j107]) + i = encodeVarintPlan(dAtA, i, uint64(j107)) i-- dAtA[i] = 0x4 i-- @@ -25423,21 +26100,21 @@ func (m *Node) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0xe2 } if len(m.SourceStep) > 0 { - dAtA125 := make([]byte, len(m.SourceStep)*10) - var j124 int + dAtA126 := make([]byte, len(m.SourceStep)*10) + var j125 int for _, num1 := range m.SourceStep { num := uint64(num1) for num >= 1<<7 { - dAtA125[j124] = uint8(uint64(num)&0x7f | 0x80) + dAtA126[j125] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j124++ + j125++ } - dAtA125[j124] = uint8(num) - j124++ + dAtA126[j125] = uint8(num) + j125++ } - i -= j124 - copy(dAtA[i:], dAtA125[:j124]) - i = encodeVarintPlan(dAtA, i, uint64(j124)) + i -= j125 + copy(dAtA[i:], dAtA126[:j125]) + i = encodeVarintPlan(dAtA, i, uint64(j125)) i-- dAtA[i] = 0x1 i-- @@ -25474,21 +26151,21 @@ func (m *Node) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0xca } if len(m.BindingTags) > 0 { - dAtA128 := make([]byte, len(m.BindingTags)*10) - var j127 int + dAtA129 := make([]byte, len(m.BindingTags)*10) + var j128 int for _, num1 := range m.BindingTags { num := uint64(num1) for num >= 1<<7 { - dAtA128[j127] = uint8(uint64(num)&0x7f | 0x80) + dAtA129[j128] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j127++ + j128++ } - dAtA128[j127] = uint8(num) - j127++ + dAtA129[j128] = uint8(num) + j128++ } - i -= j127 - copy(dAtA[i:], dAtA128[:j127]) - i = encodeVarintPlan(dAtA, i, uint64(j127)) + i -= j128 + copy(dAtA[i:], dAtA129[:j128]) + i = encodeVarintPlan(dAtA, i, uint64(j128)) i-- dAtA[i] = 0x1 i-- @@ -25738,21 +26415,21 @@ func (m *Node) MarshalToSizedBuffer(dAtA []byte) (int, error) { } } if len(m.Children) > 0 { - dAtA138 := make([]byte, len(m.Children)*10) - var j137 int + dAtA139 := make([]byte, len(m.Children)*10) + var j138 int for _, num1 := range m.Children { num := uint64(num1) for num >= 1<<7 { - dAtA138[j137] = uint8(uint64(num)&0x7f | 0x80) + dAtA139[j138] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j137++ + j138++ } - dAtA138[j137] = uint8(num) - j137++ + dAtA139[j138] = uint8(num) + j138++ } - i -= j137 - copy(dAtA[i:], dAtA138[:j137]) - i = encodeVarintPlan(dAtA, i, uint64(j137)) + i -= j138 + copy(dAtA[i:], dAtA139[:j138]) + i = encodeVarintPlan(dAtA, i, uint64(j138)) i-- dAtA[i] = 0x22 } @@ -26352,21 +27029,21 @@ func (m *IcebergScan) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x52 } if len(m.ProjectedFieldIds) > 0 { - dAtA149 := make([]byte, len(m.ProjectedFieldIds)*10) - var j148 int + dAtA150 := make([]byte, len(m.ProjectedFieldIds)*10) + var j149 int for _, num1 := range m.ProjectedFieldIds { num := uint64(num1) for num >= 1<<7 { - dAtA149[j148] = uint8(uint64(num)&0x7f | 0x80) + dAtA150[j149] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j148++ + j149++ } - dAtA149[j148] = uint8(num) - j148++ + dAtA150[j149] = uint8(num) + j149++ } - i -= j148 - copy(dAtA[i:], dAtA149[:j148]) - i = encodeVarintPlan(dAtA, i, uint64(j148)) + i -= j149 + copy(dAtA[i:], dAtA150[:j149]) + i = encodeVarintPlan(dAtA, i, uint64(j149)) i-- dAtA[i] = 0x4a } @@ -27065,21 +27742,21 @@ func (m *PreInsertUkCtx) MarshalToSizedBuffer(dAtA []byte) (int, error) { } } if len(m.KeyTypeCounts) > 0 { - dAtA157 := make([]byte, len(m.KeyTypeCounts)*10) - var j156 int + dAtA158 := make([]byte, len(m.KeyTypeCounts)*10) + var j157 int for _, num1 := range m.KeyTypeCounts { num := uint64(num1) for num >= 1<<7 { - dAtA157[j156] = uint8(uint64(num)&0x7f | 0x80) + dAtA158[j157] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j156++ + j157++ } - dAtA157[j156] = uint8(num) - j156++ + dAtA158[j157] = uint8(num) + j157++ } - i -= j156 - copy(dAtA[i:], dAtA157[:j156]) - i = encodeVarintPlan(dAtA, i, uint64(j156)) + i -= j157 + copy(dAtA[i:], dAtA158[:j157]) + i = encodeVarintPlan(dAtA, i, uint64(j157)) i-- dAtA[i] = 0x1 i-- @@ -27143,21 +27820,21 @@ func (m *PreInsertUkCtx) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x58 } if len(m.TargetColumns) > 0 { - dAtA159 := make([]byte, len(m.TargetColumns)*10) - var j158 int + dAtA160 := make([]byte, len(m.TargetColumns)*10) + var j159 int for _, num1 := range m.TargetColumns { num := uint64(num1) for num >= 1<<7 { - dAtA159[j158] = uint8(uint64(num)&0x7f | 0x80) + dAtA160[j159] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j158++ + j159++ } - dAtA159[j158] = uint8(num) - j158++ + dAtA160[j159] = uint8(num) + j159++ } - i -= j158 - copy(dAtA[i:], dAtA159[:j158]) - i = encodeVarintPlan(dAtA, i, uint64(j158)) + i -= j159 + copy(dAtA[i:], dAtA160[:j159]) + i = encodeVarintPlan(dAtA, i, uint64(j159)) i-- dAtA[i] = 0x52 } @@ -27177,40 +27854,40 @@ func (m *PreInsertUkCtx) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x40 } if len(m.ConflictColumns) > 0 { - dAtA161 := make([]byte, len(m.ConflictColumns)*10) - var j160 int + dAtA162 := make([]byte, len(m.ConflictColumns)*10) + var j161 int for _, num1 := range m.ConflictColumns { num := uint64(num1) for num >= 1<<7 { - dAtA161[j160] = uint8(uint64(num)&0x7f | 0x80) + dAtA162[j161] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j160++ + j161++ } - dAtA161[j160] = uint8(num) - j160++ + dAtA162[j161] = uint8(num) + j161++ } - i -= j160 - copy(dAtA[i:], dAtA161[:j160]) - i = encodeVarintPlan(dAtA, i, uint64(j160)) + i -= j161 + copy(dAtA[i:], dAtA162[:j161]) + i = encodeVarintPlan(dAtA, i, uint64(j161)) i-- dAtA[i] = 0x3a } if len(m.KeyColumns) > 0 { - dAtA163 := make([]byte, len(m.KeyColumns)*10) - var j162 int + dAtA164 := make([]byte, len(m.KeyColumns)*10) + var j163 int for _, num1 := range m.KeyColumns { num := uint64(num1) for num >= 1<<7 { - dAtA163[j162] = uint8(uint64(num)&0x7f | 0x80) + dAtA164[j163] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j162++ + j163++ } - dAtA163[j162] = uint8(num) - j162++ + dAtA164[j163] = uint8(num) + j163++ } - i -= j162 - copy(dAtA[i:], dAtA163[:j162]) - i = encodeVarintPlan(dAtA, i, uint64(j162)) + i -= j163 + copy(dAtA[i:], dAtA164[:j163]) + i = encodeVarintPlan(dAtA, i, uint64(j163)) i-- dAtA[i] = 0x32 } @@ -27250,21 +27927,21 @@ func (m *PreInsertUkCtx) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x10 } if len(m.Columns) > 0 { - dAtA167 := make([]byte, len(m.Columns)*10) - var j166 int + dAtA168 := make([]byte, len(m.Columns)*10) + var j167 int for _, num1 := range m.Columns { num := uint64(num1) for num >= 1<<7 { - dAtA167[j166] = uint8(uint64(num)&0x7f | 0x80) + dAtA168[j167] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j166++ + j167++ } - dAtA167[j166] = uint8(num) - j166++ + dAtA168[j167] = uint8(num) + j167++ } - i -= j166 - copy(dAtA[i:], dAtA167[:j166]) - i = encodeVarintPlan(dAtA, i, uint64(j166)) + i -= j167 + copy(dAtA[i:], dAtA168[:j167]) + i = encodeVarintPlan(dAtA, i, uint64(j167)) i-- dAtA[i] = 0xa } @@ -27588,21 +28265,21 @@ func (m *IdList) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.XXX_unrecognized) } if len(m.List) > 0 { - dAtA176 := make([]byte, len(m.List)*10) - var j175 int + dAtA177 := make([]byte, len(m.List)*10) + var j176 int for _, num1 := range m.List { num := uint64(num1) for num >= 1<<7 { - dAtA176[j175] = uint8(uint64(num)&0x7f | 0x80) + dAtA177[j176] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j175++ + j176++ } - dAtA176[j175] = uint8(num) - j175++ + dAtA177[j176] = uint8(num) + j176++ } - i -= j175 - copy(dAtA[i:], dAtA176[:j175]) - i = encodeVarintPlan(dAtA, i, uint64(j175)) + i -= j176 + copy(dAtA[i:], dAtA177[:j176]) + i = encodeVarintPlan(dAtA, i, uint64(j176)) i-- dAtA[i] = 0xa } @@ -27940,6 +28617,22 @@ func (m *Query) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.RoutineDependencies) > 0 { + for iNdEx := len(m.RoutineDependencies) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.RoutineDependencies[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPlan(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa2 + } + } if m.Correlation != nil { { size, err := m.Correlation.MarshalToSizedBuffer(dAtA[:i]) @@ -28133,21 +28826,21 @@ func (m *Query) MarshalToSizedBuffer(dAtA []byte) (int, error) { } } if len(m.Steps) > 0 { - dAtA184 := make([]byte, len(m.Steps)*10) - var j183 int + dAtA185 := make([]byte, len(m.Steps)*10) + var j184 int for _, num1 := range m.Steps { num := uint64(num1) for num >= 1<<7 { - dAtA184[j183] = uint8(uint64(num)&0x7f | 0x80) + dAtA185[j184] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j183++ + j184++ } - dAtA184[j183] = uint8(num) - j183++ + dAtA185[j184] = uint8(num) + j184++ } - i -= j183 - copy(dAtA[i:], dAtA184[:j183]) - i = encodeVarintPlan(dAtA, i, uint64(j183)) + i -= j184 + copy(dAtA[i:], dAtA185[:j184]) + i = encodeVarintPlan(dAtA, i, uint64(j184)) i-- dAtA[i] = 0x12 } @@ -31238,20 +31931,20 @@ func (m *DropTable) MarshalToSizedBuffer(dAtA []byte) (int, error) { } } if len(m.FkChildTblsReferToMe) > 0 { - dAtA254 := make([]byte, len(m.FkChildTblsReferToMe)*10) - var j253 int + dAtA255 := make([]byte, len(m.FkChildTblsReferToMe)*10) + var j254 int for _, num := range m.FkChildTblsReferToMe { for num >= 1<<7 { - dAtA254[j253] = uint8(uint64(num)&0x7f | 0x80) + dAtA255[j254] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j253++ + j254++ } - dAtA254[j253] = uint8(num) - j253++ + dAtA255[j254] = uint8(num) + j254++ } - i -= j253 - copy(dAtA[i:], dAtA254[:j253]) - i = encodeVarintPlan(dAtA, i, uint64(j253)) + i -= j254 + copy(dAtA[i:], dAtA255[:j254]) + i = encodeVarintPlan(dAtA, i, uint64(j254)) i-- dAtA[i] = 0x62 } @@ -31287,20 +31980,20 @@ func (m *DropTable) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x48 } if len(m.ForeignTbl) > 0 { - dAtA257 := make([]byte, len(m.ForeignTbl)*10) - var j256 int + dAtA258 := make([]byte, len(m.ForeignTbl)*10) + var j257 int for _, num := range m.ForeignTbl { for num >= 1<<7 { - dAtA257[j256] = uint8(uint64(num)&0x7f | 0x80) + dAtA258[j257] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j256++ + j257++ } - dAtA257[j256] = uint8(num) - j256++ + dAtA258[j257] = uint8(num) + j257++ } - i -= j256 - copy(dAtA[i:], dAtA257[:j256]) - i = encodeVarintPlan(dAtA, i, uint64(j256)) + i -= j257 + copy(dAtA[i:], dAtA258[:j257]) + i = encodeVarintPlan(dAtA, i, uint64(j257)) i-- dAtA[i] = 0x3a } @@ -31846,20 +32539,20 @@ func (m *TruncateTable) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x40 } if len(m.ForeignTbl) > 0 { - dAtA266 := make([]byte, len(m.ForeignTbl)*10) - var j265 int + dAtA267 := make([]byte, len(m.ForeignTbl)*10) + var j266 int for _, num := range m.ForeignTbl { for num >= 1<<7 { - dAtA266[j265] = uint8(uint64(num)&0x7f | 0x80) + dAtA267[j266] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j265++ + j266++ } - dAtA266[j265] = uint8(num) - j265++ + dAtA267[j266] = uint8(num) + j266++ } - i -= j265 - copy(dAtA[i:], dAtA266[:j265]) - i = encodeVarintPlan(dAtA, i, uint64(j265)) + i -= j266 + copy(dAtA[i:], dAtA267[:j266]) + i = encodeVarintPlan(dAtA, i, uint64(j266)) i-- dAtA[i] = 0x3a } @@ -31936,20 +32629,20 @@ func (m *ClusterTable) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x18 } if len(m.AccountIDs) > 0 { - dAtA269 := make([]byte, len(m.AccountIDs)*10) - var j268 int + dAtA270 := make([]byte, len(m.AccountIDs)*10) + var j269 int for _, num := range m.AccountIDs { for num >= 1<<7 { - dAtA269[j268] = uint8(uint64(num)&0x7f | 0x80) + dAtA270[j269] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j268++ + j269++ } - dAtA269[j268] = uint8(num) - j268++ + dAtA270[j269] = uint8(num) + j269++ } - i -= j268 - copy(dAtA[i:], dAtA269[:j268]) - i = encodeVarintPlan(dAtA, i, uint64(j268)) + i -= j269 + copy(dAtA[i:], dAtA270[:j269]) + i = encodeVarintPlan(dAtA, i, uint64(j269)) i-- dAtA[i] = 0x12 } @@ -32161,21 +32854,21 @@ func (m *Prepare) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ParamTypes) > 0 { - dAtA273 := make([]byte, len(m.ParamTypes)*10) - var j272 int + dAtA274 := make([]byte, len(m.ParamTypes)*10) + var j273 int for _, num1 := range m.ParamTypes { num := uint64(num1) for num >= 1<<7 { - dAtA273[j272] = uint8(uint64(num)&0x7f | 0x80) + dAtA274[j273] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j272++ + j273++ } - dAtA273[j272] = uint8(num) - j272++ + dAtA274[j273] = uint8(num) + j273++ } - i -= j272 - copy(dAtA[i:], dAtA273[:j272]) - i = encodeVarintPlan(dAtA, i, uint64(j272)) + i -= j273 + copy(dAtA[i:], dAtA274[:j273]) + i = encodeVarintPlan(dAtA, i, uint64(j273)) i-- dAtA[i] = 0x22 } @@ -32322,21 +33015,21 @@ func (m *OtherDCL) MarshalToSizedBuffer(dAtA []byte) (int, error) { copy(dAtA[i:], m.XXX_unrecognized) } if len(m.ParamTypes) > 0 { - dAtA276 := make([]byte, len(m.ParamTypes)*10) - var j275 int + dAtA277 := make([]byte, len(m.ParamTypes)*10) + var j276 int for _, num1 := range m.ParamTypes { num := uint64(num1) for num >= 1<<7 { - dAtA276[j275] = uint8(uint64(num)&0x7f | 0x80) + dAtA277[j276] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j275++ + j276++ } - dAtA276[j275] = uint8(num) - j275++ + dAtA277[j276] = uint8(num) + j276++ } - i -= j275 - copy(dAtA[i:], dAtA276[:j275]) - i = encodeVarintPlan(dAtA, i, uint64(j275)) + i -= j276 + copy(dAtA[i:], dAtA277[:j276]) + i = encodeVarintPlan(dAtA, i, uint64(j276)) i-- dAtA[i] = 0xa } @@ -33165,21 +33858,21 @@ func (m *ODKUForeignKeyCheck) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x12 } if len(m.ColIdxList) > 0 { - dAtA284 := make([]byte, len(m.ColIdxList)*10) - var j283 int + dAtA285 := make([]byte, len(m.ColIdxList)*10) + var j284 int for _, num1 := range m.ColIdxList { num := uint64(num1) for num >= 1<<7 { - dAtA284[j283] = uint8(uint64(num)&0x7f | 0x80) + dAtA285[j284] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j283++ + j284++ } - dAtA284[j283] = uint8(num) - j283++ + dAtA285[j284] = uint8(num) + j284++ } - i -= j283 - copy(dAtA[i:], dAtA284[:j283]) - i = encodeVarintPlan(dAtA, i, uint64(j283)) + i -= j284 + copy(dAtA[i:], dAtA285[:j284]) + i = encodeVarintPlan(dAtA, i, uint64(j284)) i-- dAtA[i] = 0xa } @@ -33382,6 +34075,505 @@ func (m *ViewStep) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *FunctionRef) Marshal() (dAtA []byte, err error) { + size := m.ProtoSize() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *FunctionRef) MarshalTo(dAtA []byte) (int, error) { + size := m.ProtoSize() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *FunctionRef) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.DatabaseId != 0 { + i = encodeVarintPlan(dAtA, i, uint64(m.DatabaseId)) + i-- + dAtA[i] = 0x28 + } + if m.AccountId != 0 { + i = encodeVarintPlan(dAtA, i, uint64(m.AccountId)) + i-- + dAtA[i] = 0x20 + } + if m.NamespaceVersion != 0 { + i = encodeVarintPlan(dAtA, i, uint64(m.NamespaceVersion)) + i-- + dAtA[i] = 0x18 + } + if m.Revision != 0 { + i = encodeVarintPlan(dAtA, i, uint64(m.Revision)) + i-- + dAtA[i] = 0x10 + } + if m.FunctionId != 0 { + i = encodeVarintPlan(dAtA, i, uint64(m.FunctionId)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *SqlRoutineImplementation) Marshal() (dAtA []byte, err error) { + size := m.ProtoSize() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SqlRoutineImplementation) MarshalTo(dAtA []byte) (int, error) { + size := m.ProtoSize() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SqlRoutineImplementation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.SemanticDefinitionSchemaVersion != 0 { + i = encodeVarintPlan(dAtA, i, uint64(m.SemanticDefinitionSchemaVersion)) + i-- + dAtA[i] = 0x10 + } + if len(m.DefinitionFingerprint) > 0 { + i -= len(m.DefinitionFingerprint) + copy(dAtA[i:], m.DefinitionFingerprint) + i = encodeVarintPlan(dAtA, i, uint64(len(m.DefinitionFingerprint))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PythonRoutineImplementation) Marshal() (dAtA []byte, err error) { + size := m.ProtoSize() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PythonRoutineImplementation) MarshalTo(dAtA []byte) (int, error) { + size := m.ProtoSize() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PythonRoutineImplementation) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.DefinitionFingerprint) > 0 { + i -= len(m.DefinitionFingerprint) + copy(dAtA[i:], m.DefinitionFingerprint) + i = encodeVarintPlan(dAtA, i, uint64(len(m.DefinitionFingerprint))) + i-- + dAtA[i] = 0x5a + } + if len(m.NullPolicy) > 0 { + i -= len(m.NullPolicy) + copy(dAtA[i:], m.NullPolicy) + i = encodeVarintPlan(dAtA, i, uint64(len(m.NullPolicy))) + i-- + dAtA[i] = 0x52 + } + if len(m.Mode) > 0 { + i -= len(m.Mode) + copy(dAtA[i:], m.Mode) + i = encodeVarintPlan(dAtA, i, uint64(len(m.Mode))) + i-- + dAtA[i] = 0x4a + } + if m.DefinitionSchemaVersion != 0 { + i = encodeVarintPlan(dAtA, i, uint64(m.DefinitionSchemaVersion)) + i-- + dAtA[i] = 0x40 + } + if len(m.SdkVersion) > 0 { + i -= len(m.SdkVersion) + copy(dAtA[i:], m.SdkVersion) + i = encodeVarintPlan(dAtA, i, uint64(len(m.SdkVersion))) + i-- + dAtA[i] = 0x3a + } + if len(m.EnvironmentDigest) > 0 { + i -= len(m.EnvironmentDigest) + copy(dAtA[i:], m.EnvironmentDigest) + i = encodeVarintPlan(dAtA, i, uint64(len(m.EnvironmentDigest))) + i-- + dAtA[i] = 0x32 + } + if len(m.ArtifactDigest) > 0 { + i -= len(m.ArtifactDigest) + copy(dAtA[i:], m.ArtifactDigest) + i = encodeVarintPlan(dAtA, i, uint64(len(m.ArtifactDigest))) + i-- + dAtA[i] = 0x2a + } + if len(m.AdapterVersion) > 0 { + i -= len(m.AdapterVersion) + copy(dAtA[i:], m.AdapterVersion) + i = encodeVarintPlan(dAtA, i, uint64(len(m.AdapterVersion))) + i-- + dAtA[i] = 0x22 + } + if len(m.AbiContract) > 0 { + i -= len(m.AbiContract) + copy(dAtA[i:], m.AbiContract) + i = encodeVarintPlan(dAtA, i, uint64(len(m.AbiContract))) + i-- + dAtA[i] = 0x1a + } + if len(m.Source) > 0 { + i -= len(m.Source) + copy(dAtA[i:], m.Source) + i = encodeVarintPlan(dAtA, i, uint64(len(m.Source))) + i-- + dAtA[i] = 0x12 + } + if len(m.Handler) > 0 { + i -= len(m.Handler) + copy(dAtA[i:], m.Handler) + i = encodeVarintPlan(dAtA, i, uint64(len(m.Handler))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RoutineCall) Marshal() (dAtA []byte, err error) { + size := m.ProtoSize() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RoutineCall) MarshalTo(dAtA []byte) (int, error) { + size := m.ProtoSize() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RoutineCall) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Leakproof { + i-- + if m.Leakproof { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x70 + } + if len(m.SecurityMode) > 0 { + i -= len(m.SecurityMode) + copy(dAtA[i:], m.SecurityMode) + i = encodeVarintPlan(dAtA, i, uint64(len(m.SecurityMode))) + i-- + dAtA[i] = 0x6a + } + if m.MayError { + i-- + if m.MayError { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x60 + } + if len(m.CallsiteId) > 0 { + i -= len(m.CallsiteId) + copy(dAtA[i:], m.CallsiteId) + i = encodeVarintPlan(dAtA, i, uint64(len(m.CallsiteId))) + i-- + dAtA[i] = 0x5a + } + if len(m.Context) > 0 { + for k := range m.Context { + v := m.Context[k] + baseI := i + i -= len(v) + copy(dAtA[i:], v) + i = encodeVarintPlan(dAtA, i, uint64(len(v))) + i-- + dAtA[i] = 0x12 + i -= len(k) + copy(dAtA[i:], k) + i = encodeVarintPlan(dAtA, i, uint64(len(k))) + i-- + dAtA[i] = 0xa + i = encodeVarintPlan(dAtA, i, uint64(baseI-i)) + i-- + dAtA[i] = 0x52 + } + } + if m.Implementation != nil { + { + size := m.Implementation.ProtoSize() + i -= size + if _, err := m.Implementation.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + if len(m.NullPolicy) > 0 { + i -= len(m.NullPolicy) + copy(dAtA[i:], m.NullPolicy) + i = encodeVarintPlan(dAtA, i, uint64(len(m.NullPolicy))) + i-- + dAtA[i] = 0x3a + } + if len(m.Volatility) > 0 { + i -= len(m.Volatility) + copy(dAtA[i:], m.Volatility) + i = encodeVarintPlan(dAtA, i, uint64(len(m.Volatility))) + i-- + dAtA[i] = 0x32 + } + { + size, err := m.ReturnType.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPlan(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x2a + if len(m.ArgumentTypes) > 0 { + for iNdEx := len(m.ArgumentTypes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ArgumentTypes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPlan(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.Language) > 0 { + i -= len(m.Language) + copy(dAtA[i:], m.Language) + i = encodeVarintPlan(dAtA, i, uint64(len(m.Language))) + i-- + dAtA[i] = 0x1a + } + if m.FunctionRef != nil { + { + size, err := m.FunctionRef.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPlan(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + if m.ContractVersion != 0 { + i = encodeVarintPlan(dAtA, i, uint64(m.ContractVersion)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *RoutineCall_Sql) MarshalTo(dAtA []byte) (int, error) { + size := m.ProtoSize() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RoutineCall_Sql) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.Sql != nil { + { + size, err := m.Sql.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPlan(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x42 + } + return len(dAtA) - i, nil +} +func (m *RoutineCall_Python) MarshalTo(dAtA []byte) (int, error) { + size := m.ProtoSize() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RoutineCall_Python) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + if m.Python != nil { + { + size, err := m.Python.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPlan(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + return len(dAtA) - i, nil +} +func (m *RoutinePlanDependency) Marshal() (dAtA []byte, err error) { + size := m.ProtoSize() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RoutinePlanDependency) MarshalTo(dAtA []byte) (int, error) { + size := m.ProtoSize() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RoutinePlanDependency) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Leakproof { + i-- + if m.Leakproof { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x58 + } + if len(m.SecurityMode) > 0 { + i -= len(m.SecurityMode) + copy(dAtA[i:], m.SecurityMode) + i = encodeVarintPlan(dAtA, i, uint64(len(m.SecurityMode))) + i-- + dAtA[i] = 0x52 + } + if m.MayError { + i-- + if m.MayError { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x48 + } + if len(m.NullPolicy) > 0 { + i -= len(m.NullPolicy) + copy(dAtA[i:], m.NullPolicy) + i = encodeVarintPlan(dAtA, i, uint64(len(m.NullPolicy))) + i-- + dAtA[i] = 0x42 + } + if len(m.Volatility) > 0 { + i -= len(m.Volatility) + copy(dAtA[i:], m.Volatility) + i = encodeVarintPlan(dAtA, i, uint64(len(m.Volatility))) + i-- + dAtA[i] = 0x3a + } + if len(m.EnvironmentDigest) > 0 { + i -= len(m.EnvironmentDigest) + copy(dAtA[i:], m.EnvironmentDigest) + i = encodeVarintPlan(dAtA, i, uint64(len(m.EnvironmentDigest))) + i-- + dAtA[i] = 0x32 + } + if len(m.ArtifactDigest) > 0 { + i -= len(m.ArtifactDigest) + copy(dAtA[i:], m.ArtifactDigest) + i = encodeVarintPlan(dAtA, i, uint64(len(m.ArtifactDigest))) + i-- + dAtA[i] = 0x2a + } + if len(m.DefinitionFingerprint) > 0 { + i -= len(m.DefinitionFingerprint) + copy(dAtA[i:], m.DefinitionFingerprint) + i = encodeVarintPlan(dAtA, i, uint64(len(m.DefinitionFingerprint))) + i-- + dAtA[i] = 0x22 + } + if m.ContractVersion != 0 { + i = encodeVarintPlan(dAtA, i, uint64(m.ContractVersion)) + i-- + dAtA[i] = 0x18 + } + if len(m.Language) > 0 { + i -= len(m.Language) + copy(dAtA[i:], m.Language) + i = encodeVarintPlan(dAtA, i, uint64(len(m.Language))) + i-- + dAtA[i] = 0x12 + } + if m.FunctionRef != nil { + { + size, err := m.FunctionRef.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintPlan(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *DatabaseDefaults) Marshal() (dAtA []byte, err error) { size := m.ProtoSize() dAtA = make([]byte, size) @@ -34129,6 +35321,10 @@ func (m *Function) ProtoSize() (n int) { if m.SyntaxExplicitCast { n += 2 } + if m.RoutineCall != nil { + l = m.RoutineCall.ProtoSize() + n += 1 + l + sovPlan(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -37572,6 +38768,12 @@ func (m *Query) ProtoSize() (n int) { l = m.Correlation.ProtoSize() n += 2 + l + sovPlan(uint64(l)) } + if len(m.RoutineDependencies) > 0 { + for _, e := range m.RoutineDependencies { + l = e.ProtoSize() + n += 2 + l + sovPlan(uint64(l)) + } + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -40041,6 +41243,248 @@ func (m *ViewStep) ProtoSize() (n int) { return n } +func (m *FunctionRef) ProtoSize() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.FunctionId != 0 { + n += 1 + sovPlan(uint64(m.FunctionId)) + } + if m.Revision != 0 { + n += 1 + sovPlan(uint64(m.Revision)) + } + if m.NamespaceVersion != 0 { + n += 1 + sovPlan(uint64(m.NamespaceVersion)) + } + if m.AccountId != 0 { + n += 1 + sovPlan(uint64(m.AccountId)) + } + if m.DatabaseId != 0 { + n += 1 + sovPlan(uint64(m.DatabaseId)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *SqlRoutineImplementation) ProtoSize() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.DefinitionFingerprint) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + if m.SemanticDefinitionSchemaVersion != 0 { + n += 1 + sovPlan(uint64(m.SemanticDefinitionSchemaVersion)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *PythonRoutineImplementation) ProtoSize() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Handler) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.Source) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.AbiContract) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.AdapterVersion) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.ArtifactDigest) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.EnvironmentDigest) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.SdkVersion) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + if m.DefinitionSchemaVersion != 0 { + n += 1 + sovPlan(uint64(m.DefinitionSchemaVersion)) + } + l = len(m.Mode) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.NullPolicy) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.DefinitionFingerprint) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *RoutineCall) ProtoSize() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ContractVersion != 0 { + n += 1 + sovPlan(uint64(m.ContractVersion)) + } + if m.FunctionRef != nil { + l = m.FunctionRef.ProtoSize() + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.Language) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + if len(m.ArgumentTypes) > 0 { + for _, e := range m.ArgumentTypes { + l = e.ProtoSize() + n += 1 + l + sovPlan(uint64(l)) + } + } + l = m.ReturnType.ProtoSize() + n += 1 + l + sovPlan(uint64(l)) + l = len(m.Volatility) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.NullPolicy) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + if m.Implementation != nil { + n += m.Implementation.ProtoSize() + } + if len(m.Context) > 0 { + for k, v := range m.Context { + _ = k + _ = v + mapEntrySize := 1 + len(k) + sovPlan(uint64(len(k))) + 1 + len(v) + sovPlan(uint64(len(v))) + n += mapEntrySize + 1 + sovPlan(uint64(mapEntrySize)) + } + } + l = len(m.CallsiteId) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + if m.MayError { + n += 2 + } + l = len(m.SecurityMode) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + if m.Leakproof { + n += 2 + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + +func (m *RoutineCall_Sql) ProtoSize() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Sql != nil { + l = m.Sql.ProtoSize() + n += 1 + l + sovPlan(uint64(l)) + } + return n +} +func (m *RoutineCall_Python) ProtoSize() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Python != nil { + l = m.Python.ProtoSize() + n += 1 + l + sovPlan(uint64(l)) + } + return n +} +func (m *RoutinePlanDependency) ProtoSize() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.FunctionRef != nil { + l = m.FunctionRef.ProtoSize() + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.Language) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + if m.ContractVersion != 0 { + n += 1 + sovPlan(uint64(m.ContractVersion)) + } + l = len(m.DefinitionFingerprint) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.ArtifactDigest) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.EnvironmentDigest) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.Volatility) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + l = len(m.NullPolicy) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + if m.MayError { + n += 2 + } + l = len(m.SecurityMode) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } + if m.Leakproof { + n += 2 + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *DatabaseDefaults) ProtoSize() (n int) { if m == nil { return 0 @@ -43272,6 +44716,42 @@ func (m *Function) Unmarshal(dAtA []byte) error { } } m.SyntaxExplicitCast = bool(v != 0) + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RoutineCall", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.RoutineCall == nil { + m.RoutineCall = &RoutineCall{} + } + if err := m.RoutineCall.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipPlan(dAtA[iNdEx:]) @@ -65059,79 +66539,113 @@ func (m *Query) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipPlan(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthPlan - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *TransationControl) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPlan - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: TransationControl: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: TransationControl: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field TclType", wireType) - } - m.TclType = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowPlan - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.TclType |= TransationControl_TclType(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 2: + case 20: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Begin", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RoutineDependencies", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RoutineDependencies = append(m.RoutineDependencies, &RoutinePlanDependency{}) + if err := m.RoutineDependencies[len(m.RoutineDependencies)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPlan(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlan + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *TransationControl) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TransationControl: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TransationControl: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TclType", wireType) + } + m.TclType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TclType |= TransationControl_TclType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Begin", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -78186,6 +79700,1586 @@ func (m *ViewStep) Unmarshal(dAtA []byte) error { } return nil } +func (m *FunctionRef) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: FunctionRef: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: FunctionRef: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FunctionId", wireType) + } + m.FunctionId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.FunctionId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Revision", wireType) + } + m.Revision = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Revision |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NamespaceVersion", wireType) + } + m.NamespaceVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NamespaceVersion |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AccountId", wireType) + } + m.AccountId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AccountId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DatabaseId", wireType) + } + m.DatabaseId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DatabaseId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipPlan(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlan + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SqlRoutineImplementation) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: SqlRoutineImplementation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SqlRoutineImplementation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DefinitionFingerprint", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DefinitionFingerprint = append(m.DefinitionFingerprint[:0], dAtA[iNdEx:postIndex]...) + if m.DefinitionFingerprint == nil { + m.DefinitionFingerprint = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SemanticDefinitionSchemaVersion", wireType) + } + m.SemanticDefinitionSchemaVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.SemanticDefinitionSchemaVersion |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipPlan(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlan + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PythonRoutineImplementation) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PythonRoutineImplementation: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PythonRoutineImplementation: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Handler", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Handler = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Source", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Source = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AbiContract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AbiContract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AdapterVersion", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AdapterVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ArtifactDigest", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ArtifactDigest = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EnvironmentDigest", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EnvironmentDigest = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SdkVersion", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SdkVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DefinitionSchemaVersion", wireType) + } + m.DefinitionSchemaVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DefinitionSchemaVersion |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Mode", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Mode = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NullPolicy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NullPolicy = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DefinitionFingerprint", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DefinitionFingerprint = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipPlan(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlan + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RoutineCall) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RoutineCall: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RoutineCall: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractVersion", wireType) + } + m.ContractVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ContractVersion |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FunctionRef", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.FunctionRef == nil { + m.FunctionRef = &FunctionRef{} + } + if err := m.FunctionRef.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Language", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Language = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ArgumentTypes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ArgumentTypes = append(m.ArgumentTypes, &Type{}) + if err := m.ArgumentTypes[len(m.ArgumentTypes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ReturnType", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.ReturnType.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Volatility", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Volatility = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NullPolicy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NullPolicy = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sql", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &SqlRoutineImplementation{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Implementation = &RoutineCall_Sql{v} + iNdEx = postIndex + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Python", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + v := &PythonRoutineImplementation{} + if err := v.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + m.Implementation = &RoutineCall_Python{v} + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Context", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Context == nil { + m.Context = make(map[string]string) + } + var mapkey string + var mapvalue string + for iNdEx < postIndex { + entryPreIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + if fieldNum == 1 { + var stringLenmapkey uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapkey |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapkey := int(stringLenmapkey) + if intStringLenmapkey < 0 { + return ErrInvalidLengthPlan + } + postStringIndexmapkey := iNdEx + intStringLenmapkey + if postStringIndexmapkey < 0 { + return ErrInvalidLengthPlan + } + if postStringIndexmapkey > l { + return io.ErrUnexpectedEOF + } + mapkey = string(dAtA[iNdEx:postStringIndexmapkey]) + iNdEx = postStringIndexmapkey + } else if fieldNum == 2 { + var stringLenmapvalue uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLenmapvalue |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLenmapvalue := int(stringLenmapvalue) + if intStringLenmapvalue < 0 { + return ErrInvalidLengthPlan + } + postStringIndexmapvalue := iNdEx + intStringLenmapvalue + if postStringIndexmapvalue < 0 { + return ErrInvalidLengthPlan + } + if postStringIndexmapvalue > l { + return io.ErrUnexpectedEOF + } + mapvalue = string(dAtA[iNdEx:postStringIndexmapvalue]) + iNdEx = postStringIndexmapvalue + } else { + iNdEx = entryPreIndex + skippy, err := skipPlan(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlan + } + if (iNdEx + skippy) > postIndex { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + m.Context[mapkey] = mapvalue + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CallsiteId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CallsiteId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MayError", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MayError = bool(v != 0) + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SecurityMode", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SecurityMode = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 14: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Leakproof", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Leakproof = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipPlan(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlan + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RoutinePlanDependency) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RoutinePlanDependency: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RoutinePlanDependency: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field FunctionRef", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.FunctionRef == nil { + m.FunctionRef = &FunctionRef{} + } + if err := m.FunctionRef.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Language", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Language = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ContractVersion", wireType) + } + m.ContractVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ContractVersion |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field DefinitionFingerprint", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.DefinitionFingerprint = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ArtifactDigest", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ArtifactDigest = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EnvironmentDigest", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EnvironmentDigest = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Volatility", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Volatility = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NullPolicy", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NullPolicy = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MayError", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.MayError = bool(v != 0) + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SecurityMode", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SecurityMode = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Leakproof", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Leakproof = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipPlan(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthPlan + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *DatabaseDefaults) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pkg/sql/colexec/evalExpression.go b/pkg/sql/colexec/evalExpression.go index b764a5c325757..ed8fee0cfdd16 100644 --- a/pkg/sql/colexec/evalExpression.go +++ b/pkg/sql/colexec/evalExpression.go @@ -455,6 +455,29 @@ func newExpressionExecutorWithAllocation( return executor, nil case *plan.Expr_F: + if routineCall := t.F.GetRoutineCall(); routineCall != nil { + parameters := make([]ExpressionExecutor, len(t.F.Args)) + for i := range parameters { + child, childErr := newExpressionExecutorWithAllocation(proc, t.F.Args[i], selection, buildCtx) + if childErr != nil { + for j := 0; j < i; j++ { + parameters[j].Free() + } + return nil, childErr + } + parameters[i] = child + } + external, externalErr := newExternalRoutineEval(proc, routineCall, parameters, selection) + if externalErr != nil { + for _, parameter := range parameters { + if parameter != nil { + parameter.Free() + } + } + return nil, externalErr + } + return external, nil + } overloadID := t.F.GetFunc().GetObj() // Validate before allocating the result wrapper, including plans retained // from the pre-versioned unary TIMESTAMP implementation. @@ -1648,7 +1671,7 @@ func isRowAlignedExpressionExecutor(executor ExpressionExecutor) bool { executor = source.state.executor case *memoRootExpressionExecutor: executor = source.executor - case *ColumnExpressionExecutor: + case *ColumnExpressionExecutor, *ExternalRoutineEval: return true case *FunctionExpressionExecutor: return !source.folded.canFold @@ -1677,8 +1700,9 @@ func (expr *FunctionExpressionExecutor) evalSelectedRows( } for i, parameter := range expr.parameterResults { // Constants, folded vectors, and list/vector literals are not row-aligned. - // They must be passed through unchanged; only column and non-folded - // function results map one-to-one to the input batch rows. + // They must be passed through unchanged. ExternalRoutineEval is included + // in the row-aligned set because it owns selection compaction and scatters + // its result back to the caller's row domain before returning. rowAligned := isRowAlignedExpressionExecutor(expr.parameterExecutor[i]) if rowAligned && !parameter.IsConst() { selected := expr.selectedParameterVectors[i] diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go new file mode 100644 index 0000000000000..b14f4c444f907 --- /dev/null +++ b/pkg/sql/colexec/external_routine_eval.go @@ -0,0 +1,704 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package colexec + +import ( + "encoding/json" + "fmt" + "os" + "sort" + "strconv" + "strings" + "sync" + "time" + + "github.com/google/uuid" + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/container/batch" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/defines" + planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" + "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/matrixorigin/matrixone/pkg/vm/process" +) + +// ExternalRoutineEval is the physical boundary for a typed RoutineCall. It +// owns argument evaluation, selection compaction/scatter, strict NULL +// guarding, and the result lifetime. The Flight gateway only sees the +// already-admitted selected rows and never owns SQL CASE semantics. +type ExternalRoutineEval struct { + mp *mpool.MPool + allocation *vector.AllocationAccountSelection + call *planpb.RoutineCall + resultType types.Type + + parameterExecutor []ExpressionExecutor + parameterResults []*vector.Vector + result vector.FunctionResultWrapper + + selectedRows []int64 + selectedParameters []*vector.Vector + selectedOwned []*vector.Vector + selectedResult vector.FunctionResultWrapper + selectedNull *vector.Vector + generation uint64 + executionMu sync.Mutex + freed bool + groupMu sync.Mutex + groupStatementID string + groupID string + groupEpoch uint64 +} + +func newExternalRoutineEval( + proc *process.Process, + call *planpb.RoutineCall, + parameters []ExpressionExecutor, + allocation *vector.AllocationAccountSelection, +) (*ExternalRoutineEval, error) { + if proc == nil || proc.Base == nil { + return nil, fmt.Errorf("python udf: evaluator has no process") + } + if err := validateRoutineCall(call); err != nil { + return nil, err + } + if len(call.ArgumentTypes) != len(parameters) { + return nil, fmt.Errorf("python udf: typed routine has %d argument descriptors but %d bound arguments", len(call.ArgumentTypes), len(parameters)) + } + resultType := planTypeToSQL(call.ReturnType) + result, err := vector.NewFunctionResultWrapperWithAllocation(resultType, proc.Mp(), allocation) + if err != nil { + return nil, err + } + return &ExternalRoutineEval{ + mp: proc.Mp(), + allocation: allocation, + call: call, + resultType: resultType, + parameterExecutor: parameters, + parameterResults: make([]*vector.Vector, len(parameters)), + result: result, + }, nil +} + +func validateRoutineCall(call *planpb.RoutineCall) error { + if call == nil || call.FunctionRef == nil || call.FunctionRef.FunctionId == 0 || + call.FunctionRef.DatabaseId == 0 || call.FunctionRef.Revision == 0 || call.FunctionRef.NamespaceVersion == 0 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no exact FunctionRef") + } + if call.ReturnType.Id == int32(types.T_any) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no return descriptor") + } + if call.ContractVersion != udf.PythonPlanContractVersion || !strings.EqualFold(call.Language, udf.LanguagePython) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported typed routine call contract") + } + if call.Volatility != "VOLATILE" { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine must be VOLATILE") + } + if call.MayError != true || call.SecurityMode != "INVOKER" || call.Leakproof { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine semantic contract is not supported") + } + if call.CallsiteId == "" || len(call.CallsiteId) > 256 || strings.ContainsAny(call.CallsiteId, "\r\n") { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no valid callsite id") + } + if len(call.Context) != 0 { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed routine call contains execution context") + } + python := call.GetPython() + if python == nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no Python implementation") + } + if python.Source != "" { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python plan contains source; rebind from the current artifact contract") + } + if python.Handler == "" || + python.AbiContract != udf.PythonABIContract || + python.AdapterVersion != udf.PythonAdapterVersion || + python.SdkVersion != udf.PythonSDKVersion || + python.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation contract is not supported") + } + if python.Mode != "SCALAR" && python.Mode != "VECTOR" { + return fmt.Errorf("python udf: unsupported typed call mode %q", python.Mode) + } + if python.NullPolicy != udf.NullCallHandler && python.NullPolicy != udf.NullReturnNull { + return fmt.Errorf("python udf: unsupported typed NULL policy %q", python.NullPolicy) + } + if call.NullPolicy != python.NullPolicy { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed call NULL policy does not match its implementation") + } + if !udf.IsSHA256Digest(python.ArtifactDigest) || !udf.IsSHA256Digest(python.EnvironmentDigest) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid artifact/environment digest") + } + if !udf.IsSHA256Digest(python.DefinitionFingerprint) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid definition fingerprint") + } + if len(call.ArgumentTypes) > 0 { + for i, argumentType := range call.ArgumentTypes { + if argumentType == nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is nil", i) + } + } + } + return nil +} + +func (e *ExternalRoutineEval) Eval(proc *process.Process, batches []*batch.Batch, selectList []bool) (*vector.Vector, error) { + if e == nil || proc == nil || proc.Base == nil { + return nil, fmt.Errorf("python udf: evaluator has no process") + } + e.executionMu.Lock() + defer e.executionMu.Unlock() + if e.freed { + return nil, fmt.Errorf("python udf: evaluator is freed") + } + if err := validateRoutineCall(e.call); err != nil { + return nil, err + } + accountID, err := defines.GetAccountId(proc.Ctx) + if err != nil { + return nil, err + } + if uint64(accountID) != e.call.FunctionRef.AccountId { + return nil, fmt.Errorf("python udf: FunctionRef account does not match the execution account") + } + python := e.call.GetPython() + rowCount, err := externalRoutineRowCount(python.Mode, batches) + if err != nil { + return nil, err + } + if rowCount == 0 { + if err := e.result.PreExtendAndReset(0); err != nil { + return nil, err + } + return e.result.GetResultVector(), nil + } + if selectList != nil && len(selectList) < rowCount { + return nil, fmt.Errorf("external routine selection is shorter than the input batch") + } + + for i, parameter := range e.parameterExecutor { + var err error + e.parameterResults[i], err = parameter.Eval(proc, batches, selectList) + if err != nil { + return nil, err + } + } + if err := validateExternalRoutineInputs(e.parameterResults, e.call, rowCount); err != nil { + return nil, err + } + e.selectedRows = e.selectedRows[:0] + for row := 0; row < rowCount; row++ { + selected := selectList == nil || selectList[row] + if selected && python.NullPolicy == udf.NullReturnNull && routineHasNullAt(e.parameterResults, row) { + selected = false + } + if selected { + e.selectedRows = append(e.selectedRows, int64(row)) + } + } + if len(e.selectedRows) == 0 { + return e.nullResult(rowCount) + } + + inputs, err := e.compactParameters(proc, rowCount) + if err != nil { + // compactParameters may have already materialized earlier selected + // arguments before a later column fails. There is no execution defer + // until compaction succeeds, so release that partial ownership here. + e.releaseOwnedParameters() + return nil, err + } + defer e.releaseOwnedParameters() + + selectedResult := e.result + if len(e.selectedRows) != rowCount { + if e.selectedResult == nil { + e.selectedResult, err = vector.NewFunctionResultWrapperWithAllocation(e.resultType, e.mp, e.allocation) + if err != nil { + return nil, err + } + } + selectedResult = e.selectedResult + } + if err := selectedResult.PreExtendAndReset(len(e.selectedRows)); err != nil { + return nil, err + } + context, err := buildRoutineContext(proc) + if err != nil { + return nil, err + } + statementContext, err := udf.StatementContextFromMap(context) + if err != nil { + return nil, err + } + if err := e.attachInvocationGroup(context, proc.QueryId()); err != nil { + return nil, err + } + tuple, err := function.NewInvocationTuple(context, proc.QueryId(), accountID) + if err != nil { + return nil, err + } + args := make([]types.Type, len(e.call.ArgumentTypes)) + for i, typ := range e.call.ArgumentTypes { + args[i] = planTypeToSQL(*typ) + } + invocation := &udf.Invocation{ + FunctionRef: udf.FunctionRef{ + AccountID: pythonFunctionAccountID(e.call), + DatabaseID: e.call.FunctionRef.DatabaseId, + FunctionID: e.call.FunctionRef.FunctionId, + Revision: e.call.FunctionRef.Revision, + NamespaceVersion: e.call.FunctionRef.NamespaceVersion, + }, + Language: udf.LanguagePython, + Handler: python.Handler, + Args: args, + ReturnType: e.resultType, + Inputs: inputs, + Length: len(e.selectedRows), + Mode: python.Mode, + NullPolicy: python.NullPolicy, + ABIContract: python.AbiContract, + AdapterVersion: python.AdapterVersion, + SDKVersion: python.SdkVersion, + DefinitionSchemaVersion: int(python.DefinitionSchemaVersion), + ArtifactDigest: python.ArtifactDigest, + EnvironmentDigest: python.EnvironmentDigest, + DefinitionFingerprint: python.DefinitionFingerprint, + Context: context, + CallsiteID: e.call.CallsiteId, + MayError: e.call.MayError, + SecurityMode: e.call.SecurityMode, + Leakproof: e.call.Leakproof, + StatementContext: statementContext, + SecurityFrame: &udf.SecurityFrame{ + ContractVersion: udf.SecurityFrameContractVersion, + Mode: e.call.SecurityMode, + InvokerUserID: defines.GetUserId(proc.Ctx), + InvokerRoleID: defines.GetRoleId(proc.Ctx), + EffectiveUserID: defines.GetUserId(proc.Ctx), + EffectiveRoleID: defines.GetRoleId(proc.Ctx), + }, + Tuple: tuple, + } + if proc.Base.UdfService == nil { + return nil, fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime is not enabled") + } + if err := proc.Base.UdfService.Execute(proc.Ctx, invocation, selectedResult, proc.Mp()); err != nil { + return nil, err + } + if len(e.selectedRows) == rowCount { + return e.result.GetResultVector(), nil + } + return e.scatter(proc, selectedResult.GetResultVector(), rowCount) +} + +// attachInvocationGroup gives one physical evaluator ownership of a reusable +// execution group for one statement. Each invocation still has its own +// InvocationID and monotonically increasing GroupEpoch, so a completed epoch +// cannot be reopened and a later batch cannot consume the previous member's +// resources. ResetForNextQuery discards the group identity; an evaluator that +// has no statement query id uses a fresh one-shot group because it cannot prove +// that two calls belong to the same statement. +func (e *ExternalRoutineEval) attachInvocationGroup(context map[string]string, queryID string) error { + if context == nil { + return fmt.Errorf("python udf: invocation context is unavailable") + } + e.groupMu.Lock() + defer e.groupMu.Unlock() + if queryID == "" { + group, err := uuid.NewV7() + if err != nil { + return fmt.Errorf("python udf: create execution group fence: %w", err) + } + context["group_id"] = "python/" + group.String() + context["group_epoch"] = "1" + return nil + } + if e.groupID == "" || e.groupStatementID != queryID { + group, err := uuid.NewV7() + if err != nil { + return fmt.Errorf("python udf: create execution group fence: %w", err) + } + e.groupStatementID = queryID + e.groupID = queryID + "/python/" + group.String() + e.groupEpoch = 0 + } + if e.groupEpoch == ^uint64(0) { + return fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF execution group epoch overflow") + } + e.groupEpoch++ + context["group_id"] = e.groupID + context["group_epoch"] = strconv.FormatUint(e.groupEpoch, 10) + return nil +} + +func pythonFunctionAccountID(call *planpb.RoutineCall) uint64 { + if call == nil || call.FunctionRef == nil { + return 0 + } + return call.FunctionRef.AccountId +} + +func (e *ExternalRoutineEval) compactParameters(proc *process.Process, rowCount int) ([]*vector.Vector, error) { + if len(e.selectedRows) == 0 { + return nil, nil + } + e.selectedParameters = e.selectedParameters[:0] + for i, input := range e.parameterResults { + if input == nil { + return nil, fmt.Errorf("external routine parameter %d is nil", i) + } + if input.IsConst() || len(e.selectedRows) == rowCount { + e.selectedParameters = append(e.selectedParameters, input) + continue + } + selected, err := vector.NewOffHeapVecWithTypeAndAllocation(*input.GetType(), e.allocation) + if err != nil { + return nil, err + } + selected.SetIsBin(input.GetIsBin()) + if err := selected.Union(input, e.selectedRows, proc.Mp()); err != nil { + selected.Free(proc.Mp()) + return nil, err + } + e.selectedOwned = append(e.selectedOwned, selected) + e.selectedParameters = append(e.selectedParameters, selected) + } + return e.selectedParameters, nil +} + +func validateExternalRoutineInputs(inputs []*vector.Vector, call *planpb.RoutineCall, rowCount int) error { + if len(inputs) != len(call.ArgumentTypes) { + return fmt.Errorf("python udf: evaluated input count %d does not match routine argument count %d", len(inputs), len(call.ArgumentTypes)) + } + for index, input := range inputs { + if input == nil || input.GetType() == nil { + return fmt.Errorf("python udf: evaluated input vector %d has no type", index) + } + if input.Length() == 0 || (!input.IsConst() && input.Length() < rowCount) { + return fmt.Errorf("python udf: evaluated input vector %d has %d rows, expected at least %d", index, input.Length(), rowCount) + } + expected, err := function.NewPythonTypeDescriptor(planTypeToSQL(*call.ArgumentTypes[index])) + if err != nil { + return fmt.Errorf("python udf: invalid argument descriptor %d: %w", index, err) + } + actual, err := function.NewPythonTypeDescriptor(*input.GetType()) + if err != nil { + return fmt.Errorf("python udf: evaluated input vector %d has unsupported type: %w", index, err) + } + expectedFingerprint, err := expected.Fingerprint() + if err != nil { + return err + } + actualFingerprint, err := actual.Fingerprint() + if err != nil { + return err + } + if expectedFingerprint != actualFingerprint { + return fmt.Errorf("python udf: evaluated input vector %d type %s does not match the frozen descriptor", index, input.GetType().DescString()) + } + } + return nil +} + +func (e *ExternalRoutineEval) releaseOwnedParameters() { + for _, selected := range e.selectedOwned { + if selected != nil { + selected.Free(e.mp) + } + } + e.selectedOwned = e.selectedOwned[:0] +} + +func (e *ExternalRoutineEval) nullResult(rowCount int) (*vector.Vector, error) { + if err := e.result.PreExtendAndReset(rowCount); err != nil { + return nil, err + } + result := e.result.GetResultVector() + result.SetAllNulls(rowCount) + result.SetLength(rowCount) + return result, nil +} + +func (e *ExternalRoutineEval) scatter(proc *process.Process, selected *vector.Vector, rowCount int) (*vector.Vector, error) { + if err := e.result.PreExtendAndReset(rowCount); err != nil { + return nil, err + } + result := e.result.GetResultVector() + result.ResetWithSameType() + if e.selectedNull == nil || *e.selectedNull.GetType() != *selected.GetType() { + if e.selectedNull != nil { + e.selectedNull.Free(e.mp) + } + e.selectedNull = vector.NewConstNull(*selected.GetType(), 1, proc.Mp()) + } + selectedRow := 0 + for row := 0; row < rowCount; row++ { + if selectedRow < len(e.selectedRows) && e.selectedRows[selectedRow] == int64(row) { + if err := result.UnionOne(selected, int64(selectedRow), proc.Mp()); err != nil { + return nil, err + } + selectedRow++ + } else if err := result.UnionOne(e.selectedNull, 0, proc.Mp()); err != nil { + return nil, err + } + } + return result, nil +} + +func (e *ExternalRoutineEval) EvalWithoutResultReusing(proc *process.Process, batches []*batch.Batch, selectList []bool) (*vector.Vector, error) { + return e.Eval(proc, batches, selectList) +} + +func (e *ExternalRoutineEval) ResetForNextQuery() { + if e == nil { + return + } + e.executionMu.Lock() + defer e.executionMu.Unlock() + if e.freed { + return + } + e.generation++ + e.groupMu.Lock() + e.groupStatementID = "" + e.groupID = "" + e.groupEpoch = 0 + e.groupMu.Unlock() + for _, parameter := range e.parameterExecutor { + parameter.ResetForNextQuery() + } + e.parameterResults = make([]*vector.Vector, len(e.parameterExecutor)) +} + +func (e *ExternalRoutineEval) Free() { + if e == nil { + return + } + e.executionMu.Lock() + defer e.executionMu.Unlock() + if e.freed { + return + } + e.freed = true + for _, parameter := range e.parameterExecutor { + if parameter != nil { + parameter.Free() + } + } + if e.result != nil { + e.result.Free() + } + if e.selectedResult != nil { + e.selectedResult.Free() + } + if e.selectedNull != nil { + e.selectedNull.Free(e.mp) + } + e.releaseOwnedParameters() +} + +func (e *ExternalRoutineEval) IsColumnExpr() bool { return false } +func (e *ExternalRoutineEval) TypeName() string { return "external routine eval" } + +func routineHasNullAt(inputs []*vector.Vector, row int) bool { + for _, input := range inputs { + if input == nil || input.IsNull(uint64(row)) { + return true + } + } + return false +} + +func planTypeToSQL(typ planpb.Type) types.Type { + return types.NewWithCharset(types.T(typ.Id), typ.Width, typ.Scale, uint8(typ.Charset)) +} + +func externalRoutineRowCount(mode string, batches []*batch.Batch) (int, error) { + if len(batches) > 0 { + // ExpressionExecutor uses the first batch as the logical row domain and + // uses relation positions to read the other batches. Join operators pass + // several one-to-one materialized relation batches, so rejecting every + // multi-batch call would make a Python routine unusable in JOIN ON. A + // different cardinality is still a contract violation: silently selecting + // batches[0] would let an argument from another relation lose rows. + rowCount := -1 + for index, input := range batches { + if input == nil { + return 0, fmt.Errorf("external routine input batch %d is nil", index) + } + if rowCount < 0 { + rowCount = input.RowCount() + continue + } + if input.RowCount() != rowCount { + return 0, fmt.Errorf("python udf: external routine input batch %d has %d rows, expected %d for the logical row domain", index, input.RowCount(), rowCount) + } + } + return rowCount, nil + } + if mode == "VECTOR" { + return 0, fmt.Errorf("python udf: zero-argument VECTOR requires an input batch with num_rows") + } + return 1, nil +} + +// buildRoutineContext freezes the statement-visible values at the physical +// execution boundary. The plan carries only immutable routine metadata; it +// must not carry a statement identity or mutable session values because a +// prepared plan can outlive both. +func buildRoutineContext(proc *process.Process) (map[string]string, error) { + if proc == nil || proc.Base == nil { + return nil, fmt.Errorf("python udf: process is unavailable for statement context") + } + context := make(map[string]string) + // The current query id is stable for the statement and changes for every + // prepared execution; NewInvocationTuple generates one only for internal + // tests that have no query id. It is control metadata, never plan data. + if queryID := proc.QueryId(); queryID != "" { + context["statement_id"] = queryID + } else { + delete(context, "statement_id") + } + queryStart := proc.GetStmtProfile().GetQueryStart() + if queryStart.IsZero() { + // Internal/background processes do not always install a statement + // profile. UnixTime is process-scoped and therefore deterministic for + // the lifetime of that process; a real frontend statement always uses + // its query start above. + if proc.Base.UnixTime == 0 { + return nil, fmt.Errorf("python udf: statement timestamp is unavailable") + } + queryStart = time.Unix(0, proc.Base.UnixTime) + } + context["statement_timestamp_utc"] = strconv.FormatInt(queryStart.UTC().UnixMicro(), 10) + + location := proc.GetSessionInfo().TimeZone + if location == nil { + return nil, fmt.Errorf("python udf: session timezone is unavailable") + } + zoneName := location.String() + var timezoneErr error + if zoneName == "" || zoneName == "SYSTEM" { + return nil, fmt.Errorf("python udf: session timezone is not a stable IANA identity") + } + if zoneName == "Local" { + zoneName, location, timezoneErr = resolveSystemTimezone() + if timezoneErr != nil { + return nil, timezoneErr + } + } + if zoneName == "FixedZone" { + _, offset := queryStart.In(location).Zone() + context["session_timezone_kind"] = "FIXED_OFFSET" + context["session_timezone_offset_minutes"] = formatTimezoneOffsetMinutes(offset / 60) + delete(context, "session_timezone_name") + delete(context, "session_timezone_tzdb_version") + } else { + context["session_timezone_kind"] = "IANA" + context["session_timezone_name"] = zoneName + tzdbVersion, err := udf.TimezoneDatabaseVersion() + if err != nil { + return nil, err + } + context["session_timezone_tzdb_version"] = tzdbVersion + delete(context, "session_timezone_offset_minutes") + } + + mode := sessionSQLMode(proc) + encodedMode, err := json.Marshal(mode) + if err != nil { + return nil, fmt.Errorf("python udf: encode sql_mode context: %w", err) + } + context["sql_mode"] = string(encodedMode) + info := proc.GetSessionInfo() + context["current_user"] = info.User + context["connection_collation"] = info.GetCollation() + if info.Database != "" { + context["current_database"] = info.Database + } else { + delete(context, "current_database") + } + if info.Role != "" { + context["current_role"] = info.Role + } else { + delete(context, "current_role") + } + return context, nil +} + +// resolveSystemTimezone turns the frontend's SYSTEM location into the IANA +// identity that is part of the Python call contract. time.Local intentionally +// hides that identity behind the name "Local"; accepting that name would make +// two workers interpret a DST boundary from different host configuration. +// Prefer an explicit TZ setting, then use the conventional /etc/localtime +// symlink. A regular localtime file has no portable IANA identity and fails +// closed until the deployment supplies one. +func resolveSystemTimezone() (string, *time.Location, error) { + candidates := []string{strings.TrimSpace(os.Getenv("TZ"))} + if link, err := os.Readlink("/etc/localtime"); err == nil { + const marker = "/zoneinfo/" + if index := strings.Index(link, marker); index >= 0 { + candidates = append(candidates, link[index+len(marker):]) + } + } + for _, candidate := range candidates { + candidate = strings.TrimPrefix(candidate, ":") + candidate = strings.TrimPrefix(candidate, "posix/") + candidate = strings.TrimPrefix(candidate, "right/") + if candidate == "" || candidate == "Local" || candidate == "SYSTEM" || strings.HasPrefix(candidate, "/") || strings.Contains(candidate, "..") { + continue + } + location, err := time.LoadLocation(candidate) + if err == nil { + return candidate, location, nil + } + } + return "", nil, fmt.Errorf("python udf: SYSTEM timezone has no stable IANA identity") +} + +func formatTimezoneOffsetMinutes(offset int) string { + if offset >= 0 { + return "+" + strconv.Itoa(offset) + } + return strconv.Itoa(offset) +} + +func sessionSQLMode(proc *process.Process) []string { + value := "" + if proc != nil && proc.GetSessionInfo() != nil { + value = proc.GetSessionInfo().SqlMode + } + if proc != nil { + if resolve := proc.GetResolveVariableFunc(); resolve != nil { + if resolved, err := resolve("sql_mode", true, false); err == nil { + if text, ok := resolved.(string); ok { + value = text + } + } + } + } + if value == process.EmptySqlModeSentinel { + value = "" + } + seen := make(map[string]struct{}) + for _, item := range strings.FieldsFunc(value, func(r rune) bool { return r == ',' || r == ' ' || r == '\t' || r == '\n' || r == '\r' }) { + item = strings.ToUpper(strings.TrimSpace(item)) + if item != "" { + seen[item] = struct{}{} + } + } + result := make([]string, 0, len(seen)) + for item := range seen { + result = append(result, item) + } + sort.Strings(result) + return result +} diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go new file mode 100644 index 0000000000000..63a54ee27fc5e --- /dev/null +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -0,0 +1,368 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package colexec + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/container/batch" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" + "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + "github.com/matrixorigin/matrixone/pkg/testutil" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/matrixorigin/matrixone/pkg/udf/python" + "github.com/matrixorigin/matrixone/pkg/vm/process" + "github.com/stretchr/testify/require" +) + +type externalRoutineTestExecutor struct { + vector *vector.Vector + evalSeen *int +} + +func (e *externalRoutineTestExecutor) Eval(_ *process.Process, _ []*batch.Batch, _ []bool) (*vector.Vector, error) { + if e.evalSeen != nil { + *e.evalSeen++ + } + return e.vector, nil +} + +func (e *externalRoutineTestExecutor) EvalWithoutResultReusing(proc *process.Process, batches []*batch.Batch, selectList []bool) (*vector.Vector, error) { + return e.Eval(proc, batches, selectList) +} + +func (e *externalRoutineTestExecutor) ResetForNextQuery() {} +func (e *externalRoutineTestExecutor) Free() {} +func (e *externalRoutineTestExecutor) IsColumnExpr() bool { return true } +func (e *externalRoutineTestExecutor) TypeName() string { return "test input" } + +type externalRoutineCaptureRuntime struct { + invocation *udf.Invocation + invocations []udf.Invocation +} + +func (r *externalRoutineCaptureRuntime) Language() string { return udf.LanguagePython } + +func (r *externalRoutineCaptureRuntime) Execute(_ context.Context, invocation *udf.Invocation, result vector.FunctionResultWrapper, mp *mpool.MPool) error { + r.invocation = invocation + r.invocations = append(r.invocations, *invocation) + output := result.(*vector.FunctionResult[int64]) + input := invocation.Inputs[0] + values := vector.MustFixedColNoTypeCheck[int64](input) + for row, value := range values[:invocation.Length] { + if err := output.Append(value+1, input.IsNull(uint64(row))); err != nil { + return err + } + } + return nil +} + +func TestExternalRoutineEvalReusesGroupWithNewEpoch(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + proc.SetQueryId("reentry-runtime-query") + proc.GetSessionInfo().TimeZone = time.FixedZone("FixedZone", 8*60*60) + proc.GetSessionInfo().User = "root" + proc.Base.StmtProfile = &process.StmtProfile{} + proc.GetStmtProfile().SetQueryStart(time.Date(2026, 9, 10, 1, 2, 3, 4000, time.UTC)) + + input := vector.NewVec(types.T_int64.ToType()) + defer input.Free(proc.Mp()) + require.NoError(t, vector.AppendFixed(input, int64(1), false, proc.Mp())) + inputBatch := batch.NewWithSize(0) + inputBatch.SetRowCount(1) + + runtime := &externalRoutineCaptureRuntime{} + proc.Base.UdfService = runtime + evaluator, err := newExternalRoutineEval(proc, testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler), []ExpressionExecutor{ + &externalRoutineTestExecutor{vector: input}, + }, nil) + require.NoError(t, err) + defer evaluator.Free() + + _, err = evaluator.Eval(proc, []*batch.Batch{inputBatch}, []bool{true}) + require.NoError(t, err) + _, err = evaluator.Eval(proc, []*batch.Batch{inputBatch}, []bool{true}) + require.NoError(t, err) + require.Len(t, runtime.invocations, 2) + require.Equal(t, runtime.invocations[0].Tuple.GroupID, runtime.invocations[1].Tuple.GroupID) + require.Equal(t, uint64(1), runtime.invocations[0].Tuple.GroupEpoch) + require.Equal(t, uint64(2), runtime.invocations[1].Tuple.GroupEpoch) + require.NotEqual(t, runtime.invocations[0].Tuple.InvocationID, runtime.invocations[1].Tuple.InvocationID) + + evaluator.ResetForNextQuery() + _, err = evaluator.Eval(proc, []*batch.Batch{inputBatch}, []bool{true}) + require.NoError(t, err) + require.Len(t, runtime.invocations, 3) + require.NotEqual(t, runtime.invocations[1].Tuple.GroupID, runtime.invocations[2].Tuple.GroupID) + require.Equal(t, uint64(1), runtime.invocations[2].Tuple.GroupEpoch) +} + +func TestExternalRoutineEvalOwnsSelectionAndStrictNullGuard(t *testing.T) { + proc := testutil.NewProcess(t) + proc.SetQueryId("runtime-query") + proc.GetSessionInfo().TimeZone = time.FixedZone("FixedZone", 8*60*60) + proc.GetSessionInfo().User = "alice" + proc.GetSessionInfo().Database = "app" + proc.GetSessionInfo().Role = "writer" + proc.GetSessionInfo().SqlMode = "STRICT_TRANS_TABLES,ANSI" + proc.Base.StmtProfile = &process.StmtProfile{} + proc.GetStmtProfile().SetQueryStart(time.Date(2026, 9, 10, 1, 2, 3, 4000, time.FixedZone("input", 8*60*60))) + + mp := proc.Mp() + input := vector.NewVec(types.T_int64.ToType()) + defer input.Free(mp) + require.NoError(t, vector.AppendFixed(input, int64(1), false, mp)) + require.NoError(t, vector.AppendFixed(input, int64(0), true, mp)) + require.NoError(t, vector.AppendFixed(input, int64(3), false, mp)) + + runtime := &externalRoutineCaptureRuntime{} + proc.Base.UdfService = runtime + call := testExternalRoutineCall(t, "SCALAR", udf.NullReturnNull) + evaluator, err := newExternalRoutineEval(proc, call, []ExpressionExecutor{ + &externalRoutineTestExecutor{vector: input}, + }, nil) + require.NoError(t, err) + defer evaluator.Free() + + inputBatch := batch.NewWithSize(0) + inputBatch.SetRowCount(3) + result, err := evaluator.Eval(proc, []*batch.Batch{inputBatch}, []bool{true, true, true}) + require.NoError(t, err) + require.Equal(t, 2, runtime.invocation.Length, "the parent evaluator removes strict NULL rows before dispatch") + require.Equal(t, []int64{2, 0, 4}, vector.MustFixedColNoTypeCheck[int64](result)) + require.True(t, result.IsNull(1), "the skipped row is scattered back as NULL") + require.Equal(t, "runtime-query", runtime.invocation.Context["statement_id"]) + require.Equal(t, "[\"ANSI\",\"STRICT_TRANS_TABLES\"]", runtime.invocation.Context["sql_mode"]) + require.Equal(t, "+480", runtime.invocation.Context["session_timezone_offset_minutes"]) + require.Equal(t, "alice", runtime.invocation.Context["current_user"]) +} + +func TestNewExpressionExecutorDispatchesTypedRoutineCall(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + proc.SetQueryId("physical-external-routine-query") + proc.GetSessionInfo().TimeZone = time.FixedZone("FixedZone", 8*60*60) + proc.GetSessionInfo().User = "root" + proc.Base.StmtProfile = &process.StmtProfile{} + proc.GetStmtProfile().SetQueryStart(time.Date(2026, 9, 10, 1, 2, 3, 4000, time.UTC)) + + input := vector.NewVec(types.T_int64.ToType()) + for _, value := range []int64{1, 2, 3} { + require.NoError(t, vector.AppendFixed(input, value, false, proc.Mp())) + } + inputBatch := batch.NewWithSize(1) + inputBatch.Vecs[0] = input + inputBatch.SetRowCount(3) + defer inputBatch.Clean(proc.Mp()) + + runtime := &externalRoutineCaptureRuntime{} + proc.Base.UdfService = runtime + call := testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler) + expression := &planpb.Expr{ + Typ: call.ReturnType, + Expr: &planpb.Expr_F{F: &planpb.Function{ + Args: []*planpb.Expr{{ + Typ: *call.ArgumentTypes[0], + Expr: &planpb.Expr_Col{Col: &planpb.ColRef{RelPos: 0, ColPos: 0}}, + }}, + RoutineCall: call, + }}, + } + + executor, err := NewExpressionExecutor(proc, expression) + require.NoError(t, err) + defer executor.Free() + result, err := executor.Eval(proc, []*batch.Batch{inputBatch}, []bool{true, false, true}) + require.NoError(t, err) + require.Len(t, runtime.invocations, 1) + require.Equal(t, 2, runtime.invocation.Length) + require.Equal(t, []int64{2, 0, 4}, vector.MustFixedColNoTypeCheck[int64](result)) + require.True(t, result.IsNull(1)) +} + +func TestExternalRoutineEvalRequiresRowDomainForZeroArgumentVector(t *testing.T) { + rows, err := externalRoutineRowCount("VECTOR", nil) + require.Zero(t, rows) + require.ErrorContains(t, err, "requires an input batch with num_rows") + + rows, err = externalRoutineRowCount("VECTOR", []*batch.Batch{nil}) + require.Zero(t, rows) + require.ErrorContains(t, err, "input batch 0 is nil") +} + +func TestExternalRoutineEvalAcceptsAlignedJoinBatches(t *testing.T) { + first := batch.NewWithSize(0) + first.SetRowCount(1) + second := batch.NewWithSize(0) + second.SetRowCount(1) + + rows, err := externalRoutineRowCount("SCALAR", []*batch.Batch{first, second}) + require.NoError(t, err) + require.Equal(t, 1, rows) + + second.SetRowCount(2) + rows, err = externalRoutineRowCount("SCALAR", []*batch.Batch{first, second}) + require.Zero(t, rows) + require.ErrorContains(t, err, "expected 1 for the logical row domain") +} + +func TestExternalRoutineEvalRejectsMissingReturnDescriptor(t *testing.T) { + call := testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler) + call.ReturnType = planpb.Type{} + + require.NotPanics(t, func() { + err := validateRoutineCall(call) + require.ErrorContains(t, err, "no return descriptor") + }) +} + +func TestExternalRoutineEvalRejectsExecutionContextInPlan(t *testing.T) { + call := testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler) + call.Context = map[string]string{"current_user": "attacker"} + + err := validateRoutineCall(call) + require.ErrorContains(t, err, "contains execution context") +} + +func TestExternalRoutineEvalRejectsAccountBeforeEvaluatingParameters(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + proc.SetQueryId("account-boundary-query") + proc.GetSessionInfo().TimeZone = time.FixedZone("FixedZone", 8*60*60) + proc.Base.StmtProfile = &process.StmtProfile{} + proc.GetStmtProfile().SetQueryStart(time.Date(2026, 9, 10, 1, 2, 3, 4000, time.UTC)) + + input := vector.NewVec(types.T_int64.ToType()) + defer input.Free(proc.Mp()) + require.NoError(t, vector.AppendFixed(input, int64(1), false, proc.Mp())) + seen := 0 + call := testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler) + call.FunctionRef.AccountId = 99 + evaluator, err := newExternalRoutineEval(proc, call, []ExpressionExecutor{ + &externalRoutineTestExecutor{vector: input, evalSeen: &seen}, + }, nil) + require.NoError(t, err) + defer evaluator.Free() + + inputBatch := batch.NewWithSize(0) + inputBatch.SetRowCount(1) + _, err = evaluator.Eval(proc, []*batch.Batch{inputBatch}, []bool{true}) + require.ErrorContains(t, err, "FunctionRef account does not match") + require.Zero(t, seen) +} + +func TestMaskedNestedExternalRoutineIsCompactedBeforeOuterEval(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + proc.SetQueryId("nested-runtime-query") + proc.GetSessionInfo().TimeZone = time.FixedZone("FixedZone", 8*60*60) + proc.GetSessionInfo().User = "alice" + proc.GetSessionInfo().Database = "app" + proc.GetSessionInfo().SqlMode = "STRICT_TRANS_TABLES" + proc.Base.StmtProfile = &process.StmtProfile{} + proc.GetStmtProfile().SetQueryStart(time.Date(2026, 9, 10, 1, 2, 3, 4000, time.FixedZone("input", 8*60*60))) + + input := vector.NewVec(types.T_int64.ToType()) + for _, value := range []int64{1, 2, 3} { + require.NoError(t, vector.AppendFixed(input, value, false, proc.Mp())) + } + inputBatch := batch.NewWithSize(1) + inputBatch.Vecs[0] = input + inputBatch.SetRowCount(3) + defer inputBatch.Clean(proc.Mp()) + + runtime := &externalRoutineCaptureRuntime{} + proc.Base.UdfService = runtime + external, err := newExternalRoutineEval(proc, testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler), []ExpressionExecutor{ + &externalRoutineTestExecutor{vector: input}, + }, nil) + require.NoError(t, err) + + outer := NewFunctionExpressionExecutor() + require.NoError(t, outer.Init(proc, 1, types.T_int64.ToType())) + defer outer.Free() + outer.evalFn = func(parameters []*vector.Vector, result vector.FunctionResultWrapper, _ *process.Process, length int, _ *function.FunctionSelectList) error { + values := vector.GenerateFunctionFixedTypeParameter[int64](parameters[0]) + output := vector.MustFunctionResult[int64](result) + for row := 0; row < length; row++ { + value, isNull := values.GetValue(uint64(row)) + if err := output.Append(value, isNull); err != nil { + return err + } + } + return nil + } + outer.SetParameter(0, external) + + result, err := outer.Eval(proc, []*batch.Batch{inputBatch}, []bool{false, true, true}) + require.NoError(t, err) + require.Equal(t, []int64{0, 3, 4}, vector.MustFixedColNoTypeCheck[int64](result)) + require.True(t, result.IsNull(0)) +} + +func TestBuildRoutineContextRejectsUnstableTimezone(t *testing.T) { + proc := testutil.NewProcess(t) + proc.GetSessionInfo().TimeZone = time.Local + _, err := buildRoutineContext(proc) + if time.Local.String() == "Local" { + if _, _, resolveErr := resolveSystemTimezone(); resolveErr != nil { + require.ErrorContains(t, err, "stable IANA identity") + } else { + require.NoError(t, err) + } + } else { + require.NoError(t, err) + } +} + +func testExternalRoutineCall(t *testing.T, mode, nullPolicy string) *planpb.RoutineCall { + t.Helper() + descriptor, err := function.NewPythonTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + body, err := json.Marshal(function.PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "add", + Source: "def add(ctx, value): return value + 1", + Mode: mode, + NullPolicy: nullPolicy, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + ArtifactDigest: udf.PythonInlineArtifactDigest("add", "def add(ctx, value): return value + 1"), + EnvironmentDigest: func() string { digest, _ := udf.PythonEnvironmentDigest(); return digest }(), + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []function.PythonTypeDescriptor{descriptor}, + ReturnType: &descriptor, + }) + require.NoError(t, err) + routine := &function.Udf{ + FunctionID: 100, + AccountID: 0, + DatabaseID: 2, + Revision: 7, + NamespaceVersion: 9, + Language: udf.LanguagePython, + Body: string(body), + PythonArgTypes: []function.PythonTypeDescriptor{descriptor}, + PythonReturnType: &descriptor, + } + call, err := routine.GetRoutineCall() + require.NoError(t, err) + call.CallsiteId = "python/test" + return call +} + +func TestExternalRoutineEvalRejectsSourceInExecutablePlan(t *testing.T) { + call := testExternalRoutineCall(t, python.ModeScalar, udf.NullCallHandler) + call.GetPython().Source = "def add(ctx, value): return value + 1" + require.ErrorContains(t, validateRoutineCall(call), "plan contains source") +} diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go index 6b3d3b76e869e..5a37bcf197cdb 100644 --- a/pkg/sql/plan/base_binder.go +++ b/pkg/sql/plan/base_binder.go @@ -5195,8 +5195,24 @@ func bindFuncExprImplUdf( return nil, moerr.NewNotSupportedf(b.GetContext(), "function '%s'", name) } - switch udf.Language { - case string(tree.SQL): + switch strings.ToLower(udf.Language) { + case strings.ToLower(string(tree.SQL)): + // A current SQL revision enters the common dependency envelope before + // its compatibility lowering expands the body. Legacy rows have no + // revision and retain the old path until an explicit replacement + // publishes a current shared revision. + if b.builder != nil && udf.Revision != 0 { + routineCall, err := udf.GetRoutineCall() + if err != nil { + return nil, moerr.NewInvalidInputf(b.GetContext(), "SQL routine is not executable: %v", err) + } + if err := b.builder.assignRoutineCallsite(routineCall); err != nil { + return nil, moerr.NewInvalidInputf(b.GetContext(), "%v", err) + } + if err := b.builder.recordRoutinePlanDependency(routineCall); err != nil { + return nil, moerr.NewInvalidInputf(b.GetContext(), "%v", err) + } + } parserSQLMode := "PIPES_AS_CONCAT" if udf.SQLMode != nil { parserSQLMode = *udf.SQLMode @@ -5239,7 +5255,7 @@ func bindFuncExprImplUdf( return b.impl.BindExpr(bodyExpr, depth, false) } return b.impl.BindSubquery(tree.NewSubquery(substmts[0], false), false) - case string(tree.PYTHON): + case strings.ToLower(string(tree.PYTHON)): expr, err := b.bindPythonUdf(udf, astArgs, depth) if err != nil { return nil, err @@ -5435,31 +5451,63 @@ func correlateSQLUdfArgument(arg *plan.Expr, depth int32) (*plan.Expr, bool) { } func (b *baseBinder) bindPythonUdf(udf *function.Udf, astArgs []tree.Expr, depth int32) (*plan.Expr, error) { - args := make([]*Expr, 2*len(astArgs)+2) - - // python udf self info and query context - args[0] = udf.GetPlanExpr() - - // bind ast function's args + if len(astArgs) != len(udf.GetArgsType()) { + return nil, moerr.NewInvalidInputf(b.GetContext(), "Python routine %s expects %d arguments, got %d", udf.Db, len(udf.GetArgsType()), len(astArgs)) + } + args := make([]*Expr, len(astArgs)) for idx, arg := range astArgs { expr, err := b.impl.BindExpr(arg, depth, false) if err != nil { return nil, err } - args[idx+1] = expr + required := udf.GetArgsType()[idx] + actual := makeTypeByPlan2Expr(expr) + if !actual.Eq(required) { + canCast, _ := function.UdfArgTypeMatch([]types.Type{actual}, []types.T{required.Oid}) + if actual.Oid == required.Oid { + canCast = true + } + if !canCast { + return nil, moerr.NewInvalidInputf(b.GetContext(), "Python routine argument %d has type %s, expected %s", idx+1, actual.String(), required.String()) + } + expr, err = appendCastBeforeExpr(b.GetContext(), expr, makePlan2Type(&required)) + if err != nil { + return nil, err + } + } + args[idx] = expr } - - // function args - fArgTypes := udf.GetArgsPlanType() - for i, t := range fArgTypes { - args[len(astArgs)+i+1] = &Expr{Typ: *t} + // Execution identity is intentionally absent from the persisted plan. A + // prepared plan can be executed many times; the physical evaluator creates + // a fresh statement fence from the current process/query identity. + routineCall, err := udf.GetRoutineCall() + if err != nil { + // RETURNING has its own semantic prohibition for external routines. + // Preserve that deterministic SQL diagnostic even when a test or a + // partially upgraded catalog supplies a Python descriptor without the + // executable identity that the normal path requires. + if b.builder != nil && b.builder.bindingReturningProjection && + strings.Contains(err.Error(), "stable catalog identity") { + return nil, returningNotSupported(b.builder, "external UDF in RETURNING expression") + } + return nil, moerr.NewInvalidInputf(b.GetContext(), "Python routine is not executable: %v", err) } - - // function ret - fRetType := udf.GetRetPlanType() - args[2*len(astArgs)+1] = &Expr{Typ: *fRetType} - - return BindFuncExprImplByPlanExpr(b.GetContext(), "python_user_defined_function", args) + if b.builder != nil { + if err := b.builder.assignRoutineCallsite(routineCall); err != nil { + return nil, moerr.NewInvalidInputf(b.GetContext(), "%v", err) + } + if err := b.builder.recordRoutinePlanDependency(routineCall); err != nil { + return nil, moerr.NewInvalidInputf(b.GetContext(), "%v", err) + } + } + return &plan.Expr{ + Typ: *udf.GetRetPlanType(), + Expr: &plan.Expr_F{F: &plan.Function{ + Func: &plan.ObjectRef{Obj: function.EncodeOverloadID(function.PYTHON_UDF, 0), ObjName: "python_user_defined_function"}, + Args: args, + RoutineCall: routineCall, + }}, + }, nil } func isFindInSetName(name string) bool { diff --git a/pkg/sql/plan/deepcopy.go b/pkg/sql/plan/deepcopy.go index 281546e428ffe..b25dcb18da688 100644 --- a/pkg/sql/plan/deepcopy.go +++ b/pkg/sql/plan/deepcopy.go @@ -887,6 +887,7 @@ func DeepCopyQuery(qry *plan.Query) *plan.Query { CatalogDependencies: make([]*plan.ObjectRef, len(qry.CatalogDependencies)), ViewMetadataDependsOnUdf: qry.ViewMetadataDependsOnUdf, Correlation: DeepCopyCorrelation(qry.Correlation), + RoutineDependencies: make([]*plan.RoutinePlanDependency, len(qry.RoutineDependencies)), } for idx, node := range qry.Nodes { newQry.Nodes[idx] = DeepCopyNode(node) @@ -914,6 +915,11 @@ func DeepCopyQuery(qry *plan.Query) *plan.Query { } } } + for idx, dependency := range qry.RoutineDependencies { + if dependency != nil { + newQry.RoutineDependencies[idx] = proto.Clone(dependency).(*plan.RoutinePlanDependency) + } + } return newQry } @@ -1291,6 +1297,10 @@ func DeepCopyExpr(expr *Expr) *Expr { for idx, arg := range item.F.Args { newArgs[idx] = DeepCopyExpr(arg) } + var routineCall *plan.RoutineCall + if item.F.RoutineCall != nil { + routineCall = proto.Clone(item.F.RoutineCall).(*plan.RoutineCall) + } newExpr.Expr = &plan.Expr_F{ F: &plan.Function{ Func: DeepCopyObjectRef(item.F.Func), @@ -1298,6 +1308,7 @@ func DeepCopyExpr(expr *Expr) *Expr { AggConfig: bytes.Clone(item.F.AggConfig), AggConfigType: item.F.AggConfigType, SyntaxExplicitCast: item.F.SyntaxExplicitCast, + RoutineCall: routineCall, }, } diff --git a/pkg/sql/plan/deepcopy_test.go b/pkg/sql/plan/deepcopy_test.go index 47d30663ceb6c..00efee37073ce 100644 --- a/pkg/sql/plan/deepcopy_test.go +++ b/pkg/sql/plan/deepcopy_test.go @@ -495,6 +495,20 @@ func TestDeepCopyQueryPreservesExecutionMetadata(t *testing.T) { StmtType: planpb.Query_SELECT, Headings: []string{"background"}, }, nil}, + RoutineDependencies: []*planpb.RoutinePlanDependency{{ + FunctionRef: &planpb.FunctionRef{ + FunctionId: 41, + Revision: 7, + NamespaceVersion: 12, + AccountId: 9, + DatabaseId: 8, + }, + Language: "python", + ContractVersion: 1, + DefinitionFingerprint: "fingerprint", + ArtifactDigest: "artifact", + EnvironmentDigest: "environment", + }}, } encoded, err := (&planpb.Query{ViewReferences: source.ViewReferences}).Marshal() @@ -528,6 +542,9 @@ func TestDeepCopyQueryPreservesExecutionMetadata(t *testing.T) { require.Len(t, cloned.BackgroundQueries, 2) require.Nil(t, cloned.BackgroundQueries[1]) require.NotSame(t, source.BackgroundQueries[0], cloned.BackgroundQueries[0]) + require.Equal(t, source.RoutineDependencies, cloned.RoutineDependencies) + require.NotSame(t, source.RoutineDependencies[0], cloned.RoutineDependencies[0]) + require.NotSame(t, source.RoutineDependencies[0].FunctionRef, cloned.RoutineDependencies[0].FunctionRef) cloned.Params[0].GetP().Pos = 99 cloned.CatalogDependencies[0].ObjName = "changed" @@ -536,9 +553,11 @@ func TestDeepCopyQueryPreservesExecutionMetadata(t *testing.T) { cloned.Steps[0] = 99 cloned.Headings[0] = "changed" cloned.BackgroundQueries[0].Headings[0] = "changed" + cloned.RoutineDependencies[0].FunctionRef.Revision = 99 require.Equal(t, int32(3), source.Steps[0]) require.Equal(t, "id", source.Headings[0]) require.Equal(t, "background", source.BackgroundQueries[0].Headings[0]) + require.Equal(t, uint64(7), source.RoutineDependencies[0].FunctionRef.Revision) } func TestDeepCopyDataDefinitionCreateTablePreservesExecutionFields(t *testing.T) { diff --git a/pkg/sql/plan/expr_hash.go b/pkg/sql/plan/expr_hash.go index 5a6f844f8c9a7..93b0dbfaac979 100644 --- a/pkg/sql/plan/expr_hash.go +++ b/pkg/sql/plan/expr_hash.go @@ -139,6 +139,17 @@ func hashExprInto(h writeByter, expr *plan.Expr) { } else { writeUint32(h, 0) } + if v.F.RoutineCall == nil { + writeByte(h, 0) + } else { + writeByte(h, 1) + if b, err := v.F.RoutineCall.Marshal(); err == nil { + writeUint32(h, uint32(len(b))) + _, _ = h.Write(b) + } else { + writeUint32(h, 0) + } + } for _, a := range v.F.Args { hashExprInto(h, a) } @@ -349,6 +360,9 @@ func exprStructuralEqual(a, b *plan.Expr) bool { if !objectRefEqual(av.F.Func, bv.F.Func) { return false } + if !routineCallEqual(av.F.RoutineCall, bv.F.RoutineCall) { + return false + } if len(av.F.Args) != len(bv.F.Args) { return false } @@ -414,6 +428,21 @@ func exprWireEqual(a, b *plan.Expr) bool { return aerr == nil && berr == nil && bytes.Equal(ab[:an], bb[:bn]) } +func routineCallEqual(a, b *plan.RoutineCall) bool { + if a == b { + return true + } + if a == nil || b == nil { + return false + } + ab, aerr := a.Marshal() + bb, berr := b.Marshal() + if aerr != nil || berr != nil { + return false + } + return bytes.Equal(ab, bb) +} + func literalEqual(typ plan.Type, a, b *plan.Literal) bool { if a == b { return true diff --git a/pkg/sql/plan/expr_hash_test.go b/pkg/sql/plan/expr_hash_test.go index 9a6a3c46e5911..b5f459767f887 100644 --- a/pkg/sql/plan/expr_hash_test.go +++ b/pkg/sql/plan/expr_hash_test.go @@ -70,6 +70,42 @@ func TestExprStructuralHashDistinguishesObjectRef(t *testing.T) { require.True(t, exprStructuralEqual(a, c)) } +func TestExprStructuralHashIncludesRoutineIdentity(t *testing.T) { + call := func(revision uint64) *planpb.RoutineCall { + return &planpb.RoutineCall{ + ContractVersion: 1, + FunctionRef: &planpb.FunctionRef{ + FunctionId: 17, + Revision: revision, + NamespaceVersion: 1, + AccountId: 9, + DatabaseId: 11, + }, + Language: "python", + Volatility: "VOLATILE", + NullPolicy: "CALLED_ON_NULL_INPUT", + ReturnType: planpb.Type{Id: int32(types.T_int64)}, + } + } + mk := func(revision uint64) *planpb.Expr { + return &planpb.Expr{ + Typ: planpb.Type{Id: int32(types.T_int64)}, + Expr: &planpb.Expr_F{F: &planpb.Function{ + Func: &planpb.ObjectRef{ObjName: "python_user_defined_function", Obj: 1}, + RoutineCall: call(revision), + }}, + } + } + + a := mk(1) + b := mk(2) + c := mk(1) + require.NotEqual(t, exprStructuralHash(a), exprStructuralHash(b)) + require.False(t, exprStructuralEqual(a, b)) + require.Equal(t, exprStructuralHash(a), exprStructuralHash(c)) + require.True(t, exprStructuralEqual(a, c)) +} + func TestExprStructuralIdentityIncludesNegativeAuxID(t *testing.T) { a := int64Lit(1) a.AuxId = -1 diff --git a/pkg/sql/plan/function/function.go b/pkg/sql/plan/function/function.go index d4b51765c7745..b551bd40ed052 100644 --- a/pkg/sql/plan/function/function.go +++ b/pkg/sql/plan/function/function.go @@ -184,7 +184,7 @@ func isConstant(expr *plan.Expr, allowParameters, currentExecution bool, purpose } return true case *plan.Expr_F: - if e.F == nil || e.F.Func == nil { + if e.F == nil || e.F.Func == nil || e.F.RoutineCall != nil { return false } fid, _ := DecodeOverloadID(e.F.Func.GetObj()) diff --git a/pkg/sql/plan/function/list_builtIn.go b/pkg/sql/plan/function/list_builtIn.go index 27ba6a6af55e7..d6ee5781fae70 100644 --- a/pkg/sql/plan/function/list_builtIn.go +++ b/pkg/sql/plan/function/list_builtIn.go @@ -16911,7 +16911,7 @@ var supportedOthersBuiltIns = []FuncNew{ // execute it once and broadcast the result to all rows. volatile: true, newOp: func() executeLogicOfOverload { - return runPythonUdf + return rejectPythonJSONPlan }, }, }, diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index 90b29bdf5cc44..9f4b54554e78e 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -9,16 +9,12 @@ package function import ( - "encoding/json" "fmt" "strconv" "github.com/google/uuid" - "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" - "github.com/matrixorigin/matrixone/pkg/defines" - "github.com/matrixorigin/matrixone/pkg/udf" "github.com/matrixorigin/matrixone/pkg/udf/protocol" "github.com/matrixorigin/matrixone/pkg/vm/process" ) @@ -78,170 +74,72 @@ func pythonTypesEqual(left, right types.Type) bool { return left.Eq(right) } -// param parameters is same with param inputs in function checkPythonUdf -func pythonUdfRetType(parameters []types.Type) types.Type { - return parameters[len(parameters)-1] -} - -// param parameters has two parts: -// 1. parameters[0]: const vector udf -// 2. parameters[1:]: data vectors -// -// The SQL executor normally applies CASE/selection compaction before this -// function is called. The NULL policy is still enforced here because it is -// part of the persisted Python routine contract and must not be inferred from -// the generic builtin STRICT bit. -func runPythonUdf(parameters []*vector.Vector, result vector.FunctionResultWrapper, proc *process.Process, length int, selectList *FunctionSelectList) error { - if len(parameters) == 0 || parameters[0] == nil { - return fmt.Errorf("python udf: missing routine descriptor") - } - if err := validatePythonRoutineDescriptor(parameters[0]); err != nil { - return err - } - if length < 0 { - return fmt.Errorf("python udf: negative input length %d", length) - } - - routine := &UdfWithContext{} - encoded, isNull := vector.GenerateFunctionStrParameter(parameters[0]).GetStrValue(0) - if isNull { - return fmt.Errorf("python udf: routine descriptor is NULL") - } - if err := json.Unmarshal(encoded, routine); err != nil { - return fmt.Errorf("python udf: decode routine descriptor: %w", err) - } - if routine.Udf == nil { - return fmt.Errorf("python udf: routine descriptor has no function") - } - if err := routine.LoadPythonTypeContract(); err != nil { - return fmt.Errorf("python udf: decode Python type contract: %w", err) - } - - body, err := DecodePythonRoutineBody(routine.Body) - if err != nil { - return fmt.Errorf("python udf: decode Python routine body: %w", err) - } - argTypes, err := routineArgumentTypes(routine) - if err != nil { - return err - } - if len(parameters)-1 != len(argTypes) { - return fmt.Errorf("python udf: routine has %d arguments, received %d", len(argTypes), len(parameters)-1) - } - - if length == 0 { - return result.PreExtendAndReset(0) - } - if err := validatePythonInputVectors(parameters[1:], argTypes, length); err != nil { - return err - } - // FunctionExpressionExecutor passes an empty, non-nil select list when the - // caller selected every row. In that state AnyNull is false and the - // missing bitmap means "all rows", not a truncated selection. A partial - // selection must still carry one entry per invocation row so that a row - // cannot accidentally be evaluated after CASE/short-circuit filtering. - if selectList != nil && !selectList.ShouldEvalAllRow() && len(selectList.SelectList) < length { - return fmt.Errorf("python udf: selection list is shorter than invocation length") - } - - selected := make([]int64, 0, length) - for row := 0; row < length; row++ { - if selectList != nil && len(selectList.SelectList) > row && !selectList.SelectList[row] { +// PythonUdfArgTypeMatch applies the ordinary implicit cast graph while also +// treating the complete frozen descriptor as the exact-match key. The shared +// UDF resolver historically compared only OIDs, which made two Python +// overloads such as DECIMAL(18,2) and DECIMAL(18,6) indistinguishable and +// allowed a non-exact candidate to win with the same cost as an exact one. +func PythonUdfArgTypeMatch(from, to []types.Type) (bool, int) { + if len(from) != len(to) { + return false, -1 + } + length := len(from) + cost := 0 + for index := range from { + if pythonTypesEqual(from[index], to[index]) { continue } - if body.NullPolicy == udf.NullReturnNull && hasNullInput(parameters[1:], row) { + if from[index].Oid == to[index].Oid { + // A same-OID descriptor change is a SQL cast to the declared + // width/scale. It is valid, but less specific than an exact match. + cost++ continue } - selected = append(selected, int64(row)) - } - if len(selected) == 0 { - if err := result.PreExtendAndReset(length); err != nil { - return err + canCast, castCost := fixedImplicitTypeCast(from[index], to[index].Oid) + if !canCast { + return false, -1 } - result.GetResultVector().SetAllNulls(length) - result.GetResultVector().SetLength(length) - return nil - } - - inputs := parameters[1:] - var compacted []*vector.Vector - if len(selected) != length { - compacted = make([]*vector.Vector, len(inputs)) - for i, input := range inputs { - if input == nil { - return fmt.Errorf("python udf: input vector %d is nil", i) - } - compacted[i] = vector.NewOffHeapVecWithType(*input.GetType()) - compacted[i].SetIsBin(input.GetIsBin()) - if err := compacted[i].Union(input, selected, proc.Mp()); err != nil { - freeVectors(compacted, proc.Mp()) - return fmt.Errorf("python udf: compact input %d: %w", i, err) - } + if castCost == 1 { + cost += castCost + } else { + cost += castCost * length } - inputs = compacted - defer freeVectors(compacted, proc.Mp()) - } - - callResult := result - var temporary vector.FunctionResultWrapper - if len(selected) != length { - temporary = vector.NewFunctionResultWrapper(routine.GetRetType(), proc.Mp()) - callResult = temporary - defer temporary.Free() - } - - accountID, err := defines.GetAccountId(proc.Ctx) - if err != nil { - return fmt.Errorf("python udf: resolve account: %w", err) - } - tuple, err := invocationTuple(routine.Context, proc.QueryId(), accountID) - if err != nil { - return err - } - invocation := &udf.Invocation{ - Language: udf.LanguagePython, - Handler: body.Handler, - Source: body.Source, - Args: argTypes, - ReturnType: routine.GetRetType(), - Inputs: inputs, - Length: len(selected), - Mode: body.Mode, - NullPolicy: body.NullPolicy, - ABIContract: body.ABIContract, - AdapterVersion: body.AdapterVersion, - SDKVersion: body.SDKVersion, - Context: cloneContext(routine.Context), - Tuple: tuple, - } - if err := proc.Base.UdfService.Execute(proc.Ctx, invocation, callResult, proc.Mp()); err != nil { - return err } + return true, cost +} - if len(selected) == length { +// PythonUdfArgTypeCast returns the exact descriptor that the Python handler +// declared for every argument. The generic UDF cast helper only receives an +// OID list, so it intentionally preserves a same-OID source type. That is +// unsafe for Python's frozen contract: DECIMAL(18,2) and DECIMAL(18,6) have +// the same OID but different Arrow interpretation. The SQL cast expression +// must therefore materialize the target descriptor even when only metadata +// differs. +func PythonUdfArgTypeCast(from, to []types.Type) []types.Type { + if len(from) != len(to) { return nil } - if err := result.PreExtendAndReset(length); err != nil { - return err - } - full := result.GetResultVector() - full.ResetWithSameType() - nullResult := vector.NewConstNull(routine.GetRetType(), 1, proc.Mp()) - defer nullResult.Free(proc.Mp()) - selectedRow := int64(0) - for row := 0; row < length; row++ { - if selectedRow < int64(len(selected)) && selected[selectedRow] == int64(row) { - if err := full.UnionOne(callResult.GetResultVector(), selectedRow, proc.Mp()); err != nil { - return err - } - selectedRow++ + castTypes := make([]types.Type, len(from)) + for index := range from { + if pythonTypesEqual(from[index], to[index]) { + castTypes[index] = from[index] continue } - if err := full.UnionOne(nullResult, 0, proc.Mp()); err != nil { - return err - } + castTypes[index] = to[index] } - return nil + return castTypes +} + +// param parameters is same with param inputs in function checkPythonUdf +func pythonUdfRetType(parameters []types.Type) types.Type { + return parameters[len(parameters)-1] +} + +// rejectPythonJSONPlan is kept as the explicit stale-plan boundary for the +// historical overload id. Long-term execution enters through the typed +// RoutineCall field and ExternalRoutineEval. +func rejectPythonJSONPlan(_ []*vector.Vector, _ vector.FunctionResultWrapper, _ *process.Process, _ int, _ *FunctionSelectList) error { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python JSON plan execution is not supported; reprepare the statement") } func validatePythonRoutineDescriptor(descriptor *vector.Vector) error { @@ -291,50 +189,6 @@ func hasNullInput(inputs []*vector.Vector, row int) bool { return false } -func routineArgumentTypes(routine *UdfWithContext) ([]types.Type, error) { - if routine.Language == "python" { - args := make([]types.Type, len(routine.PythonArgTypes)) - for i, descriptor := range routine.PythonArgTypes { - args[i] = descriptor.Type() - } - return args, nil - } - if len(routine.ArgsType) != 0 || len(routine.Args) == 0 { - return append([]types.Type(nil), routine.ArgsType...), nil - } - args := make([]types.Type, len(routine.Args)) - for i, arg := range routine.Args { - if arg == nil { - return nil, fmt.Errorf("python udf: routine argument %d is nil", i) - } - typ, ok := types.Types[arg.Type] - if !ok { - return nil, fmt.Errorf("python udf: unknown routine argument type %q", arg.Type) - } - args[i] = typ.ToType() - } - return args, nil -} - -func cloneContext(input map[string]string) map[string]string { - if len(input) == 0 { - return nil - } - output := make(map[string]string, len(input)) - for key, value := range input { - output[key] = value - } - return output -} - -func freeVectors(vectors []*vector.Vector, mp *mpool.MPool) { - for _, vector := range vectors { - if vector != nil { - vector.Free(mp) - } - } -} - func invocationTuple(context map[string]string, queryID string, accountID uint32) (protocol.FencingTuple, error) { statementID := context["statement_id"] if statementID == "" { @@ -347,14 +201,20 @@ func invocationTuple(context map[string]string, queryID string, accountID uint32 } statementID = id.String() } - groupID := context["group_id"] - if groupID == "" { - groupID = statementID + "/python" - } invocationID, err := uuid.NewV7() if err != nil { return protocol.FencingTuple{}, fmt.Errorf("python udf: create invocation fence: %w", err) } + groupID := context["group_id"] + if groupID == "" { + // The current physical adapter owns one group per invocation. A stable + // statement-only group would reject the second batch or second routine + // in the same statement; the scheduler may supply a shared group and + // explicit epoch when it is introduced. + groupID = statementID + "/python/" + invocationID.String() + } else if context["group_epoch"] == "" { + return protocol.FencingTuple{}, fmt.Errorf("python udf: explicit group_id requires group_epoch") + } groupEpoch, err := positiveContextUint(context, "group_epoch", 1) if err != nil { return protocol.FencingTuple{}, err @@ -373,6 +233,13 @@ func invocationTuple(context map[string]string, queryID string, accountID uint32 }, nil } +// NewInvocationTuple is shared by the physical external evaluator and protocol +// tests. A prepared plan supplies no execution identity; the caller provides +// the current query id and this helper creates a fresh invocation fence. +func NewInvocationTuple(context map[string]string, queryID string, accountID uint32) (protocol.FencingTuple, error) { + return invocationTuple(context, queryID, accountID) +} + func positiveContextUint(context map[string]string, key string, fallback uint64) (uint64, error) { value := context[key] if value == "" { diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index 980b8d4cb715c..f8702f89245a6 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -9,13 +9,15 @@ package function import ( + "crypto/sha256" + "encoding/hex" "encoding/json" "fmt" "io" "reflect" "strings" + "unicode/utf8" - "github.com/google/uuid" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/udf" @@ -23,14 +25,29 @@ import ( ) type Udf struct { - Body string `json:"body"` - Language string `json:"language"` - RetType string `json:"rettype"` - Args []*Arg `json:"args"` - Db string `json:"db"` - ModifiedTime string `json:"modified_time"` - SQLMode *string `json:"-"` - ArgsType []types.Type `json:"-"` + Body string `json:"body"` + Language string `json:"language"` + RetType string `json:"rettype"` + Args []*Arg `json:"args"` + Db string `json:"db"` + ModifiedTime string `json:"modified_time"` + // FunctionID and Revision are resolved from the shared catalog. They are + // part of the executable identity; the planner must never re-resolve a + // Python routine by name or latest revision at execution time. + FunctionID int64 `json:"function_id,omitempty"` + AccountID uint64 `json:"account_id,omitempty"` + DatabaseID uint64 `json:"database_id,omitempty"` + Revision uint64 `json:"revision,omitempty"` + NamespaceVersion uint64 `json:"namespace_version,omitempty"` + // SQL revisions use the same immutable identity envelope as Python. These + // fields are empty for legacy SQL rows, which intentionally remain on the + // historical text-expansion path until they are explicitly replaced. + DefinitionFingerprint string `json:"definition_fingerprint,omitempty"` + SemanticDefinitionSchemaVersion int `json:"semantic_definition_schema_version,omitempty"` + Volatility string `json:"volatility,omitempty"` + NullPolicy string `json:"null_policy,omitempty"` + SQLMode *string `json:"-"` + ArgsType []types.Type `json:"-"` // PythonArgTypes and PythonReturnType preserve the exact SQL declaration // for Python's Arrow contract. The legacy catalog's args/rettype columns // intentionally keep only logical type names, which is insufficient for @@ -42,23 +59,80 @@ type Udf struct { type UdfWithContext struct { *Udf `json:"udf"` Context map[string]string `json:"context"` + // PlanContractVersion is retained only for the guarded bridge while the + // typed RoutineCall plan node is rolled out. A missing or unknown value is + // rejected before the handler is reached. + PlanContractVersion int `json:"plan_contract_version"` } // PythonRoutineBody is the single supported Python routine definition. The // catalog must persist mode and NULL policy with the source so execution does // not infer either from a generic SQL function class bit. type PythonRoutineBody struct { - Handler string `json:"handler"` - Source string `json:"source,omitempty"` - Mode string `json:"mode"` - NullPolicy string `json:"null_policy"` - ABIContract string `json:"abi_contract"` - AdapterVersion string `json:"adapter_version"` - ArtifactDigest string `json:"artifact_digest,omitempty"` - EnvironmentDigest string `json:"environment_digest,omitempty"` - SDKVersion string `json:"sdk_version,omitempty"` - ArgTypes []PythonTypeDescriptor `json:"arg_types,omitempty"` - ReturnType *PythonTypeDescriptor `json:"return_type,omitempty"` + DefinitionSchemaVersion int `json:"definition_schema_version"` + Handler string `json:"handler"` + Source string `json:"source,omitempty"` + Mode string `json:"mode"` + NullPolicy string `json:"null_policy"` + ABIContract string `json:"abi_contract"` + AdapterVersion string `json:"adapter_version"` + ArtifactDigest string `json:"artifact_digest"` + EnvironmentDigest string `json:"environment_digest"` + SDKVersion string `json:"sdk_version"` + ArgTypes []PythonTypeDescriptor `json:"arg_types,omitempty"` + ReturnType *PythonTypeDescriptor `json:"return_type,omitempty"` +} + +// PythonSignatureMetadata is the canonical identity metadata for a Python +// routine. The input descriptor is the overload key; the return descriptor is +// persisted alongside it because it is immutable for the lifetime of the +// Function identity even though it does not participate in overload choice. +// Both JSON values are canonical encodings of the exact Arrow descriptors. +func PythonSignatureMetadata( + args []PythonTypeDescriptor, + returnType *PythonTypeDescriptor, +) (canonicalInput, canonicalReturn, fingerprint string, err error) { + if returnType == nil { + return "", "", "", fmt.Errorf("python routine is missing return descriptor") + } + if args == nil { + args = []PythonTypeDescriptor{} + } + for index, descriptor := range args { + if err := validatePythonTypeDescriptor(descriptor); err != nil { + return "", "", "", fmt.Errorf("python routine argument descriptor %d: %w", index, err) + } + } + if err := validatePythonTypeDescriptor(*returnType); err != nil { + return "", "", "", fmt.Errorf("python routine return descriptor: %w", err) + } + inputBytes, err := json.Marshal(args) + if err != nil { + return "", "", "", fmt.Errorf("marshal Python input descriptor: %w", err) + } + returnBytes, err := json.Marshal(returnType) + if err != nil { + return "", "", "", fmt.Errorf("marshal Python return descriptor: %w", err) + } + if len(inputBytes) > types.MaxStringSize || len(returnBytes) > types.MaxStringSize { + return "", "", "", fmt.Errorf("python signature descriptor exceeds the %d-byte catalog limit", types.MaxStringSize) + } + keyBytes, err := json.Marshal(struct { + SchemaVersion int `json:"schema_version"` + Input []PythonTypeDescriptor `json:"input_descriptor"` + Return PythonTypeDescriptor `json:"return_descriptor"` + }{ + SchemaVersion: udf.PythonSignatureKeySchemaVersion, + Input: args, + Return: *returnType, + }) + if err != nil { + return "", "", "", fmt.Errorf("marshal Python signature key: %w", err) + } + digest := sha256.New() + digest.Write([]byte("matrixone-python-udf-signature\x00")) + digest.Write(keyBytes) + return string(inputBytes), string(returnBytes), hex.EncodeToString(digest.Sum(nil)), nil } // DecodePythonRoutineBody decodes the one catalog representation accepted by @@ -85,13 +159,89 @@ func DecodePythonRoutineBody(raw string) (PythonRoutineBody, error) { return body, nil } +// PythonRoutineFingerprint returns the digest of the canonical current +// definition. The digest is persisted with an immutable revision and is +// checked before dispatch; source text alone is not an executable identity. +func PythonRoutineFingerprint(raw string) (string, error) { + body, err := DecodePythonRoutineBody(raw) + if err != nil { + return "", err + } + return PythonRoutineBodyFingerprint(body) +} + +func PythonRoutineBodyFingerprint(body PythonRoutineBody) (string, error) { + if err := body.Validate(); err != nil { + return "", err + } + return pythonudf.DefinitionFingerprint( + body.DefinitionSchemaVersion, + body.Handler, body.Mode, body.NullPolicy, + body.ABIContract, body.AdapterVersion, + body.ArtifactDigest, body.EnvironmentDigest, body.SDKVersion, + body.ArgTypes, *body.ReturnType, + ) +} + +// SQLRoutineFingerprint is the integrity key for the current shared SQL +// revision row. The full typed SQL semantic IR is a later catalog field; +// until that field is published, the revision's canonical stored argument +// signature, return type, and SQL body form the bounded semantic definition +// accepted by the SQL binder. Keeping this encoding here makes the writer, +// resolver, and plan-cache validator use one implementation instead of +// independently hashing source text. +func SQLRoutineFingerprint(body, argTypes, returnType string) (string, error) { + if body == "" || returnType == "" { + return "", fmt.Errorf("SQL routine definition is incomplete") + } + encoded, err := json.Marshal(struct { + SchemaVersion int `json:"schema_version"` + Body string `json:"body"` + ArgTypes string `json:"arg_types"` + ReturnType string `json:"return_type"` + }{ + SchemaVersion: udf.SQLDefinitionSchemaVersion, + Body: body, + ArgTypes: argTypes, + ReturnType: returnType, + }) + if err != nil { + return "", fmt.Errorf("marshal SQL routine definition: %w", err) + } + digest := sha256.New() + digest.Write([]byte("matrixone-sql-udf-definition\x00")) + digest.Write(encoded) + return hex.EncodeToString(digest.Sum(nil)), nil +} + +// DecodeUdfWithContext is retained only as a diagnostic boundary for old +// persisted/demo plans. JSON is not an executable representation of a new +// Python routine, so callers must rebind the statement from the current typed +// catalog contract instead of decoding and dispatching this payload. +func DecodeUdfWithContext(raw []byte) (UdfWithContext, error) { + _ = raw + return UdfWithContext{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python JSON plan is not executable; rebind the statement from the current typed catalog contract") +} + // Validate checks fields that are independent of the catalog argument list. // The argument count is checked by Udf.ValidatePythonTypeContract after the // legacy catalog args column has been decoded. func (body PythonRoutineBody) Validate() error { + if body.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: python definition schema %d is not supported", body.DefinitionSchemaVersion) + } if body.Handler == "" || body.Source == "" { return fmt.Errorf("python routine handler and source are required") } + if !utf8.ValidString(body.Source) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python source is not valid UTF-8") + } + if int64(len([]byte(body.Source))) > pythonudf.DefaultMaxArtifactBytes { + return fmt.Errorf("RESOURCE_EXHAUSTED: Python source exceeds %d bytes", pythonudf.DefaultMaxArtifactBytes) + } + if strings.Contains(body.Handler, ":") { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog") + } if body.Mode != "SCALAR" && body.Mode != "VECTOR" { return fmt.Errorf("python routine has unsupported mode %q", body.Mode) } @@ -104,6 +254,19 @@ func (body PythonRoutineBody) Validate() error { if body.SDKVersion != udf.PythonSDKVersion { return fmt.Errorf("python routine has unsupported SDK %q", body.SDKVersion) } + if !udf.IsSHA256Digest(body.ArtifactDigest) || body.EnvironmentDigest == "" { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition has no immutable artifact/environment digest; use DROP and CREATE") + } + if body.ArtifactDigest != udf.PythonInlineArtifactDigest(body.Handler, body.Source) { + return fmt.Errorf("python routine artifact digest does not match its source") + } + environmentDigest, err := udf.PythonEnvironmentDigest() + if err != nil { + return fmt.Errorf("python routine environment digest is unavailable: %w", err) + } + if body.EnvironmentDigest != environmentDigest { + return fmt.Errorf("python routine environment digest does not match the current contract") + } if body.ReturnType == nil { return fmt.Errorf("python routine is missing return descriptor") } @@ -132,10 +295,124 @@ type Arg struct { Type string `json:"type"` } -func (u *Udf) GetPlanExpr() *plan.Expr { - uid, _ := uuid.NewV7() - data, _ := json.Marshal(&UdfWithContext{Udf: u, Context: map[string]string{"statement_id": uid.String()}}) - return &plan.Expr{Typ: *type2PlanType(types.T_text.ToType()), Expr: &plan.Expr_Lit{Lit: &plan.Literal{Isnull: false, Value: &plan.Literal_Sval{Sval: string(data)}}}} +// GetRoutineCall materializes the immutable typed call metadata used by the +// physical external evaluator. Statement identity and session values are +// deliberately absent: a prepared plan may outlive the statement that bound +// it, so the physical evaluator must construct those values from the current +// process at execution time. +func (u *Udf) GetRoutineCall() (*plan.RoutineCall, error) { + if u == nil { + return nil, fmt.Errorf("routine call requires a non-nil routine") + } + if strings.EqualFold(u.Language, udf.LanguageSQL) { + return u.getSQLRoutineCall() + } + if !strings.EqualFold(u.Language, udf.LanguagePython) { + return nil, fmt.Errorf("routine call has unsupported language %q", u.Language) + } + if u.FunctionID <= 0 || u.DatabaseID == 0 || u.Revision == 0 || u.NamespaceVersion == 0 { + return nil, fmt.Errorf("python routine has no stable catalog identity or revision") + } + body, err := DecodePythonRoutineBody(u.Body) + if err != nil { + return nil, err + } + fingerprint, err := PythonRoutineFingerprint(u.Body) + if err != nil { + return nil, err + } + // The decoded immutable body is the source of truth for the executable + // Arrow signature. Do not rebuild it from the mutable legacy Udf fields; + // doing so could produce a plan whose fingerprint describes one signature + // while its argument types describe another damaged catalog row. + argTypes := make([]types.Type, len(body.ArgTypes)) + for i, descriptor := range body.ArgTypes { + argTypes[i] = descriptor.Type() + } + arguments := make([]*plan.Type, len(argTypes)) + for i, typ := range argTypes { + arguments[i] = type2PlanType(typ) + } + returnType := type2PlanType(body.ReturnType.Type()) + return &plan.RoutineCall{ + ContractVersion: udf.PythonPlanContractVersion, + FunctionRef: &plan.FunctionRef{ + FunctionId: uint64(u.FunctionID), + Revision: u.Revision, + NamespaceVersion: u.NamespaceVersion, + AccountId: u.AccountID, + DatabaseId: u.DatabaseID, + }, + Language: strings.ToLower(u.Language), + ArgumentTypes: arguments, + ReturnType: *returnType, + Volatility: "VOLATILE", + NullPolicy: body.NullPolicy, + MayError: true, + SecurityMode: "INVOKER", + Leakproof: false, + Implementation: &plan.RoutineCall_Python{Python: &plan.PythonRoutineImplementation{ + Handler: body.Handler, + AbiContract: body.ABIContract, + AdapterVersion: body.AdapterVersion, + ArtifactDigest: body.ArtifactDigest, + EnvironmentDigest: body.EnvironmentDigest, + SdkVersion: body.SDKVersion, + DefinitionSchemaVersion: int32(body.DefinitionSchemaVersion), + Mode: body.Mode, + NullPolicy: body.NullPolicy, + DefinitionFingerprint: fingerprint, + }}, + }, nil +} + +// getSQLRoutineCall builds the common catalog envelope for a current SQL +// revision. SQL's existing expression lowering still expands the body at +// bind time, but the exact revision and integrity key are retained in the +// plan dependency so replace/drop cannot silently reuse the old definition. +func (u *Udf) getSQLRoutineCall() (*plan.RoutineCall, error) { + if u.FunctionID <= 0 || u.DatabaseID == 0 || u.Revision == 0 || u.NamespaceVersion == 0 { + return nil, fmt.Errorf("SQL routine has no stable catalog identity or revision") + } + if u.SemanticDefinitionSchemaVersion != udf.SQLDefinitionSchemaVersion || !udf.IsSHA256Digest(u.DefinitionFingerprint) { + return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL routine has no supported semantic definition") + } + argTypes := u.GetArgsType() + arguments := make([]*plan.Type, len(argTypes)) + for index, typ := range argTypes { + arguments[index] = type2PlanType(typ) + } + returnType := type2PlanType(u.GetRetType()) + volatility := u.Volatility + if volatility == "" { + volatility = "VOLATILE" + } + nullPolicy := u.NullPolicy + if nullPolicy == "" { + nullPolicy = udf.NullCallHandler + } + return &plan.RoutineCall{ + ContractVersion: udf.RoutinePlanContractVersion, + FunctionRef: &plan.FunctionRef{ + FunctionId: uint64(u.FunctionID), + Revision: u.Revision, + NamespaceVersion: u.NamespaceVersion, + AccountId: u.AccountID, + DatabaseId: u.DatabaseID, + }, + Language: udf.LanguageSQL, + ArgumentTypes: arguments, + ReturnType: *returnType, + Volatility: volatility, + NullPolicy: nullPolicy, + MayError: true, + SecurityMode: "DEFINER", + Leakproof: false, + Implementation: &plan.RoutineCall_Sql{Sql: &plan.SqlRoutineImplementation{ + DefinitionFingerprint: []byte(u.DefinitionFingerprint), + SemanticDefinitionSchemaVersion: int32(u.SemanticDefinitionSchemaVersion), + }}, + }, nil } func (u *Udf) GetArgsPlanType() []*plan.Type { @@ -148,7 +425,15 @@ func (u *Udf) GetArgsPlanType() []*plan.Type { } func (u *Udf) GetRetPlanType() *plan.Type { return type2PlanType(u.GetRetType()) } func (u *Udf) GetArgsType() []types.Type { - if u.Language == "python" { + if strings.EqualFold(u.Language, "python") { + // Resolver-created routines always set PythonReturnType when the + // canonical descriptor has been loaded. Keeping the fallback makes + // the generic Udf value usable by planner tests and by the SQL-side + // preflight checks without allowing a real Python call to skip body + // validation: GetRoutineCall decodes and validates Body again. + if u.PythonReturnType == nil && u.PythonArgTypes == nil { + return u.ArgsType + } args := make([]types.Type, len(u.PythonArgTypes)) for i, descriptor := range u.PythonArgTypes { args[i] = descriptor.Type() @@ -158,9 +443,9 @@ func (u *Udf) GetArgsType() []types.Type { return u.ArgsType } func (u *Udf) GetRetType() types.Type { - if u.Language == "python" { + if strings.EqualFold(u.Language, "python") { if u.PythonReturnType == nil { - return types.Type{} + return types.Types[u.RetType].ToType() } return u.PythonReturnType.Type() } @@ -172,7 +457,7 @@ func (u *Udf) GetRetType() types.Type { // rejected instead of being reinterpreted through the legacy logical-type // columns. func (u *Udf) LoadPythonTypeContract() error { - if u.Language != "python" { + if !strings.EqualFold(u.Language, "python") { return nil } u.PythonArgTypes = nil @@ -192,7 +477,7 @@ func (u *Udf) LoadPythonTypeContract() error { // before that decode during lookup, so this second check closes the only point // where an argument list and its exact ABI could otherwise diverge. func (u *Udf) ValidatePythonTypeContract() error { - if u.Language != "python" { + if !strings.EqualFold(u.Language, "python") { return nil } if u.PythonReturnType == nil { @@ -209,6 +494,42 @@ func (u *Udf) ValidatePythonTypeContract() error { return validatePythonTypeDescriptor(*u.PythonReturnType) } +// ValidatePythonCatalogSignature verifies the logical type columns that are +// retained by mo_user_defined_function/mo_function_revisions against the +// exact Arrow descriptors in the Python implementation. The legacy columns +// intentionally omit width and scale, so they cannot replace the descriptor; +// they still must agree on the logical OID or a damaged catalog row could be +// selected by overload resolution and dispatched with a different ABI. +func (u *Udf) ValidatePythonCatalogSignature() error { + if u == nil || !strings.EqualFold(u.Language, "python") { + return nil + } + if len(u.Args) != len(u.PythonArgTypes) || u.PythonReturnType == nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python catalog signature is incomplete") + } + for index, argument := range u.Args { + if argument == nil || !pythonCatalogTypeNameMatches(argument.Type, u.PythonArgTypes[index].Type().Oid) { + name := "" + if argument != nil { + name = argument.Type + } + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python catalog argument %d type %q does not match its descriptor", index+1, name) + } + } + if !pythonCatalogTypeNameMatches(u.RetType, u.PythonReturnType.Type().Oid) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python catalog return type %q does not match its descriptor", u.RetType) + } + return nil +} + +func pythonCatalogTypeNameMatches(name string, oid types.T) bool { + name = strings.ToLower(strings.TrimSpace(name)) + if name == "decimal" { + return oid == types.T_decimal64 || oid == types.T_decimal128 + } + return name == strings.ToLower(oid.String()) +} + func validatePythonTypeDescriptor(descriptor PythonTypeDescriptor) error { typ := descriptor.Type() canonical, err := NewPythonTypeDescriptor(typ) diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go index a5844164906ff..36d90a1b3057c 100644 --- a/pkg/sql/plan/function/udf_test.go +++ b/pkg/sql/plan/function/udf_test.go @@ -21,10 +21,17 @@ import ( "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" + planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/udf" "github.com/stretchr/testify/require" ) +func pythonTestBody(body PythonRoutineBody) PythonRoutineBody { + body.ArtifactDigest = udf.PythonInlineArtifactDigest(body.Handler, body.Source) + body.EnvironmentDigest, _ = udf.PythonEnvironmentDigest() + return body +} + func TestPythonTypeContractPreservesDeclaredShape(t *testing.T) { argument := types.New(types.T_decimal64, 18, 6) returnType := types.New(types.T_varchar, 64, 0) @@ -32,36 +39,115 @@ func TestPythonTypeContractPreservesDeclaredShape(t *testing.T) { require.NoError(t, err) returnDescriptor, err := NewPythonTypeDescriptor(returnType) require.NoError(t, err) - body, err := json.Marshal(PythonRoutineBody{ - Handler: "identity", - Source: "def identity(ctx, x): return x", - Mode: "SCALAR", - NullPolicy: udf.NullCallHandler, - ABIContract: udf.PythonABIContract, - AdapterVersion: udf.PythonAdapterVersion, - SDKVersion: udf.PythonSDKVersion, - ArgTypes: []PythonTypeDescriptor{argumentDescriptor}, - ReturnType: &returnDescriptor, - }) + body, err := json.Marshal(pythonTestBody(PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "identity", + Source: "def identity(ctx, x): return x", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []PythonTypeDescriptor{argumentDescriptor}, + ReturnType: &returnDescriptor, + })) require.NoError(t, err) - routine := &Udf{Language: "python", Body: string(body), ArgsType: []types.Type{types.T_decimal64.ToType()}} + routine := &Udf{Language: "python", Body: string(body), RetType: "varchar", ArgsType: []types.Type{types.T_decimal64.ToType()}} require.NoError(t, routine.LoadPythonTypeContract()) routine.Args = []*Arg{{Type: "decimal"}} require.NoError(t, routine.ValidatePythonTypeContract()) + require.NoError(t, routine.ValidatePythonCatalogSignature()) require.Equal(t, argument, routine.GetArgsType()[0]) require.Equal(t, returnType, routine.GetRetType()) require.Equal(t, int32(6), routine.GetArgsPlanType()[0].Scale) require.Equal(t, int32(64), routine.GetRetPlanType().Width) } +func TestPythonSignatureMetadataIsCanonicalAndSensitiveToShape(t *testing.T) { + argument, err := NewPythonTypeDescriptor(types.New(types.T_decimal64, 18, 2)) + require.NoError(t, err) + returnType, err := NewPythonTypeDescriptor(types.T_varchar.ToType()) + require.NoError(t, err) + input, output, fingerprint, err := PythonSignatureMetadata([]PythonTypeDescriptor{argument}, &returnType) + require.NoError(t, err) + require.Equal(t, `[{"type_id":32,"width":18,"scale":2,"offset_width":32}]`, input) + encodedReturn, err := json.Marshal(returnType) + require.NoError(t, err) + require.Equal(t, string(encodedReturn), output) + require.Len(t, fingerprint, 64) + + otherArgument, err := NewPythonTypeDescriptor(types.New(types.T_decimal64, 18, 6)) + require.NoError(t, err) + _, _, otherFingerprint, err := PythonSignatureMetadata([]PythonTypeDescriptor{otherArgument}, &returnType) + require.NoError(t, err) + require.NotEqual(t, fingerprint, otherFingerprint) +} + +func TestPythonUdfArgTypeMatchPrefersExactDescriptor(t *testing.T) { + source := types.New(types.T_decimal64, 18, 2) + exact := types.New(types.T_decimal64, 18, 2) + coerce := types.New(types.T_decimal64, 18, 6) + exactOK, exactCost := PythonUdfArgTypeMatch([]types.Type{source}, []types.Type{exact}) + coerceOK, coerceCost := PythonUdfArgTypeMatch([]types.Type{source}, []types.Type{coerce}) + require.True(t, exactOK) + require.True(t, coerceOK) + require.Less(t, exactCost, coerceCost) +} + +func TestPythonUdfArgTypeCastKeepsDeclaredDescriptorForSameOID(t *testing.T) { + source := types.New(types.T_decimal64, 18, 2) + target := types.New(types.T_decimal64, 18, 6) + + castTypes := PythonUdfArgTypeCast([]types.Type{source}, []types.Type{target}) + require.Equal(t, []types.Type{target}, castTypes) + require.Nil(t, PythonUdfArgTypeCast([]types.Type{source}, nil)) +} + +func TestPythonCatalogSignatureRejectsLogicalDescriptorDrift(t *testing.T) { + argument, err := NewPythonTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + returnType, err := NewPythonTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + raw, err := json.Marshal(pythonTestBody(PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "identity", + Source: "def identity(ctx, value): return value", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []PythonTypeDescriptor{argument}, + ReturnType: &returnType, + })) + require.NoError(t, err) + routine := &Udf{Language: "python", Body: string(raw), RetType: "bigint"} + require.NoError(t, routine.LoadPythonTypeContract()) + routine.Args = []*Arg{{Type: "varchar"}} + require.ErrorContains(t, routine.ValidatePythonCatalogSignature(), "argument 1") + + routine.Args[0].Type = "bigint" + routine.RetType = "varchar" + require.ErrorContains(t, routine.ValidatePythonCatalogSignature(), "return type") +} + func TestPythonTypeContractRejectsMissingReturnDescriptor(t *testing.T) { + body := pythonTestBody(PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "legacy", + Source: "def legacy(ctx, x): return x", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + }) + rawBody, err := json.Marshal(body) + require.NoError(t, err) routine := &Udf{ Language: "python", - Body: `{"handler":"legacy","source":"def legacy(ctx, x): return x",` + - `"mode":"SCALAR","null_policy":"CALLED_ON_NULL_INPUT",` + - `"abi_contract":"PYTHON_ARROW","adapter_version":"2026-09",` + - `"sdk_version":"1.0"}`, + Body: string(rawBody), ArgsType: []types.Type{types.T_int32.ToType()}, RetType: "int", } @@ -73,17 +159,18 @@ func TestPythonTypeContractRejectsArgumentCountMismatch(t *testing.T) { require.NoError(t, err) returnType, err := NewPythonTypeDescriptor(types.T_int32.ToType()) require.NoError(t, err) - body, err := json.Marshal(PythonRoutineBody{ - Handler: "identity", - Source: "def identity(ctx, x): return x", - Mode: "SCALAR", - NullPolicy: udf.NullCallHandler, - ABIContract: udf.PythonABIContract, - AdapterVersion: udf.PythonAdapterVersion, - SDKVersion: udf.PythonSDKVersion, - ArgTypes: []PythonTypeDescriptor{argument}, - ReturnType: &returnType, - }) + body, err := json.Marshal(pythonTestBody(PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "identity", + Source: "def identity(ctx, x): return x", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []PythonTypeDescriptor{argument}, + ReturnType: &returnType, + })) require.NoError(t, err) routine := &Udf{Language: "python", Body: string(body)} require.NoError(t, routine.LoadPythonTypeContract()) @@ -95,17 +182,18 @@ func TestPythonTypeContractReloadReplacesDescriptors(t *testing.T) { require.NoError(t, err) returnType, err := NewPythonTypeDescriptor(types.T_int32.ToType()) require.NoError(t, err) - body, err := json.Marshal(PythonRoutineBody{ - Handler: "identity", - Source: "def identity(ctx, x): return x", - Mode: "SCALAR", - NullPolicy: udf.NullCallHandler, - ABIContract: udf.PythonABIContract, - AdapterVersion: udf.PythonAdapterVersion, - SDKVersion: udf.PythonSDKVersion, - ArgTypes: []PythonTypeDescriptor{argument}, - ReturnType: &returnType, - }) + body, err := json.Marshal(pythonTestBody(PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "identity", + Source: "def identity(ctx, x): return x", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []PythonTypeDescriptor{argument}, + ReturnType: &returnType, + })) require.NoError(t, err) routine := &Udf{Language: "python", Body: string(body)} require.NoError(t, routine.LoadPythonTypeContract()) @@ -114,16 +202,17 @@ func TestPythonTypeContractReloadReplacesDescriptors(t *testing.T) { } func TestPythonRoutineBodyRejectsUnknownAndTrailingData(t *testing.T) { - valid, err := json.Marshal(PythonRoutineBody{ - Handler: "identity", - Source: "def identity(ctx): return 1", - Mode: "SCALAR", - NullPolicy: udf.NullCallHandler, - ABIContract: udf.PythonABIContract, - AdapterVersion: udf.PythonAdapterVersion, - SDKVersion: udf.PythonSDKVersion, - ReturnType: func() *PythonTypeDescriptor { d, _ := NewPythonTypeDescriptor(types.T_int32.ToType()); return &d }(), - }) + valid, err := json.Marshal(pythonTestBody(PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "identity", + Source: "def identity(ctx): return 1", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ReturnType: func() *PythonTypeDescriptor { d, _ := NewPythonTypeDescriptor(types.T_int32.ToType()); return &d }(), + })) require.NoError(t, err) var withUnknown map[string]any @@ -141,16 +230,17 @@ func TestPythonTypeContractRejectsUnrepresentableArrowPrecision(t *testing.T) { Width: 39, OffsetWidth: 32, } - body, err := json.Marshal(PythonRoutineBody{ - Handler: "identity", - Source: "def identity(ctx): return 1", - Mode: "SCALAR", - NullPolicy: udf.NullCallHandler, - ABIContract: udf.PythonABIContract, - AdapterVersion: udf.PythonAdapterVersion, - SDKVersion: udf.PythonSDKVersion, - ReturnType: &returnDescriptor, - }) + body, err := json.Marshal(pythonTestBody(PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "identity", + Source: "def identity(ctx): return 1", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ReturnType: &returnDescriptor, + })) require.NoError(t, err) routine := &Udf{Language: "python", Body: string(body)} require.ErrorContains(t, routine.LoadPythonTypeContract(), "precision") @@ -202,3 +292,117 @@ func TestPythonRoutineIsVolatile(t *testing.T) { _, overloadID := DecodeOverloadID(resolved.GetEncodedOverloadID()) require.True(t, allSupportedFunctions[PYTHON_UDF].Overloads[overloadID].CannotFold()) } + +func TestPythonRoutineCallCarriesExactCatalogContract(t *testing.T) { + descriptor, err := NewPythonTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + body, err := json.Marshal(pythonTestBody(PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "identity", + Source: "def identity(ctx, value): return value", + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []PythonTypeDescriptor{descriptor}, + ReturnType: &descriptor, + })) + require.NoError(t, err) + + routine := &Udf{ + FunctionID: 41, + AccountID: 7, + DatabaseID: 8, + Revision: 7, + NamespaceVersion: 12, + Language: "python", + Body: string(body), + Args: []*Arg{{Name: "value", Type: "bigint"}}, + } + require.NoError(t, routine.LoadPythonTypeContract()) + require.NoError(t, routine.ValidatePythonTypeContract()) + + call, err := routine.GetRoutineCall() + require.NoError(t, err) + require.Equal(t, int32(udf.PythonPlanContractVersion), call.ContractVersion) + require.Equal(t, &planpb.FunctionRef{FunctionId: 41, Revision: 7, NamespaceVersion: 12, AccountId: 7, DatabaseId: 8}, call.FunctionRef) + require.Equal(t, "python", call.Language) + require.Equal(t, "VOLATILE", call.Volatility) + require.Equal(t, udf.NullCallHandler, call.NullPolicy) + require.True(t, call.MayError) + require.Equal(t, "INVOKER", call.SecurityMode) + require.False(t, call.Leakproof) + require.Empty(t, call.Context) + require.Empty(t, call.GetPython().Source, "source is catalog payload, never executable plan state") + require.NotEmpty(t, call.GetPython().DefinitionFingerprint) +} + +func TestSQLRoutineFingerprintAndCallUseSharedRevisionContract(t *testing.T) { + fingerprint, err := SQLRoutineFingerprint("select value + 1", "[\"bigint\"]", "bigint") + require.NoError(t, err) + require.Len(t, fingerprint, 64) + changed, err := SQLRoutineFingerprint("select value + 2", "[\"bigint\"]", "bigint") + require.NoError(t, err) + require.NotEqual(t, fingerprint, changed) + + routine := &Udf{ + FunctionID: 41, + AccountID: 7, + DatabaseID: 8, + Revision: 3, + NamespaceVersion: 4, + Language: udf.LanguageSQL, + RetType: "bigint", + ArgsType: []types.Type{types.T_int64.ToType()}, + DefinitionFingerprint: fingerprint, + SemanticDefinitionSchemaVersion: udf.SQLDefinitionSchemaVersion, + Volatility: "VOLATILE", + NullPolicy: udf.NullCallHandler, + } + call, err := routine.GetRoutineCall() + require.NoError(t, err) + require.Equal(t, udf.LanguageSQL, call.Language) + require.Equal(t, &planpb.FunctionRef{ + FunctionId: 41, Revision: 3, NamespaceVersion: 4, AccountId: 7, DatabaseId: 8, + }, call.FunctionRef) + require.Equal(t, fingerprint, string(call.GetSql().DefinitionFingerprint)) + require.Equal(t, int32(udf.SQLDefinitionSchemaVersion), call.GetSql().SemanticDefinitionSchemaVersion) + require.True(t, call.MayError) + require.Equal(t, "DEFINER", call.SecurityMode) + require.False(t, call.Leakproof) +} + +func TestPythonJSONPlanRequiresExactIdentity(t *testing.T) { + raw, err := json.Marshal(UdfWithContext{ + Udf: &Udf{ + Language: "python", + Body: `{"legacy":true}`, + }, + PlanContractVersion: udf.PythonPlanContractVersion, + }) + require.NoError(t, err) + _, err = DecodeUdfWithContext(raw) + require.ErrorContains(t, err, "JSON plan is not executable") +} + +func TestPythonInvocationTupleUsesOneShotGroupsByDefault(t *testing.T) { + first, err := NewInvocationTuple(nil, "query-1", 7) + require.NoError(t, err) + second, err := NewInvocationTuple(nil, "query-1", 7) + require.NoError(t, err) + require.NotEqual(t, first.InvocationID, second.InvocationID) + require.NotEqual(t, first.GroupID, second.GroupID) + require.Equal(t, first.GroupEpoch, uint64(1)) + require.Equal(t, second.GroupEpoch, uint64(1)) + + _, err = NewInvocationTuple(map[string]string{"group_id": "shared-group"}, "query-1", 7) + require.ErrorContains(t, err, "explicit group_id requires group_epoch") + shared, err := NewInvocationTuple(map[string]string{ + "group_id": "shared-group", + "group_epoch": "3", + }, "query-1", 7) + require.NoError(t, err) + require.Equal(t, "shared-group", shared.GroupID) + require.Equal(t, uint64(3), shared.GroupEpoch) +} diff --git a/pkg/sql/plan/returning.go b/pkg/sql/plan/returning.go index 138e45319211b..1ce5a99442864 100644 --- a/pkg/sql/plan/returning.go +++ b/pkg/sql/plan/returning.go @@ -329,6 +329,9 @@ func (builder *QueryBuilder) appendReturningProjection(exprs tree.SelectExprs, b if len(exprs) == 0 { return nil } + previousReturningBinding := builder.bindingReturningProjection + builder.bindingReturningProjection = true + defer func() { builder.bindingReturningProjection = previousReturningBinding }() if builder.returningSourceStep < 0 || builder.returningTableDef == nil { return moerr.NewInternalError(builder.GetContext(), "DML RETURNING row image was not materialized") } diff --git a/pkg/sql/plan/routine_dependency.go b/pkg/sql/plan/routine_dependency.go new file mode 100644 index 0000000000000..3245686641d67 --- /dev/null +++ b/pkg/sql/plan/routine_dependency.go @@ -0,0 +1,105 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package plan + +import ( + "fmt" + "strings" + + planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" +) + +// maxRoutinePlanDependencies bounds the amount of catalog state retained by +// one executable plan. A plan with more distinct routine revisions is rejected +// during binding instead of creating an unbounded cache invalidation payload. +const maxRoutinePlanDependencies = 1024 + +// assignRoutineCallsite gives a bound routine expression a stable identity +// within its plan. It is not a function identity and is never used for +// catalog lookup; it lets the physical stage, diagnostics and future +// scheduler account for two references to the same revision independently. +func (builder *QueryBuilder) assignRoutineCallsite(call *planpb.RoutineCall) error { + if builder == nil || call == nil { + return nil + } + if call.CallsiteId != "" { + if len(call.CallsiteId) > 256 || strings.ContainsAny(call.CallsiteId, "\r\n") { + return fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine callsite id is too large or invalid") + } + return nil + } + if builder.nextRoutineCallID == ^uint64(0) { + return fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine callsite id exhausted") + } + builder.nextRoutineCallID++ + call.CallsiteId = fmt.Sprintf("%s/%d", strings.ToLower(call.Language), builder.nextRoutineCallID) + return nil +} + +func (builder *QueryBuilder) recordRoutinePlanDependency(call *planpb.RoutineCall) error { + if builder == nil || builder.qry == nil || call == nil || call.FunctionRef == nil { + return nil + } + ref := call.FunctionRef + dependency := &planpb.RoutinePlanDependency{ + FunctionRef: &planpb.FunctionRef{ + FunctionId: ref.FunctionId, + Revision: ref.Revision, + NamespaceVersion: ref.NamespaceVersion, + AccountId: ref.AccountId, + DatabaseId: ref.DatabaseId, + }, + Language: strings.ToLower(call.Language), + ContractVersion: call.ContractVersion, + DefinitionFingerprint: "", + Volatility: call.Volatility, + NullPolicy: call.NullPolicy, + MayError: call.MayError, + SecurityMode: call.SecurityMode, + Leakproof: call.Leakproof, + } + if python := call.GetPython(); python != nil { + dependency.DefinitionFingerprint = python.DefinitionFingerprint + dependency.ArtifactDigest = python.ArtifactDigest + dependency.EnvironmentDigest = python.EnvironmentDigest + } else if sql := call.GetSql(); sql != nil { + // SQL uses the same dependency envelope. The implementation digest is + // stored as the canonical hexadecimal SHA-256 string so cache + // validation has the same representation across languages. + dependency.DefinitionFingerprint = string(sql.DefinitionFingerprint) + } + for _, existing := range builder.qry.RoutineDependencies { + if routinePlanDependenciesEqual(existing, dependency) { + return nil + } + } + if len(builder.qry.RoutineDependencies) >= maxRoutinePlanDependencies { + return fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) + } + builder.qry.RoutineDependencies = append(builder.qry.RoutineDependencies, dependency) + return nil +} + +func routinePlanDependenciesEqual(left, right *planpb.RoutinePlanDependency) bool { + if left == nil || right == nil || left.FunctionRef == nil || right.FunctionRef == nil { + return left == right + } + return left.Language == right.Language && + left.ContractVersion == right.ContractVersion && + left.DefinitionFingerprint == right.DefinitionFingerprint && + left.ArtifactDigest == right.ArtifactDigest && + left.EnvironmentDigest == right.EnvironmentDigest && + left.Volatility == right.Volatility && + left.NullPolicy == right.NullPolicy && + left.MayError == right.MayError && + left.SecurityMode == right.SecurityMode && + left.Leakproof == right.Leakproof && + left.FunctionRef.FunctionId == right.FunctionRef.FunctionId && + left.FunctionRef.Revision == right.FunctionRef.Revision && + left.FunctionRef.NamespaceVersion == right.FunctionRef.NamespaceVersion && + left.FunctionRef.AccountId == right.FunctionRef.AccountId && + left.FunctionRef.DatabaseId == right.FunctionRef.DatabaseId +} diff --git a/pkg/sql/plan/routine_dependency_test.go b/pkg/sql/plan/routine_dependency_test.go new file mode 100644 index 0000000000000..4f49ada054540 --- /dev/null +++ b/pkg/sql/plan/routine_dependency_test.go @@ -0,0 +1,120 @@ +// Copyright 2026 Matrix Origin +// +// 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 plan + +import ( + "testing" + + planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/stretchr/testify/require" +) + +func testRoutineCallForDependency() *planpb.RoutineCall { + return &planpb.RoutineCall{ + ContractVersion: udf.PythonPlanContractVersion, + FunctionRef: &planpb.FunctionRef{ + FunctionId: 11, + Revision: 3, + NamespaceVersion: 4, + AccountId: 5, + DatabaseId: 6, + }, + Language: udf.LanguagePython, + Volatility: "VOLATILE", + NullPolicy: udf.NullCallHandler, + MayError: true, + SecurityMode: "INVOKER", + Leakproof: false, + Implementation: &planpb.RoutineCall_Python{Python: &planpb.PythonRoutineImplementation{ + DefinitionFingerprint: "fingerprint", + ArtifactDigest: "artifact", + EnvironmentDigest: "environment", + }}, + } +} + +func TestRecordRoutinePlanDependencyDeduplicatesAndCopiesIdentity(t *testing.T) { + builder := &QueryBuilder{qry: &planpb.Query{}} + call := testRoutineCallForDependency() + + require.NoError(t, builder.recordRoutinePlanDependency(call)) + require.NoError(t, builder.recordRoutinePlanDependency(call)) + require.Len(t, builder.qry.RoutineDependencies, 1) + + dependency := builder.qry.RoutineDependencies[0] + require.Equal(t, uint64(11), dependency.FunctionRef.FunctionId) + require.Equal(t, uint64(3), dependency.FunctionRef.Revision) + require.Equal(t, "fingerprint", dependency.DefinitionFingerprint) + require.Equal(t, "artifact", dependency.ArtifactDigest) + require.Equal(t, "environment", dependency.EnvironmentDigest) + require.Equal(t, "VOLATILE", dependency.Volatility) + require.Equal(t, udf.NullCallHandler, dependency.NullPolicy) + require.True(t, dependency.MayError) + require.Equal(t, "INVOKER", dependency.SecurityMode) + require.False(t, dependency.Leakproof) + + // The envelope is a plan-owned snapshot of the call identity. Mutating the + // source FunctionRef after binding must not mutate cache validation state. + call.FunctionRef.Revision = 99 + require.Equal(t, uint64(3), dependency.FunctionRef.Revision) +} + +func TestAssignRoutineCallsiteIsPlanLocalAndIdempotent(t *testing.T) { + builder := &QueryBuilder{qry: &planpb.Query{}} + call := testRoutineCallForDependency() + require.NoError(t, builder.assignRoutineCallsite(call)) + require.Equal(t, "python/1", call.CallsiteId) + require.NoError(t, builder.assignRoutineCallsite(call)) + require.Equal(t, "python/1", call.CallsiteId) + + second := testRoutineCallForDependency() + require.NoError(t, builder.assignRoutineCallsite(second)) + require.Equal(t, "python/2", second.CallsiteId) +} + +func TestRecordRoutinePlanDependencyBoundsPlanClosure(t *testing.T) { + builder := &QueryBuilder{qry: &planpb.Query{ + RoutineDependencies: make([]*planpb.RoutinePlanDependency, maxRoutinePlanDependencies), + }} + + err := builder.recordRoutinePlanDependency(testRoutineCallForDependency()) + require.ErrorContains(t, err, "PROGRAM_LIMIT_EXCEEDED") +} + +func TestRecordSQLRoutinePlanDependencyUsesSharedEnvelope(t *testing.T) { + builder := &QueryBuilder{qry: &planpb.Query{}} + call := &planpb.RoutineCall{ + ContractVersion: udf.RoutinePlanContractVersion, + FunctionRef: &planpb.FunctionRef{ + FunctionId: 11, Revision: 3, NamespaceVersion: 4, AccountId: 5, DatabaseId: 6, + }, + Language: udf.LanguageSQL, + Volatility: "VOLATILE", + NullPolicy: udf.NullCallHandler, + MayError: true, + SecurityMode: "DEFINER", + Leakproof: false, + Implementation: &planpb.RoutineCall_Sql{Sql: &planpb.SqlRoutineImplementation{ + DefinitionFingerprint: []byte("0123456789abcdef"), + }}, + } + require.NoError(t, builder.recordRoutinePlanDependency(call)) + require.Len(t, builder.qry.RoutineDependencies, 1) + require.Equal(t, udf.LanguageSQL, builder.qry.RoutineDependencies[0].Language) + require.Equal(t, "0123456789abcdef", builder.qry.RoutineDependencies[0].DefinitionFingerprint) + require.Empty(t, builder.qry.RoutineDependencies[0].ArtifactDigest) + require.Empty(t, builder.qry.RoutineDependencies[0].EnvironmentDigest) +} diff --git a/pkg/sql/plan/rule/constant_fold.go b/pkg/sql/plan/rule/constant_fold.go index 6e1c0943c04e7..763692bf262e8 100644 --- a/pkg/sql/plan/rule/constant_fold.go +++ b/pkg/sql/plan/rule/constant_fold.go @@ -220,6 +220,12 @@ func (r *ConstantFold) foldExpr(expr *plan.Expr, proc *process.Process, spatialC return expr } + // A typed RoutineCall is an execute-time boundary. Even a zero-argument + // call with only literal metadata must reach ExternalRoutineEval so that + // volatility, row cardinality, and the captured revision remain intact. + if fn.RoutineCall != nil { + return expr + } overloadID := fn.Func.GetObj() if r.isPrepared && IsNullIntegerArgumentCast(expr) { return expr diff --git a/pkg/sql/plan/rule/constant_fold_test.go b/pkg/sql/plan/rule/constant_fold_test.go index da2d76b74cb7e..d02937a458dd7 100644 --- a/pkg/sql/plan/rule/constant_fold_test.go +++ b/pkg/sql/plan/rule/constant_fold_test.go @@ -74,6 +74,29 @@ func TestConstantFoldRuleRetainsStandaloneInterval(t *testing.T) { require.Same(t, expr, NewConstantFold(false).constantFold(expr, testutil.NewProcess(t))) } +func TestConstantFoldRuleNeverExecutesTypedRoutineCall(t *testing.T) { + expr := &plan.Expr{ + Typ: plan.Type{Id: int32(types.T_int64)}, + Expr: &plan.Expr_F{F: &plan.Function{ + Func: &plan.ObjectRef{ + Obj: function.EncodeOverloadID(function.PYTHON_UDF, 0), + ObjName: "python_user_defined_function", + }, + Args: []*plan.Expr{{ + Typ: plan.Type{Id: int32(types.T_int64)}, + Expr: &plan.Expr_Lit{Lit: &plan.Literal{Value: &plan.Literal_I64Val{I64Val: 1}}}, + }}, + RoutineCall: &plan.RoutineCall{ + FunctionRef: &plan.FunctionRef{FunctionId: 1, DatabaseId: 1, Revision: 1, NamespaceVersion: 1}, + Language: "PYTHON", + }, + }}, + } + + require.False(t, IsConstant(expr, false)) + require.Same(t, expr, NewConstantFold(false).constantFold(expr, testutil.NewProcess(t))) +} + func TestGetConstantValue2PreservesAndValidatesLiteralStringSource(t *testing.T) { proc := testutil.NewProcess(t) vec := vector.NewVec(types.T_varchar.ToType()) diff --git a/pkg/sql/plan/types.go b/pkg/sql/plan/types.go index 9f951ef8796a2..6b2ec13f1ac9b 100644 --- a/pkg/sql/plan/types.go +++ b/pkg/sql/plan/types.go @@ -500,6 +500,11 @@ type QueryBuilder struct { // Negative AuxIds identify memoized expression sources across every bind // context that can contribute expressions to this query. nextVolatileExprMemoID int32 + // nextRoutineCallID gives every typed routine expression a plan-local + // callsite identity. It is deliberately separate from the SQL body + // substitution counter: lowering must not make a callsite depend on the + // number of generated parameter markers. + nextRoutineCallID uint64 isPrepareStatement bool mysqlCompatible bool @@ -619,13 +624,14 @@ type QueryBuilder struct { // returningFilterPos identifies an optional semantic eligibility selector in // the materialized row image. It filters only the RETURNING reader; mutation // readers continue to consume implicit FK action rows. - returningFilterPos int32 - returningRequested bool - returningTableDef *plan.TableDef - returningObjRef *plan.ObjectRef - returningTableName string - returningAlias string - returningColPos map[string]int32 + returningFilterPos int32 + returningRequested bool + bindingReturningProjection bool + returningTableDef *plan.TableDef + returningObjRef *plan.ObjectRef + returningTableName string + returningAlias string + returningColPos map[string]int32 // updateParentActionStack bounds recursive ON UPDATE actions by the active // physical-table path. Acyclic multi-layer cascades recurse normally; a // cycle is rejected before any mutation step is appended. diff --git a/pkg/sql/plan/utils.go b/pkg/sql/plan/utils.go index b31331f004fb7..c488adda7e02f 100644 --- a/pkg/sql/plan/utils.go +++ b/pkg/sql/plan/utils.go @@ -2068,6 +2068,11 @@ func constantFoldWithPreparedExactSource( if fn == nil || proc == nil { return expr, nil } + // Typed external routines are execute-time calls. Do not let statistics or + // binder-side folding execute or replace a captured FunctionRef/revision. + if fn.RoutineCall != nil { + return expr, nil + } overloadID := fn.Func.GetObj() functionID, _ := function.DecodeOverloadID(overloadID) diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 61bce709bbee7..f06920c8461d8 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -38,6 +38,12 @@ const ( // MaxControlBytes is a trust-boundary ceiling. A runtime may negotiate a // smaller limit, but a caller must never silently raise it. MaxControlBytes = 1 << 20 + + // MaxFenceComponentBytes bounds the identity retained by active and + // terminal ledgers. The wire envelope is larger than a single component, + // but allowing an unbounded statement/group/invocation string would make + // every bounded entry claim an unbounded memory claim. + MaxFenceComponentBytes = 256 ) var ( @@ -72,6 +78,9 @@ func (t FencingTuple) Validate() error { if !utf8.ValidString(t.StatementID) || !utf8.ValidString(t.GroupID) || !utf8.ValidString(t.InvocationID) { return fmt.Errorf("%w: fencing tuple contains invalid UTF-8", ErrProtocol) } + if len(t.StatementID) > MaxFenceComponentBytes || len(t.GroupID) > MaxFenceComponentBytes || len(t.InvocationID) > MaxFenceComponentBytes { + return fmt.Errorf("%w: fencing tuple component is too large", ErrProtocol) + } return nil } @@ -79,16 +88,19 @@ func (t FencingTuple) Validate() error { // app_metadata. Payload is a versioned descriptor or error body owned by the // message kind; it is bounded before JSON decoding. type Control struct { - Version int `json:"version"` - Kind string `json:"kind"` - Tuple FencingTuple `json:"tuple"` - Sequence uint64 `json:"sequence,omitempty"` - LastSequence uint64 `json:"last_sequence,omitempty"` - AckSequence uint64 `json:"ack_sequence,omitempty"` - FinishID string `json:"finish_id,omitempty"` - Status string `json:"status,omitempty"` - Reason string `json:"reason,omitempty"` - Payload json.RawMessage `json:"payload,omitempty"` + Version int `json:"version"` + Kind string `json:"kind"` + Tuple FencingTuple `json:"tuple"` + Sequence uint64 `json:"sequence,omitempty"` + LastSequence uint64 `json:"last_sequence,omitempty"` + AckSequence uint64 `json:"ack_sequence,omitempty"` + ReleasedBytes int64 `json:"released_bytes,omitempty"` + ReleasedBatches uint64 `json:"released_batches,omitempty"` + LastResultSequence uint64 `json:"last_result_sequence,omitempty"` + FinishID string `json:"finish_id,omitempty"` + Status string `json:"status,omitempty"` + Reason string `json:"reason,omitempty"` + Payload json.RawMessage `json:"payload,omitempty"` } type controlFieldRule struct { @@ -101,9 +113,9 @@ var controlFieldRules = map[string]controlFieldRule{ "InputBatch": {allowed: map[string]struct{}{"sequence": {}}, required: map[string]struct{}{"sequence": {}}}, "EndInput": {allowed: map[string]struct{}{"last_sequence": {}}, required: map[string]struct{}{"last_sequence": {}}}, "ResultSchema": {allowed: map[string]struct{}{}}, - "InputConsumed": {allowed: map[string]struct{}{"sequence": {}}, required: map[string]struct{}{"sequence": {}}}, + "InputConsumed": {allowed: map[string]struct{}{"sequence": {}, "released_bytes": {}, "released_batches": {}}, required: map[string]struct{}{"sequence": {}, "released_bytes": {}, "released_batches": {}}}, "ResultBatch": {allowed: map[string]struct{}{"sequence": {}}, required: map[string]struct{}{"sequence": {}}}, - "Finish": {allowed: map[string]struct{}{"last_sequence": {}, "finish_id": {}, "status": {}}, required: map[string]struct{}{"last_sequence": {}, "finish_id": {}, "status": {}}}, + "Finish": {allowed: map[string]struct{}{"last_sequence": {}, "last_result_sequence": {}, "finish_id": {}, "status": {}}, required: map[string]struct{}{"last_sequence": {}, "last_result_sequence": {}, "finish_id": {}, "status": {}}}, "AcknowledgeResults": {allowed: map[string]struct{}{"ack_sequence": {}}, required: map[string]struct{}{"ack_sequence": {}}}, "AcknowledgeFinish": {allowed: map[string]struct{}{"finish_id": {}}, required: map[string]struct{}{"finish_id": {}}}, "Ack": {allowed: map[string]struct{}{"ack_sequence": {}, "finish_id": {}, "status": {}}, required: map[string]struct{}{"status": {}}}, @@ -149,6 +161,21 @@ func validateControlFields(control Control, wire map[string]json.RawMessage) err return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "ack_sequence", control.Kind) } } + if control.ReleasedBytes != 0 { + if _, allowed := rule.allowed["released_bytes"]; !allowed { + return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "released_bytes", control.Kind) + } + } + if control.ReleasedBatches != 0 { + if _, allowed := rule.allowed["released_batches"]; !allowed { + return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "released_batches", control.Kind) + } + } + if control.LastResultSequence != 0 { + if _, allowed := rule.allowed["last_result_sequence"]; !allowed { + return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "last_result_sequence", control.Kind) + } + } if control.FinishID != "" { if _, allowed := rule.allowed["finish_id"]; !allowed { return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "finish_id", control.Kind) @@ -174,10 +201,14 @@ func validateControlFields(control Control, wire map[string]json.RawMessage) err if len(control.Payload) == 0 && wire == nil { return fmt.Errorf("%w: control kind %q is missing field %q", ErrProtocol, control.Kind, "payload") } - case "InputBatch", "InputConsumed", "ResultBatch": + case "InputBatch", "ResultBatch": if control.Sequence == 0 { return fmt.Errorf("%w: control kind %q requires a positive sequence", ErrProtocol, control.Kind) } + case "InputConsumed": + if control.Sequence == 0 || control.ReleasedBytes <= 0 || control.ReleasedBatches == 0 { + return fmt.Errorf("%w: control kind %q requires sequence and positive released bytes/batches", ErrProtocol, control.Kind) + } case "AcknowledgeResults": if control.AckSequence == 0 { return fmt.Errorf("%w: control kind %q requires a positive ack_sequence", ErrProtocol, control.Kind) @@ -209,16 +240,19 @@ func validateControlFields(control Control, wire map[string]json.RawMessage) err // omission used for fields they do not own. func (c Control) MarshalJSON() ([]byte, error) { type wireControl struct { - Version int `json:"version"` - Kind string `json:"kind"` - Tuple FencingTuple `json:"tuple"` - Sequence uint64 `json:"sequence,omitempty"` - LastSequence *uint64 `json:"last_sequence,omitempty"` - AckSequence uint64 `json:"ack_sequence,omitempty"` - FinishID string `json:"finish_id,omitempty"` - Status string `json:"status,omitempty"` - Reason string `json:"reason,omitempty"` - Payload json.RawMessage `json:"payload,omitempty"` + Version int `json:"version"` + Kind string `json:"kind"` + Tuple FencingTuple `json:"tuple"` + Sequence uint64 `json:"sequence,omitempty"` + LastSequence *uint64 `json:"last_sequence,omitempty"` + AckSequence uint64 `json:"ack_sequence,omitempty"` + ReleasedBytes *int64 `json:"released_bytes,omitempty"` + ReleasedBatches *uint64 `json:"released_batches,omitempty"` + LastResultSequence *uint64 `json:"last_result_sequence,omitempty"` + FinishID string `json:"finish_id,omitempty"` + Status string `json:"status,omitempty"` + Reason string `json:"reason,omitempty"` + Payload json.RawMessage `json:"payload,omitempty"` } wire := wireControl{ Version: c.Version, Kind: c.Kind, Tuple: c.Tuple, @@ -230,6 +264,16 @@ func (c Control) MarshalJSON() ([]byte, error) { lastSequence := c.LastSequence wire.LastSequence = &lastSequence } + if c.Kind == "Finish" { + lastResultSequence := c.LastResultSequence + wire.LastResultSequence = &lastResultSequence + } + if c.Kind == "InputConsumed" { + releasedBytes := c.ReleasedBytes + releasedBatches := c.ReleasedBatches + wire.ReleasedBytes = &releasedBytes + wire.ReleasedBatches = &releasedBatches + } return json.Marshal(wire) } @@ -546,6 +590,7 @@ const ( ReasonAllNull CloseReason = "ALL_NULL" ReasonNoSelectedRows CloseReason = "NO_SELECTED_ROWS" ReasonPartialOpenError CloseReason = "PARTIAL_OPEN_FAILURE" + ReasonFailure CloseReason = "FAILURE" ReasonCancel CloseReason = "CANCEL" ReasonIdle CloseReason = "IDLE" ) @@ -565,6 +610,8 @@ type ExecutionGroup struct { terminal map[string]bool closing bool releaseBusy bool + releaseDone chan struct{} + releaseErr error released bool release func() error reason CloseReason @@ -633,7 +680,7 @@ func (t *OpenToken) Commit() error { delete(g.pending, t.memberID) g.inFlight-- if g.closing || g.released { - release := g.canReleaseLocked() + release := g.shouldReleaseLocked() g.mu.Unlock() if release { return errors.Join(ErrGroupClosed, g.releaseIfReady()) @@ -657,7 +704,7 @@ func (t *OpenToken) Abort() error { g.mu.Lock() delete(g.pending, t.memberID) g.inFlight-- - release := g.canReleaseLocked() + release := g.shouldReleaseLocked() g.mu.Unlock() if release { return g.releaseIfReady() @@ -692,7 +739,7 @@ func (g *ExecutionGroup) Close(reason CloseReason) error { g.closing = true g.reason = reason } - release := g.canReleaseLocked() + release := g.shouldReleaseLocked() g.mu.Unlock() if release { return g.releaseIfReady() @@ -712,7 +759,7 @@ func (g *ExecutionGroup) MemberTerminal(memberID string) error { } delete(g.members, memberID) g.terminal[memberID] = true - release := g.canReleaseLocked() + release := g.shouldReleaseLocked() g.mu.Unlock() if release { return g.releaseIfReady() @@ -721,23 +768,51 @@ func (g *ExecutionGroup) MemberTerminal(memberID string) error { } func (g *ExecutionGroup) canReleaseLocked() bool { - return g.closing && len(g.members) == 0 && g.inFlight == 0 && !g.released && !g.releaseBusy + return g.shouldReleaseLocked() && !g.releaseBusy +} + +func (g *ExecutionGroup) shouldReleaseLocked() bool { + return g.closing && len(g.members) == 0 && g.inFlight == 0 && !g.released } func (g *ExecutionGroup) releaseIfReady() error { g.mu.Lock() - if !g.canReleaseLocked() { + if !g.shouldReleaseLocked() { g.mu.Unlock() return nil } + if g.releaseBusy { + done := g.releaseDone + g.mu.Unlock() + <-done + g.mu.Lock() + err := g.releaseErr + released := g.released + g.mu.Unlock() + if released { + return nil + } + return err + } g.releaseBusy = true + g.releaseDone = make(chan struct{}) + done := g.releaseDone g.mu.Unlock() - err := g.release() + err := func() (err error) { + defer func() { + if recovered := recover(); recovered != nil { + err = fmt.Errorf("%w: group release panicked: %v", ErrProtocol, recovered) + } + }() + return g.release() + }() g.mu.Lock() g.releaseBusy = false + g.releaseErr = err if err == nil { g.released = true } + close(done) g.mu.Unlock() return err } @@ -769,11 +844,33 @@ func (g *ExecutionGroup) Counts() (registered, active, inFlight int) { return g.registered, len(g.members), g.inFlight } +// ID and Epoch identify the ownership fence used by the group owner. They are +// immutable for the lifetime of an ExecutionGroup. +func (g *ExecutionGroup) ID() string { + if g == nil { + return "" + } + g.mu.Lock() + defer g.mu.Unlock() + return g.id +} + +func (g *ExecutionGroup) Epoch() uint64 { + if g == nil { + return 0 + } + g.mu.Lock() + defer g.mu.Unlock() + return g.epoch +} + type ledgerEntry struct { - key string - bytes int64 - expiresAt time.Time - tombstone bool + key string + groupID string + groupEpoch uint64 + bytes int64 + expiresAt time.Time + tombstone bool } // TerminalLedger is an admission-reserved bounded deduplication ledger. A @@ -791,6 +888,7 @@ type TerminalLedger struct { type LedgerCredit struct { ledger *TerminalLedger groupID string + groupEpoch uint64 remainingN int remainingB int64 closed bool @@ -803,8 +901,8 @@ func NewTerminalLedger(maxEntries int, maxBytes int64) (*TerminalLedger, error) return &TerminalLedger{maxEntries: maxEntries, maxBytes: maxBytes, entries: make(map[string]ledgerEntry)}, nil } -func (l *TerminalLedger) Reserve(groupID string, entries int, bytes int64) (*LedgerCredit, error) { - if groupID == "" || entries <= 0 || bytes <= 0 { +func (l *TerminalLedger) Reserve(groupID string, groupEpoch uint64, entries int, bytes int64) (*LedgerCredit, error) { + if groupID == "" || groupEpoch == 0 || entries <= 0 || bytes <= 0 { return nil, fmt.Errorf("%w: invalid terminal ledger reservation", ErrProtocol) } l.mu.Lock() @@ -814,7 +912,7 @@ func (l *TerminalLedger) Reserve(groupID string, entries int, bytes int64) (*Led } l.reservedN += entries l.reservedB += bytes - return &LedgerCredit{ledger: l, groupID: groupID, remainingN: entries, remainingB: bytes}, nil + return &LedgerCredit{ledger: l, groupID: groupID, groupEpoch: groupEpoch, remainingN: entries, remainingB: bytes}, nil } func (c *LedgerCredit) Add(key string, bytes int64, expiry time.Time) error { @@ -829,7 +927,7 @@ func (c *LedgerCredit) Add(key string, bytes int64, expiry time.Time) error { if _, exists := c.ledger.entries[key]; exists { return ErrDuplicate } - c.ledger.entries[key] = ledgerEntry{key: key, bytes: bytes, expiresAt: expiry} + c.ledger.entries[key] = ledgerEntry{key: key, groupID: c.groupID, groupEpoch: c.groupEpoch, bytes: bytes, expiresAt: expiry} c.remainingN-- c.remainingB -= bytes return nil @@ -866,7 +964,14 @@ func (l *TerminalLedger) Complete(key string) error { return nil } -func (l *TerminalLedger) Expire(now time.Time) int { +// EpochFence is supplied by the Scheduler/group owner. It must return true +// only after the owner has durably or monotonically closed the corresponding +// group epoch so that an old grant cannot be issued again. A wall clock TTL is +// deliberately insufficient proof and a nil fence therefore reclaims nothing. +// The callback must not call back into the ledger. +type EpochFence func(groupID string, groupEpoch uint64) bool + +func (l *TerminalLedger) Expire(now time.Time, fence EpochFence) int { l.mu.Lock() defer l.mu.Unlock() removed := 0 @@ -878,7 +983,7 @@ func (l *TerminalLedger) Expire(now time.Time) int { if !entry.tombstone { continue } - if !now.Before(entry.expiresAt) { + if !now.Before(entry.expiresAt) && fence != nil && fence(entry.groupID, entry.groupEpoch) { delete(l.entries, key) l.reservedN-- l.reservedB -= entry.bytes diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index f22aaa2d3073e..1eeee14913a0f 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -18,6 +18,7 @@ import ( "bytes" "encoding/json" "errors" + "sync" "sync/atomic" "testing" "time" @@ -96,6 +97,7 @@ func TestClosingControlCarriesZeroLastSequence(t *testing.T) { if kind == "Finish" { control.Status = "OK" control.FinishID = "finish" + control.LastResultSequence = 0 } wire, err := MarshalControl(control) require.NoError(t, err) @@ -118,6 +120,32 @@ func TestClosingControlCarriesZeroLastSequence(t *testing.T) { require.False(t, ok, "non-closing controls should not grow a closing-only field") } +func TestInputConsumedCarriesReleaseCredit(t *testing.T) { + control := Control{ + Kind: "InputConsumed", + Tuple: testTuple(), + Sequence: 2, + ReleasedBytes: 128, + ReleasedBatches: 1, + } + wire, err := MarshalControl(control) + require.NoError(t, err) + decoded, err := UnmarshalControl(wire) + require.NoError(t, err) + require.Equal(t, int64(128), decoded.ReleasedBytes) + require.Equal(t, uint64(1), decoded.ReleasedBatches) + + var object map[string]any + require.NoError(t, json.Unmarshal(wire, &object)) + require.Equal(t, float64(128), object["released_bytes"]) + require.Equal(t, float64(1), object["released_batches"]) + delete(object, "released_batches") + invalid, err := json.Marshal(object) + require.NoError(t, err) + _, err = UnmarshalControl(invalid) + require.ErrorIs(t, err, ErrProtocol) +} + func TestSystemAccountIsValidFencingIdentity(t *testing.T) { tuple := testTuple() tuple.AccountID = 0 @@ -134,6 +162,14 @@ func TestFencingTupleRejectsInvalidUTF8(t *testing.T) { require.ErrorContains(t, err, "invalid UTF-8") } +func TestFencingTupleRejectsUnboundedIdentityComponents(t *testing.T) { + tuple := testTuple() + tuple.GroupID = string(bytes.Repeat([]byte{'g'}, MaxFenceComponentBytes+1)) + require.ErrorContains(t, tuple.Validate(), "component is too large") + _, err := MarshalControl(Control{Kind: "OpenInvocation", Tuple: tuple, Payload: []byte(`{}`)}) + require.ErrorContains(t, err, "component is too large") +} + func TestUnmarshalControlRejectsInvalidWireUTF8(t *testing.T) { wire := []byte(`{"version":1,"kind":"InputBatch","tuple":{"account_id":1,"statement_id":"`) wire = append(wire, 0xff) @@ -286,25 +322,28 @@ func TestTerminalLedgerRetainsTombstonesUntilExpiry(t *testing.T) { ledger, err := NewTerminalLedger(2, 200) require.NoError(t, err) now := time.Unix(100, 0) - credit, err := ledger.Reserve("g1", 1, 100) + credit, err := ledger.Reserve("g1", 1, 1, 100) require.NoError(t, err) require.NoError(t, credit.Add("i1", 100, now.Add(time.Hour))) require.NoError(t, ledger.Complete("i1")) credit.ReleaseUnused() - second, err := ledger.Reserve("g2", 1, 100) + second, err := ledger.Reserve("g2", 1, 1, 100) require.NoError(t, err) require.NoError(t, second.Add("i2", 100, now.Add(time.Hour))) require.NoError(t, ledger.Complete("i2")) second.ReleaseUnused() - _, err = ledger.Reserve("g3", 1, 1) + _, err = ledger.Reserve("g3", 1, 1, 1) require.ErrorIs(t, err, ErrLedgerFull) require.Equal(t, 2, func() int { n, _ := ledger.Counts(); return n }()) - require.Equal(t, 0, ledger.Expire(now.Add(time.Minute))) + require.Equal(t, 0, ledger.Expire(now.Add(time.Minute), func(string, uint64) bool { return true })) require.Equal(t, 2, func() int { n, _ := ledger.Counts(); return n }()) - require.Equal(t, 2, ledger.Expire(now.Add(2*time.Hour))) - third, err := ledger.Reserve("g3", 1, 1) + require.Equal(t, 0, ledger.Expire(now.Add(2*time.Hour), nil), "TTL must not advance the ownership epoch") + require.Equal(t, 2, ledger.Expire(now.Add(2*time.Hour), func(groupID string, groupEpoch uint64) bool { + return groupID == "g1" && groupEpoch == 1 || groupID == "g2" && groupEpoch == 1 + })) + third, err := ledger.Reserve("g3", 1, 1, 1) require.NoError(t, err) require.NoError(t, third.Add("i3", 1, now.Add(3*time.Hour))) @@ -317,15 +356,15 @@ func TestTerminalLedgerDoesNotExpireActiveEntries(t *testing.T) { ledger, err := NewTerminalLedger(1, 100) require.NoError(t, err) now := time.Unix(100, 0) - credit, err := ledger.Reserve("g", 1, 100) + credit, err := ledger.Reserve("g", 1, 1, 100) require.NoError(t, err) require.NoError(t, credit.Add("active", 100, now.Add(time.Second))) credit.ReleaseUnused() - require.Equal(t, 0, ledger.Expire(now.Add(time.Hour))) + require.Equal(t, 0, ledger.Expire(now.Add(time.Hour), func(string, uint64) bool { return true })) entries, bytes := ledger.Counts() require.Equal(t, 1, entries) require.Equal(t, int64(100), bytes) - _, err = ledger.Reserve("other", 1, 1) + _, err = ledger.Reserve("other", 1, 1, 1) require.ErrorIs(t, err, ErrLedgerFull) require.NoError(t, ledger.Abandon("active")) entries, bytes = ledger.Counts() @@ -350,6 +389,32 @@ func TestExecutionGroupReleaseErrorCanBeRetried(t *testing.T) { require.Equal(t, int32(2), attempts.Load()) } +func TestExecutionGroupConcurrentReleaseWaitersObserveTheSameFailure(t *testing.T) { + releaseStarted := make(chan struct{}) + releaseContinue := make(chan struct{}) + var releaseStartOnce sync.Once + group, err := NewExecutionGroup("concurrent", 1, 1, func() error { + releaseStartOnce.Do(func() { close(releaseStarted) }) + <-releaseContinue + return errors.New("temporary concurrent release failure") + }) + require.NoError(t, err) + member, err := group.BeginOpen("member") + require.NoError(t, err) + require.NoError(t, member.Commit()) + require.NoError(t, group.Close(ReasonCancel)) + + firstDone := make(chan error, 1) + go func() { firstDone <- group.MemberTerminal("member") }() + <-releaseStarted + secondDone := make(chan error, 1) + go func() { secondDone <- group.Close(ReasonCancel) }() + close(releaseContinue) + require.ErrorContains(t, <-firstDone, "temporary concurrent release failure") + require.ErrorContains(t, <-secondDone, "temporary concurrent release failure") + require.Equal(t, GroupDraining, group.State()) +} + func TestExecutionGroupCommitReportsReleaseFailure(t *testing.T) { var attempts atomic.Int32 group, err := NewExecutionGroup("g", 1, 1, func() error { diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 7d4b14dc8a08a..38e48df652361 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -59,7 +59,33 @@ type TypeDescriptor struct { } func NewTypeDescriptor(typ types.Type) (TypeDescriptor, error) { - d := TypeDescriptor{TypeID: int32(typ.Oid), Width: typ.Width, Scale: typ.Scale, Charset: typ.Charset, OffsetWidth: 32} + // Planner types use scale=-1 as the sentinel for types whose SQL + // definition has no scale (for example INT and BINARY). That sentinel is + // an internal planner representation and cannot cross the Python ABI: + // descriptors are canonical and use zero for every non-applicable field. + // Likewise, display widths on numeric types are not part of their value + // contract. Normalize those fields here so SQL planner metadata and the + // persisted/Arrow descriptor have one stable representation. + width := typ.Width + scale := typ.Scale + switch typ.Oid { + case types.T_decimal64, types.T_decimal128: + if scale < 0 { + scale = 0 + } + case types.T_time, types.T_datetime, types.T_timestamp: + width = 0 + if scale < 0 { + scale = 0 + } + case types.T_char, types.T_varchar, types.T_binary, types.T_varbinary, + types.T_array_float32, types.T_array_float64: + scale = 0 + default: + width = 0 + scale = 0 + } + d := TypeDescriptor{TypeID: int32(typ.Oid), Width: width, Scale: scale, Charset: typ.Charset, OffsetWidth: 32} switch typ.Oid { case types.T_json: d.JSONEncoding = "canonical_text" @@ -139,9 +165,15 @@ func (d TypeDescriptor) Validate() error { if d.JSONEncoding != "" && (oid != types.T_json || d.JSONEncoding != "canonical_text") { return fmt.Errorf("TYPE_CONTRACT: unsupported JSON encoding") } + if oid == types.T_json && d.JSONEncoding != "canonical_text" { + return fmt.Errorf("TYPE_CONTRACT: JSON descriptor must use canonical_text encoding") + } if d.TemporalEncoding != "" && (oid != types.T_date && oid != types.T_datetime && oid != types.T_timestamp || d.TemporalEncoding != "sql_zero_struct") { return fmt.Errorf("TYPE_CONTRACT: unsupported temporal encoding") } + if (oid == types.T_date || oid == types.T_datetime || oid == types.T_timestamp) && d.TemporalEncoding != "sql_zero_struct" { + return fmt.Errorf("TYPE_CONTRACT: temporal descriptor must use sql_zero_struct encoding") + } switch oid { case types.T_bool, types.T_int8, types.T_int16, types.T_int32, types.T_int64, @@ -525,7 +557,11 @@ func appendInputValue(builder array.Builder, v *vector.Vector, typ types.Type, s p := vector.GenerateFunctionStrParameter(v) value, _ := p.GetStrValue(uint64(index)) if typ.Oid == types.T_json { - value = []byte(types.DecodeJson(value).String()) + canonical, err := canonicalJSONInput(value) + if err != nil { + return err + } + value = canonical } b.Append(string(value)) } @@ -567,6 +603,21 @@ func appendInputValue(builder array.Builder, v *vector.Vector, typ types.Type, s } return nil } + +// canonicalJSONInput converts MatrixOne's binary JSON rendering into the +// compact UTF-8 text required by the Python ABI. ByteJson.String is intended +// for SQL display and includes object/array whitespace; passing it directly +// would make a valid object fail the worker's canonical-text check even +// though scalar JSON values happen to work. +func canonicalJSONInput(value []byte) ([]byte, error) { + text := []byte(types.DecodeJson(value).String()) + var compact bytes.Buffer + if err := json.Compact(&compact, text); err != nil { + return nil, fmt.Errorf("TYPE_CONTRACT: invalid JSON input: %w", err) + } + return compact.Bytes(), nil +} + func appendTemporalInput(builder *array.StructBuilder, v *vector.Vector, typ types.Type, index int, null bool) error { zero := false var raw int64 diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index c4b9c5b01570d..0caea06d05b05 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -7,7 +7,9 @@ package python import ( "encoding/binary" + "encoding/json" "math" + "os" "testing" "github.com/apache/arrow-go/v18/arrow" @@ -182,7 +184,10 @@ func TestTypeDescriptorRejectsNonCanonicalDomain(t *testing.T) { invalid := []TypeDescriptor{ {TypeID: int32(types.T_varchar), Width: -1, OffsetWidth: 32}, {TypeID: int32(types.T_int64), OffsetWidth: 64}, + {TypeID: int32(types.T_int64)}, {TypeID: int32(types.T_decimal64), Width: 3, Scale: 4, OffsetWidth: 32}, + {TypeID: int32(types.T_json), OffsetWidth: 32}, + {TypeID: int32(types.T_date), OffsetWidth: 32}, {TypeID: int32(types.T_array_float32), Width: types.MaxArrayDimension + 1}, } for _, descriptor := range invalid { @@ -191,6 +196,274 @@ func TestTypeDescriptorRejectsNonCanonicalDomain(t *testing.T) { } } +func TestFloatDescriptorsRoundTripThroughArrowFieldContract(t *testing.T) { + for _, typ := range []types.T{types.T_float32, types.T_float64} { + descriptor, err := NewTypeDescriptor(typ.ToType()) + require.NoError(t, err) + field, err := descriptor.Field("value") + require.NoError(t, err) + require.NoError(t, descriptor.ValidateField(field)) + require.Equal(t, typ, types.T(descriptor.TypeID)) + } +} + +func TestNewTypeDescriptorNormalizesPlannerOnlySentinels(t *testing.T) { + integer := types.T_int32.ToTypeWithScale(-1) + integer.Width = 32 + descriptor, err := NewTypeDescriptor(integer) + require.NoError(t, err) + require.Equal(t, int32(0), descriptor.Width) + require.Equal(t, int32(0), descriptor.Scale) + + binaryType := types.T_binary.ToTypeWithScale(-1) + binaryType.Width = 8 + descriptor, err = NewTypeDescriptor(binaryType) + require.NoError(t, err) + require.Equal(t, int32(8), descriptor.Width) + require.Equal(t, int32(0), descriptor.Scale) + + temporal := types.T_datetime.ToTypeWithScale(-1) + descriptor, err = NewTypeDescriptor(temporal) + require.NoError(t, err) + require.Equal(t, int32(0), descriptor.Width) + require.Equal(t, int32(0), descriptor.Scale) +} + +func TestBuildInputRecordCanonicalizesJSONText(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + input := vector.NewVec(types.T_json.ToType()) + defer input.Free(mp) + bj, err := types.ParseStringToByteJson(`{"a":1,"b":[true,null,"中"]}`) + require.NoError(t, err) + raw, err := bj.Marshal() + require.NoError(t, err) + require.NoError(t, vector.AppendBytes(input, raw, false, mp)) + + record, _, err := BuildInputRecord([]*vector.Vector{input}, []types.Type{types.T_json.ToType()}, 1) + require.NoError(t, err) + defer record.Release() + values := record.Column(0).(*array.String) + require.Equal(t, `{"a":1,"b":[true,null,"中"]}`, values.Value(0)) +} + +func TestGoPythonTypeDescriptorFixtures(t *testing.T) { + data, err := os.ReadFile("testdata/type_descriptors.json") + require.NoError(t, err) + var fixtures []struct { + Name string `json:"name"` + Descriptor TypeDescriptor `json:"descriptor"` + Fingerprint string `json:"fingerprint"` + } + require.NoError(t, json.Unmarshal(data, &fixtures)) + require.NotEmpty(t, fixtures) + for _, fixture := range fixtures { + require.NoError(t, fixture.Descriptor.Validate(), fixture.Name) + fingerprint, err := fixture.Descriptor.Fingerprint() + require.NoError(t, err, fixture.Name) + require.Equal(t, fixture.Fingerprint, fingerprint, fixture.Name) + field, err := fixture.Descriptor.Field("value") + require.NoError(t, err, fixture.Name) + require.NoError(t, fixture.Descriptor.ValidateField(field), fixture.Name) + } +} + +func TestBuildInputRecordCoversEverySupportedType(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + + jsonValue, err := types.ParseStringToByteJson(`{"a":1,"b":[true,null]}`) + require.NoError(t, err) + jsonBytes, err := jsonValue.Marshal() + require.NoError(t, err) + + cases := []struct { + name string + typ types.Type + append func(*vector.Vector) error + }{ + {"bool", types.T_bool.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, true, false, mp); err != nil { + return err + } + return vector.AppendFixed(v, false, true, mp) + }}, + {"int8", types.T_int8.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, int8(-1), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, int8(0), true, mp) + }}, + {"int16", types.T_int16.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, int16(-1), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, int16(0), true, mp) + }}, + {"int32", types.T_int32.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, int32(-1), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, int32(0), true, mp) + }}, + {"int64", types.T_int64.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, int64(-1), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, int64(0), true, mp) + }}, + {"uint8", types.T_uint8.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, uint8(1), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, uint8(0), true, mp) + }}, + {"uint16", types.T_uint16.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, uint16(1), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, uint16(0), true, mp) + }}, + {"uint32", types.T_uint32.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, uint32(1), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, uint32(0), true, mp) + }}, + {"uint64", types.T_uint64.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, uint64(1), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, uint64(0), true, mp) + }}, + {"float32", types.T_float32.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, float32(1.25), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, float32(0), true, mp) + }}, + {"float64", types.T_float64.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, float64(1.25), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, float64(0), true, mp) + }}, + {"decimal64", types.New(types.T_decimal64, 18, 6), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, types.Decimal64(123456), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, types.Decimal64(0), true, mp) + }}, + {"decimal128", types.New(types.T_decimal128, 38, 10), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, types.Decimal128{B0_63: 123456}, false, mp); err != nil { + return err + } + return vector.AppendFixed(v, types.Decimal128{}, true, mp) + }}, + {"date", types.T_date.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, types.Date(1), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, types.Date(0), true, mp) + }}, + {"time", types.New(types.T_time, 0, 6), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, types.Time(123456), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, types.Time(0), true, mp) + }}, + {"datetime", types.New(types.T_datetime, 0, 6), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, types.Datetime(types.GetUnixEpochSecs()+1), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, types.Datetime(0), true, mp) + }}, + {"timestamp", types.New(types.T_timestamp, 0, 6), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, types.Timestamp(types.GetUnixEpochSecs()+1), false, mp); err != nil { + return err + } + return vector.AppendFixed(v, types.Timestamp(0), true, mp) + }}, + {"char", types.New(types.T_char, 16, 0), func(v *vector.Vector) error { + if err := vector.AppendBytes(v, []byte("中"), false, mp); err != nil { + return err + } + return vector.AppendBytes(v, nil, true, mp) + }}, + {"varchar", types.New(types.T_varchar, 64, 0), func(v *vector.Vector) error { + if err := vector.AppendBytes(v, []byte("matrixone"), false, mp); err != nil { + return err + } + return vector.AppendBytes(v, nil, true, mp) + }}, + {"text", types.T_text.ToType(), func(v *vector.Vector) error { + if err := vector.AppendBytes(v, []byte("matrixone"), false, mp); err != nil { + return err + } + return vector.AppendBytes(v, nil, true, mp) + }}, + {"json", types.T_json.ToType(), func(v *vector.Vector) error { + if err := vector.AppendBytes(v, jsonBytes, false, mp); err != nil { + return err + } + return vector.AppendBytes(v, nil, true, mp) + }}, + {"binary", types.New(types.T_binary, 8, 0), func(v *vector.Vector) error { + if err := vector.AppendBytes(v, []byte{1, 2}, false, mp); err != nil { + return err + } + return vector.AppendBytes(v, nil, true, mp) + }}, + {"varbinary", types.New(types.T_varbinary, 8, 0), func(v *vector.Vector) error { + if err := vector.AppendBytes(v, []byte{1, 2}, false, mp); err != nil { + return err + } + return vector.AppendBytes(v, nil, true, mp) + }}, + {"blob", types.T_blob.ToType(), func(v *vector.Vector) error { + if err := vector.AppendBytes(v, []byte{1, 2}, false, mp); err != nil { + return err + } + return vector.AppendBytes(v, nil, true, mp) + }}, + {"uuid", types.T_uuid.ToType(), func(v *vector.Vector) error { + if err := vector.AppendFixed(v, types.Uuid{1, 2, 3}, false, mp); err != nil { + return err + } + return vector.AppendFixed(v, types.Uuid{}, true, mp) + }}, + {"vecf32", types.New(types.T_array_float32, 3, 0), func(v *vector.Vector) error { + if err := vector.AppendArray(v, []float32{1, 2, 3}, false, mp); err != nil { + return err + } + return vector.AppendArray[float32](v, nil, true, mp) + }}, + {"vecf64", types.New(types.T_array_float64, 3, 0), func(v *vector.Vector) error { + if err := vector.AppendArray(v, []float64{1, 2, 3}, false, mp); err != nil { + return err + } + return vector.AppendArray[float64](v, nil, true, mp) + }}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + input := vector.NewVec(tc.typ) + require.NoError(t, tc.append(input)) + record, _, err := BuildInputRecord([]*vector.Vector{input}, []types.Type{tc.typ}, 2) + require.NoError(t, err) + defer record.Release() + input.Free(mp) + + descriptor, err := NewTypeDescriptor(tc.typ) + require.NoError(t, err) + require.NoError(t, descriptor.ValidateField(record.Schema().Field(0))) + require.Equal(t, int64(2), record.NumRows()) + require.False(t, record.Column(0).IsNull(0)) + require.True(t, record.Column(0).IsNull(1)) + }) + } +} + func TestArrowValueDomainRejectsDecimalOverflowAndNullableVectorChild(t *testing.T) { decimalType := &arrow.Decimal128Type{Precision: 3, Scale: 0} decimalBuilder := array.NewDecimal128Builder(memory.NewGoAllocator(), decimalType) diff --git a/pkg/udf/python/artifact.go b/pkg/udf/python/artifact.go new file mode 100644 index 0000000000000..957eff9deccaf --- /dev/null +++ b/pkg/udf/python/artifact.go @@ -0,0 +1,190 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package python + +import ( + "context" + "fmt" + "strings" + "unicode/utf8" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/fileservice" + "github.com/matrixorigin/matrixone/pkg/udf" +) + +// DefaultMaxArtifactBytes bounds the inline source bundle used by the current +// Python contract. The bound is applied before a write and before a read, so a +// corrupt or malicious object cannot turn an artifact lookup into an +// unbounded allocation. +const DefaultMaxArtifactBytes int64 = 1 << 20 + +// ArtifactResolver supplies the immutable source bytes for an exact catalog +// artifact reference. The resolver is deliberately keyed by account and +// digest: a digest alone must not become a cross-account capability. +type ArtifactResolver interface { + Resolve(ctx context.Context, accountID uint64, handler, digest string) (string, error) +} + +// ArtifactPublisher publishes an immutable artifact before its catalog +// revision becomes visible. Implementations must make a digest collision or a +// corrupt pre-existing object an error; replacing an object at the same path +// would break old plans that still reference that digest. +type ArtifactPublisher interface { + Publish(ctx context.Context, accountID uint64, handler, source string) (string, error) +} + +// ArtifactStore is the current FileService-backed artifact implementation. +// Resolver and publisher are separate interfaces so execution only needs read +// capability and cannot accidentally publish from the hot path. +type ArtifactStore interface { + ArtifactResolver + ArtifactPublisher +} + +// FileArtifactStore stores content addressed inline source under the shared +// FileService. The account component is part of the object path even though +// the content digest is global, preventing one account from using another +// account's artifact as an execution capability. +type FileArtifactStore struct { + fs fileservice.FileService + maxSize int64 +} + +var _ ArtifactStore = (*FileArtifactStore)(nil) + +func NewFileArtifactStore(fs fileservice.FileService, maxSize int64) (*FileArtifactStore, error) { + if fs == nil { + return nil, fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact store has no FileService") + } + shared, err := fileservice.Get[fileservice.FileService](fs, defines.SharedFileServiceName) + if err != nil { + return nil, fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact store has no shared FileService: %w", err) + } + if maxSize <= 0 { + maxSize = DefaultMaxArtifactBytes + } + return &FileArtifactStore{fs: shared, maxSize: maxSize}, nil +} + +func (s *FileArtifactStore) Publish(ctx context.Context, accountID uint64, handler, source string) (string, error) { + if err := s.validate(); err != nil { + return "", err + } + if ctx == nil { + ctx = context.Background() + } + digest, err := validateArtifactInput(accountID, handler, source, s.maxSize) + if err != nil { + return "", err + } + path := artifactPath(accountID, digest) + data := []byte(source) + // FileService implementations may retain the caller's IOEntry until the + // write returns. Give the store its own immutable backing so later caller + // mutation cannot alter the bytes whose digest is being published. + owned := append([]byte(nil), data...) + err = s.fs.Write(ctx, fileservice.IOVector{ + FilePath: path, + Entries: []fileservice.IOEntry{{Offset: 0, Size: int64(len(owned)), Data: owned}}, + }) + if err == nil { + return digest, nil + } + if !moerr.IsMoErrCode(err, moerr.ErrFileAlreadyExists) { + return "", fmt.Errorf("python artifact publish %s: %w", digest, err) + } + // A concurrent or retrying publisher is successful only after reading and + // validating the existing object. This closes the write-once collision + // boundary instead of treating path existence as proof of content identity. + existing, resolveErr := s.Resolve(ctx, accountID, handler, digest) + if resolveErr != nil { + return "", fmt.Errorf("python artifact publish %s found an invalid existing object: %w", digest, resolveErr) + } + if existing != source { + return "", fmt.Errorf("python artifact publish %s encountered a digest collision", digest) + } + return digest, nil +} + +func (s *FileArtifactStore) Resolve(ctx context.Context, accountID uint64, handler, digest string) (string, error) { + if err := s.validate(); err != nil { + return "", err + } + if ctx == nil { + ctx = context.Background() + } + if strings.TrimSpace(handler) == "" { + return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact has no handler") + } + if !udf.IsSHA256Digest(digest) { + return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest is invalid") + } + path := artifactPath(accountID, digest) + entry, err := s.fs.StatFile(ctx, path) + if err != nil { + return "", fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact %s is unavailable: %w", digest, err) + } + if entry == nil || entry.IsDir || entry.Size <= 0 || entry.Size > s.maxSize { + return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s has invalid size", digest) + } + data := make([]byte, entry.Size) + readVector := &fileservice.IOVector{ + FilePath: path, + Entries: []fileservice.IOEntry{{Offset: 0, Size: entry.Size, Data: data}}, + } + if err := s.fs.Read(ctx, readVector); err != nil { + return "", fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact %s cannot be read: %w", digest, err) + } + if len(readVector.Entries) != 1 || int64(len(readVector.Entries[0].Data)) != entry.Size { + return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s changed size while reading", digest) + } + source := string(readVector.Entries[0].Data) + if !utf8.ValidString(source) { + return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s is not valid UTF-8", digest) + } + if udf.PythonInlineArtifactDigest(handler, source) != digest { + return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s content digest mismatch", digest) + } + return source, nil +} + +func validateArtifactInput(accountID uint64, handler, source string, maxSize int64) (string, error) { + if maxSize <= 0 { + return "", fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact store has an invalid size limit") + } + if strings.TrimSpace(handler) == "" { + return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact has no handler") + } + if source == "" { + return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is empty") + } + if !utf8.ValidString(source) { + return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is not valid UTF-8") + } + if int64(len([]byte(source))) > maxSize { + return "", fmt.Errorf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", maxSize) + } + return udf.PythonInlineArtifactDigest(handler, source), nil +} + +func (s *FileArtifactStore) validate() error { + if s == nil || s.fs == nil { + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact store has no FileService") + } + if s.maxSize <= 0 { + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact store has an invalid size limit") + } + return nil +} + +func artifactPath(accountID uint64, digest string) string { + return fileservice.JoinPath( + defines.SharedFileServiceName, + fmt.Sprintf("udf-artifacts/%d/%s", accountID, digest), + ) +} diff --git a/pkg/udf/python/artifact_test.go b/pkg/udf/python/artifact_test.go new file mode 100644 index 0000000000000..cc617f68f52ec --- /dev/null +++ b/pkg/udf/python/artifact_test.go @@ -0,0 +1,97 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package python + +import ( + "context" + "strings" + "testing" + + "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/fileservice" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/stretchr/testify/require" +) + +func newTestArtifactStore(t *testing.T, maxSize int64) *FileArtifactStore { + t.Helper() + fs, err := fileservice.NewMemoryFS(defines.SharedFileServiceName, fileservice.DisabledCacheConfig, nil) + require.NoError(t, err) + store, err := NewFileArtifactStore(fs, maxSize) + require.NoError(t, err) + return store +} + +func TestFileArtifactStorePublishesAndResolvesByAccount(t *testing.T) { + store := newTestArtifactStore(t, DefaultMaxArtifactBytes) + ctx := context.Background() + source := "def add(ctx, value):\n return value + 1\n" + digest := udf.PythonInlineArtifactDigest("add", source) + + published, err := store.Publish(ctx, 7, "add", source) + require.NoError(t, err) + require.Equal(t, digest, published) + resolved, err := store.Resolve(ctx, 7, "add", digest) + require.NoError(t, err) + require.Equal(t, source, resolved) + + _, err = store.Resolve(ctx, 8, "add", digest) + require.ErrorContains(t, err, "unavailable") + second, err := store.Publish(ctx, 7, "add", source) + require.NoError(t, err) + require.Equal(t, digest, second, "republication of the exact immutable object is idempotent") +} + +func TestFileArtifactStoreRejectsCorruptionAndDigestCollision(t *testing.T) { + store := newTestArtifactStore(t, DefaultMaxArtifactBytes) + ctx := context.Background() + source := "def add(ctx, value): return value + 1" + digest := udf.PythonInlineArtifactDigest("add", source) + + path := artifactPath(7, digest) + err := store.fs.Write(ctx, fileservice.IOVector{ + FilePath: path, + Entries: []fileservice.IOEntry{{Offset: 0, Size: int64(len("corrupt")), Data: []byte("corrupt")}}, + }) + require.NoError(t, err) + _, err = store.Resolve(ctx, 7, "add", digest) + require.ErrorContains(t, err, "content digest mismatch") + _, err = store.Publish(ctx, 7, "add", source) + require.ErrorContains(t, err, "invalid existing object") +} + +func TestFileArtifactStoreRejectsOversizedSourceBeforeWrite(t *testing.T) { + store := newTestArtifactStore(t, 4) + _, err := store.Publish(context.Background(), 7, "add", "12345") + require.ErrorContains(t, err, "exceeds 4 bytes") + _, statErr := store.fs.StatFile(context.Background(), artifactPath(7, udf.PythonInlineArtifactDigest("add", "12345"))) + require.Error(t, statErr) +} + +func TestNewFileArtifactStoreRequiresSharedFileService(t *testing.T) { + local, err := fileservice.NewMemoryFS("LOCAL", fileservice.DisabledCacheConfig, nil) + require.NoError(t, err) + _, err = NewFileArtifactStore(local, 0) + require.ErrorContains(t, err, "shared FileService") +} + +func TestFileArtifactStoreRejectsInvalidDirectConstruction(t *testing.T) { + var nilStore *FileArtifactStore + _, err := nilStore.Publish(context.Background(), 7, "add", "source") + require.ErrorContains(t, err, "no FileService") + _, err = nilStore.Resolve(context.Background(), 7, "add", strings.Repeat("a", 64)) + require.ErrorContains(t, err, "no FileService") + + store := &FileArtifactStore{} + _, err = store.Publish(context.Background(), 7, "add", "source") + require.ErrorContains(t, err, "no FileService") +} + +func TestFileArtifactStoreRejectsInvalidUTF8(t *testing.T) { + store := newTestArtifactStore(t, DefaultMaxArtifactBytes) + _, err := store.Publish(context.Background(), 7, "add", string([]byte{'\xff'})) + require.ErrorContains(t, err, "not valid UTF-8") +} diff --git a/pkg/udf/python/config.go b/pkg/udf/python/config.go index 13ccc64588969..a5de9d35dcefa 100644 --- a/pkg/udf/python/config.go +++ b/pkg/udf/python/config.go @@ -36,12 +36,32 @@ type ClientConfig struct { // Enabled is deliberately false by default. The Python worker is an // unisolated development adapter until the production sandbox contract is // deployed, so a generic CN launch must never attach it implicitly. - Enabled bool `toml:"enabled"` - AllowUnisolated bool `toml:"allow-unisolated"` - ServerAddress string `toml:"server-address"` - MaxBatchBytes int64 `toml:"max-batch-bytes"` - MaxBatchRows int64 `toml:"max-batch-rows"` - RequestTimeout time.Duration `toml:"request-timeout"` + Enabled bool `toml:"enabled"` + AllowUnisolated bool `toml:"allow-unisolated"` + ServerAddress string `toml:"server-address"` + MaxBatchBytes int64 `toml:"max-batch-bytes"` + MaxBatchRows int64 `toml:"max-batch-rows"` + // MaxInvocationRows bounds the rows retained by one physical invocation. + // It is checked before OpenInvocation so a large request cannot reserve a + // worker or run user code before the CN has accepted its result shape. + MaxInvocationRows int64 `toml:"max-invocation-rows"` + // MaxInvocationResultBytes bounds the retained MO result vector for one + // invocation. Arrow frames remain subject to MaxBatchBytes; this separate + // limit prevents many individually valid batches from accumulating an + // unbounded result in the Gateway. + MaxInvocationResultBytes int64 `toml:"max-invocation-result-bytes"` + // MaxActiveInvocations is K: a CN refuses a new physical invocation when + // all slots are in use. It deliberately does not queue, because queued + // execution would retain the caller's input vectors and their allocation + // accounts while waiting for a worker slot. + MaxActiveInvocations int `toml:"max-active-invocations"` + RequestTimeout time.Duration `toml:"request-timeout"` + // Terminal limits cover both active and retained completion tombstones. + // They are reserved before an invocation is sent, so a long stream of + // short calls cannot grow the deduplication ledger without bound. + MaxTerminalEntries int `toml:"max-terminal-entries"` + MaxTerminalBytes int64 `toml:"max-terminal-bytes"` + TerminalRecordTTL time.Duration `toml:"terminal-record-ttl"` } func (c *ClientConfig) Validate() error { @@ -60,8 +80,26 @@ func (c *ClientConfig) Validate() error { if c.MaxBatchRows < 0 || c.MaxBatchRows > 1<<30 { return moerr.NewInternalError(context.Background(), "invalid python udf max batch rows") } + if c.MaxInvocationRows < 0 || c.MaxInvocationRows > 1<<32 { + return moerr.NewInternalError(context.Background(), "invalid python udf max invocation rows") + } + if c.MaxInvocationResultBytes < 0 || c.MaxInvocationResultBytes > 1<<40 { + return moerr.NewInternalError(context.Background(), "invalid python udf max invocation result bytes") + } + if c.MaxActiveInvocations < 0 || c.MaxActiveInvocations > 1<<20 { + return moerr.NewInternalError(context.Background(), "invalid python udf max active invocations") + } if c.RequestTimeout < 0 { return moerr.NewInternalError(context.Background(), "invalid python udf request timeout") } + if c.MaxTerminalEntries < 0 || c.MaxTerminalEntries > 1<<30 { + return moerr.NewInternalError(context.Background(), "invalid python udf max terminal entries") + } + if c.MaxTerminalBytes < 0 || c.MaxTerminalBytes > 1<<40 { + return moerr.NewInternalError(context.Background(), "invalid python udf max terminal bytes") + } + if c.TerminalRecordTTL < 0 { + return moerr.NewInternalError(context.Background(), "invalid python udf terminal record ttl") + } return nil } diff --git a/pkg/udf/python/config_test.go b/pkg/udf/python/config_test.go index 090963b6709ea..29034df2000e8 100644 --- a/pkg/udf/python/config_test.go +++ b/pkg/udf/python/config_test.go @@ -23,3 +23,28 @@ func TestClientConfigRequiresExplicitUnisolatedOptIn(t *testing.T) { config.RequestTimeout = time.Second require.NoError(t, config.Validate()) } + +func TestClientConfigRejectsUnboundedInvocationAdmission(t *testing.T) { + config := &ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:50051", + MaxActiveInvocations: -1, + } + require.ErrorContains(t, config.Validate(), "max active invocations") + config.MaxActiveInvocations = 1 << 20 + require.NoError(t, config.Validate()) + config.MaxActiveInvocations++ + require.ErrorContains(t, config.Validate(), "max active invocations") +} + +func TestClientConfigRejectsInvalidInvocationBudgets(t *testing.T) { + config := &ClientConfig{ + Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:50051", + MaxInvocationRows: -1, + } + require.ErrorContains(t, config.Validate(), "max invocation rows") + config.MaxInvocationRows = 1 + config.MaxInvocationResultBytes = -1 + require.ErrorContains(t, config.Validate(), "max invocation result bytes") +} diff --git a/pkg/udf/python/definition.go b/pkg/udf/python/definition.go new file mode 100644 index 0000000000000..4b118b3b83d9c --- /dev/null +++ b/pkg/udf/python/definition.go @@ -0,0 +1,78 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package python + +import ( + "crypto/sha256" + "encoding/hex" + "encoding/json" + "fmt" +) + +// definitionFingerprintBody is the canonical executable contract. Source is +// deliberately absent: original source is a catalog/audit payload, while the +// immutable artifact digest identifies the exact bytes that may be executed. +// Changing a type or execution policy must invalidate the definition even +// when the artifact bytes stay unchanged. +type definitionFingerprintBody struct { + DefinitionSchemaVersion int `json:"definition_schema_version"` + Handler string `json:"handler"` + Mode string `json:"mode"` + NullPolicy string `json:"null_policy"` + ABIContract string `json:"abi_contract"` + AdapterVersion string `json:"adapter_version"` + ArtifactDigest string `json:"artifact_digest"` + EnvironmentDigest string `json:"environment_digest"` + SDKVersion string `json:"sdk_version"` + ArgTypes []TypeDescriptor `json:"arg_types,omitempty"` + ReturnType *TypeDescriptor `json:"return_type,omitempty"` +} + +// DefinitionFingerprint computes the canonical current Python definition +// fingerprint. Callers must pass descriptors produced by NewTypeDescriptor; +// validating here makes the worker and Gateway reject an identity whose type +// metadata is not part of the supported Arrow contract before user code runs. +func DefinitionFingerprint( + definitionSchemaVersion int, + handler, mode, nullPolicy, abiContract, adapterVersion string, + artifactDigest, environmentDigest, sdkVersion string, + args []TypeDescriptor, + returnType TypeDescriptor, +) (string, error) { + if definitionSchemaVersion <= 0 || handler == "" || + mode == "" || nullPolicy == "" || abiContract == "" || + adapterVersion == "" || sdkVersion == "" || artifactDigest == "" || + environmentDigest == "" { + return "", fmt.Errorf("python definition fingerprint has incomplete metadata") + } + for index, descriptor := range args { + if err := descriptor.Validate(); err != nil { + return "", fmt.Errorf("argument descriptor %d: %w", index, err) + } + } + if err := returnType.Validate(); err != nil { + return "", fmt.Errorf("return descriptor: %w", err) + } + body := definitionFingerprintBody{ + DefinitionSchemaVersion: definitionSchemaVersion, + Handler: handler, + Mode: mode, + NullPolicy: nullPolicy, + ABIContract: abiContract, + AdapterVersion: adapterVersion, + ArtifactDigest: artifactDigest, + EnvironmentDigest: environmentDigest, + SDKVersion: sdkVersion, + ArgTypes: args, + ReturnType: &returnType, + } + canonical, err := json.Marshal(body) + if err != nil { + return "", fmt.Errorf("marshal definition fingerprint: %w", err) + } + digest := sha256.Sum256(canonical) + return hex.EncodeToString(digest[:]), nil +} diff --git a/pkg/udf/python/definition_test.go b/pkg/udf/python/definition_test.go new file mode 100644 index 0000000000000..9a0209935afe0 --- /dev/null +++ b/pkg/udf/python/definition_test.go @@ -0,0 +1,51 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package python + +import ( + "encoding/json" + "strings" + "testing" + + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/stretchr/testify/require" +) + +func TestDefinitionFingerprintCanonicalContractExcludesSource(t *testing.T) { + argument, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + returnType, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + artifactDigest := udf.PythonInlineArtifactDigest("add", "def add(ctx, value): return value") + first, err := DefinitionFingerprint( + udf.PythonDefinitionSchemaVersion, + "add", ModeScalar, NullCallHandler, + udf.PythonABIContract, udf.PythonAdapterVersion, + artifactDigest, strings.Repeat("e", 64), udf.PythonSDKVersion, + []TypeDescriptor{argument}, returnType, + ) + require.NoError(t, err) + require.Equal(t, "d0348f99deac2a1518fdf0f32d37a4e7924acbce450c7328d1e83d67d5f7e635", first) + require.True(t, udf.IsSHA256Digest(first)) + + canonical, err := json.Marshal(definitionFingerprintBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "add", + Mode: ModeScalar, + NullPolicy: NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + ArtifactDigest: artifactDigest, + EnvironmentDigest: strings.Repeat("e", 64), + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []TypeDescriptor{argument}, + ReturnType: &returnType, + }) + require.NoError(t, err) + require.NotContains(t, string(canonical), `"source"`) + require.Contains(t, string(canonical), `"artifact_digest"`) +} diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 0329541172bad..b4de40772d9ff 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -11,10 +11,13 @@ package python import ( "bytes" "context" + "crypto/sha256" + "encoding/hex" "encoding/json" "errors" "fmt" "io" + "strings" "sync" "time" @@ -29,24 +32,75 @@ import ( ) const ( - ModeScalar = "SCALAR" - ModeVector = "VECTOR" - NullCallHandler = "CALLED_ON_NULL_INPUT" - NullReturnNull = "RETURNS_NULL_ON_NULL_INPUT" - statusOK = "OK" + ModeScalar = "SCALAR" + ModeVector = "VECTOR" + NullCallHandler = "CALLED_ON_NULL_INPUT" + NullReturnNull = "RETURNS_NULL_ON_NULL_INPUT" + DefaultMaxActiveInvocations = 8 + DefaultMaxInvocationRows = 1 << 20 + DefaultMaxInvocationResultBytes = 256 << 20 + DefaultMaxTerminalEntries = 8192 + DefaultMaxTerminalBytes = 8 << 20 + DefaultTerminalRecordTTL = 10 * time.Minute + // These limits are part of the current worker capability contract. H is + // the worker-wide child budget; account and owner limits are narrower + // fairness fences enforced before a handler child is started. + DefaultWorkerMaxHandlerProcesses = 8 + DefaultWorkerMaxAccountHandlers = 8 + DefaultWorkerMaxOwnerHandlers = 4 + statusOK = "OK" ) var errGatewayClosed = errors.New("python udf gateway is closed") type Gateway struct { - cfg ClientConfig - conn *grpc.ClientConn - flight flight.FlightServiceClient - mu sync.Mutex - closed bool + cfg ClientConfig + artifactResolver ArtifactResolver + allowInlineSource bool + conn *grpc.ClientConn + flight flight.FlightServiceClient + mu sync.Mutex + capabilityMu sync.Mutex + admissionMu sync.Mutex + capabilityReady bool + workerLeaseEpoch uint64 + closed bool + active chan struct{} + ledger *protocol.TerminalLedger + ledgerTTL time.Duration + // admittedGroups and closedGroups are the Gateway's ownership fence for + // the current one-member adapter. A group epoch may be admitted only once; + // a terminal tombstone is reclaimable only after its exact group epoch has + // been closed by this owner. closedGroups stores a monotonic high-water + // epoch per group so a late lower-epoch retry cannot become executable + // after its ledger tombstone is collected. + admittedGroups map[string]uint64 + closedGroups map[string]uint64 + closedGroupBytes int64 + reservedGroupBytes int64 + closedGroupLimit int + closedGroupByteLimit int64 } func NewGateway(cfg ClientConfig) (*Gateway, error) { + // NewGateway is kept for direct adapter tests and local development. CN + // production construction uses NewGatewayWithArtifactStore so an + // executable plan can never supply source bytes itself. + return newGateway(cfg, nil, true) +} + +// NewGatewayWithArtifactStore constructs the CN data-plane client for the +// current typed contract. Source is resolved from the exact account/digest +// reference before Open is sent to the worker; a plan carrying source is +// rejected at this boundary. +func NewGatewayWithArtifactStore(cfg ClientConfig, resolver ArtifactResolver) (*Gateway, error) { + if resolver == nil { + return nil, fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") + } + return newGateway(cfg, resolver, false) +} + +func newGateway(cfg ClientConfig, resolver ArtifactResolver, allowInlineSource bool) (*Gateway, error) { if err := cfg.Validate(); err != nil { return nil, err } @@ -56,14 +110,67 @@ func NewGateway(cfg ClientConfig) (*Gateway, error) { if cfg.MaxBatchRows == 0 { cfg.MaxBatchRows = DefaultMaxBatchRows } + if cfg.MaxInvocationRows == 0 { + cfg.MaxInvocationRows = DefaultMaxInvocationRows + } + if cfg.MaxInvocationResultBytes == 0 { + cfg.MaxInvocationResultBytes = DefaultMaxInvocationResultBytes + } if cfg.RequestTimeout == 0 { cfg.RequestTimeout = 30 * time.Second } - return &Gateway{cfg: cfg}, nil + if cfg.MaxActiveInvocations == 0 { + cfg.MaxActiveInvocations = DefaultMaxActiveInvocations + } + if cfg.MaxTerminalEntries == 0 { + cfg.MaxTerminalEntries = DefaultMaxTerminalEntries + } + if cfg.MaxTerminalBytes == 0 { + cfg.MaxTerminalBytes = DefaultMaxTerminalBytes + } + if cfg.TerminalRecordTTL == 0 { + cfg.TerminalRecordTTL = DefaultTerminalRecordTTL + } + ledger, err := protocol.NewTerminalLedger(cfg.MaxTerminalEntries, cfg.MaxTerminalBytes) + if err != nil { + return nil, err + } + return &Gateway{ + cfg: cfg, + artifactResolver: resolver, + allowInlineSource: allowInlineSource, + active: make(chan struct{}, cfg.MaxActiveInvocations), + ledger: ledger, + ledgerTTL: cfg.TerminalRecordTTL, + admittedGroups: make(map[string]uint64), + closedGroups: make(map[string]uint64), + closedGroupLimit: cfg.MaxTerminalEntries, + closedGroupByteLimit: cfg.MaxTerminalBytes, + }, nil } func (g *Gateway) Language() string { return udf.LanguagePython } +func (g *Gateway) CheckLanguageReady(ctx context.Context, language string) error { + if ctx == nil { + ctx = context.Background() + } + if language != udf.LanguagePython { + return fmt.Errorf("python udf: unsupported readiness language %q", language) + } + if !g.cfg.Enabled { + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") + } + if !g.cfg.AllowUnisolated { + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") + } + client, err := g.flightClient() + if err != nil { + return err + } + return g.ensureCapabilities(ctx, client) +} + func (g *Gateway) connect() error { _, err := g.flightClient() return err @@ -114,28 +221,47 @@ func (g *Gateway) Close() error { } type openPayload struct { - Handler string `json:"handler"` - Source string `json:"source"` - Mode string `json:"mode"` - NullPolicy string `json:"null_policy"` - ABIContract string `json:"abi_contract"` - AdapterVersion string `json:"adapter_version"` - SDKVersion string `json:"sdk_version"` - Context map[string]string `json:"context,omitempty"` - Args []TypeDescriptor `json:"args"` - Return TypeDescriptor `json:"return"` - MaxBatchBytes int64 `json:"max_batch_bytes"` - MaxBatchRows int64 `json:"max_batch_rows"` - HandlerTimeoutSeconds float64 `json:"handler_timeout_seconds"` -} - -func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, result vector.FunctionResultWrapper, mp *mpool.MPool) error { + FunctionRef udf.FunctionRef `json:"function_ref"` + Handler string `json:"handler"` + Source string `json:"source"` + Mode string `json:"mode"` + NullPolicy string `json:"null_policy"` + ABIContract string `json:"abi_contract"` + AdapterVersion string `json:"adapter_version"` + SDKVersion string `json:"sdk_version"` + DefinitionSchemaVersion int `json:"definition_schema_version"` + ArtifactDigest string `json:"artifact_digest"` + EnvironmentDigest string `json:"environment_digest"` + DefinitionFingerprint string `json:"definition_fingerprint"` + Context map[string]string `json:"context,omitempty"` + CallsiteID string `json:"callsite_id"` + MayError bool `json:"may_error"` + SecurityMode string `json:"security_mode"` + Leakproof bool `json:"leakproof"` + StatementContext *udf.StatementContext `json:"statement_context,omitempty"` + SecurityFrame *udf.SecurityFrame `json:"security_frame,omitempty"` + Args []TypeDescriptor `json:"args"` + Return TypeDescriptor `json:"return"` + MaxBatchBytes int64 `json:"max_batch_bytes"` + MaxBatchRows int64 `json:"max_batch_rows"` + MaxInvocationRows int64 `json:"max_invocation_rows"` + MaxInvocationResultBytes int64 `json:"max_invocation_result_bytes"` + HandlerTimeoutSeconds float64 `json:"handler_timeout_seconds"` +} + +func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, result vector.FunctionResultWrapper, mp *mpool.MPool) (err error) { g.mu.Lock() closed := g.closed g.mu.Unlock() if closed { return errGatewayClosed } + if !g.cfg.Enabled { + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") + } + if !g.cfg.AllowUnisolated { + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") + } if ctx == nil { ctx = context.Background() } @@ -144,12 +270,36 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if invocation == nil || result == nil || mp == nil { return fmt.Errorf("python udf: nil invocation, result, or memory pool") } - if err := validateInvocation(invocation); err != nil { + execution := *invocation + if g.artifactResolver != nil { + if execution.Source != "" { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python invocation contains source; use its immutable artifact digest") + } + // Validate the identity, semantic contract, descriptors, and resource + // shape before resolving an account-scoped artifact. Resolution is a + // read with tenant-sensitive error/latency behavior; it must not become + // the first operation performed on an untrusted or stale plan. The + // source-dependent digest check is repeated after the resolver returns. + if err := validateInvocationHeader(&execution); err != nil { + return err + } + execution.Source, err = g.artifactResolver.Resolve( + streamCtx, + execution.FunctionRef.AccountID, + execution.Handler, + execution.ArtifactDigest, + ) + if err != nil { + return err + } + } else if !g.allowInlineSource && execution.Source == "" { + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") + } + if err := validateInvocation(&execution); err != nil { return err } - args := make([]TypeDescriptor, len(invocation.Args)) - for i, typ := range invocation.Args { - var err error + args := make([]TypeDescriptor, len(execution.Args)) + for i, typ := range execution.Args { args[i], err = NewTypeDescriptor(typ) if err != nil { return err @@ -159,21 +309,77 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if err != nil { return err } - if invocation.Length == 0 { + if err := validateInvocationBudget(executionBudget{ + rows: int64(execution.Length), + maxRows: g.cfg.MaxInvocationRows, + returnType: execution.ReturnType, + maxResultBytes: g.cfg.MaxInvocationResultBytes, + }); err != nil { + return err + } + if execution.Length == 0 { return result.PreExtendAndReset(0) } client, err := g.flightClient() if err != nil { return err } - openBody, err := json.Marshal(openPayload{Handler: invocation.Handler, Source: invocation.Source, Mode: invocation.Mode, NullPolicy: invocation.NullPolicy, ABIContract: invocation.ABIContract, AdapterVersion: invocation.AdapterVersion, SDKVersion: invocation.SDKVersion, Context: cloneMap(invocation.Context), Args: args, Return: returnDescriptor, MaxBatchBytes: g.cfg.MaxBatchBytes, MaxBatchRows: g.cfg.MaxBatchRows, HandlerTimeoutSeconds: g.cfg.RequestTimeout.Seconds()}) + if err := g.ensureCapabilities(streamCtx, client); err != nil { + return err + } + // The worker instance owns the lease epoch. Copy the invocation before + // attaching it so a caller cannot observe or reuse an identity issued for + // another worker process. If the worker was restarted after the cached + // handshake, the exchange fails with STALE_LEASE_EPOCH and the deferred + // invalidation below forces a fresh handshake on the next call. + g.mu.Lock() + workerLeaseEpoch := g.workerLeaseEpoch + g.mu.Unlock() + if workerLeaseEpoch == 0 { + return fmt.Errorf("python udf: capability handshake did not return a worker lease epoch") + } + execution.Tuple.LeaseEpoch = workerLeaseEpoch + if err := validateInvocation(&execution); err != nil { + return err + } + defer func() { + if err != nil { + g.invalidateCapabilities() + } + }() + openBody, err := json.Marshal(openPayload{ + FunctionRef: execution.FunctionRef, Handler: execution.Handler, Source: execution.Source, + Mode: execution.Mode, NullPolicy: execution.NullPolicy, ABIContract: execution.ABIContract, + AdapterVersion: execution.AdapterVersion, SDKVersion: execution.SDKVersion, + DefinitionSchemaVersion: execution.DefinitionSchemaVersion, + ArtifactDigest: execution.ArtifactDigest, EnvironmentDigest: execution.EnvironmentDigest, + DefinitionFingerprint: execution.DefinitionFingerprint, + Context: cloneMap(execution.Context), CallsiteID: execution.CallsiteID, + MayError: execution.MayError, SecurityMode: execution.SecurityMode, + Leakproof: execution.Leakproof, StatementContext: execution.StatementContext, + SecurityFrame: execution.SecurityFrame, Args: args, Return: returnDescriptor, + MaxBatchBytes: g.cfg.MaxBatchBytes, MaxBatchRows: g.cfg.MaxBatchRows, + MaxInvocationRows: g.cfg.MaxInvocationRows, MaxInvocationResultBytes: g.cfg.MaxInvocationResultBytes, + HandlerTimeoutSeconds: g.cfg.RequestTimeout.Seconds(), + }) if err != nil { return fmt.Errorf("python udf: encode open payload: %w", err) } - open, err := protocol.MarshalControl(protocol.Control{Kind: "OpenInvocation", Tuple: invocation.Tuple, Payload: openBody}) + open, err := protocol.MarshalControl(protocol.Control{Kind: "OpenInvocation", Tuple: execution.Tuple, Payload: openBody}) if err != nil { return err } + admission, err := g.admitInvocation(&execution) + if err != nil { + return err + } + openAttempted := false + defer func() { + reason := admissionReason(streamCtx, openAttempted, err) + if cleanupErr := admission.finish(openAttempted, reason); err == nil && cleanupErr != nil { + err = cleanupErr + } + }() stream, err := client.DoExchange(streamCtx) if err != nil { @@ -183,10 +389,14 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul // is delivered to the server separately from the Arrow IPC reader; putting // the JSON command in AppMetadata on this message makes PyArrow try to // decode it as an IPC message. + // Once Send is attempted the remote side may have accepted the command. The + // admission is therefore terminalized conservatively even when Send returns + // a transport error; transparent replay would violate VOLATILE semantics. + openAttempted = true if err := stream.Send(&flight.FlightData{FlightDescriptor: &flight.FlightDescriptor{Type: flight.FlightDescriptor_CMD, Cmd: open}}); err != nil { return err } - if err := result.PreExtendAndReset(invocation.Length); err != nil { + if err := result.PreExtendAndReset(execution.Length); err != nil { return err } @@ -199,8 +409,8 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul var batchIndex uint64 var lastSequence uint64 var inputEnded bool - for start < int64(invocation.Length) { - batch, err := encodeInputBatch(invocation.Inputs, invocation.Args, start, int64(invocation.Length)-start, g.cfg.MaxBatchBytes, g.cfg.MaxBatchRows) + for start < int64(execution.Length) { + batch, err := encodeInputBatch(execution.Inputs, execution.Args, start, int64(execution.Length)-start, g.cfg.MaxBatchBytes, g.cfg.MaxBatchRows) if err != nil { return err } @@ -219,7 +429,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if err := sequence.AcceptInput(sequenceNumber); err != nil { return err } - inputControl, err := protocol.MarshalControl(protocol.Control{Kind: "InputBatch", Tuple: invocation.Tuple, Sequence: sequenceNumber}) + inputControl, err := protocol.MarshalControl(protocol.Control{Kind: "InputBatch", Tuple: execution.Tuple, Sequence: sequenceNumber}) if err != nil { return err } @@ -227,12 +437,12 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return err } lastSequence = sequenceNumber - isLastBatch := start+batch.Rows == int64(invocation.Length) + isLastBatch := start+batch.Rows == int64(execution.Length) if isLastBatch { // EndInput is an application-level half-close. Send it before // waiting for the final result so the runtime must keep its result // direction alive when that result is delayed on the wire. - endInput, err := protocol.MarshalControl(protocol.Control{Kind: "EndInput", Tuple: invocation.Tuple, LastSequence: lastSequence}) + endInput, err := protocol.MarshalControl(protocol.Control{Kind: "EndInput", Tuple: execution.Tuple, LastSequence: lastSequence}) if err != nil { return err } @@ -247,7 +457,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul } inputEnded = true } - batchRows, err := g.receiveResultBatch(streamCtx, client, stream, invocation.Tuple, sequenceNumber, batch.Rows, &schemaFrame, &schemaReady, returnDescriptor, result, mp, &sequence) + batchRows, err := g.receiveResultBatch(streamCtx, client, stream, execution.Tuple, sequenceNumber, batch.Rows, &schemaFrame, &schemaReady, returnDescriptor, result, mp, &sequence) if err != nil { return err } @@ -261,7 +471,451 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if !inputEnded || lastSequence != batchIndex { return fmt.Errorf("python udf: input stream did not reach EndInput") } - return g.receiveFinish(streamCtx, client, stream, invocation.Tuple, invocation.Length, rows, &sequence) + return g.receiveFinish(streamCtx, client, stream, execution.Tuple, execution.Length, rows, &sequence) +} + +// invocationAdmission is the real Gateway owner for the CN-side execution +// resources. K is the active slot, the group owns its release, and the ledger +// retains the fencing key after completion so a late retry cannot create a new +// execution. The current W=1 exchange has one member per physical invocation; +// the group API remains able to grow to a multi-member scheduler later. +type invocationAdmission struct { + gateway *Gateway + group *protocol.ExecutionGroup + credit *protocol.LedgerCredit + key string + invocationID string + + mu sync.Mutex + finished bool + memberOpen bool +} + +func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmission, error) { + if invocation == nil { + return nil, fmt.Errorf("python udf: cannot admit a nil invocation") + } + if err := invocation.Tuple.Validate(); err != nil { + return nil, err + } + if err := g.ensureAdmissionState(); err != nil { + return nil, err + } + + key, err := invocationLedgerKey(invocation.Tuple) + if err != nil { + return nil, err + } + g.admissionMu.Lock() + ledger := g.ledger + ttl := g.ledgerTTL + active := g.active + if err := g.claimGroupLocked(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch); err != nil { + g.admissionMu.Unlock() + return nil, err + } + g.admissionMu.Unlock() + if ledger == nil || active == nil { + g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + return nil, fmt.Errorf("python udf: admission state is not initialized") + } + // Expire is intentionally limited to tombstones by TerminalLedger. An + // active invocation can leave this path only through finish/abandon. + // TTL alone cannot prove that a stale tuple can no longer receive a grant. + // The group owner supplies that proof; a closed epoch is the only fence + // that permits an expired tombstone to release its reserved capacity. + ledger.Expire(time.Now(), g.epochClosed) + entryBytes := int64(len(key)) + credit, err := ledger.Reserve(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch, 1, entryBytes) + if err != nil { + g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + return nil, fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF terminal ledger: %w", err) + } + if err := credit.Add(key, entryBytes, time.Now().Add(ttl)); err != nil { + credit.ReleaseUnused() + g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + return nil, err + } + select { + case active <- struct{}{}: + // The group release callback returns this slot after the member is + // terminal. No queue is created, so caller vectors are never held while + // waiting for K. + default: + _ = ledger.Abandon(key) + credit.ReleaseUnused() + g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + return nil, fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF active invocation slots are full") + } + + var releaseOnce sync.Once + release := func() error { + releaseOnce.Do(func() { + <-active + }) + credit.ReleaseUnused() + return nil + } + group, err := protocol.NewExecutionGroup(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch, 1, release) + if err != nil { + <-active + _ = ledger.Abandon(key) + credit.ReleaseUnused() + g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + return nil, err + } + token, err := group.BeginOpen(invocation.Tuple.InvocationID) + if err != nil { + _ = group.Close(protocol.ReasonPartialOpenError) + _ = ledger.Abandon(key) + g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + return nil, err + } + if err := token.Commit(); err != nil { + _ = group.Close(protocol.ReasonPartialOpenError) + _ = ledger.Abandon(key) + g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + return nil, err + } + return &invocationAdmission{ + gateway: g, + group: group, + credit: credit, + key: key, + invocationID: invocation.Tuple.InvocationID, + memberOpen: true, + }, nil +} + +func (g *Gateway) ensureAdmissionState() error { + g.admissionMu.Lock() + defer g.admissionMu.Unlock() + if g.active == nil { + maxActive := g.cfg.MaxActiveInvocations + if maxActive <= 0 { + maxActive = DefaultMaxActiveInvocations + } + g.active = make(chan struct{}, maxActive) + } + if g.ledger == nil { + maxEntries := g.cfg.MaxTerminalEntries + if maxEntries <= 0 { + maxEntries = DefaultMaxTerminalEntries + } + maxBytes := g.cfg.MaxTerminalBytes + if maxBytes <= 0 { + maxBytes = DefaultMaxTerminalBytes + } + ledger, err := protocol.NewTerminalLedger(maxEntries, maxBytes) + if err != nil { + return err + } + g.ledger = ledger + } + if g.ledgerTTL <= 0 { + g.ledgerTTL = g.cfg.TerminalRecordTTL + if g.ledgerTTL <= 0 { + g.ledgerTTL = DefaultTerminalRecordTTL + } + } + if g.admittedGroups == nil { + g.admittedGroups = make(map[string]uint64) + } + if g.closedGroups == nil { + g.closedGroups = make(map[string]uint64) + } + if g.closedGroupLimit <= 0 { + g.closedGroupLimit = g.cfg.MaxTerminalEntries + if g.closedGroupLimit <= 0 { + g.closedGroupLimit = DefaultMaxTerminalEntries + } + } + if g.closedGroupByteLimit <= 0 { + g.closedGroupByteLimit = g.cfg.MaxTerminalBytes + if g.closedGroupByteLimit <= 0 { + g.closedGroupByteLimit = DefaultMaxTerminalBytes + } + } + return nil +} + +func (g *Gateway) claimGroupLocked(groupID string, groupEpoch uint64) error { + if closedEpoch, ok := g.closedGroups[groupID]; ok && groupEpoch <= closedEpoch { + return fmt.Errorf("%w: execution group %q epoch %d is already closed", protocol.ErrDuplicate, groupID, groupEpoch) + } + if admittedEpoch, ok := g.admittedGroups[groupID]; ok { + return fmt.Errorf("%w: execution group %q epoch %d is already admitted", protocol.ErrDuplicate, groupID, admittedEpoch) + } + if _, exists := g.closedGroups[groupID]; !exists { + // Reserve the future tombstone while the group is active. Checking only + // closedGroups admits an unbounded number of concurrent groups between + // two completions and can overflow the bounded fence ledger when they + // drain together. + if len(g.closedGroups)+len(g.admittedGroups) >= g.closedGroupLimit || + g.closedGroupBytes+g.reservedGroupBytes+int64(len(groupID)+8) > g.closedGroupByteLimit { + return fmt.Errorf("%w: Python UDF closed-group fence is full", protocol.ErrLedgerFull) + } + g.reservedGroupBytes += int64(len(groupID) + 8) + } + g.admittedGroups[groupID] = groupEpoch + return nil +} + +func (g *Gateway) releaseGroupClaim(groupID string, groupEpoch uint64) { + g.admissionMu.Lock() + if admittedEpoch, ok := g.admittedGroups[groupID]; ok && admittedEpoch == groupEpoch { + delete(g.admittedGroups, groupID) + if _, closed := g.closedGroups[groupID]; !closed { + g.reservedGroupBytes -= int64(len(groupID) + 8) + } + } + g.admissionMu.Unlock() +} + +func (g *Gateway) closeGroupEpoch(groupID string, groupEpoch uint64) { + g.admissionMu.Lock() + if admittedEpoch, ok := g.admittedGroups[groupID]; ok && admittedEpoch == groupEpoch { + delete(g.admittedGroups, groupID) + if _, closed := g.closedGroups[groupID]; !closed { + g.reservedGroupBytes -= int64(len(groupID) + 8) + } + } + if closedEpoch := g.closedGroups[groupID]; groupEpoch > closedEpoch { + g.closedGroups[groupID] = groupEpoch + if closedEpoch == 0 { + g.closedGroupBytes += int64(len(groupID) + 8) + } + } + g.admissionMu.Unlock() +} + +func (g *Gateway) epochClosed(groupID string, groupEpoch uint64) bool { + g.admissionMu.Lock() + defer g.admissionMu.Unlock() + closedEpoch, ok := g.closedGroups[groupID] + return ok && groupEpoch <= closedEpoch +} + +func invocationLedgerKey(tuple protocol.FencingTuple) (string, error) { + wire, err := json.Marshal(tuple) + if err != nil { + return "", fmt.Errorf("python udf: encode invocation identity: %w", err) + } + digest := sha256.Sum256(wire) + return hex.EncodeToString(digest[:]), nil +} + +func admissionReason(ctx context.Context, attempted bool, err error) protocol.CloseReason { + if err == nil { + return protocol.ReasonInputEOF + } + if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) || + (ctx != nil && ctx.Err() != nil) { + return protocol.ReasonCancel + } + if !attempted { + return protocol.ReasonPartialOpenError + } + return protocol.ReasonFailure +} + +func (a *invocationAdmission) finish(attempted bool, reason protocol.CloseReason) error { + if a == nil { + return nil + } + a.mu.Lock() + defer a.mu.Unlock() + if a.finished { + return nil + } + + // The admission owner is normally reached from one defer. A release + // callback can still fail after the terminal protocol state is frozen, so + // perform one bounded retry here before returning. The group and ledger + // operations are idempotent; only the group release callback has meaningful + // retry state. If both attempts fail, leave `finished` false so a higher + // level shutdown/recovery owner can call finish again without losing the + // resources still owned by this admission. + for attempt := 0; attempt < 2; attempt++ { + var errs []error + if attempted { + if err := a.gateway.ledger.Complete(a.key); err != nil && !errors.Is(err, protocol.ErrUnknownIdentity) { + errs = append(errs, err) + } + } else if err := a.gateway.ledger.Abandon(a.key); err != nil && !errors.Is(err, protocol.ErrUnknownIdentity) { + errs = append(errs, err) + } + if a.memberOpen { + if err := a.group.MemberTerminal(a.invocationID); err != nil && !errors.Is(err, protocol.ErrUnknownIdentity) { + errs = append(errs, err) + } + } + if err := a.group.Close(reason); err != nil { + errs = append(errs, err) + } + if a.group.State() == protocol.GroupReleased { + a.gateway.closeGroupEpoch(a.group.ID(), a.group.Epoch()) + } + if err := errors.Join(errs...); err == nil { + a.finished = true + return nil + } else if attempt == 1 { + return err + } + } + return nil +} + +type capabilityRequest struct { + ProtocolVersion int `json:"protocol_version"` +} + +type capabilityResponse struct { + ProtocolVersion int `json:"protocol_version"` + ABIContract string `json:"abi_contract"` + AdapterVersion string `json:"adapter_version"` + SDKVersion string `json:"sdk_version"` + DefinitionSchemaVersion int `json:"definition_schema_version"` + PlanContractVersion int `json:"plan_contract_version"` + TypeDescriptorContract string `json:"type_descriptor_contract"` + TimezoneDatabaseVersion string `json:"timezone_database_version"` + Modes []string `json:"modes"` + NullPolicies []string `json:"null_policies"` + WindowBatches int `json:"window_batches"` + CumulativeAck bool `json:"cumulative_ack"` + MaxExecutionFrameBytes int64 `json:"max_execution_frame_bytes"` + MaxHandlerProcesses int `json:"max_handler_processes"` + MaxAccountHandlerProcesses int `json:"max_account_handler_processes"` + MaxOwnerHandlerProcesses int `json:"max_owner_handler_processes"` + LeaseEpoch uint64 `json:"lease_epoch"` +} + +// ensureCapabilities is the feature-level readiness gate. It runs once per +// Gateway connection before OpenInvocation, and it caches only a successful +// match. A worker with an unknown or different contract therefore cannot run +// user code, while ordinary SQL remains independent of this client. +func (g *Gateway) ensureCapabilities(ctx context.Context, client flight.FlightServiceClient) error { + g.capabilityMu.Lock() + defer g.capabilityMu.Unlock() + g.mu.Lock() + ready := g.capabilityReady + closed := g.closed + g.mu.Unlock() + if closed { + return errGatewayClosed + } + if ready { + g.mu.Lock() + leaseEpoch := g.workerLeaseEpoch + g.mu.Unlock() + if leaseEpoch != 0 { + return nil + } + // A partially initialized Gateway must not treat readiness as a valid + // worker contract. Fall through and establish the complete capability + // record again. + } + request, err := json.Marshal(capabilityRequest{ProtocolVersion: protocol.Version}) + if err != nil { + return err + } + actionCtx, cancel := context.WithTimeout(ctx, g.cfg.RequestTimeout) + defer cancel() + stream, err := client.DoAction(actionCtx, &flight.Action{Type: "GetPythonCapabilities", Body: request}) + if err != nil { + return fmt.Errorf("python udf: capability handshake: %w", err) + } + result, err := stream.Recv() + if err != nil { + return fmt.Errorf("python udf: capability handshake response: %w", err) + } + if result == nil { + return fmt.Errorf("python udf: empty capability handshake response") + } + var response capabilityResponse + decoder := json.NewDecoder(bytes.NewReader(result.Body)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(&response); err != nil { + return fmt.Errorf("python udf: decode capability handshake: %w", err) + } + var trailing any + if err := decoder.Decode(&trailing); err != io.EOF { + return fmt.Errorf("python udf: capability handshake has trailing JSON") + } + if err := validateCapabilities(response); err != nil { + return err + } + if _, err := stream.Recv(); err != io.EOF { + if err == nil { + return fmt.Errorf("python udf: capability handshake returned multiple results") + } + return fmt.Errorf("python udf: capability handshake stream: %w", err) + } + g.mu.Lock() + if !g.closed { + g.capabilityReady = true + g.workerLeaseEpoch = response.LeaseEpoch + } + g.mu.Unlock() + return nil +} + +// invalidateCapabilities is called after a post-handshake execution error. +// In particular, a restarted worker keeps the same endpoint but advertises a +// new instance lease epoch; clearing the cached record makes the next +// invocation perform the handshake again. This never retries the failed +// invocation or changes its terminal outcome. +func (g *Gateway) invalidateCapabilities() { + g.capabilityMu.Lock() + defer g.capabilityMu.Unlock() + g.mu.Lock() + g.capabilityReady = false + g.workerLeaseEpoch = 0 + g.mu.Unlock() +} + +func validateCapabilities(response capabilityResponse) error { + if response.ProtocolVersion != protocol.Version || + response.ABIContract != udf.PythonABIContract || + response.AdapterVersion != udf.PythonAdapterVersion || + response.SDKVersion != udf.PythonSDKVersion || + response.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion || + response.PlanContractVersion != udf.PythonPlanContractVersion || + response.TypeDescriptorContract != udf.PythonTypeDescriptorContract || + response.TimezoneDatabaseVersion != currentTimezoneDatabaseVersion() || + response.WindowBatches != 1 || response.CumulativeAck || + response.MaxExecutionFrameBytes != 1<<30 || + response.MaxHandlerProcesses != DefaultWorkerMaxHandlerProcesses || + response.MaxAccountHandlerProcesses != DefaultWorkerMaxAccountHandlers || + response.MaxOwnerHandlerProcesses != DefaultWorkerMaxOwnerHandlers || + response.LeaseEpoch == 0 { + return fmt.Errorf("python udf: worker capability contract does not match the current contract") + } + if !sameStrings(response.Modes, []string{ModeScalar, ModeVector}) || + !sameStrings(response.NullPolicies, []string{NullCallHandler, NullReturnNull}) { + return fmt.Errorf("python udf: worker capability set does not match the current contract") + } + return nil +} + +func currentTimezoneDatabaseVersion() string { + version, err := udf.TimezoneDatabaseVersion() + if err != nil { + return "" + } + return version +} + +func sameStrings(actual, expected []string) bool { + if len(actual) != len(expected) { + return false + } + for i := range expected { + if actual[i] != expected[i] { + return false + } + } + return true } func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaining, maxBytes, maxRows int64) (encodedRecordBatch, error) { @@ -274,6 +928,24 @@ func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaini if remaining > maxRows { remaining = maxRows } + // Fixed-width input records can be materialized once at the bounded row + // limit and sliced for each size probe. This removes repeated Arrow builder + // work without assuming anything about variable-length SQL values. The + // slice keeps the same backing buffers, and every candidate is still encoded + // and checked against maxBytes before publication. + if fixedWidthInputTypes(args) { + record, _, err := BuildInputRecordRange(inputs, args, int(start), int(remaining)) + if err != nil { + return encodedRecordBatch{}, err + } + defer record.Release() + tryEncode := func(rows int64) ([]ArrowFrame, error) { + candidate := record.NewSlice(0, rows) + defer candidate.Release() + return EncodeRecordBatch(candidate, maxBytes) + } + return chooseInputBatch(remaining, maxBytes, tryEncode) + } tryEncode := func(rows int64) ([]ArrowFrame, error) { record, _, err := BuildInputRecordRange(inputs, args, int(start), int(rows)) if err != nil { @@ -283,6 +955,19 @@ func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaini record.Release() return frames, encodeErr } + return chooseInputBatch(remaining, maxBytes, tryEncode) +} + +func fixedWidthInputTypes(args []types.Type) bool { + for _, typ := range args { + if typ.IsVarlen() { + return false + } + } + return true +} + +func chooseInputBatch(remaining, maxBytes int64, tryEncode func(int64) ([]ArrowFrame, error)) (encodedRecordBatch, error) { best, probe := int64(0), int64(1) var bestFrames []ArrowFrame failedAt := int64(0) @@ -410,6 +1095,10 @@ func (g *Gateway) receiveResultBatch( decoded.Release() return 0, err } + if limit := g.cfg.MaxInvocationResultBytes; limit > 0 && result.GetResultVector() != nil && int64(result.GetResultVector().Size()) > limit { + decoded.Release() + return 0, fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF invocation result exceeds %d bytes", limit) + } decoded.Release() if err := g.action(ctx, client, "AcknowledgeResults", protocol.Control{Kind: "AcknowledgeResults", Tuple: tuple, AckSequence: control.Sequence}); err != nil { return 0, err @@ -440,6 +1129,9 @@ func (g *Gateway) receiveResultBatch( if control.Sequence != sequenceNumber { return 0, fmt.Errorf("python udf: input sequence %d was consumed while waiting for result %d", control.Sequence, sequenceNumber) } + if control.ReleasedBatches != 1 || control.ReleasedBytes <= 0 || control.ReleasedBytes > g.cfg.MaxBatchBytes { + return 0, fmt.Errorf("python udf: input sequence %d released invalid bytes/batches (%d/%d)", sequenceNumber, control.ReleasedBytes, control.ReleasedBatches) + } if inputConsumed { return 0, fmt.Errorf("python udf: input sequence %d was consumed more than once", sequenceNumber) } @@ -455,6 +1147,38 @@ func (g *Gateway) receiveResultBatch( } } +type executionBudget struct { + rows int64 + maxRows int64 + returnType types.Type + maxResultBytes int64 +} + +func validateInvocationBudget(budget executionBudget) error { + if budget.rows < 0 { + return fmt.Errorf("python udf: invocation row count is negative") + } + if budget.maxRows > 0 && budget.rows > budget.maxRows { + return fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF invocation has %d rows, limit is %d", budget.rows, budget.maxRows) + } + if budget.maxResultBytes <= 0 || budget.rows == 0 { + return nil + } + // PreExtendAndReset allocates the fixed-width payload and the validity + // domain before the first result arrives. Check that unavoidable portion + // before OpenInvocation; variable-width payloads are checked again after + // each validated append because their area size depends on user values. + validityBytes := (budget.rows-1)/8 + 1 + if validityBytes >= budget.maxResultBytes { + return fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF invocation result reservation exceeds %d bytes", budget.maxResultBytes) + } + perRow := int64(budget.returnType.TypeSize()) + if perRow > 0 && budget.rows > (budget.maxResultBytes-validityBytes)/perRow { + return fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF invocation result reservation exceeds %d bytes", budget.maxResultBytes) + } + return nil +} + func validateResultSchemaMetadata(metadata []byte, tuple protocol.FencingTuple) error { control, err := protocol.UnmarshalControl(metadata) if err != nil || control.Tuple != tuple || control.Kind != "ResultSchema" { @@ -500,19 +1224,68 @@ func (g *Gateway) receiveFinish( !inputEnded || control.LastSequence != lastInput || lastResult != lastInput || acked != lastInput || !sequence.ReadyToFinish() { return fmt.Errorf("python udf: invalid Finish status=%q rows=%d", control.Status, rows) } - return g.action(ctx, client, "AcknowledgeFinish", protocol.Control{Kind: "AcknowledgeFinish", Tuple: tuple, FinishID: control.FinishID}) + if control.LastResultSequence != lastResult { + return fmt.Errorf("python udf: invalid Finish result sequence %d, expected %d", control.LastResultSequence, lastResult) + } + return g.acknowledgeFinish(ctx, client, "AcknowledgeFinish", protocol.Control{Kind: "AcknowledgeFinish", Tuple: tuple, FinishID: control.FinishID}) default: return fmt.Errorf("python udf: unexpected control %q", control.Kind) } } } +// acknowledgeFinish retries only the idempotent terminal ACK. A lost ACK +// request or response must not replay any STARTED input or handler work. +// Once the request budget is exhausted the caller preserves the distinction +// between an accepted terminal result and a locally unconfirmed Finish. +func (g *Gateway) acknowledgeFinish(ctx context.Context, client flight.FlightServiceClient, kind string, finish protocol.Control) error { + if client == nil { + return fmt.Errorf("FINISH_UNCONFIRMED: finish ACK client is unavailable") + } + firstErr := g.action(ctx, client, kind, finish) + if firstErr == nil { + return nil + } + if ctx != nil && ctx.Err() != nil { + return fmt.Errorf("FINISH_UNCONFIRMED: finish ACK budget expired: %w", firstErr) + } + if retryErr := g.action(ctx, client, kind, finish); retryErr == nil { + return nil + } else { + return fmt.Errorf("FINISH_UNCONFIRMED: finish ACK was not confirmed after idempotent retry: %v; retry: %w", firstErr, retryErr) + } +} + func validateInvocation(invocation *udf.Invocation) error { + if err := validateInvocationHeader(invocation); err != nil { + return err + } + if invocation.Source == "" { + return fmt.Errorf("python udf: handler and source are required") + } + if invocation.ArtifactDigest != udf.PythonInlineArtifactDigest(invocation.Handler, invocation.Source) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") + } + return nil +} + +// validateInvocationHeader checks every field that is independent of the +// artifact bytes. The CN must run this before an account-scoped artifact +// lookup; otherwise a malformed plan could make the resolver inspect an +// arbitrary tenant path before its FunctionRef and fencing tuple are known to +// be valid. +func validateInvocationHeader(invocation *udf.Invocation) error { + if invocation == nil { + return fmt.Errorf("python udf: nil invocation") + } if invocation.Language != "" && invocation.Language != udf.LanguagePython { return fmt.Errorf("python udf: unsupported language %q", invocation.Language) } - if invocation.Handler == "" || invocation.Source == "" { - return fmt.Errorf("python udf: handler and source are required") + if invocation.Handler == "" { + return fmt.Errorf("python udf: handler is required") + } + if strings.Contains(invocation.Handler, ":") { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog") } if invocation.Length < 0 || len(invocation.Args) != len(invocation.Inputs) { return fmt.Errorf("python udf: invalid input shape") @@ -520,6 +1293,27 @@ func validateInvocation(invocation *udf.Invocation) error { if invocation.Mode != ModeScalar && invocation.Mode != ModeVector { return fmt.Errorf("python udf: unsupported mode %q", invocation.Mode) } + if invocation.CallsiteID == "" || len(invocation.CallsiteID) > 256 || strings.ContainsAny(invocation.CallsiteID, "\r\n") { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no valid callsite id") + } + if !invocation.MayError || invocation.SecurityMode != "INVOKER" || invocation.Leakproof { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invocation semantic contract is not supported") + } + if invocation.StatementContext == nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no statement context") + } + if err := invocation.StatementContext.Validate(); err != nil { + return err + } + if invocation.SecurityFrame == nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no security frame") + } + if err := invocation.SecurityFrame.Validate(); err != nil { + return err + } + if invocation.SecurityFrame.Mode != invocation.SecurityMode { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invocation security mode does not match its frame") + } if invocation.NullPolicy != NullCallHandler && invocation.NullPolicy != NullReturnNull { return fmt.Errorf("python udf: unsupported NULL policy %q", invocation.NullPolicy) } @@ -529,9 +1323,93 @@ func validateInvocation(invocation *udf.Invocation) error { if invocation.SDKVersion != udf.PythonSDKVersion { return fmt.Errorf("python udf: unsupported Python SDK %q", invocation.SDKVersion) } + if invocation.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python definition schema %d", invocation.DefinitionSchemaVersion) + } + if !udf.IsSHA256Digest(invocation.ArtifactDigest) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") + } + environmentDigest, err := udf.PythonEnvironmentDigest() + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest is unavailable: %w", err) + } + if invocation.EnvironmentDigest != environmentDigest { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the current worker contract") + } + if !udf.IsSHA256Digest(invocation.DefinitionFingerprint) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint is invalid") + } + args := make([]TypeDescriptor, len(invocation.Args)) + for index, typ := range invocation.Args { + descriptor, err := NewTypeDescriptor(typ) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python argument descriptor %d: %w", index, err) + } + args[index] = descriptor + } + returnDescriptor, err := NewTypeDescriptor(invocation.ReturnType) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python return descriptor: %w", err) + } + if err := validateInvocationInputs(invocation, args); err != nil { + return err + } + expectedFingerprint, err := DefinitionFingerprint( + invocation.DefinitionSchemaVersion, + invocation.Handler, invocation.Mode, invocation.NullPolicy, + invocation.ABIContract, invocation.AdapterVersion, + invocation.ArtifactDigest, invocation.EnvironmentDigest, invocation.SDKVersion, + args, returnDescriptor, + ) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint cannot be computed: %w", err) + } + if invocation.DefinitionFingerprint != expectedFingerprint { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition") + } + if err := invocation.FunctionRef.Validate(); err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: %w", err) + } + if invocation.FunctionRef.AccountID != invocation.Tuple.AccountID { + return fmt.Errorf("python udf: FunctionRef account does not match the fencing tuple") + } return invocation.Tuple.Validate() } +func validateInvocationInputs(invocation *udf.Invocation, args []TypeDescriptor) error { + if invocation == nil || len(invocation.Inputs) != len(args) { + return fmt.Errorf("python udf: invalid input shape") + } + // An empty physical selection has no input backing to inspect. The + // descriptor and arity have already been validated above; keeping this + // case explicit allows zero-row operators to avoid manufacturing vectors. + if invocation.Length == 0 { + return nil + } + for index, input := range invocation.Inputs { + if input == nil || input.GetType() == nil || input.Length() == 0 { + return fmt.Errorf("python udf: input column %d has no backing vector", index) + } + if !input.GetType().Eq(invocation.Args[index]) { + return fmt.Errorf( + "python udf: input column %d type %s does not match the frozen argument type %s", + index, + input.GetType().DescString(), + invocation.Args[index].DescString(), + ) + } + if !input.IsConst() && input.Length() < invocation.Length { + return fmt.Errorf( + "python udf: input column %d has %d rows, expected at least %d", + index, + input.Length(), + invocation.Length, + ) + } + } + return nil +} + func (g *Gateway) action(ctx context.Context, client flight.FlightServiceClient, kind string, control protocol.Control) error { body, err := protocol.MarshalControl(control) if err != nil { diff --git a/pkg/udf/python/gateway_admission_test.go b/pkg/udf/python/gateway_admission_test.go new file mode 100644 index 0000000000000..457f0d7a9308a --- /dev/null +++ b/pkg/udf/python/gateway_admission_test.go @@ -0,0 +1,200 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package python + +import ( + "errors" + "testing" + "time" + + "github.com/matrixorigin/matrixone/pkg/udf/protocol" + "github.com/stretchr/testify/require" +) + +func newAdmissionTestGateway(t *testing.T, maxActive int) *Gateway { + t.Helper() + gateway, err := NewGateway(ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:1", + MaxActiveInvocations: maxActive, + MaxTerminalEntries: 8, + MaxTerminalBytes: 1 << 20, + TerminalRecordTTL: time.Minute, + }) + require.NoError(t, err) + return gateway +} + +func TestGatewayAdmissionFencesDuplicateAndReleasesOnce(t *testing.T) { + gateway := newAdmissionTestGateway(t, 1) + in := validInvocation() + admission, err := gateway.admitInvocation(in) + require.NoError(t, err) + registered, active, inFlight := admission.group.Counts() + require.Equal(t, 1, registered) + require.Equal(t, 1, active) + require.Equal(t, 0, inFlight) + + _, err = gateway.admitInvocation(in) + require.ErrorIs(t, err, protocol.ErrDuplicate) + entries, _ := gateway.ledger.Counts() + require.Equal(t, 1, entries) + require.Len(t, gateway.active, 1) + + require.NoError(t, admission.finish(true, protocol.ReasonInputEOF)) + require.NoError(t, admission.finish(true, protocol.ReasonInputEOF)) + entries, _ = gateway.ledger.Counts() + require.Equal(t, 1, entries, "accepted execution keeps its tombstone") + require.Len(t, gateway.active, 0, "group owner releases K exactly once") + require.Equal(t, protocol.GroupReleased, admission.group.State()) + _, err = gateway.admitInvocation(in) + require.ErrorIs(t, err, protocol.ErrDuplicate) +} + +func TestGatewayAdmissionRejectsAtKWithoutLeavingLedgerEntry(t *testing.T) { + gateway := newAdmissionTestGateway(t, 1) + first := validInvocation() + firstAdmission, err := gateway.admitInvocation(first) + require.NoError(t, err) + + second := validInvocation() + second.Tuple.GroupID = "second-group" + second.Tuple.InvocationID = "second-invocation" + _, err = gateway.admitInvocation(second) + require.ErrorContains(t, err, "active invocation slots are full") + entries, _ := gateway.ledger.Counts() + require.Equal(t, 1, entries, "K rejection abandons the speculative ledger entry") + require.Len(t, gateway.active, 1) + + require.NoError(t, firstAdmission.finish(true, protocol.ReasonFailure)) + secondAdmission, err := gateway.admitInvocation(second) + require.NoError(t, err) + require.NoError(t, secondAdmission.finish(false, protocol.ReasonPartialOpenError)) + entries, _ = gateway.ledger.Counts() + require.Equal(t, 1, entries, "a pre-send failure abandons instead of tombstoning") + require.Len(t, gateway.active, 0) +} + +func TestGatewayAdmissionReclaimsOnlyClosedEpochTombstones(t *testing.T) { + gateway := newAdmissionTestGateway(t, 1) + gateway.cfg.MaxTerminalEntries = 1 + gateway.ledgerTTL = time.Nanosecond + first := validInvocation() + first.Tuple.GroupID = "reclaim-first" + first.Tuple.InvocationID = "reclaim-first-invocation" + firstAdmission, err := gateway.admitInvocation(first) + require.NoError(t, err) + require.NoError(t, firstAdmission.finish(true, protocol.ReasonInputEOF)) + entries, _ := gateway.ledger.Counts() + require.Equal(t, 1, entries) + gateway.ledgerTTL = time.Nanosecond + + replay := validInvocation() + replay.Tuple.GroupID = first.Tuple.GroupID + replay.Tuple.InvocationID = "reclaim-replay" + _, err = gateway.admitInvocation(replay) + require.ErrorIs(t, err, protocol.ErrDuplicate, "a closed group epoch remains fenced after its TTL") + + second := validInvocation() + second.Tuple.GroupID = "reclaim-second" + second.Tuple.InvocationID = "reclaim-second-invocation" + secondAdmission, err := gateway.admitInvocation(second) + require.NoError(t, err, "an owner-closed tombstone can release bounded ledger capacity") + require.NoError(t, secondAdmission.finish(false, protocol.ReasonPartialOpenError)) + entries, _ = gateway.ledger.Counts() + require.Zero(t, entries) +} + +func TestGatewayAdmissionAcceptedSendIsTerminalOnTransportFailure(t *testing.T) { + gateway := newAdmissionTestGateway(t, 1) + in := validInvocation() + admission, err := gateway.admitInvocation(in) + require.NoError(t, err) + require.NoError(t, admission.finish(true, protocol.ReasonFailure)) + _, err = gateway.admitInvocation(in) + require.Error(t, err) + require.True(t, errors.Is(err, protocol.ErrDuplicate)) + require.Len(t, gateway.active, 0) +} + +func TestGatewayAdmissionRetriesOwnerCleanupAfterGroupReleaseFailure(t *testing.T) { + gateway := newAdmissionTestGateway(t, 1) + require.NoError(t, gateway.ensureAdmissionState()) + + var releaseAttempts int + group, err := protocol.NewExecutionGroup( + "release-retry", 1, 1, + func() error { + releaseAttempts++ + if releaseAttempts <= 2 { + return errors.New("injected group release failure") + } + return nil + }, + ) + require.NoError(t, err) + token, err := group.BeginOpen("member") + require.NoError(t, err) + require.NoError(t, token.Commit()) + credit, err := gateway.ledger.Reserve("release-retry", 1, 1, 16) + require.NoError(t, err) + require.NoError(t, credit.Add("release-retry-key", 16, time.Now().Add(time.Minute))) + + admission := &invocationAdmission{ + gateway: gateway, group: group, credit: credit, + key: "release-retry-key", invocationID: "member", memberOpen: true, + } + require.ErrorContains(t, admission.finish(true, protocol.ReasonFailure), "injected group release failure") + require.Equal(t, protocol.GroupDraining, group.State()) + require.NoError(t, admission.finish(true, protocol.ReasonFailure)) + require.Equal(t, 3, releaseAttempts) + require.Equal(t, protocol.GroupReleased, group.State()) + require.NoError(t, admission.finish(true, protocol.ReasonFailure)) +} + +func TestGatewayAdmissionReservesClosedGroupCapacityWhileActive(t *testing.T) { + gateway := newAdmissionTestGateway(t, 2) + gateway.closedGroupLimit = 1 + gateway.closedGroupByteLimit = 1 << 20 + + first := validInvocation() + first.Tuple.GroupID = "reserved-first" + first.Tuple.InvocationID = "first" + firstAdmission, err := gateway.admitInvocation(first) + require.NoError(t, err) + + second := validInvocation() + second.Tuple.GroupID = "reserved-second" + second.Tuple.InvocationID = "second" + _, err = gateway.admitInvocation(second) + require.ErrorIs(t, err, protocol.ErrLedgerFull) + gateway.admissionMu.Lock() + require.Len(t, gateway.admittedGroups, 1) + require.Positive(t, gateway.reservedGroupBytes) + gateway.admissionMu.Unlock() + + require.NoError(t, firstAdmission.finish(true, protocol.ReasonInputEOF)) + gateway.admissionMu.Lock() + require.Empty(t, gateway.admittedGroups) + require.Zero(t, gateway.reservedGroupBytes) + require.Equal(t, uint64(1), gateway.closedGroups[first.Tuple.GroupID]) + gateway.admissionMu.Unlock() + + // A new epoch of the same group reuses its already-reserved fence. A + // different group remains rejected until the closed fence is reclaimed by a + // future owner protocol. + reentry := validInvocation() + reentry.Tuple.GroupID = first.Tuple.GroupID + reentry.Tuple.GroupEpoch = 2 + reentry.Tuple.InvocationID = "reentry" + reentryAdmission, err := gateway.admitInvocation(reentry) + require.NoError(t, err) + require.NoError(t, reentryAdmission.finish(false, protocol.ReasonPartialOpenError)) + + _, err = gateway.admitInvocation(second) + require.ErrorIs(t, err, protocol.ErrLedgerFull) +} diff --git a/pkg/udf/python/gateway_benchmark_test.go b/pkg/udf/python/gateway_benchmark_test.go new file mode 100644 index 0000000000000..2ab7f7d49dc40 --- /dev/null +++ b/pkg/udf/python/gateway_benchmark_test.go @@ -0,0 +1,118 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package python + +import ( + "testing" + + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" +) + +func benchmarkInputVector(b *testing.B, typ types.Type, rows int) (*vector.Vector, *mpool.MPool) { + b.Helper() + mp := mpool.MustNewZeroNoFixed() + input := vector.NewVec(typ) + for row := 0; row < rows; row++ { + var err error + switch typ.Oid { + case types.T_int64: + err = vector.AppendFixed(input, int64(row), false, mp) + case types.T_varchar: + err = vector.AppendBytes(input, []byte("matrixone-python-udf"), false, mp) + default: + b.Fatalf("unsupported benchmark type %s", typ) + } + if err != nil { + input.Free(mp) + mpool.DeleteMPool(mp) + b.Fatal(err) + } + } + return input, mp +} + +func BenchmarkEncodeInputBatchFixedWidth(b *testing.B) { + benchmarkEncodeInputBatch(b, types.T_int64.ToType()) +} + +func BenchmarkEncodeInputBatchFixedWidthRebuildBaseline(b *testing.B) { + const rows = 8192 + input, mp := benchmarkInputVector(b, types.T_int64.ToType(), rows) + defer func() { + input.Free(mp) + mpool.DeleteMPool(mp) + }() + + b.ReportAllocs() + b.SetBytes(int64(rows)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + batch, err := encodeInputBatchRebuildBaseline( + []*vector.Vector{input}, []types.Type{types.T_int64.ToType()}, + 0, rows, DefaultMaxBatchBytes, rows, + ) + if err != nil { + b.Fatal(err) + } + if batch.Rows != rows || len(batch.Frames) != 2 { + b.Fatalf("unexpected encoded batch rows=%d frames=%d", batch.Rows, len(batch.Frames)) + } + } +} + +func BenchmarkEncodeInputBatchVariableWidth(b *testing.B) { + benchmarkEncodeInputBatch(b, types.New(types.T_varchar, 64, 0)) +} + +func benchmarkEncodeInputBatch(b *testing.B, typ types.Type) { + const rows = 8192 + input, mp := benchmarkInputVector(b, typ, rows) + defer func() { + input.Free(mp) + mpool.DeleteMPool(mp) + }() + + b.ReportAllocs() + b.SetBytes(int64(rows)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + batch, err := encodeInputBatch( + []*vector.Vector{input}, []types.Type{typ}, 0, rows, + DefaultMaxBatchBytes, rows, + ) + if err != nil { + b.Fatal(err) + } + if batch.Rows != rows || len(batch.Frames) != 2 { + b.Fatalf("unexpected encoded batch rows=%d frames=%d", batch.Rows, len(batch.Frames)) + } + } +} + +// encodeInputBatchRebuildBaseline is a benchmark-only reference for the +// pre-optimization path. It intentionally rebuilds the Arrow record for every +// size probe, while production encodeInputBatch slices one fixed-width record. +func encodeInputBatchRebuildBaseline( + inputs []*vector.Vector, + args []types.Type, + start, remaining, maxBytes, maxRows int64, +) (encodedRecordBatch, error) { + if remaining > maxRows { + remaining = maxRows + } + tryEncode := func(rows int64) ([]ArrowFrame, error) { + record, _, err := BuildInputRecordRange(inputs, args, int(start), int(rows)) + if err != nil { + return nil, err + } + frames, encodeErr := EncodeRecordBatch(record, maxBytes) + record.Release() + return frames, encodeErr + } + return chooseInputBatch(remaining, maxBytes, tryEncode) +} diff --git a/pkg/udf/python/gateway_integration_test.go b/pkg/udf/python/gateway_integration_test.go new file mode 100644 index 0000000000000..5e78aaf52da88 --- /dev/null +++ b/pkg/udf/python/gateway_integration_test.go @@ -0,0 +1,631 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package python + +import ( + "context" + "fmt" + "net" + "os" + "os/exec" + "path/filepath" + "runtime" + "strconv" + "strings" + "sync/atomic" + "syscall" + "testing" + "time" + + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/fileservice" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/matrixorigin/matrixone/pkg/udf/protocol" + "github.com/stretchr/testify/require" +) + +var realWorkerBenchmarkRun atomic.Uint64 + +func TestGatewayExecutesAgainstRealPythonWorker(t *testing.T) { + python, err := exec.LookPath("python3") + require.NoError(t, err, "python3 is required for the real worker contract test") + workerPath := realWorkerPath(t) + port := freeTCPPort(t) + + cmd := startRealWorker(t, python, workerPath, port) + artifactFS, err := fileservice.NewMemoryFS(defines.SharedFileServiceName, fileservice.DisabledCacheConfig, nil) + require.NoError(t, err) + artifactStore, err := NewFileArtifactStore(artifactFS, DefaultMaxArtifactBytes) + require.NoError(t, err) + + cfg := ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:" + strconv.Itoa(port), + MaxBatchBytes: 1 << 20, + // Keep the integration path deliberately smaller than the input so a + // single Gateway.Execute exercises more than one W=1 batch and the + // bounded handler burst reuse contract. + MaxBatchRows: 2, + MaxActiveInvocations: 2, + RequestTimeout: 5 * time.Second, + MaxTerminalEntries: 32, + MaxTerminalBytes: 1 << 20, + TerminalRecordTTL: time.Minute, + } + gateway, err := NewGatewayWithArtifactStore(cfg, artifactStore) + require.NoError(t, err) + defer func() { + _ = gateway.Close() + stopRealWorker(cmd) + }() + + readyContext, cancel := context.WithTimeout(context.Background(), 5*time.Second) + require.NoError(t, gateway.CheckLanguageReady(readyContext, udf.LanguagePython)) + cancel() + + t.Run("scalar", func(t *testing.T) { + input, mp := integrationInput(t, []int64{1, 2, 3}) + defer func() { + input.Free(mp) + mpool.DeleteMPool(mp) + }() + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer result.Free() + invocation := integrationInvocation(ModeScalar, "def add(ctx, value): return value + 10", input, protocol.FencingTuple{ + AccountID: 1, StatementID: "real-flight-scalar", GroupID: "real-flight-scalar-group", + GroupEpoch: 1, InvocationID: "real-flight-scalar-invocation", LeaseEpoch: 1, + }) + publishIntegrationArtifact(t, artifactStore, invocation) + require.NoError(t, gateway.Execute(context.Background(), invocation, result, mp)) + require.Equal(t, uint64(1), invocation.Tuple.LeaseEpoch, "Gateway must not mutate the caller's tuple when attaching the worker lease") + require.Equal(t, []int64{11, 12, 13}, vector.MustFixedColNoTypeCheck[int64](result.GetResultVector())) + }) + + t.Run("zero-argument scalar", func(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer result.Free() + invocation := integrationInvocationForArgs( + ModeScalar, + "add", + "def add(ctx): return 42", + nil, + nil, + 1, + protocol.FencingTuple{ + AccountID: 1, StatementID: "real-flight-zero-arg-scalar", GroupID: "real-flight-zero-arg-scalar-group", + GroupEpoch: 1, InvocationID: "real-flight-zero-arg-scalar-invocation", LeaseEpoch: 1, + }, + ) + publishIntegrationArtifact(t, artifactStore, invocation) + require.NoError(t, gateway.Execute(context.Background(), invocation, result, mp)) + require.Equal(t, []int64{42}, vector.MustFixedColNoTypeCheck[int64](result.GetResultVector())) + }) + + t.Run("vector", func(t *testing.T) { + input, mp := integrationInput(t, []int64{4, 5, 6}) + defer func() { + input.Free(mp) + mpool.DeleteMPool(mp) + }() + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer result.Free() + invocation := integrationInvocation( + ModeVector, + "import pyarrow as pa\ndef add(ctx, values): return pa.array([value.as_py() + 20 for value in values], type=pa.int64())", + input, + protocol.FencingTuple{ + AccountID: 1, StatementID: "real-flight-vector", GroupID: "real-flight-vector-group", + GroupEpoch: 1, InvocationID: "real-flight-vector-invocation", LeaseEpoch: 1, + }, + ) + publishIntegrationArtifact(t, artifactStore, invocation) + require.NoError(t, gateway.Execute(context.Background(), invocation, result, mp)) + require.Equal(t, []int64{24, 25, 26}, vector.MustFixedColNoTypeCheck[int64](result.GetResultVector())) + }) + + t.Run("zero-argument vector", func(t *testing.T) { + const rows = 4 + resultMP := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(resultMP) + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), resultMP) + defer result.Free() + source := "import pyarrow as pa\ndef add(ctx): return pa.array([ctx.num_rows] * ctx.num_rows, type=pa.int64())" + invocation := integrationZeroArgVectorInvocation(source, rows, protocol.FencingTuple{ + AccountID: 1, StatementID: "real-flight-zero-arg", GroupID: "real-flight-zero-arg-group", + GroupEpoch: 1, InvocationID: "real-flight-zero-arg-invocation", LeaseEpoch: 1, + }) + publishIntegrationArtifact(t, artifactStore, invocation) + require.NoError(t, gateway.Execute(context.Background(), invocation, result, resultMP)) + // MaxBatchRows is two, so each vector invocation receives the exact + // physical batch shape rather than the total statement length. + require.Equal(t, []int64{2, 2, 2, 2}, vector.MustFixedColNoTypeCheck[int64](result.GetResultVector())) + }) +} + +func TestSupervisorExecutesAgainstRealPythonWorker(t *testing.T) { + python, err := exec.LookPath("python3") + require.NoError(t, err, "python3 is required for the Supervisor integration test") + workerPath := realWorkerPath(t) + port := freeTCPPort(t) + supervisor, err := NewSupervisor(Config{ + Address: "127.0.0.1:" + strconv.Itoa(port), + Path: filepath.Dir(workerPath), + Python: python, + }) + require.NoError(t, err) + require.NoError(t, supervisor.Start()) + workerDone := supervisor.Done() + require.NotNil(t, workerDone) + t.Cleanup(func() { + _ = supervisor.Close() + }) + waitForWorkerPort(t, port) + + artifactFS, err := fileservice.NewMemoryFS(defines.SharedFileServiceName, fileservice.DisabledCacheConfig, nil) + require.NoError(t, err) + artifactStore, err := NewFileArtifactStore(artifactFS, DefaultMaxArtifactBytes) + require.NoError(t, err) + gateway, err := NewGatewayWithArtifactStore(ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:" + strconv.Itoa(port), + MaxBatchBytes: 1 << 20, + MaxBatchRows: 2, + MaxInvocationRows: 32, + MaxInvocationResultBytes: 1 << 20, + MaxActiveInvocations: 1, + RequestTimeout: 5 * time.Second, + MaxTerminalEntries: 16, + MaxTerminalBytes: 1 << 20, + TerminalRecordTTL: time.Minute, + }, artifactStore) + require.NoError(t, err) + defer gateway.Close() + readyContext, cancel := context.WithTimeout(context.Background(), 5*time.Second) + require.NoError(t, gateway.CheckLanguageReady(readyContext, udf.LanguagePython)) + cancel() + + input, mp := integrationInput(t, []int64{5, 6, 7}) + defer func() { + input.Free(mp) + mpool.DeleteMPool(mp) + }() + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer result.Free() + invocation := integrationInvocation(ModeScalar, "def add(ctx, value): return value + 30", input, protocol.FencingTuple{ + AccountID: 1, StatementID: "supervisor-flight", GroupID: "supervisor-flight-group", + GroupEpoch: 1, InvocationID: "supervisor-flight-invocation", LeaseEpoch: 1, + }) + publishIntegrationArtifact(t, artifactStore, invocation) + require.NoError(t, gateway.Execute(context.Background(), invocation, result, mp)) + require.Equal(t, []int64{35, 36, 37}, vector.MustFixedColNoTypeCheck[int64](result.GetResultVector())) + select { + case <-workerDone: + t.Fatal("Python worker exited during a successful Supervisor integration") + default: + } +} + +func publishIntegrationArtifact(t testing.TB, store *FileArtifactStore, invocation *udf.Invocation) { + t.Helper() + source := invocation.Source + require.NotEmpty(t, source) + _, err := store.Publish(context.Background(), invocation.FunctionRef.AccountID, invocation.Handler, source) + require.NoError(t, err) + invocation.Source = "" +} + +func TestGatewayRejectsThePreviousWorkerLeaseAfterRestart(t *testing.T) { + python, err := exec.LookPath("python3") + require.NoError(t, err, "python3 is required for the real worker contract test") + workerPath := realWorkerPath(t) + port := freeTCPPort(t) + first := startRealWorker(t, python, workerPath, port) + + cfg := ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:" + strconv.Itoa(port), + MaxBatchBytes: 1 << 20, + MaxBatchRows: 1024, + MaxActiveInvocations: 1, + RequestTimeout: 2 * time.Second, + MaxTerminalEntries: 32, + MaxTerminalBytes: 1 << 20, + TerminalRecordTTL: time.Minute, + } + gateway, err := NewGateway(cfg) + require.NoError(t, err) + defer gateway.Close() + readyContext, cancel := context.WithTimeout(context.Background(), 5*time.Second) + require.NoError(t, gateway.CheckLanguageReady(readyContext, udf.LanguagePython)) + cancel() + + stopRealWorker(first) + second := startRealWorker(t, python, workerPath, port) + defer stopRealWorker(second) + + input, mp := integrationInput(t, []int64{9}) + defer func() { + input.Free(mp) + mpool.DeleteMPool(mp) + }() + firstResult := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer firstResult.Free() + firstInvocation := integrationInvocation(ModeScalar, "def add(ctx, value): return value + 1", input, protocol.FencingTuple{ + AccountID: 1, StatementID: "restart-statement", GroupID: "restart-group", GroupEpoch: 1, + InvocationID: "restart-invocation", LeaseEpoch: 1, + }) + // The Gateway has a cached lease from the first worker. The second worker + // must reject it before handler admission; the failed invocation is never + // transparently replayed. + require.Error(t, gateway.Execute(context.Background(), firstInvocation, firstResult, mp)) + require.Equal(t, uint64(1), firstInvocation.Tuple.LeaseEpoch) + + secondResult := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer secondResult.Free() + secondInvocation := integrationInvocation(ModeScalar, "def add(ctx, value): return value + 1", input, protocol.FencingTuple{ + AccountID: 1, StatementID: "restart-statement", GroupID: "restart-group-2", GroupEpoch: 1, + InvocationID: "restart-invocation-2", LeaseEpoch: 1, + }) + require.NoError(t, gateway.Execute(context.Background(), secondInvocation, secondResult, mp)) + require.Equal(t, []int64{10}, vector.MustFixedColNoTypeCheck[int64](secondResult.GetResultVector())) +} + +func TestGatewayCloseCancelsAnInFlightExchange(t *testing.T) { + python, err := exec.LookPath("python3") + require.NoError(t, err, "python3 is required for the real worker contract test") + workerPath := realWorkerPath(t) + port := freeTCPPort(t) + worker := startRealWorker(t, python, workerPath, port) + + marker := filepath.Join(t.TempDir(), "handler-started") + // The handler has a deterministic start barrier and then never returns on + // its own. Gateway.Close must cancel the Flight exchange and cause the + // worker's independent cleanup path to terminate this process group. + source := fmt.Sprintf(`import pathlib +import time + +def add(ctx, value): + pathlib.Path(%q).write_text(str(__import__("os").getpid())) + while True: + time.sleep(1) +`, marker) + + gateway, err := NewGateway(ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:" + strconv.Itoa(port), + MaxBatchBytes: 1 << 20, + MaxBatchRows: 1, + MaxActiveInvocations: 1, + RequestTimeout: 30 * time.Second, + MaxTerminalEntries: 32, + MaxTerminalBytes: 1 << 20, + TerminalRecordTTL: time.Minute, + }) + require.NoError(t, err) + defer func() { + _ = gateway.Close() + stopRealWorker(worker) + }() + + readyContext, cancel := context.WithTimeout(context.Background(), 5*time.Second) + require.NoError(t, gateway.CheckLanguageReady(readyContext, udf.LanguagePython)) + cancel() + + input, mp := integrationInput(t, []int64{1}) + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + invocation := integrationInvocation(ModeScalar, source, input, protocol.FencingTuple{ + AccountID: 1, StatementID: "gateway-close", GroupID: "gateway-close-group", + GroupEpoch: 1, InvocationID: "gateway-close-invocation", LeaseEpoch: 1, + }) + done := make(chan error, 1) + go func() { + done <- gateway.Execute(context.Background(), invocation, result, mp) + }() + + require.Eventually(t, func() bool { + _, statErr := os.Stat(marker) + return statErr == nil + }, 5*time.Second, 10*time.Millisecond, "handler did not reach the cancellation barrier") + require.NoError(t, gateway.Close()) + select { + case err := <-done: + require.Error(t, err, "closing the Gateway must not report a successful in-flight invocation") + case <-time.After(5 * time.Second): + t.Fatal("Gateway.Close did not cancel the in-flight exchange") + } + pidBytes, err := os.ReadFile(marker) + require.NoError(t, err) + handlerPID, err := strconv.Atoi(string(pidBytes)) + require.NoError(t, err) + if runtime.GOOS != "windows" { + require.Eventually(t, func() bool { + return syscall.Kill(handlerPID, 0) != nil + }, 5*time.Second, 10*time.Millisecond, "handler process survived Gateway.Close") + } + // The transport error is only half of the shutdown contract. The owner + // cleanup must also have removed the active admission, released K, and + // retained exactly one terminal fence for the accepted Open. Inspect these + // after Execute has returned so the assertion is about the real Flight path, + // rather than a helper's cleanup callback. + gateway.admissionMu.Lock() + require.Empty(t, gateway.admittedGroups) + require.Empty(t, gateway.active) + closedEpoch := gateway.closedGroups[invocation.Tuple.GroupID] + gateway.admissionMu.Unlock() + require.Equal(t, uint64(1), closedEpoch) + entries, _ := gateway.ledger.Counts() + require.Equal(t, 1, entries, "accepted Open retains one terminal tombstone") + + input.Free(mp) + result.Free() + mpool.DeleteMPool(mp) +} + +// BenchmarkGatewayRealPythonWorkerBurst measures the real Flight path with a +// fixed two-row batch. The first sub-benchmark performs eight independent +// one-batch invocations; the second performs one invocation containing eight +// batches. The handler records module loads in a test-owned file, which makes +// the child/import count observable instead of inferring reuse from elapsed +// time. This is a W=1 comparison: it measures bounded burst reuse and does not +// claim a W>1 pipeline benefit. +func BenchmarkGatewayRealPythonWorkerBurst(b *testing.B) { + python, err := exec.LookPath("python3") + if err != nil { + b.Skip("python3 is required for the real worker benchmark") + } + workerPath := realWorkerPath(b) + port := freeTCPPort(b) + worker := startRealWorker(b, python, workerPath, port) + defer stopRealWorker(worker) + + gateway, err := NewGateway(ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:" + strconv.Itoa(port), + MaxBatchBytes: 1 << 20, + MaxBatchRows: 2, + MaxActiveInvocations: 2, + MaxInvocationRows: 1024, + MaxInvocationResultBytes: 1 << 20, + RequestTimeout: 30 * time.Second, + MaxTerminalEntries: 1024, + MaxTerminalBytes: 1 << 20, + TerminalRecordTTL: time.Minute, + }) + if err != nil { + b.Fatal(err) + } + defer gateway.Close() + readyContext, cancel := context.WithTimeout(context.Background(), 5*time.Second) + if err := gateway.CheckLanguageReady(readyContext, udf.LanguagePython); err != nil { + cancel() + b.Fatal(err) + } + cancel() + + benchmark := func(b *testing.B, rows, calls int, label string) { + marker := filepath.Join(b.TempDir(), label+"-module-loads") + runID := realWorkerBenchmarkRun.Add(1) + source := fmt.Sprintf(`from pathlib import Path +with Path(%q).open("a", encoding="utf-8") as marker: + marker.write("loaded\n") + +def add(ctx, value): + return value + 1 +`, marker) + input, mp := integrationInput(b, make([]int64, rows)) + for index := range make([]int64, rows) { + vector.MustFixedColNoTypeCheck[int64](input)[index] = int64(index) + } + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer func() { + input.Free(mp) + result.Free() + mpool.DeleteMPool(mp) + }() + + b.ReportAllocs() + b.ResetTimer() + for iteration := 0; iteration < b.N; iteration++ { + for call := 0; call < calls; call++ { + invocation := integrationInvocation( + ModeScalar, source, input, + protocol.FencingTuple{ + AccountID: 1, + StatementID: fmt.Sprintf("benchmark-%s-%d-%d-%d", label, runID, iteration, call), + GroupID: fmt.Sprintf("benchmark-%s-group-%d-%d-%d", label, runID, iteration, call), + GroupEpoch: 1, + InvocationID: fmt.Sprintf("benchmark-%s-invocation-%d-%d-%d", label, runID, iteration, call), + LeaseEpoch: 1, + }, + ) + if err := gateway.Execute(context.Background(), invocation, result, mp); err != nil { + b.Fatal(err) + } + } + } + b.StopTimer() + loads, err := os.ReadFile(marker) + if err != nil { + b.Fatal(err) + } + actualLoads := strings.Count(string(loads), "loaded\n") + if actualLoads == 0 { + b.Fatal("the handler did not record a module load") + } + b.ReportMetric(float64(rows*calls*b.N)/float64(b.Elapsed().Nanoseconds())*1e9, "rows/s") + b.Logf("batches/invocation=%d module_loads=%d", rows/2, actualLoads) + } + + b.Run("eight_independent_one_batch_invocations", func(b *testing.B) { + benchmark(b, 2, 8, "independent") + }) + b.Run("one_eight_batch_invocation", func(b *testing.B) { + benchmark(b, 16, 1, "burst") + }) +} + +func realWorkerPath(t testing.TB) string { + t.Helper() + _, sourceFile, _, ok := runtime.Caller(0) + require.True(t, ok) + path := filepath.Join(filepath.Dir(sourceFile), "worker", "worker.py") + _, err := os.Stat(path) + require.NoError(t, err) + return path +} + +func freeTCPPort(t testing.TB) int { + t.Helper() + listener, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + defer listener.Close() + return listener.Addr().(*net.TCPAddr).Port +} + +func waitForWorkerPort(t testing.TB, port int) { + t.Helper() + deadline := time.Now().Add(5 * time.Second) + ticker := time.NewTicker(10 * time.Millisecond) + defer ticker.Stop() + for { + connection, err := net.DialTimeout("tcp", "127.0.0.1:"+strconv.Itoa(port), 100*time.Millisecond) + if err == nil { + _ = connection.Close() + return + } + if time.Now().After(deadline) { + require.NoError(t, err, "Python worker did not listen before the startup deadline") + } + <-ticker.C + } +} + +func startRealWorker(t testing.TB, python, workerPath string, port int) *exec.Cmd { + t.Helper() + cmd := exec.Command(python, workerPath, "--address=grpc+tcp://127.0.0.1:"+strconv.Itoa(port)) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Env = append(os.Environ(), "PYTHONUNBUFFERED=1") + if runtime.GOOS != "windows" { + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + } + require.NoError(t, cmd.Start()) + waitForWorkerPort(t, port) + return cmd +} + +func stopRealWorker(cmd *exec.Cmd) { + if cmd == nil || cmd.Process == nil || cmd.ProcessState != nil { + return + } + if runtime.GOOS != "windows" { + _ = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + } else { + _ = cmd.Process.Kill() + } + _, _ = cmd.Process.Wait() +} + +func integrationInput(t testing.TB, values []int64) (*vector.Vector, *mpool.MPool) { + t.Helper() + mp := mpool.MustNewZeroNoFixed() + input := vector.NewVec(types.T_int64.ToType()) + for _, value := range values { + require.NoError(t, vector.AppendFixed(input, value, false, mp)) + } + return input, mp +} + +func integrationInvocation(mode, source string, input *vector.Vector, tuple protocol.FencingTuple) *udf.Invocation { + return integrationInvocationForArgs( + mode, "add", source, + []types.Type{types.T_int64.ToType()}, []*vector.Vector{input}, input.Length(), tuple, + ) +} + +func integrationZeroArgVectorInvocation(source string, length int, tuple protocol.FencingTuple) *udf.Invocation { + return integrationInvocationForArgs(ModeVector, "add", source, nil, nil, length, tuple) +} + +func integrationInvocationForArgs( + mode, handler, source string, + args []types.Type, + inputs []*vector.Vector, + length int, + tuple protocol.FencingTuple, +) *udf.Invocation { + environmentDigest := func() string { + digest, _ := udf.PythonEnvironmentDigest() + return digest + }() + argumentDescriptors := make([]TypeDescriptor, len(args)) + for index, typ := range args { + argumentDescriptors[index], _ = NewTypeDescriptor(typ) + } + returnDescriptor, _ := NewTypeDescriptor(types.T_int64.ToType()) + statementValues := map[string]string{ + "statement_id": tuple.StatementID, + "statement_timestamp_utc": "1704067200123456", + "session_timezone_kind": "FIXED_OFFSET", + "session_timezone_offset_minutes": "+480", + "sql_mode": "[\"ANSI\",\"STRICT_TRANS_TABLES\"]", + "current_database": "udf_integration", + "current_user": "root", + "current_role": "writer", + "connection_collation": "utf8mb4_bin", + } + statementContext, _ := udf.StatementContextFromMap(statementValues) + return &udf.Invocation{ + FunctionRef: udf.FunctionRef{ + AccountID: tuple.AccountID, DatabaseID: 2, FunctionID: 3, Revision: 1, NamespaceVersion: 1, + }, + Language: udf.LanguagePython, + Handler: handler, + Source: source, + Args: args, + ReturnType: types.T_int64.ToType(), + Inputs: inputs, + Length: length, + Mode: mode, + NullPolicy: NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + ArtifactDigest: udf.PythonInlineArtifactDigest(handler, source), + EnvironmentDigest: environmentDigest, + DefinitionFingerprint: func() string { + fingerprint, _ := DefinitionFingerprint( + udf.PythonDefinitionSchemaVersion, + handler, mode, NullCallHandler, + udf.PythonABIContract, udf.PythonAdapterVersion, + udf.PythonInlineArtifactDigest(handler, source), environmentDigest, + udf.PythonSDKVersion, argumentDescriptors, returnDescriptor, + ) + return fingerprint + }(), + CallsiteID: "python/integration", + MayError: true, + SecurityMode: "INVOKER", + StatementContext: statementContext, + SecurityFrame: &udf.SecurityFrame{ + ContractVersion: udf.SecurityFrameContractVersion, + Mode: "INVOKER", + }, + Context: statementValues, + Tuple: tuple, + } +} diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index f4def0e6051a1..c313e81eed2a7 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -7,11 +7,14 @@ package python import ( "context" + "errors" "io" + "strings" "testing" "time" "github.com/apache/arrow-go/v18/arrow/flight/gen/flight" + "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" "github.com/matrixorigin/matrixone/pkg/udf" @@ -26,6 +29,66 @@ type gatewayResultStream struct { index int } +type finishAckActionStream struct { + grpc.ClientStream + result *flight.Result + err error + read bool +} + +func (s *finishAckActionStream) Recv() (*flight.Result, error) { + if !s.read { + s.read = true + if s.err != nil { + return nil, s.err + } + return s.result, nil + } + return nil, io.EOF +} + +type finishAckFlightClient struct { + flight.FlightServiceClient + calls int + actions []*flight.Action +} + +type recordingArtifactResolver struct { + source string + calls int + account uint64 + handler string + digest string +} + +func (r *recordingArtifactResolver) Resolve(_ context.Context, accountID uint64, handler, digest string) (string, error) { + r.calls++ + r.account = accountID + r.handler = handler + r.digest = digest + return r.source, nil +} + +func (c *finishAckFlightClient) DoAction( + ctx context.Context, + action *flight.Action, + opts ...grpc.CallOption, +) (flight.FlightService_DoActionClient, error) { + c.calls++ + c.actions = append(c.actions, action) + if c.calls == 1 { + return &finishAckActionStream{err: errors.New("injected ACK response loss")}, nil + } + tuple := validInvocation().Tuple + ack, err := protocol.MarshalControl(protocol.Control{ + Kind: "Ack", Tuple: tuple, Status: statusOK, FinishID: "finish-1", + }) + if err != nil { + return nil, err + } + return &finishAckActionStream{result: &flight.Result{Body: ack}}, nil +} + func (s *gatewayResultStream) Recv() (*flight.FlightData, error) { if s.index == len(s.results) { return nil, io.EOF @@ -52,18 +115,54 @@ func gatewayControl(t *testing.T, kind string, tuple protocol.FencingTuple, fiel func validInvocation() *udf.Invocation { return &udf.Invocation{ - Language: udf.LanguagePython, - Handler: "add", - Source: "def add(ctx, value): return value", - Args: []types.Type{types.T_int64.ToType()}, - ReturnType: types.T_int64.ToType(), - Length: 0, - Inputs: []*vector.Vector{nil}, - Mode: ModeScalar, - NullPolicy: NullCallHandler, - ABIContract: udf.PythonABIContract, - AdapterVersion: udf.PythonAdapterVersion, - SDKVersion: udf.PythonSDKVersion, + FunctionRef: udf.FunctionRef{ + AccountID: 1, DatabaseID: 2, FunctionID: 3, Revision: 1, NamespaceVersion: 1, + }, + Language: udf.LanguagePython, + Handler: "add", + Source: "def add(ctx, value): return value", + Args: []types.Type{types.T_int64.ToType()}, + ReturnType: types.T_int64.ToType(), + Length: 0, + Inputs: []*vector.Vector{nil}, + Mode: ModeScalar, + NullPolicy: NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + ArtifactDigest: udf.PythonInlineArtifactDigest("add", "def add(ctx, value): return value"), + EnvironmentDigest: func() string { digest, _ := udf.PythonEnvironmentDigest(); return digest }(), + DefinitionFingerprint: func() string { + argument, _ := NewTypeDescriptor(types.T_int64.ToType()) + fingerprint, _ := DefinitionFingerprint( + udf.PythonDefinitionSchemaVersion, + "add", ModeScalar, NullCallHandler, + udf.PythonABIContract, udf.PythonAdapterVersion, + udf.PythonInlineArtifactDigest("add", "def add(ctx, value): return value"), + func() string { digest, _ := udf.PythonEnvironmentDigest(); return digest }(), + udf.PythonSDKVersion, []TypeDescriptor{argument}, argument, + ) + return fingerprint + }(), + CallsiteID: "python/test", + MayError: true, + SecurityMode: "INVOKER", + StatementContext: &udf.StatementContext{ + ContractVersion: udf.StatementContextContractVersion, + StatementTimestampUTC: 1704067200123456, + TimezoneKind: "FIXED_OFFSET", + TimezoneOffsetMinutes: 480, + SQLMode: []string{"ANSI", "STRICT_TRANS_TABLES"}, + CurrentDatabase: "udf", + CurrentUser: "root", + CurrentRole: "writer", + ConnectionCollation: "utf8mb4_bin", + }, + SecurityFrame: &udf.SecurityFrame{ + ContractVersion: udf.SecurityFrameContractVersion, + Mode: "INVOKER", + }, Tuple: protocol.FencingTuple{ AccountID: 1, StatementID: "statement", GroupID: "group", GroupEpoch: 1, InvocationID: "invocation", LeaseEpoch: 1, @@ -80,10 +179,18 @@ func TestValidateInvocationRequiresFrozenContract(t *testing.T) { mutate func(*udf.Invocation) }{ {name: "mode", mutate: func(invocation *udf.Invocation) { invocation.Mode = "" }}, + {name: "external handler", mutate: func(invocation *udf.Invocation) { invocation.Handler = "module:add" }}, {name: "null policy", mutate: func(invocation *udf.Invocation) { invocation.NullPolicy = "" }}, {name: "ABI", mutate: func(invocation *udf.Invocation) { invocation.ABIContract = "" }}, {name: "adapter", mutate: func(invocation *udf.Invocation) { invocation.AdapterVersion = "" }}, {name: "SDK", mutate: func(invocation *udf.Invocation) { invocation.SDKVersion = "" }}, + {name: "definition schema", mutate: func(invocation *udf.Invocation) { invocation.DefinitionSchemaVersion = 0 }}, + {name: "artifact digest", mutate: func(invocation *udf.Invocation) { invocation.ArtifactDigest = "" }}, + {name: "environment digest", mutate: func(invocation *udf.Invocation) { invocation.EnvironmentDigest = "" }}, + {name: "definition fingerprint", mutate: func(invocation *udf.Invocation) { invocation.DefinitionFingerprint = "" }}, + {name: "definition fingerprint contents", mutate: func(invocation *udf.Invocation) { + invocation.DefinitionFingerprint = strings.Repeat("b", 64) + }}, } for _, test := range cases { t.Run(test.name, func(t *testing.T) { @@ -94,6 +201,160 @@ func TestValidateInvocationRequiresFrozenContract(t *testing.T) { } } +func TestGatewayValidatesIdentityBeforeResolvingArtifact(t *testing.T) { + resolver := &recordingArtifactResolver{source: validInvocation().Source} + gateway, err := NewGatewayWithArtifactStore(ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:50051", + }, resolver) + require.NoError(t, err) + + invocation := validInvocation() + invocation.Source = "" + invocation.FunctionRef.FunctionID = 0 + resultMP := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(resultMP) + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), resultMP) + defer result.Free() + + err = gateway.Execute(context.Background(), invocation, result, resultMP) + require.ErrorContains(t, err, "incomplete UDF FunctionRef") + require.Zero(t, resolver.calls, "a malformed typed plan must not probe an account-scoped artifact") +} + +func TestGatewayResolvesArtifactOnlyAfterHeaderValidation(t *testing.T) { + base := validInvocation() + resolver := &recordingArtifactResolver{source: base.Source} + gateway, err := NewGatewayWithArtifactStore(ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:50051", + }, resolver) + require.NoError(t, err) + + invocation := *base + invocation.Source = "" + resultMP := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(resultMP) + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), resultMP) + defer result.Free() + + require.NoError(t, gateway.Execute(context.Background(), &invocation, result, resultMP)) + require.Equal(t, 1, resolver.calls) + require.Equal(t, uint64(1), resolver.account) + require.Equal(t, "add", resolver.handler) + require.Equal(t, base.ArtifactDigest, resolver.digest) +} + +func TestValidateInvocationRejectsMismatchedInputBacking(t *testing.T) { + cases := []struct { + name string + make func(*mpool.MPool) *vector.Vector + want string + }{ + { + name: "nil backing", + make: func(*mpool.MPool) *vector.Vector { return nil }, + want: "has no backing vector", + }, + { + name: "wrong type", + make: func(mp *mpool.MPool) *vector.Vector { + input := vector.NewVec(types.T_float64.ToType()) + require.NoError(t, vector.AppendFixed(input, float64(1), false, mp)) + return input + }, + want: "does not match", + }, + { + name: "short flat vector", + make: func(mp *mpool.MPool) *vector.Vector { + input := vector.NewVec(types.T_int64.ToType()) + require.NoError(t, vector.AppendFixed(input, int64(1), false, mp)) + return input + }, + want: "expected at least 2", + }, + } + for _, test := range cases { + t.Run(test.name, func(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + t.Cleanup(func() { mpool.DeleteMPool(mp) }) + input := test.make(mp) + if input != nil { + t.Cleanup(func() { input.Free(mp) }) + } + invocation := validInvocation() + invocation.Length = 2 + invocation.Inputs = []*vector.Vector{input} + require.ErrorContains(t, validateInvocation(invocation), test.want) + }) + } +} + +func TestValidateInvocationAcceptsConstInputWithFrozenType(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + t.Cleanup(func() { mpool.DeleteMPool(mp) }) + input, err := vector.NewConstFixed(types.T_int64.ToType(), int64(7), 2, mp) + require.NoError(t, err) + t.Cleanup(func() { input.Free(mp) }) + + invocation := validInvocation() + invocation.Length = 2 + invocation.Inputs = []*vector.Vector{input} + require.NoError(t, validateInvocation(invocation)) +} + +func TestValidateInvocationBudgetRejectsBeforeOpen(t *testing.T) { + require.NoError(t, validateInvocationBudget(executionBudget{ + rows: 2, maxRows: 2, returnType: types.T_int64.ToType(), maxResultBytes: 32, + })) + require.ErrorContains(t, validateInvocationBudget(executionBudget{ + rows: 3, maxRows: 2, returnType: types.T_int64.ToType(), maxResultBytes: 32, + }), "invocation has 3 rows") + // Two int64 values plus the validity bitmap need more than sixteen bytes; + // this is rejected before OpenInvocation rather than after user code runs. + require.ErrorContains(t, validateInvocationBudget(executionBudget{ + rows: 2, maxRows: 2, returnType: types.T_int64.ToType(), maxResultBytes: 16, + }), "result reservation") +} + +func TestGatewayFeatureGateRejectsDisabledRuntime(t *testing.T) { + gateway, err := NewGateway(ClientConfig{}) + require.NoError(t, err) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + require.ErrorContains(t, gateway.CheckLanguageReady(ctx, udf.LanguagePython), "runtime is disabled") + require.ErrorContains(t, gateway.Execute(ctx, validInvocation(), nil, nil), "runtime is disabled") +} + +func TestValidateCapabilitiesRequiresWorkerInstanceLease(t *testing.T) { + response := capabilityResponse{ + ProtocolVersion: protocol.Version, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + PlanContractVersion: udf.PythonPlanContractVersion, + TypeDescriptorContract: udf.PythonTypeDescriptorContract, + TimezoneDatabaseVersion: currentTimezoneDatabaseVersion(), + Modes: []string{ModeScalar, ModeVector}, + NullPolicies: []string{NullCallHandler, NullReturnNull}, + WindowBatches: 1, + MaxExecutionFrameBytes: 1 << 30, + MaxHandlerProcesses: DefaultWorkerMaxHandlerProcesses, + MaxAccountHandlerProcesses: DefaultWorkerMaxAccountHandlers, + MaxOwnerHandlerProcesses: DefaultWorkerMaxOwnerHandlers, + } + require.ErrorContains(t, validateCapabilities(response), "contract does not match") + response.LeaseEpoch = 17 + require.NoError(t, validateCapabilities(response)) + response.MaxOwnerHandlerProcesses++ + require.ErrorContains(t, validateCapabilities(response), "contract does not match") +} + func TestValidateActionAckCorrelatesTheRequestedFence(t *testing.T) { request := protocol.Control{ Kind: "AcknowledgeResults", @@ -112,6 +373,22 @@ func TestValidateActionAckCorrelatesTheRequestedFence(t *testing.T) { require.ErrorContains(t, validateActionAck(finish.Kind, finish, finishAck), "finish ID") } +func TestAcknowledgeFinishRetriesTheSameIdempotentRequest(t *testing.T) { + request := protocol.Control{ + Kind: "AcknowledgeFinish", + Tuple: validInvocation().Tuple, + FinishID: "finish-1", + } + client := &finishAckFlightClient{} + gateway := &Gateway{cfg: ClientConfig{RequestTimeout: time.Second}} + + require.NoError(t, gateway.acknowledgeFinish(context.Background(), client, request.Kind, request)) + require.Equal(t, 2, client.calls) + require.Len(t, client.actions, 2) + require.Equal(t, client.actions[0].Type, client.actions[1].Type) + require.Equal(t, client.actions[0].Body, client.actions[1].Body) +} + func TestGatewayCloseIsTerminal(t *testing.T) { gateway, err := NewGateway(ClientConfig{}) require.NoError(t, err) @@ -133,6 +410,8 @@ func TestGatewayFinishRejectsLateHalfStreamControls(t *testing.T) { gatewayControl(t, kind, tuple, func(control *protocol.Control) { if kind == "InputConsumed" { control.Sequence = 1 + control.ReleasedBytes = 1 + control.ReleasedBatches = 1 } }), }} @@ -154,6 +433,7 @@ func TestGatewayRejectsArrowBodyOnControlFrame(t *testing.T) { value.Status = statusOK value.FinishID = "finish-1" value.LastSequence = 1 + value.LastResultSequence = 1 }) control.DataBody = []byte("hidden Arrow payload") gateway := &Gateway{cfg: ClientConfig{RequestTimeout: time.Second}} diff --git a/pkg/udf/python/supervisor.go b/pkg/udf/python/supervisor.go index 87df045f68ac8..4927d3dde7109 100644 --- a/pkg/udf/python/supervisor.go +++ b/pkg/udf/python/supervisor.go @@ -24,6 +24,7 @@ type Supervisor struct { mu sync.Mutex cmd *exec.Cmd done chan struct{} + lastErr error closing bool } @@ -69,7 +70,13 @@ func (s *Supervisor) Start() error { return err } done := make(chan struct{}) + // Keep the notification channel after Wait clears cmd. A very short-lived + // worker can exit between cmd.Start and the caller's Done call; dropping the + // channel in that window would make the service role miss an unexpected + // worker exit entirely. The next successful Start replaces it with a fresh + // channel. s.cmd, s.done = cmd, done + s.lastErr = nil go s.wait(cmd, done) logutil.Infof("started Python UDF worker: %s", cmd.String()) return nil @@ -79,7 +86,10 @@ func (s *Supervisor) wait(cmd *exec.Cmd, done chan struct{}) { err := cmd.Wait() s.mu.Lock() if s.cmd == cmd { - s.cmd, s.done = nil, nil + // cmd is cleared so a later Start can launch a new worker, while done is + // retained as the completed notification that Start's caller captured. + s.cmd = nil + s.lastErr = err s.closing = false } s.mu.Unlock() @@ -89,6 +99,26 @@ func (s *Supervisor) wait(cmd *exec.Cmd, done chan struct{}) { } } +// Done returns the exit notification for the currently running worker. The +// channel is captured after Start and is closed exactly once by wait. A caller +// that owns the service role can therefore observe an unexpected worker exit +// independently of the normal shutdown context. +func (s *Supervisor) Done() <-chan struct{} { + s.mu.Lock() + defer s.mu.Unlock() + return s.done +} + +// Err returns the exit error for the most recently completed worker. It must +// be read after the channel returned by Done has closed. A nil error means the +// process exited with status zero; the service layer still treats that as an +// unexpected exit while the role is running. +func (s *Supervisor) Err() error { + s.mu.Lock() + defer s.mu.Unlock() + return s.lastErr +} + func (s *Supervisor) Close() error { s.mu.Lock() cmd, done := s.cmd, s.done @@ -96,12 +126,11 @@ func (s *Supervisor) Close() error { s.closing = true } s.mu.Unlock() - if cmd == nil { - return nil - } var closeErr error - if err := killSupervisorProcess(cmd); err != nil && !errors.Is(err, os.ErrProcessDone) { - closeErr = fmt.Errorf("stop Python UDF worker: %w", err) + if cmd != nil { + if err := killSupervisorProcess(cmd); err != nil && !errors.Is(err, os.ErrProcessDone) { + closeErr = fmt.Errorf("stop Python UDF worker: %w", err) + } } if done != nil { <-done diff --git a/pkg/udf/python/supervisor_test.go b/pkg/udf/python/supervisor_test.go index b5f17f2cfc6cb..9105ffb7adb6e 100644 --- a/pkg/udf/python/supervisor_test.go +++ b/pkg/udf/python/supervisor_test.go @@ -35,11 +35,69 @@ func TestSupervisorCloseStopsTheCurrentWorkerBeforeReturning(t *testing.T) { require.Eventually(t, func() bool { supervisor.mu.Lock() defer supervisor.mu.Unlock() - return supervisor.cmd == nil && supervisor.done == nil + return supervisor.cmd == nil && supervisor.done != nil }, time.Second, time.Millisecond) + select { + case <-supervisor.Done(): + default: + t.Fatal("closed worker did not publish a completed notification") + } // A second start is only safe after the first wait has completed. This // catches a Close implementation that clears cmd and returns before Wait. require.NoError(t, supervisor.Start()) require.NoError(t, supervisor.Close()) } + +func TestSupervisorPublishesUnexpectedWorkerExit(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("worker supervisor test uses a POSIX executable script") + } + dir := t.TempDir() + workerPath := filepath.Join(dir, "worker.py") + require.NoError(t, os.WriteFile(workerPath, []byte("#!/bin/sh\nexit 17\n"), 0o755)) + + supervisor, err := NewSupervisor(Config{Address: "127.0.0.1:0", Path: dir, Python: "/bin/sh"}) + require.NoError(t, err) + require.NoError(t, supervisor.Start()) + done := supervisor.Done() + require.NotNil(t, done) + select { + case <-done: + case <-time.After(time.Second): + t.Fatal("worker exit was not published") + } + require.EqualError(t, supervisor.Err(), "exit status 17") + require.NoError(t, supervisor.Close()) +} + +func TestSupervisorKeepsImmediateExitObservable(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("worker supervisor test uses a POSIX executable script") + } + dir := t.TempDir() + workerDir := filepath.Join(dir, "worker") + require.NoError(t, os.Mkdir(workerDir, 0o755)) + require.NoError(t, os.WriteFile(filepath.Join(workerDir, "worker.py"), []byte(""), 0o644)) + + script := filepath.Join(dir, "python") + require.NoError(t, os.WriteFile(script, []byte("#!/bin/sh\nexit 17\n"), 0o755)) + s, err := NewSupervisor(Config{ + Path: workerDir, + Python: script, + Address: "127.0.0.1:0", + }) + require.NoError(t, err) + require.NoError(t, s.Start()) + done := s.Done() + require.NotNil(t, done, "Start must publish an observable exit channel even for an immediate failure") + // Close must wait even when Wait has already cleared cmd but has not yet + // published the terminal notification. + require.NoError(t, s.Close()) + select { + case <-done: + case <-time.After(time.Second): + t.Fatal("immediate worker exit was not published") + } + require.Error(t, s.Err(), "a close that races an immediate worker exit must still publish the terminal process result") +} diff --git a/pkg/udf/python/testdata/type_descriptors.json b/pkg/udf/python/testdata/type_descriptors.json new file mode 100644 index 0000000000000..fcc281fc6ea61 --- /dev/null +++ b/pkg/udf/python/testdata/type_descriptors.json @@ -0,0 +1,29 @@ +[ + {"name":"bool","descriptor":{"type_id":10,"offset_width":32},"fingerprint":"7843e5e6f50016ce5cded0cf2c3c9d72134b84e33ef06680dfa1a249bb4c6595"}, + {"name":"int8","descriptor":{"type_id":20,"offset_width":32},"fingerprint":"43302f179a9dc14fc9ad45f5c2c785d7defb402c5e6da00d7f4735b4761b9cea"}, + {"name":"int16","descriptor":{"type_id":21,"offset_width":32},"fingerprint":"f346acef35ead4474900db739a1083b75d76439f4ac1e5ced6d4f2dd1bdcb748"}, + {"name":"int32","descriptor":{"type_id":22,"offset_width":32},"fingerprint":"069fd1e0859fa6d348313e71c9052087b867a486dae7b205906c85fb9b731a00"}, + {"name":"int64","descriptor":{"type_id":23,"offset_width":32},"fingerprint":"482d3c55b8a9d662c2b41326b3ca55cbae65153e662c47c4919ba020d006262b"}, + {"name":"uint8","descriptor":{"type_id":25,"offset_width":32},"fingerprint":"bfb8e804f99c17fda55421b073fecde0b8bb90fc857f21a43abe67de5a6b4e25"}, + {"name":"uint16","descriptor":{"type_id":26,"offset_width":32},"fingerprint":"373eace0b3ab82f3a5380113a75fecb56d4db68775e2e6aa70e0dc9779b918f7"}, + {"name":"uint32","descriptor":{"type_id":27,"offset_width":32},"fingerprint":"be2c02da94fda7b5ab40012b8d8b2f5a76312e1bdf7b93db26b067bd406f3dfc"}, + {"name":"uint64","descriptor":{"type_id":28,"offset_width":32},"fingerprint":"09088571e78bcb6fe65965e09a45886a9f15b58f6000a26de2214842ee9abaf8"}, + {"name":"float32","descriptor":{"type_id":30,"offset_width":32},"fingerprint":"8ade0ed866ef188cbe1dbfeadac487b54edf3e933e811637138db817222a3150"}, + {"name":"float64","descriptor":{"type_id":31,"offset_width":32},"fingerprint":"0121acc964077e1ada1525d4abca8011c297586bd8bb0c20614a8f8e21288b67"}, + {"name":"decimal64","descriptor":{"type_id":32,"width":18,"scale":6,"offset_width":32},"fingerprint":"0ee43811e24e92d89b801a19dbc4e2b4256e0688a08040b0995fde6f18ee6a20"}, + {"name":"decimal128","descriptor":{"type_id":33,"width":38,"scale":10,"offset_width":32},"fingerprint":"3690a03c5e39c40b2d53156c79ee2b9ccb4bea2d7ccb611a5ee8004bada46178"}, + {"name":"date","descriptor":{"type_id":50,"temporal_encoding":"sql_zero_struct","offset_width":32},"fingerprint":"8c401bde992eb173ca8aedca97dbd9f47453b7a860fae199ae0439307e858b4b"}, + {"name":"time","descriptor":{"type_id":51,"scale":6,"offset_width":32},"fingerprint":"8da0f51443fd6822c406d856627054978cef335020a4ba908d0ba41f5438dc93"}, + {"name":"datetime","descriptor":{"type_id":52,"scale":6,"temporal_encoding":"sql_zero_struct","offset_width":32},"fingerprint":"bc5e43e10dbd23c35fe3dea194d8f9a2c294f5ed3eb882e4f9fabd1768a6a618"}, + {"name":"timestamp","descriptor":{"type_id":53,"scale":6,"temporal_encoding":"sql_zero_struct","offset_width":32},"fingerprint":"c1e750fc23cb99b128f673299fa74580a1b8cf896ae64f2a8f7c73c01843f89b"}, + {"name":"char","descriptor":{"type_id":60,"width":16,"charset":3,"offset_width":32},"fingerprint":"1d158d5de44d8579a38f1267d8323ac5f787e83a9ce8a162d97ee744a44e5d60"}, + {"name":"varchar","descriptor":{"type_id":61,"width":64,"charset":3,"offset_width":32},"fingerprint":"eac25e693910d4a54f43e574304d8963c7ea0984c47a2ee1687f0fc4a6fac61f"}, + {"name":"text","descriptor":{"type_id":71,"offset_width":32},"fingerprint":"4d9f162421867c37eb20b22da43637a04e00c18d18a2d73d8018f7b3c2b56169"}, + {"name":"json","descriptor":{"type_id":62,"json_encoding":"canonical_text","offset_width":32},"fingerprint":"b156af5241a070ff80a287da19c46d1593dabee4fb5429f964452e711cd275eb"}, + {"name":"binary","descriptor":{"type_id":64,"width":8,"charset":1,"offset_width":32},"fingerprint":"18b158eee03eb5ea1e481c77fbb31a0201de6c68a27524cd208b0cb4ba09bbf3"}, + {"name":"varbinary","descriptor":{"type_id":65,"width":8,"charset":1,"offset_width":32},"fingerprint":"64406870de1c10859088bb512897cce6e80db525844780113bd9ffb5c3878f1e"}, + {"name":"blob","descriptor":{"type_id":70,"charset":1,"offset_width":32},"fingerprint":"d93ae4faac1d4c092a3fa35e7b8faf596eef890351aef5a7e9020c8fe0d2dd5d"}, + {"name":"uuid","descriptor":{"type_id":63,"offset_width":0},"fingerprint":"370e2939c178acee55aaae27a7bcf92937a203e2788e9e0140d84884be042780"}, + {"name":"vecf32","descriptor":{"type_id":224,"width":3,"offset_width":0},"fingerprint":"9134065bb458a203dae86dc150ec07d814e640ed3a39b04b474f7c9396e64ee9"}, + {"name":"vecf64","descriptor":{"type_id":225,"width":3,"offset_width":0},"fingerprint":"746241d9a35175c5d9fe14a61a9d951e1a97c371dba535c0fc1012f32412ec3c"} +] diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 91a2001b97284..c0eb7f0421183 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import datetime +import decimal import importlib.util import json import os @@ -18,6 +19,7 @@ from unittest import mock import pyarrow as pa +import pyarrow.flight as flight WORKER_PATH = pathlib.Path(__file__).with_name("worker.py") @@ -27,7 +29,373 @@ spec.loader.exec_module(worker) +def complete_open_payload(payload): + """Build a current-contract Open payload for direct Flight tests.""" + payload = dict(payload) + payload.update( + { + "definition_schema_version": worker.DEFINITION_SCHEMA_VERSION, + "artifact_digest": worker._inline_artifact_digest( + payload["handler"], payload["source"] + ), + "environment_digest": worker._environment_digest(), + "max_invocation_rows": 1 << 20, + "max_invocation_result_bytes": 256 << 20, + } + ) + payload.setdefault("callsite_id", "python/test") + payload.setdefault("may_error", True) + payload.setdefault("security_mode", "INVOKER") + payload.setdefault("leakproof", False) + payload.setdefault( + "statement_context", + { + "contract_version": 1, + "statement_timestamp_utc": 1704067200123456, + "timezone_kind": "FIXED_OFFSET", + "timezone_offset_minutes": 480, + "sql_mode": ["ANSI", "STRICT_TRANS_TABLES"], + "current_database": "test", + "current_user": "root", + "current_role": "writer", + "connection_collation": "utf8mb4_bin", + }, + ) + payload.setdefault( + "security_frame", + { + "contract_version": 1, + "mode": "INVOKER", + "invoker_user_id": 0, + "invoker_role_id": 0, + "effective_user_id": 0, + "effective_role_id": 0, + }, + ) + try: + payload["definition_fingerprint"] = worker._definition_fingerprint(payload) + except ValueError: + # Some tests intentionally carry an invalid Arrow descriptor and must + # reach that validation branch before fingerprint computation. + payload["definition_fingerprint"] = "a" * 64 + return payload + + class WorkerContractTest(unittest.TestCase): + def test_capability_advertises_worker_instance_lease(self): + encoded = worker._encode_capabilities( + {"protocol_version": worker.PROTOCOL_VERSION}, lease_epoch=17 + ) + value = json.loads(encoded) + self.assertEqual(17, value["lease_epoch"]) + self.assertEqual(worker.MAX_HANDLER_PROCESSES, value["max_handler_processes"]) + self.assertEqual( + worker.MAX_ACCOUNT_HANDLER_PROCESSES, + value["max_account_handler_processes"], + ) + self.assertEqual( + worker.MAX_OWNER_HANDLER_PROCESSES, + value["max_owner_handler_processes"], + ) + with self.assertRaisesRegex(ValueError, "invalid worker lease epoch"): + worker._encode_capabilities( + {"protocol_version": worker.PROTOCOL_VERSION}, lease_epoch=0 + ) + + def test_typed_statement_context_matches_canonical_handler_context(self): + typed = { + "contract_version": 1, + "statement_timestamp_utc": 1704067200123456, + "timezone_kind": "FIXED_OFFSET", + "timezone_offset_minutes": 510, + "sql_mode": ["ANSI", "STRICT_TRANS_TABLES"], + "current_database": "app", + "current_user": "alice", + "current_role": "writer", + "connection_collation": "utf8mb4_bin", + } + values = worker._typed_statement_context(typed) + statement = worker._statement_context(values) + self.assertEqual("alice", statement.current_user) + self.assertEqual(510, statement.session_timezone.offset_minutes) + self.assertEqual(("ANSI", "STRICT_TRANS_TABLES"), statement.sql_mode) + + def test_typed_statement_context_accepts_unix_epoch(self): + typed = { + "contract_version": 1, + "statement_timestamp_utc": 0, + "timezone_kind": "FIXED_OFFSET", + "timezone_offset_minutes": 0, + "sql_mode": [], + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + values = worker._typed_statement_context(typed) + statement = worker._statement_context(values) + self.assertEqual( + datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc), + statement.statement_timestamp_utc, + ) + + def test_typed_routine_semantics_reject_partial_or_definer_contract(self): + payload = { + "callsite_id": "python/1", + "may_error": True, + "security_mode": "INVOKER", + "leakproof": False, + "security_frame": { + "contract_version": 1, + "mode": "INVOKER", + "invoker_user_id": 7, + "invoker_role_id": 8, + "effective_user_id": 7, + "effective_role_id": 8, + }, + } + worker._validate_typed_call_contract(payload) + payload["security_mode"] = "DEFINER" + with self.assertRaisesRegex(ValueError, "semantic contract"): + worker._validate_typed_call_contract(payload) + payload.pop("security_mode") + with self.assertRaisesRegex(ValueError, "incomplete typed routine semantic contract"): + worker._validate_typed_call_contract(payload) + + def test_handler_quota_uses_typed_effective_principal(self): + payload = complete_open_payload( + { + "function_ref": { + "account_id": 1, + "database_id": 2, + "function_id": 3, + "revision": 1, + "namespace_version": 1, + }, + "source": "def f(ctx, value): return value", + "handler": "f", + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "abi_contract": worker.ABI_CONTRACT, + "adapter_version": worker.ADAPTER_VERSION, + "sdk_version": worker.SDK_VERSION, + "args": [{"type_id": worker.INT64, "offset_width": 32}], + "return": {"type_id": worker.INT64, "offset_width": 32}, + "max_batch_bytes": 1 << 20, + "max_batch_rows": 1, + "handler_timeout_seconds": 1.0, + } + ) + payload["security_frame"].update( + { + "invoker_user_id": 23, + "invoker_role_id": 7, + "effective_user_id": 23, + "effective_role_id": 7, + } + ) + self.assertEqual("user:23/role:7", worker._handler_quota_owner(payload)) + payload["statement_context"]["current_user"] = "same-name-different-principal" + self.assertEqual("user:23/role:7", worker._handler_quota_owner(payload)) + + def test_exchange_rejects_old_demo_open_before_user_code(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + fence = { + "account_id": 1, + "statement_id": "legacy-demo", + "group_id": "legacy-group", + "group_epoch": 1, + "invocation_id": "legacy-invocation", + "lease_epoch": 1, + } + descriptor = {"type_id": worker.INT64, "offset_width": 32} + payload = complete_open_payload( + { + "function_ref": { + "account_id": 1, + "database_id": 2, + "function_id": 3, + "revision": 1, + "namespace_version": 1, + }, + "source": "def f(ctx, x): return x", + "handler": "f", + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "abi_contract": worker.ABI_CONTRACT, + "adapter_version": worker.ADAPTER_VERSION, + "sdk_version": worker.SDK_VERSION, + "args": [descriptor], + "return": descriptor, + "max_batch_bytes": 1 << 20, + "max_batch_rows": 8, + "handler_timeout_seconds": 2, + } + ) + payload.pop("statement_context") + command = worker._encode_control( + {"kind": "OpenInvocation", "tuple": fence, "payload": payload} + ) + reader = types.SimpleNamespace(schema=None, read_chunk=lambda: None) + writer = types.SimpleNamespace( + begin=lambda schema: None, + write_metadata=lambda data: None, + write_with_metadata=lambda record, data: None, + ) + try: + with self.assertRaisesRegex(ValueError, "invocation payload is missing a required field"): + server.do_exchange( + types.SimpleNamespace(is_cancelled=lambda: False), + types.SimpleNamespace(command=command), + reader, + writer, + ) + self.assertFalse(server._active) + self.assertFalse(server._terminal) + finally: + server.shutdown() + + def test_exchange_rejects_missing_typed_statement_context_before_user_code(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + fence = { + "account_id": 1, + "statement_id": "missing-context", + "group_id": "missing-context-group", + "group_epoch": 1, + "invocation_id": "missing-context-invocation", + "lease_epoch": 1, + } + descriptor = {"type_id": worker.INT64, "offset_width": 32} + payload = complete_open_payload( + { + "function_ref": { + "account_id": 1, + "database_id": 2, + "function_id": 3, + "revision": 1, + "namespace_version": 1, + }, + "source": "def f(ctx, x): return x", + "handler": "f", + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "abi_contract": worker.ABI_CONTRACT, + "adapter_version": worker.ADAPTER_VERSION, + "sdk_version": worker.SDK_VERSION, + "args": [descriptor], + "return": descriptor, + "max_batch_bytes": 1 << 20, + "max_batch_rows": 8, + "handler_timeout_seconds": 2, + } + ) + payload["statement_context"] = None + command = worker._encode_control( + {"kind": "OpenInvocation", "tuple": fence, "payload": payload} + ) + reader = types.SimpleNamespace(schema=None, read_chunk=lambda: None) + writer = types.SimpleNamespace( + begin=lambda schema: None, + write_metadata=lambda data: None, + write_with_metadata=lambda record, data: None, + ) + try: + with self.assertRaisesRegex(ValueError, "missing typed statement context"): + server.do_exchange( + types.SimpleNamespace(is_cancelled=lambda: False), + types.SimpleNamespace(command=command), + reader, + writer, + ) + self.assertFalse(server._active) + self.assertFalse(server._terminal) + finally: + server.shutdown() + + def test_worker_rejects_a_tuple_from_another_instance(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0", lease_epoch=17) + with self.assertRaisesRegex(ValueError, "STALE_LEASE_EPOCH"): + server._require_current_lease((1, "statement", "group", 1, "invocation", 16)) + with self.assertRaisesRegex(ValueError, "invalid worker lease epoch"): + worker.RoutineFlightServer("grpc://127.0.0.1:0", lease_epoch=0) + + def test_inline_contract_rejects_external_handler_import(self): + with self.assertRaisesRegex(ValueError, "immutable artifact catalog"): + worker._load_handler("def add(ctx, value): return value", "module:add") + + def test_go_python_type_descriptor_fixtures(self): + fixture_path = WORKER_PATH.parent.parent / "testdata" / "type_descriptors.json" + fixtures = json.loads(fixture_path.read_text()) + self.assertGreaterEqual(len(fixtures), 20) + for fixture in fixtures: + descriptor = fixture["descriptor"] + field = worker._field("value", descriptor) + self.assertEqual( + fixture["fingerprint"], + worker._fingerprint(descriptor), + fixture["name"], + ) + self.assertEqual( + fixture["fingerprint"], + field.metadata[worker.TypeFingerprintKey].decode("ascii"), + fixture["name"], + ) + + def test_all_type_fixtures_round_trip_scalar_values_and_nulls(self): + fixture_path = WORKER_PATH.parent.parent / "testdata" / "type_descriptors.json" + fixtures = json.loads(fixture_path.read_text()) + values = { + "bool": False, + "int8": 1, + "int16": 1, + "int32": 1, + "int64": 1, + "uint8": 1, + "uint16": 1, + "uint32": 1, + "uint64": 1, + "float32": 1.25, + "float64": 1.25, + "decimal64": decimal.Decimal("0.123456"), + "decimal128": decimal.Decimal("0.0000000001"), + "date": worker.SqlDate(False, datetime.date(2024, 1, 2)), + "time": datetime.timedelta(microseconds=123456), + "datetime": worker.SqlDatetime( + False, datetime.datetime(2024, 1, 2, 3, 4, 5, 123456) + ), + "timestamp": worker.SqlTimestamp( + False, + datetime.datetime( + 2024, 1, 2, 3, 4, 5, 123456, tzinfo=datetime.timezone.utc + ), + ), + "char": "中", + "varchar": "中", + "text": "matrixone", + "json": '{"a":1,"b":[true,null]}', + "binary": b"\\x01\\x02", + "varbinary": b"\\x01\\x02", + "blob": b"\\x01\\x02", + "uuid": uuid.UUID("123e4567-e89b-12d3-a456-426614174000"), + "vecf32": memoryview(struct.pack(" str: + for root in TZPATH: + try: + with open( + os.path.join(root, "tzdata.zi"), "r", encoding="utf-8" + ) as source: + line = source.readline().strip() + except (OSError, UnicodeError): + continue + prefix = "# version " + if line.startswith(prefix) and line[len(prefix) :].strip(): + return line[len(prefix) :].strip() + return "" + + +TIMEZONE_DATABASE_VERSION = _timezone_database_version() + + +def _contract_digest(domain: str, *parts: str) -> str: + digest = hashlib.sha256() + for part in (domain, *parts): + encoded = part.encode("utf-8") + digest.update(struct.pack(">Q", len(encoded))) + digest.update(encoded) + return digest.hexdigest() + + +def _inline_artifact_digest(handler: str, source: str) -> str: + return _contract_digest("matrixone-python-inline-artifact", handler, source) + + +def _environment_digest() -> str: + if not TIMEZONE_DATABASE_VERSION: + return "" + return _contract_digest( + "matrixone-python-environment", + str(PROTOCOL_VERSION), + ABI_CONTRACT, + ADAPTER_VERSION, + SDK_VERSION, + str(DEFINITION_SCHEMA_VERSION), + str(PLAN_CONTRACT_VERSION), + TYPE_DESCRIPTOR_CONTRACT, + TIMEZONE_DATABASE_VERSION, + ) + + +def _canonical_definition_json(value: Any) -> bytes: + """Match Go encoding/json's canonical UTF-8 output for this contract.""" + encoded = json.dumps( + value, separators=(",", ":"), ensure_ascii=False, allow_nan=False + ) + # encoding/json escapes these characters even when the payload is UTF-8. + # U+2028/U+2029 are also escaped by Go for safe embedding in JavaScript. + return ( + encoded.replace("&", "\\u0026") + .replace("<", "\\u003c") + .replace(">", "\\u003e") + .replace("\u2028", "\\u2028") + .replace("\u2029", "\\u2029") + .encode("utf-8") + ) + + +def _definition_fingerprint(payload: Dict[str, Any]) -> str: + """Hash the immutable executable contract in an Open. + + The original source is a catalog/audit payload. The artifact digest + identifies the exact bytes resolved by the trusted Gateway, so source is + intentionally absent from this canonical definition body. + """ + body = { + "definition_schema_version": payload["definition_schema_version"], + "handler": payload["handler"], + "mode": payload["mode"], + "null_policy": payload["null_policy"], + "abi_contract": payload["abi_contract"], + "adapter_version": payload["adapter_version"], + "artifact_digest": payload["artifact_digest"], + "environment_digest": payload["environment_digest"], + "sdk_version": payload["sdk_version"], + # Go's canonical definition body uses `omitempty` for ArgTypes. An + # empty VECTOR signature must therefore omit the field rather than + # encode it as an empty array, otherwise zero-argument calls would + # have different fingerprints on the two sides of the ABI. + "arg_types": [ + json.loads(_canonical_descriptor(descriptor).decode("utf-8")) + for descriptor in payload["args"] + ], + "return_type": json.loads( + _canonical_descriptor(payload["return"]).decode("utf-8") + ), + } + if not body["arg_types"]: + del body["arg_types"] + return hashlib.sha256(_canonical_definition_json(body)).hexdigest() + +_CAPABILITY_REQUEST_KEYS = frozenset({"protocol_version"}) +_CAPABILITY_RESPONSE_KEYS = frozenset( + { + "protocol_version", + "abi_contract", + "adapter_version", + "sdk_version", + "definition_schema_version", + "plan_contract_version", + "type_descriptor_contract", + "timezone_database_version", + "modes", + "null_policies", + "window_batches", + "cumulative_ack", + "max_execution_frame_bytes", + "max_handler_processes", + "max_account_handler_processes", + "max_owner_handler_processes", + "lease_epoch", + } +) log = logging.getLogger("matrixone.python.udf.worker") @@ -214,6 +399,13 @@ class _TerminalRecord: bytes: int last_result: int finish_id: Optional[str] + outcome: str + + +_TERMINAL_SUCCESS = "SUCCESS" +_TERMINAL_FINISH_UNCONFIRMED = "FINISH_UNCONFIRMED" +_TERMINAL_CANCELLED = "CANCELLED" +_TERMINAL_FAILED = "FAILED" _FENCING_CONTEXT_KEYS = frozenset( @@ -233,6 +425,31 @@ class _TerminalRecord: "connection_collation", } ) +_TYPED_STATEMENT_CONTEXT_KEYS = frozenset( + { + "contract_version", + "statement_timestamp_utc", + "timezone_kind", + "timezone_name", + "timezone_offset_minutes", + "timezone_database_version", + "sql_mode", + "current_database", + "current_user", + "current_role", + "connection_collation", + } +) +_SECURITY_FRAME_KEYS = frozenset( + { + "contract_version", + "mode", + "invoker_user_id", + "invoker_role_id", + "effective_user_id", + "effective_role_id", + } +) def _required_context_value(context: Dict[str, Any], key: str) -> str: @@ -251,6 +468,108 @@ def _optional_context_value(context: Dict[str, Any], key: str) -> Optional[str]: return value or None +def _typed_statement_context(raw: Any) -> Optional[Dict[str, Any]]: + """Validate the typed Go execution snapshot and return canonical map data.""" + if raw is None: + return None + if not isinstance(raw, dict) or set(raw) - _TYPED_STATEMENT_CONTEXT_KEYS: + raise ValueError("PROTOCOL: unsupported typed statement context field") + if raw.get("contract_version") != 1: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported statement context contract") + timestamp = raw.get("statement_timestamp_utc") + if isinstance(timestamp, bool) or not isinstance(timestamp, int): + raise ValueError("PROTOCOL: invalid typed statement timestamp") + timezone_kind = raw.get("timezone_kind") + if not isinstance(timezone_kind, str): + raise ValueError("PROTOCOL: typed statement timezone is missing") + timezone_kind = timezone_kind.upper() + timezone_name = raw.get("timezone_name", "") + tzdb_version = raw.get("timezone_database_version", "") + offset = raw.get("timezone_offset_minutes", 0) + if isinstance(offset, bool) or not isinstance(offset, int): + raise ValueError("PROTOCOL: invalid typed timezone offset") + if timezone_kind == "IANA": + if not isinstance(timezone_name, str) or not timezone_name or not isinstance(tzdb_version, str) or not tzdb_version or offset != 0: + raise ValueError("PROTOCOL: incomplete typed IANA timezone") + elif timezone_kind == "FIXED_OFFSET": + if timezone_name != "" or tzdb_version != "" or offset < -839 or offset > 840: + raise ValueError("PROTOCOL: invalid typed fixed timezone") + else: + raise ValueError("PROTOCOL: unsupported typed statement timezone") + sql_mode = raw.get("sql_mode") + if not isinstance(sql_mode, list) or any(not isinstance(item, str) or not item for item in sql_mode): + raise ValueError("PROTOCOL: typed statement sql_mode must be an array of strings") + if sql_mode != sorted(set(sql_mode)): + raise ValueError("PROTOCOL: typed statement sql_mode is not canonical") + current_user = raw.get("current_user") + collation = raw.get("connection_collation") + if not isinstance(current_user, str) or not current_user or not isinstance(collation, str) or not collation: + raise ValueError("PROTOCOL: typed statement principal or collation is missing") + optional_text = ("current_database", "current_role") + for key in optional_text: + if key in raw and not isinstance(raw[key], str): + raise ValueError(f"PROTOCOL: typed statement field {key} must be text") + value = { + "statement_timestamp_utc": str(timestamp), + "session_timezone_kind": timezone_kind, + "sql_mode": json.dumps(sql_mode, separators=(",", ":"), ensure_ascii=True), + "current_user": current_user, + "connection_collation": collation, + } + if timezone_kind == "IANA": + value["session_timezone_name"] = timezone_name + value["session_timezone_tzdb_version"] = tzdb_version + else: + value["session_timezone_offset_minutes"] = str(offset) + for key in optional_text: + if raw.get(key, ""): + value[key] = raw[key] + return value + + +def _validate_typed_call_contract(payload: Dict[str, Any]) -> None: + fields = {"callsite_id", "may_error", "security_mode", "leakproof"} + present = fields & set(payload) + if not present: + return + if present != fields: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: incomplete typed routine semantic contract") + callsite_id = payload.get("callsite_id") + if not isinstance(callsite_id, str) or not callsite_id or len(callsite_id) > 256 or "\n" in callsite_id or "\r" in callsite_id: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: invalid typed routine callsite id") + if payload.get("may_error") is not True or payload.get("security_mode") != "INVOKER" or payload.get("leakproof") is not False: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported typed routine semantic contract") + frame = payload.get("security_frame") + if not isinstance(frame, dict) or set(frame) != _SECURITY_FRAME_KEYS: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: incomplete Python security frame") + if frame.get("contract_version") != 1 or frame.get("mode") != "INVOKER": + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported Python security frame") + integer_fields = ("invoker_user_id", "invoker_role_id", "effective_user_id", "effective_role_id") + if any(type(frame.get(key)) is not int or frame[key] < 0 for key in integer_fields): + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: invalid Python security frame") + if frame["invoker_user_id"] != frame["effective_user_id"] or frame["invoker_role_id"] != frame["effective_role_id"]: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: Python security frame changed effective principal") + + +def _handler_quota_owner(payload: Dict[str, Any]) -> str: + """Return the stable effective principal key used by the H budget. + + A session display username is mutable text and is not an identity boundary: + two principals can share it across roles or accounts. The typed security + frame has already been validated before this helper is called, so the + numeric effective IDs are the only values used for account/owner quota + accounting. + """ + frame = payload.get("security_frame") if isinstance(payload, dict) else None + if not isinstance(frame, dict): + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: missing Python security frame") + user_id = frame.get("effective_user_id") + role_id = frame.get("effective_role_id") + if type(user_id) is not int or user_id < 0 or type(role_id) is not int or role_id < 0: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: invalid Python effective principal") + return f"user:{user_id}/role:{role_id}" + + def _statement_context(raw: Any) -> Optional[StatementContext]: if raw is None: return None @@ -277,6 +596,8 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: tzdb_version = _required_context_value(raw, "session_timezone_tzdb_version") if "session_timezone_offset_minutes" in raw: raise ValueError("PROTOCOL: IANA timezone cannot carry a fixed offset") + if not TIMEZONE_DATABASE_VERSION or tzdb_version != TIMEZONE_DATABASE_VERSION: + raise ValueError("PROTOCOL: IANA timezone database version does not match the worker contract") try: ZoneInfo(timezone_name) except (ZoneInfoNotFoundError, ValueError) as exc: @@ -357,6 +678,26 @@ def _tuple_key(value: Dict[str, Any]) -> tuple: ) +def _function_ref(value: Any, tuple_value: Dict[str, Any]) -> tuple: + if not isinstance(value, dict) or set(value) != _FUNCTION_REF_KEYS: + raise ValueError("PROTOCOL: incomplete FunctionRef") + fields = {} + for key in _FUNCTION_REF_KEYS: + item = value.get(key) + minimum = 0 if key == "account_id" else 1 + if ( + isinstance(item, bool) + or not isinstance(item, int) + or item < minimum + or item > (1 << 64) - 1 + ): + raise ValueError(f"PROTOCOL: invalid FunctionRef field {key}") + fields[key] = item + if fields["account_id"] != tuple_value["account_id"]: + raise ValueError("PROTOCOL: FunctionRef account does not match the fencing tuple") + return tuple(fields[key] for key in ("account_id", "database_id", "function_id", "revision", "namespace_version")) + + def _reject_duplicate_json_pairs(pairs): result = {} for key, value in pairs: @@ -402,6 +743,63 @@ def _decode_control(data: bytes) -> Dict[str, Any]: return value +def _decode_capability_request(data: bytes) -> Dict[str, Any]: + if not data or len(data) > MAX_CONTROL_BYTES: + raise ValueError("PROTOCOL: invalid capability request size") + try: + value = json.loads( + bytes(data).decode("utf-8"), + object_pairs_hook=_reject_duplicate_json_pairs, + parse_constant=_reject_nonstandard_json_constant, + ) + except (UnicodeDecodeError, json.JSONDecodeError, RecursionError) as exc: + raise ValueError("PROTOCOL: invalid capability request JSON") from exc + if not isinstance(value, dict) or set(value) != _CAPABILITY_REQUEST_KEYS: + raise ValueError("PROTOCOL: invalid capability request fields") + if type(value.get("protocol_version")) is not int or value["protocol_version"] != PROTOCOL_VERSION: + raise ValueError("PROTOCOL: unsupported capability protocol version") + return value + + +def _encode_capabilities(request: Dict[str, Any], lease_epoch: int = 1) -> bytes: + _decode_capability_request(json.dumps(request, separators=(",", ":")).encode("utf-8")) + if isinstance(lease_epoch, bool) or not isinstance(lease_epoch, int) or lease_epoch <= 0 or lease_epoch > (1 << 64) - 1: + raise ValueError("PROTOCOL: invalid worker lease epoch") + value = { + "protocol_version": PROTOCOL_VERSION, + "abi_contract": ABI_CONTRACT, + "adapter_version": ADAPTER_VERSION, + "sdk_version": SDK_VERSION, + "definition_schema_version": DEFINITION_SCHEMA_VERSION, + "plan_contract_version": PLAN_CONTRACT_VERSION, + "type_descriptor_contract": TYPE_DESCRIPTOR_CONTRACT, + "timezone_database_version": TIMEZONE_DATABASE_VERSION, + "modes": [MODE_SCALAR, MODE_VECTOR], + "null_policies": [NULL_CALL, NULL_RETURN], + # The current implementation intentionally exposes one in-flight + # batch per invocation. This is a capability, not an implied promise + # that a future worker accepts cumulative ACKs. + "window_batches": 1, + "cumulative_ack": False, + "max_execution_frame_bytes": MAX_EXECUTION_FRAME_BYTES, + "max_handler_processes": MAX_HANDLER_PROCESSES, + "max_account_handler_processes": MAX_ACCOUNT_HANDLER_PROCESSES, + "max_owner_handler_processes": MAX_OWNER_HANDLER_PROCESSES, + # This is an instance lease, not a liveness timer. A new worker + # process gets a new value, so a Gateway cannot accidentally reuse an + # invocation tuple that was admitted by a previous worker instance. + "lease_epoch": lease_epoch, + } + if set(value) != _CAPABILITY_RESPONSE_KEYS: + raise ValueError("PROTOCOL: invalid capability response") + encoded = json.dumps( + value, separators=(",", ":"), sort_keys=True, allow_nan=False + ).encode("utf-8") + if len(encoded) > MAX_CONTROL_BYTES: + raise ValueError("RESOURCE_EXHAUSTED: capability response is too large") + return encoded + + def _require_tuple(value: Dict[str, Any], expected: Dict[str, Any]) -> None: if _tuple_key(value) != _tuple_key(expected): raise ValueError("PROTOCOL: fencing tuple changed") @@ -414,6 +812,19 @@ def _required_string(value: Dict[str, Any], key: str) -> str: return item +def _required_digest(value: Dict[str, Any], key: str) -> str: + item = _required_string(value, key) + if len(item) != hashlib.sha256().digest_size * 2: + raise ValueError(f"PROTOCOL: invalid invocation field {key}") + try: + decoded = bytes.fromhex(item) + except ValueError as exc: + raise ValueError(f"PROTOCOL: invalid invocation field {key}") from exc + if item.lower() != item or len(decoded) != hashlib.sha256().digest_size: + raise ValueError(f"PROTOCOL: invalid invocation field {key}") + return item + + def _required_positive_int(value: Dict[str, Any], key: str, maximum: int) -> int: item = value.get(key) if isinstance(item, bool) or not isinstance(item, int) or item <= 0 or item > maximum: @@ -464,8 +875,14 @@ def _validate_control_fields(value: Dict[str, Any], wire: bool) -> None: _required_uint64(value, "sequence") if "last_sequence" in value: _required_uint64(value, "last_sequence", allow_zero=True) + if "last_result_sequence" in value: + _required_uint64(value, "last_result_sequence", allow_zero=True) if "ack_sequence" in value: _required_uint64(value, "ack_sequence") + if "released_bytes" in value: + _required_positive_int(value, "released_bytes", MAX_EXECUTION_FRAME_BYTES) + if "released_batches" in value: + _required_uint64(value, "released_batches") if "finish_id" in value: _required_string(value, "finish_id") if "status" in value: @@ -536,20 +953,35 @@ def _validate_descriptor_domain(descriptor: Dict[str, Any]) -> None: raise ValueError("TYPE_CONTRACT: descriptor width must be non-negative") if scale < 0: raise ValueError("TYPE_CONTRACT: descriptor scale must be non-negative") - if int(descriptor.get("offset_width") or expected_offset_width) != expected_offset_width: + # A 32-bit offset is part of the canonical descriptor for ordinary values + # and is serialized by the Go descriptor. Only fixed-width UUID/vector + # descriptors omit the zero-valued field. Do not turn a missing or + # explicitly zero ordinary offset into an implicit default: that would + # accept a damaged Catalog row and produce a different ABI on the two + # sides. + if expected_offset_width == 32 and "offset_width" not in descriptor: + raise ValueError("TYPE_CONTRACT: descriptor offset_width is required") + if int(descriptor.get("offset_width", expected_offset_width)) != expected_offset_width: raise ValueError( f"TYPE_CONTRACT: descriptor offset_width must be {expected_offset_width}" ) json_encoding = descriptor.get("json_encoding") if json_encoding not in (None, "") and (type_id != JSON or json_encoding != "canonical_text"): raise ValueError("TYPE_CONTRACT: unsupported JSON encoding") + if type_id == JSON and json_encoding != "canonical_text": + raise ValueError("TYPE_CONTRACT: JSON descriptor must use canonical_text encoding") temporal_encoding = descriptor.get("temporal_encoding") if temporal_encoding not in (None, "") and ( type_id not in (DATE, DATETIME, TIMESTAMP) or temporal_encoding != "sql_zero_struct" ): raise ValueError("TYPE_CONTRACT: unsupported temporal encoding") + if type_id in (DATE, DATETIME, TIMESTAMP) and temporal_encoding != "sql_zero_struct": + raise ValueError("TYPE_CONTRACT: temporal descriptor must use sql_zero_struct encoding") - if type_id in (BOOL, INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64, JSON): + if type_id in ( + BOOL, INT8, INT16, INT32, INT64, UINT8, UINT16, UINT32, UINT64, + FLOAT32, FLOAT64, JSON, + ): if width or scale or charset: raise ValueError("TYPE_CONTRACT: descriptor carries unused fields") elif type_id in (DECIMAL64, DECIMAL128): @@ -695,15 +1127,13 @@ def _validate_input_batch_schema( def _load_handler(source: str, handler: str): + if ":" in handler: + raise ValueError( + "UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog" + ) namespace: Dict[str, Any] = {"__name__": "__matrixone_routine__"} exec(compile(source, "", "exec"), namespace, namespace) - if ":" in handler: - module_name, function_name = handler.split(":", 1) - function = namespace.get(function_name) - if function is None and module_name: - function = getattr(importlib.import_module(module_name), function_name, None) - else: - function = namespace.get(handler) + function = namespace.get(handler) if not callable(function) or inspect.iscoroutinefunction(function): raise ValueError("USER_CODE: handler must be a synchronous callable") return function @@ -976,19 +1406,26 @@ def _deserialize_record_batch(data: bytes) -> pa.RecordBatch: reader.close() -def _execute_handler_batch(request: Dict[str, Any]) -> bytes: +def _execute_handler_batch( + request: Dict[str, Any], + *, + handler=None, + statement_context: Optional[StatementContext] = None, +) -> bytes: batch = _deserialize_record_batch(request["input"]) args = request["args"] result_descriptor = request["return"] mode = request["mode"] null_policy = request["null_policy"] sdk_version = request["sdk_version"] - statement_context = _statement_context(request.get("context")) + if statement_context is None: + statement_context = _statement_context(request.get("context")) # User code has no stdout/stderr channel in the Flight protocol. Discard # it so a print() cannot corrupt the length-prefixed response frame. with contextlib.redirect_stdout(_DiscardText()), contextlib.redirect_stderr(_DiscardText()): - handler = _load_handler(request["source"], request["handler"]) + if handler is None: + handler = _load_handler(request["source"], request["handler"]) if mode == MODE_VECTOR: call_context = VectorContext(sdk_version, _CallLogger(), statement_context, batch.num_rows) output = handler(call_context, *[batch.column(index) for index in range(batch.num_columns)]) @@ -1032,27 +1469,122 @@ def _write_execution_frame(stream, payload: bytes) -> None: stream.flush() +def _watch_parent_liveness(read_fd: int) -> None: + """Terminate the whole handler group when the worker disappears. + + The worker cannot run its normal cleanup after SIGKILL/OOM. A pipe whose + write end is owned by the worker gives the handler a kernel-owned death + notification, including the race where the worker exits before the + handler has finished starting. This is a reliability owner for ordinary + handler processes; it is deliberately not described as a security + sandbox, because unisolated user code can inspect or interfere with its + own process. + """ + try: + while True: + if os.read(read_fd, 1) == b"": + if os.name == "posix": + try: + os.killpg(os.getpgrp(), signal.SIGKILL) + except ProcessLookupError: + pass + os._exit(137) + except (OSError, ValueError): + os._exit(137) + + +def _watch_handler_group(read_fd: int, process_group_id: int) -> None: + """Reap a handler process group even after its leader has exited. + + This watchdog is a worker-owned reliability process, not a security + boundary. It has no user-code imports and only has the group id plus a + read end of a worker-owned pipe. If the worker disappears, the pipe gets + EOF and the watchdog kills the whole handler process group. Keeping this + responsibility outside the handler leader closes the case where the + leader exits first while a descendant keeps running. + """ + try: + while True: + if os.read(read_fd, 1) == b"": + if os.name == "posix": + try: + os.killpg(process_group_id, signal.SIGKILL) + except ProcessLookupError: + pass + return + except (OSError, ValueError): + return + finally: + try: + os.close(read_fd) + except OSError: + pass + + def _execute_handler_subprocess() -> None: response_fd_text = os.environ.pop(_HANDLER_RESPONSE_FD_ENV, None) - if response_fd_text is None: + parent_watch_fd_text = os.environ.pop(_HANDLER_PARENT_WATCH_FD_ENV, None) + if response_fd_text is None or parent_watch_fd_text is None: raise ValueError("PROTOCOL: handler response channel is missing") try: response_fd = int(response_fd_text) + parent_watch_fd = int(parent_watch_fd_text) response_stream = os.fdopen(response_fd, "wb", buffering=0, closefd=True) + threading.Thread( + target=_watch_parent_liveness, + args=(parent_watch_fd,), + name="matrixone-udf-parent-watch", + daemon=True, + ).start() except (OSError, TypeError, ValueError) as exc: raise ValueError("PROTOCOL: handler response channel is invalid") from exc try: - size = struct.unpack(">Q", _read_exact(sys.stdin.buffer, 8))[0] - if size > MAX_EXECUTION_FRAME_BYTES: - raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") - request = pickle.loads(_read_exact(sys.stdin.buffer, size)) - response = bytes([_HANDLER_RESPONSE_OK]) + _execute_handler_batch(request) - except Exception as exc: - response = bytes([_HANDLER_RESPONSE_ERROR]) + _safe_error(exc).encode("utf-8") - try: - # This descriptor is created by the adapter and is distinct from the - # process stdout/stderr descriptors available to handler code. - _write_execution_frame(response_stream, response) + # A child is reused only within one bounded invocation burst. The + # source is compiled once and every later request must carry the same + # frozen contract; input Arrow batches remain independently validated + # by the parent and by _execute_handler_batch. + frozen = None + handler = None + statement_context = None + while True: + header = sys.stdin.buffer.read(8) + if not header: + break + if len(header) != 8: + raise EOFError("execution request header ended unexpectedly") + size = struct.unpack(">Q", header)[0] + if size > MAX_EXECUTION_FRAME_BYTES: + raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") + try: + request = pickle.loads(_read_exact(sys.stdin.buffer, size)) + if not isinstance(request, dict): + raise ValueError("PROTOCOL: execution request is not an object") + contract = { + key: request.get(key) + for key in ( + "source", "handler", "mode", "null_policy", "abi_contract", + "adapter_version", "sdk_version", "definition_schema_version", + "artifact_digest", "environment_digest", "definition_fingerprint", + "context", "args", "return", "max_batch_bytes", "max_batch_rows", + "max_invocation_rows", "max_invocation_result_bytes", + ) + } + if frozen is None: + frozen = contract + statement_context = _statement_context(request.get("context")) + handler = _load_handler(request["source"], request["handler"]) + elif contract != frozen: + raise ValueError("PROTOCOL: handler burst contract changed") + response = bytes([_HANDLER_RESPONSE_OK]) + _execute_handler_batch( + request, handler=handler, statement_context=statement_context + ) + except Exception as exc: + response = bytes([_HANDLER_RESPONSE_ERROR]) + _safe_error(exc).encode("utf-8") + # This descriptor is created by the adapter and is distinct from + # process stdout/stderr descriptors available to handler code. + _write_execution_frame(response_stream, response) + if response[0] == _HANDLER_RESPONSE_ERROR: + break finally: response_stream.close() @@ -1066,22 +1598,121 @@ def _context_is_cancelled(context) -> bool: return False +class _ExchangeInputReader: + """Make a blocking Flight input read observable to cancellation. + + ``FlightStreamReader.read_chunk`` is a blocking native call. Polling the + Flight context around that call is insufficient: a cancelled RPC can + remain stuck in the native reader and therefore keep the invocation, its + handler, and its ledger entry alive. Keep at most one chunk in flight and + interrupt the native reader through its cancellation API when the server + context is cancelled. The reader thread is bounded by the admitted + exchange, and is joined before the exchange returns. + """ + + _POLL_SECONDS = 0.05 + + def __init__(self, reader): + self._reader = reader + self._stop = threading.Event() + self._items = queue.Queue(maxsize=1) + self._thread = threading.Thread( + target=self._read_loop, + name="matrixone-udf-flight-reader", + daemon=True, + ) + self._thread.start() + + def _publish(self, kind, value=None): + item = (kind, value) + while not self._stop.is_set(): + try: + self._items.put(item, timeout=self._POLL_SECONDS) + return True + except queue.Full: + continue + return False + + def _read_loop(self): + try: + while not self._stop.is_set(): + try: + chunk = self._reader.read_chunk() + except StopIteration: + self._publish("eof") + return + self._publish("chunk", chunk) + except Exception as exc: + self._publish("error", exc) + + def _cancel_native_reader(self): + cancel = getattr(self._reader, "cancel", None) + if not callable(cancel): + cancel = getattr(self._reader, "close", None) + if callable(cancel): + try: + cancel() + except Exception: + # The RPC is already being torn down. The join below still + # verifies whether the native read actually returned. + pass + + def next(self, context): + while True: + if _context_is_cancelled(context): + self.cancel() + raise TimeoutError("DEADLINE_EXCEEDED: input stream cancelled") + try: + kind, value = self._items.get(timeout=self._POLL_SECONDS) + except queue.Empty: + continue + if kind == "chunk": + return value + if kind == "eof": + raise StopIteration + raise value + + def cancel(self): + self._stop.set() + self._cancel_native_reader() + + def close(self): + self.cancel() + self._thread.join(timeout=1.0) + if self._thread.is_alive(): + raise ValueError( + "RESOURCE_EXHAUSTED: Flight input reader did not stop after cancellation" + ) def _kill_execution_process(process: subprocess.Popen) -> None: # The leader can already have exited while one of its descendants keeps - # the execution alive. Always address the process group first; checking - # poll() before killpg() leaves that descendant outside the cleanup path. + # the execution alive. The session closes the worker-owned liveness pipe + # before calling this helper, so the watchdog owns that leader-exited + # case. Do not call killpg with a reaped PID: macOS may have already + # reused the process-group id and returns EPERM (or could address an + # unrelated group). An un-reaped leader is still killed as a group. if os.name == "posix": - try: - os.killpg(process.pid, signal.SIGKILL) - except ProcessLookupError: - pass + if process.poll() is None: + try: + os.killpg(process.pid, signal.SIGKILL) + except ProcessLookupError: + pass elif process.poll() is None: process.kill() try: process.wait(timeout=1.0) except subprocess.TimeoutExpired: process.kill() - process.wait() + try: + process.wait(timeout=1.0) + except subprocess.TimeoutExpired as exc: + # The caller retains the handler session, H slot, and invocation + # ledger in the bounded pending-cleanup owner. Do not let an + # unbounded reap wait turn a cancellation path into a worker-wide + # hang; the process group has already received SIGKILL and the + # failure is surfaced to the owner. + raise TimeoutError( + "DEADLINE_EXCEEDED: handler process did not exit after SIGKILL" + ) from exc def _execution_group_alive(process: subprocess.Popen) -> bool: @@ -1096,129 +1727,455 @@ def _execution_group_alive(process: subprocess.Popen) -> bool: return True -def _run_handler_process(context, request: Dict[str, Any], timeout_seconds: float) -> bytes: - deadline = time.monotonic() + timeout_seconds - request_wire = pickle.dumps(request, protocol=5) - if len(request_wire) > MAX_EXECUTION_FRAME_BYTES: - raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") - request_frame = struct.pack(">Q", len(request_wire)) + request_wire - response_read_fd, response_write_fd = os.pipe() - process = None - selector = None - popen_kwargs = { - "stdin": subprocess.PIPE, - # Handler output is diagnostic-only. It must never share the - # adapter response channel, even when user code writes directly to - # file descriptor 1. - "stdout": subprocess.DEVNULL, - "stderr": subprocess.DEVNULL, - "close_fds": True, - } - if os.name == "posix": - popen_kwargs["start_new_session"] = True - popen_kwargs["pass_fds"] = (response_write_fd,) - # User code runs under a separate execution identity. In particular, do - # not inherit CN, object-store, database, or tenant credentials from the - # worker process. Routine dependencies are supplied by the selected Python - # environment and do not need ambient environment variables. - child_env = { - name: value - for name, value in os.environ.items() - if name in _HANDLER_ENV_ALLOWLIST - } - child_env[_HANDLER_RESPONSE_FD_ENV] = str(response_write_fd) - # The extra descriptor is a protocol-channel separation mechanism, not a - # sandbox boundary. An unisolated handler with arbitrary OS access can - # still inspect inherited descriptors; production isolation must enforce - # the stronger policy that handler code cannot write this channel. - popen_kwargs["env"] = child_env - response = bytearray() - expected = None - response_eof = False - request_offset = 0 - try: - process = subprocess.Popen( - [sys.executable, os.path.abspath(__file__), "--execute-handler"], - **popen_kwargs, +DEFAULT_BURST_BATCHES = 64 +DEFAULT_BURST_BYTES = 64 << 20 +DEFAULT_BURST_SECONDS = 30.0 +# A pending cleanup retains an admitted invocation, so it is bounded by the +# same ledger entry budget as active invocations. H is only the bound for +# child processes; empty/ALL-NULL invocations can still own a Flight reader +# without owning a handler child. +MAX_PENDING_CLEANUPS = MAX_LEDGER_ENTRIES +PENDING_HANDLER_CLEANUP_INITIAL_DELAY = 0.05 +PENDING_HANDLER_CLEANUP_MAX_DELAY = 1.0 + + +class _HandlerQuotaLease: + """Idempotent ownership token for one live handler child.""" + + def __init__(self, quota, account_id: int, owner_id: str): + self._quota = quota + self._account_id = account_id + self._owner_id = owner_id + self._released = False + self._lock = threading.Lock() + + def release(self) -> None: + with self._lock: + if self._released: + return + self._released = True + self._quota._release(self._account_id, self._owner_id) + + +class _HandlerQuota: + """Non-blocking worker, account, and principal handler budgets. + + The owner key is scoped by account. Two tenants using the same username + therefore do not contend for one another's principal budget. Acquisition + is deliberately all-or-nothing and never waits while a caller owns an + input buffer or a process slot. + """ + + def __init__( + self, + max_account_handlers: int = MAX_ACCOUNT_HANDLER_PROCESSES, + max_owner_handlers: int = MAX_OWNER_HANDLER_PROCESSES, + ): + if ( + type(max_account_handlers) is not int + or max_account_handlers <= 0 + or max_account_handlers > MAX_HANDLER_PROCESSES + ): + raise ValueError("PROTOCOL: invalid account handler budget") + if ( + type(max_owner_handlers) is not int + or max_owner_handlers <= 0 + or max_owner_handlers > max_account_handlers + ): + raise ValueError("PROTOCOL: invalid owner handler budget") + self._max_account_handlers = max_account_handlers + self._max_owner_handlers = max_owner_handlers + self._lock = threading.Lock() + self._account_counts: Dict[int, int] = {} + self._owner_counts: Dict[tuple[int, str], int] = {} + + def acquire(self, account_id: int, owner_id: str) -> _HandlerQuotaLease: + if type(account_id) is not int or account_id < 0: + raise ValueError("PROTOCOL: invalid handler budget account") + if not isinstance(owner_id, str) or not owner_id: + raise ValueError("PROTOCOL: invalid handler budget owner") + owner_key = (account_id, owner_id) + with self._lock: + account_count = self._account_counts.get(account_id, 0) + if account_count >= self._max_account_handlers: + raise ValueError("RESOURCE_EXHAUSTED: account handler budget is full") + owner_count = self._owner_counts.get(owner_key, 0) + if owner_count >= self._max_owner_handlers: + raise ValueError("RESOURCE_EXHAUSTED: owner handler budget is full") + self._account_counts[account_id] = account_count + 1 + self._owner_counts[owner_key] = owner_count + 1 + return _HandlerQuotaLease(self, account_id, owner_id) + + def _release(self, account_id: int, owner_id: str) -> None: + owner_key = (account_id, owner_id) + with self._lock: + account_count = self._account_counts.get(account_id, 0) + owner_count = self._owner_counts.get(owner_key, 0) + if account_count <= 0 or owner_count <= 0: + raise RuntimeError("handler quota release without ownership") + if account_count == 1: + del self._account_counts[account_id] + else: + self._account_counts[account_id] = account_count - 1 + if owner_count == 1: + del self._owner_counts[owner_key] + else: + self._owner_counts[owner_key] = owner_count - 1 + + def counts(self) -> tuple[Dict[int, int], Dict[tuple[int, str], int]]: + """Return copies for deterministic tests and bounded diagnostics.""" + with self._lock: + return dict(self._account_counts), dict(self._owner_counts) + + +class _HandlerProcessSession: + """One handler child reused only inside a bounded invocation burst.""" + + def __init__( + self, + execution_slots: Optional[threading.BoundedSemaphore] = None, + *, + handler_quota: Optional[_HandlerQuota] = None, + account_id: int = 0, + owner_id: str = "__anonymous__", + ): + self._slots = execution_slots or _DEFAULT_HANDLER_SLOTS + self._slot_acquired = False + self._quota_lease = None + self._process = None + self._watchdog_process = None + self._selector = None + self._response_read_fd = -1 + self._parent_watch_write_fd = -1 + self._response_buffer = bytearray() + self._closed = False + self._close_lock = threading.Lock() + self._burst_started = time.monotonic() + self._burst_batches = 0 + self._burst_bytes = 0 + try: + if handler_quota is not None: + self._quota_lease = handler_quota.acquire(account_id, owner_id) + if not self._slots.acquire(blocking=False): + raise ValueError("RESOURCE_EXHAUSTED: handler execution slots are full") + self._slot_acquired = True + response_read_fd, response_write_fd = os.pipe() + parent_watch_read_fd, parent_watch_write_fd = os.pipe() + watchdog_read_fd = os.dup(parent_watch_read_fd) + self._response_read_fd = response_read_fd + self._parent_watch_write_fd = parent_watch_write_fd + popen_kwargs = { + "stdin": subprocess.PIPE, + # Handler output is diagnostic-only. It must never share the + # adapter response channel, even when user code writes directly + # to file descriptor 1. + "stdout": subprocess.DEVNULL, + "stderr": subprocess.DEVNULL, + "close_fds": True, + } + if os.name == "posix": + popen_kwargs["start_new_session"] = True + popen_kwargs["pass_fds"] = (response_write_fd, parent_watch_read_fd) + # User code runs under a separate execution identity. In + # particular, do not inherit CN, object-store, database, or tenant + # credentials from the worker process. This is process hygiene, + # not a sandbox boundary. + child_env = { + name: value + for name, value in os.environ.items() + if name in _HANDLER_ENV_ALLOWLIST + } + child_env[_HANDLER_RESPONSE_FD_ENV] = str(response_write_fd) + child_env[_HANDLER_PARENT_WATCH_FD_ENV] = str(parent_watch_read_fd) + popen_kwargs["env"] = child_env + self._process = subprocess.Popen( + [sys.executable, os.path.abspath(__file__), "--execute-handler"], + **popen_kwargs, + ) + os.close(response_write_fd) + response_write_fd = -1 + os.close(parent_watch_read_fd) + parent_watch_read_fd = -1 + if os.name == "posix": + watchdog_env = { + name: value + for name, value in os.environ.items() + if name in _HANDLER_ENV_ALLOWLIST + } + watchdog_env[_HANDLER_WATCHDOG_FD_ENV] = str(watchdog_read_fd) + self._watchdog_process = subprocess.Popen( + [ + sys.executable, + os.path.abspath(__file__), + "--watch-handler-group", + str(self._process.pid), + ], + stdin=subprocess.DEVNULL, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + close_fds=True, + env=watchdog_env, + start_new_session=True, + pass_fds=(watchdog_read_fd,), + ) + os.close(watchdog_read_fd) + watchdog_read_fd = -1 + self._selector = selectors.DefaultSelector() + stdin_fd = self._process.stdin.fileno() + os.set_blocking(stdin_fd, False) + os.set_blocking(response_read_fd, False) + self._selector.register(response_read_fd, selectors.EVENT_READ, "response") + except Exception: + for fd in ( + locals().get("response_write_fd", -1), + locals().get("parent_watch_read_fd", -1), + locals().get("watchdog_read_fd", -1), + ): + if fd >= 0: + try: + os.close(fd) + except OSError: + pass + # Preserve the construction failure. Cleanup is best effort and + # must not hide the contract error that caused session creation + # to fail. + try: + self.close() + except Exception: + pass + raise + + @property + def should_rollover(self) -> bool: + return ( + self._burst_batches >= DEFAULT_BURST_BATCHES + or self._burst_bytes >= DEFAULT_BURST_BYTES + or time.monotonic() - self._burst_started >= DEFAULT_BURST_SECONDS ) - os.close(response_write_fd) - response_write_fd = -1 - selector = selectors.DefaultSelector() - stdin_fd = process.stdin.fileno() - os.set_blocking(stdin_fd, False) - os.set_blocking(response_read_fd, False) - selector.register(stdin_fd, selectors.EVENT_WRITE, "request") - selector.register(response_read_fd, selectors.EVENT_READ, "response") - while True: - if _context_is_cancelled(context): - raise TimeoutError("DEADLINE_EXCEEDED: handler execution cancelled") - remaining = deadline - time.monotonic() - if remaining <= 0: - raise TimeoutError("DEADLINE_EXCEEDED: handler execution timeout") - events = selector.select(min(remaining, 0.1)) - for event, _ in events: - if event.data == "request": + + def _take_response(self) -> Optional[bytes]: + if len(self._response_buffer) < 8: + return None + expected = struct.unpack(">Q", self._response_buffer[:8])[0] + if expected > MAX_EXECUTION_FRAME_BYTES: + raise ValueError("RESOURCE_EXHAUSTED: execution response is too large") + if len(self._response_buffer) < expected + 8: + return None + payload = bytes(self._response_buffer[8 : expected + 8]) + del self._response_buffer[: expected + 8] + return payload + + def run(self, context, request: Dict[str, Any], timeout_seconds: float) -> bytes: + if self._closed or self._process is None or self._selector is None: + raise ValueError("PROTOCOL: handler session is closed") + # The handler budget is an absolute deadline for the whole request, + # including serialization and the non-blocking write. Starting the + # clock after pickle.dumps would let a large request consume an + # unbounded part of the caller's budget before the deadline was even + # installed. + deadline = time.monotonic() + timeout_seconds + request_wire = pickle.dumps(request, protocol=5) + if time.monotonic() >= deadline: + raise TimeoutError("DEADLINE_EXCEEDED: handler execution timeout") + if len(request_wire) > MAX_EXECUTION_FRAME_BYTES: + raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") + request_frame = struct.pack(">Q", len(request_wire)) + request_wire + request_offset = 0 + stdin_fd = self._process.stdin.fileno() + self._selector.register(stdin_fd, selectors.EVENT_WRITE, "request") + try: + while True: + if _context_is_cancelled(context): + raise TimeoutError("DEADLINE_EXCEEDED: handler execution cancelled") + remaining = deadline - time.monotonic() + if remaining <= 0: + raise TimeoutError("DEADLINE_EXCEEDED: handler execution timeout") + response = self._take_response() + if response is not None: + break + events = self._selector.select(min(remaining, 0.1)) + for event, _ in events: + if event.data == "request": + try: + written = os.write(stdin_fd, request_frame[request_offset:]) + except BlockingIOError: + continue + except BrokenPipeError as exc: + raise ValueError("USER_CODE: handler process closed its request channel") from exc + request_offset += written + if request_offset == len(request_frame): + self._selector.unregister(stdin_fd) + else: + try: + chunk = os.read(self._response_read_fd, 65536) + except BlockingIOError: + continue + if not chunk: + raise ValueError("USER_CODE: handler process exited without a response") + self._response_buffer.extend(chunk) + if self._process.poll() is not None: + if self._process.returncode != 0: + raise ValueError("USER_CODE: handler process exited abnormally") + if _execution_group_alive(self._process): + raise ValueError("USER_CODE: handler process left descendant processes") + raise ValueError("USER_CODE: handler process exited before the burst completed") + if not response: + raise ValueError("PROTOCOL: handler process returned an empty response") + if response[0] == _HANDLER_RESPONSE_ERROR: + try: + message = response[1:].decode("utf-8") + except UnicodeDecodeError as exc: + raise ValueError("PROTOCOL: handler process returned an invalid error") from exc + raise ValueError(message or "USER_CODE: handler process failed") + if response[0] != _HANDLER_RESPONSE_OK: + raise ValueError("PROTOCOL: handler process returned an unknown status") + output = response[1:] + self._burst_batches += 1 + self._burst_bytes += len(request_wire) + len(response) + return output + finally: + # A failed write/read must not leave a stale registration that a + # later close or diagnostic path mistakes for active work. + try: + self._selector.unregister(stdin_fd) + except (KeyError, ValueError): + pass + + def close(self) -> None: + # Mark the session closed before taking the lock so no new batch can + # enter while another terminal path is retrying cleanup. Ownership + # fields are cleared only after their operation succeeds; otherwise a + # transient kill/close error would make a later cleanup call unable to + # find the resource it still owns. + self._closed = True + with self._close_lock: + close_error = None + + def attempt(operation, commit) -> None: + nonlocal close_error + operation_error = None + # Process reaping can race a child exiting and descriptor + # close can transiently fail during RPC teardown. A bounded + # second attempt makes cleanup retryable without turning + # cancellation into an unbounded wait. + for _ in range(2): try: - written = os.write(stdin_fd, request_frame[request_offset:]) - except BlockingIOError: - continue - except BrokenPipeError as exc: - raise ValueError("USER_CODE: handler process closed its request channel") from exc - request_offset += written - if request_offset == len(request_frame): - selector.unregister(stdin_fd) + operation() + commit() + return + except Exception as exc: + operation_error = exc + if close_error is None: + close_error = operation_error + + if self._selector is not None: + selector = self._selector + attempt(selector.close, lambda: setattr(self, "_selector", None)) + if self._parent_watch_write_fd >= 0: + parent_watch_write_fd = self._parent_watch_write_fd + + def close_parent_watch() -> None: + os.close(parent_watch_write_fd) + + attempt( + close_parent_watch, + lambda: setattr(self, "_parent_watch_write_fd", -1), + ) + if self._process is not None: + process = self._process + + def close_process() -> None: + _kill_execution_process(process) + if process.stdin is not None: process.stdin.close() - else: + + attempt(close_process, lambda: setattr(self, "_process", None)) + if self._watchdog_process is not None: + watchdog_process = self._watchdog_process + + def wait_for_watchdog() -> None: try: - chunk = os.read(response_read_fd, 65536) - except BlockingIOError: - continue - if not chunk: - response_eof = True - selector.unregister(response_read_fd) - if expected is None or len(response) < expected + 8: - raise ValueError("USER_CODE: handler process exited without a response") - else: - response.extend(chunk) - if expected is None and len(response) >= 8: - expected = struct.unpack(">Q", response[:8])[0] - if expected > MAX_EXECUTION_FRAME_BYTES: - raise ValueError("RESOURCE_EXHAUSTED: execution response is too large") - if expected is not None and len(response) > expected + 8: - raise ValueError("PROTOCOL: handler process returned trailing response data") - - # A complete frame is not enough. The adapter wrapper must have - # returned normally, and all of its process-group descendants - # must be gone before the adapter accepts the result. - if process.poll() is not None: - if process.returncode != 0: - raise ValueError("USER_CODE: handler process exited abnormally") - if _execution_group_alive(process): - raise ValueError("USER_CODE: handler process left descendant processes") - if response_eof and expected is not None and len(response) == expected + 8: - break - payload = bytes(response[8 : expected + 8]) - if not payload: - raise ValueError("PROTOCOL: handler process returned an empty response") - if payload[0] == _HANDLER_RESPONSE_ERROR: - try: - message = payload[1:].decode("utf-8") - except UnicodeDecodeError as exc: - raise ValueError("PROTOCOL: handler process returned an invalid error") from exc - raise ValueError(message or "USER_CODE: handler process failed") - if payload[0] != _HANDLER_RESPONSE_OK: - raise ValueError("PROTOCOL: handler process returned an unknown status") - return payload[1:] - finally: - if selector is not None: - selector.close() - if process is not None: - _kill_execution_process(process) - if process.stdin is not None: - process.stdin.close() - if response_write_fd >= 0: - os.close(response_write_fd) - os.close(response_read_fd) + watchdog_process.wait(timeout=0.1) + except subprocess.TimeoutExpired: + try: + watchdog_process.kill() + except ProcessLookupError: + pass + watchdog_process.wait(timeout=1.0) + + attempt( + wait_for_watchdog, + lambda: setattr(self, "_watchdog_process", None), + ) + if self._response_read_fd >= 0: + response_read_fd = self._response_read_fd + + def close_response_read() -> None: + os.close(response_read_fd) + + attempt( + close_response_read, + lambda: setattr(self, "_response_read_fd", -1), + ) + # H and the account/owner quota describe a live handler child. A + # failed kill must therefore keep both leases held while this + # session is owned by the pending-cleanup reaper. Releasing them + # merely because the close attempt returned an error would let a + # later invocation exceed the real process budget. The fields are + # cleared only after every process/IPC owner has been cleared. + resources_closed = ( + self._selector is None + and self._process is None + and self._watchdog_process is None + and self._response_read_fd < 0 + and self._parent_watch_write_fd < 0 + ) + if resources_closed and self._slot_acquired: + attempt(self._slots.release, lambda: setattr(self, "_slot_acquired", False)) + quota_lease = getattr(self, "_quota_lease", None) + if resources_closed and quota_lease is not None: + attempt(quota_lease.release, lambda: setattr(self, "_quota_lease", None)) + if close_error is not None: + raise close_error + + +# Keep stable class identities for cleanup ownership checks. Contract tests +# replace the module constructors to inject failures; using the mutable module +# attributes in isinstance() would then turn a valid cleanup path into a +# TypeError and could mask the original exchange outcome. +_EXCHANGE_INPUT_READER_TYPE = _ExchangeInputReader +_HANDLER_PROCESS_SESSION_TYPE = _HandlerProcessSession + + +@dataclass +class _PendingInvocationCleanup: + input_reader: Optional[_ExchangeInputReader] + handler_session: Optional[_HandlerProcessSession] + key: tuple + state: _InvocationState + next_attempt: float + failures: int = 0 + + +def _run_handler_process( + context, request: Dict[str, Any], timeout_seconds: float, + execution_slots: Optional[threading.BoundedSemaphore] = None, +) -> bytes: + session = _HandlerProcessSession(execution_slots) + try: + result = session.run(context, request, timeout_seconds) + except BaseException: + # Preserve the handler/transport failure as the primary diagnosis. + # Cleanup is still mandatory, but a close failure must not replace a + # deadline, user-code, or protocol error and hide the actual cause. + try: + session.close() + except Exception: + logging.exception("Python UDF handler cleanup failed after an execution error") + raise + else: + session.close() + return result @@ -1232,9 +2189,108 @@ def __init__(self, tuple_value: Dict[str, Any], terminal_bytes: int): self.acked_result = 0 self.finish_id: Optional[str] = None self.finish_acked = False + self.finish_sent = False + self.cancelled = False + self.terminal_outcome: Optional[str] = None + + def input_sequence(self) -> int: + with self.condition: + return self.last_input + + def record_input(self, sequence: int) -> None: + with self.condition: + if self.terminal_outcome is not None or self.cancelled: + raise ValueError("PROTOCOL: invocation is already terminal") + if sequence != self.last_input + 1: + raise ValueError("PROTOCOL: input sequence is not contiguous") + self.last_input = sequence + self.condition.notify_all() + + def sequences(self) -> tuple: + with self.condition: + return self.last_input, self.last_result, self.acked_result + + def record_result(self, sequence: int) -> None: + with self.condition: + if self.terminal_outcome is not None or self.cancelled: + raise ValueError("PROTOCOL: invocation is already terminal") + if sequence != self.last_result + 1 or sequence > self.last_input: + raise ValueError("PROTOCOL: result sequence is not contiguous") + self.last_result = sequence + self.condition.notify_all() + + def terminal_snapshot(self) -> tuple: + with self.condition: + outcome = self.terminal_outcome + if outcome is None: + if self.finish_acked: + outcome = _TERMINAL_SUCCESS + elif self.finish_sent: + outcome = _TERMINAL_FINISH_UNCONFIRMED + elif self.cancelled: + outcome = _TERMINAL_CANCELLED + else: + outcome = _TERMINAL_FAILED + return self.last_result, self.finish_id, outcome + + def mark_finish_sent(self, finish_id: str) -> str: + with self.condition: + if self.terminal_outcome is not None or self.cancelled: + raise ValueError("PROTOCOL: invocation is already terminal") + if self.finish_sent or not finish_id: + raise ValueError("PROTOCOL: Finish was already sent") + self.finish_id = finish_id + self.finish_sent = True + return finish_id + + def freeze_terminal(self) -> str: + """Linearize the outcome before the active entry is removed. + + A Finish identifier only proves that the worker emitted Finish. It + does not prove that the peer accepted AcknowledgeFinish. The latter + is the condition for SUCCESS; otherwise a sent Finish is frozen as + FINISH_UNCONFIRMED and cannot be promoted by a late action. + """ + with self.condition: + if self.terminal_outcome is None: + if self.finish_acked: + self.terminal_outcome = _TERMINAL_SUCCESS + elif self.finish_sent: + self.terminal_outcome = _TERMINAL_FINISH_UNCONFIRMED + elif self.cancelled: + self.terminal_outcome = _TERMINAL_CANCELLED + else: + self.terminal_outcome = _TERMINAL_FAILED + return self.terminal_outcome + + def mark_cancelled(self) -> None: + """Freeze cancellation intent before the active lease is removed. + + Cancellation is recorded on the invocation state rather than inferred + from cleanup timing. This lets a concurrent ACK observe the same + terminal gate: an already accepted Finish ACK still wins, while a + result or Finish ACK arriving after cancellation cannot advance the + invocation. + """ + with self.condition: + if self.terminal_outcome is None: + # An accepted Finish ACK is the terminal proof. Cancellation + # may race the transport teardown after that ACK, but it must + # not overwrite SUCCESS or make a later cleanup publish a + # contradictory CANCELLED tombstone. + if self.finish_acked: + return + self.cancelled = True + self.condition.notify_all() def ack_result(self, sequence: int) -> None: with self.condition: + if self.cancelled: + raise ValueError("PROTOCOL: invocation terminal outcome is CANCELLED") + if self.terminal_outcome is not None and self.terminal_outcome != _TERMINAL_SUCCESS: + raise ValueError( + f"PROTOCOL: invocation terminal outcome is {self.terminal_outcome}" + ) if sequence <= 0 or sequence < self.acked_result or sequence > self.last_result: raise ValueError("PROTOCOL: result ACK is outside the received range") self.acked_result = sequence @@ -1252,6 +2308,20 @@ def wait_result_ack(self, sequence: int, context=None) -> None: def ack_finish(self, finish_id: str) -> None: with self.condition: + if self.terminal_outcome is not None: + if self.terminal_outcome == _TERMINAL_SUCCESS and finish_id == self.finish_id: + return + raise ValueError( + f"PROTOCOL: invocation terminal outcome is {self.terminal_outcome}" + ) + # Cancellation may race the response after the peer has already + # accepted this exact Finish ACK. The accepted acknowledgement + # is the terminal proof and remains idempotent; a cancellation + # that won the race before the ACK is still rejected below. + if self.finish_acked and finish_id == self.finish_id: + return + if self.cancelled: + raise ValueError("PROTOCOL: invocation terminal outcome is CANCELLED") if not self.finish_id or finish_id != self.finish_id: raise ValueError("PROTOCOL: invalid finish id") self.finish_acked = True self.condition.notify_all() @@ -1268,13 +2338,44 @@ def wait_finish_ack(self, context=None) -> None: class RoutineFlightServer(flight.FlightServerBase): - def __init__(self, location: str): + def __init__( + self, + location: str, + *, + clock=time.monotonic, + terminal_ttl_seconds=TERMINAL_TTL_SECONDS, + lease_epoch=1, + ): + if isinstance(lease_epoch, bool) or not isinstance(lease_epoch, int) or lease_epoch <= 0 or lease_epoch > (1 << 64) - 1: + raise ValueError("PROTOCOL: invalid worker lease epoch") super().__init__(location) self._lock = threading.RLock() self._active: Dict[tuple, _InvocationState] = {} self._terminal: OrderedDict[tuple, _TerminalRecord] = OrderedDict() self._terminal_bytes = 0 self._active_bytes = 0 + self._active_groups: Dict[str, int] = {} + self._closed_groups: Dict[str, int] = {} + self._closed_group_bytes = 0 + self._reserved_groups = set() + self._reserved_group_bytes = 0 + self._clock = clock + self._terminal_ttl_seconds = terminal_ttl_seconds + self._lease_epoch = lease_epoch + # H is independent from the number of admitted Flight invocations K. + # A rejected acquire fails before the handler process is created and + # therefore cannot accumulate a hidden Python task queue. + self._handler_slots = threading.BoundedSemaphore(MAX_HANDLER_PROCESSES) + self._handler_quota = _HandlerQuota() + # A Flight reader or handler session remains owned by the Flight + # server until every resource close has succeeded. This queue is + # bounded by the active ledger budget, so a transient cleanup failure + # cannot create an unbounded reaper queue or silently release an + # invocation while a native reader or child is still live. + self._pending_cleanup_condition = threading.Condition() + self._pending_cleanups: Dict[tuple, _PendingInvocationCleanup] = {} + self._pending_cleanup_thread: Optional[threading.Thread] = None + self._pending_cleanup_stopping = False @staticmethod def _entry_bytes(key: tuple) -> int: @@ -1285,68 +2386,367 @@ def _entry_bytes(key: tuple) -> int: return len(encoded) + 128 def _purge_terminal_locked(self, now: float) -> None: - expired = [key for key, record in self._terminal.items() if record.expires_at <= now] + expired = [ + key + for key, record in self._terminal.items() + if record.expires_at <= now + and self._closed_groups.get(key[2], 0) >= key[3] + ] for key in expired: record = self._terminal.pop(key) self._terminal_bytes -= record.bytes def _admit(self, key: tuple) -> _InvocationState: size = self._entry_bytes(key) + group_id, group_epoch = key[2], key[3] with self._lock: - self._purge_terminal_locked(time.monotonic()) + if self._closed_groups.get(group_id, 0) >= group_epoch: + raise ValueError("PROTOCOL: execution group epoch is already closed") + self._purge_terminal_locked(self._clock()) if key in self._active: raise ValueError("PROTOCOL: invocation fence is active") if key in self._terminal: raise ValueError("PROTOCOL: invocation fence is terminal") + if group_id in self._active_groups: + raise ValueError("PROTOCOL: execution group epoch is already active") if len(self._active) + len(self._terminal) >= MAX_LEDGER_ENTRIES: raise ValueError("RESOURCE_EXHAUSTED: terminal ledger entries are full") if self._active_bytes + self._terminal_bytes + size > MAX_LEDGER_BYTES: raise ValueError("RESOURCE_EXHAUSTED: terminal ledger bytes are full") + if group_id not in self._closed_groups and group_id not in self._reserved_groups: + fence_bytes = len(group_id.encode("utf-8")) + 8 + if ( + len(self._closed_groups) + len(self._reserved_groups) + >= MAX_CLOSED_GROUP_ENTRIES + or self._closed_group_bytes + self._reserved_group_bytes + fence_bytes + > MAX_CLOSED_GROUP_BYTES + ): + raise ValueError("RESOURCE_EXHAUSTED: closed-group fence is full") + # Reserve the future tombstone before creating the handler. + # Terminal cleanup converts this reservation into the + # closed-generation fence. + self._reserved_groups.add(group_id) + self._reserved_group_bytes += fence_bytes state = _InvocationState({}, size) self._active[key] = state self._active_bytes += size + self._active_groups[group_id] = group_epoch return state + def _require_current_lease(self, key: tuple) -> None: + if key[5] != self._lease_epoch: + raise ValueError( + "STALE_LEASE_EPOCH: invocation belongs to a different worker instance" + ) + def _remember_terminal_locked(self, key: tuple, state: _InvocationState) -> None: - deadline = time.monotonic() + TERMINAL_TTL_SECONDS + deadline = self._clock() + self._terminal_ttl_seconds + last_result, finish_id, outcome = state.terminal_snapshot() self._terminal[key] = _TerminalRecord( - deadline, state.terminal_bytes, state.last_result, state.finish_id + deadline, state.terminal_bytes, last_result, finish_id, outcome ) self._terminal.move_to_end(key) self._terminal_bytes += state.terminal_bytes + def _close_group_epoch_locked(self, key: tuple) -> None: + group_id, group_epoch = key[2], key[3] + current = self._closed_groups.get(group_id, 0) + if group_epoch <= current: + return + if group_id not in self._closed_groups: + fence_bytes = len(group_id.encode("utf-8")) + 8 + if group_id in self._reserved_groups: + self._reserved_groups.remove(group_id) + self._reserved_group_bytes -= fence_bytes + elif ( + len(self._closed_groups) >= MAX_CLOSED_GROUP_ENTRIES + or self._closed_group_bytes + fence_bytes > MAX_CLOSED_GROUP_BYTES + ): + # This is only reachable for state restored from an adapter + # predating group-fence reservations. Keep the terminal record + # and refuse collection until the fence is reconstructed. + return + self._closed_group_bytes += fence_bytes + self._closed_groups[group_id] = group_epoch + def _finish_invocation(self, key: tuple, state: Optional[_InvocationState]) -> None: # A rejected duplicate Open has no ownership of the existing state. # Cleanup must therefore be identity based, not key based. if key is None or state is None: return + state.freeze_terminal() with self._lock: current = self._active.get(key) if current is not state: return self._active.pop(key, None) self._active_bytes -= state.terminal_bytes + group_id, group_epoch = key[2], key[3] + if self._active_groups.get(group_id) == group_epoch: + self._active_groups.pop(group_id, None) # A started invocation is terminal even when the worker reports an # error. Retaining the fence prevents a late retry from running # user code a second time. self._remember_terminal_locked(key, state) + # The current Gateway contract uses one member per group. The + # worker records that owner closure before allowing TTL collection; + # a future multi-member scheduler must send an explicit group + # closure before reusing this hook. + self._close_group_epoch_locked(key) + + def _ensure_pending_cleanup_thread_locked(self) -> None: + thread = self._pending_cleanup_thread + if thread is not None and thread.is_alive(): + return + thread = threading.Thread( + target=self._pending_cleanup_loop, + name="matrixone-python-udf-cleanup", + daemon=True, + ) + self._pending_cleanup_thread = thread + thread.start() + + def _retain_pending_cleanup( + self, + input_reader: Optional[_ExchangeInputReader], + handler_session: Optional[_HandlerProcessSession], + key: Optional[tuple], + state: Optional[_InvocationState], + ) -> bool: + """Retain exchange resources until every cleanup operation succeeds.""" + if key is None or state is None or (input_reader is None and handler_session is None): + return False + with self._pending_cleanup_condition: + existing = self._pending_cleanups.get(key) + if existing is not None: + return True + if len(self._pending_cleanups) >= MAX_PENDING_CLEANUPS: + # An admitted invocation must not lose its cleanup owner. A + # full queue is an adapter invariant violation; keeping the + # invocation active is safer than pretending ownership was + # released. + logging.critical( + "Python UDF pending cleanup capacity is full for %r", + key, + ) + return False + self._pending_cleanups[key] = _PendingInvocationCleanup( + input_reader=input_reader, + handler_session=handler_session, + key=key, + state=state, + next_attempt=time.monotonic(), + ) + self._ensure_pending_cleanup_thread_locked() + self._pending_cleanup_condition.notify_all() + return True + + def _pending_cleanup_loop(self) -> None: + while True: + with self._pending_cleanup_condition: + while True: + if self._pending_cleanup_stopping and not self._pending_cleanups: + return + if not self._pending_cleanups: + self._pending_cleanup_condition.wait() + continue + now = time.monotonic() + ready = [ + item for item in self._pending_cleanups.values() + if item.next_attempt <= now + ] + if ready: + break + wait_for = min( + item.next_attempt + for item in self._pending_cleanups.values() + ) - now + self._pending_cleanup_condition.wait(max(0.01, wait_for)) + + for item in ready: + errors = [] + if item.input_reader is not None: + try: + item.input_reader.close() + except Exception as exc: + errors.append(exc) + else: + with self._pending_cleanup_condition: + current = self._pending_cleanups.get(item.key) + if current is item: + item.input_reader = None + if item.handler_session is not None: + try: + item.handler_session.close() + except Exception as exc: + errors.append(exc) + else: + with self._pending_cleanup_condition: + current = self._pending_cleanups.get(item.key) + if current is item: + item.handler_session = None + if errors: + exc = errors[0] + item.failures += 1 + delay = min( + PENDING_HANDLER_CLEANUP_MAX_DELAY, + PENDING_HANDLER_CLEANUP_INITIAL_DELAY + * (2 ** min(item.failures, 5)), + ) + with self._pending_cleanup_condition: + current = self._pending_cleanups.get(item.key) + if current is item: + item.next_attempt = time.monotonic() + delay + self._pending_cleanup_condition.notify_all() + logging.error( + "Python UDF exchange cleanup retry failed for %r: %s", + item.key, + exc, + ) + continue + + # The session is now fully closed. Only then can the + # invocation owner release K, the ledger entry, and the group + # fence. _finish_invocation is idempotent with respect to any + # late ACK that arrived while the cleanup was pending. + finish_error = None + try: + self._finish_invocation(item.key, item.state) + except Exception as exc: + finish_error = exc + with self._pending_cleanup_condition: + current = self._pending_cleanups.get(item.key) + if current is item and finish_error is None: + del self._pending_cleanups[item.key] + elif current is item: + item.failures += 1 + item.next_attempt = time.monotonic() + PENDING_HANDLER_CLEANUP_MAX_DELAY + self._pending_cleanup_condition.notify_all() + if finish_error is not None: + logging.error( + "Python UDF invocation cleanup retry failed for %r: %s", + item.key, + finish_error, + ) + + def shutdown(self): + result = super().shutdown() + with self._pending_cleanup_condition: + self._pending_cleanup_stopping = True + self._pending_cleanup_condition.notify_all() + thread = self._pending_cleanup_thread + if thread is not None: + # Normal shutdown has no pending sessions and joins immediately. + # A persistent OS/resource failure remains owned by the daemon + # reaper; the handler's parent-liveness pipe still guarantees + # child-group cleanup if this worker process exits. + thread.join(timeout=2.0) + with self._pending_cleanup_condition: + pending = len(self._pending_cleanups) + if pending: + logging.error( + "Python UDF worker shutdown left %d handler cleanups pending", + pending, + ) + return result + + def _cleanup_exchange( + self, + key: Optional[tuple], + state: Optional[_InvocationState], + input_reader, + handler_session, + ) -> Optional[Exception]: + """Run every exchange cleanup step and return its first error. + + Closing a native Flight reader or a handler process is allowed to + fail while an RPC is already being cancelled. Those failures must + not skip the invocation fence cleanup: otherwise K, handler slots, + group reservations, and terminal de-duplication can disagree about + whether the invocation still owns resources. The caller decides + whether a cleanup error should replace an existing exchange error. + """ + cleanup_error: Optional[Exception] = None + + def close_with_retry(resource) -> tuple[bool, Optional[Exception]]: + last_error = None + for _ in range(2): + try: + resource.close() + return True, None + except Exception as exc: + last_error = exc + return False, last_error + + input_cleanup_succeeded = input_reader is None + if input_reader is not None: + input_cleanup_succeeded, cleanup_error = close_with_retry(input_reader) + + handler_cleanup_succeeded = handler_session is None + handler_error = None + if handler_session is not None: + handler_cleanup_succeeded, handler_error = close_with_retry(handler_session) + if cleanup_error is None: + cleanup_error = handler_error + + # Real native readers and process sessions retain ownership when close + # fails. Test doubles deliberately keep the old direct-cleanup + # behaviour so the helper tests do not create a false production + # resource owner. + pending_reader = ( + input_reader + if isinstance(input_reader, _EXCHANGE_INPUT_READER_TYPE) and not input_cleanup_succeeded + else None + ) + pending_session = ( + handler_session + if isinstance(handler_session, _HANDLER_PROCESS_SESSION_TYPE) and not handler_cleanup_succeeded + else None + ) + if pending_reader is None and pending_session is None: + try: + self._finish_invocation(key, state) + except Exception as exc: + if cleanup_error is None: + cleanup_error = exc + elif not self._retain_pending_cleanup(pending_reader, pending_session, key, state): + # Keep the invocation active if no cleanup owner could be + # registered. Returning the error makes the failure visible and + # prevents a false terminal record from authorizing a retry. + if cleanup_error is None: + cleanup_error = RuntimeError( + "Python UDF exchange cleanup owner could not be retained" + ) + return cleanup_error def do_action(self, context, action): + if action.type == "GetPythonCapabilities": + request = _decode_capability_request(action.body) + # pyarrow exposes Result as a one positional-buffer value across + # supported releases; using a keyword here breaks the real Flight + # path before any routine is opened. + yield flight.Result(_encode_capabilities(request, self._lease_epoch)) + return control = _decode_control(action.body) key = _tuple_key(control["tuple"]) + self._require_current_lease(key) if action.type not in ("AcknowledgeResults", "AcknowledgeFinish"): raise ValueError("PROTOCOL: unknown action") if control["kind"] != action.type: raise ValueError("PROTOCOL: action kind does not match action type") with self._lock: - self._purge_terminal_locked(time.monotonic()) + self._purge_terminal_locked(self._clock()) state = self._active.get(key) terminal = self._terminal.get(key) if state is None: if terminal is None: raise ValueError("PROTOCOL: unknown invocation") + if terminal.outcome != _TERMINAL_SUCCESS: + raise ValueError( + f"PROTOCOL: invocation terminal outcome is {terminal.outcome}" + ) if not terminal.finish_id: - raise ValueError("PROTOCOL: invocation did not complete successfully") + raise ValueError("PROTOCOL: successful invocation has no Finish") if action.type == "AcknowledgeResults": sequence = _required_uint64(control, "ack_sequence") if sequence != terminal.last_result: @@ -1375,6 +2775,8 @@ def _ack_control(control: Dict[str, Any]) -> Dict[str, Any]: def do_exchange(self, context, descriptor, reader, writer): state = None key = None + handler_session = None + input_reader = None writer_started = False try: command = getattr(descriptor, "command", None) @@ -1385,21 +2787,56 @@ def do_exchange(self, context, descriptor, reader, writer): if not isinstance(open_control.get("payload"), dict): raise ValueError("PROTOCOL: invocation payload must be an object") key = _tuple_key(open_control["tuple"]) + self._require_current_lease(key) payload = open_control["payload"] + unknown_payload = set(payload) - _OPEN_PAYLOAD_KEYS + missing_payload = _OPEN_PAYLOAD_REQUIRED_KEYS - set(payload) + if unknown_payload: + raise ValueError("PROTOCOL: unsupported invocation payload field") + if missing_payload: + raise ValueError("PROTOCOL: invocation payload is missing a required field") + _validate_typed_call_contract(payload) + _function_ref(payload.get("function_ref"), open_control["tuple"]) args = payload.get("args") result_descriptor = payload.get("return") if not isinstance(args, list) or any(not isinstance(item, dict) for item in args): raise ValueError("PROTOCOL: invocation args must be an array of descriptors") if not isinstance(result_descriptor, dict): raise ValueError("PROTOCOL: invocation return must be a descriptor") - statement_context = _statement_context(payload.get("context")) + context_values = payload.get("context") + statement_context = _statement_context(context_values) + typed_context_values = _typed_statement_context(payload.get("statement_context")) + if typed_context_values is None: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: missing typed statement context") + typed_statement_context = _statement_context(typed_context_values) + if statement_context is not None and statement_context != typed_statement_context: + raise ValueError("PROTOCOL: typed statement context does not match context") + statement_context = typed_statement_context + effective_context = dict(context_values or {}) + # The typed form is the canonical wire representation. The + # trusted CN map predates it and may use equivalent textual + # encodings such as "+480" for a fixed offset. The parsed + # StatementContext comparison above rejects semantic drift; + # overwrite the handler-facing map with canonical values so + # equivalent encodings do not become a false protocol error. + effective_context.update(typed_context_values) mode = _required_string(payload, "mode") null_policy = _required_string(payload, "null_policy") abi_contract = _required_string(payload, "abi_contract") adapter_version = _required_string(payload, "adapter_version") sdk_version = _required_string(payload, "sdk_version") + definition_schema_version = payload.get("definition_schema_version") + if type(definition_schema_version) is not int or definition_schema_version != DEFINITION_SCHEMA_VERSION: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported Python definition schema") + artifact_digest = _required_digest(payload, "artifact_digest") + environment_digest = _required_digest(payload, "environment_digest") + definition_fingerprint = _required_digest(payload, "definition_fingerprint") max_batch_bytes = _required_positive_int(payload, "max_batch_bytes", 1 << 30) max_batch_rows = _required_positive_int(payload, "max_batch_rows", 1 << 30) + max_invocation_rows = _required_positive_int(payload, "max_invocation_rows", 1 << 32) + max_invocation_result_bytes = _required_positive_int( + payload, "max_invocation_result_bytes", 1 << 40 + ) handler_timeout_seconds = _required_positive_float( payload, "handler_timeout_seconds", 3600.0 ) @@ -1408,12 +2845,21 @@ def do_exchange(self, context, descriptor, reader, writer): if sdk_version != SDK_VERSION: raise ValueError("PROTOCOL: unsupported Python SDK") source = _required_string(payload, "source") handler_name = _required_string(payload, "handler") + if artifact_digest != _inline_artifact_digest(handler_name, source): + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the source") + if environment_digest != _environment_digest(): + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the worker contract") # Validate the complete frozen type contract before reserving a # ledger entry. A malformed Open is rejected before it can leave # a terminal tombstone behind. for index, descriptor in enumerate(args): _field(f"arg_{index}", descriptor) result_field = _field("result", result_descriptor) + expected_fingerprint = _definition_fingerprint(payload) + if definition_fingerprint != expected_fingerprint: + raise ValueError( + "UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition" + ) state = self._admit(key) state.tuple = open_control["tuple"] schema = None @@ -1422,11 +2868,20 @@ def do_exchange(self, context, descriptor, reader, writer): writer_started = True writer.write_metadata(_encode_control({"kind": "ResultSchema", "tuple": open_control["tuple"]})) ended = False + invocation_rows = 0 + invocation_result_bytes = 0 + input_reader = _ExchangeInputReader(reader) while True: try: - chunk = reader.read_chunk() + chunk = input_reader.next(context) except StopIteration: break + # The reader can publish a chunk at the same instant that the + # RPC is cancelled. Re-check after the blocking handoff so a + # chunk already dequeued after cancellation cannot start user + # code or consume another handler slot. + if _context_is_cancelled(context): + raise TimeoutError("DEADLINE_EXCEEDED: input stream cancelled") if chunk is None or (chunk.data is None and not chunk.app_metadata): raise ValueError("PROTOCOL: empty input frame") if chunk.data is not None: @@ -1441,25 +2896,45 @@ def do_exchange(self, context, descriptor, reader, writer): _require_tuple(control["tuple"], open_control["tuple"]) if control["kind"] != "InputBatch": raise ValueError("PROTOCOL: data batch is missing InputBatch") sequence = _required_uint64(control, "sequence") - if sequence != state.last_input + 1: raise ValueError("PROTOCOL: input sequence is not contiguous") + if sequence != state.input_sequence() + 1: raise ValueError("PROTOCOL: input sequence is not contiguous") if batch.num_rows <= 0: raise ValueError("PROTOCOL: empty input batch") if batch.num_rows > max_batch_rows: raise ValueError("RESOURCE_EXHAUSTED: input batch has too many rows") + if invocation_rows > max_invocation_rows - batch.num_rows: + raise ValueError("RESOURCE_EXHAUSTED: invocation has too many rows") if batch.nbytes > max_batch_bytes: raise ValueError("RESOURCE_EXHAUSTED: input batch exceeds byte limit") for index, descriptor in enumerate(args): _validate_array_values(batch.column(index), descriptor) + state.record_input(sequence) execution_request = { "source": source, "handler": handler_name, "mode": mode, "null_policy": null_policy, + "abi_contract": abi_contract, + "adapter_version": adapter_version, "sdk_version": sdk_version, - "context": payload.get("context"), + "definition_schema_version": definition_schema_version, + "artifact_digest": artifact_digest, + "environment_digest": environment_digest, + "definition_fingerprint": definition_fingerprint, + "context": effective_context, "args": args, "return": result_descriptor, "max_batch_bytes": max_batch_bytes, + "max_batch_rows": max_batch_rows, + "max_invocation_rows": max_invocation_rows, + "max_invocation_result_bytes": max_invocation_result_bytes, "input": _serialize_record_batch(batch), } - output_wire = _run_handler_process( + if handler_session is None: + owner_id = _handler_quota_owner(payload) + handler_session = _HandlerProcessSession( + self._handler_slots, + handler_quota=self._handler_quota, + account_id=key[0], + owner_id=owner_id, + ) + output_wire = handler_session.run( context, execution_request, handler_timeout_seconds ) output_batch = _deserialize_record_batch(output_wire) @@ -1470,21 +2945,40 @@ def do_exchange(self, context, descriptor, reader, writer): _validate_array_values(output_array, result_descriptor) if pa.ipc.get_record_batch_size(output_batch) > max_batch_bytes: raise ValueError("RESOURCE_EXHAUSTED: output batch exceeds byte limit") - state.last_input = sequence - state.last_result = sequence - writer.write_metadata(_encode_control({"kind": "InputConsumed", "tuple": open_control["tuple"], "sequence": sequence})) + invocation_result_bytes += pa.ipc.get_record_batch_size(output_batch) + if invocation_result_bytes > max_invocation_result_bytes: + raise ValueError("RESOURCE_EXHAUSTED: invocation result exceeds byte limit") + invocation_rows += batch.num_rows + state.record_result(sequence) + writer.write_metadata(_encode_control({ + "kind": "InputConsumed", + "tuple": open_control["tuple"], + "sequence": sequence, + # This is the decoded Arrow backing released by the + # worker after the handler has returned. It is bounded + # by max_batch_bytes and is distinct from the CN's + # transport framing bytes. A zero-column batch has + # no value buffers, but still consumes one logical + # accounting unit so the positive-credit protocol + # remains valid for zero-argument VECTOR calls. + "released_bytes": max(int(batch.nbytes), 1), + "released_batches": 1, + })) writer.write_with_metadata(output_batch, _encode_control({"kind": "ResultBatch", "tuple": open_control["tuple"], "sequence": sequence})) state.wait_result_ack(sequence, context) + if handler_session.should_rollover: + handler_session.close() + handler_session = None elif chunk.app_metadata: control = _decode_control(chunk.app_metadata) _require_tuple(control["tuple"], open_control["tuple"]) if control["kind"] == "EndInput": last_sequence = _required_uint64(control, "last_sequence", allow_zero=True) if ended: - if last_sequence != state.last_input: + if last_sequence != state.input_sequence(): raise ValueError("PROTOCOL: EndInput changed after input was closed") continue - if last_sequence != state.last_input: + if last_sequence != state.input_sequence(): raise ValueError("PROTOCOL: invalid EndInput") ended = True elif control["kind"] == "OpenInvocation": @@ -1492,11 +2986,21 @@ def do_exchange(self, context, descriptor, reader, writer): else: raise ValueError("PROTOCOL: unexpected control without Arrow data") if not ended: raise ValueError("PROTOCOL: input stream ended before EndInput") - if state.acked_result != state.last_result: raise ValueError("PROTOCOL: result is not acknowledged") - state.finish_id = _uuid.uuid4().hex - writer.write_metadata(_encode_control({"kind": "Finish", "tuple": open_control["tuple"], "status": "OK", "finish_id": state.finish_id, "last_sequence": state.last_input})) + last_input, last_result, acked_result = state.sequences() + if acked_result != last_result: raise ValueError("PROTOCOL: result is not acknowledged") + finish_id = state.mark_finish_sent(_uuid.uuid4().hex) + writer.write_metadata(_encode_control({ + "kind": "Finish", + "tuple": open_control["tuple"], + "status": "OK", + "finish_id": finish_id, + "last_sequence": last_input, + "last_result_sequence": last_result, + })) state.wait_finish_ack(context) except Exception as exc: + if state is not None and _is_cancellation_error(exc, context): + state.mark_cancelled() if writer_started and key is not None: try: writer.write_metadata(_encode_control({"kind": "Error", "tuple": open_control["tuple"], "status": "ERROR", "reason": _safe_error(exc)})) @@ -1504,7 +3008,26 @@ def do_exchange(self, context, descriptor, reader, writer): pass raise finally: - self._finish_invocation(key, state) + exchange_error = sys.exc_info()[1] + cleanup_error = self._cleanup_exchange( + key, state, input_reader, handler_session + ) + if cleanup_error is not None and exchange_error is None: + raise cleanup_error + if cleanup_error is not None: + logging.error( + "Python UDF exchange cleanup failed after an exchange error: %s", + cleanup_error, + ) + + +def _is_cancellation_error(exc: Exception, context) -> bool: + if _context_is_cancelled(context): + return True + # Handler, result-ACK, and Finish-ACK deadlines use this stable protocol + # category. Once observed, they are a cancellation terminal outcome even + # if the transport context has not yet reported cancellation locally. + return isinstance(exc, TimeoutError) and str(exc).startswith("DEADLINE_EXCEEDED:") def _safe_error(exc: Exception) -> str: @@ -1518,16 +3041,32 @@ def _safe_error(exc: Exception) -> str: def main() -> None: parser = argparse.ArgumentParser() parser.add_argument("--execute-handler", action="store_true") + parser.add_argument("--watch-handler-group", type=int) parser.add_argument("--address") args = parser.parse_args() if args.execute_handler: _execute_handler_subprocess() return + if args.watch_handler_group is not None: + watchdog_fd_text = os.environ.pop(_HANDLER_WATCHDOG_FD_ENV, None) + if watchdog_fd_text is None: + parser.error("--watch-handler-group requires a watchdog pipe") + try: + watchdog_fd = int(watchdog_fd_text) + except ValueError: + parser.error("invalid watchdog pipe") + _watch_handler_group(watchdog_fd, args.watch_handler_group) + return if not args.address: parser.error("--address is required for the Flight server") logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(levelname)s %(message)s") address = args.address if "://" in args.address else "grpc://" + args.address - server = RoutineFlightServer(address) + # Every worker process is a distinct execution owner. A random positive + # epoch prevents a restarted worker at the same endpoint from accepting + # control messages issued to the previous process. Direct unit-test + # servers keep the deterministic default of one. + lease_epoch = secrets.randbits(63) or 1 + server = RoutineFlightServer(address, lease_epoch=lease_epoch) server.serve() diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go new file mode 100644 index 0000000000000..c9a12dd2eaa61 --- /dev/null +++ b/pkg/udf/python_contract.go @@ -0,0 +1,86 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package udf + +import ( + "crypto/sha256" + "encoding/binary" + "encoding/hex" + "fmt" + + "github.com/matrixorigin/matrixone/pkg/udf/protocol" +) + +const ( + pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" + pythonEnvironmentDigestDomain = "matrixone-python-environment" +) + +// PythonInlineArtifactDigest identifies the exact source payload sent to the +// worker. Length-prefixing each UTF-8 string prevents delimiter ambiguity and +// gives the Python adapter an unambiguous, language-independent algorithm. +func PythonInlineArtifactDigest(handler, source string) string { + return pythonContractDigest(pythonInlineArtifactDigestDomain, handler, source) +} + +// PythonEnvironmentDigest identifies the worker-side contract that interprets +// an inline source definition. The current environment plane is deliberately +// small: the executable artifact is inline, while the ABI, plan, type and +// timezone contracts are fixed by the negotiated worker capability. A future +// artifact store may add its immutable environment digest without changing +// this current digest algorithm. +func PythonEnvironmentDigest() (string, error) { + tzVersion, err := TimezoneDatabaseVersion() + if err != nil { + return "", err + } + return pythonContractDigest( + pythonEnvironmentDigestDomain, + fmt.Sprintf("%d", protocol.Version), + PythonABIContract, + PythonAdapterVersion, + PythonSDKVersion, + fmt.Sprintf("%d", PythonDefinitionSchemaVersion), + fmt.Sprintf("%d", PythonPlanContractVersion), + PythonTypeDescriptorContract, + tzVersion, + ), nil +} + +// IsSHA256Digest is used at execution boundaries for persisted digests and +// fingerprints. It accepts the canonical lower-case hexadecimal spelling +// only, so malformed or alternate encodings cannot create ambiguous identity. +func IsSHA256Digest(value string) bool { + if len(value) != sha256.Size*2 { + return false + } + decoded, err := hex.DecodeString(value) + if err != nil || len(decoded) != sha256.Size { + return false + } + for _, ch := range value { + if ch >= 'A' && ch <= 'F' { + return false + } + } + return true +} + +func pythonContractDigest(domain string, parts ...string) string { + hash := sha256.New() + writePythonDigestPart(hash, domain) + for _, part := range parts { + writePythonDigestPart(hash, part) + } + return hex.EncodeToString(hash.Sum(nil)) +} + +func writePythonDigestPart(hash interface{ Write([]byte) (int, error) }, value string) { + var length [8]byte + binary.BigEndian.PutUint64(length[:], uint64(len(value))) + _, _ = hash.Write(length[:]) + _, _ = hash.Write([]byte(value)) +} diff --git a/pkg/udf/python_contract_test.go b/pkg/udf/python_contract_test.go new file mode 100644 index 0000000000000..1f9edd7070603 --- /dev/null +++ b/pkg/udf/python_contract_test.go @@ -0,0 +1,28 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package udf + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPythonInlineArtifactDigestMatchesCrossLanguageVector(t *testing.T) { + const want = "d3b06769662f0e30fca60e6dedc479c5aacef6c488c6489366fdb540ee374f26" + require.Equal(t, want, PythonInlineArtifactDigest("add", "def add(ctx, value): return value")) + require.True(t, IsSHA256Digest(want)) + require.False(t, IsSHA256Digest("D3B06769662F0E30FCA60E6DED C479C5AACEF6C488C6489366FDB540EE374F26")) +} + +func TestPythonEnvironmentDigestIsCurrentAndStable(t *testing.T) { + first, err := PythonEnvironmentDigest() + require.NoError(t, err) + second, err := PythonEnvironmentDigest() + require.NoError(t, err) + require.Equal(t, first, second) + require.True(t, IsSHA256Digest(first)) +} diff --git a/pkg/udf/runtime.go b/pkg/udf/runtime.go index 5df11f7a374de..3c92e352a560d 100644 --- a/pkg/udf/runtime.go +++ b/pkg/udf/runtime.go @@ -20,8 +20,12 @@ package udf import ( "context" + "encoding/json" "errors" + "fmt" "sort" + "strconv" + "strings" "sync" "github.com/matrixorigin/matrixone/pkg/common/moerr" @@ -32,18 +36,178 @@ import ( ) const ( + LanguageSQL = "sql" LanguagePython = "python" PythonABIContract = "PYTHON_ARROW" PythonAdapterVersion = "2026-09" PythonSDKVersion = "1.0" - NullCallHandler = "CALLED_ON_NULL_INPUT" - NullReturnNull = "RETURNS_NULL_ON_NULL_INPUT" + // These numeric contracts are persisted in catalog and plan records. They + // are intentionally separate from the human-facing adapter/SDK names: + // changing a wire or persistent shape must fail closed before user code is + // entered, even when the runtime happens to use the same language ABI name. + SQLDefinitionSchemaVersion = 1 + RoutinePlanContractVersion = 1 + PythonDefinitionSchemaVersion = 1 + // Kept as a source-compatible alias for the Python adapter while the + // plan field is shared by SQL and Python routine calls. + PythonPlanContractVersion = RoutinePlanContractVersion + // PythonSignatureKeySchemaVersion versions the canonical descriptor + // encoding stored on the shared Function identity. It is independent of + // the implementation body schema: changing the overload key is an + // identity/catalog migration, while changing the body is a revision. + PythonSignatureKeySchemaVersion = 1 + PythonTypeDescriptorContract = "ARROW_DESCRIPTOR" + NullCallHandler = "CALLED_ON_NULL_INPUT" + NullReturnNull = "RETURNS_NULL_ON_NULL_INPUT" + StatementContextContractVersion = 1 + SecurityFrameContractVersion = 1 ) +// StatementContext is the typed execution-time snapshot visible to a Python +// handler. It is intentionally separate from plan metadata: a prepared plan +// may be reused by many statements, while these values are frozen once per +// execution. The JSON form is also the cross-process contract used by the +// Gateway and worker. +type StatementContext struct { + ContractVersion int `json:"contract_version"` + StatementTimestampUTC int64 `json:"statement_timestamp_utc"` + TimezoneKind string `json:"timezone_kind"` + TimezoneName string `json:"timezone_name,omitempty"` + TimezoneOffsetMinutes int32 `json:"timezone_offset_minutes"` + TimezoneDatabaseVersion string `json:"timezone_database_version,omitempty"` + SQLMode []string `json:"sql_mode"` + CurrentDatabase string `json:"current_database,omitempty"` + CurrentUser string `json:"current_user"` + CurrentRole string `json:"current_role,omitempty"` + ConnectionCollation string `json:"connection_collation"` +} + +func (c StatementContext) Validate() error { + if c.ContractVersion != StatementContextContractVersion { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported statement context contract %d", c.ContractVersion) + } + if c.CurrentUser == "" || c.ConnectionCollation == "" { + return fmt.Errorf("python udf: statement context has no authenticated user or collation") + } + if c.TimezoneKind == "IANA" { + if c.TimezoneName == "" || c.TimezoneDatabaseVersion == "" || c.TimezoneOffsetMinutes != 0 { + return fmt.Errorf("python udf: IANA statement timezone is incomplete") + } + } else if c.TimezoneKind == "FIXED_OFFSET" { + if c.TimezoneName != "" || c.TimezoneDatabaseVersion != "" || c.TimezoneOffsetMinutes < -839 || c.TimezoneOffsetMinutes > 840 { + return fmt.Errorf("python udf: fixed statement timezone is invalid") + } + } else { + return fmt.Errorf("python udf: unsupported statement timezone kind %q", c.TimezoneKind) + } + mode := append([]string(nil), c.SQLMode...) + sort.Strings(mode) + for i := range mode { + if mode[i] == "" || (i > 0 && mode[i] == mode[i-1]) { + return fmt.Errorf("python udf: statement sql_mode is not canonical") + } + } + if len(mode) != len(c.SQLMode) { + return fmt.Errorf("python udf: statement sql_mode is not canonical") + } + for i := range mode { + if mode[i] != c.SQLMode[i] { + return fmt.Errorf("python udf: statement sql_mode is not sorted") + } + } + return nil +} + +// StatementContextFromMap is the only adapter from the legacy internal map +// assembled by the SQL session to the typed runtime contract. It accepts the +// map solely at the trusted CN boundary and returns nil when no statement +// fields are present, which keeps transport/protocol unit tests able to test +// zero-row admission without manufacturing session state. +func StatementContextFromMap(values map[string]string) (*StatementContext, error) { + if len(values) == 0 { + return nil, nil + } + statementKeys := []string{ + "statement_timestamp_utc", "session_timezone_kind", "session_timezone_name", + "session_timezone_offset_minutes", "session_timezone_tzdb_version", "sql_mode", + "current_database", "current_user", "current_role", "connection_collation", + } + present := false + for _, key := range statementKeys { + if _, ok := values[key]; ok { + present = true + break + } + } + if !present { + return nil, nil + } + timestamp, err := strconv.ParseInt(values["statement_timestamp_utc"], 10, 64) + if err != nil { + return nil, fmt.Errorf("python udf: invalid statement timestamp: %w", err) + } + mode := make([]string, 0) + if raw := values["sql_mode"]; raw != "" { + if err := json.Unmarshal([]byte(raw), &mode); err != nil { + return nil, fmt.Errorf("python udf: invalid statement sql_mode: %w", err) + } + } + context := &StatementContext{ + ContractVersion: StatementContextContractVersion, + StatementTimestampUTC: timestamp, + TimezoneKind: strings.ToUpper(values["session_timezone_kind"]), + TimezoneName: values["session_timezone_name"], + SQLMode: mode, + CurrentDatabase: values["current_database"], + CurrentUser: values["current_user"], + CurrentRole: values["current_role"], + ConnectionCollation: values["connection_collation"], + TimezoneDatabaseVersion: values["session_timezone_tzdb_version"], + } + if raw := values["session_timezone_offset_minutes"]; raw != "" { + offset, parseErr := strconv.ParseInt(raw, 10, 32) + if parseErr != nil { + return nil, fmt.Errorf("python udf: invalid fixed timezone offset: %w", parseErr) + } + context.TimezoneOffsetMinutes = int32(offset) + } + if err := context.Validate(); err != nil { + return nil, err + } + return context, nil +} + +// SecurityFrame records the principal entering this routine layer. Python +// currently supports INVOKER only, so the effective IDs must equal the +// invoker IDs. The explicit frame prevents a future definer implementation +// from silently reusing the outer session's principal. +type SecurityFrame struct { + ContractVersion int `json:"contract_version"` + Mode string `json:"mode"` + InvokerUserID uint32 `json:"invoker_user_id"` + InvokerRoleID uint32 `json:"invoker_role_id"` + EffectiveUserID uint32 `json:"effective_user_id"` + EffectiveRoleID uint32 `json:"effective_role_id"` +} + +func (f SecurityFrame) Validate() error { + if f.ContractVersion != SecurityFrameContractVersion || f.Mode != "INVOKER" { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python security frame") + } + if f.InvokerUserID != f.EffectiveUserID || f.InvokerRoleID != f.EffectiveRoleID { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invoker security frame changed effective principal") + } + return nil +} + // Invocation is the language-neutral routine call handed to an admitted // runtime. The runtime owns transport, worker lifecycle, and Arrow // conversion; CN owns the SQL vectors, result wrapper, and fencing identity. type Invocation struct { + // Function identity and revision are copied from the typed plan. They are + // part of the execution grant sent to the worker; the runtime never + // resolves a function name or latest revision. + FunctionRef FunctionRef Language string Handler string Source string @@ -56,8 +220,40 @@ type Invocation struct { ABIContract string AdapterVersion string SDKVersion string - Context map[string]string - Tuple protocol.FencingTuple + // These values are copied from the immutable typed implementation. The + // gateway and worker validate them before opening user code; they are not + // inferred from a mutable source path or a function name. + DefinitionSchemaVersion int + ArtifactDigest string + EnvironmentDigest string + DefinitionFingerprint string + Context map[string]string + // Common routine semantics are copied from the typed plan. The Python + // gateway refuses an invocation with absent or altered values. + CallsiteID string + MayError bool + SecurityMode string + Leakproof bool + StatementContext *StatementContext + SecurityFrame *SecurityFrame + Tuple protocol.FencingTuple +} + +// FunctionRef is the language-neutral form of the shared Catalog identity +// carried through the runtime boundary. +type FunctionRef struct { + AccountID uint64 `json:"account_id"` + DatabaseID uint64 `json:"database_id"` + FunctionID uint64 `json:"function_id"` + Revision uint64 `json:"revision"` + NamespaceVersion uint64 `json:"namespace_version"` +} + +func (r FunctionRef) Validate() error { + if r.DatabaseID == 0 || r.FunctionID == 0 || r.Revision == 0 || r.NamespaceVersion == 0 { + return moerr.NewInvalidInputNoCtx("incomplete UDF FunctionRef") + } + return nil } // Runtime executes one invocation. Implementations must not retain the @@ -75,6 +271,14 @@ type RuntimeCloser interface { Close() error } +// RuntimeReadiness is an optional feature-level gate. A caller uses it before +// publishing a routine so a node never persists a new external definition +// that its current runtime cannot execute. It does not affect ordinary SQL +// routines or ordinary SQL when the Python runtime is disabled. +type RuntimeReadiness interface { + CheckLanguageReady(context.Context, string) error +} + // Registry dispatches to the one runtime selected by a routine's language. // A registry is immutable after construction, so plan execution cannot race // service registration or observe a partially initialized adapter. @@ -116,6 +320,18 @@ func (r *runtimeRegistry) Execute( return runtime.Execute(ctx, invocation, result, mp) } +func (r *runtimeRegistry) CheckLanguageReady(ctx context.Context, language string) error { + runtime := r.byLanguage[language] + if runtime == nil { + return moerr.NewNotSupportedf(ctx, "%s UDF runtime is not enabled", language) + } + readiness, ok := runtime.(RuntimeReadiness) + if !ok { + return moerr.NewNotSupportedf(ctx, "%s UDF runtime does not expose the current contract", language) + } + return readiness.CheckLanguageReady(ctx, language) +} + func (r *runtimeRegistry) Close() error { r.closeOnce.Do(func() { languages := make([]string, 0, len(r.byLanguage)) diff --git a/pkg/udf/runtime_test.go b/pkg/udf/runtime_test.go index 908d7764f225b..9c937606a8f15 100644 --- a/pkg/udf/runtime_test.go +++ b/pkg/udf/runtime_test.go @@ -46,3 +46,73 @@ func TestRuntimeRegistryClosesOwnedRuntimesOnce(t *testing.T) { require.NoError(t, closer.Close()) require.Equal(t, int32(1), python.closed.Load()) } + +func TestStatementContextFromMapProducesCanonicalTypedSnapshot(t *testing.T) { + snapshot, err := StatementContextFromMap(map[string]string{ + "statement_timestamp_utc": "1704067200123456", + "session_timezone_kind": "FIXED_OFFSET", + "session_timezone_offset_minutes": "+510", + "sql_mode": "[\"ANSI\",\"STRICT_TRANS_TABLES\"]", + "current_database": "app", + "current_user": "alice", + "current_role": "writer", + "connection_collation": "utf8mb4_bin", + }) + require.NoError(t, err) + require.Equal(t, int32(510), snapshot.TimezoneOffsetMinutes) + require.Equal(t, []string{"ANSI", "STRICT_TRANS_TABLES"}, snapshot.SQLMode) + require.NoError(t, snapshot.Validate()) + + snapshot.SQLMode = []string{"STRICT_TRANS_TABLES", "ANSI"} + require.ErrorContains(t, snapshot.Validate(), "not sorted") +} + +func TestStatementContextFromMapRejectsAmbiguousTimezoneAndMalformedMode(t *testing.T) { + base := map[string]string{ + "statement_timestamp_utc": "1704067200123456", + "session_timezone_kind": "FIXED_OFFSET", + "session_timezone_offset_minutes": "+480", + "sql_mode": "[]", + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + ambiguous := make(map[string]string, len(base)+1) + for key, value := range base { + ambiguous[key] = value + } + ambiguous["session_timezone_name"] = "Asia/Shanghai" + _, err := StatementContextFromMap(ambiguous) + require.ErrorContains(t, err, "fixed statement timezone") + + malformed := make(map[string]string, len(base)) + for key, value := range base { + malformed[key] = value + } + malformed["sql_mode"] = "[\"ANSI\",\"ANSI\"]" + _, err = StatementContextFromMap(malformed) + require.ErrorContains(t, err, "not canonical") +} + +func TestStatementContextAcceptsUnixEpoch(t *testing.T) { + snapshot, err := StatementContextFromMap(map[string]string{ + "statement_timestamp_utc": "0", + "session_timezone_kind": "FIXED_OFFSET", + "session_timezone_offset_minutes": "0", + "sql_mode": "[]", + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + }) + require.NoError(t, err) + require.Zero(t, snapshot.StatementTimestampUTC) + require.NoError(t, snapshot.Validate()) +} + +func TestSecurityFrameRejectsEffectivePrincipalChange(t *testing.T) { + frame := SecurityFrame{ + ContractVersion: SecurityFrameContractVersion, + Mode: "INVOKER", + InvokerUserID: 7, + EffectiveUserID: 8, + } + require.ErrorContains(t, frame.Validate(), "changed effective principal") +} diff --git a/pkg/udf/timezone.go b/pkg/udf/timezone.go new file mode 100644 index 0000000000000..f4816995f043d --- /dev/null +++ b/pkg/udf/timezone.go @@ -0,0 +1,47 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package udf + +import ( + "bufio" + "fmt" + "os" + "strings" +) + +// TimezoneDatabaseVersion returns the version of the system IANA tz database +// used by the current process. An IANA timezone is part of the Python UDF +// statement contract, so silently returning a made-up version would allow two +// hosts to interpret a DST boundary differently. +func TimezoneDatabaseVersion() (string, error) { + paths := []string{ + "/usr/share/zoneinfo/tzdata.zi", + "/usr/lib/zoneinfo/tzdata.zi", + "/usr/share/lib/zoneinfo/tzdata.zi", + "/etc/zoneinfo/tzdata.zi", + } + for _, path := range paths { + file, err := os.Open(path) + if err != nil { + continue + } + scanner := bufio.NewScanner(file) + lineOK := scanner.Scan() + line := scanner.Text() + _ = file.Close() + if !lineOK { + continue + } + const prefix = "# version " + if strings.HasPrefix(line, prefix) { + version := strings.TrimSpace(strings.TrimPrefix(line, prefix)) + if version != "" { + return version, nil + } + } + } + return "", fmt.Errorf("python udf: IANA timezone database version is unavailable") +} diff --git a/proto/plan.proto b/proto/plan.proto index d79bc0fd40d5b..44b3b88f93f73 100644 --- a/proto/plan.proto +++ b/proto/plan.proto @@ -265,6 +265,8 @@ message Function { // overload while optimizers still distinguish it from an implicit cast. // Older CNs safely ignore this unknown field and execute the legacy overload. bool syntax_explicit_cast = 5; + // Typed routine metadata. Ordinary builtin Function values leave this nil. + RoutineCall routine_call = 6; } // PreparedNumericMetadata is sparse planner provenance for a numeric overload @@ -1826,6 +1828,11 @@ message Query { // Logical access paths, not grants or resolved security roles. repeated ViewReference view_references = 18; CorrelationSpec correlation = 19; + // Exact routine revisions captured while binding this statement. The + // expression tree carries the call-site implementation, while this bounded + // envelope lets prepared and ordinary plan-cache reuse validate the shared + // catalog namespace without walking or reinterpreting user source. + repeated RoutinePlanDependency routine_dependencies = 20; } message TransationControl { @@ -2522,6 +2529,88 @@ message ViewStep { string subscription_name = 4; } +// FunctionRef is the exact catalog identity carried by an executable plan. +// A zero revision is invalid for external routines; the planner validates the +// complete call before a fragment is dispatched. +message FunctionRef { + uint64 function_id = 1; + uint64 revision = 2; + uint64 namespace_version = 3; + // Function identity is tenant/database scoped. These fields prevent a + // plan fragment from being interpreted in a different catalog namespace. + uint64 account_id = 4; + uint64 database_id = 5; +} + +message SqlRoutineImplementation { + bytes definition_fingerprint = 1; + int32 semantic_definition_schema_version = 2; +} + +message PythonRoutineImplementation { + string handler = 1; + // Source is retained only so an old serialized demo plan can be identified + // and rejected. A current executable plan must carry the immutable artifact + // digest and resolve the artifact through the runtime artifact store. + string source = 2 [deprecated = true]; + string abi_contract = 3; + string adapter_version = 4; + string artifact_digest = 5; + string environment_digest = 6; + string sdk_version = 7; + int32 definition_schema_version = 8; + string mode = 9; + string null_policy = 10; + string definition_fingerprint = 11; +} + +// RoutineCall is the common typed call envelope for SQL and external +// language routines. Function.Args remains the normal expression argument +// list so existing expression traversal and CASE/selection ownership stay +// intact; this field carries only immutable routine identity and semantics. +message RoutineCall { + int32 contract_version = 1; + FunctionRef function_ref = 2; + string language = 3; + repeated Type argument_types = 4; + Type return_type = 5 [(gogoproto.nullable) = false]; + string volatility = 6; + string null_policy = 7; + oneof implementation { + SqlRoutineImplementation sql = 8; + PythonRoutineImplementation python = 9; + } + // Reserved from the current executable contract. Statement identity, + // session values, and group fences are created at execution time; keeping + // them in a prepared plan would allow stale state to cross executions. + map context = 10 [deprecated = true]; + // These fields are the common semantic contract. They must survive SQL + // lowering and expression/plan cloning; the optimizer may only move a + // routine call when the attached contract permits it. + string callsite_id = 11; + bool may_error = 12; + string security_mode = 13; + bool leakproof = 14; +} + +// RoutinePlanDependency is the shared cache/prepared-plan validation envelope +// for a resolved routine closure. FunctionRef is the executable identity; +// the integrity fields prove that the implementation attached to the plan is +// the same immutable revision that the resolver admitted. +message RoutinePlanDependency { + FunctionRef function_ref = 1; + string language = 2; + int32 contract_version = 3; + string definition_fingerprint = 4; + string artifact_digest = 5; + string environment_digest = 6; + string volatility = 7; + string null_policy = 8; + bool may_error = 9; + string security_mode = 10; + bool leakproof = 11; +} + // A zero version represents a legacy database without a persisted default. // Names are derived display values; identity/revision own the effective domain. message DatabaseDefaults { diff --git a/test/distributed/cases/udf_python/README.md b/test/distributed/cases/udf_python/README.md index 2e34d22d10070..4b253a3642c6f 100644 --- a/test/distributed/cases/udf_python/README.md +++ b/test/distributed/cases/udf_python/README.md @@ -39,6 +39,14 @@ The cases keep the data sets small and target contract boundaries: UUID round trips, and NULL. - `temporal_boundaries.sql` checks leap days, microseconds, TIME limits, SQL zero-date values, and NULL. +- `relational_positions.sql` checks UDF evaluation in WHERE, JOIN ON and outer + join predicates, aggregate arguments, window ordering, and nested calls. +- `dml_positions.sql` checks UDF evaluation in INSERT values, UPDATE + assignments, and DELETE predicates while preserving SQL NULL filtering. +- `dml_error_paths.sql` checks that handler failures abort UPDATE, INSERT + SELECT, and DELETE atomically without publishing partial changes. +- `revision_lifecycle.sql` checks create, immutable-revision replacement, + prepared-plan invalidation, drop, and recreate on the same SQL signature. The shape follows established correctness coverage from [DuckDB's scalar UDF tests](https://github.com/duckdb/duckdb-go/blob/main/scalar_udf_test.go) diff --git a/test/distributed/cases/udf_python/dml_error_paths.result b/test/distributed/cases/udf_python/dml_error_paths.result new file mode 100644 index 0000000000000..f1eaa4c487777 --- /dev/null +++ b/test/distributed/cases/udf_python/dml_error_paths.result @@ -0,0 +1,30 @@ +drop database if exists udf_python_dml_errors_bvt; +create database udf_python_dml_errors_bvt; +use udf_python_dml_errors_bvt; +create function python_bvt_dml_fail (x int) returns int language python as 'def python_bvt_dml_fail(ctx, x): return x if x != 2 else 1 / 0' handler 'python_bvt_dml_fail'; +create table source_values (id int primary key, value int); +insert into source_values values (1, 1), (2, 2), (3, 3); +update source_values set value = python_bvt_dml_fail(value); +python udf: worker error: USER_CODE: handler or runtime failed +select id, value from source_values order by id; +➤ id[4,32,0] ¦ value[4,32,0] 𝄀 +1 ¦ 1 𝄀 +2 ¦ 2 𝄀 +3 ¦ 3 +create table inserted_values (id int primary key, value int); +insert into inserted_values select id, python_bvt_dml_fail(value) from source_values; +python udf: worker error: USER_CODE: handler or runtime failed +select count(*) as inserted_rows from inserted_values; +➤ inserted_rows[-5,64,0] 𝄀 +0 +delete from source_values where python_bvt_dml_fail(value) > 0; +python udf: worker error: USER_CODE: handler or runtime failed +select id, value from source_values order by id; +➤ id[4,32,0] ¦ value[4,32,0] 𝄀 +1 ¦ 1 𝄀 +2 ¦ 2 𝄀 +3 ¦ 3 +drop function python_bvt_dml_fail(int); +drop table inserted_values; +drop table source_values; +drop database udf_python_dml_errors_bvt; diff --git a/test/distributed/cases/udf_python/dml_error_paths.sql b/test/distributed/cases/udf_python/dml_error_paths.sql new file mode 100644 index 0000000000000..5e7b4d562b889 --- /dev/null +++ b/test/distributed/cases/udf_python/dml_error_paths.sql @@ -0,0 +1,31 @@ +-- A Python failure is a statement failure. The DML operator must not publish +-- rows that were evaluated before the handler raised an error. +drop database if exists udf_python_dml_errors_bvt; +create database udf_python_dml_errors_bvt; +use udf_python_dml_errors_bvt; + +create function python_bvt_dml_fail (x int) returns int language python as 'def python_bvt_dml_fail(ctx, x): return x if x != 2 else 1 / 0' handler 'python_bvt_dml_fail'; +create table source_values (id int primary key, value int); +insert into source_values values (1, 1), (2, 2), (3, 3); + +-- UPDATE evaluates row 1 before row 2 raises. The original table must remain +-- unchanged after the failed statement. +--error +update source_values set value = python_bvt_dml_fail(value); +select id, value from source_values order by id; + +create table inserted_values (id int primary key, value int); +-- INSERT ... SELECT must publish no row after the same handler failure. +--error +insert into inserted_values select id, python_bvt_dml_fail(value) from source_values; +select count(*) as inserted_rows from inserted_values; + +-- DELETE must also leave all source rows intact when its predicate fails. +--error +delete from source_values where python_bvt_dml_fail(value) > 0; +select id, value from source_values order by id; + +drop function python_bvt_dml_fail(int); +drop table inserted_values; +drop table source_values; +drop database udf_python_dml_errors_bvt; diff --git a/test/distributed/cases/udf_python/dml_positions.result b/test/distributed/cases/udf_python/dml_positions.result new file mode 100644 index 0000000000000..8b284aaf5211e --- /dev/null +++ b/test/distributed/cases/udf_python/dml_positions.result @@ -0,0 +1,17 @@ +drop database if exists udf_python_dml_bvt; +create database udf_python_dml_bvt; +use udf_python_dml_bvt; +create function python_bvt_dml_add (x int) returns int language python as 'def python_bvt_dml_add(ctx, x): return None if x is None else x + 1' handler 'python_bvt_dml_add'; +create table dml_values (id int primary key, value int); +insert into dml_values values (1, 1), (2, 2), (3, null); +insert into dml_values values (4, python_bvt_dml_add(3)); +update dml_values set value = python_bvt_dml_add(value) where id = 1; +delete from dml_values where python_bvt_dml_add(value) >= 4; +select id, value from dml_values order by id; +➤ id[4,32,0] ¦ value[4,32,0] 𝄀 +1 ¦ 2 𝄀 +2 ¦ 2 𝄀 +3 ¦ null +drop function python_bvt_dml_add(int); +drop table dml_values; +drop database udf_python_dml_bvt; diff --git a/test/distributed/cases/udf_python/dml_positions.sql b/test/distributed/cases/udf_python/dml_positions.sql new file mode 100644 index 0000000000000..f956d284924af --- /dev/null +++ b/test/distributed/cases/udf_python/dml_positions.sql @@ -0,0 +1,25 @@ +-- Exercise Python UDFs in INSERT values, UPDATE assignments, and DELETE +-- predicates. Every mutation is observed by the final SELECT. +drop database if exists udf_python_dml_bvt; +create database udf_python_dml_bvt; +use udf_python_dml_bvt; + +create function python_bvt_dml_add (x int) returns int language python as 'def python_bvt_dml_add(ctx, x): return None if x is None else x + 1' handler 'python_bvt_dml_add'; +create table dml_values (id int primary key, value int); +insert into dml_values values (1, 1), (2, 2), (3, null); + +-- INSERT must evaluate the routine for the incoming row. +insert into dml_values values (4, python_bvt_dml_add(3)); + +-- UPDATE must evaluate the routine against the target row image. +update dml_values set value = python_bvt_dml_add(value) where id = 1; + +-- DELETE must keep the routine in its target predicate. NULL remains unknown +-- and therefore must not be deleted. +delete from dml_values where python_bvt_dml_add(value) >= 4; + +select id, value from dml_values order by id; + +drop function python_bvt_dml_add(int); +drop table dml_values; +drop database udf_python_dml_bvt; diff --git a/test/distributed/cases/udf_python/relational_positions.result b/test/distributed/cases/udf_python/relational_positions.result new file mode 100644 index 0000000000000..3ccca0c83215c --- /dev/null +++ b/test/distributed/cases/udf_python/relational_positions.result @@ -0,0 +1,59 @@ +drop database if exists udf_python_positions_bvt; +create database udf_python_positions_bvt; +use udf_python_positions_bvt; +create function python_bvt_position_add (x int) returns int language python as 'def python_bvt_position_add(ctx, x): return None if x is None else x + 1' handler 'python_bvt_position_add'; +create function python_bvt_position_twice (x int) returns int language python as 'def python_bvt_position_twice(ctx, x): return None if x is None else x * 2' handler 'python_bvt_position_twice'; +create table position_left (id int, join_key int, value int); +create table position_right (join_key int, tag varchar(8)); +insert into position_left values (1, 10, 1), (2, 20, 2), (3, 30, null); +insert into position_right values (11, 'a'), (21, 'b'), (40, 'd'); +select id, python_bvt_position_add(value) as plus +from position_left +where python_bvt_position_add(value) > 1 +order by id; +➤ id[4,32,0] ¦ plus[4,32,0] 𝄀 +1 ¦ 2 𝄀 +2 ¦ 3 +select l.id, r.tag +from position_left l join position_right r +on python_bvt_position_add(l.join_key) = r.join_key +order by l.id; +➤ id[4,32,0] ¦ tag[12,8,0] 𝄀 +1 ¦ a 𝄀 +2 ¦ b +select l.id, r.tag +from position_left l left join position_right r +on python_bvt_position_add(l.join_key) = r.join_key +order by l.id; +➤ id[4,32,0] ¦ tag[12,8,0] 𝄀 +1 ¦ a 𝄀 +2 ¦ b 𝄀 +3 ¦ null +select join_key, sum(python_bvt_position_add(value)) as total +from position_left +group by join_key +order by join_key; +➤ join_key[4,32,0] ¦ total[-5,64,0] 𝄀 +10 ¦ 2 𝄀 +20 ¦ 3 𝄀 +30 ¦ null +select id, python_bvt_position_add(value) as plus, +row_number() over (order by python_bvt_position_add(value)) as rn +from position_left +order by id; +➤ id[4,32,0] ¦ plus[4,32,0] ¦ rn[-5,64,0] 𝄀 +1 ¦ 2 ¦ 2 𝄀 +2 ¦ 3 ¦ 3 𝄀 +3 ¦ null ¦ 1 +select id, python_bvt_position_twice(python_bvt_position_add(value)) as nested +from position_left +order by id; +➤ id[4,32,0] ¦ nested[4,32,0] 𝄀 +1 ¦ 4 𝄀 +2 ¦ 6 𝄀 +3 ¦ null +drop function python_bvt_position_add(int); +drop function python_bvt_position_twice(int); +drop table position_left; +drop table position_right; +drop database udf_python_positions_bvt; diff --git a/test/distributed/cases/udf_python/relational_positions.sql b/test/distributed/cases/udf_python/relational_positions.sql new file mode 100644 index 0000000000000..8ec2e716f4470 --- /dev/null +++ b/test/distributed/cases/udf_python/relational_positions.sql @@ -0,0 +1,54 @@ +-- Exercise the current SQL execution positions that must preserve the +-- Python call's row mapping: WHERE, JOIN ON, outer join, aggregate, window, +-- and a dependent call g(f(x)). +drop database if exists udf_python_positions_bvt; +create database udf_python_positions_bvt; +use udf_python_positions_bvt; + +create function python_bvt_position_add (x int) returns int language python as 'def python_bvt_position_add(ctx, x): return None if x is None else x + 1' handler 'python_bvt_position_add'; +create function python_bvt_position_twice (x int) returns int language python as 'def python_bvt_position_twice(ctx, x): return None if x is None else x * 2' handler 'python_bvt_position_twice'; + +create table position_left (id int, join_key int, value int); +create table position_right (join_key int, tag varchar(8)); +insert into position_left values (1, 10, 1), (2, 20, 2), (3, 30, null); +insert into position_right values (11, 'a'), (21, 'b'), (40, 'd'); + +-- The predicate and projection both use Python, with NULL filtered by SQL. +select id, python_bvt_position_add(value) as plus +from position_left +where python_bvt_position_add(value) > 1 +order by id; + +-- The UDF remains part of JOIN ON and must not be rewritten as a post-join +-- filter, so the LEFT JOIN keeps the unmatched outer row. +select l.id, r.tag +from position_left l join position_right r + on python_bvt_position_add(l.join_key) = r.join_key +order by l.id; + +select l.id, r.tag +from position_left l left join position_right r + on python_bvt_position_add(l.join_key) = r.join_key +order by l.id; + +-- Aggregate input and window ordering both consume a Python expression. +select join_key, sum(python_bvt_position_add(value)) as total +from position_left +group by join_key +order by join_key; + +select id, python_bvt_position_add(value) as plus, + row_number() over (order by python_bvt_position_add(value)) as rn +from position_left +order by id; + +-- The outer call consumes the inner call's result and must retain NULL. +select id, python_bvt_position_twice(python_bvt_position_add(value)) as nested +from position_left +order by id; + +drop function python_bvt_position_add(int); +drop function python_bvt_position_twice(int); +drop table position_left; +drop table position_right; +drop database udf_python_positions_bvt; diff --git a/test/distributed/cases/udf_python/revision_lifecycle.result b/test/distributed/cases/udf_python/revision_lifecycle.result new file mode 100644 index 0000000000000..9cc809811a16c --- /dev/null +++ b/test/distributed/cases/udf_python/revision_lifecycle.result @@ -0,0 +1,35 @@ +drop database if exists udf_python_revision_bvt; +create database udf_python_revision_bvt; +use udf_python_revision_bvt; +create function python_bvt_revision (x int) returns int language python as 'def python_bvt_revision(ctx, x): return None if x is None else x + 1' handler 'python_bvt_revision'; +create table revision_values (id int, value int); +insert into revision_values values (1, 1), (2, null); +select id, python_bvt_revision(value) as result from revision_values order by id; +➤ id[4,32,0] ¦ result[4,32,0] 𝄀 +1 ¦ 2 𝄀 +2 ¦ null +create or replace function python_bvt_revision (x int) returns int language python as 'def python_bvt_revision(ctx, x): return None if x is None else x + 2' handler 'python_bvt_revision'; +select id, python_bvt_revision(value) as result from revision_values order by id; +➤ id[4,32,0] ¦ result[4,32,0] 𝄀 +1 ¦ 3 𝄀 +2 ¦ null +prepare python_revision_plan from 'select id, python_bvt_revision(value) as result from revision_values order by id'; +execute python_revision_plan; +➤ id[4,32,0] ¦ result[4,32,0] 𝄀 +1 ¦ 3 𝄀 +2 ¦ null +create or replace function python_bvt_revision (x int) returns int language python as 'def python_bvt_revision(ctx, x): return None if x is None else x + 4' handler 'python_bvt_revision'; +execute python_revision_plan; +➤ id[4,32,0] ¦ result[4,32,0] 𝄀 +1 ¦ 5 𝄀 +2 ¦ null +deallocate prepare python_revision_plan; +drop function python_bvt_revision(int); +create function python_bvt_revision (x int) returns int language python as 'def python_bvt_revision(ctx, x): return None if x is None else x + 3' handler 'python_bvt_revision'; +select id, python_bvt_revision(value) as result from revision_values order by id; +➤ id[4,32,0] ¦ result[4,32,0] 𝄀 +1 ¦ 4 𝄀 +2 ¦ null +drop function python_bvt_revision(int); +drop table revision_values; +drop database udf_python_revision_bvt; diff --git a/test/distributed/cases/udf_python/revision_lifecycle.sql b/test/distributed/cases/udf_python/revision_lifecycle.sql new file mode 100644 index 0000000000000..dbb28f1abd098 --- /dev/null +++ b/test/distributed/cases/udf_python/revision_lifecycle.sql @@ -0,0 +1,20 @@ +drop database if exists udf_python_revision_bvt; +create database udf_python_revision_bvt; +use udf_python_revision_bvt; +create function python_bvt_revision (x int) returns int language python as 'def python_bvt_revision(ctx, x): return None if x is None else x + 1' handler 'python_bvt_revision'; +create table revision_values (id int, value int); +insert into revision_values values (1, 1), (2, null); +select id, python_bvt_revision(value) as result from revision_values order by id; +create or replace function python_bvt_revision (x int) returns int language python as 'def python_bvt_revision(ctx, x): return None if x is None else x + 2' handler 'python_bvt_revision'; +select id, python_bvt_revision(value) as result from revision_values order by id; +prepare python_revision_plan from 'select id, python_bvt_revision(value) as result from revision_values order by id'; +execute python_revision_plan; +create or replace function python_bvt_revision (x int) returns int language python as 'def python_bvt_revision(ctx, x): return None if x is None else x + 4' handler 'python_bvt_revision'; +execute python_revision_plan; +deallocate prepare python_revision_plan; +drop function python_bvt_revision(int); +create function python_bvt_revision (x int) returns int language python as 'def python_bvt_revision(ctx, x): return None if x is None else x + 3' handler 'python_bvt_revision'; +select id, python_bvt_revision(value) as result from revision_values order by id; +drop function python_bvt_revision(int); +drop table revision_values; +drop database udf_python_revision_bvt; From 0212c0dd745087b91a79d2921b464fd23f722784 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 11 Sep 2026 22:16:05 +0800 Subject: [PATCH 054/241] feat(udf): validate Python definitions before publication --- pkg/frontend/authenticate.go | 222 +++++++---- pkg/frontend/python_udf_catalog_test.go | 62 +++ pkg/udf/python/arrow.go | 240 +++++++++++- pkg/udf/python/arrow_test.go | 95 +++++ pkg/udf/python/gateway.go | 294 +++++++++++++- pkg/udf/python/gateway_benchmark_test.go | 58 ++- pkg/udf/python/gateway_integration_test.go | 49 +++ pkg/udf/python/worker/test_worker.py | 136 ++++++- pkg/udf/python/worker/worker.py | 362 ++++++++++++++++-- pkg/udf/runtime.go | 51 +++ .../cases/udf_python/udf_python.sql | 13 + 11 files changed, 1431 insertions(+), 151 deletions(-) diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index 5aeb8e0f6bbcc..f857768ca6612 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -11871,9 +11871,63 @@ func ensurePythonUdfRuntimeReady(ctx context.Context, ses *Session) error { if !ok { return moerr.NewNotSupportedNoCtx("Python UDF runtime does not expose the current contract") } + if _, ok := pu.UdfService.(udf.RuntimeDefinitionValidator); !ok { + return moerr.NewNotSupportedNoCtx("Python UDF runtime does not expose definition validation") + } return readiness.CheckLanguageReady(ctx, udf.LanguagePython) } +// validatePythonUdfDefinitionAtCreate runs after the immutable artifact has +// been published and before the Catalog transaction writes the new identity +// or revision. The source is transient input to the validator; the Gateway +// resolves the same account-scoped digest before sending it to the worker. +func validatePythonUdfDefinitionAtCreate( + ctx context.Context, + ses *Session, + tenant *TenantInfo, + body function.PythonRoutineBody, +) error { + pu := getPuIfPresent(ses.GetService()) + if pu == nil || pu.UdfService == nil { + return moerr.NewNotSupportedNoCtx("Python UDF feature is disabled") + } + validator, ok := pu.UdfService.(udf.RuntimeDefinitionValidator) + if !ok { + return moerr.NewNotSupportedNoCtx("Python UDF runtime does not expose definition validation") + } + if tenant == nil { + return moerr.NewInvalidInputNoCtx("Python UDF definition validation requires an account") + } + if err := body.Validate(); err != nil { + return moerr.NewInvalidInputNoCtxf("Python UDF definition rejected before publication: %v", err) + } + definitionFingerprint, err := function.PythonRoutineBodyFingerprint(body) + if err != nil { + return moerr.NewInvalidInputNoCtxf("Python UDF definition fingerprint cannot be computed: %v", err) + } + args := make([]types.Type, len(body.ArgTypes)) + for index, descriptor := range body.ArgTypes { + args[index] = descriptor.Type() + } + return validator.ValidateDefinition(ctx, &udf.RoutineDefinition{ + Language: udf.LanguagePython, + AccountID: uint64(tenant.GetTenantID()), + Handler: body.Handler, + Source: body.Source, + Args: args, + ReturnType: body.ReturnType.Type(), + Mode: body.Mode, + NullPolicy: body.NullPolicy, + ABIContract: body.ABIContract, + AdapterVersion: body.AdapterVersion, + SDKVersion: body.SDKVersion, + DefinitionSchemaVersion: body.DefinitionSchemaVersion, + ArtifactDigest: body.ArtifactDigest, + EnvironmentDigest: body.EnvironmentDigest, + DefinitionFingerprint: definitionFingerprint, + }) +} + // canonicalPythonInputDescriptor is the shared overload key used by the // catalog lookup and by the immutable revision metadata. Keeping this // conversion at the create boundary prevents the logical SQL OID list from @@ -11887,6 +11941,7 @@ func canonicalPythonInputDescriptor( } func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.CreateFunction) (err error) { + isPython := strings.EqualFold(cf.Language, string(tree.PYTHON)) var retTypeStr string var dbName string var dbExists bool @@ -11900,7 +11955,7 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C var erArray []ExecResult var pythonArgTypes []function.PythonTypeDescriptor var pythonReturnType *function.PythonTypeDescriptor - if strings.EqualFold(cf.Language, string(tree.PYTHON)) { + if isPython { if err := ensurePythonUdfRuntimeReady(execCtx.reqCtx, ses); err != nil { return err } @@ -11916,44 +11971,17 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C dbName = string(cf.Name.Name.SchemaName) } - // Exact function signatures need an exclusion boundary in every deployment - // mode. The catalog unique index documents the identity, but optimistic/SI - // transactions do not acquire FOR UPDATE locks. This private transaction is - // therefore explicitly pessimistic RC, locks the target database row, then - // rechecks and writes the signature before releasing that lock. - bh := ses.GetBackgroundExec(execCtx.reqCtx, &BackgroundExecOption{forcePessimisticRC: true}) - defer bh.Close() - - err = bh.Exec(execCtx.reqCtx, "begin;") - if err != nil { - return err - } - defer func() { - err = finishTxn(execCtx.reqCtx, bh, err) - }() - if cf.Language == string(tree.PYTHON) { - if err = ensurePythonUdfCatalogReady(execCtx.reqCtx, bh); err != nil { - return err - } - } - - // Lock and authenticate the target database before the exact-signature - // read. The lock stays held through persistence and commit. - dbExists, err = lockDatabaseForUDFCreation(execCtx.reqCtx, bh, dbName) - if err != nil { - return err - } - if !dbExists { - return moerr.NewBadDB(execCtx.reqCtx, dbName) - } - - // format return type + // Parse the complete typed definition before opening the Catalog + // transaction. Python validation performs a network round trip to the + // worker; holding the database lock while waiting would make a slow or + // unavailable worker block unrelated DDL. The later transaction still + // locks and rechecks the exact identity before publication. fmtctx = tree.NewFmtCtx(dialect.MYSQL, tree.WithQuoteString(true)) retTypeStr, err = plan2.GetFunctionTypeStrFromAst(cf.ReturnType.Type) if err != nil { return err } - if cf.Language == string(tree.PYTHON) { + if isPython { returnType, typeErr := plan2.GetFunctionTypeFromAst(cf.ReturnType.Type) if typeErr != nil { return typeErr @@ -11979,7 +12007,7 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C } argList[i].Type = typ typeList[i] = typ - if cf.Language == string(tree.PYTHON) { + if isPython { argType, typeErr := plan2.GetFunctionTypeFromAst(cf.Args[i].(*tree.FunctionArgDecl).Type) if typeErr != nil { return typeErr @@ -12001,42 +12029,15 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C return err } logicalArgTypes = argTypes - if cf.Language == string(tree.PYTHON) { + if isPython { exactArgTypes, err = canonicalPythonInputDescriptor(pythonArgTypes, pythonReturnType) if err != nil { return err } } - // validate duplicate function declaration - bh.ClearExecResultSet() - if cf.Language == string(tree.PYTHON) { - checkExistence = fmt.Sprintf(checkPythonUdfExistence, string(cf.Name.Name.ObjectName), dbName) - } else { - checkExistence = fmt.Sprintf(checkUdfExistence, string(cf.Name.Name.ObjectName), dbName) - } - err = bh.Exec(execCtx.reqCtx, checkExistence) - if err != nil { - return err - } - - erArray, err = getResultSet(execCtx.reqCtx, bh) - if err != nil { - return err - } - - matchedIDs, err := matchUserDefinedFunctionCandidates(execCtx.reqCtx, erArray, string(cf.Language), logicalArgTypes, exactArgTypes) - if err != nil { - return err - } - if len(matchedIDs) > 1 { - return moerr.NewInvalidInputNoCtxf("function %s has multiple catalog identities for the same signature", string(cf.Name.Name.ObjectName)) - } - if len(matchedIDs) == 1 && !cf.Replace { - return moerr.NewUDFAlreadyExistsNoCtx(string(cf.Name.Name.ObjectName)) - } var body string - if cf.Language == string(tree.SQL) { + if !isPython { body = cf.Body } else { if cf.Import { @@ -12078,22 +12079,11 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C // Using strconv.Quote here would preserve backslashes before JSON quotes // in storage and break json.Unmarshal when invoking python UDFs. body = string(byt) - } - definition := userDefinedFunctionDefinition{ - name: string(cf.Name.Name.ObjectName), - args: string(argsJson), - argTypes: argTypes, - retType: retTypeStr, - body: body, - lang: cf.Language, - sqlMode: sessionSQLModeForParser(ses), - dbName: dbName, - } - if strings.EqualFold(cf.Language, string(tree.PYTHON)) { - // The catalog revision stores the source for restore/inspection, while - // the executable plan carries only its immutable digest. Publish the - // account-scoped object before the catalog row becomes visible; a failed - // transaction can leave only an unreferenced object for later GC. + + // Publish and validate the exact immutable artifact before opening the + // Catalog transaction. A failed CREATE/REPLACE therefore cannot expose + // a revision whose source the current worker has not accepted, while a + // failed replacement leaves its previous active revision untouched. artifactStore, storeErr := pythonudf.NewFileArtifactStore( getPu(ses.GetService()).FileService, pythonudf.DefaultMaxArtifactBytes, @@ -12109,6 +12099,78 @@ func InitFunction(ses *Session, execCtx *ExecCtx, tenant *TenantInfo, cf *tree.C ); err != nil { return err } + if err = validatePythonUdfDefinitionAtCreate(execCtx.reqCtx, ses, tenant, nb); err != nil { + return err + } + } + definition := userDefinedFunctionDefinition{ + name: string(cf.Name.Name.ObjectName), + args: string(argsJson), + argTypes: argTypes, + retType: retTypeStr, + body: body, + lang: cf.Language, + sqlMode: sessionSQLModeForParser(ses), + dbName: dbName, + } + + // Exact function signatures need an exclusion boundary in every deployment + // mode. The catalog unique index documents the identity, but optimistic/SI + // transactions do not acquire FOR UPDATE locks. This private transaction is + // therefore explicitly pessimistic RC, locks the target database row, then + // rechecks and writes the signature before releasing that lock. + bh := ses.GetBackgroundExec(execCtx.reqCtx, &BackgroundExecOption{forcePessimisticRC: true}) + defer bh.Close() + + err = bh.Exec(execCtx.reqCtx, "begin;") + if err != nil { + return err + } + defer func() { + err = finishTxn(execCtx.reqCtx, bh, err) + }() + if isPython { + if err = ensurePythonUdfCatalogReady(execCtx.reqCtx, bh); err != nil { + return err + } + } + + // Lock and authenticate the target database before the exact-signature + // read. The lock stays held through persistence and commit. + dbExists, err = lockDatabaseForUDFCreation(execCtx.reqCtx, bh, dbName) + if err != nil { + return err + } + if !dbExists { + return moerr.NewBadDB(execCtx.reqCtx, dbName) + } + + // Validate duplicate function declaration under the same lock used for + // persistence. Python source validation above is intentionally outside this + // transaction, but identity/revision publication remains linearized here. + bh.ClearExecResultSet() + if isPython { + checkExistence = fmt.Sprintf(checkPythonUdfExistence, string(cf.Name.Name.ObjectName), dbName) + } else { + checkExistence = fmt.Sprintf(checkUdfExistence, string(cf.Name.Name.ObjectName), dbName) + } + err = bh.Exec(execCtx.reqCtx, checkExistence) + if err != nil { + return err + } + erArray, err = getResultSet(execCtx.reqCtx, bh) + if err != nil { + return err + } + matchedIDs, err := matchUserDefinedFunctionCandidates(execCtx.reqCtx, erArray, string(cf.Language), logicalArgTypes, exactArgTypes) + if err != nil { + return err + } + if len(matchedIDs) > 1 { + return moerr.NewInvalidInputNoCtxf("function %s has multiple catalog identities for the same signature", string(cf.Name.Name.ObjectName)) + } + if len(matchedIDs) == 1 && !cf.Replace { + return moerr.NewUDFAlreadyExistsNoCtx(string(cf.Name.Name.ObjectName)) } if len(matchedIDs) == 1 { // replace id := matchedIDs[0] diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 6d7c9fa549789..be7771ec4537b 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -14,8 +14,10 @@ import ( "testing" "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/config" "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/container/vector" "github.com/matrixorigin/matrixone/pkg/defines" "github.com/matrixorigin/matrixone/pkg/fileservice" "github.com/matrixorigin/matrixone/pkg/sql/parsers" @@ -27,6 +29,66 @@ import ( "github.com/stretchr/testify/require" ) +type definitionValidationRuntime struct { + definition *udf.RoutineDefinition + err error +} + +func (r *definitionValidationRuntime) Language() string { return udf.LanguagePython } + +func (r *definitionValidationRuntime) Execute( + context.Context, + *udf.Invocation, + vector.FunctionResultWrapper, + *mpool.MPool, +) error { + return nil +} + +func (r *definitionValidationRuntime) CheckLanguageReady(context.Context, string) error { + return nil +} + +func (r *definitionValidationRuntime) ValidateDefinition( + _ context.Context, + definition *udf.RoutineDefinition, +) error { + r.definition = definition + return r.err +} + +func TestValidatePythonUdfDefinitionAtCreateUsesTypedWorkerGate(t *testing.T) { + const service = "python-definition-validation-test" + InitServerLevelVars(service) + previous := getPuIfPresent(service) + t.Cleanup(func() { setPu(service, previous) }) + + runtime := &definitionValidationRuntime{err: fmt.Errorf("USER_CODE: Python syntax error at line 1, column 22")} + pu := config.NewParameterUnit(&config.FrontendParameters{}, nil, nil, nil) + pu.UdfService = runtime + setPu(service, pu) + + source := "def f(ctx, value): return value" + body, err := function.DecodePythonRoutineBody(pythonCatalogTestBody(t, types.T_int64)) + require.NoError(t, err) + body.Source = source + body.ArtifactDigest = udf.PythonInlineArtifactDigest(body.Handler, source) + body.EnvironmentDigest, err = udf.PythonEnvironmentDigest() + require.NoError(t, err) + + ses := &Session{feSessionImpl: feSessionImpl{service: service}} + tenant := &TenantInfo{TenantID: 27} + err = validatePythonUdfDefinitionAtCreate(context.Background(), ses, tenant, body) + require.ErrorContains(t, err, "Python syntax error") + require.NotNil(t, runtime.definition) + require.Equal(t, uint64(27), runtime.definition.AccountID) + require.Equal(t, body.Handler, runtime.definition.Handler) + require.Equal(t, body.Source, runtime.definition.Source) + require.Equal(t, body.ArtifactDigest, runtime.definition.ArtifactDigest) + require.Equal(t, body.EnvironmentDigest, runtime.definition.EnvironmentDigest) + require.Equal(t, types.T_int64.ToType(), runtime.definition.ReturnType) +} + func TestPersistPythonReplaceRejectsLegacyHeadBeforeWriting(t *testing.T) { ctx := context.Background() functionID := int64(41) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 38e48df652361..1d80e00bd67a7 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -381,6 +381,14 @@ type flightFrameCollector struct { total int64 } +func (c *flightFrameCollector) reset(maxBytes, retainedBytes int64) { + // Do not reuse the frame slice backing array. A successful candidate can be + // retained by the size search while the next candidate is encoded. + c.frames = nil + c.maxBytes = maxBytes + c.total = retainedBytes +} + func (c *flightFrameCollector) Send(data *flight.FlightData) error { if data == nil || len(data.DataHeader) == 0 { return fmt.Errorf("invalid Arrow Flight frame") @@ -398,43 +406,251 @@ func (c *flightFrameCollector) Send(data *flight.FlightData) error { return nil } +// inputBatchWireEncoder keeps one Arrow IPC writer alive for an invocation. +// The writer emits the schema once; later candidates and batches only encode a +// record message. The cached schema is still counted in every candidate's +// limit, because MaxBatchBytes describes the complete Flight payload that the +// receiver would have to admit for that batch. +type inputBatchWireEncoder struct { + schema *arrow.Schema + collector *flightFrameCollector + writer *flight.Writer + schemaFrame ArrowFrame + schemaBytes int64 + schemaReady bool + closed bool +} + +func (e *inputBatchWireEncoder) encode(record arrow.RecordBatch, maxBytes int64) ([]ArrowFrame, error) { + if e == nil || e.closed || record == nil || maxBytes <= 0 { + return nil, fmt.Errorf("invalid Arrow record batch encoder") + } + if e.schema == nil || !record.Schema().Equal(e.schema) { + return nil, fmt.Errorf("Arrow record batch schema does not match the invocation schema") + } + if e.writer == nil { + e.collector = &flightFrameCollector{} + e.writer = flight.NewRecordWriter( + e.collector, + ipc.WithSchema(e.schema), + ipc.WithAllocator(memory.NewGoAllocator()), + ) + } + writerHadSchema := e.schemaReady + e.collector.reset(maxBytes, e.schemaBytes) + if err := e.writer.Write(record); err != nil { + e.captureSchema() + return nil, fmt.Errorf("encode Arrow record batch: %w", err) + } + e.captureSchema() + if writerHadSchema { + if len(e.collector.frames) != 1 { + return nil, fmt.Errorf("Arrow writer did not emit one record frame") + } + return []ArrowFrame{e.schemaFrame, e.collector.frames[0]}, nil + } + if len(e.collector.frames) != 2 || !e.schemaReady { + return nil, fmt.Errorf("Arrow stream did not contain schema and record batch") + } + return append([]ArrowFrame(nil), e.collector.frames...), nil +} + +func (e *inputBatchWireEncoder) captureSchema() { + if e == nil || e.schemaReady || e.collector == nil || len(e.collector.frames) == 0 { + return + } + frame := e.collector.frames[0] + e.schemaFrame = ArrowFrame{ + Header: append([]byte(nil), frame.Header...), + Body: append([]byte(nil), frame.Body...), + } + e.schemaBytes = int64(len(e.schemaFrame.Header) + len(e.schemaFrame.Body)) + e.schemaReady = true +} + +func (e *inputBatchWireEncoder) close() error { + if e == nil || e.closed { + return nil + } + e.closed = true + if e.writer == nil { + return nil + } + if err := e.writer.Close(); err != nil { + return fmt.Errorf("close Arrow record batch encoder: %w", err) + } + return nil +} + func BuildInputRecord(inputs []*vector.Vector, args []types.Type, length int) (arrow.RecordBatch, *arrow.Schema, error) { return BuildInputRecordRange(inputs, args, 0, length) } func BuildInputRecordRange(inputs []*vector.Vector, args []types.Type, start, length int) (arrow.RecordBatch, *arrow.Schema, error) { - if start < 0 || length <= 0 || len(inputs) != len(args) { - return nil, nil, fmt.Errorf("invalid Python UDF input shape") + encoder, err := newInputBatchEncoder(inputs, args) + if err != nil { + return nil, nil, err + } + return encoder.build(start, length) +} + +// inputBatchEncoder owns the immutable descriptor/schema portion of the +// Gateway input boundary for one invocation. Building it once avoids +// re-creating TypeDescriptor, Field metadata, and the Arrow Schema for every +// physical batch and every size probe. The record builder and encoded bytes +// remain per batch, so the encoder does not retain input or output buffers. +type inputBatchEncoder struct { + inputs []*vector.Vector + args []types.Type + descriptors []TypeDescriptor + schema *arrow.Schema + fixedWidth bool + wire *inputBatchWireEncoder +} + +func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBatchEncoder, error) { + if len(inputs) != len(args) { + return nil, fmt.Errorf("invalid Python UDF input shape") } fields := make([]arrow.Field, len(args)) + descriptors := make([]TypeDescriptor, len(args)) + fixedWidth := true for i, typ := range args { descriptor, err := NewTypeDescriptor(typ) if err != nil { - return nil, nil, err + return nil, err } + descriptors[i] = descriptor fields[i], err = descriptor.Field(fmt.Sprintf("arg_%d", i)) if err != nil { - return nil, nil, err + return nil, err } - if inputs[i] == nil || inputs[i].Length() == 0 || (!inputs[i].IsConst() && inputs[i].Length() < start+length) { - return nil, nil, fmt.Errorf("input column %d is shorter than batch range", i) + if typ.IsVarlen() { + fixedWidth = false + } + if inputs[i] == nil || inputs[i].Length() == 0 { + return nil, fmt.Errorf("input column %d is shorter than batch range", i) } } schema := arrow.NewSchema(fields, nil) - if len(fields) == 0 { - return array.NewRecordBatch(schema, nil, int64(length)), schema, nil + return &inputBatchEncoder{ + inputs: inputs, + args: args, + descriptors: descriptors, + schema: schema, + fixedWidth: fixedWidth, + }, nil +} + +func (e *inputBatchEncoder) encode(record arrow.RecordBatch, maxBytes int64) ([]ArrowFrame, error) { + if e == nil { + return nil, fmt.Errorf("invalid Python UDF input encoder") + } + if e.wire == nil { + e.wire = &inputBatchWireEncoder{schema: e.schema} } - builder := array.NewRecordBuilder(memory.NewGoAllocator(), schema) + return e.wire.encode(record, maxBytes) +} + +func (e *inputBatchEncoder) close() error { + if e == nil || e.wire == nil { + return nil + } + return e.wire.close() +} + +func (e *inputBatchEncoder) build(start, length int) (arrow.RecordBatch, *arrow.Schema, error) { + if e == nil || start < 0 || length <= 0 { + return nil, nil, fmt.Errorf("invalid Python UDF input shape") + } + for i, input := range e.inputs { + if !input.IsConst() && input.Length() < start+length { + return nil, nil, fmt.Errorf("input column %d is shorter than batch range", i) + } + } + if len(e.args) == 0 { + return array.NewRecordBatch(e.schema, nil, int64(length)), e.schema, nil + } + builder := array.NewRecordBuilder(memory.NewGoAllocator(), e.schema) defer builder.Release() - for column, typ := range args { + for column, typ := range e.args { for row := 0; row < length; row++ { - if err := appendInputValue(builder.Field(column), inputs[column], typ, start, row); err != nil { + if err := appendInputValue(builder.Field(column), e.inputs[column], typ, start, row); err != nil { return nil, nil, fmt.Errorf("input column %d row %d: %w", column, row, err) } } } - return builder.NewRecordBatch(), schema, nil + return builder.NewRecordBatch(), e.schema, nil +} + +// canBuildFullBatch cheaply decides whether a variable-width full candidate +// is worth materializing. It uses the source values already owned by the +// SQL vector and a deliberately inflated bound. If the bound is not clearly +// below the wire limit, the bounded probe path is retained so a very wide +// input cannot create an oversized temporary Arrow record just to discover +// that it does not fit. +func (e *inputBatchEncoder) canBuildFullBatch(start, length, maxBytes int64) bool { + if e == nil || e.fixedWidth || length <= 0 || maxBytes <= 0 { + return false + } + const safetyNumerator = int64(2) + const safetyDenominator = int64(1) + const perColumnOverhead = int64(4096) + const perRowOverhead = int64(16) + const maxEstimate = int64(^uint64(0) >> 1) + add := func(total, value int64) int64 { + if value < 0 || total > maxEstimate-value { + return maxEstimate + } + return total + value + } + multiply := func(left, right int64) int64 { + if left < 0 || right < 0 || (left != 0 && right > maxEstimate/left) { + return maxEstimate + } + return left * right + } + estimate := int64(128) + for column, typ := range e.args { + if !typ.IsVarlen() { + return false + } + descriptor := e.descriptors[column] + offsetWidth := int64(descriptor.OffsetWidth) + if offsetWidth == 0 { + offsetWidth = 32 + } + offsetWidth /= 8 + if offsetWidth != 4 && offsetWidth != 8 { + return false + } + estimate = add(estimate, perColumnOverhead) + estimate = add(estimate, multiply(add(length, 1), offsetWidth)) + estimate = add(estimate, add(length, 7)/8) + parameter := vector.GenerateFunctionStrParameter(e.inputs[column]) + for row := int64(0); row < length; row++ { + index := sourceRow(e.inputs[column], int(start), int(row)) + if e.inputs[column].IsNull(uint64(index)) { + continue + } + value, _ := parameter.GetStrValue(uint64(index)) + valueBytes := int64(len(value)) + // JSON canonicalization can add escaping and separators. The + // factor is intentionally conservative; a bound that is not + // clearly safe falls back to the ordinary bounded probes. + if typ.Oid == types.T_json { + valueBytes = add(valueBytes, valueBytes) + } + estimate = add(estimate, valueBytes) + estimate = add(estimate, perRowOverhead) + } + } + if estimate > maxEstimate/safetyNumerator { + return false + } + return estimate*safetyNumerator <= maxBytes*safetyDenominator } + func sourceRow(v *vector.Vector, start, row int) int { if v.IsConst() { return 0 diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 0caea06d05b05..cf1f812fdcc88 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -145,6 +145,101 @@ func TestBuildInputRecordRejectsEmptyConstantVector(t *testing.T) { require.ErrorContains(t, err, "shorter than batch range") } +func TestInputBatchEncoderReusesSchemaAndPreservesRange(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + input := vector.NewVec(types.T_int64.ToType()) + defer func() { + input.Free(mp) + mpool.DeleteMPool(mp) + }() + for _, value := range []int64{10, 20, 30} { + require.NoError(t, vector.AppendFixed(input, value, false, mp)) + } + encoder, err := newInputBatchEncoder( + []*vector.Vector{input}, []types.Type{types.T_int64.ToType()}, + ) + require.NoError(t, err) + first, firstSchema, err := encoder.build(0, 2) + require.NoError(t, err) + defer first.Release() + second, secondSchema, err := encoder.build(2, 1) + require.NoError(t, err) + defer second.Release() + require.Same(t, firstSchema, secondSchema) + firstValues := first.Column(0).(*array.Int64) + secondValues := second.Column(0).(*array.Int64) + require.Equal(t, int64(10), firstValues.Value(0)) + require.Equal(t, int64(20), firstValues.Value(1)) + require.Equal(t, int64(30), secondValues.Value(0)) +} + +func TestInputBatchWireEncoderReusesSchemaAcrossBatches(t *testing.T) { + descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + field, err := descriptor.Field("arg_0") + require.NoError(t, err) + schema := arrow.NewSchema([]arrow.Field{field}, nil) + makeRecord := func(value int64) arrow.RecordBatch { + builder := array.NewInt64Builder(memory.NewGoAllocator()) + builder.Append(value) + values := builder.NewInt64Array() + record := array.NewRecordBatch(schema, []arrow.Array{values}, 1) + values.Release() + return record + } + + encoder := &inputBatchWireEncoder{schema: schema} + first := makeRecord(1) + second := makeRecord(2) + defer first.Release() + defer second.Release() + defer func() { require.NoError(t, encoder.close()) }() + + firstFrames, err := encoder.encode(first, DefaultMaxBatchBytes) + require.NoError(t, err) + secondFrames, err := encoder.encode(second, DefaultMaxBatchBytes) + require.NoError(t, err) + require.Len(t, firstFrames, 2) + require.Len(t, secondFrames, 2) + require.Equal(t, firstFrames[0].Header, secondFrames[0].Header) + require.Equal(t, firstFrames[0].Body, secondFrames[0].Body) + require.NotEqual(t, firstFrames[1].Body, secondFrames[1].Body) +} + +func TestInputBatchWireEncoderRecoversAfterOversizeCandidate(t *testing.T) { + descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + field, err := descriptor.Field("arg_0") + require.NoError(t, err) + schema := arrow.NewSchema([]arrow.Field{field}, nil) + makeRecord := func(values ...int64) arrow.RecordBatch { + builder := array.NewInt64Builder(memory.NewGoAllocator()) + builder.AppendValues(values, nil) + arrayValues := builder.NewInt64Array() + record := array.NewRecordBatch(schema, []arrow.Array{arrayValues}, int64(len(values))) + arrayValues.Release() + return record + } + + one := makeRecord(1) + defer one.Release() + measure := &inputBatchWireEncoder{schema: schema} + oneFrames, err := measure.encode(one, DefaultMaxBatchBytes) + require.NoError(t, err) + maxBytes := int64(len(oneFrames[0].Header) + len(oneFrames[0].Body) + len(oneFrames[1].Header) + len(oneFrames[1].Body)) + require.NoError(t, measure.close()) + + encoder := &inputBatchWireEncoder{schema: schema} + defer func() { require.NoError(t, encoder.close()) }() + wider := makeRecord(1, 2) + defer wider.Release() + _, err = encoder.encode(wider, maxBytes) + require.ErrorIs(t, err, errArrowBatchTooLarge) + frames, err := encoder.encode(one, maxBytes) + require.NoError(t, err) + require.Len(t, frames, 2) +} + func TestArrowValueDomainRejectsWidthAndTimeOverflow(t *testing.T) { allocator := memory.NewGoAllocator() stringBuilder := array.NewStringBuilder(allocator) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index b4de40772d9ff..66edcb1fe3ba2 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -20,6 +20,7 @@ import ( "strings" "sync" "time" + "unicode/utf8" "github.com/apache/arrow-go/v18/arrow/flight/gen/flight" "github.com/matrixorigin/matrixone/pkg/common/mpool" @@ -53,6 +54,8 @@ const ( var errGatewayClosed = errors.New("python udf gateway is closed") +var _ udf.RuntimeDefinitionValidator = (*Gateway)(nil) + type Gateway struct { cfg ClientConfig artifactResolver ArtifactResolver @@ -171,6 +174,194 @@ func (g *Gateway) CheckLanguageReady(ctx context.Context, language string) error return g.ensureCapabilities(ctx, client) } +// ValidateDefinition asks the current worker to compile the exact artifact +// that a CREATE or REPLACE is about to publish. This action has no +// FunctionRef, invocation lease, handler slot, or ledger entry: a definition +// has not acquired a Catalog identity and must not consume execution state. +// The worker performs compile(source, ..., "exec") only; it does not execute +// top-level code, import dependencies, or call the handler. +func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.RoutineDefinition) error { + g.mu.Lock() + closed := g.closed + g.mu.Unlock() + if closed { + return errGatewayClosed + } + if !g.cfg.Enabled { + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") + } + if !g.cfg.AllowUnisolated { + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") + } + if ctx == nil { + ctx = context.Background() + } + if definition == nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: nil Python routine definition") + } + if definition.Language != "" && definition.Language != udf.LanguagePython { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported UDF language %q", definition.Language) + } + if strings.TrimSpace(definition.Handler) == "" { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python handler is required") + } + if strings.Contains(definition.Handler, ":") { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires the immutable artifact catalog") + } + if definition.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion || + definition.ABIContract != udf.PythonABIContract || + definition.AdapterVersion != udf.PythonAdapterVersion || + definition.SDKVersion != udf.PythonSDKVersion { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition contract is not supported") + } + if definition.Mode != ModeScalar && definition.Mode != ModeVector { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python mode %q", definition.Mode) + } + if definition.NullPolicy != NullCallHandler && definition.NullPolicy != NullReturnNull { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python NULL policy %q", definition.NullPolicy) + } + if !udf.IsSHA256Digest(definition.ArtifactDigest) || !udf.IsSHA256Digest(definition.EnvironmentDigest) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition digest is invalid") + } + currentEnvironment, err := udf.PythonEnvironmentDigest() + if err != nil || currentEnvironment != definition.EnvironmentDigest { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the current contract") + } + if !udf.IsSHA256Digest(definition.DefinitionFingerprint) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint is invalid") + } + args := make([]TypeDescriptor, len(definition.Args)) + for index, typ := range definition.Args { + args[index], err = NewTypeDescriptor(typ) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python argument descriptor %d: %w", index, err) + } + } + returnDescriptor, err := NewTypeDescriptor(definition.ReturnType) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python return descriptor: %w", err) + } + expectedFingerprint, err := DefinitionFingerprint( + definition.DefinitionSchemaVersion, + definition.Handler, definition.Mode, definition.NullPolicy, + definition.ABIContract, definition.AdapterVersion, + definition.ArtifactDigest, definition.EnvironmentDigest, definition.SDKVersion, + args, returnDescriptor, + ) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint cannot be computed: %w", err) + } + if definition.DefinitionFingerprint != expectedFingerprint { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition") + } + + source := definition.Source + if g.artifactResolver != nil { + resolved, resolveErr := g.artifactResolver.Resolve( + ctx, definition.AccountID, definition.Handler, definition.ArtifactDigest, + ) + if resolveErr != nil { + return resolveErr + } + if source != "" && source != resolved { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source does not match the immutable artifact") + } + source = resolved + } else if !g.allowInlineSource { + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") + } + if source == "" || !utf8.ValidString(source) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is empty or not valid UTF-8") + } + if int64(len([]byte(source))) > DefaultMaxArtifactBytes { + return fmt.Errorf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", DefaultMaxArtifactBytes) + } + if udf.PythonInlineArtifactDigest(definition.Handler, source) != definition.ArtifactDigest { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") + } + + client, err := g.flightClient() + if err != nil { + return err + } + if err := g.ensureCapabilities(ctx, client); err != nil { + return err + } + payload, err := json.Marshal(definitionValidationPayload{ + AccountID: definition.AccountID, + Handler: definition.Handler, + Source: source, + Mode: definition.Mode, + NullPolicy: definition.NullPolicy, + ABIContract: definition.ABIContract, + AdapterVersion: definition.AdapterVersion, + SDKVersion: definition.SDKVersion, + DefinitionSchemaVersion: definition.DefinitionSchemaVersion, + ArtifactDigest: definition.ArtifactDigest, + EnvironmentDigest: definition.EnvironmentDigest, + DefinitionFingerprint: definition.DefinitionFingerprint, + Args: args, + Return: returnDescriptor, + }) + if err != nil { + return fmt.Errorf("python udf: encode definition validation: %w", err) + } + actionCtx, cancel := context.WithTimeout(ctx, g.cfg.RequestTimeout) + defer cancel() + stream, err := client.DoAction(actionCtx, &flight.Action{Type: "ValidatePythonDefinition", Body: payload}) + if err != nil { + g.invalidateCapabilities() + return fmt.Errorf("python udf: definition validation action: %w", err) + } + result, err := stream.Recv() + if err != nil { + g.invalidateCapabilities() + return fmt.Errorf("python udf: definition validation response: %w", err) + } + if result == nil { + g.invalidateCapabilities() + return fmt.Errorf("python udf: empty definition validation response") + } + var response definitionValidationResponse + decoder := json.NewDecoder(bytes.NewReader(result.Body)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(&response); err != nil { + g.invalidateCapabilities() + return fmt.Errorf("python udf: decode definition validation response: %w", err) + } + var trailing any + if err := decoder.Decode(&trailing); err != io.EOF { + g.invalidateCapabilities() + return fmt.Errorf("python udf: definition validation response has trailing JSON") + } + if response.Status == "ERROR" { + if _, err := stream.Recv(); err != io.EOF { + g.invalidateCapabilities() + if err == nil { + return fmt.Errorf("python udf: definition validation returned multiple results") + } + return fmt.Errorf("python udf: definition validation stream: %w", err) + } + if response.Reason == "" { + return fmt.Errorf("USER_CODE: Python definition validation failed") + } + return errors.New(response.Reason) + } + if response.Status != statusOK || response.ArtifactDigest != definition.ArtifactDigest || + response.DefinitionFingerprint != definition.DefinitionFingerprint { + g.invalidateCapabilities() + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition validation returned an invalid result") + } + if _, err := stream.Recv(); err != io.EOF { + g.invalidateCapabilities() + if err == nil { + return fmt.Errorf("python udf: definition validation returned multiple results") + } + return fmt.Errorf("python udf: definition validation stream: %w", err) + } + return nil +} + func (g *Gateway) connect() error { _, err := g.flightClient() return err @@ -320,6 +511,23 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if execution.Length == 0 { return result.PreExtendAndReset(0) } + inputEncoder, err := newInputBatchEncoder(execution.Inputs, execution.Args) + if err != nil { + return err + } + inputEncoderClosed := false + closeInputEncoder := func() error { + if inputEncoderClosed { + return nil + } + inputEncoderClosed = true + return inputEncoder.close() + } + defer func() { + if closeErr := closeInputEncoder(); err == nil && closeErr != nil { + err = closeErr + } + }() client, err := g.flightClient() if err != nil { return err @@ -410,7 +618,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul var lastSequence uint64 var inputEnded bool for start < int64(execution.Length) { - batch, err := encodeInputBatch(execution.Inputs, execution.Args, start, int64(execution.Length)-start, g.cfg.MaxBatchBytes, g.cfg.MaxBatchRows) + batch, err := encodeInputBatchWithEncoder(inputEncoder, start, int64(execution.Length)-start, g.cfg.MaxBatchBytes, g.cfg.MaxBatchRows) if err != nil { return err } @@ -471,7 +679,10 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if !inputEnded || lastSequence != batchIndex { return fmt.Errorf("python udf: input stream did not reach EndInput") } - return g.receiveFinish(streamCtx, client, stream, execution.Tuple, execution.Length, rows, &sequence) + if err := g.receiveFinish(streamCtx, client, stream, execution.Tuple, execution.Length, rows, &sequence); err != nil { + return err + } + return closeInputEncoder() } // invocationAdmission is the real Gateway owner for the CN-side execution @@ -770,6 +981,33 @@ type capabilityRequest struct { ProtocolVersion int `json:"protocol_version"` } +// definitionValidationPayload is a create-time action payload. It is not a +// plan or an invocation envelope: it carries the source only after the +// Gateway has resolved the exact account-scoped artifact digest. +type definitionValidationPayload struct { + AccountID uint64 `json:"account_id"` + Handler string `json:"handler"` + Source string `json:"source"` + Mode string `json:"mode"` + NullPolicy string `json:"null_policy"` + ABIContract string `json:"abi_contract"` + AdapterVersion string `json:"adapter_version"` + SDKVersion string `json:"sdk_version"` + DefinitionSchemaVersion int `json:"definition_schema_version"` + ArtifactDigest string `json:"artifact_digest"` + EnvironmentDigest string `json:"environment_digest"` + DefinitionFingerprint string `json:"definition_fingerprint"` + Args []TypeDescriptor `json:"args"` + Return TypeDescriptor `json:"return"` +} + +type definitionValidationResponse struct { + Status string `json:"status"` + Reason string `json:"reason,omitempty"` + ArtifactDigest string `json:"artifact_digest,omitempty"` + DefinitionFingerprint string `json:"definition_fingerprint,omitempty"` +} + type capabilityResponse struct { ProtocolVersion int `json:"protocol_version"` ABIContract string `json:"abi_contract"` @@ -919,6 +1157,14 @@ func sameStrings(actual, expected []string) bool { } func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaining, maxBytes, maxRows int64) (encodedRecordBatch, error) { + encoder, err := newInputBatchEncoder(inputs, args) + if err != nil { + return encodedRecordBatch{}, err + } + return encodeInputBatchWithEncoder(encoder, start, remaining, maxBytes, maxRows) +} + +func encodeInputBatchWithEncoder(encoder *inputBatchEncoder, start, remaining, maxBytes, maxRows int64) (encodedRecordBatch, error) { if start < 0 || remaining <= 0 { return encodedRecordBatch{}, fmt.Errorf("invalid Python UDF input batch range") } @@ -933,8 +1179,11 @@ func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaini // work without assuming anything about variable-length SQL values. The // slice keeps the same backing buffers, and every candidate is still encoded // and checked against maxBytes before publication. - if fixedWidthInputTypes(args) { - record, _, err := BuildInputRecordRange(inputs, args, int(start), int(remaining)) + if encoder == nil { + return encodedRecordBatch{}, fmt.Errorf("invalid Python UDF input encoder") + } + if encoder.fixedWidth { + record, _, err := encoder.build(int(start), int(remaining)) if err != nil { return encodedRecordBatch{}, err } @@ -942,32 +1191,43 @@ func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaini tryEncode := func(rows int64) ([]ArrowFrame, error) { candidate := record.NewSlice(0, rows) defer candidate.Release() - return EncodeRecordBatch(candidate, maxBytes) + return encoder.encode(candidate, maxBytes) } - return chooseInputBatch(remaining, maxBytes, tryEncode) + // The full fixed-width record is already materialized under the + // invocation's bounded input range. Try publishing it once before the + // size search; the normal SQL batch fits in the limit and avoids a + // logarithmic series of identical IPC encodes. + return chooseInputBatchWithFullCandidate(remaining, maxBytes, tryEncode, true) } tryEncode := func(rows int64) ([]ArrowFrame, error) { - record, _, err := BuildInputRecordRange(inputs, args, int(start), int(rows)) + record, _, err := encoder.build(int(start), int(rows)) if err != nil { return nil, err } - frames, encodeErr := EncodeRecordBatch(record, maxBytes) + frames, encodeErr := encoder.encode(record, maxBytes) record.Release() return frames, encodeErr } - return chooseInputBatch(remaining, maxBytes, tryEncode) + return chooseInputBatchWithFullCandidate( + remaining, maxBytes, tryEncode, + encoder.canBuildFullBatch(start, remaining, maxBytes), + ) } -func fixedWidthInputTypes(args []types.Type) bool { - for _, typ := range args { - if typ.IsVarlen() { - return false - } - } - return true +func chooseInputBatch(remaining, maxBytes int64, tryEncode func(int64) ([]ArrowFrame, error)) (encodedRecordBatch, error) { + return chooseInputBatchWithFullCandidate(remaining, maxBytes, tryEncode, false) } -func chooseInputBatch(remaining, maxBytes int64, tryEncode func(int64) ([]ArrowFrame, error)) (encodedRecordBatch, error) { +func chooseInputBatchWithFullCandidate(remaining, maxBytes int64, tryEncode func(int64) ([]ArrowFrame, error), tryFull bool) (encodedRecordBatch, error) { + if tryFull { + frames, err := tryEncode(remaining) + if err == nil { + return encodedRecordBatch{Frames: frames, Rows: remaining}, nil + } + if !errors.Is(err, errArrowBatchTooLarge) { + return encodedRecordBatch{}, err + } + } best, probe := int64(0), int64(1) var bestFrames []ArrowFrame failedAt := int64(0) diff --git a/pkg/udf/python/gateway_benchmark_test.go b/pkg/udf/python/gateway_benchmark_test.go index 2ab7f7d49dc40..bd95a5bc1a6f3 100644 --- a/pkg/udf/python/gateway_benchmark_test.go +++ b/pkg/udf/python/gateway_benchmark_test.go @@ -47,13 +47,18 @@ func BenchmarkEncodeInputBatchFixedWidthRebuildBaseline(b *testing.B) { input.Free(mp) mpool.DeleteMPool(mp) }() + encoder, err := newInputBatchEncoder([]*vector.Vector{input}, []types.Type{types.T_int64.ToType()}) + if err != nil { + b.Fatal(err) + } + defer func() { _ = encoder.close() }() b.ReportAllocs() b.SetBytes(int64(rows)) b.ResetTimer() for i := 0; i < b.N; i++ { batch, err := encodeInputBatchRebuildBaseline( - []*vector.Vector{input}, []types.Type{types.T_int64.ToType()}, + encoder, 0, rows, DefaultMaxBatchBytes, rows, ) if err != nil { @@ -69,6 +74,37 @@ func BenchmarkEncodeInputBatchVariableWidth(b *testing.B) { benchmarkEncodeInputBatch(b, types.New(types.T_varchar, 64, 0)) } +func BenchmarkEncodeInputBatchVariableWidthRebuildBaseline(b *testing.B) { + const rows = 8192 + typ := types.New(types.T_varchar, 64, 0) + input, mp := benchmarkInputVector(b, typ, rows) + defer func() { + input.Free(mp) + mpool.DeleteMPool(mp) + }() + encoder, err := newInputBatchEncoder([]*vector.Vector{input}, []types.Type{typ}) + if err != nil { + b.Fatal(err) + } + defer func() { _ = encoder.close() }() + + b.ReportAllocs() + b.SetBytes(int64(rows)) + b.ResetTimer() + for i := 0; i < b.N; i++ { + batch, err := encodeInputBatchRebuildBaseline( + encoder, + 0, rows, DefaultMaxBatchBytes, rows, + ) + if err != nil { + b.Fatal(err) + } + if batch.Rows != rows || len(batch.Frames) != 2 { + b.Fatalf("unexpected encoded batch rows=%d frames=%d", batch.Rows, len(batch.Frames)) + } + } +} + func benchmarkEncodeInputBatch(b *testing.B, typ types.Type) { const rows = 8192 input, mp := benchmarkInputVector(b, typ, rows) @@ -76,13 +112,18 @@ func benchmarkEncodeInputBatch(b *testing.B, typ types.Type) { input.Free(mp) mpool.DeleteMPool(mp) }() + encoder, err := newInputBatchEncoder([]*vector.Vector{input}, []types.Type{typ}) + if err != nil { + b.Fatal(err) + } + defer func() { _ = encoder.close() }() b.ReportAllocs() b.SetBytes(int64(rows)) b.ResetTimer() for i := 0; i < b.N; i++ { - batch, err := encodeInputBatch( - []*vector.Vector{input}, []types.Type{typ}, 0, rows, + batch, err := encodeInputBatchWithEncoder( + encoder, 0, rows, DefaultMaxBatchBytes, rows, ) if err != nil { @@ -96,21 +137,22 @@ func benchmarkEncodeInputBatch(b *testing.B, typ types.Type) { // encodeInputBatchRebuildBaseline is a benchmark-only reference for the // pre-optimization path. It intentionally rebuilds the Arrow record for every -// size probe, while production encodeInputBatch slices one fixed-width record. +// size probe while sharing the reusable Flight writer with production. This +// measures input record construction and probe avoidance without counting +// repeated schema serialization as a second optimization. func encodeInputBatchRebuildBaseline( - inputs []*vector.Vector, - args []types.Type, + encoder *inputBatchEncoder, start, remaining, maxBytes, maxRows int64, ) (encodedRecordBatch, error) { if remaining > maxRows { remaining = maxRows } tryEncode := func(rows int64) ([]ArrowFrame, error) { - record, _, err := BuildInputRecordRange(inputs, args, int(start), int(rows)) + record, _, err := BuildInputRecordRange(encoder.inputs, encoder.args, int(start), int(rows)) if err != nil { return nil, err } - frames, encodeErr := EncodeRecordBatch(record, maxBytes) + frames, encodeErr := encoder.encode(record, maxBytes) record.Release() return frames, encodeErr } diff --git a/pkg/udf/python/gateway_integration_test.go b/pkg/udf/python/gateway_integration_test.go index 5e78aaf52da88..95d46fe22d8db 100644 --- a/pkg/udf/python/gateway_integration_test.go +++ b/pkg/udf/python/gateway_integration_test.go @@ -70,6 +70,36 @@ func TestGatewayExecutesAgainstRealPythonWorker(t *testing.T) { require.NoError(t, gateway.CheckLanguageReady(readyContext, udf.LanguagePython)) cancel() + t.Run("definition validation", func(t *testing.T) { + marker := filepath.Join(t.TempDir(), "executed") + source := fmt.Sprintf( + "from pathlib import Path\nPath(%q).write_text('executed')\ndef add(ctx, value): return value\n", + marker, + ) + valid := integrationInvocationForArgs( + ModeScalar, "add", source, + []types.Type{types.T_int64.ToType()}, nil, 0, + protocol.FencingTuple{AccountID: 1, StatementID: "definition-validation", GroupID: "definition-validation-group", GroupEpoch: 1, InvocationID: "valid", LeaseEpoch: 1}, + ) + publishIntegrationArtifact(t, artifactStore, valid) + definition := routineDefinitionForIntegration(valid) + validationContext, cancel := context.WithTimeout(context.Background(), 5*time.Second) + require.NoError(t, gateway.ValidateDefinition(validationContext, definition)) + cancel() + require.NoFileExists(t, marker, "definition validation executed top-level Python code") + + invalid := integrationInvocationForArgs( + ModeScalar, "add", "def add(ctx, value) return value", + []types.Type{types.T_int64.ToType()}, nil, 0, + protocol.FencingTuple{AccountID: 1, StatementID: "definition-validation-invalid", GroupID: "definition-validation-invalid-group", GroupEpoch: 1, InvocationID: "invalid", LeaseEpoch: 1}, + ) + publishIntegrationArtifact(t, artifactStore, invalid) + validationContext, cancel = context.WithTimeout(context.Background(), 5*time.Second) + err := gateway.ValidateDefinition(validationContext, routineDefinitionForIntegration(invalid)) + cancel() + require.ErrorContains(t, err, "USER_CODE: Python syntax error") + }) + t.Run("scalar", func(t *testing.T) { input, mp := integrationInput(t, []int64{1, 2, 3}) defer func() { @@ -629,3 +659,22 @@ func integrationInvocationForArgs( Tuple: tuple, } } + +func routineDefinitionForIntegration(invocation *udf.Invocation) *udf.RoutineDefinition { + return &udf.RoutineDefinition{ + Language: udf.LanguagePython, + AccountID: invocation.FunctionRef.AccountID, + Handler: invocation.Handler, + Args: append([]types.Type(nil), invocation.Args...), + ReturnType: invocation.ReturnType, + Mode: invocation.Mode, + NullPolicy: invocation.NullPolicy, + ABIContract: invocation.ABIContract, + AdapterVersion: invocation.AdapterVersion, + SDKVersion: invocation.SDKVersion, + DefinitionSchemaVersion: invocation.DefinitionSchemaVersion, + ArtifactDigest: invocation.ArtifactDigest, + EnvironmentDigest: invocation.EnvironmentDigest, + DefinitionFingerprint: invocation.DefinitionFingerprint, + } +} diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index c0eb7f0421183..d48139e6721a3 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -6,6 +6,7 @@ import json import os import pathlib +import pickle import signal import struct import subprocess @@ -81,7 +82,78 @@ def complete_open_payload(payload): return payload +def complete_definition_validation_payload(source="def f(ctx, value): return value", handler="f"): + descriptor = {"type_id": worker.INT64, "offset_width": 32} + payload = { + "account_id": 1, + "handler": handler, + "source": source, + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "abi_contract": worker.ABI_CONTRACT, + "adapter_version": worker.ADAPTER_VERSION, + "sdk_version": worker.SDK_VERSION, + "definition_schema_version": worker.DEFINITION_SCHEMA_VERSION, + "artifact_digest": worker._inline_artifact_digest(handler, source), + "environment_digest": worker._environment_digest(), + "definition_fingerprint": "", + "args": [descriptor], + "return": descriptor, + } + payload["definition_fingerprint"] = worker._definition_fingerprint(payload) + return payload + + class WorkerContractTest(unittest.TestCase): + def test_definition_validation_compiles_without_executing_module_code(self): + with tempfile.TemporaryDirectory(prefix="mo-udf-definition-") as directory: + marker = pathlib.Path(directory) / "executed" + source = ( + "from pathlib import Path\n" + f"Path({str(marker)!r}).write_text('executed')\n" + "def f(ctx, value): return value\n" + ) + payload = complete_definition_validation_payload(source) + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + try: + results = list( + server.do_action( + None, + flight.Action( + "ValidatePythonDefinition", + json.dumps(payload, separators=(",", ":")).encode(), + ), + ) + ) + self.assertEqual(1, len(results)) + self.assertEqual("OK", json.loads(bytes(results[0].body))["status"]) + self.assertFalse(marker.exists(), "definition validation executed module code") + self.assertEqual({}, server._active) + self.assertEqual({}, server._terminal) + finally: + server.shutdown() + + def test_definition_validation_rejects_syntax_before_catalog_state(self): + payload = complete_definition_validation_payload("def f(ctx, value) return value") + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + try: + results = list( + server.do_action( + None, + flight.Action( + "ValidatePythonDefinition", + json.dumps(payload, separators=(",", ":")).encode(), + ), + ) + ) + response = json.loads(bytes(results[0].body)) + self.assertEqual("ERROR", response["status"]) + self.assertRegex(response["reason"], r"USER_CODE: Python syntax error at line 1, column") + self.assertEqual({}, server._active) + self.assertEqual({}, server._terminal) + finally: + server.shutdown() + def test_capability_advertises_worker_instance_lease(self): encoded = worker._encode_capabilities( {"protocol_version": worker.PROTOCOL_VERSION}, lease_epoch=17 @@ -929,7 +1001,7 @@ def test_invocation_budget_is_cumulative_across_batches(self): output = pa.RecordBatch.from_arrays( [pa.array([1], type=pa.int64())], schema=result_schema ) - output_wire = worker._serialize_record_batch(output) + output_wire = worker._serialize_record_batch_message(output) output_bytes = pa.ipc.get_record_batch_size(output) for limit_name, limit, error_text, expected_calls in ( @@ -1064,6 +1136,64 @@ def test_handler_process_is_fresh_and_can_be_terminated(self): worker._run_handler_process(None, request, 0.1) self.assertLess(time.monotonic() - started, 2) + def test_record_batch_message_reuses_the_frozen_schema(self): + descriptor = {"type_id": worker.INT64, "offset_width": 32} + schema = worker._schema_from_descriptors([descriptor], "arg") + batch = pa.RecordBatch.from_arrays( + [pa.array([1, 2], type=pa.int64())], schema=schema + ) + stream_wire = worker._serialize_record_batch(batch) + message_wire = worker._serialize_record_batch_message(batch) + self.assertLess(len(message_wire), len(stream_wire)) + + decoded = worker._deserialize_record_batch_message(message_wire, schema) + self.assertEqual([1, 2], decoded.column(0).to_pylist()) + with self.assertRaisesRegex(ValueError, "valid Arrow record batch"): + worker._deserialize_record_batch_message( + message_wire, + worker._schema_from_descriptors( + [{"type_id": worker.VARCHAR, "offset_width": 32}], "arg" + ), + ) + + def test_handler_frame_keeps_arrow_bytes_out_of_pickle_metadata(self): + arrow_wire = b"arrow-payload" + parts, payload_size = worker._encode_execution_request( + { + "arrow_encoding": worker.HANDLER_ARROW_RECORD_BATCH, + "input": arrow_wire, + } + ) + self.assertEqual(4, len(parts)) + self.assertEqual(payload_size, len(parts[1]) + len(parts[2]) + len(parts[3])) + metadata = pickle.loads(parts[2], buffers=[pickle.PickleBuffer(parts[3])]) + self.assertIsInstance(metadata["input"], pickle.PickleBuffer) + self.assertEqual(arrow_wire, bytes(metadata["input"].raw())) + + def test_handler_process_accepts_schema_free_record_batch_messages(self): + descriptor = {"type_id": worker.INT64, "offset_width": 32} + schema = worker._schema_from_descriptors([descriptor], "arg") + result_schema = pa.schema([worker._field("result", descriptor)]) + batch = pa.RecordBatch.from_arrays( + [pa.array([1, 2], type=pa.int64())], schema=schema + ) + request = { + "source": "def f(ctx, x): return x + 1", + "handler": "f", + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "sdk_version": worker.SDK_VERSION, + "context": None, + "args": [descriptor], + "return": descriptor, + "max_batch_bytes": 1 << 20, + "arrow_encoding": worker.HANDLER_ARROW_RECORD_BATCH, + "input": worker._serialize_record_batch_message(batch), + } + output_wire = worker._run_handler_process(None, request, 3) + output = worker._deserialize_record_batch_message(output_wire, result_schema) + self.assertEqual([2, 3], output.column(0).to_pylist()) + @unittest.skipUnless(os.name == "posix", "process-group cleanup race") def test_handler_error_after_leader_exit_releases_quota(self): """A normal handler error must not strand H while its leader exits.""" @@ -2530,7 +2660,7 @@ def invoke(): @unittest.skipUnless(os.name == "posix", "handler deadline test") def test_handler_deadline_includes_request_serialization(self): # The session owns one monotonic timestamp for the whole request. A - # deterministic clock jump after pickle.dumps proves that serialization + # deterministic clock jump after request encoding proves that serialization # cannot consume time outside the handler budget. clock = iter((0.0, 0.0, 1.0)) session = None @@ -2538,7 +2668,7 @@ def test_handler_deadline_includes_request_serialization(self): with mock.patch.object(worker.time, "monotonic", side_effect=clock): session = worker._HandlerProcessSession() with self.assertRaisesRegex(TimeoutError, "handler execution timeout"): - session.run(None, {}, 0.05) + session.run(None, {"input": b"x"}, 0.05) finally: if session is not None: session.close() diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 0b4b0d3cf0dad..cc25b3c152414 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -59,6 +59,18 @@ TERMINAL_TTL_SECONDS = 300.0 ACK_TIMEOUT_SECONDS = 60.0 MAX_EXECUTION_FRAME_BYTES = 1 << 30 +# The handler IPC frame keeps the control metadata in pickle and transports +# the Arrow bytes through protocol 5's out-of-band buffer. The Arrow payload +# itself is a RecordBatch message; its schema is reconstructed from the +# frozen descriptors on both sides, so a schema message is not repeated for +# every batch in a bounded invocation burst. +HANDLER_ARROW_STREAM = "stream" +HANDLER_ARROW_RECORD_BATCH = "record_batch" +# A definition validation action carries one immutable source plus its typed +# contract. The source itself is bounded by the artifact limit below; keep +# the action envelope separate from MAX_CONTROL_BYTES, which bounds the +# smaller per-invocation control frames. +MAX_DEFINITION_VALIDATION_BYTES = (2 << 20) + MAX_CONTROL_BYTES MAX_HANDLER_PROCESSES = 8 # H is a worker-wide child limit. The two narrower limits prevent one # account, or one principal inside an account, from consuming all H slots. @@ -303,6 +315,24 @@ def _definition_fingerprint(payload: Dict[str, Any]) -> str: return hashlib.sha256(_canonical_definition_json(body)).hexdigest() _CAPABILITY_REQUEST_KEYS = frozenset({"protocol_version"}) +_DEFINITION_VALIDATION_KEYS = frozenset( + { + "account_id", + "handler", + "source", + "mode", + "null_policy", + "abi_contract", + "adapter_version", + "sdk_version", + "definition_schema_version", + "artifact_digest", + "environment_digest", + "definition_fingerprint", + "args", + "return", + } +) _CAPABILITY_RESPONSE_KEYS = frozenset( { "protocol_version", @@ -761,6 +791,111 @@ def _decode_capability_request(data: bytes) -> Dict[str, Any]: return value +def _decode_definition_validation(data: bytes) -> Dict[str, Any]: + """Decode the strict, pre-publication definition validation payload.""" + if not data or len(data) > MAX_DEFINITION_VALIDATION_BYTES: + raise ValueError("PROTOCOL: invalid definition validation size") + try: + value = json.loads( + bytes(data).decode("utf-8"), + object_pairs_hook=_reject_duplicate_json_pairs, + parse_constant=_reject_nonstandard_json_constant, + ) + except (UnicodeDecodeError, json.JSONDecodeError, RecursionError) as exc: + raise ValueError("PROTOCOL: invalid definition validation JSON") from exc + if not isinstance(value, dict) or set(value) != _DEFINITION_VALIDATION_KEYS: + raise ValueError("PROTOCOL: invalid definition validation fields") + + account_id = value.get("account_id") + if ( + isinstance(account_id, bool) + or not isinstance(account_id, int) + or account_id < 0 + or account_id > (1 << 64) - 1 + ): + raise ValueError("PROTOCOL: invalid definition validation account") + handler = _required_string(value, "handler") + if ":" in handler: + raise ValueError( + "UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires the immutable artifact catalog" + ) + source = _required_string(value, "source") + try: + source_bytes = source.encode("utf-8") + except UnicodeEncodeError as exc: + raise ValueError("PROTOCOL: definition validation source is not valid UTF-8") from exc + if len(source_bytes) > (1 << 20): + raise ValueError("RESOURCE_EXHAUSTED: Python artifact exceeds 1048576 bytes") + + mode = _required_string(value, "mode") + null_policy = _required_string(value, "null_policy") + abi_contract = _required_string(value, "abi_contract") + adapter_version = _required_string(value, "adapter_version") + sdk_version = _required_string(value, "sdk_version") + if mode not in (MODE_SCALAR, MODE_VECTOR) or null_policy not in (NULL_CALL, NULL_RETURN): + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported Python mode or NULL policy") + if abi_contract != ABI_CONTRACT or adapter_version != ADAPTER_VERSION: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported Python ABI contract") + if sdk_version != SDK_VERSION: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported Python SDK") + if value.get("definition_schema_version") != DEFINITION_SCHEMA_VERSION: + raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported Python definition schema") + artifact_digest = _required_digest(value, "artifact_digest") + environment_digest = _required_digest(value, "environment_digest") + definition_fingerprint = _required_digest(value, "definition_fingerprint") + if artifact_digest != _inline_artifact_digest(handler, source): + raise ValueError( + "UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the source" + ) + if environment_digest != _environment_digest(): + raise ValueError( + "UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the worker contract" + ) + + args = value.get("args") + result_descriptor = value.get("return") + if not isinstance(args, list) or any(not isinstance(item, dict) for item in args): + raise ValueError("TYPE_CONTRACT: definition validation args must be an array of descriptors") + if not isinstance(result_descriptor, dict): + raise ValueError("TYPE_CONTRACT: definition validation return must be a descriptor") + for index, descriptor in enumerate(args): + _field(f"arg_{index}", descriptor) + _field("return", result_descriptor) + expected_fingerprint = _definition_fingerprint(value) + if definition_fingerprint != expected_fingerprint: + raise ValueError( + "UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition" + ) + return value + + +def _validate_definition_syntax(value: Dict[str, Any]) -> None: + """Compile source without executing its module or resolving its handler.""" + try: + compile(value["source"], "", "exec") + except SyntaxError as exc: + line = exc.lineno or 0 + column = exc.offset or 0 + message = exc.msg or "invalid syntax" + raise ValueError( + f"USER_CODE: Python syntax error at line {line}, column {column}: {message}" + ) from exc + + +def _encode_definition_validation_result( + value: Dict[str, Any], status: str, reason: Optional[str] = None +) -> bytes: + response = {"status": status} + if reason: + response["reason"] = reason + if status == "OK": + response["artifact_digest"] = value["artifact_digest"] + response["definition_fingerprint"] = value["definition_fingerprint"] + return json.dumps(response, separators=(",", ":"), sort_keys=True, allow_nan=False).encode( + "utf-8" + ) + + def _encode_capabilities(request: Dict[str, Any], lease_epoch: int = 1) -> bytes: _decode_capability_request(json.dumps(request, separators=(",", ":")).encode("utf-8")) if isinstance(lease_epoch, bool) or not isinstance(lease_epoch, int) or lease_epoch <= 0 or lease_epoch > (1 << 64) - 1: @@ -1093,6 +1228,14 @@ def _field(name: str, descriptor: Dict[str, Any]) -> pa.Field: return pa.field(name, _arrow_type(descriptor), nullable=True, metadata=metadata) +def _schema_from_descriptors( + descriptors: Iterable[Dict[str, Any]], prefix: str +) -> pa.Schema: + return pa.schema( + [_field(f"{prefix}_{index}", descriptor) for index, descriptor in enumerate(descriptors)] + ) + + TypeMetadataKey = b"mo.udf.type" TypeFingerprintKey = b"mo.udf.type_fingerprint" @@ -1121,9 +1264,15 @@ def _validate_input_batch_schema( # Flight carries one stream schema, but each received RecordBatch still # owns a schema object. Validate every batch so a later frame cannot # replace a fixed-width Arrow type after the first frame was admitted. + # The first batch validates every field against the descriptor. Later + # batches only need the schema equality check in the normal case; rebuilding + # every Field and its metadata for every batch was measurable overhead on + # small W=1 bursts. Retain the detailed validation on the mismatch path so + # a malformed later frame still gets the same contract diagnosis. + if batch.schema == expected_schema: + return _validate_schema(batch.schema, descriptors) - if batch.schema != expected_schema: - raise ValueError("TYPE_CONTRACT: input batch schema changed") + raise ValueError("TYPE_CONTRACT: input batch schema changed") def _load_handler(source: str, handler: str): @@ -1385,8 +1534,21 @@ def _serialize_record_batch(record: pa.RecordBatch) -> bytes: return sink.getvalue().to_pybytes() +def _serialize_record_batch_message(record: pa.RecordBatch) -> memoryview: + """Serialize one Arrow record-batch message without repeating its schema.""" + try: + # Keep the Arrow-owned buffer alive through the returned memoryview so + # the parent can hand it directly to protocol 5's out-of-band buffer + # without first copying it into a Python bytes object. + return memoryview(record.serialize()) + except (pa.ArrowException, OSError, ValueError, TypeError) as exc: + raise ValueError("PROTOCOL: cannot serialize Arrow record batch") from exc + + def _deserialize_record_batch(data: bytes) -> pa.RecordBatch: - if not isinstance(data, (bytes, bytearray)) or not data: + if isinstance(data, pickle.PickleBuffer): + data = data.raw() + if not isinstance(data, (bytes, bytearray, memoryview)) or not data: raise ValueError("PROTOCOL: execution payload is missing an Arrow batch") try: reader = pa.ipc.open_stream(pa.py_buffer(data)) @@ -1406,15 +1568,46 @@ def _deserialize_record_batch(data: bytes) -> pa.RecordBatch: reader.close() +def _deserialize_record_batch_message(data: Any, schema: pa.Schema) -> pa.RecordBatch: + """Decode one schema-free Arrow IPC record-batch message. + + The schema is derived from the already validated routine descriptor. This + is an internal handler IPC format, not a replacement for the Flight + schema, which remains validated independently at the worker boundary. + """ + if isinstance(data, pickle.PickleBuffer): + data = data.raw() + if not isinstance(data, (bytes, bytearray, memoryview)) or not data: + raise ValueError("PROTOCOL: execution payload is missing an Arrow batch") + if not isinstance(schema, pa.Schema): + raise ValueError("PROTOCOL: execution payload schema is invalid") + try: + return pa.ipc.read_record_batch(pa.py_buffer(data), schema) + except (pa.ArrowException, OSError, ValueError, TypeError) as exc: + raise ValueError("PROTOCOL: execution payload is not a valid Arrow record batch") from exc + + def _execute_handler_batch( request: Dict[str, Any], *, handler=None, statement_context: Optional[StatementContext] = None, + input_schema: Optional[pa.Schema] = None, + result_schema: Optional[pa.Schema] = None, ) -> bytes: - batch = _deserialize_record_batch(request["input"]) args = request["args"] result_descriptor = request["return"] + arrow_encoding = request.get("arrow_encoding", HANDLER_ARROW_STREAM) + if arrow_encoding == HANDLER_ARROW_RECORD_BATCH: + if input_schema is None: + input_schema = _schema_from_descriptors(args, "arg") + batch = _deserialize_record_batch_message( + request["input"], input_schema + ) + elif arrow_encoding == HANDLER_ARROW_STREAM: + batch = _deserialize_record_batch(request["input"]) + else: + raise ValueError("PROTOCOL: unsupported handler Arrow encoding") mode = request["mode"] null_policy = request["null_policy"] sdk_version = request["sdk_version"] @@ -1442,12 +1635,15 @@ def _execute_handler_batch( values.append(handler(call_context, *params)) output = values output_array = _output_array(output, result_descriptor, batch.num_rows) - result_field = _field("result", result_descriptor) + if result_schema is None: + result_schema = pa.schema([_field("result", result_descriptor)]) result_batch = pa.RecordBatch.from_arrays( - [output_array], schema=pa.schema([result_field]) + [output_array], schema=result_schema ) if pa.ipc.get_record_batch_size(result_batch) > request["max_batch_bytes"]: raise ValueError("RESOURCE_EXHAUSTED: output batch exceeds byte limit") + if arrow_encoding == HANDLER_ARROW_RECORD_BATCH: + return _serialize_record_batch_message(result_batch) return _serialize_record_batch(result_batch) @@ -1469,6 +1665,78 @@ def _write_execution_frame(stream, payload: bytes) -> None: stream.flush() +def _encode_execution_request(request: Dict[str, Any]): + """Build a handler frame without copying Arrow bytes into pickle. + + The outer length bounds the complete frame. The first eight bytes of the + payload bound the pickle metadata, and protocol 5 carries exactly one + out-of-band Arrow buffer. Returning write parts lets the nonblocking + sender avoid concatenating another full request-sized byte string. + """ + if not isinstance(request, dict) or "input" not in request: + raise ValueError("PROTOCOL: execution request is missing an Arrow batch") + input_wire = request["input"] + if isinstance(input_wire, pickle.PickleBuffer): + input_wire = input_wire.raw() + if not isinstance(input_wire, (bytes, bytearray, memoryview)): + raise ValueError("PROTOCOL: execution request Arrow batch is not bytes-like") + if not input_wire: + raise ValueError("PROTOCOL: execution request Arrow batch is empty") + metadata = dict(request) + metadata["input"] = pickle.PickleBuffer(input_wire) + buffers = [] + try: + metadata_wire = pickle.dumps( + metadata, protocol=5, buffer_callback=buffers.append + ) + except (pickle.PickleError, TypeError, ValueError) as exc: + raise ValueError("PROTOCOL: cannot encode execution request") from exc + if len(buffers) != 1: + raise ValueError("PROTOCOL: execution request must contain one Arrow buffer") + arrow_wire = buffers[0].raw() + payload_size = 8 + len(metadata_wire) + len(arrow_wire) + if payload_size > MAX_EXECUTION_FRAME_BYTES: + raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") + parts = ( + struct.pack(">Q", payload_size), + struct.pack(">Q", len(metadata_wire)), + metadata_wire, + arrow_wire, + ) + return parts, payload_size + + +def _read_execution_request(stream) -> Optional[Dict[str, Any]]: + """Read and validate one metadata plus out-of-band Arrow frame.""" + header = stream.read(8) + if not header: + return None + if len(header) != 8: + raise EOFError("execution request header ended unexpectedly") + payload_size = struct.unpack(">Q", header)[0] + if payload_size > MAX_EXECUTION_FRAME_BYTES or payload_size < 8: + raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") + metadata_size = struct.unpack(">Q", _read_exact(stream, 8))[0] + if metadata_size > payload_size - 8: + raise ValueError("PROTOCOL: execution request metadata is too large") + metadata_wire = _read_exact(stream, metadata_size) + arrow_size = payload_size - 8 - metadata_size + if arrow_size <= 0: + raise ValueError("PROTOCOL: execution request Arrow batch is empty") + arrow_wire = _read_exact(stream, arrow_size) + try: + request = pickle.loads( + metadata_wire, buffers=[pickle.PickleBuffer(arrow_wire)] + ) + except (EOFError, pickle.PickleError, TypeError, ValueError) as exc: + raise ValueError("PROTOCOL: execution request metadata is invalid") from exc + if not isinstance(request, dict) or not isinstance( + request.get("input"), pickle.PickleBuffer + ): + raise ValueError("PROTOCOL: execution request does not contain one Arrow buffer") + return request + + def _watch_parent_liveness(read_fd: int) -> None: """Terminate the whole handler group when the worker disappears. @@ -1546,19 +1814,14 @@ def _execute_handler_subprocess() -> None: frozen = None handler = None statement_context = None + input_schema = None + result_schema = None while True: - header = sys.stdin.buffer.read(8) - if not header: - break - if len(header) != 8: - raise EOFError("execution request header ended unexpectedly") - size = struct.unpack(">Q", header)[0] - if size > MAX_EXECUTION_FRAME_BYTES: - raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") try: - request = pickle.loads(_read_exact(sys.stdin.buffer, size)) - if not isinstance(request, dict): - raise ValueError("PROTOCOL: execution request is not an object") + request = _read_execution_request(sys.stdin.buffer) + if request is None: + # EOF before a new frame is the normal burst shutdown. + break contract = { key: request.get(key) for key in ( @@ -1566,17 +1829,24 @@ def _execute_handler_subprocess() -> None: "adapter_version", "sdk_version", "definition_schema_version", "artifact_digest", "environment_digest", "definition_fingerprint", "context", "args", "return", "max_batch_bytes", "max_batch_rows", - "max_invocation_rows", "max_invocation_result_bytes", + "max_invocation_rows", "max_invocation_result_bytes", "arrow_encoding", ) } if frozen is None: frozen = contract statement_context = _statement_context(request.get("context")) handler = _load_handler(request["source"], request["handler"]) + if request.get("arrow_encoding") == HANDLER_ARROW_RECORD_BATCH: + input_schema = _schema_from_descriptors(request["args"], "arg") + result_schema = pa.schema([_field("result", request["return"])]) elif contract != frozen: raise ValueError("PROTOCOL: handler burst contract changed") response = bytes([_HANDLER_RESPONSE_OK]) + _execute_handler_batch( - request, handler=handler, statement_context=statement_context + request, + handler=handler, + statement_context=statement_context, + input_schema=input_schema, + result_schema=result_schema, ) except Exception as exc: response = bytes([_HANDLER_RESPONSE_ERROR]) + _safe_error(exc).encode("utf-8") @@ -1974,13 +2244,11 @@ def run(self, context, request: Dict[str, Any], timeout_seconds: float) -> bytes # unbounded part of the caller's budget before the deadline was even # installed. deadline = time.monotonic() + timeout_seconds - request_wire = pickle.dumps(request, protocol=5) + request_parts, request_size = _encode_execution_request(request) if time.monotonic() >= deadline: raise TimeoutError("DEADLINE_EXCEEDED: handler execution timeout") - if len(request_wire) > MAX_EXECUTION_FRAME_BYTES: - raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") - request_frame = struct.pack(">Q", len(request_wire)) + request_wire - request_offset = 0 + request_part_index = 0 + request_part_offset = 0 stdin_fd = self._process.stdin.fileno() self._selector.register(stdin_fd, selectors.EVENT_WRITE, "request") try: @@ -1997,13 +2265,25 @@ def run(self, context, request: Dict[str, Any], timeout_seconds: float) -> bytes for event, _ in events: if event.data == "request": try: - written = os.write(stdin_fd, request_frame[request_offset:]) + while request_part_index < len(request_parts): + part = request_parts[request_part_index] + if request_part_offset == len(part): + request_part_index += 1 + request_part_offset = 0 + continue + written = os.write(stdin_fd, part[request_part_offset:]) + if written <= 0: + raise BrokenPipeError("handler request channel made no progress") + request_part_offset += written + if request_part_offset < len(part): + break except BlockingIOError: continue except BrokenPipeError as exc: - raise ValueError("USER_CODE: handler process closed its request channel") from exc - request_offset += written - if request_offset == len(request_frame): + raise ValueError( + "USER_CODE: handler process closed its request channel" + ) from exc + if request_part_index == len(request_parts): self._selector.unregister(stdin_fd) else: try: @@ -2031,7 +2311,7 @@ def run(self, context, request: Dict[str, Any], timeout_seconds: float) -> bytes raise ValueError("PROTOCOL: handler process returned an unknown status") output = response[1:] self._burst_batches += 1 - self._burst_bytes += len(request_wire) + len(response) + self._burst_bytes += request_size + len(response) return output finally: # A failed write/read must not leave a stale registration that a @@ -2727,6 +3007,23 @@ def do_action(self, context, action): # path before any routine is opened. yield flight.Result(_encode_capabilities(request, self._lease_epoch)) return + if action.type == "ValidatePythonDefinition": + value = _decode_definition_validation(action.body) + try: + _validate_definition_syntax(value) + except Exception as exc: + # A syntax error is a definition result, not an invocation + # failure. Returning a bounded structured result lets the + # Gateway reject CREATE/REPLACE without creating an active + # invocation, handler process, or terminal tombstone. + yield flight.Result( + _encode_definition_validation_result( + value, "ERROR", _safe_error(exc) + ) + ) + else: + yield flight.Result(_encode_definition_validation_result(value, "OK")) + return control = _decode_control(action.body) key = _tuple_key(control["tuple"]) self._require_current_lease(key) @@ -2924,7 +3221,8 @@ def do_exchange(self, context, descriptor, reader, writer): "max_batch_rows": max_batch_rows, "max_invocation_rows": max_invocation_rows, "max_invocation_result_bytes": max_invocation_result_bytes, - "input": _serialize_record_batch(batch), + "arrow_encoding": HANDLER_ARROW_RECORD_BATCH, + "input": _serialize_record_batch_message(batch), } if handler_session is None: owner_id = _handler_quota_owner(payload) @@ -2937,7 +3235,9 @@ def do_exchange(self, context, descriptor, reader, writer): output_wire = handler_session.run( context, execution_request, handler_timeout_seconds ) - output_batch = _deserialize_record_batch(output_wire) + output_batch = _deserialize_record_batch_message( + output_wire, result_schema + ) if output_batch.num_rows != batch.num_rows or output_batch.num_columns != 1: raise ValueError("TYPE_CONTRACT: handler result has the wrong shape") _validate_field(output_batch.schema.field(0), "result", result_descriptor) diff --git a/pkg/udf/runtime.go b/pkg/udf/runtime.go index 3c92e352a560d..e56f5e08b78a7 100644 --- a/pkg/udf/runtime.go +++ b/pkg/udf/runtime.go @@ -279,6 +279,42 @@ type RuntimeReadiness interface { CheckLanguageReady(context.Context, string) error } +// RoutineDefinition is the typed, pre-publication contract handed to a +// language runtime for definition validation. It is deliberately separate +// from Invocation: a CREATE or REPLACE has no FunctionRef/revision yet and +// must be validated before the new Catalog revision becomes visible. +// +// Source is transient create-time input. An executable plan never carries +// source; a runtime with an ArtifactResolver must resolve the same immutable +// artifact digest before sending source to the worker. +type RoutineDefinition struct { + Language string + AccountID uint64 + Handler string + Source string + Args []types.Type + ReturnType types.Type + Mode string + NullPolicy string + ABIContract string + AdapterVersion string + SDKVersion string + DefinitionSchemaVersion int + ArtifactDigest string + EnvironmentDigest string + DefinitionFingerprint string +} + +// RuntimeDefinitionValidator is an optional language runtime capability. +// Python CREATE/REPLACE requires it: the worker must compile the exact +// immutable artifact before Catalog publication. Keeping this as a separate +// capability preserves the language-neutral execution interface and lets +// ordinary SQL UDFs continue to use Runtime implementations that do not own +// a source validation protocol. +type RuntimeDefinitionValidator interface { + ValidateDefinition(context.Context, *RoutineDefinition) error +} + // Registry dispatches to the one runtime selected by a routine's language. // A registry is immutable after construction, so plan execution cannot race // service registration or observe a partially initialized adapter. @@ -332,6 +368,21 @@ func (r *runtimeRegistry) CheckLanguageReady(ctx context.Context, language strin return readiness.CheckLanguageReady(ctx, language) } +func (r *runtimeRegistry) ValidateDefinition(ctx context.Context, definition *RoutineDefinition) error { + if definition == nil { + return moerr.NewInvalidInputNoCtx("nil UDF routine definition") + } + runtime := r.byLanguage[definition.Language] + if runtime == nil { + return moerr.NewNotSupportedf(ctx, "%s UDF runtime is not enabled", definition.Language) + } + validator, ok := runtime.(RuntimeDefinitionValidator) + if !ok { + return moerr.NewNotSupportedf(ctx, "%s UDF runtime does not expose definition validation", definition.Language) + } + return validator.ValidateDefinition(ctx, definition) +} + func (r *runtimeRegistry) Close() error { r.closeOnce.Do(func() { languages := make([]string, 0, len(r.byLanguage)) diff --git a/test/distributed/cases/udf_python/udf_python.sql b/test/distributed/cases/udf_python/udf_python.sql index 26799d1531eea..e0f580774427b 100644 --- a/test/distributed/cases/udf_python/udf_python.sql +++ b/test/distributed/cases/udf_python/udf_python.sql @@ -9,6 +9,19 @@ insert into input_values values (1), (null), (3); select v, python_bvt_add(v) as plus_one from input_values order by v is null, v; select case when v is null then 99 else python_bvt_add(v) end as guarded from input_values order by v is null, v; +-- Python source is compiled by the current worker before a Catalog identity +-- or revision is published. +-- @regex("Python syntax error at line",true) +create function python_bvt_bad_syntax (x int) returns int language python as 'def python_bvt_bad_syntax(ctx, x) return x' handler 'python_bvt_bad_syntax'; + +-- A failed replacement keeps the previous immutable active revision usable. +create function python_bvt_replace (x int) returns int language python as 'def python_bvt_replace(ctx, x): return x + 10' handler 'python_bvt_replace'; +select python_bvt_replace(1); +-- @regex("Python syntax error at line",true) +create or replace function python_bvt_replace (x int) returns int language python as 'def python_bvt_replace(ctx, x) return x + 20' handler 'python_bvt_replace'; +select python_bvt_replace(1); + drop function python_bvt_add(int); +drop function python_bvt_replace(int); drop table input_values; drop database udf_python_bvt; From 42a806459a0a19089aa492c503ecad9b94247456 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 11 Sep 2026 22:17:01 +0800 Subject: [PATCH 055/241] fix(udf): read handler frames across pipe short reads --- pkg/udf/python/worker/test_worker.py | 23 +++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 11 ++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index d48139e6721a3..78812bc17af3f 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1170,6 +1170,29 @@ def test_handler_frame_keeps_arrow_bytes_out_of_pickle_metadata(self): self.assertIsInstance(metadata["input"], pickle.PickleBuffer) self.assertEqual(arrow_wire, bytes(metadata["input"].raw())) + def test_handler_request_reader_accepts_fragmented_headers(self): + parts, _ = worker._encode_execution_request( + { + "arrow_encoding": worker.HANDLER_ARROW_RECORD_BATCH, + "input": b"arrow-payload", + } + ) + + class OneByteReader: + def __init__(self, data): + self.data = data + + def read(self, size=-1): + if not self.data: + return b"" + count = 1 if size < 0 else min(1, size) + value, self.data = self.data[:count], self.data[count:] + return value + + request = worker._read_execution_request(OneByteReader(b"".join(parts))) + self.assertEqual(worker.HANDLER_ARROW_RECORD_BATCH, request["arrow_encoding"]) + self.assertEqual(b"arrow-payload", bytes(request["input"].raw())) + def test_handler_process_accepts_schema_free_record_batch_messages(self): descriptor = {"type_id": worker.INT64, "offset_width": 32} schema = worker._schema_from_descriptors([descriptor], "arg") diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index cc25b3c152414..ae2c41f4a41f6 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1708,11 +1708,16 @@ def _encode_execution_request(request: Dict[str, Any]): def _read_execution_request(stream) -> Optional[Dict[str, Any]]: """Read and validate one metadata plus out-of-band Arrow frame.""" - header = stream.read(8) - if not header: + # A pipe is a byte stream: one read is allowed to return a prefix even + # when the sender has already written the complete frame. Read one byte + # first so only an empty read means clean burst EOF, then complete the + # fixed-width header through the same exact-read path as the body. + first = stream.read(1) + if not first: return None - if len(header) != 8: + if len(first) != 1: raise EOFError("execution request header ended unexpectedly") + header = bytes(first) + _read_exact(stream, 7) payload_size = struct.unpack(">Q", header)[0] if payload_size > MAX_EXECUTION_FRAME_BYTES or payload_size < 8: raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") From 8306f1fd8604ac6543cffa85de2c7d3c5b4411df Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 11 Sep 2026 22:17:55 +0800 Subject: [PATCH 056/241] fix(udf): keep Arrow encoder cleanup retryable --- pkg/udf/python/arrow.go | 5 ++++- pkg/udf/python/arrow_test.go | 22 ++++++++++++++++++++++ pkg/udf/python/gateway.go | 5 ++++- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 1d80e00bd67a7..40da330625b81 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -472,13 +472,16 @@ func (e *inputBatchWireEncoder) close() error { if e == nil || e.closed { return nil } - e.closed = true if e.writer == nil { + e.closed = true return nil } if err := e.writer.Close(); err != nil { return fmt.Errorf("close Arrow record batch encoder: %w", err) } + // Commit the closed state only after the writer has released its resources. + // A failed close remains retryable for the owning invocation cleanup path. + e.closed = true return nil } diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index cf1f812fdcc88..5a4ca75bed7ee 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -240,6 +240,28 @@ func TestInputBatchWireEncoderRecoversAfterOversizeCandidate(t *testing.T) { require.Len(t, frames, 2) } +func TestInputBatchWireEncoderCloseIsIdempotent(t *testing.T) { + descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + field, err := descriptor.Field("arg_0") + require.NoError(t, err) + schema := arrow.NewSchema([]arrow.Field{field}, nil) + builder := array.NewInt64Builder(memory.NewGoAllocator()) + builder.AppendValues([]int64{1}, nil) + values := builder.NewInt64Array() + record := array.NewRecordBatch(schema, []arrow.Array{values}, 1) + values.Release() + defer record.Release() + + encoder := &inputBatchWireEncoder{schema: schema} + _, err = encoder.encode(record, DefaultMaxBatchBytes) + require.NoError(t, err) + require.NoError(t, encoder.close()) + require.NoError(t, encoder.close()) + _, err = encoder.encode(record, DefaultMaxBatchBytes) + require.ErrorContains(t, err, "invalid Arrow record batch encoder") +} + func TestArrowValueDomainRejectsWidthAndTimeOverflow(t *testing.T) { allocator := memory.NewGoAllocator() stringBuilder := array.NewStringBuilder(allocator) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 66edcb1fe3ba2..6ebcf0bfd2958 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -520,8 +520,11 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if inputEncoderClosed { return nil } + if err := inputEncoder.close(); err != nil { + return err + } inputEncoderClosed = true - return inputEncoder.close() + return nil } defer func() { if closeErr := closeInputEncoder(); err == nil && closeErr != nil { From fef319128d9c5ea0cd7ff9fcee5f074f9705169c Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 11 Sep 2026 22:18:42 +0800 Subject: [PATCH 057/241] fix(udf): finalize input before terminal success --- pkg/udf/python/gateway.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 6ebcf0bfd2958..3b5ff104a3eb6 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -682,10 +682,17 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if !inputEnded || lastSequence != batchIndex { return fmt.Errorf("python udf: input stream did not reach EndInput") } + // Close the local Arrow writer before accepting the worker's terminal + // Finish. If finalizing the local input owner fails, the admission cleanup + // still has a chance to cancel/close the remote invocation; acknowledging + // Finish first would publish remote success while returning a local error. + if err := closeInputEncoder(); err != nil { + return err + } if err := g.receiveFinish(streamCtx, client, stream, execution.Tuple, execution.Length, rows, &sequence); err != nil { return err } - return closeInputEncoder() + return nil } // invocationAdmission is the real Gateway owner for the CN-side execution From 4e885bc07defee3a53d1bf8a28818e20889af236 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 11 Sep 2026 22:19:27 +0800 Subject: [PATCH 058/241] fix(udf): classify invalid handler buffers --- pkg/udf/python/worker/test_worker.py | 6 ++++++ pkg/udf/python/worker/worker.py | 10 +++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 78812bc17af3f..b4d1d1c226a64 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1193,6 +1193,12 @@ def read(self, size=-1): self.assertEqual(worker.HANDLER_ARROW_RECORD_BATCH, request["arrow_encoding"]) self.assertEqual(b"arrow-payload", bytes(request["input"].raw())) + def test_handler_request_encoder_rejects_non_contiguous_arrow_buffer(self): + with self.assertRaisesRegex(ValueError, "cannot encode execution request"): + worker._encode_execution_request( + {"input": memoryview(b"arrow-payload")[::2]} + ) + def test_handler_process_accepts_schema_free_record_batch_messages(self): descriptor = {"type_id": worker.INT64, "offset_width": 32} schema = worker._schema_from_descriptors([descriptor], "arg") diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index ae2c41f4a41f6..a05f8f6b20cdc 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1683,17 +1683,17 @@ def _encode_execution_request(request: Dict[str, Any]): if not input_wire: raise ValueError("PROTOCOL: execution request Arrow batch is empty") metadata = dict(request) - metadata["input"] = pickle.PickleBuffer(input_wire) buffers = [] try: + metadata["input"] = pickle.PickleBuffer(input_wire) metadata_wire = pickle.dumps( metadata, protocol=5, buffer_callback=buffers.append ) - except (pickle.PickleError, TypeError, ValueError) as exc: + if len(buffers) != 1: + raise ValueError("PROTOCOL: execution request must contain one Arrow buffer") + arrow_wire = buffers[0].raw() + except (BufferError, pickle.PickleError, TypeError, ValueError) as exc: raise ValueError("PROTOCOL: cannot encode execution request") from exc - if len(buffers) != 1: - raise ValueError("PROTOCOL: execution request must contain one Arrow buffer") - arrow_wire = buffers[0].raw() payload_size = 8 + len(metadata_wire) + len(arrow_wire) if payload_size > MAX_EXECUTION_FRAME_BYTES: raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") From fe5ede4a4377f28678f2bf4ef026a316b91649d9 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 11 Sep 2026 22:22:34 +0800 Subject: [PATCH 059/241] fix(udf): reject trailing handler batch bytes --- pkg/udf/python/worker/test_worker.py | 2 ++ pkg/udf/python/worker/worker.py | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index b4d1d1c226a64..02188127337d6 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1155,6 +1155,8 @@ def test_record_batch_message_reuses_the_frozen_schema(self): [{"type_id": worker.VARCHAR, "offset_width": 32}], "arg" ), ) + with self.assertRaisesRegex(ValueError, "valid Arrow record batch"): + worker._deserialize_record_batch_message(bytes(message_wire) + b"junk", schema) def test_handler_frame_keeps_arrow_bytes_out_of_pickle_metadata(self): arrow_wire = b"arrow-payload" diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index a05f8f6b20cdc..6d99c2ec253c9 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1582,7 +1582,11 @@ def _deserialize_record_batch_message(data: Any, schema: pa.Schema) -> pa.Record if not isinstance(schema, pa.Schema): raise ValueError("PROTOCOL: execution payload schema is invalid") try: - return pa.ipc.read_record_batch(pa.py_buffer(data), schema) + reader = pa.BufferReader(pa.py_buffer(data)) + record = pa.ipc.read_record_batch(reader, schema) + if reader.tell() != reader.size(): + raise ValueError("trailing bytes after Arrow record batch") + return record except (pa.ArrowException, OSError, ValueError, TypeError) as exc: raise ValueError("PROTOCOL: execution payload is not a valid Arrow record batch") from exc From 257b4ead9685b25fbf7d1ec2505157a87f8cc1e9 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 11 Sep 2026 22:25:35 +0800 Subject: [PATCH 060/241] fix(udf): validate Python handler bindings at create --- pkg/udf/python/worker/test_worker.py | 46 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 28 ++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 02188127337d6..f30d33304486a 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -154,6 +154,52 @@ def test_definition_validation_rejects_syntax_before_catalog_state(self): finally: server.shutdown() + def test_definition_validation_rejects_missing_handler_before_catalog_state(self): + payload = complete_definition_validation_payload( + "def other(ctx, value): return value" + ) + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + try: + results = list( + server.do_action( + None, + flight.Action( + "ValidatePythonDefinition", + json.dumps(payload, separators=(",", ":")).encode(), + ), + ) + ) + response = json.loads(bytes(results[0].body)) + self.assertEqual("ERROR", response["status"]) + self.assertIn("not a module-level function", response["reason"]) + self.assertEqual({}, server._active) + self.assertEqual({}, server._terminal) + finally: + server.shutdown() + + def test_definition_validation_rejects_async_handler_before_catalog_state(self): + payload = complete_definition_validation_payload( + "async def f(ctx, value): return value" + ) + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + try: + results = list( + server.do_action( + None, + flight.Action( + "ValidatePythonDefinition", + json.dumps(payload, separators=(",", ":")).encode(), + ), + ) + ) + response = json.loads(bytes(results[0].body)) + self.assertEqual("ERROR", response["status"]) + self.assertIn("must be synchronous", response["reason"]) + self.assertEqual({}, server._active) + self.assertEqual({}, server._terminal) + finally: + server.shutdown() + def test_capability_advertises_worker_instance_lease(self): encoded = worker._encode_capabilities( {"protocol_version": worker.PROTOCOL_VERSION}, lease_epoch=17 diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 6d99c2ec253c9..20d3a6ec4446b 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -14,6 +14,7 @@ from __future__ import annotations import argparse +import ast import contextlib import datetime as _datetime import decimal as _decimal @@ -870,7 +871,7 @@ def _decode_definition_validation(data: bytes) -> Dict[str, Any]: def _validate_definition_syntax(value: Dict[str, Any]) -> None: - """Compile source without executing its module or resolving its handler.""" + """Validate source and the static handler binding without executing it.""" try: compile(value["source"], "", "exec") except SyntaxError as exc: @@ -880,6 +881,31 @@ def _validate_definition_syntax(value: Dict[str, Any]) -> None: raise ValueError( f"USER_CODE: Python syntax error at line {line}, column {column}: {message}" ) from exc + handler = value["handler"] + if not handler.isidentifier(): + raise ValueError( + "USER_CODE: Python handler must be a module-level identifier" + ) + tree = ast.parse(value["source"], filename="", mode="exec") + binding = None + for node in tree.body: + if isinstance(node, ast.AsyncFunctionDef) and node.name == handler: + raise ValueError("USER_CODE: Python handler must be synchronous") + if isinstance(node, ast.FunctionDef) and node.name == handler: + binding = node + break + if isinstance(node, ast.Assign) and isinstance(node.value, ast.Lambda): + if any(isinstance(target, ast.Name) and target.id == handler for target in node.targets): + binding = node + break + if isinstance(node, ast.AnnAssign) and isinstance(node.value, ast.Lambda): + if isinstance(node.target, ast.Name) and node.target.id == handler: + binding = node + break + if binding is None: + raise ValueError( + f"USER_CODE: Python handler {handler!r} is not a module-level function" + ) def _encode_definition_validation_result( From 0d3472ce18ef3cc19eb8b805f4158859ead5bcdf Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 11 Sep 2026 22:30:59 +0800 Subject: [PATCH 061/241] fix(udf): validate empty and typed input boundaries --- pkg/udf/python/arrow.go | 18 +++++++++++++++--- pkg/udf/python/arrow_test.go | 14 ++++++++++++++ pkg/udf/python/gateway.go | 18 +++++++++++++++--- pkg/udf/python/gateway_test.go | 18 ++++++++++++++++++ 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 40da330625b81..5697fbc8b22bf 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -531,8 +531,20 @@ func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBat if typ.IsVarlen() { fixedWidth = false } - if inputs[i] == nil || inputs[i].Length() == 0 { - return nil, fmt.Errorf("input column %d is shorter than batch range", i) + if inputs[i] == nil { + return nil, fmt.Errorf("input column %d is missing", i) + } + actualType := inputs[i].GetType() + if actualType == nil { + return nil, fmt.Errorf("input column %d has no type", i) + } + if !actualType.Eq(typ) { + return nil, fmt.Errorf( + "input column %d type %s does not match the frozen argument type %s", + i, + actualType.DescString(), + typ.DescString(), + ) } } schema := arrow.NewSchema(fields, nil) @@ -567,7 +579,7 @@ func (e *inputBatchEncoder) build(start, length int) (arrow.RecordBatch, *arrow. return nil, nil, fmt.Errorf("invalid Python UDF input shape") } for i, input := range e.inputs { - if !input.IsConst() && input.Length() < start+length { + if input.Length() == 0 || (!input.IsConst() && input.Length() < start+length) { return nil, nil, fmt.Errorf("input column %d is shorter than batch range", i) } } diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 5a4ca75bed7ee..7e24f171465c7 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -145,6 +145,20 @@ func TestBuildInputRecordRejectsEmptyConstantVector(t *testing.T) { require.ErrorContains(t, err, "shorter than batch range") } +func TestInputBatchEncoderRejectsMismatchedVectorType(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + input := vector.NewVec(types.T_int32.ToType()) + defer func() { + input.Free(mp) + mpool.DeleteMPool(mp) + }() + + _, err := newInputBatchEncoder( + []*vector.Vector{input}, []types.Type{types.T_int64.ToType()}, + ) + require.ErrorContains(t, err, "does not match the frozen argument type") +} + func TestInputBatchEncoderReusesSchemaAndPreservesRange(t *testing.T) { mp := mpool.MustNewZeroNoFixed() input := vector.NewVec(types.T_int64.ToType()) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 3b5ff104a3eb6..243f036a407d7 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -1650,10 +1650,22 @@ func validateInvocationInputs(invocation *udf.Invocation, args []TypeDescriptor) if invocation == nil || len(invocation.Inputs) != len(args) { return fmt.Errorf("python udf: invalid input shape") } - // An empty physical selection has no input backing to inspect. The - // descriptor and arity have already been validated above; keeping this - // case explicit allows zero-row operators to avoid manufacturing vectors. + // An empty physical selection has no input backing to inspect. Nil inputs + // are valid in this case, but a vector supplied by a caller still has to + // match the frozen descriptor. Otherwise a zero-row invocation could + // bypass the same type boundary enforced for non-empty execution. if invocation.Length == 0 { + for index, input := range invocation.Inputs { + if input == nil { + continue + } + if input.GetType() == nil || !input.GetType().Eq(invocation.Args[index]) { + return fmt.Errorf( + "python udf: input column %d type does not match the frozen argument type", + index, + ) + } + } return nil } for index, input := range invocation.Inputs { diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index c313e81eed2a7..128ea37a965e6 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -170,6 +170,24 @@ func validInvocation() *udf.Invocation { } } +func TestValidateInvocationInputsChecksZeroRowVectorTypes(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + input := vector.NewVec(types.T_int32.ToType()) + defer func() { + input.Free(mp) + mpool.DeleteMPool(mp) + }() + + descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + err = validateInvocationInputs(&udf.Invocation{ + Length: 0, + Args: []types.Type{types.T_int64.ToType()}, + Inputs: []*vector.Vector{input}, + }, []TypeDescriptor{descriptor}) + require.ErrorContains(t, err, "does not match the frozen argument type") +} + func TestValidateInvocationRequiresFrozenContract(t *testing.T) { base := validInvocation() require.NoError(t, validateInvocation(base)) From ff8e80e8b5d447da9918c8e682eca8553155b3c2 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 11 Sep 2026 22:33:38 +0800 Subject: [PATCH 062/241] fix(udf): reject unsupported routine types before allocation --- pkg/sql/colexec/external_routine_eval.go | 14 +++++++++----- pkg/sql/colexec/external_routine_eval_test.go | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index b14f4c444f907..e41386047e92f 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -138,13 +138,17 @@ func validateRoutineCall(call *planpb.RoutineCall) error { if !udf.IsSHA256Digest(python.DefinitionFingerprint) { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid definition fingerprint") } - if len(call.ArgumentTypes) > 0 { - for i, argumentType := range call.ArgumentTypes { - if argumentType == nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is nil", i) - } + for i, argumentType := range call.ArgumentTypes { + if argumentType == nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is nil", i) + } + if _, err := function.NewPythonTypeDescriptor(planTypeToSQL(*argumentType)); err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is unsupported: %w", i, err) } } + if _, err := function.NewPythonTypeDescriptor(planTypeToSQL(call.ReturnType)); err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python return descriptor is unsupported: %w", err) + } return nil } diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index 63a54ee27fc5e..31ae3847f95df 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -226,6 +226,23 @@ func TestExternalRoutineEvalRejectsMissingReturnDescriptor(t *testing.T) { }) } +func TestExternalRoutineEvalRejectsUnsupportedTypeBeforeResultAllocation(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + + call := testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler) + call.ReturnType = planpb.Type{Id: int32(types.T_decimal256), Width: 76, Scale: 2} + input := vector.NewVec(types.T_int64.ToType()) + defer input.Free(proc.Mp()) + + require.NotPanics(t, func() { + _, err := newExternalRoutineEval(proc, call, []ExpressionExecutor{ + &externalRoutineTestExecutor{vector: input}, + }, nil) + require.ErrorContains(t, err, "typed Python return descriptor is unsupported") + }) +} + func TestExternalRoutineEvalRejectsExecutionContextInPlan(t *testing.T) { call := testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler) call.Context = map[string]string{"current_user": "attacker"} From 8eed2174681eecb62b9de0d9f704bf7e381c31c2 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 11 Sep 2026 22:34:52 +0800 Subject: [PATCH 063/241] fix(udf): enforce exact external routine selection domain --- pkg/sql/colexec/external_routine_eval.go | 8 ++++++-- pkg/sql/colexec/external_routine_eval_test.go | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index e41386047e92f..db8a4537921e0 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -182,8 +182,12 @@ func (e *ExternalRoutineEval) Eval(proc *process.Process, batches []*batch.Batch } return e.result.GetResultVector(), nil } - if selectList != nil && len(selectList) < rowCount { - return nil, fmt.Errorf("external routine selection is shorter than the input batch") + if selectList != nil && len(selectList) != rowCount { + return nil, fmt.Errorf( + "external routine selection has %d rows, expected %d", + len(selectList), + rowCount, + ) } for i, parameter := range e.parameterExecutor { diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index 31ae3847f95df..ba187fdb53551 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -147,6 +147,25 @@ func TestExternalRoutineEvalOwnsSelectionAndStrictNullGuard(t *testing.T) { require.Equal(t, "alice", runtime.invocation.Context["current_user"]) } +func TestExternalRoutineEvalRejectsSelectionWithWrongRowDomain(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + + input := vector.NewVec(types.T_int64.ToType()) + defer input.Free(proc.Mp()) + require.NoError(t, vector.AppendFixed(input, int64(1), false, proc.Mp())) + inputBatch := batch.NewWithSize(0) + inputBatch.SetRowCount(1) + evaluator, err := newExternalRoutineEval(proc, testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler), []ExpressionExecutor{ + &externalRoutineTestExecutor{vector: input}, + }, nil) + require.NoError(t, err) + defer evaluator.Free() + + _, err = evaluator.Eval(proc, []*batch.Batch{inputBatch}, []bool{true, false}) + require.ErrorContains(t, err, "selection has 2 rows, expected 1") +} + func TestNewExpressionExecutorDispatchesTypedRoutineCall(t *testing.T) { proc := testutil.NewProcess(t) defer proc.Free() From 5647cd533c17d10bf62ad72dcb88018f756eae21 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 10:43:18 +0800 Subject: [PATCH 064/241] fix(udf): transfer external expression result ownership --- pkg/sql/colexec/external_routine_eval.go | 14 ++++++- pkg/sql/colexec/external_routine_eval_test.go | 38 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index db8a4537921e0..da90cf800e105 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -153,6 +153,10 @@ func validateRoutineCall(call *planpb.RoutineCall) error { } func (e *ExternalRoutineEval) Eval(proc *process.Process, batches []*batch.Batch, selectList []bool) (*vector.Vector, error) { + return e.eval(proc, batches, selectList, false) +} + +func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch, selectList []bool, transfer bool) (output *vector.Vector, evalErr error) { if e == nil || proc == nil || proc.Base == nil { return nil, fmt.Errorf("python udf: evaluator has no process") } @@ -161,6 +165,14 @@ func (e *ExternalRoutineEval) Eval(proc *process.Process, batches []*batch.Batch if e.freed { return nil, fmt.Errorf("python udf: evaluator is freed") } + // Transfer under executionMu, before a concurrent Eval/Free can reuse the + // backing. The wrapper retains its allocation policy for the next result. + defer func() { + if transfer && evalErr == nil { + e.result.SetResultVector(nil) + } + }() + if err := validateRoutineCall(e.call); err != nil { return nil, err } @@ -462,7 +474,7 @@ func (e *ExternalRoutineEval) scatter(proc *process.Process, selected *vector.Ve } func (e *ExternalRoutineEval) EvalWithoutResultReusing(proc *process.Process, batches []*batch.Batch, selectList []bool) (*vector.Vector, error) { - return e.Eval(proc, batches, selectList) + return e.eval(proc, batches, selectList, true) } func (e *ExternalRoutineEval) ResetForNextQuery() { diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index ba187fdb53551..03f3f8f5043e0 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -402,3 +402,41 @@ func TestExternalRoutineEvalRejectsSourceInExecutablePlan(t *testing.T) { call.GetPython().Source = "def add(ctx, value): return value + 1" require.ErrorContains(t, validateRoutineCall(call), "plan contains source") } + +func TestExternalRoutineTransfersResultOwnership(t *testing.T) { + for _, mode := range []string{"SCALAR", "VECTOR"} { + t.Run(mode, func(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + proc.SetQueryId("result-ownership") + proc.GetSessionInfo().TimeZone = time.UTC + proc.GetSessionInfo().User = "root" + proc.Base.StmtProfile = &process.StmtProfile{} + proc.GetStmtProfile().SetQueryStart(time.Date(2026, 9, 14, 0, 0, 0, 0, time.UTC)) + input := vector.NewVec(types.T_int64.ToType()) + defer input.Free(proc.Mp()) + require.NoError(t, vector.AppendFixed(input, int64(10), false, proc.Mp())) + require.NoError(t, vector.AppendFixed(input, int64(20), false, proc.Mp())) + bat := batch.NewWithSize(0) + bat.SetRowCount(2) + proc.Base.UdfService = &externalRoutineCaptureRuntime{} + evaluator, err := newExternalRoutineEval(proc, testExternalRoutineCall(t, mode, udf.NullCallHandler), []ExpressionExecutor{&externalRoutineTestExecutor{vector: input}}, nil) + require.NoError(t, err) + defer evaluator.Free() + owned, err := evaluator.EvalWithoutResultReusing(proc, []*batch.Batch{bat}, []bool{true, false}) + require.NoError(t, err) + // Only free when ownership actually moved, so the pre-fix counterexample + // reports the alias without double freeing the evaluator's vector. + if owned != evaluator.result.GetResultVector() { + defer owned.Free(proc.Mp()) + } + require.NotSame(t, owned, evaluator.result.GetResultVector()) + _, err = evaluator.Eval(proc, []*batch.Batch{bat}, nil) + require.NoError(t, err) + evaluator.Free() + require.Equal(t, 2, owned.Length()) + require.Equal(t, int64(11), vector.GetFixedAtNoTypeCheck[int64](owned, 0)) + require.True(t, owned.IsNull(1)) + }) + } +} From 8ee1f94098e33581f3658569f8fba0d19da99ae6 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 10:45:13 +0800 Subject: [PATCH 065/241] fix(udf): verify frozen definitions before evaluating arguments --- pkg/sql/colexec/external_routine_eval.go | 21 +++++++++++++++++-- pkg/sql/colexec/external_routine_eval_test.go | 17 +++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index da90cf800e105..cc90131a427d4 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -24,6 +24,7 @@ import ( planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/sql/plan/function" "github.com/matrixorigin/matrixone/pkg/udf" + pythonudf "github.com/matrixorigin/matrixone/pkg/udf/python" "github.com/matrixorigin/matrixone/pkg/vm/process" ) @@ -138,17 +139,33 @@ func validateRoutineCall(call *planpb.RoutineCall) error { if !udf.IsSHA256Digest(python.DefinitionFingerprint) { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid definition fingerprint") } + arguments := make([]pythonudf.TypeDescriptor, len(call.ArgumentTypes)) for i, argumentType := range call.ArgumentTypes { if argumentType == nil { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is nil", i) } - if _, err := function.NewPythonTypeDescriptor(planTypeToSQL(*argumentType)); err != nil { + descriptor, err := function.NewPythonTypeDescriptor(planTypeToSQL(*argumentType)) + if err != nil { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is unsupported: %w", i, err) } + arguments[i] = descriptor } - if _, err := function.NewPythonTypeDescriptor(planTypeToSQL(call.ReturnType)); err != nil { + result, err := function.NewPythonTypeDescriptor(planTypeToSQL(call.ReturnType)) + if err != nil { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python return descriptor is unsupported: %w", err) } + fingerprint, err := pythonudf.DefinitionFingerprint( + int(python.DefinitionSchemaVersion), python.Handler, python.Mode, python.NullPolicy, + python.AbiContract, python.AdapterVersion, python.ArtifactDigest, + python.EnvironmentDigest, python.SdkVersion, arguments, result, + ) + if err != nil { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: invalid typed Python definition: %w", err) + } + if fingerprint != python.DefinitionFingerprint { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python definition fingerprint mismatch") + } + return nil } diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index 03f3f8f5043e0..33982beafb1ce 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -440,3 +440,20 @@ func TestExternalRoutineTransfersResultOwnership(t *testing.T) { }) } } + +func TestExternalRoutineRejectsDamagedDefinitionBeforeArguments(t *testing.T) { + for _, damage := range []string{"precision", "fingerprint", "argument-type"} { + t.Run(damage, func(t *testing.T) { + call := testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler) + switch damage { + case "precision": + call.ReturnType = planpb.Type{Id: int32(types.T_decimal64), Width: 19, Scale: 2} + case "fingerprint": + call.GetPython().DefinitionFingerprint = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + case "argument-type": + call.ArgumentTypes[0].Id = int32(types.T_int32) + } + require.Error(t, validateRoutineCall(call)) + }) + } +} From 1fb7642d1770ce01a616cf0bf49b81a272efb9b6 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 10:49:19 +0800 Subject: [PATCH 066/241] fix(udf): skip arguments outside the selected row domain --- pkg/sql/colexec/external_routine_eval.go | 4 ++++ pkg/sql/colexec/external_routine_eval_test.go | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index cc90131a427d4..72594708e47cb 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -219,6 +219,10 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch ) } + if noRowsSelected(selectList, rowCount) { + return e.nullResult(rowCount) + } + for i, parameter := range e.parameterExecutor { var err error e.parameterResults[i], err = parameter.Eval(proc, batches, selectList) diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index 33982beafb1ce..36107b842e754 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -457,3 +457,25 @@ func TestExternalRoutineRejectsDamagedDefinitionBeforeArguments(t *testing.T) { }) } } + +func TestExternalRoutineSkipsArgumentsForEmptySelection(t *testing.T) { + for _, mode := range []string{"SCALAR", "VECTOR"} { + t.Run(mode, func(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + input := vector.NewVec(types.T_int64.ToType()) + defer input.Free(proc.Mp()) + require.NoError(t, vector.AppendFixed(input, int64(1), false, proc.Mp())) + seen := 0 + evaluator, err := newExternalRoutineEval(proc, testExternalRoutineCall(t, mode, udf.NullCallHandler), []ExpressionExecutor{&externalRoutineTestExecutor{vector: input, evalSeen: &seen}}, nil) + require.NoError(t, err) + defer evaluator.Free() + bat := batch.NewWithSize(0) + bat.SetRowCount(1) + result, err := evaluator.Eval(proc, []*batch.Batch{bat}, []bool{false}) + require.NoError(t, err) + require.True(t, result.IsNull(0)) + require.Zero(t, seen, "an unselected call must not evaluate any arguments") + }) + } +} From 3645af3b47f80696789bfc85c1d3f0848ac25d9b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 10:51:28 +0800 Subject: [PATCH 067/241] fix(udf): preserve canonical JSON tokens across adapters --- pkg/udf/python/worker/test_worker.py | 9 +++++++++ pkg/udf/python/worker/worker.py | 25 +++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index f30d33304486a..3e3e9925e502f 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -708,6 +708,15 @@ def test_json_input_is_canonicalized_before_handler(self): worker._scalar_input(array, 0, descriptor), ) + def test_json_canonical_text_preserves_number_and_string_tokens(self): + descriptor = {"type_id": worker.JSON, "offset_width": 32, "json_encoding": "canonical_text"} + for value in ('1e-7', '1e+20', r'{"escaped":"\u4e2d","number":1e-7}'): + with self.subTest(value=value): + self.assertEqual(value, worker._check_scalar(value, descriptor)) + self.assertEqual(value, worker._scalar_input(pa.array([value]), 0, descriptor)) + self.assertEqual('{"space":"a b","number":1e-7}', + worker._canonical_json_text(' { "space" : "a b", "number" : 1e-7 } ')) + def test_json_rejects_nonstandard_numbers(self): descriptor = {"type_id": worker.JSON, "offset_width": 32, "json_encoding": "canonical_text"} for value in ("NaN", "Infinity", "-Infinity", "1e9999"): diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 20d3a6ec4446b..f77f4b84b984a 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1355,14 +1355,35 @@ def reject_nonfinite_float(number: str): return parsed try: - parsed = json.loads( + json.loads( value, parse_constant=reject_nonstandard_number, parse_float=reject_nonfinite_float, ) except Exception as exc: raise ValueError("TYPE_CONTRACT: invalid JSON input") from exc - return json.dumps(parsed, ensure_ascii=False, separators=(",", ":")) + # Match the Gateway's json.Compact contract: remove insignificant + # whitespace without rewriting number or string tokens. A loads/dumps + # round trip changes e.g. 1e-7 to 1e-07 and makes SCALAR and VECTOR + # handlers observe different text for the same SQL value. + compact = [] + in_string = False + escaped = False + for char in value: + if in_string: + compact.append(char) + if escaped: + escaped = False + elif char == "\\": + escaped = True + elif char == '"': + in_string = False + elif char == '"': + in_string = True + compact.append(char) + elif char not in " \t\r\n": + compact.append(char) + return "".join(compact) def _check_json(value: str) -> str: From 41c6c70117eedcec77755e04bd1d4fd4a24a2232 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 10:52:53 +0800 Subject: [PATCH 068/241] fix(udf): avoid re-expanding shared routine query dependencies --- pkg/frontend/routine_plan_validation.go | 8 ++++++++ pkg/frontend/routine_plan_validation_test.go | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/pkg/frontend/routine_plan_validation.go b/pkg/frontend/routine_plan_validation.go index 0c411455bc538..27101cefe3594 100644 --- a/pkg/frontend/routine_plan_validation.go +++ b/pkg/frontend/routine_plan_validation.go @@ -96,6 +96,7 @@ func routinePlanDependencies(p *planpb.Plan) ([]*planpb.RoutinePlanDependency, e dependencyBytes := 0 stack := []queryFrame{{query: query}} active := map[*planpb.Query]struct{}{query: {}} + completed := make(map[*planpb.Query]struct{}) for len(stack) != 0 { frameIndex := len(stack) - 1 frame := &stack[frameIndex] @@ -119,6 +120,7 @@ func routinePlanDependencies(p *planpb.Plan) ([]*planpb.RoutinePlanDependency, e backgroundQueries := frame.query.GetBackgroundQueries() if frame.next >= len(backgroundQueries) { delete(active, frame.query) + completed[frame.query] = struct{}{} stack = stack[:frameIndex] continue } @@ -133,6 +135,12 @@ func routinePlanDependencies(p *planpb.Plan) ([]*planpb.RoutinePlanDependency, e if _, exists := active[background]; exists { return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency query graph contains a cycle") } + // Shared background queries contribute their immutable dependencies + // once. Re-expanding a DAG as a tree can turn a small plan into + // exponential work (even when it contains no routine dependencies). + if _, exists := completed[background]; exists { + continue + } active[background] = struct{}{} stack = append(stack, queryFrame{query: background, depth: frame.depth + 1}) } diff --git a/pkg/frontend/routine_plan_validation_test.go b/pkg/frontend/routine_plan_validation_test.go index bcabf01f4dd7d..ab710f975f07b 100644 --- a/pkg/frontend/routine_plan_validation_test.go +++ b/pkg/frontend/routine_plan_validation_test.go @@ -302,3 +302,15 @@ func TestRoutinePlanCatalogIdentityAcceptsAndRejectsSQLRevision(t *testing.T) { udf.SQLDefinitionSchemaVersion, "", "", "", udf.NullCallHandler, )) } + +func TestRoutinePlanDependenciesVisitsSharedQueriesOnce(t *testing.T) { + dependency := testRoutinePlanDependency() + query := &planpb.Query{RoutineDependencies: []*planpb.RoutinePlanDependency{dependency}} + for depth := 0; depth < 12; depth++ { + query = &planpb.Query{BackgroundQueries: []*planpb.Query{query, query}} + } + dependencies, err := routinePlanDependencies(&planpb.Plan{Plan: &planpb.Plan_Query{Query: query}}) + require.NoError(t, err) + require.Len(t, dependencies, 1) + require.Same(t, dependency, dependencies[0]) +} From 7c9bc97f030449121244f4114e736b2e74a70cc7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 10:54:34 +0800 Subject: [PATCH 069/241] fix(udf): own handler pipes before subsequent allocations --- pkg/udf/python/worker/test_worker.py | 35 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 6 +++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 3e3e9925e502f..d3930d3bf74d2 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1397,6 +1397,41 @@ def test_handler_quota_is_scoped_by_account_and_owner(self): third.release() self.assertEqual(({}, {}), quota.counts()) + def test_handler_initialization_closes_partial_pipe_ownership(self): + real_pipe = os.pipe + for failure in ("second_pipe", "watchdog_dup"): + with self.subTest(failure=failure): + opened = [] + slots = threading.BoundedSemaphore(1) + quota = worker._HandlerQuota(max_account_handlers=1, max_owner_handlers=1) + + def allocate_pipe(): + if failure == "second_pipe" and opened: + raise OSError("injected pipe exhaustion") + pair = real_pipe() + opened.extend(pair) + return pair + + try: + with mock.patch.object(worker.os, "pipe", side_effect=allocate_pipe), mock.patch.object( + worker.os, "dup", side_effect=OSError("injected dup exhaustion") + ), mock.patch.object(worker.subprocess, "Popen") as popen: + with self.assertRaisesRegex(OSError, "injected"): + worker._HandlerProcessSession(slots, handler_quota=quota, account_id=1, owner_id="owner") + popen.assert_not_called() + self.assertEqual(({}, {}), quota.counts()) + self.assertTrue(slots.acquire(blocking=False)) + slots.release() + for fd in opened: + with self.assertRaises(OSError, msg=f"descriptor {fd} leaked after {failure}"): + os.fstat(fd) + finally: + for fd in opened: + try: + os.close(fd) + except OSError: + pass + def test_handler_session_releases_account_owner_quota_idempotently(self): quota = worker._HandlerQuota(max_account_handlers=2, max_owner_handlers=1) session = worker._HandlerProcessSession( diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index f77f4b84b984a..f862a62c30f1d 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -2186,10 +2186,12 @@ def __init__( raise ValueError("RESOURCE_EXHAUSTED: handler execution slots are full") self._slot_acquired = True response_read_fd, response_write_fd = os.pipe() - parent_watch_read_fd, parent_watch_write_fd = os.pipe() - watchdog_read_fd = os.dup(parent_watch_read_fd) + # Publish each acquired descriptor to its cleanup owner before + # the next allocation can fail (in particular under FD pressure). self._response_read_fd = response_read_fd + parent_watch_read_fd, parent_watch_write_fd = os.pipe() self._parent_watch_write_fd = parent_watch_write_fd + watchdog_read_fd = os.dup(parent_watch_read_fd) popen_kwargs = { "stdin": subprocess.PIPE, # Handler output is diagnostic-only. It must never share the From d00e5df055673b20905eeb9518e81ed4f39b2c47 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 10:55:41 +0800 Subject: [PATCH 070/241] docs(udf): describe CI workers without isolation claims --- pkg/udf/python/worker/requirements.txt | 4 ++-- test/distributed/cases/udf_python/README.md | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/udf/python/worker/requirements.txt b/pkg/udf/python/worker/requirements.txt index d2a628aab1355..9a2bd0abbb48a 100644 --- a/pkg/udf/python/worker/requirements.txt +++ b/pkg/udf/python/worker/requirements.txt @@ -1,3 +1,3 @@ -# The worker is a separate sandbox process. The runtime image must pin the -# complete environment lock used when the routine revision was published. +# Dependencies for the unisolated external worker adapter. This lock does +# not provide a sandbox or tenant isolation. pyarrow==24.0.0 diff --git a/test/distributed/cases/udf_python/README.md b/test/distributed/cases/udf_python/README.md index 4b253a3642c6f..8e93f01a90baa 100644 --- a/test/distributed/cases/udf_python/README.md +++ b/test/distributed/cases/udf_python/README.md @@ -26,8 +26,10 @@ cd /path/to/mo-tester ``` The ordinary BVT launch starts one worker for the single CN. Compose BVT starts -one isolated worker service per CN from the same pinned image, so adding a SQL -case here does not require another CI workflow. +one dedicated worker service per CN, built from the same Dockerfile and +dependency lock. These workers are unisolated adapters; a separate process or +container does not establish tenant isolation. Adding a SQL case here does +not require another CI workflow. The cases keep the data sets small and target contract boundaries: @@ -47,6 +49,8 @@ The cases keep the data sets small and target contract boundaries: SELECT, and DELETE atomically without publishing partial changes. - `revision_lifecycle.sql` checks create, immutable-revision replacement, prepared-plan invalidation, drop, and recreate on the same SQL signature. +- `vector_mode.sql` checks Arrow VECTOR handlers, zero-argument batch shape, + NULL policies, and handler validation during create and replace. The shape follows established correctness coverage from [DuckDB's scalar UDF tests](https://github.com/duckdb/duckdb-go/blob/main/scalar_udf_test.go) From cfe9ab713972df613431a06354b88a42a2e56b65 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 10:59:23 +0800 Subject: [PATCH 071/241] test(udf): cover canonical JSON through real Flight batches --- pkg/udf/python/gateway_integration_test.go | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/pkg/udf/python/gateway_integration_test.go b/pkg/udf/python/gateway_integration_test.go index 95d46fe22d8db..44bcbdaee67f3 100644 --- a/pkg/udf/python/gateway_integration_test.go +++ b/pkg/udf/python/gateway_integration_test.go @@ -118,6 +118,53 @@ func TestGatewayExecutesAgainstRealPythonWorker(t *testing.T) { require.Equal(t, []int64{11, 12, 13}, vector.MustFixedColNoTypeCheck[int64](result.GetResultVector())) }) + for _, mode := range []string{ModeScalar, ModeVector} { + t.Run("JSON canonical text/"+mode, func(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + typ := types.T_json.ToType() + input := vector.NewVec(typ) + defer input.Free(mp) + // ByteJson renders this finite number as 0.000001. Python's + // loads/dumps would rewrite it to 1e-06, violating the shared + // compact-text contract before the handler even runs. + value, err := types.ParseStringToByteJson("0.000001") + require.NoError(t, err) + raw, err := value.Marshal() + require.NoError(t, err) + for _, null := range []bool{false, true, false} { + require.NoError(t, vector.AppendBytes(input, raw, null, mp)) + } + result := vector.NewFunctionResultWrapper(typ, mp) + defer result.Free() + invocation := integrationInvocationForArgs( + mode, "identity", "def identity(ctx, value): return value", + []types.Type{typ}, []*vector.Vector{input}, 3, + protocol.FencingTuple{AccountID: 1, StatementID: "json-" + mode, + GroupID: "json-group-" + mode, GroupEpoch: 1, InvocationID: "json-" + mode, LeaseEpoch: 1}, + ) + invocation.ReturnType = typ + descriptor, err := NewTypeDescriptor(typ) + require.NoError(t, err) + invocation.DefinitionFingerprint, err = DefinitionFingerprint( + invocation.DefinitionSchemaVersion, invocation.Handler, invocation.Mode, + invocation.NullPolicy, invocation.ABIContract, invocation.AdapterVersion, + invocation.ArtifactDigest, invocation.EnvironmentDigest, invocation.SDKVersion, + []TypeDescriptor{descriptor}, descriptor, + ) + require.NoError(t, err) + publishIntegrationArtifact(t, artifactStore, invocation) + require.NoError(t, gateway.Execute(context.Background(), invocation, result, mp)) + output := result.GetResultVector() + require.Equal(t, 3, output.Length()) + require.True(t, output.IsNull(1)) + for _, row := range []int{0, 2} { + require.False(t, output.IsNull(uint64(row))) + require.Equal(t, "0.000001", types.DecodeJson(output.GetBytesAt(row)).String()) + } + }) + } + t.Run("zero-argument scalar", func(t *testing.T) { mp := mpool.MustNewZeroNoFixed() defer mpool.DeleteMPool(mp) From 4a9857118763145d4a718b5141cc0bcdf306fee2 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 13:49:09 +0800 Subject: [PATCH 072/241] perf(udf): reduce scalar batch conversion overhead --- pkg/udf/python/gateway_integration_test.go | 79 ++++++++++++++++++ pkg/udf/python/worker/test_worker.py | 17 ++++ pkg/udf/python/worker/worker.py | 97 ++++++++++++++++++++-- 3 files changed, 188 insertions(+), 5 deletions(-) diff --git a/pkg/udf/python/gateway_integration_test.go b/pkg/udf/python/gateway_integration_test.go index 44bcbdaee67f3..64dec7b9b2b56 100644 --- a/pkg/udf/python/gateway_integration_test.go +++ b/pkg/udf/python/gateway_integration_test.go @@ -554,6 +554,85 @@ def add(ctx, value): }) } +// BenchmarkGatewayRealPythonWorkerLargeBatch compares the two handler modes +// on one 8,192-row batch. The small-batch burst benchmark above is dominated +// by process startup and Flight control traffic; this benchmark makes the +// scalar conversion cost visible while keeping the complete Gateway/Flight/ +// worker/materialization path intact. +func BenchmarkGatewayRealPythonWorkerLargeBatch(b *testing.B) { + python, err := exec.LookPath("python3") + if err != nil { + b.Skip("python3 is required for the real worker benchmark") + } + workerPath := realWorkerPath(b) + port := freeTCPPort(b) + worker := startRealWorker(b, python, workerPath, port) + defer stopRealWorker(worker) + + gateway, err := NewGateway(ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:" + strconv.Itoa(port), + MaxBatchBytes: 1 << 20, + MaxBatchRows: 8192, + MaxActiveInvocations: 2, + MaxInvocationRows: 1 << 20, + MaxInvocationResultBytes: 1 << 20, + RequestTimeout: 30 * time.Second, + MaxTerminalEntries: 1024, + MaxTerminalBytes: 1 << 20, + TerminalRecordTTL: time.Minute, + }) + if err != nil { + b.Fatal(err) + } + defer gateway.Close() + readyContext, cancel := context.WithTimeout(context.Background(), 5*time.Second) + if err := gateway.CheckLanguageReady(readyContext, udf.LanguagePython); err != nil { + cancel() + b.Fatal(err) + } + cancel() + + const rows = 8192 + run := func(b *testing.B, mode, source, label string) { + input, mp := integrationInput(b, make([]int64, rows)) + defer func() { + input.Free(mp) + mpool.DeleteMPool(mp) + }() + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer result.Free() + b.ReportAllocs() + b.SetBytes(int64(rows * 8)) + b.ResetTimer() + for iteration := 0; iteration < b.N; iteration++ { + runID := realWorkerBenchmarkRun.Add(1) + invocation := integrationInvocationForArgs( + mode, "add", source, []types.Type{types.T_int64.ToType()}, + []*vector.Vector{input}, rows, + protocol.FencingTuple{ + AccountID: 1, StatementID: fmt.Sprintf("large-%s-%d-%d", label, runID, iteration), + GroupID: fmt.Sprintf("large-%s-group-%d-%d", label, runID, iteration), GroupEpoch: 1, + InvocationID: fmt.Sprintf("large-%s-invocation-%d-%d", label, runID, iteration), LeaseEpoch: 1, + }, + ) + if err := gateway.Execute(context.Background(), invocation, result, mp); err != nil { + b.Fatal(err) + } + } + b.StopTimer() + b.ReportMetric(float64(rows*b.N)/float64(b.Elapsed().Nanoseconds())*1e9, "rows/s") + } + + b.Run("scalar", func(b *testing.B) { + run(b, ModeScalar, "def add(ctx, value): return value + 1", "scalar") + }) + b.Run("vector", func(b *testing.B) { + run(b, ModeVector, "import pyarrow.compute as pc\ndef add(ctx, values): return pc.add(values, 1)", "vector") + }) +} + func realWorkerPath(t testing.TB) string { t.Helper() _, sourceFile, _, ok := runtime.Caller(0) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index d3930d3bf74d2..f32ae1a458e82 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -514,6 +514,23 @@ def test_all_type_fixtures_round_trip_scalar_values_and_nulls(self): else: self.assertEqual(value, round_trip, name) + def test_scalar_column_materialization_preserves_fixed_width_values(self): + small_arrays = ( + pa.array([1, None, 3], type=pa.int64()), + pa.array([True, None, False], type=pa.bool_()), + pa.array([1.25, None, 3.5], type=pa.float64()), + ) + for array in small_arrays: + self.assertIsNone(worker._scalar_column_values(array)) + for array in ( + pa.array([1, None] + list(range(2, 64)), type=pa.int64()), + pa.array([True, None] + [False] * 62, type=pa.bool_()), + pa.array([1.25, None] + [float(value) for value in range(2, 64)], type=pa.float64()), + ): + with self.subTest(type=array.type): + self.assertEqual(array.to_pylist(), worker._scalar_column_values(array)) + self.assertIsNone(worker._scalar_column_values(pa.array(["a", None], type=pa.string()))) + def test_go_python_fingerprint_vectors(self): cases = [ ({"type_id": worker.INT64, "offset_width": 32}, "482d3c55b8a9d662c2b41326b3ca55cbae65153e662c47c4919ba020d006262b"), diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index f862a62c30f1d..8f2b4c2f0baf0 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -80,6 +80,11 @@ MAX_ACCOUNT_HANDLER_PROCESSES = MAX_HANDLER_PROCESSES MAX_OWNER_HANDLER_PROCESSES = MAX_HANDLER_PROCESSES // 2 _DEFAULT_HANDLER_SLOTS = threading.BoundedSemaphore(MAX_HANDLER_PROCESSES) +# Materializing a scalar column once is useful for a substantial batch, but +# costs more than indexed access for the tiny batches common in short calls. +# Keep this threshold local to the worker conversion path; it is not a wire +# or admission limit and does not change the handler's batch semantics. +SCALAR_MATERIALIZATION_MIN_ROWS = 64 _CONTROL_KEYS = frozenset( { "version", @@ -1341,6 +1346,54 @@ def _scalar_input(array: pa.Array, row: int, descriptor: Dict[str, Any]): return value +def _scalar_input_value(value: Any, descriptor: Dict[str, Any]): + if value is None: + return None + type_id = int(descriptor["type_id"]) + if type_id in (VECF32, VECF64): + # A scalar vector is exposed as read-only bytes. Consumers can use + # memoryview.cast("f"/"d") without receiving a mutable Arrow buffer. + import struct + values = value + fmt = "f" if type_id == VECF32 else "d" + return memoryview(struct.pack("<" + fmt * len(values), *values)) + if type_id in (DATE, DATETIME, TIMESTAMP): + zero = bool(value["is_zero"]) + child = value["value"] + if type_id == DATE: + return SqlDate(zero, None if zero else child) + if type_id == DATETIME: + return SqlDatetime(zero, None if zero else child) + return SqlTimestamp(zero, None if zero else child) + if type_id == JSON: + return _canonical_json_text(value) + if type_id == UUID: + return _uuid.UUID(bytes=bytes(value)) + return value + + +def _scalar_column_values(array: pa.Array): + """Materialize cheap fixed-width scalar columns once per batch. + + Calling Array.__getitem__().as_py() for every argument and row crosses + the PyArrow/Python boundary repeatedly. Primitive values have a bounded + representation under the batch row/byte limits, so one to_pylist() call + lets the scalar loop reuse those Python objects. Keep small, nested, and + variable-width values on the indexed path: that avoids retaining a second + copy of user data while preserving the same per-row conversion contract. + """ + if len(array) < SCALAR_MATERIALIZATION_MIN_ROWS: + return None + data_type = array.type + if ( + pa.types.is_boolean(data_type) + or pa.types.is_integer(data_type) + or pa.types.is_floating(data_type) + ): + return array.to_pylist() + return None + + def _canonical_json_text(value: str) -> str: if not isinstance(value, str): raise ValueError("TYPE_CONTRACT: JSON value must be text") @@ -1678,12 +1731,46 @@ def _execute_handler_batch( else: call_context = ScalarContext(sdk_version, _CallLogger(), statement_context) values = [] - for row in range(batch.num_rows): - params = [_scalar_input(batch.column(index), row, args[index]) for index in range(batch.num_columns)] - if null_policy == NULL_RETURN and any(value is None for value in params): - values.append(None) + if batch.num_rows < SCALAR_MATERIALIZATION_MIN_ROWS: + for row in range(batch.num_rows): + params = [ + _scalar_input(batch.column(index), row, args[index]) + for index in range(batch.num_columns) + ] + if null_policy == NULL_RETURN and any(value is None for value in params): + values.append(None) + else: + values.append(handler(call_context, *params)) + else: + columns = [batch.column(index) for index in range(batch.num_columns)] + scalar_columns = [ + _scalar_column_values(column) for column in columns + ] + if not any(column_values is not None for column_values in scalar_columns): + for row in range(batch.num_rows): + params = [ + _scalar_input(columns[index], row, args[index]) + for index in range(batch.num_columns) + ] + if null_policy == NULL_RETURN and any(value is None for value in params): + values.append(None) + else: + values.append(handler(call_context, *params)) else: - values.append(handler(call_context, *params)) + for row in range(batch.num_rows): + params = [ + _scalar_input_value( + column_values[row] + if column_values is not None + else columns[index][row].as_py(), + args[index], + ) + for index, column_values in enumerate(scalar_columns) + ] + if null_policy == NULL_RETURN and any(value is None for value in params): + values.append(None) + else: + values.append(handler(call_context, *params)) output = values output_array = _output_array(output, result_descriptor, batch.num_rows) if result_schema is None: From de7cf34e5b337ba70288a5fad619d2ea2464340d Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 13:51:47 +0800 Subject: [PATCH 073/241] refactor(udf): share scalar conversion contract --- pkg/udf/python/worker/worker.py | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 8f2b4c2f0baf0..8efe0b9a041bd 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1320,30 +1320,7 @@ def _load_handler(source: str, handler: str): def _scalar_input(array: pa.Array, row: int, descriptor: Dict[str, Any]): - value = array[row].as_py() - if value is None: - return None - type_id = int(descriptor["type_id"]) - if type_id in (VECF32, VECF64): - # A scalar vector is exposed as read-only bytes. Consumers can use - # memoryview.cast("f"/"d") without receiving a mutable Arrow buffer. - import struct - values = value - fmt = "f" if type_id == VECF32 else "d" - return memoryview(struct.pack("<" + fmt * len(values), *values)) - if type_id in (DATE, DATETIME, TIMESTAMP): - zero = bool(value["is_zero"]) - child = value["value"] - if type_id == DATE: - return SqlDate(zero, None if zero else child) - if type_id == DATETIME: - return SqlDatetime(zero, None if zero else child) - return SqlTimestamp(zero, None if zero else child) - if type_id == JSON: - return _canonical_json_text(value) - if type_id == UUID: - return _uuid.UUID(bytes=bytes(value)) - return value + return _scalar_input_value(array[row].as_py(), descriptor) def _scalar_input_value(value: Any, descriptor: Dict[str, Any]): From e69a213809559ca8d21d9ebdf3d1ba9ff7e0cacc Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 14:01:51 +0800 Subject: [PATCH 074/241] perf(udf): trim handler process startup --- pkg/udf/python/worker/Dockerfile | 2 +- pkg/udf/python/worker/watchdog.py | 45 ++++++++++++++++ pkg/udf/python/worker/worker.py | 90 +++++++++++++------------------ 3 files changed, 83 insertions(+), 54 deletions(-) create mode 100644 pkg/udf/python/worker/watchdog.py diff --git a/pkg/udf/python/worker/Dockerfile b/pkg/udf/python/worker/Dockerfile index 3fdb7d5528114..0a3aab23067dc 100644 --- a/pkg/udf/python/worker/Dockerfile +++ b/pkg/udf/python/worker/Dockerfile @@ -14,7 +14,7 @@ WORKDIR /home/mo # && apt-get update \ # && apt-get install -y vim -COPY requirements.txt worker.py ./ +COPY requirements.txt worker.py watchdog.py ./ RUN pip install --no-cache-dir -r requirements.txt diff --git a/pkg/udf/python/worker/watchdog.py b/pkg/udf/python/worker/watchdog.py new file mode 100644 index 0000000000000..25c417a73b7d4 --- /dev/null +++ b/pkg/udf/python/worker/watchdog.py @@ -0,0 +1,45 @@ +# Copyright 2026 Matrix Origin +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. + +"""Minimal process-group liveness watchdog for a Python UDF handler.""" + +import os +import signal +import sys + + +def _watch(read_fd: int, process_group_id: int) -> None: + try: + while True: + if os.read(read_fd, 1) == b"": + try: + os.killpg(process_group_id, signal.SIGKILL) + except ProcessLookupError: + pass + return + except (OSError, ValueError): + return + finally: + try: + os.close(read_fd) + except OSError: + pass + + +def main() -> None: + if len(sys.argv) != 3: + raise SystemExit("usage: watchdog.py READ_FD PROCESS_GROUP_ID") + try: + read_fd = int(sys.argv[1]) + process_group_id = int(sys.argv[2]) + except ValueError as exc: + raise SystemExit("watchdog arguments must be integers") from exc + if read_fd < 0 or process_group_id <= 0: + raise SystemExit("watchdog arguments are out of range") + _watch(read_fd, process_group_id) + + +if __name__ == "__main__": + main() diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 8efe0b9a041bd..6d68d887b296f 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -41,7 +41,24 @@ from zoneinfo import TZPATH, ZoneInfo, ZoneInfoNotFoundError import pyarrow as pa -import pyarrow.flight as flight + +# Handler children only need Arrow. Avoid importing Flight on that entry path; +# the annotations in this module are postponed, and the Flight server class is +# never instantiated by the handler child. +_HANDLER_ENTRY = "--execute-handler" in sys.argv + + +class _NoFlightServerBase: + pass + + +if _HANDLER_ENTRY: + flight = None + _FlightServerBase = _NoFlightServerBase +else: + import pyarrow.flight as flight + + _FlightServerBase = flight.FlightServerBase PROTOCOL_VERSION = 1 MAX_CONTROL_BYTES = 1 << 20 @@ -193,7 +210,6 @@ _HANDLER_RESPONSE_OK = 1 _HANDLER_RESPONSE_FD_ENV = "MATRIXONE_HANDLER_RESPONSE_FD" _HANDLER_PARENT_WATCH_FD_ENV = "MATRIXONE_HANDLER_PARENT_WATCH_FD" -_HANDLER_WATCHDOG_FD_ENV = "MATRIXONE_HANDLER_WATCHDOG_FD" _HANDLER_ENV_ALLOWLIST = frozenset({"PATH"}) _MICROS_PER_SECOND = 1_000_000 _MAX_TIME_MICROS = (838 * 60 * 60 + 59 * 60 + 59) * _MICROS_PER_SECOND @@ -1881,34 +1897,6 @@ def _watch_parent_liveness(read_fd: int) -> None: os._exit(137) -def _watch_handler_group(read_fd: int, process_group_id: int) -> None: - """Reap a handler process group even after its leader has exited. - - This watchdog is a worker-owned reliability process, not a security - boundary. It has no user-code imports and only has the group id plus a - read end of a worker-owned pipe. If the worker disappears, the pipe gets - EOF and the watchdog kills the whole handler process group. Keeping this - responsibility outside the handler leader closes the case where the - leader exits first while a descendant keeps running. - """ - try: - while True: - if os.read(read_fd, 1) == b"": - if os.name == "posix": - try: - os.killpg(process_group_id, signal.SIGKILL) - except ProcessLookupError: - pass - return - except (OSError, ValueError): - return - finally: - try: - os.close(read_fd) - except OSError: - pass - - def _execute_handler_subprocess() -> None: response_fd_text = os.environ.pop(_HANDLER_RESPONSE_FD_ENV, None) parent_watch_fd_text = os.environ.pop(_HANDLER_PARENT_WATCH_FD_ENV, None) @@ -2289,17 +2277,19 @@ def __init__( os.close(parent_watch_read_fd) parent_watch_read_fd = -1 if os.name == "posix": + watchdog_path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "watchdog.py" + ) watchdog_env = { name: value for name, value in os.environ.items() if name in _HANDLER_ENV_ALLOWLIST } - watchdog_env[_HANDLER_WATCHDOG_FD_ENV] = str(watchdog_read_fd) self._watchdog_process = subprocess.Popen( [ sys.executable, - os.path.abspath(__file__), - "--watch-handler-group", + watchdog_path, + str(watchdog_read_fd), str(self._process.pid), ], stdin=subprocess.DEVNULL, @@ -2739,7 +2729,7 @@ def wait_finish_ack(self, context=None) -> None: self.condition.wait(min(remaining, 0.2)) -class RoutineFlightServer(flight.FlightServerBase): +class RoutineFlightServer(_FlightServerBase): def __init__( self, location: str, @@ -3324,6 +3314,19 @@ def do_exchange(self, context, descriptor, reader, writer): for index, descriptor in enumerate(args): _validate_array_values(batch.column(index), descriptor) state.record_input(sequence) + if handler_session is None: + # Start the bounded child while the parent builds the + # handler request. The child imports the frozen + # runtime concurrently with this Arrow snapshot; + # admission and all input validation still happen + # before a handler slot is acquired. + owner_id = _handler_quota_owner(payload) + handler_session = _HandlerProcessSession( + self._handler_slots, + handler_quota=self._handler_quota, + account_id=key[0], + owner_id=owner_id, + ) execution_request = { "source": source, "handler": handler_name, @@ -3346,14 +3349,6 @@ def do_exchange(self, context, descriptor, reader, writer): "arrow_encoding": HANDLER_ARROW_RECORD_BATCH, "input": _serialize_record_batch_message(batch), } - if handler_session is None: - owner_id = _handler_quota_owner(payload) - handler_session = _HandlerProcessSession( - self._handler_slots, - handler_quota=self._handler_quota, - account_id=key[0], - owner_id=owner_id, - ) output_wire = handler_session.run( context, execution_request, handler_timeout_seconds ) @@ -3463,22 +3458,11 @@ def _safe_error(exc: Exception) -> str: def main() -> None: parser = argparse.ArgumentParser() parser.add_argument("--execute-handler", action="store_true") - parser.add_argument("--watch-handler-group", type=int) parser.add_argument("--address") args = parser.parse_args() if args.execute_handler: _execute_handler_subprocess() return - if args.watch_handler_group is not None: - watchdog_fd_text = os.environ.pop(_HANDLER_WATCHDOG_FD_ENV, None) - if watchdog_fd_text is None: - parser.error("--watch-handler-group requires a watchdog pipe") - try: - watchdog_fd = int(watchdog_fd_text) - except ValueError: - parser.error("invalid watchdog pipe") - _watch_handler_group(watchdog_fd, args.watch_handler_group) - return if not args.address: parser.error("--address is required for the Flight server") logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(levelname)s %(message)s") From c9572abcbe38693bc7f4efc74ea48cbdfc4098a9 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 14:37:36 +0800 Subject: [PATCH 075/241] perf(udf): trim bounded handler IPC frames --- pkg/udf/python/worker/test_worker.py | 33 ++++++++++ pkg/udf/python/worker/worker.py | 93 +++++++++++++++++++++------- 2 files changed, 105 insertions(+), 21 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index f32ae1a458e82..49010aa693101 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -2,6 +2,7 @@ import datetime import decimal +import io import importlib.util import json import os @@ -1244,6 +1245,20 @@ def test_handler_frame_keeps_arrow_bytes_out_of_pickle_metadata(self): self.assertIsInstance(metadata["input"], pickle.PickleBuffer) self.assertEqual(arrow_wire, bytes(metadata["input"].raw())) + compact_parts, compact_size = worker._encode_execution_request( + {"source": "must-not-repeat", "input": arrow_wire}, compact=True + ) + compact_metadata = pickle.loads( + compact_parts[2], buffers=[pickle.PickleBuffer(compact_parts[3])] + ) + self.assertEqual( + worker._HANDLER_REQUEST_BATCH, + compact_metadata[worker._HANDLER_REQUEST_KIND_KEY], + ) + self.assertNotIn("source", compact_metadata) + self.assertEqual(arrow_wire, bytes(compact_metadata["input"].raw())) + self.assertLess(compact_size, payload_size) + def test_handler_request_reader_accepts_fragmented_headers(self): parts, _ = worker._encode_execution_request( { @@ -1273,6 +1288,24 @@ def test_handler_request_encoder_rejects_non_contiguous_arrow_buffer(self): {"input": memoryview(b"arrow-payload")[::2]} ) + def test_handler_response_frame_separates_status_from_payload(self): + session = object.__new__(worker._HandlerProcessSession) + session._response_buffer = bytearray(struct.pack(">Q", 4) + b"\x01abc") + self.assertEqual( + (worker._HANDLER_RESPONSE_OK, b"abc"), session._take_response() + ) + self.assertEqual(bytearray(), session._response_buffer) + session._response_buffer = bytearray(struct.pack(">Q", 0)) + with self.assertRaisesRegex(ValueError, "empty response"): + session._take_response() + + def test_handler_response_frame_parts_keep_one_wire_frame(self): + stream = io.BytesIO() + worker._write_execution_frame_parts( + stream, (b"\x01", memoryview(b"abc")) + ) + self.assertEqual(struct.pack(">Q", 4) + b"\x01abc", stream.getvalue()) + def test_handler_process_accepts_schema_free_record_batch_messages(self): descriptor = {"type_id": worker.INT64, "offset_width": 32} schema = worker._schema_from_descriptors([descriptor], "arg") diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 6d68d887b296f..b06500b57a1cd 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -208,6 +208,9 @@ class _NoFlightServerBase: _DESCRIPTOR_TEXT_KEYS = frozenset({"json_encoding", "temporal_encoding"}) _HANDLER_RESPONSE_ERROR = 0 _HANDLER_RESPONSE_OK = 1 +_HANDLER_REQUEST_KIND_KEY = "__matrixone_handler_request_kind" +_HANDLER_REQUEST_FULL = "full" +_HANDLER_REQUEST_BATCH = "batch" _HANDLER_RESPONSE_FD_ENV = "MATRIXONE_HANDLER_RESPONSE_FD" _HANDLER_PARENT_WATCH_FD_ENV = "MATRIXONE_HANDLER_PARENT_WATCH_FD" _HANDLER_ENV_ALLOWLIST = frozenset({"PATH"}) @@ -1788,15 +1791,22 @@ def _read_exact(stream, size: int) -> bytes: return bytes(result) -def _write_execution_frame(stream, payload: bytes) -> None: - if len(payload) > MAX_EXECUTION_FRAME_BYTES: +def _write_execution_frame_parts(stream, parts: Iterable[bytes]) -> None: + parts = tuple(parts) + payload_size = sum(len(part) for part in parts) + if payload_size > MAX_EXECUTION_FRAME_BYTES: raise ValueError("RESOURCE_EXHAUSTED: execution frame is too large") - stream.write(struct.pack(">Q", len(payload))) - stream.write(payload) + stream.write(struct.pack(">Q", payload_size)) + for part in parts: + stream.write(part) stream.flush() -def _encode_execution_request(request: Dict[str, Any]): +def _write_execution_frame(stream, payload: bytes) -> None: + _write_execution_frame_parts(stream, (payload,)) + + +def _encode_execution_request(request: Dict[str, Any], *, compact: bool = False): """Build a handler frame without copying Arrow bytes into pickle. The outer length bounds the complete frame. The first eight bytes of the @@ -1813,7 +1823,11 @@ def _encode_execution_request(request: Dict[str, Any]): raise ValueError("PROTOCOL: execution request Arrow batch is not bytes-like") if not input_wire: raise ValueError("PROTOCOL: execution request Arrow batch is empty") - metadata = dict(request) + if compact: + metadata = {_HANDLER_REQUEST_KIND_KEY: _HANDLER_REQUEST_BATCH} + else: + metadata = dict(request) + metadata[_HANDLER_REQUEST_KIND_KEY] = _HANDLER_REQUEST_FULL buffers = [] try: metadata["input"] = pickle.PickleBuffer(input_wire) @@ -1920,6 +1934,7 @@ def _execute_handler_subprocess() -> None: # frozen contract; input Arrow batches remain independently validated # by the parent and by _execute_handler_batch. frozen = None + frozen_request = None handler = None statement_context = None input_schema = None @@ -1930,6 +1945,20 @@ def _execute_handler_subprocess() -> None: if request is None: # EOF before a new frame is the normal burst shutdown. break + request_kind = request.get(_HANDLER_REQUEST_KIND_KEY) + if request_kind not in ( + _HANDLER_REQUEST_FULL, + _HANDLER_REQUEST_BATCH, + ): + raise ValueError("PROTOCOL: handler request kind is invalid") + if request_kind == _HANDLER_REQUEST_BATCH: + if frozen is None or frozen_request is None: + raise ValueError( + "PROTOCOL: compact handler request arrived before the full contract" + ) + batch_input = request.get("input") + request = dict(frozen_request) + request["input"] = batch_input contract = { key: request.get(key) for key in ( @@ -1942,6 +1971,12 @@ def _execute_handler_subprocess() -> None: } if frozen is None: frozen = contract + # Do not retain the first Arrow batch while the child is + # reused. The immutable contract is enough to reconstruct + # later compact requests. + frozen_request = { + key: value for key, value in request.items() if key != "input" + } statement_context = _statement_context(request.get("context")) handler = _load_handler(request["source"], request["handler"]) if request.get("arrow_encoding") == HANDLER_ARROW_RECORD_BATCH: @@ -1949,19 +1984,25 @@ def _execute_handler_subprocess() -> None: result_schema = pa.schema([_field("result", request["return"])]) elif contract != frozen: raise ValueError("PROTOCOL: handler burst contract changed") - response = bytes([_HANDLER_RESPONSE_OK]) + _execute_handler_batch( + output = _execute_handler_batch( request, handler=handler, statement_context=statement_context, input_schema=input_schema, result_schema=result_schema, ) + response_parts = (bytes([_HANDLER_RESPONSE_OK]), output) + succeeded = True except Exception as exc: - response = bytes([_HANDLER_RESPONSE_ERROR]) + _safe_error(exc).encode("utf-8") + response_parts = ( + bytes([_HANDLER_RESPONSE_ERROR]), + _safe_error(exc).encode("utf-8"), + ) + succeeded = False # This descriptor is created by the adapter and is distinct from # process stdout/stderr descriptors available to handler code. - _write_execution_frame(response_stream, response) - if response[0] == _HANDLER_RESPONSE_ERROR: + _write_execution_frame_parts(response_stream, response_parts) + if not succeeded: break finally: response_stream.close() @@ -2335,7 +2376,7 @@ def should_rollover(self) -> bool: or time.monotonic() - self._burst_started >= DEFAULT_BURST_SECONDS ) - def _take_response(self) -> Optional[bytes]: + def _take_response(self) -> Optional[tuple[int, bytes]]: if len(self._response_buffer) < 8: return None expected = struct.unpack(">Q", self._response_buffer[:8])[0] @@ -2343,9 +2384,19 @@ def _take_response(self) -> Optional[bytes]: raise ValueError("RESOURCE_EXHAUSTED: execution response is too large") if len(self._response_buffer) < expected + 8: return None - payload = bytes(self._response_buffer[8 : expected + 8]) + if expected < 1: + raise ValueError("PROTOCOL: handler process returned an empty response") + status = self._response_buffer[8] + # A memoryview avoids an intermediate bytearray slice. Release it + # before resizing the receive buffer below; the returned Arrow bytes + # remain the only copy needed by the parent decoder. + response_view = memoryview(self._response_buffer) + try: + payload = bytes(response_view[9 : expected + 8]) + finally: + response_view.release() del self._response_buffer[: expected + 8] - return payload + return status, payload def run(self, context, request: Dict[str, Any], timeout_seconds: float) -> bytes: if self._closed or self._process is None or self._selector is None: @@ -2356,7 +2407,9 @@ def run(self, context, request: Dict[str, Any], timeout_seconds: float) -> bytes # unbounded part of the caller's budget before the deadline was even # installed. deadline = time.monotonic() + timeout_seconds - request_parts, request_size = _encode_execution_request(request) + request_parts, request_size = _encode_execution_request( + request, compact=self._burst_batches > 0 + ) if time.monotonic() >= deadline: raise TimeoutError("DEADLINE_EXCEEDED: handler execution timeout") request_part_index = 0 @@ -2411,19 +2464,17 @@ def run(self, context, request: Dict[str, Any], timeout_seconds: float) -> bytes if _execution_group_alive(self._process): raise ValueError("USER_CODE: handler process left descendant processes") raise ValueError("USER_CODE: handler process exited before the burst completed") - if not response: - raise ValueError("PROTOCOL: handler process returned an empty response") - if response[0] == _HANDLER_RESPONSE_ERROR: + status, output = response + if status == _HANDLER_RESPONSE_ERROR: try: - message = response[1:].decode("utf-8") + message = output.decode("utf-8") except UnicodeDecodeError as exc: raise ValueError("PROTOCOL: handler process returned an invalid error") from exc raise ValueError(message or "USER_CODE: handler process failed") - if response[0] != _HANDLER_RESPONSE_OK: + if status != _HANDLER_RESPONSE_OK: raise ValueError("PROTOCOL: handler process returned an unknown status") - output = response[1:] self._burst_batches += 1 - self._burst_bytes += request_size + len(response) + self._burst_bytes += request_size + len(output) + 1 return output finally: # A failed write/read must not leave a stale registration that a From 14f59de17f6745079c0687fe0233beb6dd735b8e Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 14:37:43 +0800 Subject: [PATCH 076/241] perf(udf): avoid Arrow result stream copies --- pkg/udf/python/arrow.go | 262 +++++++++++++++++++++++------------ pkg/udf/python/arrow_test.go | 181 ++++++++++++++++++++++++ 2 files changed, 357 insertions(+), 86 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 5697fbc8b22bf..84955c57178bd 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -23,6 +23,7 @@ import ( "encoding/json" "errors" "fmt" + "io" "math" "reflect" "unicode/utf8" @@ -34,6 +35,7 @@ import ( "github.com/apache/arrow-go/v18/arrow/ipc" "github.com/apache/arrow-go/v18/arrow/memory" "github.com/matrixorigin/matrixone/pkg/common/mpool" + commonutil "github.com/matrixorigin/matrixone/pkg/common/util" "github.com/matrixorigin/matrixone/pkg/container/arrowipc" "github.com/matrixorigin/matrixone/pkg/container/bytejson" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -919,11 +921,13 @@ func DecodeRecordBatch(schemaFrame, batchFrame ArrowFrame, maxBytes int64) (arro if batchInfo.HeaderType != arrowipc.MessageHeaderRecordBatch { return nil, fmt.Errorf("invalid Arrow record frame header %d", batchInfo.HeaderType) } - stream := make([]byte, 0, len(schemaFrame.Header)+len(batchFrame.Header)+len(batchFrame.Body)+32) - stream = appendIPCFrame(stream, schemaFrame.Header, schemaFrame.Body) - stream = appendIPCFrame(stream, batchFrame.Header, batchFrame.Body) - stream = append(stream, 0, 0, 0, 0, 0, 0, 0, 0) - reader, err := ipc.NewReader(bytes.NewReader(stream), ipc.WithAllocator(memory.NewGoAllocator())) + // The snapshot is already the immutable validation/publication backing. + // Feed that backing directly to Arrow's stream reader instead of assembling + // another stream-sized byte slice around it. The small IPC continuation + // prefixes and alignment padding are separate readers; the body remains + // owned by the validated snapshot until Arrow releases the record. + stream := newIPCStreamReader(schemaFrame, batchFrame) + reader, err := ipc.NewReader(stream, ipc.WithAllocator(memory.NewGoAllocator())) if err != nil { return nil, fmt.Errorf("decode Arrow output: %w", err) } @@ -938,21 +942,57 @@ func DecodeRecordBatch(schemaFrame, batchFrame ArrowFrame, maxBytes int64) (arro record.Retain() return record, nil } -func appendIPCFrame(dst, header, body []byte) []byte { - metadataLength := (len(header) + 7) &^ 7 - var prefix [8]byte - binary.LittleEndian.PutUint32(prefix[:4], math.MaxUint32) - binary.LittleEndian.PutUint32(prefix[4:], uint32(metadataLength)) - dst = append(dst, prefix[:]...) - dst = append(dst, header...) - for len(dst)%8 != 0 { - dst = append(dst, 0) - } - dst = append(dst, body...) - for len(dst)%8 != 0 { - dst = append(dst, 0) - } - return dst + +var ipcZeroPadding [8]byte + +func newIPCStreamReader(frames ...ArrowFrame) io.Reader { + parts := make([][]byte, 0, len(frames)*5+1) + for _, frame := range frames { + metadataLength := (len(frame.Header) + 7) &^ 7 + bodyLength := (len(frame.Body) + 7) &^ 7 + var prefix [8]byte + binary.LittleEndian.PutUint32(prefix[:4], math.MaxUint32) + binary.LittleEndian.PutUint32(prefix[4:], uint32(metadataLength)) + parts = append(parts, + prefix[:], + frame.Header, + ipcZeroPadding[:metadataLength-len(frame.Header)], + frame.Body, + ipcZeroPadding[:bodyLength-len(frame.Body)], + ) + } + // Arrow's stream reader uses an eight-byte zero continuation marker to + // observe the end of the stream after the one record batch. + parts = append(parts, ipcZeroPadding[:]) + return &ipcStreamReader{parts: parts} +} + +type ipcStreamReader struct { + parts [][]byte + part int + offset int +} + +func (r *ipcStreamReader) Read(dst []byte) (int, error) { + if len(dst) == 0 { + return 0, nil + } + read := 0 + for read < len(dst) && r.part < len(r.parts) { + source := r.parts[r.part] + if r.offset >= len(source) { + r.part++ + r.offset = 0 + continue + } + copied := copy(dst[read:], source[r.offset:]) + r.offset += copied + read += copied + } + if read != 0 { + return read, nil + } + return 0, io.EOF } func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vector.FunctionResultWrapper, mp *mpool.MPool) error { @@ -976,53 +1016,39 @@ func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vect } result.GetResultVector().SetTypeScale(descriptor.Scale) typ := types.T(descriptor.TypeID) + switch typ { + case types.T_bool: + return appendBoolArrowResult(input.(*array.Boolean), result) + case types.T_int8: + return appendFixedArrowValues(input.(*array.Int8).Int8Values(), input, result) + case types.T_int16: + return appendFixedArrowValues(input.(*array.Int16).Int16Values(), input, result) + case types.T_int32: + return appendFixedArrowValues(input.(*array.Int32).Int32Values(), input, result) + case types.T_int64: + return appendFixedArrowValues(input.(*array.Int64).Int64Values(), input, result) + case types.T_uint8: + return appendFixedArrowValues(input.(*array.Uint8).Uint8Values(), input, result) + case types.T_uint16: + return appendFixedArrowValues(input.(*array.Uint16).Uint16Values(), input, result) + case types.T_uint32: + return appendFixedArrowValues(input.(*array.Uint32).Uint32Values(), input, result) + case types.T_uint64: + return appendFixedArrowValues(input.(*array.Uint64).Uint64Values(), input, result) + case types.T_float32: + return appendFixedArrowValues(input.(*array.Float32).Float32Values(), input, result) + case types.T_float64: + return appendFixedArrowValues(input.(*array.Float64).Float64Values(), input, result) + case types.T_char, types.T_varchar, types.T_text: + return appendStringArrowResult(input.(*array.String), result) + case types.T_json: + return appendJSONArrowResult(input.(*array.String), result) + case types.T_binary, types.T_varbinary, types.T_blob: + return appendBinaryArrowResult(input.(*array.Binary), result) + } for i := 0; i < input.Len(); i++ { null := input.IsNull(i) switch typ { - case types.T_bool: - if err := vector.MustFunctionResult[bool](result).Append(input.(*array.Boolean).Value(i), null); err != nil { - return err - } - case types.T_int8: - if err := vector.MustFunctionResult[int8](result).Append(input.(*array.Int8).Value(i), null); err != nil { - return err - } - case types.T_int16: - if err := vector.MustFunctionResult[int16](result).Append(input.(*array.Int16).Value(i), null); err != nil { - return err - } - case types.T_int32: - if err := vector.MustFunctionResult[int32](result).Append(input.(*array.Int32).Value(i), null); err != nil { - return err - } - case types.T_int64: - if err := vector.MustFunctionResult[int64](result).Append(input.(*array.Int64).Value(i), null); err != nil { - return err - } - case types.T_uint8: - if err := vector.MustFunctionResult[uint8](result).Append(input.(*array.Uint8).Value(i), null); err != nil { - return err - } - case types.T_uint16: - if err := vector.MustFunctionResult[uint16](result).Append(input.(*array.Uint16).Value(i), null); err != nil { - return err - } - case types.T_uint32: - if err := vector.MustFunctionResult[uint32](result).Append(input.(*array.Uint32).Value(i), null); err != nil { - return err - } - case types.T_uint64: - if err := vector.MustFunctionResult[uint64](result).Append(input.(*array.Uint64).Value(i), null); err != nil { - return err - } - case types.T_float32: - if err := vector.MustFunctionResult[float32](result).Append(input.(*array.Float32).Value(i), null); err != nil { - return err - } - case types.T_float64: - if err := vector.MustFunctionResult[float64](result).Append(input.(*array.Float64).Value(i), null); err != nil { - return err - } case types.T_decimal64: var value types.Decimal64 if !null { @@ -1047,28 +1073,6 @@ func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vect if err := vector.MustFunctionResult[types.Decimal128](result).Append(value, null); err != nil { return err } - case types.T_char, types.T_varchar, types.T_text: - if err := vector.MustFunctionResult[types.Varlena](result).AppendBytes([]byte(input.(*array.String).Value(i)), null); err != nil { - return err - } - case types.T_json: - if null { - if err := vector.MustFunctionResult[types.Varlena](result).AppendBytes(nil, true); err != nil { - return err - } - continue - } - encoded, err := bytejson.ParseJsonByteFromString(input.(*array.String).Value(i)) - if err != nil { - return fmt.Errorf("TYPE_CONTRACT: invalid JSON result: %w", err) - } - if err = vector.MustFunctionResult[types.Varlena](result).AppendBytes(encoded, false); err != nil { - return err - } - case types.T_binary, types.T_varbinary, types.T_blob: - if err := vector.MustFunctionResult[types.Varlena](result).AppendBytes(input.(*array.Binary).Value(i), null); err != nil { - return err - } case types.T_uuid: var value types.Uuid if !null { @@ -1100,6 +1104,92 @@ func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vect return nil } +func appendStringArrowResult(input *array.String, result vector.FunctionResultWrapper) error { + output := vector.MustFunctionResult[types.Varlena](result) + for i := 0; i < input.Len(); i++ { + // AppendBytes copies synchronously into the MO-owned area. The unsafe + // view therefore never escapes the call and does not retain Arrow's + // backing buffer after the decoded record is released. + if err := output.AppendBytes( + commonutil.UnsafeStringToBytes(input.Value(i)), input.IsNull(i), + ); err != nil { + return err + } + } + return nil +} + +func appendJSONArrowResult(input *array.String, result vector.FunctionResultWrapper) error { + output := vector.MustFunctionResult[types.Varlena](result) + for i := 0; i < input.Len(); i++ { + if input.IsNull(i) { + if err := output.AppendBytes(nil, true); err != nil { + return err + } + continue + } + encoded, err := bytejson.ParseJsonByteFromString(input.Value(i)) + if err != nil { + return fmt.Errorf("TYPE_CONTRACT: invalid JSON result: %w", err) + } + if err = output.AppendBytes(encoded, false); err != nil { + return err + } + } + return nil +} + +func appendBinaryArrowResult(input *array.Binary, result vector.FunctionResultWrapper) error { + output := vector.MustFunctionResult[types.Varlena](result) + for i := 0; i < input.Len(); i++ { + if err := output.AppendBytes(input.Value(i), input.IsNull(i)); err != nil { + return err + } + } + return nil +} + +type nullableArrowArray interface { + NullN() int + IsNull(int) bool +} + +func appendBoolArrowResult(input *array.Boolean, result vector.FunctionResultWrapper) error { + output := vector.MustFunctionResult[bool](result) + if input.NullN() == 0 { + for i := 0; i < input.Len(); i++ { + output.AppendMustValue(input.Value(i)) + } + return nil + } + for i := 0; i < input.Len(); i++ { + if input.IsNull(i) { + output.AppendMustNull() + } else { + output.AppendMustValue(input.Value(i)) + } + } + return nil +} + +func appendFixedArrowValues[T types.FixedSizeT](values []T, input nullableArrowArray, result vector.FunctionResultWrapper) error { + output := vector.MustFunctionResult[T](result) + if input.NullN() == 0 { + for _, value := range values { + output.AppendMustValue(value) + } + return nil + } + for i, value := range values { + if input.IsNull(i) { + output.AppendMustNull() + } else { + output.AppendMustValue(value) + } + } + return nil +} + func appendFloat32ArrayResult(input *array.FixedSizeList, row int, null bool, result vector.FunctionResultWrapper, mp *mpool.MPool) error { if null { return vector.AppendArray[float32](result.GetResultVector(), nil, true, mp) diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 7e24f171465c7..d1db4d404a8e9 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -6,8 +6,10 @@ package python import ( + "bytes" "encoding/binary" "encoding/json" + "fmt" "math" "os" "testing" @@ -15,6 +17,7 @@ import ( "github.com/apache/arrow-go/v18/arrow" "github.com/apache/arrow-go/v18/arrow/array" "github.com/apache/arrow-go/v18/arrow/decimal128" + "github.com/apache/arrow-go/v18/arrow/ipc" "github.com/apache/arrow-go/v18/arrow/memory" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -68,6 +71,184 @@ func TestEncodeRecordBatchUsesFlightPayloadFrames(t *testing.T) { require.Equal(t, int64(3), decodedValues.Value(2)) } +func BenchmarkDecodeRecordBatch(b *testing.B) { + descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(b, err) + field, err := descriptor.Field("arg_0") + require.NoError(b, err) + builder := array.NewInt64Builder(memory.NewGoAllocator()) + values := make([]int64, 8192) + for i := range values { + values[i] = int64(i) + } + builder.AppendValues(values, nil) + arrayValues := builder.NewInt64Array() + defer arrayValues.Release() + record := array.NewRecordBatch( + arrow.NewSchema([]arrow.Field{field}, nil), + []arrow.Array{arrayValues}, + int64(len(values)), + ) + defer record.Release() + frames, err := EncodeRecordBatch(record, DefaultMaxBatchBytes) + require.NoError(b, err) + b.SetBytes(int64(len(frames[1].Body))) + + b.Run("copy_baseline", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + decoded, err := decodeRecordBatchCopyBaseline(frames[0], frames[1], DefaultMaxBatchBytes) + if err != nil { + b.Fatal(err) + } + decoded.Release() + } + }) + b.Run("snapshot_reader", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + decoded, err := DecodeRecordBatch(frames[0], frames[1], DefaultMaxBatchBytes) + if err != nil { + b.Fatal(err) + } + decoded.Release() + } + }) +} + +func BenchmarkAppendArrowResultFixedWidth(b *testing.B) { + builder := array.NewInt64Builder(memory.NewGoAllocator()) + values := make([]int64, 8192) + for i := range values { + values[i] = int64(i) + } + builder.AppendValues(values, nil) + input := builder.NewInt64Array() + defer input.Release() + mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + b.SetBytes(int64(len(values) * 8)) + + bench := func(b *testing.B, appendResult func(vector.FunctionResultWrapper) error) { + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer result.Free() + require.NoError(b, result.PreExtendAndReset(len(values))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + if err := result.PreExtendAndReset(len(values)); err != nil { + b.Fatal(err) + } + if err := appendResult(result); err != nil { + b.Fatal(err) + } + } + } + + b.Run("wrapper_each_row", func(b *testing.B) { + bench(b, func(result vector.FunctionResultWrapper) error { + for i := 0; i < input.Len(); i++ { + if err := vector.MustFunctionResult[int64](result).Append(input.Value(i), input.IsNull(i)); err != nil { + return err + } + } + return nil + }) + }) + b.Run("wrapper_once", func(b *testing.B) { + bench(b, func(result vector.FunctionResultWrapper) error { + return appendFixedArrowValues(input.Int64Values(), input, result) + }) + }) +} + +func BenchmarkAppendArrowResultVariableWidth(b *testing.B) { + builder := array.NewStringBuilder(memory.NewGoAllocator()) + values := make([]string, 8192) + for i := range values { + values[i] = fmt.Sprintf("value-%d", i) + } + builder.AppendValues(values, nil) + input := builder.NewStringArray() + defer input.Release() + mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + b.SetBytes(int64(len(values) * 8)) + + bench := func(b *testing.B, appendResult func(vector.FunctionResultWrapper) error) { + result := vector.NewFunctionResultWrapper(types.T_varchar.ToType(), mp) + defer result.Free() + require.NoError(b, result.PreExtendAndReset(len(values))) + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + if err := result.PreExtendAndReset(len(values)); err != nil { + b.Fatal(err) + } + if err := appendResult(result); err != nil { + b.Fatal(err) + } + } + } + + b.Run("string_to_bytes_copy", func(b *testing.B) { + bench(b, func(result vector.FunctionResultWrapper) error { + output := vector.MustFunctionResult[types.Varlena](result) + for i := 0; i < input.Len(); i++ { + if err := output.AppendBytes([]byte(input.Value(i)), input.IsNull(i)); err != nil { + return err + } + } + return nil + }) + }) + b.Run("borrowed_string_view", func(b *testing.B) { + bench(b, func(result vector.FunctionResultWrapper) error { + return appendStringArrowResult(input, result) + }) + }) +} + +func decodeRecordBatchCopyBaseline(schemaFrame, batchFrame ArrowFrame, maxBytes int64) (arrow.RecordBatch, error) { + stream := make([]byte, 0, len(schemaFrame.Header)+len(batchFrame.Header)+len(batchFrame.Body)+32) + stream = appendIPCFrameCopyBaseline(stream, schemaFrame.Header, schemaFrame.Body) + stream = appendIPCFrameCopyBaseline(stream, batchFrame.Header, batchFrame.Body) + stream = append(stream, 0, 0, 0, 0, 0, 0, 0, 0) + reader, err := ipc.NewReader(bytes.NewReader(stream), ipc.WithAllocator(memory.NewGoAllocator())) + if err != nil { + return nil, err + } + defer reader.Release() + if !reader.Next() { + return nil, reader.Err() + } + record := reader.RecordBatch() + if record == nil { + return nil, fmt.Errorf("missing record batch") + } + record.Retain() + return record, nil +} + +func appendIPCFrameCopyBaseline(dst, header, body []byte) []byte { + metadataLength := (len(header) + 7) &^ 7 + var prefix [8]byte + binary.LittleEndian.PutUint32(prefix[:4], math.MaxUint32) + binary.LittleEndian.PutUint32(prefix[4:], uint32(metadataLength)) + dst = append(dst, prefix[:]...) + dst = append(dst, header...) + for len(dst)%8 != 0 { + dst = append(dst, 0) + } + dst = append(dst, body...) + for len(dst)%8 != 0 { + dst = append(dst, 0) + } + return dst +} + func TestDecodeRecordBatchRequiresSchemaAndRecordHeaders(t *testing.T) { descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) require.NoError(t, err) From 3f99f5704ce692d98047dcab87ec92c7901cb953 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 14:53:59 +0800 Subject: [PATCH 077/241] perf(udf): batch fixed-width input materialization --- pkg/udf/python/arrow.go | 139 ++++++++++++++++++++++++++++++++ pkg/udf/python/arrow_test.go | 57 +++++++++++++ pkg/udf/python/gateway.go | 6 +- pkg/udf/python/worker/worker.py | 37 ++++++--- 4 files changed, 226 insertions(+), 13 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 84955c57178bd..5fab28aed21b9 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -48,6 +48,10 @@ const ( DefaultMaxBatchBytes = 16 << 20 DefaultMaxBatchRows = 65536 DefaultMaxControlBytes = 1 << 20 + // Bulk append is only used for a large fixed-width primitive column. The + // small-batch path avoids allocating a temporary validity slice and keeps + // the ordinary per-value path for constants and special SQL encodings. + bulkInputMinRows = 64 ) type TypeDescriptor struct { @@ -591,6 +595,15 @@ func (e *inputBatchEncoder) build(start, length int) (arrow.RecordBatch, *arrow. builder := array.NewRecordBuilder(memory.NewGoAllocator(), e.schema) defer builder.Release() for column, typ := range e.args { + bulk, err := appendBulkFixedInputValue( + builder.Field(column), e.inputs[column], typ, start, length, + ) + if err != nil { + return nil, nil, fmt.Errorf("input column %d: %w", column, err) + } + if bulk { + continue + } for row := 0; row < length; row++ { if err := appendInputValue(builder.Field(column), e.inputs[column], typ, start, row); err != nil { return nil, nil, fmt.Errorf("input column %d row %d: %w", column, row, err) @@ -600,6 +613,132 @@ func (e *inputBatchEncoder) build(start, length int) (arrow.RecordBatch, *arrow. return builder.NewRecordBatch(), e.schema, nil } +// appendBulkFixedInputValue uses Arrow's typed AppendValues APIs for the +// primitive SQL types whose MatrixOne storage already has the same physical +// representation. It copies only the values that Arrow must own; the source +// vector remains the ownership boundary, and NULL positions are supplied as a +// separate validity slice. The return value says whether the type was +// handled by this path. +func appendBulkFixedInputValue( + builder array.Builder, v *vector.Vector, typ types.Type, start, length int, +) (bool, error) { + if length < bulkInputMinRows { + return false, nil + } + validity := func() []bool { + if v.IsConstNull() { + return make([]bool, length) + } + if v.GetNulls() == nil || v.GetNulls().IsEmpty() { + return nil + } + valid := make([]bool, length) + for row := range valid { + valid[row] = !v.IsNull(uint64(sourceRow(v, start, row))) + } + return valid + } + if builder == nil || v == nil { + return false, fmt.Errorf("input column is missing") + } + + switch typ.Oid { + case types.T_bool: + values, err := bulkFixedInputWindow[bool](v, start, length) + if err != nil { + return false, err + } + builder.(*array.BooleanBuilder).AppendValues(values, validity()) + case types.T_int8: + values, err := bulkFixedInputWindow[int8](v, start, length) + if err != nil { + return false, err + } + builder.(*array.Int8Builder).AppendValues(values, validity()) + case types.T_int16: + values, err := bulkFixedInputWindow[int16](v, start, length) + if err != nil { + return false, err + } + builder.(*array.Int16Builder).AppendValues(values, validity()) + case types.T_int32: + values, err := bulkFixedInputWindow[int32](v, start, length) + if err != nil { + return false, err + } + builder.(*array.Int32Builder).AppendValues(values, validity()) + case types.T_int64: + values, err := bulkFixedInputWindow[int64](v, start, length) + if err != nil { + return false, err + } + builder.(*array.Int64Builder).AppendValues(values, validity()) + case types.T_uint8: + values, err := bulkFixedInputWindow[uint8](v, start, length) + if err != nil { + return false, err + } + builder.(*array.Uint8Builder).AppendValues(values, validity()) + case types.T_uint16: + values, err := bulkFixedInputWindow[uint16](v, start, length) + if err != nil { + return false, err + } + builder.(*array.Uint16Builder).AppendValues(values, validity()) + case types.T_uint32: + values, err := bulkFixedInputWindow[uint32](v, start, length) + if err != nil { + return false, err + } + builder.(*array.Uint32Builder).AppendValues(values, validity()) + case types.T_uint64: + values, err := bulkFixedInputWindow[uint64](v, start, length) + if err != nil { + return false, err + } + builder.(*array.Uint64Builder).AppendValues(values, validity()) + case types.T_float32: + values, err := bulkFixedInputWindow[float32](v, start, length) + if err != nil { + return false, err + } + builder.(*array.Float32Builder).AppendValues(values, validity()) + case types.T_float64: + values, err := bulkFixedInputWindow[float64](v, start, length) + if err != nil { + return false, err + } + builder.(*array.Float64Builder).AppendValues(values, validity()) + default: + return false, nil + } + return true, nil +} + +func bulkFixedInputWindow[T any](v *vector.Vector, start, length int) ([]T, error) { + if v.IsConstNull() { + // A constant NULL intentionally has no physical value slot. Arrow + // still needs one placeholder per logical row so its validity bitmap + // preserves the batch shape. + return make([]T, length), nil + } + values := vector.MustFixedColNoTypeCheck[T](v) + if v.IsConst() { + if len(values) == 0 { + return nil, fmt.Errorf("constant input column has no value") + } + expanded := make([]T, length) + for row := range expanded { + expanded[row] = values[0] + } + return expanded, nil + } + if start < 0 || length <= 0 || start > len(values) || length > len(values)-start { + return nil, fmt.Errorf("input column is shorter than batch range") + } + return values[start : start+length], nil +} + // canBuildFullBatch cheaply decides whether a variable-width full candidate // is worth materializing. It uses the source values already owned by the // SQL vector and a deliberately inflated bound. If the bound is not clearly diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index d1db4d404a8e9..8ccdf33615243 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -368,6 +368,63 @@ func TestInputBatchEncoderReusesSchemaAndPreservesRange(t *testing.T) { require.Equal(t, int64(30), secondValues.Value(0)) } +func TestInputBatchEncoderBulkPrimitivePreservesRangeNullsAndConstants(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + + input := vector.NewVec(types.T_int64.ToType()) + defer input.Free(mp) + for row := 0; row < 128; row++ { + require.NoError(t, vector.AppendFixed(input, int64(row+100), row%19 == 0, mp)) + } + encoder, err := newInputBatchEncoder( + []*vector.Vector{input}, []types.Type{types.T_int64.ToType()}, + ) + require.NoError(t, err) + record, _, err := encoder.build(7, 100) + require.NoError(t, err) + defer record.Release() + values := record.Column(0).(*array.Int64) + for row := 0; row < 100; row++ { + sourceRow := row + 7 + require.Equal(t, sourceRow%19 == 0, values.IsNull(row), "row %d", row) + if !values.IsNull(row) { + require.Equal(t, int64(sourceRow+100), values.Value(row), "row %d", row) + } + } + + constant, err := vector.NewConstFixed(types.T_int64.ToType(), int64(42), 128, mp) + require.NoError(t, err) + defer constant.Free(mp) + constantEncoder, err := newInputBatchEncoder( + []*vector.Vector{constant}, []types.Type{types.T_int64.ToType()}, + ) + require.NoError(t, err) + constantRecord, _, err := constantEncoder.build(32, 96) + require.NoError(t, err) + defer constantRecord.Release() + constantValues := constantRecord.Column(0).(*array.Int64) + require.Equal(t, 96, int(constantRecord.NumRows())) + for row := 0; row < 96; row++ { + require.False(t, constantValues.IsNull(row)) + require.Equal(t, int64(42), constantValues.Value(row)) + } + + nullConstant := vector.NewConstNull(types.T_int64.ToType(), 128, mp) + defer nullConstant.Free(mp) + nullConstantEncoder, err := newInputBatchEncoder( + []*vector.Vector{nullConstant}, []types.Type{types.T_int64.ToType()}, + ) + require.NoError(t, err) + nullConstantRecord, _, err := nullConstantEncoder.build(0, 96) + require.NoError(t, err) + defer nullConstantRecord.Release() + nullConstantValues := nullConstantRecord.Column(0).(*array.Int64) + for row := 0; row < 96; row++ { + require.True(t, nullConstantValues.IsNull(row)) + } +} + func TestInputBatchWireEncoderReusesSchemaAcrossBatches(t *testing.T) { descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) require.NoError(t, err) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 243f036a407d7..505be4097a32c 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -1341,7 +1341,11 @@ func (g *Gateway) receiveResultBatch( if err != nil { return 0, err } - if err := snapshot.Validate(len(data.DataBody), snapshot.Digest()); err != nil { + // FreezeOutput already stores the digest of its private copy. An + // empty expectedDigest still makes Validate rehash that same + // backing and detect any trusted-boundary mutation, without + // allocating the hexadecimal digest string twice on every batch. + if err := snapshot.Validate(len(data.DataBody), ""); err != nil { return 0, err } decoded, err := DecodeRecordBatch(**schemaFrame, ArrowFrame{Header: append([]byte(nil), data.DataHeader...), Body: snapshot.TrustedBytes()}, g.cfg.MaxBatchBytes) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index b06500b57a1cd..418c212a2f5e4 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -13,8 +13,13 @@ from __future__ import annotations -import argparse -import ast +import sys + +# Handler children execute only the length-prefixed Arrow/pipe contract. Keep +# service-side modules out of that import path; the child is started for each +# invocation burst and cannot reuse the worker's imported Python heap. +_HANDLER_ENTRY = "--execute-handler" in sys.argv + import contextlib import datetime as _datetime import decimal as _decimal @@ -25,13 +30,8 @@ import math import os import pickle -import queue -import secrets -import selectors import signal import struct -import subprocess -import sys import threading import time import uuid as _uuid @@ -40,13 +40,16 @@ from typing import Any, Dict, Iterable, Optional from zoneinfo import TZPATH, ZoneInfo, ZoneInfoNotFoundError +if not _HANDLER_ENTRY: + import queue + import selectors + import subprocess + import pyarrow as pa # Handler children only need Arrow. Avoid importing Flight on that entry path; # the annotations in this module are postponed, and the Flight server class is # never instantiated by the handler child. -_HANDLER_ENTRY = "--execute-handler" in sys.argv - class _NoFlightServerBase: pass @@ -896,6 +899,8 @@ def _decode_definition_validation(data: bytes) -> Dict[str, Any]: def _validate_definition_syntax(value: Dict[str, Any]) -> None: """Validate source and the static handler binding without executing it.""" + import ast + try: compile(value["source"], "", "exec") except SyntaxError as exc: @@ -2329,6 +2334,10 @@ def __init__( self._watchdog_process = subprocess.Popen( [ sys.executable, + # The watchdog is a standard-library-only helper; + # skipping site-package discovery trims its startup + # without changing the handler's Python environment. + "-S", watchdog_path, str(watchdog_read_fd), str(self._process.pid), @@ -3507,13 +3516,17 @@ def _safe_error(exc: Exception) -> str: def main() -> None: + if _HANDLER_ENTRY: + _execute_handler_subprocess() + return + + import argparse + import secrets + parser = argparse.ArgumentParser() parser.add_argument("--execute-handler", action="store_true") parser.add_argument("--address") args = parser.parse_args() - if args.execute_handler: - _execute_handler_subprocess() - return if not args.address: parser.error("--address is required for the Flight server") logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(levelname)s %(message)s") From 22c19f64be210257f72ee255cf7810d286671fd0 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 15:04:53 +0800 Subject: [PATCH 078/241] perf(udf): reuse variable-width input wrappers --- pkg/udf/python/arrow.go | 99 ++++++++++++++++++------ pkg/udf/python/arrow_test.go | 29 +++++++ pkg/udf/python/gateway_benchmark_test.go | 10 +-- 3 files changed, 110 insertions(+), 28 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 5fab28aed21b9..f8626192be8b2 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -509,12 +509,13 @@ func BuildInputRecordRange(inputs []*vector.Vector, args []types.Type, start, le // physical batch and every size probe. The record builder and encoded bytes // remain per batch, so the encoder does not retain input or output buffers. type inputBatchEncoder struct { - inputs []*vector.Vector - args []types.Type - descriptors []TypeDescriptor - schema *arrow.Schema - fixedWidth bool - wire *inputBatchWireEncoder + inputs []*vector.Vector + args []types.Type + descriptors []TypeDescriptor + stringParameters []vector.FunctionParameterWrapper[types.Varlena] + schema *arrow.Schema + fixedWidth bool + wire *inputBatchWireEncoder } func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBatchEncoder, error) { @@ -523,6 +524,7 @@ func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBat } fields := make([]arrow.Field, len(args)) descriptors := make([]TypeDescriptor, len(args)) + stringParameters := make([]vector.FunctionParameterWrapper[types.Varlena], len(args)) fixedWidth := true for i, typ := range args { descriptor, err := NewTypeDescriptor(typ) @@ -552,14 +554,18 @@ func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBat typ.DescString(), ) } + if isStringInputType(typ.Oid) { + stringParameters[i] = vector.GenerateFunctionStrParameter(inputs[i]) + } } schema := arrow.NewSchema(fields, nil) return &inputBatchEncoder{ - inputs: inputs, - args: args, - descriptors: descriptors, - schema: schema, - fixedWidth: fixedWidth, + inputs: inputs, + args: args, + descriptors: descriptors, + stringParameters: stringParameters, + schema: schema, + fixedWidth: fixedWidth, }, nil } @@ -605,7 +611,10 @@ func (e *inputBatchEncoder) build(start, length int) (arrow.RecordBatch, *arrow. continue } for row := 0; row < length; row++ { - if err := appendInputValue(builder.Field(column), e.inputs[column], typ, start, row); err != nil { + if err := appendInputValue( + builder.Field(column), e.inputs[column], typ, start, row, + e.stringParameters[column], + ); err != nil { return nil, nil, fmt.Errorf("input column %d row %d: %w", column, row, err) } } @@ -783,7 +792,7 @@ func (e *inputBatchEncoder) canBuildFullBatch(start, length, maxBytes int64) boo estimate = add(estimate, perColumnOverhead) estimate = add(estimate, multiply(add(length, 1), offsetWidth)) estimate = add(estimate, add(length, 7)/8) - parameter := vector.GenerateFunctionStrParameter(e.inputs[column]) + parameter := e.stringParameters[column] for row := int64(0); row < length; row++ { index := sourceRow(e.inputs[column], int(start), int(row)) if e.inputs[column].IsNull(uint64(index)) { @@ -813,9 +822,29 @@ func sourceRow(v *vector.Vector, start, row int) int { } return start + row } -func appendInputValue(builder array.Builder, v *vector.Vector, typ types.Type, start, row int) error { + +func isStringInputType(oid types.T) bool { + switch oid { + case types.T_char, types.T_varchar, types.T_text, types.T_json, + types.T_binary, types.T_varbinary, types.T_blob: + return true + default: + return false + } +} + +func appendInputValue( + builder array.Builder, + v *vector.Vector, + typ types.Type, + start, row int, + stringParameter vector.FunctionParameterWrapper[types.Varlena], +) error { index := sourceRow(v, start, row) null := v.IsNull(uint64(index)) + if !null && isStringInputType(typ.Oid) && stringParameter == nil { + return fmt.Errorf("missing cached string input parameter") + } if typ.Oid == types.T_date || typ.Oid == types.T_datetime || typ.Oid == types.T_timestamp { return appendTemporalInput(builder.(*array.StructBuilder), v, typ, index, null) } @@ -926,8 +955,7 @@ func appendInputValue(builder array.Builder, v *vector.Vector, typ types.Type, s if null { b.AppendNull() } else { - p := vector.GenerateFunctionStrParameter(v) - value, _ := p.GetStrValue(uint64(index)) + value, _ := stringParameter.GetStrValue(uint64(index)) if typ.Oid == types.T_json { canonical, err := canonicalJSONInput(value) if err != nil { @@ -942,8 +970,7 @@ func appendInputValue(builder array.Builder, v *vector.Vector, typ types.Type, s if null { b.AppendNull() } else { - p := vector.GenerateFunctionStrParameter(v) - value, _ := p.GetStrValue(uint64(index)) + value, _ := stringParameter.GetStrValue(uint64(index)) b.Append(value) } case types.T_uuid: @@ -1085,6 +1112,32 @@ func DecodeRecordBatch(schemaFrame, batchFrame ArrowFrame, maxBytes int64) (arro var ipcZeroPadding [8]byte func newIPCStreamReader(frames ...ArrowFrame) io.Reader { + reader := &ipcStreamReader{} + if len(frames) <= len(reader.inlineParts)/5 { + reader.parts = reader.inlineParts[:0] + for index, frame := range frames { + metadataLength := (len(frame.Header) + 7) &^ 7 + bodyLength := (len(frame.Body) + 7) &^ 7 + binary.LittleEndian.PutUint32(reader.prefixes[index][:4], math.MaxUint32) + binary.LittleEndian.PutUint32(reader.prefixes[index][4:], uint32(metadataLength)) + reader.parts = append(reader.parts, + reader.prefixes[index][:], + frame.Header, + ipcZeroPadding[:metadataLength-len(frame.Header)], + frame.Body, + ipcZeroPadding[:bodyLength-len(frame.Body)], + ) + } + // Arrow's stream reader uses an eight-byte zero continuation marker to + // observe the end of the stream after the one record batch. + reader.parts = append(reader.parts, ipcZeroPadding[:]) + return reader + } + + // Keep the helper correct for future callers that need more than the + // schema-plus-record pair. The production result path stays on the inline + // storage above, so this fallback does not add a per-batch allocation to + // the current protocol. parts := make([][]byte, 0, len(frames)*5+1) for _, frame := range frames { metadataLength := (len(frame.Header) + 7) &^ 7 @@ -1100,16 +1153,16 @@ func newIPCStreamReader(frames ...ArrowFrame) io.Reader { ipcZeroPadding[:bodyLength-len(frame.Body)], ) } - // Arrow's stream reader uses an eight-byte zero continuation marker to - // observe the end of the stream after the one record batch. parts = append(parts, ipcZeroPadding[:]) return &ipcStreamReader{parts: parts} } type ipcStreamReader struct { - parts [][]byte - part int - offset int + parts [][]byte + inlineParts [11][]byte + prefixes [2][8]byte + part int + offset int } func (r *ipcStreamReader) Read(dst []byte) (int, error) { diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 8ccdf33615243..abeb111d1b941 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -368,6 +368,35 @@ func TestInputBatchEncoderReusesSchemaAndPreservesRange(t *testing.T) { require.Equal(t, int64(30), secondValues.Value(0)) } +func TestInputBatchEncoderCachesVariableWidthParameterAcrossRanges(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + + input := vector.NewVec(types.T_varchar.ToType()) + defer input.Free(mp) + for index, value := range []string{"zero", "one", "two", "three"} { + require.NoError(t, vector.AppendBytes(input, []byte(value), index == 2, mp)) + } + encoder, err := newInputBatchEncoder( + []*vector.Vector{input}, []types.Type{types.T_varchar.ToType()}, + ) + require.NoError(t, err) + + first, _, err := encoder.build(0, 2) + require.NoError(t, err) + defer first.Release() + second, _, err := encoder.build(2, 2) + require.NoError(t, err) + defer second.Release() + + firstValues := first.Column(0).(*array.String) + require.Equal(t, "zero", firstValues.Value(0)) + require.Equal(t, "one", firstValues.Value(1)) + secondValues := second.Column(0).(*array.String) + require.True(t, secondValues.IsNull(0)) + require.Equal(t, "three", secondValues.Value(1)) +} + func TestInputBatchEncoderBulkPrimitivePreservesRangeNullsAndConstants(t *testing.T) { mp := mpool.MustNewZeroNoFixed() defer mpool.DeleteMPool(mp) diff --git a/pkg/udf/python/gateway_benchmark_test.go b/pkg/udf/python/gateway_benchmark_test.go index bd95a5bc1a6f3..3ce304fe2ef19 100644 --- a/pkg/udf/python/gateway_benchmark_test.go +++ b/pkg/udf/python/gateway_benchmark_test.go @@ -135,11 +135,11 @@ func benchmarkEncodeInputBatch(b *testing.B, typ types.Type) { } } -// encodeInputBatchRebuildBaseline is a benchmark-only reference for the -// pre-optimization path. It intentionally rebuilds the Arrow record for every -// size probe while sharing the reusable Flight writer with production. This -// measures input record construction and probe avoidance without counting -// repeated schema serialization as a second optimization. +// encodeInputBatchRebuildBaseline is a benchmark-only reference for repeated +// Arrow record construction. It intentionally rebuilds the record and its +// input encoder for every size probe while sharing the reusable Flight writer +// with production. This measures record construction and probe avoidance +// without counting repeated schema serialization as a second optimization. func encodeInputBatchRebuildBaseline( encoder *inputBatchEncoder, start, remaining, maxBytes, maxRows int64, From 794fb51cec03a150f914a8514b4b3ceec41c18cb Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 15:07:08 +0800 Subject: [PATCH 079/241] fix(udf): guard empty variable-width inputs --- pkg/udf/python/arrow.go | 2 +- pkg/udf/python/arrow_test.go | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index f8626192be8b2..db22c53348682 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -554,7 +554,7 @@ func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBat typ.DescString(), ) } - if isStringInputType(typ.Oid) { + if inputs[i].Length() > 0 && isStringInputType(typ.Oid) { stringParameters[i] = vector.GenerateFunctionStrParameter(inputs[i]) } } diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index abeb111d1b941..278fdb09566aa 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -314,6 +314,8 @@ func TestZeroArgumentRecordPreservesRows(t *testing.T) { func TestBuildInputRecordRejectsEmptyConstantVector(t *testing.T) { mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + input := vector.NewConstNull(types.T_int64.ToType(), 0, mp) defer input.Free(mp) @@ -324,6 +326,23 @@ func TestBuildInputRecordRejectsEmptyConstantVector(t *testing.T) { 1, ) require.ErrorContains(t, err, "shorter than batch range") + + textInput, err := vector.NewConstBytes(types.T_varchar.ToType(), nil, 0, mp) + require.NoError(t, err) + defer textInput.Free(mp) + var record arrow.RecordBatch + require.NotPanics(t, func() { + record, _, err = BuildInputRecordRange( + []*vector.Vector{textInput}, + []types.Type{types.T_varchar.ToType()}, + 0, + 1, + ) + }) + if record != nil { + record.Release() + } + require.ErrorContains(t, err, "shorter than batch range") } func TestInputBatchEncoderRejectsMismatchedVectorType(t *testing.T) { From 6c8170367d5b4f8bc374b385a3c602f2a7a93e09 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 15:11:54 +0800 Subject: [PATCH 080/241] perf(udf): reduce handler request copies --- pkg/udf/python/worker/test_worker.py | 12 ++++++++ pkg/udf/python/worker/worker.py | 43 ++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 49010aa693101..b62f332687317 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1282,6 +1282,18 @@ def read(self, size=-1): self.assertEqual(worker.HANDLER_ARROW_RECORD_BATCH, request["arrow_encoding"]) self.assertEqual(b"arrow-payload", bytes(request["input"].raw())) + def test_handler_request_reader_keeps_readinto_payload_as_pickle_buffer(self): + parts, _ = worker._encode_execution_request( + { + "arrow_encoding": worker.HANDLER_ARROW_RECORD_BATCH, + "input": b"arrow-payload", + } + ) + request = worker._read_execution_request(io.BytesIO(b"".join(parts))) + self.assertIsInstance(request["input"], pickle.PickleBuffer) + self.assertEqual(b"arrow-payload", bytes(request["input"].raw())) + self.assertTrue(request["input"].raw().readonly) + def test_handler_request_encoder_rejects_non_contiguous_arrow_buffer(self): with self.assertRaisesRegex(ValueError, "cannot encode execution request"): worker._encode_execution_request( diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 418c212a2f5e4..16e702f0c41a5 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1786,14 +1786,34 @@ def _execute_handler_batch( return _serialize_record_batch(result_batch) -def _read_exact(stream, size: int) -> bytes: - result = bytearray() - while len(result) < size: - chunk = stream.read(size - len(result)) +def _read_exact(stream, size: int) -> bytearray: + if size < 0: + raise ValueError("execution frame read size is negative") + result = bytearray(size) + readinto = getattr(stream, "readinto", None) + if callable(readinto): + view = memoryview(result) + offset = 0 + try: + while offset < size: + count = readinto(view[offset:]) + if not isinstance(count, int) or count <= 0: + raise EOFError("execution frame ended unexpectedly") + offset += count + finally: + view.release() + return result + + # Keep compatibility with the small stream doubles used by the contract + # tests and with file-like readers that expose only read(). + offset = 0 + while offset < size: + chunk = stream.read(size - offset) if not chunk: raise EOFError("execution frame ended unexpectedly") - result.extend(chunk) - return bytes(result) + result[offset : offset + len(chunk)] = chunk + offset += len(chunk) + return result def _write_execution_frame_parts(stream, parts: Iterable[bytes]) -> None: @@ -1867,7 +1887,9 @@ def _read_execution_request(stream) -> Optional[Dict[str, Any]]: return None if len(first) != 1: raise EOFError("execution request header ended unexpectedly") - header = bytes(first) + _read_exact(stream, 7) + header = bytearray(8) + header[0] = first[0] + header[1:] = _read_exact(stream, 7) payload_size = struct.unpack(">Q", header)[0] if payload_size > MAX_EXECUTION_FRAME_BYTES or payload_size < 8: raise ValueError("RESOURCE_EXHAUSTED: execution request is too large") @@ -1881,7 +1903,12 @@ def _read_execution_request(stream) -> Optional[Dict[str, Any]]: arrow_wire = _read_exact(stream, arrow_size) try: request = pickle.loads( - metadata_wire, buffers=[pickle.PickleBuffer(arrow_wire)] + metadata_wire, + # A readonly memoryview preserves the protocol-5 PickleBuffer + # type when the exact-read backing is a bytearray, while keeping + # the Arrow payload zero-copy and preventing handler code from + # mutating the receive buffer through the request object. + buffers=[pickle.PickleBuffer(memoryview(arrow_wire).toreadonly())], ) except (EOFError, pickle.PickleError, TypeError, ValueError) as exc: raise ValueError("PROTOCOL: execution request metadata is invalid") from exc From f2f4bf4fdd6d7b9d768d63508b71893f5e47119e Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 15:14:40 +0800 Subject: [PATCH 081/241] refactor(udf): clarify varlena cache naming --- pkg/udf/python/arrow.go | 59 ++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index db22c53348682..622b096c1bec0 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -509,13 +509,13 @@ func BuildInputRecordRange(inputs []*vector.Vector, args []types.Type, start, le // physical batch and every size probe. The record builder and encoded bytes // remain per batch, so the encoder does not retain input or output buffers. type inputBatchEncoder struct { - inputs []*vector.Vector - args []types.Type - descriptors []TypeDescriptor - stringParameters []vector.FunctionParameterWrapper[types.Varlena] - schema *arrow.Schema - fixedWidth bool - wire *inputBatchWireEncoder + inputs []*vector.Vector + args []types.Type + descriptors []TypeDescriptor + varlenaParameters []vector.FunctionParameterWrapper[types.Varlena] + schema *arrow.Schema + fixedWidth bool + wire *inputBatchWireEncoder } func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBatchEncoder, error) { @@ -524,7 +524,7 @@ func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBat } fields := make([]arrow.Field, len(args)) descriptors := make([]TypeDescriptor, len(args)) - stringParameters := make([]vector.FunctionParameterWrapper[types.Varlena], len(args)) + varlenaParameters := make([]vector.FunctionParameterWrapper[types.Varlena], len(args)) fixedWidth := true for i, typ := range args { descriptor, err := NewTypeDescriptor(typ) @@ -554,18 +554,18 @@ func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBat typ.DescString(), ) } - if inputs[i].Length() > 0 && isStringInputType(typ.Oid) { - stringParameters[i] = vector.GenerateFunctionStrParameter(inputs[i]) + if inputs[i].Length() > 0 && isVarlenaInputType(typ.Oid) { + varlenaParameters[i] = vector.GenerateFunctionStrParameter(inputs[i]) } } schema := arrow.NewSchema(fields, nil) return &inputBatchEncoder{ - inputs: inputs, - args: args, - descriptors: descriptors, - stringParameters: stringParameters, - schema: schema, - fixedWidth: fixedWidth, + inputs: inputs, + args: args, + descriptors: descriptors, + varlenaParameters: varlenaParameters, + schema: schema, + fixedWidth: fixedWidth, }, nil } @@ -613,7 +613,7 @@ func (e *inputBatchEncoder) build(start, length int) (arrow.RecordBatch, *arrow. for row := 0; row < length; row++ { if err := appendInputValue( builder.Field(column), e.inputs[column], typ, start, row, - e.stringParameters[column], + e.varlenaParameters[column], ); err != nil { return nil, nil, fmt.Errorf("input column %d row %d: %w", column, row, err) } @@ -792,7 +792,7 @@ func (e *inputBatchEncoder) canBuildFullBatch(start, length, maxBytes int64) boo estimate = add(estimate, perColumnOverhead) estimate = add(estimate, multiply(add(length, 1), offsetWidth)) estimate = add(estimate, add(length, 7)/8) - parameter := e.stringParameters[column] + parameter := e.varlenaParameters[column] for row := int64(0); row < length; row++ { index := sourceRow(e.inputs[column], int(start), int(row)) if e.inputs[column].IsNull(uint64(index)) { @@ -823,7 +823,7 @@ func sourceRow(v *vector.Vector, start, row int) int { return start + row } -func isStringInputType(oid types.T) bool { +func isVarlenaInputType(oid types.T) bool { switch oid { case types.T_char, types.T_varchar, types.T_text, types.T_json, types.T_binary, types.T_varbinary, types.T_blob: @@ -838,12 +838,12 @@ func appendInputValue( v *vector.Vector, typ types.Type, start, row int, - stringParameter vector.FunctionParameterWrapper[types.Varlena], + varlenaParameter vector.FunctionParameterWrapper[types.Varlena], ) error { index := sourceRow(v, start, row) null := v.IsNull(uint64(index)) - if !null && isStringInputType(typ.Oid) && stringParameter == nil { - return fmt.Errorf("missing cached string input parameter") + if !null && isVarlenaInputType(typ.Oid) && varlenaParameter == nil { + return fmt.Errorf("missing cached varlena input parameter") } if typ.Oid == types.T_date || typ.Oid == types.T_datetime || typ.Oid == types.T_timestamp { return appendTemporalInput(builder.(*array.StructBuilder), v, typ, index, null) @@ -955,7 +955,7 @@ func appendInputValue( if null { b.AppendNull() } else { - value, _ := stringParameter.GetStrValue(uint64(index)) + value, _ := varlenaParameter.GetStrValue(uint64(index)) if typ.Oid == types.T_json { canonical, err := canonicalJSONInput(value) if err != nil { @@ -970,7 +970,7 @@ func appendInputValue( if null { b.AppendNull() } else { - value, _ := stringParameter.GetStrValue(uint64(index)) + value, _ := varlenaParameter.GetStrValue(uint64(index)) b.Append(value) } case types.T_uuid: @@ -1109,11 +1109,16 @@ func DecodeRecordBatch(schemaFrame, batchFrame ArrowFrame, maxBytes int64) (arro return record, nil } +const ( + inlineIPCFrameCount = 2 + inlineIPCPartCount = inlineIPCFrameCount*5 + 1 +) + var ipcZeroPadding [8]byte func newIPCStreamReader(frames ...ArrowFrame) io.Reader { reader := &ipcStreamReader{} - if len(frames) <= len(reader.inlineParts)/5 { + if len(frames) <= inlineIPCFrameCount { reader.parts = reader.inlineParts[:0] for index, frame := range frames { metadataLength := (len(frame.Header) + 7) &^ 7 @@ -1159,8 +1164,8 @@ func newIPCStreamReader(frames ...ArrowFrame) io.Reader { type ipcStreamReader struct { parts [][]byte - inlineParts [11][]byte - prefixes [2][8]byte + inlineParts [inlineIPCPartCount][]byte + prefixes [inlineIPCFrameCount][8]byte part int offset int } From 5d0a92c6be7a784164a0d67a1583fa49609c74b1 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 15:23:10 +0800 Subject: [PATCH 082/241] fix(udf): handle vector inputs in batch sizing --- pkg/udf/python/arrow.go | 29 +++++++++++++++++++++++++ pkg/udf/python/arrow_test.go | 42 ++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 622b096c1bec0..3bf9e60d65f75 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -780,6 +780,24 @@ func (e *inputBatchEncoder) canBuildFullBatch(start, length, maxBytes int64) boo if !typ.IsVarlen() { return false } + if elementWidth, ok := arrayElementByteWidth(typ.Oid); ok { + // Vector arguments use a fixed-size-list physical type. They are + // varlen in MatrixOne's storage, but do not have a Varlena wrapper + // or Arrow string/binary offsets to inspect. Account for every + // child value and the parent validity bitmap instead of treating + // the vector as a byte string. + valueBytes := multiply(int64(typ.Width), elementWidth) + estimate = add(estimate, multiply(valueBytes, length)) + estimate = add(estimate, add(length, 7)/8) + estimate = add(estimate, multiply(length, perRowOverhead)) + continue + } + if !isVarlenaInputType(typ.Oid) { + // An unsupported variable-width physical type must use the + // ordinary bounded probe path. In particular, never call a nil + // Varlena wrapper while estimating a batch. + return false + } descriptor := e.descriptors[column] offsetWidth := int64(descriptor.OffsetWidth) if offsetWidth == 0 { @@ -816,6 +834,17 @@ func (e *inputBatchEncoder) canBuildFullBatch(start, length, maxBytes int64) boo return estimate*safetyNumerator <= maxBytes*safetyDenominator } +func arrayElementByteWidth(oid types.T) (int64, bool) { + switch oid { + case types.T_array_float32: + return 4, true + case types.T_array_float64: + return 8, true + default: + return 0, false + } +} + func sourceRow(v *vector.Vector, start, row int) int { if v.IsConst() { return 0 diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 278fdb09566aa..a3d12adf65cb4 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -473,6 +473,48 @@ func TestInputBatchEncoderBulkPrimitivePreservesRangeNullsAndConstants(t *testin } } +func TestInputBatchEncoderVectorSizeProbeDoesNotUseVarlenaWrapper(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + + for _, tc := range []struct { + name string + typ types.Type + }{ + {name: "vecf32", typ: types.New(types.T_array_float32, 3, 0)}, + {name: "vecf64", typ: types.New(types.T_array_float64, 3, 0)}, + } { + t.Run(tc.name, func(t *testing.T) { + input := vector.NewVec(tc.typ) + defer input.Free(mp) + for row := 0; row < 64; row++ { + var err error + switch tc.typ.Oid { + case types.T_array_float32: + err = vector.AppendArray(input, []float32{float32(row), 1, 2}, row%11 == 0, mp) + case types.T_array_float64: + err = vector.AppendArray(input, []float64{float64(row), 1, 2}, row%11 == 0, mp) + } + require.NoError(t, err) + } + + encoder, err := newInputBatchEncoder([]*vector.Vector{input}, []types.Type{tc.typ}) + require.NoError(t, err) + defer func() { require.NoError(t, encoder.close()) }() + + var batch encodedRecordBatch + require.NotPanics(t, func() { + batch, err = encodeInputBatchWithEncoder( + encoder, 0, 64, DefaultMaxBatchBytes, 64, + ) + }) + require.NoError(t, err) + require.Equal(t, int64(64), batch.Rows) + require.Len(t, batch.Frames, 2) + }) + } +} + func TestInputBatchWireEncoderReusesSchemaAcrossBatches(t *testing.T) { descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) require.NoError(t, err) From 176fed46c7e97100951f30bf3c11ce6d92d601a2 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 15:23:54 +0800 Subject: [PATCH 083/241] perf(udf): reuse result headers during decode --- pkg/udf/python/gateway.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 505be4097a32c..2e35736cf8f6e 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -1348,7 +1348,11 @@ func (g *Gateway) receiveResultBatch( if err := snapshot.Validate(len(data.DataBody), ""); err != nil { return 0, err } - decoded, err := DecodeRecordBatch(**schemaFrame, ArrowFrame{Header: append([]byte(nil), data.DataHeader...), Body: snapshot.TrustedBytes()}, g.cfg.MaxBatchBytes) + // DecodeRecordBatch consumes the result header synchronously before + // the next Recv. The schema header is retained across batches, but + // this per-batch header has no cross-call lifetime, so keep the + // Flight-owned slice and avoid a redundant allocation/copy. + decoded, err := DecodeRecordBatch(**schemaFrame, ArrowFrame{Header: data.DataHeader, Body: snapshot.TrustedBytes()}, g.cfg.MaxBatchBytes) if err != nil { return 0, fmt.Errorf("python udf: decode result: %w", err) } From ad36b4f0c833b938e1b69995aeecaf493f1b0c62 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 15:32:09 +0800 Subject: [PATCH 084/241] fix(udf): preserve Arrow metadata across input batches --- pkg/udf/python/worker/test_worker.py | 9 +++++++++ pkg/udf/python/worker/worker.py | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index b62f332687317..fa3342bb25c22 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -656,6 +656,15 @@ def test_every_input_batch_keeps_the_frozen_schema(self): with self.assertRaisesRegex(ValueError, "Arrow type"): worker._validate_input_batch_schema(invalid_batch, valid_schema, [descriptor]) + metadata_changed = pa.RecordBatch.from_arrays( + [pa.array([1], type=pa.int64())], + schema=pa.schema( + [pa.field("arg_0", pa.int64(), nullable=True, metadata={b"mo.udf.type": b"tampered"})] + ), + ) + with self.assertRaisesRegex(ValueError, "logical metadata"): + worker._validate_input_batch_schema(metadata_changed, valid_schema, [descriptor]) + def test_closing_control_preserves_zero_last_sequence(self): fence = { "account_id": 1, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 16e702f0c41a5..5263c5bf6db85 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1324,7 +1324,11 @@ def _validate_input_batch_schema( # every Field and its metadata for every batch was measurable overhead on # small W=1 bursts. Retain the detailed validation on the mismatch path so # a malformed later frame still gets the same contract diagnosis. - if batch.schema == expected_schema: + # PyArrow's Schema equality ignores metadata by default. The metadata + # carries the frozen logical descriptor and fingerprint, so a later batch + # with the same physical type but a different contract must not pass this + # fast path. + if batch.schema.equals(expected_schema, check_metadata=True): return _validate_schema(batch.schema, descriptors) raise ValueError("TYPE_CONTRACT: input batch schema changed") From 1caf71772cafdb2cac59f322cf5088f96f0bc0b6 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 15:34:31 +0800 Subject: [PATCH 085/241] fix(udf): fence supervisor restart during close --- pkg/udf/python/supervisor.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/pkg/udf/python/supervisor.go b/pkg/udf/python/supervisor.go index 4927d3dde7109..815433db35be7 100644 --- a/pkg/udf/python/supervisor.go +++ b/pkg/udf/python/supervisor.go @@ -86,14 +86,16 @@ func (s *Supervisor) wait(cmd *exec.Cmd, done chan struct{}) { err := cmd.Wait() s.mu.Lock() if s.cmd == cmd { - // cmd is cleared so a later Start can launch a new worker, while done is - // retained as the completed notification that Start's caller captured. + // Keep the terminal state transition and Done close under the same lock. + // Otherwise Start can observe cmd == nil in the small interval after + // Wait clears it but before the old Done channel is closed, and launch a + // replacement while a concurrent Close is still waiting for the old + // worker. s.cmd = nil s.lastErr = err - s.closing = false } - s.mu.Unlock() close(done) + s.mu.Unlock() if err != nil { logutil.Errorf("Python UDF worker exited: %v", err) } @@ -122,7 +124,7 @@ func (s *Supervisor) Err() error { func (s *Supervisor) Close() error { s.mu.Lock() cmd, done := s.cmd, s.done - if cmd != nil { + if cmd != nil || done != nil { s.closing = true } s.mu.Unlock() @@ -135,5 +137,13 @@ func (s *Supervisor) Close() error { if done != nil { <-done } + // Keep Start fenced until the worker observed by this Close has published + // its terminal notification. This also clears the fence when Close is + // called after an unexpected exit, where cmd is already nil. + s.mu.Lock() + if s.cmd == nil && s.done == done { + s.closing = false + } + s.mu.Unlock() return closeErr } From 548dd1263bb73045a08df204c367ea505636babe Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 15:43:48 +0800 Subject: [PATCH 086/241] fix(udf): require explicit Python invocation language --- pkg/udf/python/gateway.go | 2 +- pkg/udf/python/gateway_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 2e35736cf8f6e..0f949dca8b6fa 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -1556,7 +1556,7 @@ func validateInvocationHeader(invocation *udf.Invocation) error { if invocation == nil { return fmt.Errorf("python udf: nil invocation") } - if invocation.Language != "" && invocation.Language != udf.LanguagePython { + if invocation.Language != udf.LanguagePython { return fmt.Errorf("python udf: unsupported language %q", invocation.Language) } if invocation.Handler == "" { diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index 128ea37a965e6..b9fa665e3e062 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -196,6 +196,7 @@ func TestValidateInvocationRequiresFrozenContract(t *testing.T) { name string mutate func(*udf.Invocation) }{ + {name: "language", mutate: func(invocation *udf.Invocation) { invocation.Language = "" }}, {name: "mode", mutate: func(invocation *udf.Invocation) { invocation.Mode = "" }}, {name: "external handler", mutate: func(invocation *udf.Invocation) { invocation.Handler = "module:add" }}, {name: "null policy", mutate: func(invocation *udf.Invocation) { invocation.NullPolicy = "" }}, From 871d749f21992ee7caedd78b8006a59e90082e84 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 15:47:49 +0800 Subject: [PATCH 087/241] fix(udf): require explicit Python definition language --- pkg/udf/python/gateway.go | 2 +- pkg/udf/python/gateway_integration_test.go | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 0f949dca8b6fa..6b703cf61b95d 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -199,7 +199,7 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin if definition == nil { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: nil Python routine definition") } - if definition.Language != "" && definition.Language != udf.LanguagePython { + if definition.Language != udf.LanguagePython { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported UDF language %q", definition.Language) } if strings.TrimSpace(definition.Handler) == "" { diff --git a/pkg/udf/python/gateway_integration_test.go b/pkg/udf/python/gateway_integration_test.go index 64dec7b9b2b56..74577c936075f 100644 --- a/pkg/udf/python/gateway_integration_test.go +++ b/pkg/udf/python/gateway_integration_test.go @@ -88,6 +88,13 @@ func TestGatewayExecutesAgainstRealPythonWorker(t *testing.T) { cancel() require.NoFileExists(t, marker, "definition validation executed top-level Python code") + invalidLanguage := routineDefinitionForIntegration(valid) + invalidLanguage.Language = "" + validationContext, cancel = context.WithTimeout(context.Background(), 5*time.Second) + err = gateway.ValidateDefinition(validationContext, invalidLanguage) + cancel() + require.ErrorContains(t, err, "unsupported UDF language") + invalid := integrationInvocationForArgs( ModeScalar, "add", "def add(ctx, value) return value", []types.Type{types.T_int64.ToType()}, nil, 0, From a8e45748d4b985b74b881593e2cb87f91af2b7c7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 15:57:46 +0800 Subject: [PATCH 088/241] fix(udf): validate final Python handler binding --- pkg/udf/python/worker/test_worker.py | 24 ++++++++++++++++++++ pkg/udf/python/worker/worker.py | 33 ++++++++++++++++++---------- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index fa3342bb25c22..e21b0a1a4cbdd 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -201,6 +201,30 @@ def test_definition_validation_rejects_async_handler_before_catalog_state(self): finally: server.shutdown() + def test_definition_validation_rejects_handler_rebound_after_definition(self): + payload = complete_definition_validation_payload( + "def f(ctx, value): return value\n" + "f = 1\n" + ) + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + try: + results = list( + server.do_action( + None, + flight.Action( + "ValidatePythonDefinition", + json.dumps(payload, separators=(",", ":")).encode(), + ), + ) + ) + response = json.loads(bytes(results[0].body)) + self.assertEqual("ERROR", response["status"]) + self.assertIn("not a module-level function", response["reason"]) + self.assertEqual({}, server._active) + self.assertEqual({}, server._terminal) + finally: + server.shutdown() + def test_capability_advertises_worker_instance_lease(self): encoded = worker._encode_capabilities( {"protocol_version": worker.PROTOCOL_VERSION}, lease_epoch=17 diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 5263c5bf6db85..06319fdac1e7e 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -918,20 +918,29 @@ def _validate_definition_syntax(value: Dict[str, Any]) -> None: tree = ast.parse(value["source"], filename="", mode="exec") binding = None for node in tree.body: - if isinstance(node, ast.AsyncFunctionDef) and node.name == handler: - raise ValueError("USER_CODE: Python handler must be synchronous") - if isinstance(node, ast.FunctionDef) and node.name == handler: - binding = node - break - if isinstance(node, ast.Assign) and isinstance(node.value, ast.Lambda): + if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name == handler: + # Continue scanning: a later module-level assignment can replace + # the function object that exec() will expose to the runtime. + binding = "async" if isinstance(node, ast.AsyncFunctionDef) else "sync" + continue + if isinstance(node, ast.ClassDef) and node.name == handler: + binding = "other" + continue + if isinstance(node, ast.Assign): if any(isinstance(target, ast.Name) and target.id == handler for target in node.targets): - binding = node - break - if isinstance(node, ast.AnnAssign) and isinstance(node.value, ast.Lambda): + binding = "lambda" if isinstance(node.value, ast.Lambda) else "other" + continue + if isinstance(node, ast.AnnAssign): if isinstance(node.target, ast.Name) and node.target.id == handler: - binding = node - break - if binding is None: + binding = "lambda" if isinstance(node.value, ast.Lambda) else "other" + continue + if isinstance(node, ast.Delete): + if any(isinstance(target, ast.Name) and target.id == handler for target in node.targets): + binding = "other" + continue + if binding == "async": + raise ValueError("USER_CODE: Python handler must be synchronous") + if binding not in ("sync", "lambda"): raise ValueError( f"USER_CODE: Python handler {handler!r} is not a module-level function" ) From 8944e55bdfd1b57df75141f379e917b08ad57936 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 16:09:07 +0800 Subject: [PATCH 089/241] fix(udf): fall back when handler group kill is denied --- pkg/udf/python/worker/test_worker.py | 12 ++++++++++++ pkg/udf/python/worker/worker.py | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index e21b0a1a4cbdd..9fc5f52f91280 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1578,6 +1578,18 @@ def test_handler_close_retries_failed_process_cleanup_without_losing_ownership(s if session._slot_acquired: slots.release() + @unittest.skipUnless(os.name == "posix", "process-group cleanup fallback") + def test_process_cleanup_falls_back_to_owned_leader_on_group_permission_error(self): + process = mock.Mock(pid=1234) + process.poll.return_value = None + process.wait.return_value = 0 + + with mock.patch.object(worker.os, "killpg", side_effect=PermissionError): + worker._kill_execution_process(process) + + process.kill.assert_called_once_with() + process.wait.assert_called_once_with(timeout=1.0) + def test_handler_close_retains_process_for_a_later_cleanup_retry(self): session = object.__new__(worker._HandlerProcessSession) session._slots = threading.BoundedSemaphore(1) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 06319fdac1e7e..0fa4b800d4442 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -2160,6 +2160,16 @@ def _kill_execution_process(process: subprocess.Popen) -> None: os.killpg(process.pid, signal.SIGKILL) except ProcessLookupError: pass + except PermissionError: + # A process-group kill can be denied during a platform or + # teardown race even though the worker still owns the leader. + # Kill the Popen child directly so the handler slot is not + # stranded; the parent-liveness watchdog remains responsible + # for descendants when the group cannot be addressed here. + try: + process.kill() + except ProcessLookupError: + pass elif process.poll() is None: process.kill() try: From 2928a19e0f20e0e461a77e5d9295d655f4c4e2ea Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 18:08:04 +0800 Subject: [PATCH 090/241] fix(udf): include timezone data in runtime image --- optools/images/Dockerfile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/optools/images/Dockerfile b/optools/images/Dockerfile index f0fb1f142a221..0d72ad6029979 100644 --- a/optools/images/Dockerfile +++ b/optools/images/Dockerfile @@ -62,6 +62,14 @@ RUN if [ "$TYPECHECK" = "1" ]; then \ FROM matrixorigin/ubuntu:22.04 +# The Python UDF capability contract includes the IANA timezone database +# version. The worker image and the CN image must advertise the same version +# before Python execution is admitted; the minimal MatrixOne runtime image +# does not contain tzdata by default. +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata \ + && rm -rf /var/lib/apt/lists/* + COPY --from=builder /go/src/github.com/matrixorigin/matrixone/mo-service /mo-service COPY --from=builder /go/src/github.com/matrixorigin/matrixone/etc /etc COPY --from=builder /go/src/github.com/matrixorigin/matrixone/thirdparties/install/lib/*.so /usr/local/lib/ From 9b0d2347c29bd913e9eaa1176ce634fb4ca2a24f Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 18:25:24 +0800 Subject: [PATCH 091/241] fix(udf): fail closed on broken liveness watches --- pkg/udf/python/worker/test_watchdog.py | 29 ++++++++++++++++++++++++++ pkg/udf/python/worker/test_worker.py | 13 ++++++++++++ pkg/udf/python/worker/watchdog.py | 7 +++++++ pkg/udf/python/worker/worker.py | 9 ++++++++ 4 files changed, 58 insertions(+) create mode 100644 pkg/udf/python/worker/test_watchdog.py diff --git a/pkg/udf/python/worker/test_watchdog.py b/pkg/udf/python/worker/test_watchdog.py new file mode 100644 index 0000000000000..56d31f77a5cf7 --- /dev/null +++ b/pkg/udf/python/worker/test_watchdog.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 + +import importlib.util +import pathlib +import unittest +from unittest import mock + + +WATCHDOG_PATH = pathlib.Path(__file__).with_name("watchdog.py") +spec = importlib.util.spec_from_file_location("matrixone_python_watchdog", WATCHDOG_PATH) +watchdog = importlib.util.module_from_spec(spec) +spec.loader.exec_module(watchdog) + + +class WatchdogTest(unittest.TestCase): + @unittest.skipUnless(watchdog.os.name == "posix", "process-group watchdog") + def test_parent_watch_read_error_kills_process_group(self): + with ( + mock.patch.object(watchdog.os, "read", side_effect=OSError("closed")), + mock.patch.object(watchdog.os, "killpg") as killpg, + mock.patch.object(watchdog.os, "close"), + ): + watchdog._watch(17, 23) + + killpg.assert_called_once_with(23, watchdog.signal.SIGKILL) + + +if __name__ == "__main__": + unittest.main() diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 9fc5f52f91280..24df2a4a938e1 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -2190,6 +2190,19 @@ def process_is_running(pid): except ProcessLookupError: pass + @unittest.skipUnless(os.name == "posix", "handler process-group cleanup") + def test_parent_watch_read_error_kills_own_group_before_handler_exit(self): + with ( + mock.patch.object(worker.os, "read", side_effect=OSError("closed")), + mock.patch.object(worker.os, "getpgrp", return_value=23), + mock.patch.object(worker.os, "killpg") as killpg, + mock.patch.object(worker.os, "_exit", side_effect=SystemExit(137)), + ): + with self.assertRaises(SystemExit): + worker._watch_parent_liveness(17) + + killpg.assert_called_once_with(23, worker.signal.SIGKILL) + def test_handler_stdout_cannot_inject_parent_protocol(self): descriptor = {"type_id": worker.INT64, "offset_width": 32} batch = pa.RecordBatch.from_arrays([pa.array([1], type=pa.int64())], ["arg_0"]) diff --git a/pkg/udf/python/worker/watchdog.py b/pkg/udf/python/worker/watchdog.py index 25c417a73b7d4..30805ad09c8a5 100644 --- a/pkg/udf/python/worker/watchdog.py +++ b/pkg/udf/python/worker/watchdog.py @@ -20,6 +20,13 @@ def _watch(read_fd: int, process_group_id: int) -> None: pass return except (OSError, ValueError): + # A broken descriptor means the worker death signal can no longer be + # observed. Kill the owned group before the watchdog exits so a + # handler descendant cannot outlive both its owners. + try: + os.killpg(process_group_id, signal.SIGKILL) + except ProcessLookupError: + pass return finally: try: diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 0fa4b800d4442..2bc0ad54268ba 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1953,6 +1953,15 @@ def _watch_parent_liveness(read_fd: int) -> None: pass os._exit(137) except (OSError, ValueError): + # A broken watch descriptor is also a lost parent notification. The + # handler must terminate its whole process group before leaving; an + # ordinary thread exit would leave descendants alive after the worker + # has already lost ownership of them. + if os.name == "posix": + try: + os.killpg(os.getpgrp(), signal.SIGKILL) + except ProcessLookupError: + pass os._exit(137) From bbb0febc287b6139a4bd84bd2adf05315d532d59 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 18:29:12 +0800 Subject: [PATCH 092/241] fix(udf): close gateway admission barrier --- pkg/udf/python/gateway.go | 14 ++++++++++++++ pkg/udf/python/gateway_admission_test.go | 13 +++++++++++++ 2 files changed, 27 insertions(+) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 6b703cf61b95d..217d769363c4a 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -397,9 +397,13 @@ func (g *Gateway) Close() error { g.mu.Unlock() return nil } + // Serialize the close barrier with group admission. Once this lock is + // released, no caller can pass the admission check after Close returns. + g.admissionMu.Lock() g.closed = true conn := g.conn g.conn = nil + g.admissionMu.Unlock() g.mu.Unlock() if conn == nil { return nil @@ -727,15 +731,25 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss if err != nil { return nil, err } + // g.mu -> admissionMu is the lifecycle lock order. Close uses the same + // order so a concurrent shutdown cannot return while this invocation is + // still being admitted. + g.mu.Lock() + if g.closed { + g.mu.Unlock() + return nil, errGatewayClosed + } g.admissionMu.Lock() ledger := g.ledger ttl := g.ledgerTTL active := g.active if err := g.claimGroupLocked(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch); err != nil { g.admissionMu.Unlock() + g.mu.Unlock() return nil, err } g.admissionMu.Unlock() + g.mu.Unlock() if ledger == nil || active == nil { g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) return nil, fmt.Errorf("python udf: admission state is not initialized") diff --git a/pkg/udf/python/gateway_admission_test.go b/pkg/udf/python/gateway_admission_test.go index 457f0d7a9308a..0288b0e3fd0ef 100644 --- a/pkg/udf/python/gateway_admission_test.go +++ b/pkg/udf/python/gateway_admission_test.go @@ -55,6 +55,19 @@ func TestGatewayAdmissionFencesDuplicateAndReleasesOnce(t *testing.T) { require.ErrorIs(t, err, protocol.ErrDuplicate) } +func TestGatewayAdmissionRejectsAfterClose(t *testing.T) { + gateway := newAdmissionTestGateway(t, 1) + require.NoError(t, gateway.Close()) + + _, err := gateway.admitInvocation(validInvocation()) + require.ErrorIs(t, err, errGatewayClosed) + if gateway.ledger != nil { + entries, _ := gateway.ledger.Counts() + require.Zero(t, entries) + } + require.Len(t, gateway.active, 0) +} + func TestGatewayAdmissionRejectsAtKWithoutLeavingLedgerEntry(t *testing.T) { gateway := newAdmissionTestGateway(t, 1) first := validInvocation() From 9d3317873e7c34b4cc5c6fb24902773a797d5416 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 18:33:54 +0800 Subject: [PATCH 093/241] fix(udf): validate empty selection domains --- pkg/sql/colexec/external_routine_eval.go | 15 +++++++++------ pkg/sql/colexec/external_routine_eval_test.go | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index 72594708e47cb..dffe882326fb3 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -205,12 +205,9 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch if err != nil { return nil, err } - if rowCount == 0 { - if err := e.result.PreExtendAndReset(0); err != nil { - return nil, err - } - return e.result.GetResultVector(), nil - } + // Keep the row-domain contract strict even for an empty batch. Returning + // early before this check would let a stale selection mask cross the + // physical boundary and hide a relation-position bug in the caller. if selectList != nil && len(selectList) != rowCount { return nil, fmt.Errorf( "external routine selection has %d rows, expected %d", @@ -218,6 +215,12 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch rowCount, ) } + if rowCount == 0 { + if err := e.result.PreExtendAndReset(0); err != nil { + return nil, err + } + return e.result.GetResultVector(), nil + } if noRowsSelected(selectList, rowCount) { return e.nullResult(rowCount) diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index 36107b842e754..42d36d1acbe72 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -166,6 +166,24 @@ func TestExternalRoutineEvalRejectsSelectionWithWrongRowDomain(t *testing.T) { require.ErrorContains(t, err, "selection has 2 rows, expected 1") } +func TestExternalRoutineEvalRejectsSelectionForEmptyRowDomain(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + + input := vector.NewVec(types.T_int64.ToType()) + defer input.Free(proc.Mp()) + evaluator, err := newExternalRoutineEval(proc, testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler), []ExpressionExecutor{ + &externalRoutineTestExecutor{vector: input}, + }, nil) + require.NoError(t, err) + defer evaluator.Free() + + emptyBatch := batch.NewWithSize(0) + emptyBatch.SetRowCount(0) + _, err = evaluator.Eval(proc, []*batch.Batch{emptyBatch}, []bool{true}) + require.ErrorContains(t, err, "selection has 1 rows, expected 0") +} + func TestNewExpressionExecutorDispatchesTypedRoutineCall(t *testing.T) { proc := testutil.NewProcess(t) defer proc.Free() From 9f825f7570231abae8f5aabdb6eb0b5856802130 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 18:38:24 +0800 Subject: [PATCH 094/241] fix(udf): reject noncanonical JSON results --- pkg/udf/python/arrow.go | 29 +++++++++++++++++++++++++++-- pkg/udf/python/arrow_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 3bf9e60d65f75..69714be8ffa65 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -1039,10 +1039,26 @@ func appendInputValue( // though scalar JSON values happen to work. func canonicalJSONInput(value []byte) ([]byte, error) { text := []byte(types.DecodeJson(value).String()) - var compact bytes.Buffer - if err := json.Compact(&compact, text); err != nil { + canonical, err := canonicalJSONTextBytes(text) + if err != nil { return nil, fmt.Errorf("TYPE_CONTRACT: invalid JSON input: %w", err) } + return canonical, nil +} + +func canonicalJSONText(value string) (string, error) { + canonical, err := canonicalJSONTextBytes([]byte(value)) + if err != nil { + return "", err + } + return string(canonical), nil +} + +func canonicalJSONTextBytes(value []byte) ([]byte, error) { + var compact bytes.Buffer + if err := json.Compact(&compact, value); err != nil { + return nil, err + } return compact.Bytes(), nil } @@ -1471,6 +1487,15 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro if descriptor.Width > 0 && int32(utf8.RuneCountInString(input.(*array.String).Value(row))) > descriptor.Width { return fmt.Errorf("TYPE_CONTRACT: string row %d exceeds width %d", row, descriptor.Width) } + case types.T_json: + value := input.(*array.String).Value(row) + canonical, err := canonicalJSONText(value) + if err != nil { + return fmt.Errorf("TYPE_CONTRACT: JSON row %d is not valid canonical text: %w", row, err) + } + if canonical != value { + return fmt.Errorf("TYPE_CONTRACT: JSON row %d is not canonical text", row) + } case types.T_binary, types.T_varbinary, types.T_blob: if descriptor.Width > 0 && int32(len(input.(*array.Binary).Value(row))) > descriptor.Width { return fmt.Errorf("TYPE_CONTRACT: binary row %d exceeds width %d", row, descriptor.Width) diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index a3d12adf65cb4..c74266bd1a80b 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -705,6 +705,35 @@ func TestBuildInputRecordCanonicalizesJSONText(t *testing.T) { require.Equal(t, `{"a":1,"b":[true,null,"中"]}`, values.Value(0)) } +func TestArrowValueDomainRequiresCanonicalJSONText(t *testing.T) { + descriptor, err := NewTypeDescriptor(types.T_json.ToType()) + require.NoError(t, err) + + for _, test := range []struct { + name string + value string + valid bool + }{ + {name: "canonical", value: `{"a":1,"b":[true,null]}`, valid: true}, + {name: "whitespace", value: ` { "a": 1, "b": [true, null] } `}, + {name: "invalid", value: `{"a":}`}, + } { + t.Run(test.name, func(t *testing.T) { + builder := array.NewStringBuilder(memory.NewGoAllocator()) + builder.Append(test.value) + values := builder.NewStringArray() + defer values.Release() + + err := validateArrowValueDomain(descriptor, values) + if test.valid { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, "JSON row 0") + } + }) + } +} + func TestGoPythonTypeDescriptorFixtures(t *testing.T) { data, err := os.ReadFile("testdata/type_descriptors.json") require.NoError(t, err) From a684d600220d1bf1bac8b4fd6a93ff2bf30aed02 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 18:39:51 +0800 Subject: [PATCH 095/241] fix(udf): reject opaque text descriptors --- pkg/udf/python/arrow.go | 4 +++- pkg/udf/python/arrow_test.go | 1 + pkg/udf/python/worker/test_worker.py | 9 +++++++++ pkg/udf/python/worker/worker.py | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 69714be8ffa65..c7615947b9692 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -211,7 +211,9 @@ func (d TypeDescriptor) Validate() error { return fmt.Errorf("TYPE_CONTRACT: temporal scale or charset is outside the supported range") } case types.T_char, types.T_varchar, types.T_text: - if d.Charset > types.CharsetUTF8 { + switch d.Charset { + case types.CharsetLegacy, types.CharsetUTF8MB4Bin, types.CharsetUTF8: + default: return fmt.Errorf("TYPE_CONTRACT: unsupported text charset %d", d.Charset) } case types.T_binary, types.T_varbinary, types.T_blob: diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index c74266bd1a80b..c0fd830d93746 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -648,6 +648,7 @@ func TestTypeDescriptorRejectsNonCanonicalDomain(t *testing.T) { {TypeID: int32(types.T_json), OffsetWidth: 32}, {TypeID: int32(types.T_date), OffsetWidth: 32}, {TypeID: int32(types.T_array_float32), Width: types.MaxArrayDimension + 1}, + {TypeID: int32(types.T_varchar), Width: 16, Charset: types.CharsetBinary, OffsetWidth: 32}, } for _, descriptor := range invalid { _, err := descriptor.Field("value") diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 24df2a4a938e1..37f4480a33abb 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -626,6 +626,15 @@ def test_type_descriptor_shape_is_strict(self): with self.assertRaisesRegex(ValueError, "offset_width must be an integer"): worker._field("result", {"type_id": worker.INT64, "offset_width": "32"}) + def test_text_descriptor_rejects_opaque_binary_charset(self): + for type_id in (worker.CHAR, worker.VARCHAR, worker.TEXT): + with self.subTest(type_id=type_id): + with self.assertRaisesRegex(ValueError, "unsupported text charset"): + worker._field( + "result", + {"type_id": type_id, "width": 16, "charset": 1, "offset_width": 32}, + ) + def test_malformed_control_is_reported_as_protocol_error(self): with self.assertRaisesRegex(ValueError, "PROTOCOL: invalid control UTF-8"): worker._decode_control(b"\xff") diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 2bc0ad54268ba..81fb7019c23e6 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1198,7 +1198,7 @@ def _validate_descriptor_domain(descriptor: Dict[str, Any]) -> None: if scale > 6 or charset: raise ValueError("TYPE_CONTRACT: temporal scale or charset is outside the supported range") elif type_id in (CHAR, VARCHAR, TEXT): - if charset > 3: + if charset not in (0, 2, 3): raise ValueError("TYPE_CONTRACT: unsupported text charset") elif type_id in (BINARY, VARBINARY, BLOB): if charset != 1: From 09d384e4b8c10ee1de4e9510272188e264428196 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 18:44:37 +0800 Subject: [PATCH 096/241] fix(udf): serialize admission with gateway close --- pkg/udf/python/gateway.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 217d769363c4a..2f999602acd55 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -733,7 +733,9 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss } // g.mu -> admissionMu is the lifecycle lock order. Close uses the same // order so a concurrent shutdown cannot return while this invocation is - // still being admitted. + // still being admitted. Keep g.mu held until the complete claim is either + // published or rolled back; otherwise Close could return in the gap between + // the group claim and the ledger/K reservation becoming owned. g.mu.Lock() if g.closed { g.mu.Unlock() @@ -749,9 +751,9 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss return nil, err } g.admissionMu.Unlock() - g.mu.Unlock() if ledger == nil || active == nil { g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.mu.Unlock() return nil, fmt.Errorf("python udf: admission state is not initialized") } // Expire is intentionally limited to tombstones by TerminalLedger. An @@ -764,11 +766,13 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss credit, err := ledger.Reserve(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch, 1, entryBytes) if err != nil { g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.mu.Unlock() return nil, fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF terminal ledger: %w", err) } if err := credit.Add(key, entryBytes, time.Now().Add(ttl)); err != nil { credit.ReleaseUnused() g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.mu.Unlock() return nil, err } select { @@ -780,6 +784,7 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss _ = ledger.Abandon(key) credit.ReleaseUnused() g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.mu.Unlock() return nil, fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF active invocation slots are full") } @@ -797,6 +802,7 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss _ = ledger.Abandon(key) credit.ReleaseUnused() g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.mu.Unlock() return nil, err } token, err := group.BeginOpen(invocation.Tuple.InvocationID) @@ -804,14 +810,17 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss _ = group.Close(protocol.ReasonPartialOpenError) _ = ledger.Abandon(key) g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.mu.Unlock() return nil, err } if err := token.Commit(); err != nil { _ = group.Close(protocol.ReasonPartialOpenError) _ = ledger.Abandon(key) g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.mu.Unlock() return nil, err } + g.mu.Unlock() return &invocationAdmission{ gateway: g, group: group, From 642d73b4dd69b32b8a24a2afd2c4fc42bf86961a Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 18:48:42 +0800 Subject: [PATCH 097/241] fix(udf): enforce budget during handler writes --- pkg/udf/python/worker/test_worker.py | 51 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 19 ++++++++--- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 37f4480a33abb..38ecf5dda8d97 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -2923,6 +2923,57 @@ def test_handler_deadline_includes_request_serialization(self): if session is not None: session.close() + @unittest.skipUnless(os.name == "posix", "non-blocking write budget test") + def test_handler_request_write_rechecks_budget_within_one_write_event(self): + class CancelAfterWrites: + def __init__(self): + self.writes = 0 + + def is_cancelled(self): + return self.writes >= 2 + + class FakeStdin: + def fileno(self): + return 123 + + class FakeProcess: + stdin = FakeStdin() + + def poll(self): + return None + + class FakeSelector: + def register(self, *args): + pass + + def unregister(self, *args): + pass + + def select(self, _timeout): + return [(types.SimpleNamespace(data="request"), None)] + + context = CancelAfterWrites() + session = object.__new__(worker._HandlerProcessSession) + session._closed = False + session._process = FakeProcess() + session._selector = FakeSelector() + session._response_buffer = bytearray() + session._burst_batches = 0 + + request_parts = tuple(b"x" for _ in range(100)) + + def write(_fd, data): + context.writes += 1 + return len(data) + + with mock.patch.object( + worker, "_encode_execution_request", return_value=(request_parts, 100) + ), mock.patch.object(worker.os, "write", side_effect=write): + with self.assertRaisesRegex(TimeoutError, "handler execution cancelled"): + session.run(context, {"input": b"x"}, 10) + + self.assertLess(context.writes, len(request_parts)) + def test_zero_argument_vector_uses_context_rows(self): descriptor = {"type_id": worker.INT64, "offset_width": 32} output = pa.array([7, 7, 7], type=pa.int64()) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 81fb7019c23e6..e7816943179ec 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -2478,16 +2478,21 @@ def run(self, context, request: Dict[str, Any], timeout_seconds: float) -> bytes request_parts, request_size = _encode_execution_request( request, compact=self._burst_batches > 0 ) - if time.monotonic() >= deadline: - raise TimeoutError("DEADLINE_EXCEEDED: handler execution timeout") + + def check_budget() -> None: + if _context_is_cancelled(context): + raise TimeoutError("DEADLINE_EXCEEDED: handler execution cancelled") + if time.monotonic() >= deadline: + raise TimeoutError("DEADLINE_EXCEEDED: handler execution timeout") + + check_budget() request_part_index = 0 request_part_offset = 0 stdin_fd = self._process.stdin.fileno() self._selector.register(stdin_fd, selectors.EVENT_WRITE, "request") try: while True: - if _context_is_cancelled(context): - raise TimeoutError("DEADLINE_EXCEEDED: handler execution cancelled") + check_budget() remaining = deadline - time.monotonic() if remaining <= 0: raise TimeoutError("DEADLINE_EXCEEDED: handler execution timeout") @@ -2499,6 +2504,11 @@ def run(self, context, request: Dict[str, Any], timeout_seconds: float) -> bytes if event.data == "request": try: while request_part_index < len(request_parts): + # A single writable notification can drain many + # small frame parts. Re-check the caller budget + # inside that loop so serialization/write work + # cannot outrun cancellation or the deadline. + check_budget() part = request_parts[request_part_index] if request_part_offset == len(part): request_part_index += 1 @@ -2508,6 +2518,7 @@ def run(self, context, request: Dict[str, Any], timeout_seconds: float) -> bytes if written <= 0: raise BrokenPipeError("handler request channel made no progress") request_part_offset += written + check_budget() if request_part_offset < len(part): break except BlockingIOError: From 64736bb56db7b13cb87691d8f055d67fcc39455c Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 18:58:10 +0800 Subject: [PATCH 098/241] fix(udf): validate Python catalog signature before publish --- pkg/frontend/authenticate.go | 38 ++++++++++++++++++--- pkg/frontend/python_udf_catalog_test.go | 45 +++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index f857768ca6612..fa4aed6b959a1 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -12387,17 +12387,45 @@ func normalizePythonFunctionDefinition(definition userDefinedFunctionDefinition) definition.returnDescriptor = returnDescriptor definition.signatureKeySchemaVersion = udf.PythonSignatureKeySchemaVersion definition.signatureFingerprint = signatureFingerprint - // Keep arg_types as the shared logical signature key. The exact Python - // descriptor belongs in canonical_input_descriptor and in the immutable - // revision row; mixing the two encodings makes shared SQL readers and - // upgrade paths depend on a language-specific workaround. + // The base catalog keeps the historical logical signature columns while the + // immutable revision keeps the exact Python descriptors. Both are + // execution authority: accepting a caller-supplied args/retType pair that + // disagrees with the typed body would publish an identity whose shared + // overload key and immutable revision describe different functions. That + // malformed row would only be discovered on a later read or plan bind. logicalArgTypes, err := userDefinedFunctionArgumentTypesFromJSON(definition.args) if err != nil { return userDefinedFunctionDefinition{}, moerr.NewInvalidInputNoCtxf( "UNSUPPORTED_ROUTINE_VERSION: Python logical argument metadata is invalid: %v", err, ) } - definition.argTypes = logicalArgTypes + expectedLogicalTypes := make([]string, len(body.ArgTypes)) + for index, descriptor := range body.ArgTypes { + expectedLogicalTypes[index] = strings.ToLower(descriptor.Type().Oid.String()) + } + expectedLogicalArgTypes, err := userDefinedFunctionArgumentTypes(expectedLogicalTypes) + if err != nil { + return userDefinedFunctionDefinition{}, moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: Python typed argument metadata is invalid: %v", err, + ) + } + if logicalArgTypes != expectedLogicalArgTypes { + return userDefinedFunctionDefinition{}, moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: Python catalog arguments %q do not match the typed body %q", + logicalArgTypes, expectedLogicalArgTypes, + ) + } + if !routineRevisionReturnTypeMatches(definition.retType, body.ReturnType.Type().Oid) { + return userDefinedFunctionDefinition{}, moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: Python catalog return type %q does not match the typed body %q", + definition.retType, body.ReturnType.Type().Oid.String(), + ) + } + // Keep arg_types canonicalized from the typed body. The exact Python + // descriptor belongs in canonical_input_descriptor and in the immutable + // revision row; the shared logical key is derived from the same source so + // SQL readers and Python readers cannot drift. + definition.argTypes = expectedLogicalArgTypes return definition, nil } diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index be7771ec4537b..9f2ac17cbd174 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -269,6 +269,51 @@ func TestPersistPythonCreateRejectsMalformedDefinitionBeforeWriting(t *testing.T require.Empty(t, bh.executedSqls) } +func TestNormalizePythonDefinitionRejectsCatalogSignatureDrift(t *testing.T) { + body := pythonCatalogTestBody(t, types.T_int64) + cases := []struct { + name string + args string + retType string + message string + }{ + { + name: "arguments", + args: `[{"name":"value","type":"varchar"}]`, + retType: "bigint", + message: "catalog arguments", + }, + { + name: "return", + args: `[{"name":"value","type":"bigint"}]`, + retType: "varchar", + message: "catalog return type", + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + _, err := normalizePythonFunctionDefinition(userDefinedFunctionDefinition{ + args: tc.args, + retType: tc.retType, + body: body, + }) + require.ErrorContains(t, err, "UNSUPPORTED_ROUTINE_VERSION") + require.ErrorContains(t, err, tc.message) + }) + } +} + +func TestNormalizePythonDefinitionDerivesLogicalSignatureFromTypedBody(t *testing.T) { + normalized, err := normalizePythonFunctionDefinition(userDefinedFunctionDefinition{ + args: `[{"name":"value","type":"int"}]`, + retType: "int", + body: pythonCatalogTestBody(t, types.T_int32), + }) + require.NoError(t, err) + require.Equal(t, `["int"]`, normalized.argTypes) +} + func TestPersistPythonCreateIdentityLookupIncludesLanguage(t *testing.T) { definition := userDefinedFunctionDefinition{ name: "python_identity", From 8f314a0860b34e3a3f5d2a3a40f54cc1bbacea98 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 19:02:14 +0800 Subject: [PATCH 099/241] fix(udf): refresh worker lease for readiness --- pkg/udf/python/gateway.go | 22 ++++++++-- pkg/udf/python/gateway_integration_test.go | 48 ++++++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 2f999602acd55..4c113a0c807d9 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -171,7 +171,10 @@ func (g *Gateway) CheckLanguageReady(ctx context.Context, language string) error if err != nil { return err } - return g.ensureCapabilities(ctx, client) + // Readiness is an external admission decision. Refresh the worker + // capability record so a worker replacement at the same endpoint cannot + // inherit a stale success from the previous process. + return g.ensureCapabilities(ctx, client, true) } // ValidateDefinition asks the current worker to compile the exact artifact @@ -284,7 +287,11 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin if err != nil { return err } - if err := g.ensureCapabilities(ctx, client); err != nil { + // Definition validation is a Flight Action and therefore has no invocation + // lease in its request. It must perform its own worker-instance handshake; + // relying on a cached readiness result could validate against a replacement + // worker with a different contract. + if err := g.ensureCapabilities(ctx, client, true); err != nil { return err } payload, err := json.Marshal(definitionValidationPayload{ @@ -539,7 +546,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if err != nil { return err } - if err := g.ensureCapabilities(streamCtx, client); err != nil { + if err := g.ensureCapabilities(streamCtx, client, false); err != nil { return err } // The worker instance owns the lease epoch. Copy the invocation before @@ -1065,10 +1072,17 @@ type capabilityResponse struct { // Gateway connection before OpenInvocation, and it caches only a successful // match. A worker with an unknown or different contract therefore cannot run // user code, while ordinary SQL remains independent of this client. -func (g *Gateway) ensureCapabilities(ctx context.Context, client flight.FlightServiceClient) error { +func (g *Gateway) ensureCapabilities(ctx context.Context, client flight.FlightServiceClient, forceRefresh bool) error { g.capabilityMu.Lock() defer g.capabilityMu.Unlock() g.mu.Lock() + if forceRefresh { + // Clear the old lease before probing. If the probe fails, callers must + // observe the worker as unavailable rather than retaining a stale + // success that could authorize a lease-less Flight Action. + g.capabilityReady = false + g.workerLeaseEpoch = 0 + } ready := g.capabilityReady closed := g.closed g.mu.Unlock() diff --git a/pkg/udf/python/gateway_integration_test.go b/pkg/udf/python/gateway_integration_test.go index 74577c936075f..f50913691492b 100644 --- a/pkg/udf/python/gateway_integration_test.go +++ b/pkg/udf/python/gateway_integration_test.go @@ -365,6 +365,54 @@ func TestGatewayRejectsThePreviousWorkerLeaseAfterRestart(t *testing.T) { require.Equal(t, []int64{10}, vector.MustFixedColNoTypeCheck[int64](secondResult.GetResultVector())) } +func TestGatewayReadinessRefreshesLeaseAfterWorkerRestart(t *testing.T) { + python, err := exec.LookPath("python3") + require.NoError(t, err, "python3 is required for the real worker contract test") + workerPath := realWorkerPath(t) + port := freeTCPPort(t) + first := startRealWorker(t, python, workerPath, port) + + gateway, err := NewGateway(ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:" + strconv.Itoa(port), + MaxBatchBytes: 1 << 20, + MaxBatchRows: 1024, + MaxActiveInvocations: 1, + RequestTimeout: 2 * time.Second, + MaxTerminalEntries: 32, + MaxTerminalBytes: 1 << 20, + TerminalRecordTTL: time.Minute, + }) + require.NoError(t, err) + defer gateway.Close() + + readyContext, cancel := context.WithTimeout(context.Background(), 5*time.Second) + require.NoError(t, gateway.CheckLanguageReady(readyContext, udf.LanguagePython)) + cancel() + gateway.mu.Lock() + firstEpoch := gateway.workerLeaseEpoch + gateway.mu.Unlock() + require.NotZero(t, firstEpoch) + + stopRealWorker(first) + second := startRealWorker(t, python, workerPath, port) + defer stopRealWorker(second) + + // CheckLanguageReady is a live admission check. It must probe the + // replacement worker rather than returning the cached success from the + // previous process, even though the endpoint and software contract are the + // same. + readyContext, cancel = context.WithTimeout(context.Background(), 5*time.Second) + require.NoError(t, gateway.CheckLanguageReady(readyContext, udf.LanguagePython)) + cancel() + gateway.mu.Lock() + secondEpoch := gateway.workerLeaseEpoch + gateway.mu.Unlock() + require.NotZero(t, secondEpoch) + require.NotEqual(t, firstEpoch, secondEpoch, "readiness must bind to the replacement worker instance") +} + func TestGatewayCloseCancelsAnInFlightExchange(t *testing.T) { python, err := exec.LookPath("python3") require.NoError(t, err, "python3 is required for the real worker contract test") From 7ad6d4e9e98aeed7188e08e04026cdc6212b722f Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 14 Sep 2026 19:05:31 +0800 Subject: [PATCH 100/241] fix(udf): validate temporal child validity --- pkg/udf/python/worker/test_worker.py | 12 ++++++++++++ pkg/udf/python/worker/worker.py | 11 ++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 38ecf5dda8d97..2e0e11ac03d39 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -760,6 +760,18 @@ def test_zero_temporal_is_distinct_from_null(self): self.assertEqual(True, array.field("is_zero")[0].as_py()) self.assertEqual(datetime.date(1970, 1, 1), array.field("value")[0].as_py()) + def test_temporal_valid_row_requires_both_child_fields(self): + descriptor = {"type_id": worker.DATE, "offset_width": 32, "temporal_encoding": "sql_zero_struct"} + array = pa.StructArray.from_arrays( + [ + pa.array([None, False], type=pa.bool_()), + pa.array([datetime.date(1970, 1, 1), datetime.date(2024, 1, 2)], type=pa.date32()), + ], + names=["is_zero", "value"], + ) + with self.assertRaisesRegex(ValueError, "temporal zero flag is null"): + worker._validate_array_values(array, descriptor) + def test_json_input_is_canonicalized_before_handler(self): descriptor = {"type_id": worker.JSON, "offset_width": 32, "json_encoding": "canonical_text"} array = pa.array(['{"b": [true, null, "中"], "a": 1}'], type=pa.string()) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index e7816943179ec..19ea9aa2f318b 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1601,9 +1601,14 @@ def _validate_array_values(array: pa.Array, descriptor: Dict[str, Any]) -> None: struct = array for index in range(len(struct)): if not struct[index].is_valid: continue - is_zero = bool(struct.field("is_zero")[index].as_py()) - value = struct.field("value")[index].as_py() - if value is None: raise ValueError("TYPE_CONTRACT: temporal child is null") + is_zero_scalar = struct.field("is_zero")[index] + value_scalar = struct.field("value")[index] + if not is_zero_scalar.is_valid: + raise ValueError("TYPE_CONTRACT: temporal zero flag is null") + if not value_scalar.is_valid: + raise ValueError("TYPE_CONTRACT: temporal child is null") + is_zero = bool(is_zero_scalar.as_py()) + value = value_scalar.as_py() if is_zero and ((type_id == DATE and value != _datetime.date(1970, 1, 1)) or (type_id == DATETIME and value != _datetime.datetime(1970, 1, 1)) or (type_id == TIMESTAMP and value != _datetime.datetime(1970, 1, 1, tzinfo=_datetime.timezone.utc))): raise ValueError("TYPE_CONTRACT: temporal zero placeholder is invalid") if not is_zero: From fc219755ac1acbb469540205e5b832ebc6b07d63 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 10:23:53 +0800 Subject: [PATCH 101/241] fix(udf): scope worker group fences by account --- pkg/udf/python/worker/test_worker.py | 33 ++++++++++++++-- pkg/udf/python/worker/worker.py | 57 ++++++++++++++++++---------- 2 files changed, 65 insertions(+), 25 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 2e0e11ac03d39..f57d6dfefa548 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -873,7 +873,7 @@ def close(self): self.assertEqual("close failed", str(cleanup_error)) self.assertNotIn(key, server._active) self.assertIn(key, server._terminal) - self.assertNotIn(key[2], server._active_groups) + self.assertNotIn((key[0], key[2]), server._active_groups) finally: server.shutdown() @@ -3154,13 +3154,13 @@ def test_active_groups_reserve_future_closed_fences(self): first = (1, "statement", "reserved-first", 1, "first", 1) second = (1, "statement", "reserved-second", 1, "second", 1) first_state = server._admit(first) - self.assertIn(first[2], server._reserved_groups) + self.assertIn((first[0], first[2]), server._reserved_groups) with self.assertRaisesRegex(ValueError, "closed-group fence is full"): server._admit(second) server._finish_invocation(first, first_state) - self.assertNotIn(first[2], server._reserved_groups) - self.assertIn(first[2], server._closed_groups) + self.assertNotIn((first[0], first[2]), server._reserved_groups) + self.assertIn((first[0], first[2]), server._closed_groups) with self.assertRaisesRegex(ValueError, "already closed"): server._admit((1, "statement", first[2], 1, "late", 1)) finally: @@ -3177,6 +3177,31 @@ def test_active_group_rejects_a_second_member_before_handler_creation(self): finally: server._finish_invocation(first, first_state) + def test_group_fence_is_scoped_by_account(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + first = (1, "statement-a", "same-name", 1, "first", 1) + second = (2, "statement-b", "same-name", 1, "second", 1) + first_state = server._admit(first) + second_state = server._admit(second) + try: + self.assertIn((1, "same-name"), server._active_groups) + self.assertIn((2, "same-name"), server._active_groups) + server._finish_invocation(first, first_state) + self.assertIn(second, server._active) + self.assertIn((1, "same-name"), server._closed_groups) + self.assertNotIn((2, "same-name"), server._closed_groups) + finally: + server._finish_invocation(second, second_state) + + # Each account can advance its own epoch independently after the + # previous same-named group has closed. + self.assertIsNotNone( + server._admit((1, "statement-a-2", "same-name", 2, "third", 1)) + ) + self.assertIsNotNone( + server._admit((2, "statement-b-2", "same-name", 2, "fourth", 1)) + ) + def test_terminal_ack_requires_the_completed_fence(self): server = worker.RoutineFlightServer("grpc://127.0.0.1:0") key = (1, "statement", "group", 1, "completed", 1) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 19ea9aa2f318b..523b8a8171afc 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -2881,10 +2881,13 @@ def __init__( self._terminal: OrderedDict[tuple, _TerminalRecord] = OrderedDict() self._terminal_bytes = 0 self._active_bytes = 0 - self._active_groups: Dict[str, int] = {} - self._closed_groups: Dict[str, int] = {} + # A group id is scoped by the account in the fencing tuple. Keeping + # only the textual id here would let one tenant block or close a + # same-named group owned by another tenant. + self._active_groups: Dict[tuple, int] = {} + self._closed_groups: Dict[tuple, int] = {} self._closed_group_bytes = 0 - self._reserved_groups = set() + self._reserved_groups: set[tuple] = set() self._reserved_group_bytes = 0 self._clock = clock self._terminal_ttl_seconds = terminal_ttl_seconds @@ -2912,12 +2915,24 @@ def _entry_bytes(key: tuple) -> int: encoded = json.dumps(key, separators=(",", ":"), ensure_ascii=True).encode("utf-8") return len(encoded) + 128 + @staticmethod + def _group_key(key: tuple) -> tuple: + """Return the account-scoped identity of a group epoch.""" + return key[0], key[2] + + @staticmethod + def _group_fence_bytes(group_key: tuple) -> int: + # Account id is a fixed-width uint64 on the wire. Include it in the + # bounded fence estimate so the capacity accounting matches the + # account-scoped key rather than only charging the display id. + return len(group_key[1].encode("utf-8")) + 16 + def _purge_terminal_locked(self, now: float) -> None: expired = [ key for key, record in self._terminal.items() if record.expires_at <= now - and self._closed_groups.get(key[2], 0) >= key[3] + and self._closed_groups.get(self._group_key(key), 0) >= key[3] ] for key in expired: record = self._terminal.pop(key) @@ -2925,23 +2940,23 @@ def _purge_terminal_locked(self, now: float) -> None: def _admit(self, key: tuple) -> _InvocationState: size = self._entry_bytes(key) - group_id, group_epoch = key[2], key[3] + group_key, group_epoch = self._group_key(key), key[3] with self._lock: - if self._closed_groups.get(group_id, 0) >= group_epoch: + if self._closed_groups.get(group_key, 0) >= group_epoch: raise ValueError("PROTOCOL: execution group epoch is already closed") self._purge_terminal_locked(self._clock()) if key in self._active: raise ValueError("PROTOCOL: invocation fence is active") if key in self._terminal: raise ValueError("PROTOCOL: invocation fence is terminal") - if group_id in self._active_groups: + if group_key in self._active_groups: raise ValueError("PROTOCOL: execution group epoch is already active") if len(self._active) + len(self._terminal) >= MAX_LEDGER_ENTRIES: raise ValueError("RESOURCE_EXHAUSTED: terminal ledger entries are full") if self._active_bytes + self._terminal_bytes + size > MAX_LEDGER_BYTES: raise ValueError("RESOURCE_EXHAUSTED: terminal ledger bytes are full") - if group_id not in self._closed_groups and group_id not in self._reserved_groups: - fence_bytes = len(group_id.encode("utf-8")) + 8 + if group_key not in self._closed_groups and group_key not in self._reserved_groups: + fence_bytes = self._group_fence_bytes(group_key) if ( len(self._closed_groups) + len(self._reserved_groups) >= MAX_CLOSED_GROUP_ENTRIES @@ -2952,12 +2967,12 @@ def _admit(self, key: tuple) -> _InvocationState: # Reserve the future tombstone before creating the handler. # Terminal cleanup converts this reservation into the # closed-generation fence. - self._reserved_groups.add(group_id) + self._reserved_groups.add(group_key) self._reserved_group_bytes += fence_bytes state = _InvocationState({}, size) self._active[key] = state self._active_bytes += size - self._active_groups[group_id] = group_epoch + self._active_groups[group_key] = group_epoch return state def _require_current_lease(self, key: tuple) -> None: @@ -2976,14 +2991,14 @@ def _remember_terminal_locked(self, key: tuple, state: _InvocationState) -> None self._terminal_bytes += state.terminal_bytes def _close_group_epoch_locked(self, key: tuple) -> None: - group_id, group_epoch = key[2], key[3] - current = self._closed_groups.get(group_id, 0) + group_key, group_epoch = self._group_key(key), key[3] + current = self._closed_groups.get(group_key, 0) if group_epoch <= current: return - if group_id not in self._closed_groups: - fence_bytes = len(group_id.encode("utf-8")) + 8 - if group_id in self._reserved_groups: - self._reserved_groups.remove(group_id) + if group_key not in self._closed_groups: + fence_bytes = self._group_fence_bytes(group_key) + if group_key in self._reserved_groups: + self._reserved_groups.remove(group_key) self._reserved_group_bytes -= fence_bytes elif ( len(self._closed_groups) >= MAX_CLOSED_GROUP_ENTRIES @@ -2994,7 +3009,7 @@ def _close_group_epoch_locked(self, key: tuple) -> None: # and refuse collection until the fence is reconstructed. return self._closed_group_bytes += fence_bytes - self._closed_groups[group_id] = group_epoch + self._closed_groups[group_key] = group_epoch def _finish_invocation(self, key: tuple, state: Optional[_InvocationState]) -> None: # A rejected duplicate Open has no ownership of the existing state. @@ -3008,9 +3023,9 @@ def _finish_invocation(self, key: tuple, state: Optional[_InvocationState]) -> N return self._active.pop(key, None) self._active_bytes -= state.terminal_bytes - group_id, group_epoch = key[2], key[3] - if self._active_groups.get(group_id) == group_epoch: - self._active_groups.pop(group_id, None) + group_key, group_epoch = self._group_key(key), key[3] + if self._active_groups.get(group_key) == group_epoch: + self._active_groups.pop(group_key, None) # A started invocation is terminal even when the worker reports an # error. Retaining the fence prevents a late retry from running # user code a second time. From 83a14a2122f99a3e7f0eb454963eb256dc640ec1 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 10:26:16 +0800 Subject: [PATCH 102/241] fix(udf): scope gateway groups by account --- pkg/udf/python/gateway.go | 37 +++++++++++++++++------- pkg/udf/python/gateway_admission_test.go | 33 +++++++++++++++++++-- 2 files changed, 58 insertions(+), 12 deletions(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 4c113a0c807d9..6667a824e8c2a 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -17,6 +17,7 @@ import ( "errors" "fmt" "io" + "strconv" "strings" "sync" "time" @@ -716,6 +717,7 @@ type invocationAdmission struct { group *protocol.ExecutionGroup credit *protocol.LedgerCredit key string + groupKey string invocationID string mu sync.Mutex @@ -738,6 +740,7 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss if err != nil { return nil, err } + groupKey := scopedGroupKey(invocation.Tuple.AccountID, invocation.Tuple.GroupID) // g.mu -> admissionMu is the lifecycle lock order. Close uses the same // order so a concurrent shutdown cannot return while this invocation is // still being admitted. Keep g.mu held until the complete claim is either @@ -752,14 +755,14 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss ledger := g.ledger ttl := g.ledgerTTL active := g.active - if err := g.claimGroupLocked(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch); err != nil { + if err := g.claimGroupLocked(groupKey, invocation.Tuple.GroupEpoch); err != nil { g.admissionMu.Unlock() g.mu.Unlock() return nil, err } g.admissionMu.Unlock() if ledger == nil || active == nil { - g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() return nil, fmt.Errorf("python udf: admission state is not initialized") } @@ -770,15 +773,15 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss // that permits an expired tombstone to release its reserved capacity. ledger.Expire(time.Now(), g.epochClosed) entryBytes := int64(len(key)) - credit, err := ledger.Reserve(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch, 1, entryBytes) + credit, err := ledger.Reserve(groupKey, invocation.Tuple.GroupEpoch, 1, entryBytes) if err != nil { - g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() return nil, fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF terminal ledger: %w", err) } if err := credit.Add(key, entryBytes, time.Now().Add(ttl)); err != nil { credit.ReleaseUnused() - g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() return nil, err } @@ -790,7 +793,7 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss default: _ = ledger.Abandon(key) credit.ReleaseUnused() - g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() return nil, fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF active invocation slots are full") } @@ -808,7 +811,7 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss <-active _ = ledger.Abandon(key) credit.ReleaseUnused() - g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() return nil, err } @@ -816,14 +819,14 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss if err != nil { _ = group.Close(protocol.ReasonPartialOpenError) _ = ledger.Abandon(key) - g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() return nil, err } if err := token.Commit(); err != nil { _ = group.Close(protocol.ReasonPartialOpenError) _ = ledger.Abandon(key) - g.releaseGroupClaim(invocation.Tuple.GroupID, invocation.Tuple.GroupEpoch) + g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() return nil, err } @@ -833,6 +836,7 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss group: group, credit: credit, key: key, + groupKey: groupKey, invocationID: invocation.Tuple.InvocationID, memberOpen: true, }, nil @@ -947,6 +951,13 @@ func (g *Gateway) epochClosed(groupID string, groupEpoch uint64) bool { return ok && groupEpoch <= closedEpoch } +// scopedGroupKey is an internal ownership key. The wire protocol keeps the +// original group id, but group reservations and terminal fences are scoped by +// account because the tuple identity is {account_id, group_id, group_epoch}. +func scopedGroupKey(accountID uint64, groupID string) string { + return strconv.FormatUint(accountID, 10) + "\x00" + groupID +} + func invocationLedgerKey(tuple protocol.FencingTuple) (string, error) { wire, err := json.Marshal(tuple) if err != nil { @@ -1005,7 +1016,13 @@ func (a *invocationAdmission) finish(attempted bool, reason protocol.CloseReason errs = append(errs, err) } if a.group.State() == protocol.GroupReleased { - a.gateway.closeGroupEpoch(a.group.ID(), a.group.Epoch()) + groupKey := a.groupKey + if groupKey == "" { + // Keep manually constructed admission records safe for protocol + // tests; all production admissions set the account-scoped key. + groupKey = a.group.ID() + } + a.gateway.closeGroupEpoch(groupKey, a.group.Epoch()) } if err := errors.Join(errs...); err == nil { a.finished = true diff --git a/pkg/udf/python/gateway_admission_test.go b/pkg/udf/python/gateway_admission_test.go index 0288b0e3fd0ef..c29eb711f1423 100644 --- a/pkg/udf/python/gateway_admission_test.go +++ b/pkg/udf/python/gateway_admission_test.go @@ -159,7 +159,7 @@ func TestGatewayAdmissionRetriesOwnerCleanupAfterGroupReleaseFailure(t *testing. admission := &invocationAdmission{ gateway: gateway, group: group, credit: credit, - key: "release-retry-key", invocationID: "member", memberOpen: true, + key: "release-retry-key", groupKey: "release-retry", invocationID: "member", memberOpen: true, } require.ErrorContains(t, admission.finish(true, protocol.ReasonFailure), "injected group release failure") require.Equal(t, protocol.GroupDraining, group.State()) @@ -194,7 +194,7 @@ func TestGatewayAdmissionReservesClosedGroupCapacityWhileActive(t *testing.T) { gateway.admissionMu.Lock() require.Empty(t, gateway.admittedGroups) require.Zero(t, gateway.reservedGroupBytes) - require.Equal(t, uint64(1), gateway.closedGroups[first.Tuple.GroupID]) + require.Equal(t, uint64(1), gateway.closedGroups[scopedGroupKey(first.Tuple.AccountID, first.Tuple.GroupID)]) gateway.admissionMu.Unlock() // A new epoch of the same group reuses its already-reserved fence. A @@ -211,3 +211,32 @@ func TestGatewayAdmissionReservesClosedGroupCapacityWhileActive(t *testing.T) { _, err = gateway.admitInvocation(second) require.ErrorIs(t, err, protocol.ErrLedgerFull) } + +func TestGatewayAdmissionScopesGroupByAccount(t *testing.T) { + gateway := newAdmissionTestGateway(t, 2) + first := validInvocation() + first.Tuple.GroupID = "same-name" + first.Tuple.InvocationID = "account-one" + second := validInvocation() + second.Tuple.AccountID = 2 + second.Tuple.GroupID = first.Tuple.GroupID + second.Tuple.InvocationID = "account-two" + + firstAdmission, err := gateway.admitInvocation(first) + require.NoError(t, err) + secondAdmission, err := gateway.admitInvocation(second) + require.NoError(t, err) + require.Len(t, gateway.active, 2) + + require.NoError(t, firstAdmission.finish(true, protocol.ReasonInputEOF)) + require.Len(t, gateway.active, 1) + gateway.admissionMu.Lock() + require.Equal(t, uint64(1), gateway.closedGroups[scopedGroupKey(1, "same-name")]) + require.NotContains(t, gateway.closedGroups, scopedGroupKey(2, "same-name")) + gateway.admissionMu.Unlock() + + require.NoError(t, secondAdmission.finish(true, protocol.ReasonInputEOF)) + gateway.admissionMu.Lock() + require.Equal(t, uint64(1), gateway.closedGroups[scopedGroupKey(2, "same-name")]) + gateway.admissionMu.Unlock() +} From c3ab1fea91465f9c4eb858d69ba40e2f5b6d5dac Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 10:39:26 +0800 Subject: [PATCH 103/241] fix(udf): reject noncanonical descriptor fields --- pkg/udf/python/arrow.go | 11 +++++++---- pkg/udf/python/arrow_test.go | 14 ++++++++++++++ pkg/udf/python/worker/test_worker.py | 13 +++++++++++++ pkg/udf/python/worker/worker.py | 8 +++++--- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index c7615947b9692..0185f4ec768b5 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -203,21 +203,24 @@ func (d TypeDescriptor) Validate() error { return fmt.Errorf("TYPE_CONTRACT: decimal descriptor carries a charset") } case types.T_date: - if d.Scale != 0 || d.Charset != types.CharsetLegacy { - return fmt.Errorf("TYPE_CONTRACT: DATE descriptor has invalid scale or charset") + if d.Width != 0 || d.Scale != 0 || d.Charset != types.CharsetLegacy { + return fmt.Errorf("TYPE_CONTRACT: DATE descriptor has unused or invalid fields") } case types.T_time, types.T_datetime, types.T_timestamp: - if d.Scale > 6 || d.Charset != types.CharsetLegacy { + if d.Width != 0 || d.Scale > 6 || d.Charset != types.CharsetLegacy { return fmt.Errorf("TYPE_CONTRACT: temporal scale or charset is outside the supported range") } case types.T_char, types.T_varchar, types.T_text: + if d.Scale != 0 { + return fmt.Errorf("TYPE_CONTRACT: text descriptor carries an unused scale") + } switch d.Charset { case types.CharsetLegacy, types.CharsetUTF8MB4Bin, types.CharsetUTF8: default: return fmt.Errorf("TYPE_CONTRACT: unsupported text charset %d", d.Charset) } case types.T_binary, types.T_varbinary, types.T_blob: - if d.Charset != types.CharsetBinary { + if d.Scale != 0 || d.Charset != types.CharsetBinary { return fmt.Errorf("TYPE_CONTRACT: binary descriptor must use the binary charset") } case types.T_uuid: diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index c0fd830d93746..4b1b3de7c1400 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -656,6 +656,20 @@ func TestTypeDescriptorRejectsNonCanonicalDomain(t *testing.T) { } } +func TestTypeDescriptorRejectsUnusedDomainFields(t *testing.T) { + invalid := []TypeDescriptor{ + {TypeID: int32(types.T_date), Width: 1, OffsetWidth: 32, TemporalEncoding: "sql_zero_struct"}, + {TypeID: int32(types.T_datetime), Width: 1, OffsetWidth: 32, TemporalEncoding: "sql_zero_struct"}, + {TypeID: int32(types.T_time), Width: 1, Scale: 6, OffsetWidth: 32}, + {TypeID: int32(types.T_varchar), Width: 16, Scale: 1, Charset: types.CharsetUTF8, OffsetWidth: 32}, + {TypeID: int32(types.T_varbinary), Width: 16, Scale: 1, Charset: types.CharsetBinary, OffsetWidth: 32}, + } + for _, descriptor := range invalid { + _, err := descriptor.Field("value") + require.Error(t, err, "%+v", descriptor) + } +} + func TestFloatDescriptorsRoundTripThroughArrowFieldContract(t *testing.T) { for _, typ := range []types.T{types.T_float32, types.T_float64} { descriptor, err := NewTypeDescriptor(typ.ToType()) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index f57d6dfefa548..08d36d21f0706 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -835,6 +835,19 @@ def test_decimal_precision_and_vector_child_validity_are_checked(self): visible = valid.slice(1, 1) self.assertEqual(visible.to_pylist(), worker._output_array(visible, vector_descriptor, 1).to_pylist()) + def test_descriptor_rejects_unused_domain_fields(self): + invalid = [ + {"type_id": worker.DATE, "width": 1, "offset_width": 32, "temporal_encoding": "sql_zero_struct"}, + {"type_id": worker.DATETIME, "width": 1, "offset_width": 32, "temporal_encoding": "sql_zero_struct"}, + {"type_id": worker.TIME, "width": 1, "scale": 6, "offset_width": 32}, + {"type_id": worker.VARCHAR, "width": 16, "scale": 1, "charset": 3, "offset_width": 32}, + {"type_id": worker.VARBINARY, "width": 16, "scale": 1, "charset": 1, "offset_width": 32}, + ] + for descriptor in invalid: + with self.subTest(descriptor=descriptor): + with self.assertRaises(ValueError): + worker._field("value", descriptor) + def test_scalar_vector_null_keeps_fixed_size_child_slots(self): descriptor = {"type_id": worker.VECF32, "width": 2, "offset_width": 0} array = worker._output_array( diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 523b8a8171afc..e18aedb71f34c 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1192,16 +1192,18 @@ def _validate_descriptor_domain(descriptor: Dict[str, Any]) -> None: if charset: raise ValueError("TYPE_CONTRACT: decimal descriptor carries a charset") elif type_id == DATE: - if scale or charset: + if width or scale or charset: raise ValueError("TYPE_CONTRACT: DATE descriptor has invalid scale or charset") elif type_id in (TIME, DATETIME, TIMESTAMP): - if scale > 6 or charset: + if width or scale > 6 or charset: raise ValueError("TYPE_CONTRACT: temporal scale or charset is outside the supported range") elif type_id in (CHAR, VARCHAR, TEXT): + if scale: + raise ValueError("TYPE_CONTRACT: text descriptor carries an unused scale") if charset not in (0, 2, 3): raise ValueError("TYPE_CONTRACT: unsupported text charset") elif type_id in (BINARY, VARBINARY, BLOB): - if charset != 1: + if scale or charset != 1: raise ValueError("TYPE_CONTRACT: binary descriptor must use the binary charset") elif type_id == UUID: if width or scale or charset: From 6fc3b67450e213ab1f8487de44ac8ba10fe6cd91 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 10:42:18 +0800 Subject: [PATCH 104/241] fix(udf): bound worker fencing identities --- pkg/udf/python/worker/test_worker.py | 15 +++++++++++++++ pkg/udf/python/worker/worker.py | 9 ++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 08d36d21f0706..0e490d1069a74 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -848,6 +848,21 @@ def test_descriptor_rejects_unused_domain_fields(self): with self.assertRaises(ValueError): worker._field("value", descriptor) + def test_fencing_tuple_rejects_oversized_identity_components(self): + for field in ("statement_id", "group_id", "invocation_id"): + value = { + "account_id": 1, + "statement_id": "statement", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invocation", + "lease_epoch": 1, + } + value[field] = "x" * (worker.MAX_FENCE_COMPONENT_BYTES + 1) + with self.subTest(field=field): + with self.assertRaisesRegex(ValueError, "component is too large"): + worker._tuple_key(value) + def test_scalar_vector_null_keeps_fixed_size_child_slots(self): descriptor = {"type_id": worker.VECF32, "width": 2, "offset_width": 0} array = worker._output_array( diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index e18aedb71f34c..f3192b521a728 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -65,6 +65,11 @@ class _NoFlightServerBase: PROTOCOL_VERSION = 1 MAX_CONTROL_BYTES = 1 << 20 +# Keep the Python wire boundary identical to protocol.FencingTuple's +# component limit. The control frame limit alone is not sufficient: a +# single oversized identity would otherwise consume most of every ledger +# entry and would be accepted by the worker after Go rejected it. +MAX_FENCE_COMPONENT_BYTES = 256 # Admission bounds cover active fences and retained terminal tombstones. The # names deliberately describe the whole ledger so a future cleanup change # cannot mistake active work for reclaimable terminal state. @@ -707,7 +712,9 @@ def _tuple_key(value: Dict[str, Any]) -> tuple: raise ValueError("PROTOCOL: incomplete fencing tuple") try: for key in string_fields: - value[key].encode("utf-8") + encoded = value[key].encode("utf-8") + if len(encoded) > MAX_FENCE_COMPONENT_BYTES: + raise ValueError("PROTOCOL: fencing tuple component is too large") except UnicodeEncodeError as exc: raise ValueError("PROTOCOL: fencing tuple contains invalid UTF-8") from exc account_id = value.get("account_id") From 98b8417010057aeb8777f85c5532ee684aae666a Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 10:47:07 +0800 Subject: [PATCH 105/241] fix(udf): align Python security IDs with uint32 --- pkg/udf/python/worker/test_worker.py | 18 ++++++++++++++++++ pkg/udf/python/worker/worker.py | 12 +++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 0e490d1069a74..4b706eedf6be2 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -303,6 +303,24 @@ def test_typed_routine_semantics_reject_partial_or_definer_contract(self): with self.assertRaisesRegex(ValueError, "incomplete typed routine semantic contract"): worker._validate_typed_call_contract(payload) + def test_typed_routine_semantics_rejects_non_uint32_principal(self): + payload = { + "callsite_id": "python/1", + "may_error": True, + "security_mode": "INVOKER", + "leakproof": False, + "security_frame": { + "contract_version": 1, + "mode": "INVOKER", + "invoker_user_id": worker.MAX_SECURITY_PRINCIPAL_ID + 1, + "invoker_role_id": 8, + "effective_user_id": worker.MAX_SECURITY_PRINCIPAL_ID + 1, + "effective_role_id": 8, + }, + } + with self.assertRaisesRegex(ValueError, "invalid Python security frame"): + worker._validate_typed_call_contract(payload) + def test_handler_quota_uses_typed_effective_principal(self): payload = complete_open_payload( { diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index f3192b521a728..43c568e45fbda 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -70,6 +70,11 @@ class _NoFlightServerBase: # single oversized identity would otherwise consume most of every ledger # entry and would be accepted by the worker after Go rejected it. MAX_FENCE_COMPONENT_BYTES = 256 +# SecurityFrame uses uint32 principal identifiers in the language-neutral +# contract. Keep the Python decoder's acceptance domain identical to Go; +# checking only for a non-negative Python int would admit values that no Go +# caller can represent and would make quota/security identity non-canonical. +MAX_SECURITY_PRINCIPAL_ID = (1 << 32) - 1 # Admission bounds cover active fences and retained terminal tombstones. The # names deliberately describe the whole ledger so a future cleanup change # cannot mistake active work for reclaimable terminal state. @@ -608,7 +613,12 @@ def _validate_typed_call_contract(payload: Dict[str, Any]) -> None: if frame.get("contract_version") != 1 or frame.get("mode") != "INVOKER": raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported Python security frame") integer_fields = ("invoker_user_id", "invoker_role_id", "effective_user_id", "effective_role_id") - if any(type(frame.get(key)) is not int or frame[key] < 0 for key in integer_fields): + if any( + type(frame.get(key)) is not int + or frame[key] < 0 + or frame[key] > MAX_SECURITY_PRINCIPAL_ID + for key in integer_fields + ): raise ValueError("UNSUPPORTED_ROUTINE_VERSION: invalid Python security frame") if frame["invoker_user_id"] != frame["effective_user_id"] or frame["invoker_role_id"] != frame["effective_role_id"]: raise ValueError("UNSUPPORTED_ROUTINE_VERSION: Python security frame changed effective principal") From 7c1404f352bf15dda0e92672cff370219ca30e51 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 10:48:16 +0800 Subject: [PATCH 106/241] fix(udf): enforce required worker controls on encode --- pkg/udf/python/worker/test_worker.py | 25 +++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 5 ++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 4b706eedf6be2..d22d846ceb9e6 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -3471,6 +3471,31 @@ def test_control_encoder_rejects_nonstandard_json_numbers(self): } ) + def test_control_encoder_rejects_missing_required_fields(self): + tuple_value = { + "account_id": 1, + "statement_id": "statement", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invocation", + "lease_epoch": 1, + } + cases = ( + ("InputBatch", {}, "sequence"), + ("EndInput", {}, "last_sequence"), + ( + "Finish", + {"last_result_sequence": 0, "finish_id": "finish", "status": "OK"}, + "last_sequence", + ), + ("AcknowledgeFinish", {}, "finish_id"), + ) + for kind, fields, field in cases: + with self.assertRaisesRegex(ValueError, f"missing.*{field}"): + worker._encode_control( + {"kind": kind, "tuple": tuple_value, **fields} + ) + def test_control_rejects_unknown_fencing_tuple_fields(self): tuple_value = { "account_id": 0, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 43c568e45fbda..5d5fa16b56c59 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1120,7 +1120,10 @@ def _encode_control(value: Dict[str, Any]) -> bytes: raise ValueError("PROTOCOL: unsupported control field") value.setdefault("version", PROTOCOL_VERSION) _tuple_key(value["tuple"]) - _validate_control_fields(value, wire=False) + # The encoder is the last boundary before bytes leave the worker. It + # must enforce the same required fields as the decoder; otherwise a new + # producer can emit a frame that Go's MarshalControl would reject. + _validate_control_fields(value, wire=True) try: data = json.dumps( value, From 122e84d3e92943b29dad474e809aad4326ad7c4f Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 10:49:05 +0800 Subject: [PATCH 107/241] fix(udf): bound Python statement timestamps --- pkg/udf/python/worker/test_worker.py | 25 +++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 11 ++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index d22d846ceb9e6..2d5962e087d65 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -280,6 +280,31 @@ def test_typed_statement_context_accepts_unix_epoch(self): statement.statement_timestamp_utc, ) + def test_typed_statement_context_rejects_timestamp_outside_int64(self): + typed = { + "contract_version": 1, + "statement_timestamp_utc": worker.MAX_INT64 + 1, + "timezone_kind": "FIXED_OFFSET", + "timezone_offset_minutes": 0, + "sql_mode": [], + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + with self.assertRaisesRegex(ValueError, "invalid typed statement timestamp"): + worker._typed_statement_context(typed) + + with self.assertRaisesRegex(ValueError, "invalid statement_timestamp_utc"): + worker._statement_context( + { + "statement_timestamp_utc": str(worker.MIN_INT64 - 1), + "session_timezone_kind": "FIXED_OFFSET", + "session_timezone_offset_minutes": "0", + "sql_mode": "[]", + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + ) + def test_typed_routine_semantics_reject_partial_or_definer_contract(self): payload = { "callsite_id": "python/1", diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 5d5fa16b56c59..39ea4af0f851d 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -75,6 +75,8 @@ class _NoFlightServerBase: # checking only for a non-negative Python int would admit values that no Go # caller can represent and would make quota/security identity non-canonical. MAX_SECURITY_PRINCIPAL_ID = (1 << 32) - 1 +MIN_INT64 = -(1 << 63) +MAX_INT64 = (1 << 63) - 1 # Admission bounds cover active fences and retained terminal tombstones. The # names deliberately describe the whole ledger so a future cleanup change # cannot mistake active work for reclaimable terminal state. @@ -545,7 +547,12 @@ def _typed_statement_context(raw: Any) -> Optional[Dict[str, Any]]: if raw.get("contract_version") != 1: raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported statement context contract") timestamp = raw.get("statement_timestamp_utc") - if isinstance(timestamp, bool) or not isinstance(timestamp, int): + if ( + isinstance(timestamp, bool) + or not isinstance(timestamp, int) + or timestamp < MIN_INT64 + or timestamp > MAX_INT64 + ): raise ValueError("PROTOCOL: invalid typed statement timestamp") timezone_kind = raw.get("timezone_kind") if not isinstance(timezone_kind, str): @@ -658,6 +665,8 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: timestamp_text = _required_context_value(raw, "statement_timestamp_utc") try: timestamp_micros = int(timestamp_text, 10) + if timestamp_micros < MIN_INT64 or timestamp_micros > MAX_INT64: + raise ValueError("timestamp is outside int64 range") seconds, micros = divmod(timestamp_micros, 1_000_000) timestamp = _datetime.datetime(1970, 1, 1, tzinfo=_datetime.timezone.utc) + _datetime.timedelta(seconds=seconds, microseconds=micros) except (TypeError, ValueError, OverflowError) as exc: From 76f0cd4d1801fa3fe1ad43effe5b189f73b54cf4 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 10:50:09 +0800 Subject: [PATCH 108/241] fix(udf): bound Python descriptor integers --- pkg/udf/python/worker/test_worker.py | 17 +++++++++++++++++ pkg/udf/python/worker/worker.py | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 2d5962e087d65..9e0f18f44d217 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -707,6 +707,23 @@ def test_descriptor_domain_is_strict(self): with self.assertRaisesRegex(ValueError, "TYPE_CONTRACT"): worker._field("value", descriptor) + def test_descriptor_integer_fields_match_go_int32_wire_domain(self): + descriptor = { + "type_id": worker.VARCHAR, + "width": worker.MAX_INT32, + "offset_width": 32, + } + self.assertEqual(pa.string(), worker._field("value", descriptor).type) + for key in ("type_id", "width", "scale", "offset_width"): + invalid = dict(descriptor) + invalid[key] = worker.MAX_INT32 + 1 + if key == "scale": + invalid["type_id"] = worker.DECIMAL128 + invalid["width"] = 38 + with self.subTest(key=key): + with self.assertRaisesRegex(ValueError, "outside int32 range"): + worker._field("value", invalid) + def test_float_descriptors_round_trip_for_scalar_and_vector_contracts(self): for type_id, arrow_type in ( (worker.FLOAT32, pa.float32()), diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 39ea4af0f851d..f09e2b9242399 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -77,6 +77,8 @@ class _NoFlightServerBase: MAX_SECURITY_PRINCIPAL_ID = (1 << 32) - 1 MIN_INT64 = -(1 << 63) MAX_INT64 = (1 << 63) - 1 +MIN_INT32 = -(1 << 31) +MAX_INT32 = (1 << 31) - 1 # Admission bounds cover active fences and retained terminal tombstones. The # names deliberately describe the whole ledger so a future cleanup change # cannot mistake active work for reclaimable terminal state. @@ -1158,6 +1160,9 @@ def _canonical_descriptor(descriptor: Dict[str, Any]) -> bytes: for key in _DESCRIPTOR_INT_KEYS - {"type_id"}: if key in descriptor and type(descriptor[key]) is not int: raise ValueError(f"TYPE_CONTRACT: descriptor {key} must be an integer") + for key in _DESCRIPTOR_INT_KEYS: + if key in descriptor and not MIN_INT32 <= descriptor[key] <= MAX_INT32: + raise ValueError(f"TYPE_CONTRACT: descriptor {key} is outside int32 range") for key in _DESCRIPTOR_TEXT_KEYS: if key in descriptor and type(descriptor[key]) is not str: raise ValueError(f"TYPE_CONTRACT: descriptor {key} must be text") From dd8bcddcdb6b9cd0472dd71d788f36e0fad0f008 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 10:52:42 +0800 Subject: [PATCH 109/241] fix(udf): verify runtime result production --- pkg/container/vector/functionTools.go | 15 ++++++++ pkg/sql/colexec/external_routine_eval.go | 10 ++++++ pkg/sql/colexec/external_routine_eval_test.go | 36 +++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/pkg/container/vector/functionTools.go b/pkg/container/vector/functionTools.go index 8322860cac750..b99688964d05a 100644 --- a/pkg/container/vector/functionTools.go +++ b/pkg/container/vector/functionTools.go @@ -547,6 +547,11 @@ type FunctionResultWrapper interface { SetResultVector(vec *Vector) GetResultVector() *Vector + // ResultLength is the number of logical values produced through the + // FunctionResult append contract. For fixed-width results the vector is + // pre-sized before execution, so Vector.Length alone describes capacity, + // not whether the producer actually populated every row. + ResultLength() int Free() PreExtendAndReset(size int) error } @@ -808,6 +813,16 @@ func (fr *FunctionResult[T]) GetResultVector() *Vector { return fr.vec } +func (fr *FunctionResult[T]) ResultLength() int { + if fr == nil || fr.vec == nil { + return 0 + } + if fr.isVarlena { + return fr.vec.Length() + } + return int(fr.length) +} + func (fr *FunctionResult[T]) ConvertToStrParameter() FunctionParameterWrapper[types.Varlena] { return GenerateFunctionStrParameter(fr.vec) } diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index dffe882326fb3..3750676b26c63 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -337,6 +337,16 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch if err := proc.Base.UdfService.Execute(proc.Ctx, invocation, selectedResult, proc.Mp()); err != nil { return nil, err } + if selectedResult.ResultLength() != len(e.selectedRows) { + return nil, fmt.Errorf( + "python udf: runtime produced %d result rows, expected %d", + selectedResult.ResultLength(), + len(e.selectedRows), + ) + } + if selectedResult.GetResultVector() == nil { + return nil, fmt.Errorf("python udf: runtime returned no result vector") + } if len(e.selectedRows) == rowCount { return e.result.GetResultVector(), nil } diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index 42d36d1acbe72..ffeff3bc3b424 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -50,6 +50,14 @@ type externalRoutineCaptureRuntime struct { invocations []udf.Invocation } +type externalRoutineEmptySuccessRuntime struct{} + +func (r *externalRoutineEmptySuccessRuntime) Language() string { return udf.LanguagePython } + +func (r *externalRoutineEmptySuccessRuntime) Execute(_ context.Context, _ *udf.Invocation, _ vector.FunctionResultWrapper, _ *mpool.MPool) error { + return nil +} + func (r *externalRoutineCaptureRuntime) Language() string { return udf.LanguagePython } func (r *externalRoutineCaptureRuntime) Execute(_ context.Context, invocation *udf.Invocation, result vector.FunctionResultWrapper, mp *mpool.MPool) error { @@ -421,6 +429,34 @@ func TestExternalRoutineEvalRejectsSourceInExecutablePlan(t *testing.T) { require.ErrorContains(t, validateRoutineCall(call), "plan contains source") } +func TestExternalRoutineEvalRejectsSuccessfulRuntimeWithoutResultRows(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + proc.SetQueryId("missing-result-query") + proc.GetSessionInfo().TimeZone = time.UTC + proc.GetSessionInfo().User = "root" + proc.Base.StmtProfile = &process.StmtProfile{} + proc.GetStmtProfile().SetQueryStart(time.Date(2026, 9, 14, 0, 0, 0, 0, time.UTC)) + + input := vector.NewVec(types.T_int64.ToType()) + defer input.Free(proc.Mp()) + require.NoError(t, vector.AppendFixed(input, int64(10), false, proc.Mp())) + bat := batch.NewWithSize(0) + bat.SetRowCount(1) + proc.Base.UdfService = &externalRoutineEmptySuccessRuntime{} + evaluator, err := newExternalRoutineEval( + proc, + testExternalRoutineCall(t, python.ModeScalar, udf.NullCallHandler), + []ExpressionExecutor{&externalRoutineTestExecutor{vector: input}}, + nil, + ) + require.NoError(t, err) + defer evaluator.Free() + + _, err = evaluator.Eval(proc, []*batch.Batch{bat}, []bool{true}) + require.ErrorContains(t, err, "runtime produced 0 result rows, expected 1") +} + func TestExternalRoutineTransfersResultOwnership(t *testing.T) { for _, mode := range []string{"SCALAR", "VECTOR"} { t.Run(mode, func(t *testing.T) { From fb0c0db472edd1aeef0368a8de2afb8b75078612 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:01:11 +0800 Subject: [PATCH 110/241] fix(udf): reject boolean contract versions --- pkg/udf/python/worker/test_worker.py | 30 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 8 ++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 9e0f18f44d217..0539d521bfc10 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -305,6 +305,36 @@ def test_typed_statement_context_rejects_timestamp_outside_int64(self): } ) + def test_typed_contract_versions_require_integer_wire_values(self): + typed_context = { + "contract_version": True, + "statement_timestamp_utc": 0, + "timezone_kind": "FIXED_OFFSET", + "timezone_offset_minutes": 0, + "sql_mode": [], + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + with self.assertRaisesRegex(ValueError, "unsupported statement context contract"): + worker._typed_statement_context(typed_context) + + payload = { + "callsite_id": "python/1", + "may_error": True, + "security_mode": "INVOKER", + "leakproof": False, + "security_frame": { + "contract_version": True, + "mode": "INVOKER", + "invoker_user_id": 7, + "invoker_role_id": 8, + "effective_user_id": 7, + "effective_role_id": 8, + }, + } + with self.assertRaisesRegex(ValueError, "unsupported Python security frame"): + worker._validate_typed_call_contract(payload) + def test_typed_routine_semantics_reject_partial_or_definer_contract(self): payload = { "callsite_id": "python/1", diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index f09e2b9242399..eb076ce771dc6 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -546,7 +546,7 @@ def _typed_statement_context(raw: Any) -> Optional[Dict[str, Any]]: return None if not isinstance(raw, dict) or set(raw) - _TYPED_STATEMENT_CONTEXT_KEYS: raise ValueError("PROTOCOL: unsupported typed statement context field") - if raw.get("contract_version") != 1: + if type(raw.get("contract_version")) is not int or raw["contract_version"] != 1: raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported statement context contract") timestamp = raw.get("statement_timestamp_utc") if ( @@ -619,7 +619,11 @@ def _validate_typed_call_contract(payload: Dict[str, Any]) -> None: frame = payload.get("security_frame") if not isinstance(frame, dict) or set(frame) != _SECURITY_FRAME_KEYS: raise ValueError("UNSUPPORTED_ROUTINE_VERSION: incomplete Python security frame") - if frame.get("contract_version") != 1 or frame.get("mode") != "INVOKER": + if ( + type(frame.get("contract_version")) is not int + or frame["contract_version"] != 1 + or frame.get("mode") != "INVOKER" + ): raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported Python security frame") integer_fields = ("invoker_user_id", "invoker_role_id", "effective_user_id", "effective_role_id") if any( From bcb9bece3f0174cc6558ba1e4bae6865d3a8ef0b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:01:57 +0800 Subject: [PATCH 111/241] fix(udf): require canonical timezone kinds --- pkg/udf/python/worker/test_worker.py | 25 +++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 3 +-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 0539d521bfc10..839e365ac744e 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -280,6 +280,31 @@ def test_typed_statement_context_accepts_unix_epoch(self): statement.statement_timestamp_utc, ) + def test_statement_timezone_kind_requires_canonical_spelling(self): + typed = { + "contract_version": 1, + "statement_timestamp_utc": 0, + "timezone_kind": "fixed_offset", + "timezone_offset_minutes": 0, + "sql_mode": [], + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + with self.assertRaisesRegex(ValueError, "unsupported typed statement timezone"): + worker._typed_statement_context(typed) + + with self.assertRaisesRegex(ValueError, "unsupported timezone kind"): + worker._statement_context( + { + "statement_timestamp_utc": "0", + "session_timezone_kind": "fixed_offset", + "session_timezone_offset_minutes": "0", + "sql_mode": "[]", + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + ) + def test_typed_statement_context_rejects_timestamp_outside_int64(self): typed = { "contract_version": 1, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index eb076ce771dc6..89add9b9f8f4f 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -559,7 +559,6 @@ def _typed_statement_context(raw: Any) -> Optional[Dict[str, Any]]: timezone_kind = raw.get("timezone_kind") if not isinstance(timezone_kind, str): raise ValueError("PROTOCOL: typed statement timezone is missing") - timezone_kind = timezone_kind.upper() timezone_name = raw.get("timezone_name", "") tzdb_version = raw.get("timezone_database_version", "") offset = raw.get("timezone_offset_minutes", 0) @@ -678,7 +677,7 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: except (TypeError, ValueError, OverflowError) as exc: raise ValueError("PROTOCOL: invalid statement_timestamp_utc") from exc - timezone_kind = _required_context_value(raw, "session_timezone_kind").upper() + timezone_kind = _required_context_value(raw, "session_timezone_kind") if timezone_kind == "IANA": timezone_name = _required_context_value(raw, "session_timezone_name") tzdb_version = _required_context_value(raw, "session_timezone_tzdb_version") From 7f7e68bd054a9462b30e557f56bc6b02a61e880d Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:05:44 +0800 Subject: [PATCH 112/241] fix(udf): validate definition schema type --- pkg/udf/python/worker/test_worker.py | 12 ++++++++++++ pkg/udf/python/worker/worker.py | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 839e365ac744e..786bd93e994e3 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -201,6 +201,18 @@ def test_definition_validation_rejects_async_handler_before_catalog_state(self): finally: server.shutdown() + def test_definition_validation_rejects_boolean_schema_version(self): + payload = complete_definition_validation_payload() + payload["definition_schema_version"] = True + # A malformed sender could otherwise recompute its own malformed + # fingerprint and pass the later integrity check. The version domain + # must be rejected before that comparison. + payload["definition_fingerprint"] = worker._definition_fingerprint(payload) + with self.assertRaisesRegex(ValueError, "unsupported Python definition schema"): + worker._decode_definition_validation( + json.dumps(payload, separators=(",", ":")).encode() + ) + def test_definition_validation_rejects_handler_rebound_after_definition(self): payload = complete_definition_validation_payload( "def f(ctx, value): return value\n" diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 89add9b9f8f4f..a45244ec43a4d 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -897,7 +897,11 @@ def _decode_definition_validation(data: bytes) -> Dict[str, Any]: raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported Python ABI contract") if sdk_version != SDK_VERSION: raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported Python SDK") - if value.get("definition_schema_version") != DEFINITION_SCHEMA_VERSION: + definition_schema_version = value.get("definition_schema_version") + if ( + type(definition_schema_version) is not int + or definition_schema_version != DEFINITION_SCHEMA_VERSION + ): raise ValueError("UNSUPPORTED_ROUTINE_VERSION: unsupported Python definition schema") artifact_digest = _required_digest(value, "artifact_digest") environment_digest = _required_digest(value, "environment_digest") From 547ed18266258534616baeb3a3cec34cc0ef9554 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:09:00 +0800 Subject: [PATCH 113/241] fix(udf): cancel exchanges during worker shutdown --- pkg/udf/python/worker/test_worker.py | 89 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 34 +++++++++-- 2 files changed, 117 insertions(+), 6 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 786bd93e994e3..f6eefc2583107 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -570,6 +570,95 @@ def test_worker_rejects_a_tuple_from_another_instance(self): with self.assertRaisesRegex(ValueError, "invalid worker lease epoch"): worker.RoutineFlightServer("grpc://127.0.0.1:0", lease_epoch=0) + @unittest.skipUnless(os.name == "posix", "Flight shutdown cancellation test") + def test_flight_shutdown_cancels_an_active_exchange(self): + entered = threading.Event() + original_reader = worker._ExchangeInputReader + + class NotifyingReader(original_reader): + def __init__(self, reader): + entered.set() + super().__init__(reader) + + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + client = flight.FlightClient(("127.0.0.1", server.port)) + server_thread = threading.Thread(target=server.serve, daemon=True) + server_thread.start() + writer = None + shutdown_error = [] + descriptor = {"type_id": worker.INT64, "offset_width": 32} + payload = complete_open_payload( + { + "function_ref": { + "account_id": 1, + "database_id": 2, + "function_id": 3, + "revision": 1, + "namespace_version": 1, + }, + "source": "def f(ctx, x): return x", + "handler": "f", + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "abi_contract": worker.ABI_CONTRACT, + "adapter_version": worker.ADAPTER_VERSION, + "sdk_version": worker.SDK_VERSION, + "args": [descriptor], + "return": descriptor, + "max_batch_bytes": 1 << 20, + "max_batch_rows": 8, + "handler_timeout_seconds": 60, + } + ) + fence = { + "account_id": 1, + "statement_id": "shutdown", + "group_id": "shutdown-group", + "group_epoch": 1, + "invocation_id": "shutdown-invocation", + "lease_epoch": 1, + } + + def control(kind, **fields): + return worker._encode_control({"kind": kind, "tuple": fence, **fields}) + + try: + with mock.patch.object(worker, "_ExchangeInputReader", NotifyingReader): + writer, reader = client.do_exchange( + flight.FlightDescriptor.for_command( + control("OpenInvocation", payload=payload) + ), + options=flight.FlightCallOptions(timeout=5), + ) + self.assertTrue(entered.wait(2), "exchange did not reach its input reader") + + def shutdown(): + try: + server.shutdown() + except Exception as exc: + shutdown_error.append(exc) + + shutdown_thread = threading.Thread(target=shutdown) + shutdown_thread.start() + shutdown_thread.join(5) + self.assertFalse( + shutdown_thread.is_alive(), + "server shutdown waited for an active exchange", + ) + self.assertEqual([], shutdown_error) + self.assertFalse(server._active) + with server._pending_cleanup_condition: + self.assertFalse(server._pending_cleanups) + finally: + if writer is not None: + try: + writer.close() + except Exception: + pass + client.close() + if server_thread.is_alive(): + server_thread.join(2) + def test_inline_contract_rejects_external_handler_import(self): with self.assertRaisesRegex(ValueError, "immutable artifact catalog"): worker._load_handler("def add(ctx, value): return value", "module:add") diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index a45244ec43a4d..9e6665be88d37 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -2119,6 +2119,19 @@ def _context_is_cancelled(context) -> bool: return False +class _ExchangeContext: + """Combine the Flight cancellation state with server shutdown intent.""" + + __slots__ = ("_context", "_shutdown") + + def __init__(self, context, shutdown: threading.Event): + self._context = context + self._shutdown = shutdown + + def is_cancelled(self) -> bool: + return self._shutdown.is_set() or _context_is_cancelled(self._context) + + class _ExchangeInputReader: """Make a blocking Flight input read observable to cancellation. @@ -2949,6 +2962,11 @@ def __init__( self._pending_cleanups: Dict[tuple, _PendingInvocationCleanup] = {} self._pending_cleanup_thread: Optional[threading.Thread] = None self._pending_cleanup_stopping = False + # FlightServerBase.shutdown waits for active RPC methods to return. + # Set this before entering that wait so input readers, handler loops, + # and ACK waits have an independent cancellation source during a + # graceful worker shutdown. + self._shutdown_event = threading.Event() @staticmethod def _entry_bytes(key: tuple) -> int: @@ -3215,6 +3233,7 @@ def _pending_cleanup_loop(self) -> None: ) def shutdown(self): + self._shutdown_event.set() result = super().shutdown() with self._pending_cleanup_condition: self._pending_cleanup_stopping = True @@ -3375,12 +3394,15 @@ def _ack_control(control: Dict[str, Any]) -> Dict[str, Any]: return value def do_exchange(self, context, descriptor, reader, writer): + exchange_context = _ExchangeContext(context, self._shutdown_event) state = None key = None handler_session = None input_reader = None writer_started = False try: + if exchange_context.is_cancelled(): + raise TimeoutError("DEADLINE_EXCEEDED: Flight server is shutting down") command = getattr(descriptor, "command", None) if command is None: raise ValueError("PROTOCOL: exchange is missing the invocation descriptor") @@ -3475,14 +3497,14 @@ def do_exchange(self, context, descriptor, reader, writer): input_reader = _ExchangeInputReader(reader) while True: try: - chunk = input_reader.next(context) + chunk = input_reader.next(exchange_context) except StopIteration: break # The reader can publish a chunk at the same instant that the # RPC is cancelled. Re-check after the blocking handoff so a # chunk already dequeued after cancellation cannot start user # code or consume another handler slot. - if _context_is_cancelled(context): + if exchange_context.is_cancelled(): raise TimeoutError("DEADLINE_EXCEEDED: input stream cancelled") if chunk is None or (chunk.data is None and not chunk.app_metadata): raise ValueError("PROTOCOL: empty input frame") @@ -3543,7 +3565,7 @@ def do_exchange(self, context, descriptor, reader, writer): "input": _serialize_record_batch_message(batch), } output_wire = handler_session.run( - context, execution_request, handler_timeout_seconds + exchange_context, execution_request, handler_timeout_seconds ) output_batch = _deserialize_record_batch_message( output_wire, result_schema @@ -3575,7 +3597,7 @@ def do_exchange(self, context, descriptor, reader, writer): "released_batches": 1, })) writer.write_with_metadata(output_batch, _encode_control({"kind": "ResultBatch", "tuple": open_control["tuple"], "sequence": sequence})) - state.wait_result_ack(sequence, context) + state.wait_result_ack(sequence, exchange_context) if handler_session.should_rollover: handler_session.close() handler_session = None @@ -3607,9 +3629,9 @@ def do_exchange(self, context, descriptor, reader, writer): "last_sequence": last_input, "last_result_sequence": last_result, })) - state.wait_finish_ack(context) + state.wait_finish_ack(exchange_context) except Exception as exc: - if state is not None and _is_cancellation_error(exc, context): + if state is not None and _is_cancellation_error(exc, exchange_context): state.mark_cancelled() if writer_started and key is not None: try: From f29f580bfc5e758f35bc19e692864d811d3eb6e4 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:14:38 +0800 Subject: [PATCH 114/241] fix(udf): require canonical routine language --- pkg/sql/colexec/external_routine_eval.go | 2 +- pkg/sql/colexec/external_routine_eval_test.go | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index 3750676b26c63..f5274804d779a 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -95,7 +95,7 @@ func validateRoutineCall(call *planpb.RoutineCall) error { if call.ReturnType.Id == int32(types.T_any) { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no return descriptor") } - if call.ContractVersion != udf.PythonPlanContractVersion || !strings.EqualFold(call.Language, udf.LanguagePython) { + if call.ContractVersion != udf.PythonPlanContractVersion || call.Language != udf.LanguagePython { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported typed routine call contract") } if call.Volatility != "VOLATILE" { diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index ffeff3bc3b424..493d6e3b3e136 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -429,6 +429,12 @@ func TestExternalRoutineEvalRejectsSourceInExecutablePlan(t *testing.T) { require.ErrorContains(t, validateRoutineCall(call), "plan contains source") } +func TestExternalRoutineEvalRequiresCanonicalLanguage(t *testing.T) { + call := testExternalRoutineCall(t, python.ModeScalar, udf.NullCallHandler) + call.Language = "PYTHON" + require.ErrorContains(t, validateRoutineCall(call), "unsupported typed routine call contract") +} + func TestExternalRoutineEvalRejectsSuccessfulRuntimeWithoutResultRows(t *testing.T) { proc := testutil.NewProcess(t) defer proc.Free() From a962f5ce1dc714c11ea224471d0a9d031bc8c525 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:18:05 +0800 Subject: [PATCH 115/241] fix(udf): reject noncanonical plan languages --- pkg/frontend/routine_plan_validation.go | 4 ++-- pkg/frontend/routine_plan_validation_test.go | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/pkg/frontend/routine_plan_validation.go b/pkg/frontend/routine_plan_validation.go index 27101cefe3594..717f6cbc4b9fe 100644 --- a/pkg/frontend/routine_plan_validation.go +++ b/pkg/frontend/routine_plan_validation.go @@ -456,7 +456,7 @@ func validateRoutinePlanDependencyShape(dependency *planpb.RoutinePlanDependency if dependency.Volatility == "" || dependency.NullPolicy == "" || !dependency.MayError || dependency.Leakproof { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency semantic contract is incomplete") } - switch strings.ToLower(dependency.Language) { + switch dependency.Language { case udf.LanguagePython: if dependency.SecurityMode != "INVOKER" { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine plan dependency must use INVOKER security") @@ -506,7 +506,7 @@ func routinePlanDependenciesChanged( (dependency.Language == udf.LanguagePython && expectedSecurityMode != "INVOKER") || (dependency.Language == udf.LanguageSQL && expectedSecurityMode == "") || dependency.MayError != true || dependency.Leakproof || - !strings.EqualFold(state.language, dependency.Language) || + state.language != dependency.Language || state.fingerprint != dependency.DefinitionFingerprint || state.artifactDigest != dependency.ArtifactDigest || state.environmentDigest != dependency.EnvironmentDigest { diff --git a/pkg/frontend/routine_plan_validation_test.go b/pkg/frontend/routine_plan_validation_test.go index ab710f975f07b..e4e3e4441d857 100644 --- a/pkg/frontend/routine_plan_validation_test.go +++ b/pkg/frontend/routine_plan_validation_test.go @@ -152,6 +152,9 @@ func TestValidateRoutinePlanDependencyShapeRejectsCrossAccountAndUnknownContract {name: "missing identity", mutate: func(d *planpb.RoutinePlanDependency) { d.FunctionRef = nil }}, + {name: "noncanonical language", mutate: func(d *planpb.RoutinePlanDependency) { + d.Language = "PYTHON" + }}, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { @@ -164,6 +167,16 @@ func TestValidateRoutinePlanDependencyShapeRejectsCrossAccountAndUnknownContract } } +func TestRoutinePlanDependenciesChangedRequiresCanonicalLanguage(t *testing.T) { + dependency := testRoutinePlanDependency() + dependency.Language = "PYTHON" + + require.True(t, routinePlanDependenciesChanged( + []*planpb.RoutinePlanDependency{dependency}, + map[uint64]routinePlanCatalogState{41: testRoutinePlanState()}, + )) +} + func TestRoutinePlanDependenciesIncludesBackgroundQueries(t *testing.T) { dependency := testRoutinePlanDependency() plan := &planpb.Plan{ From 9f8fecb7117e88a02949da2f744890c6e3df7a1c Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:19:37 +0800 Subject: [PATCH 116/241] test(udf): inspect scoped gateway group fences --- pkg/udf/python/gateway_integration_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/udf/python/gateway_integration_test.go b/pkg/udf/python/gateway_integration_test.go index f50913691492b..0d26ddb95ca88 100644 --- a/pkg/udf/python/gateway_integration_test.go +++ b/pkg/udf/python/gateway_integration_test.go @@ -494,7 +494,7 @@ def add(ctx, value): gateway.admissionMu.Lock() require.Empty(t, gateway.admittedGroups) require.Empty(t, gateway.active) - closedEpoch := gateway.closedGroups[invocation.Tuple.GroupID] + closedEpoch := gateway.closedGroups[scopedGroupKey(invocation.Tuple.AccountID, invocation.Tuple.GroupID)] gateway.admissionMu.Unlock() require.Equal(t, uint64(1), closedEpoch) entries, _ := gateway.ledger.Counts() From d140440a510411a06fa3c357657d988a70d1d2e6 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:27:35 +0800 Subject: [PATCH 117/241] fix(udf): align gateway timeout with worker limit --- pkg/udf/python/config.go | 8 +++++++- pkg/udf/python/config_test.go | 11 +++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/config.go b/pkg/udf/python/config.go index a5de9d35dcefa..d1e1372d457d8 100644 --- a/pkg/udf/python/config.go +++ b/pkg/udf/python/config.go @@ -15,6 +15,12 @@ import ( "github.com/matrixorigin/matrixone/pkg/common/moerr" ) +// maxHandlerTimeout is part of the current Gateway/worker payload contract. +// The worker rejects a handler timeout above one hour; reject it while loading +// the CN configuration so an enabled runtime cannot appear healthy and then +// fail every invocation at the Flight boundary. +const maxHandlerTimeout = time.Hour + type Config struct { UUID string `toml:"uuid"` Address string `toml:"address"` @@ -89,7 +95,7 @@ func (c *ClientConfig) Validate() error { if c.MaxActiveInvocations < 0 || c.MaxActiveInvocations > 1<<20 { return moerr.NewInternalError(context.Background(), "invalid python udf max active invocations") } - if c.RequestTimeout < 0 { + if c.RequestTimeout < 0 || c.RequestTimeout > maxHandlerTimeout { return moerr.NewInternalError(context.Background(), "invalid python udf request timeout") } if c.MaxTerminalEntries < 0 || c.MaxTerminalEntries > 1<<30 { diff --git a/pkg/udf/python/config_test.go b/pkg/udf/python/config_test.go index 29034df2000e8..88be8ee0ca663 100644 --- a/pkg/udf/python/config_test.go +++ b/pkg/udf/python/config_test.go @@ -48,3 +48,14 @@ func TestClientConfigRejectsInvalidInvocationBudgets(t *testing.T) { config.MaxInvocationResultBytes = -1 require.ErrorContains(t, config.Validate(), "max invocation result bytes") } + +func TestClientConfigMatchesWorkerHandlerTimeoutContract(t *testing.T) { + config := &ClientConfig{ + Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:50051", + RequestTimeout: maxHandlerTimeout, + } + require.NoError(t, config.Validate()) + + config.RequestTimeout = maxHandlerTimeout + time.Nanosecond + require.ErrorContains(t, config.Validate(), "request timeout") +} From a3de0977bd59abf5c31dce5965d8cf5f574253a9 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:28:53 +0800 Subject: [PATCH 118/241] fix(udf): preserve large JSON number tokens --- pkg/udf/python/worker/test_worker.py | 3 ++- pkg/udf/python/worker/worker.py | 13 ++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index f6eefc2583107..f0082c189185f 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1007,7 +1007,8 @@ def test_json_canonical_text_preserves_number_and_string_tokens(self): def test_json_rejects_nonstandard_numbers(self): descriptor = {"type_id": worker.JSON, "offset_width": 32, "json_encoding": "canonical_text"} - for value in ("NaN", "Infinity", "-Infinity", "1e9999"): + self.assertEqual("1e9999", worker._canonical_json_text("1e9999")) + for value in ("NaN", "Infinity", "-Infinity"): with self.assertRaisesRegex(ValueError, "invalid JSON"): worker._canonical_json_text(value) with self.assertRaisesRegex(ValueError, "JSON result"): diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 9e6665be88d37..4acd357286cf8 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1458,17 +1458,16 @@ def _canonical_json_text(value: str) -> str: def reject_nonstandard_number(_constant: str): raise ValueError("non-standard JSON number") - def reject_nonfinite_float(number: str): - parsed = float(number) - if not math.isfinite(parsed): - raise ValueError("non-finite JSON number") - return parsed - try: json.loads( value, parse_constant=reject_nonstandard_number, - parse_float=reject_nonfinite_float, + # JSON values cross the ABI as compact text. Parsing numbers as + # strings keeps validation independent of Python's binary-float + # range; Go's json.Compact accepts valid tokens such as 1e999 and + # the handler must observe that exact token unchanged. + parse_int=str, + parse_float=str, ) except Exception as exc: raise ValueError("TYPE_CONTRACT: invalid JSON input") from exc From 9aa3a1c25f6cd343d604cc6cf134a3f249ee0832 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:30:46 +0800 Subject: [PATCH 119/241] fix(udf): reject noncanonical routine language at bind --- pkg/sql/plan/function/udf.go | 6 +++--- pkg/sql/plan/function/udf_test.go | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index f8702f89245a6..4816812125009 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -304,10 +304,10 @@ func (u *Udf) GetRoutineCall() (*plan.RoutineCall, error) { if u == nil { return nil, fmt.Errorf("routine call requires a non-nil routine") } - if strings.EqualFold(u.Language, udf.LanguageSQL) { + if u.Language == udf.LanguageSQL { return u.getSQLRoutineCall() } - if !strings.EqualFold(u.Language, udf.LanguagePython) { + if u.Language != udf.LanguagePython { return nil, fmt.Errorf("routine call has unsupported language %q", u.Language) } if u.FunctionID <= 0 || u.DatabaseID == 0 || u.Revision == 0 || u.NamespaceVersion == 0 { @@ -343,7 +343,7 @@ func (u *Udf) GetRoutineCall() (*plan.RoutineCall, error) { AccountId: u.AccountID, DatabaseId: u.DatabaseID, }, - Language: strings.ToLower(u.Language), + Language: udf.LanguagePython, ArgumentTypes: arguments, ReturnType: *returnType, Volatility: "VOLATILE", diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go index 36d90a1b3057c..93ada8b5ebd10 100644 --- a/pkg/sql/plan/function/udf_test.go +++ b/pkg/sql/plan/function/udf_test.go @@ -338,6 +338,12 @@ func TestPythonRoutineCallCarriesExactCatalogContract(t *testing.T) { require.NotEmpty(t, call.GetPython().DefinitionFingerprint) } +func TestPythonRoutineCallRejectsNoncanonicalLanguage(t *testing.T) { + routine := &Udf{Language: "PYTHON"} + _, err := routine.GetRoutineCall() + require.ErrorContains(t, err, `routine call has unsupported language "PYTHON"`) +} + func TestSQLRoutineFingerprintAndCallUseSharedRevisionContract(t *testing.T) { fingerprint, err := SQLRoutineFingerprint("select value + 1", "[\"bigint\"]", "bigint") require.NoError(t, err) From 5b055cedc596374bd5519921abbbcba0ae60e099 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:32:07 +0800 Subject: [PATCH 120/241] fix(udf): enforce Arrow field nullability --- pkg/udf/python/worker/test_worker.py | 6 ++++++ pkg/udf/python/worker/worker.py | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index f0082c189185f..d9d2772caf2ba 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -813,6 +813,12 @@ def test_metadata_is_owned_by_adapter(self): worker._validate_field(with_extra, "result", descriptor) with self.assertRaisesRegex(ValueError, "field name"): worker._validate_field(pa.field("other", field.type, metadata=field.metadata), "result", descriptor) + with self.assertRaisesRegex(ValueError, "nullable"): + worker._validate_field( + pa.field("result", field.type, nullable=False, metadata=field.metadata), + "result", + descriptor, + ) def test_type_descriptor_shape_is_strict(self): with self.assertRaisesRegex(ValueError, "unsupported descriptor field"): diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 4acd357286cf8..21acd5c277270 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1353,6 +1353,10 @@ def _validate_field(field: pa.Field, name: str, descriptor: Dict[str, Any]) -> N raise ValueError(f"TYPE_CONTRACT: Arrow field name {field.name!r} does not match {name!r}") if field.type != expected.type: raise ValueError(f"TYPE_CONTRACT: Arrow type {field.type} does not match {expected.type}") + if field.nullable != expected.nullable: + raise ValueError( + f"TYPE_CONTRACT: Arrow field nullable={field.nullable} does not match {expected.nullable}" + ) if field.metadata != expected.metadata: raise ValueError("TYPE_CONTRACT: Arrow logical metadata does not match the frozen descriptor") From f9d1639f2afe11e4fa363d4171b509f0c7775eef Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:35:52 +0800 Subject: [PATCH 121/241] fix(udf): require object invocation payload --- pkg/udf/protocol/protocol.go | 6 ++++++ pkg/udf/protocol/protocol_test.go | 13 +++++++++++++ pkg/udf/python/worker/test_worker.py | 21 +++++++++++++++++++++ pkg/udf/python/worker/worker.py | 9 +++++---- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index f06920c8461d8..1d9b4113d13f2 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -201,6 +201,12 @@ func validateControlFields(control Control, wire map[string]json.RawMessage) err if len(control.Payload) == 0 && wire == nil { return fmt.Errorf("%w: control kind %q is missing field %q", ErrProtocol, control.Kind, "payload") } + if len(control.Payload) != 0 { + var payload map[string]json.RawMessage + if err := json.Unmarshal(control.Payload, &payload); err != nil || payload == nil { + return fmt.Errorf("%w: control kind %q payload must be a JSON object", ErrProtocol, control.Kind) + } + } case "InputBatch", "ResultBatch": if control.Sequence == 0 { return fmt.Errorf("%w: control kind %q requires a positive sequence", ErrProtocol, control.Kind) diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index 1eeee14913a0f..f03e04e608556 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -70,6 +70,19 @@ func TestControlRejectsDuplicateJSONFields(t *testing.T) { require.ErrorContains(t, err, "duplicate control JSON field") } +func TestOpenInvocationPayloadMustBeObject(t *testing.T) { + for _, payload := range []string{"null", "[]", `"text"`} { + wire := []byte(`{"version":1,"kind":"OpenInvocation","tuple":{"account_id":1,"statement_id":"statement","group_id":"group","group_epoch":2,"invocation_id":"invocation","lease_epoch":3},"payload":` + payload + `}`) + _, err := UnmarshalControl(wire) + require.ErrorIs(t, err, ErrProtocol) + require.ErrorContains(t, err, "payload must be a JSON object") + + _, err = MarshalControl(Control{Kind: "OpenInvocation", Tuple: testTuple(), Payload: json.RawMessage(payload)}) + require.ErrorIs(t, err, ErrProtocol) + require.ErrorContains(t, err, "payload must be a JSON object") + } +} + func TestControlFieldsBelongToTheirKind(t *testing.T) { wire, err := MarshalControl(Control{Kind: "InputBatch", Tuple: testTuple(), Sequence: 1}) require.NoError(t, err) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index d9d2772caf2ba..870ce18b480f8 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -3657,6 +3657,27 @@ def test_control_fields_belong_to_their_kind(self): ).encode() ) + def test_open_invocation_payload_must_be_object(self): + tuple_value = { + "account_id": 1, + "statement_id": "statement", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invocation", + "lease_epoch": 1, + } + for payload in (None, [], "text"): + value = { + "version": worker.PROTOCOL_VERSION, + "kind": "OpenInvocation", + "tuple": tuple_value, + "payload": payload, + } + with self.assertRaisesRegex(ValueError, "payload must be an object"): + worker._decode_control(json.dumps(value).encode()) + with self.assertRaisesRegex(ValueError, "payload must be an object"): + worker._encode_control(value) + def test_control_encoder_rejects_nonstandard_json_numbers(self): tuple_value = { "account_id": 1, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 21acd5c277270..bebf9082fcefb 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1126,10 +1126,11 @@ def _validate_control_fields(value: Dict[str, Any], wire: bool) -> None: if kind == "Ack": if ("ack_sequence" in value) == ("finish_id" in value): raise ValueError("PROTOCOL: Ack requires exactly one acknowledgement identity") - elif kind == "OpenInvocation" and ( - "payload" not in value or (wire and value["payload"] is None) - ): - raise ValueError("PROTOCOL: control kind 'OpenInvocation' is missing field 'payload'") + elif kind == "OpenInvocation": + if "payload" not in value: + raise ValueError("PROTOCOL: control kind 'OpenInvocation' is missing field 'payload'") + if not isinstance(value["payload"], dict): + raise ValueError("PROTOCOL: control kind 'OpenInvocation' payload must be an object") def _encode_control(value: Dict[str, Any]) -> bytes: From 4b15721d3cb6e06e3754d8322443b0cb2e17cc80 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:37:16 +0800 Subject: [PATCH 122/241] fix(udf): reject cancelled worker actions --- pkg/udf/python/worker/test_worker.py | 28 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 12 ++++++++++++ 2 files changed, 40 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 870ce18b480f8..f850a1b8f4c7f 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -3572,6 +3572,34 @@ def test_cancelled_terminal_is_frozen_and_rejects_late_ack(self): next(server.do_action(None, action)) self.assertEqual(worker._TERMINAL_CANCELLED, server._terminal[key].outcome) + def test_cancelled_or_shutdown_action_cannot_ack_active_invocation(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + key = (1, "statement", "action-cancel", 1, "active", 1) + state = server._admit(key) + state.mark_finish_sent("finish-active") + tuple_value = { + "account_id": key[0], "statement_id": key[1], "group_id": key[2], + "group_epoch": key[3], "invocation_id": key[4], "lease_epoch": key[5], + } + action = types.SimpleNamespace( + type="AcknowledgeFinish", + body=worker._encode_control({ + "kind": "AcknowledgeFinish", "tuple": tuple_value, + "finish_id": "finish-active", + }), + ) + cancelled_context = types.SimpleNamespace(is_cancelled=lambda: True) + with self.assertRaisesRegex(TimeoutError, "DEADLINE_EXCEEDED"): + next(server.do_action(cancelled_context, action)) + self.assertFalse(state.finish_acked) + + server._shutdown_event.set() + with self.assertRaisesRegex(TimeoutError, "DEADLINE_EXCEEDED"): + next(server.do_action(None, action)) + self.assertFalse(state.finish_acked) + state.mark_cancelled() + server._finish_invocation(key, state) + def test_active_fence_cannot_be_admitted_twice(self): server = worker.RoutineFlightServer("grpc://127.0.0.1:0") key = (1, "statement", "group", 1, "invocation", 1) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index bebf9082fcefb..ac3d5d8eae6ab 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -3328,6 +3328,7 @@ def close_with_retry(resource) -> tuple[bool, Optional[Exception]]: return cleanup_error def do_action(self, context, action): + self._ensure_action_active(context) if action.type == "GetPythonCapabilities": request = _decode_capability_request(action.body) # pyarrow exposes Result as a one positional-buffer value across @@ -3363,6 +3364,13 @@ def do_action(self, context, action): self._purge_terminal_locked(self._clock()) state = self._active.get(key) terminal = self._terminal.get(key) + # A cancelled action must not advance an active invocation. This is + # checked again after decoding and ledger lookup because an action can + # be queued while its Flight context or the worker is being closed. + # If cancellation races this check, the state mutation is the action + # acceptance point; the caller may then safely retry the idempotent + # acknowledgement when its parent context is still alive. + self._ensure_action_active(context) if state is None: if terminal is None: raise ValueError("PROTOCOL: unknown invocation") @@ -3388,6 +3396,10 @@ def do_action(self, context, action): state.ack_finish(_required_string(control, "finish_id")) yield _encode_control(self._ack_control(control)) + def _ensure_action_active(self, context) -> None: + if self._shutdown_event.is_set() or _context_is_cancelled(context): + raise TimeoutError("DEADLINE_EXCEEDED: Flight action is cancelled") + @staticmethod def _ack_control(control: Dict[str, Any]) -> Dict[str, Any]: value = {"kind": "Ack", "tuple": control["tuple"], "status": "OK"} From 3a8c191640247efd9473030d3da1d01bb22bcab6 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:41:23 +0800 Subject: [PATCH 123/241] fix(udf): reject noncanonical catalog languages --- pkg/frontend/compiler_context.go | 10 +++++----- pkg/frontend/routine_plan_validation.go | 8 ++++---- pkg/frontend/routine_plan_validation_test.go | 6 ++++++ pkg/frontend/snapshot_catalog_restore.go | 8 ++++---- pkg/sql/plan/function/udf.go | 19 ++++++++++++++----- pkg/sql/plan/function/udf_test.go | 7 +++++++ pkg/sql/plan/routine_dependency.go | 9 ++++++++- pkg/sql/plan/routine_dependency_test.go | 8 ++++++++ 8 files changed, 56 insertions(+), 19 deletions(-) diff --git a/pkg/frontend/compiler_context.go b/pkg/frontend/compiler_context.go index 4842af33231a2..80729831ccf07 100644 --- a/pkg/frontend/compiler_context.go +++ b/pkg/frontend/compiler_context.go @@ -1007,7 +1007,7 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex } udf.SQLMode = &mode udf.FunctionID = functionID - if strings.EqualFold(udf.Language, string(tree.PYTHON)) { + if udf.Language == string(tree.PYTHON) { revision, revisionErr := readPythonRevision(queryCtx, bh, functionID, tcc.GetSnapshot()) if revisionErr != nil { return nil, revisionErr @@ -1018,7 +1018,7 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex udf.RetType = revision.RetType udf.Revision = revision.Revision udf.NamespaceVersion = revision.NamespaceVersion - } else if strings.EqualFold(udf.Language, string(tree.SQL)) { + } else if udf.Language == string(tree.SQL) { revision, found, revisionErr := readSQLRevision(queryCtx, bh, functionID, tcc.GetSnapshot()) if revisionErr != nil { return nil, revisionErr @@ -1058,7 +1058,7 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex toList := make([]types.T, len(args)) pythonTargetTypes := make([]types.Type, 0) - if strings.EqualFold(udf.Language, string(tree.PYTHON)) { + if udf.Language == string(tree.PYTHON) { pythonTargetTypes = udf.GetArgsType() } for j := range argList { @@ -1359,7 +1359,7 @@ func readSQLRevision( return sqlRevisionCatalogRow{}, false, err } if revisionValue <= 0 || uint64(revisionValue) != uint64(activeRevision) || - !strings.EqualFold(language, string(tree.SQL)) || + language != string(tree.SQL) || definitionSchema != udf.SQLDefinitionSchemaVersion || volatility != "VOLATILE" || nullPolicy != udf.NullCallHandler || !strings.EqualFold(securityType, "DEFINER") || @@ -1492,7 +1492,7 @@ func readPythonRevision(ctx context.Context, bh BackgroundExec, functionID int64 if err != nil { return pythonRevisionCatalogRow{}, err } - if !strings.EqualFold(language, string(tree.PYTHON)) || definitionSchema != udf.PythonDefinitionSchemaVersion || abi != udf.PythonABIContract || adapter != udf.PythonAdapterVersion || sdk != udf.PythonSDKVersion || volatility != "VOLATILE" || !strings.EqualFold(securityType, "INVOKER") || !strings.EqualFold(baseSecurityType, securityType) { + if language != string(tree.PYTHON) || definitionSchema != udf.PythonDefinitionSchemaVersion || abi != udf.PythonABIContract || adapter != udf.PythonAdapterVersion || sdk != udf.PythonSDKVersion || volatility != "VOLATILE" || !strings.EqualFold(securityType, "INVOKER") || !strings.EqualFold(baseSecurityType, securityType) { return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision contract is not supported", functionID) } bodyDefinition, err := function.DecodePythonRoutineBody(body) diff --git a/pkg/frontend/routine_plan_validation.go b/pkg/frontend/routine_plan_validation.go index 717f6cbc4b9fe..49979f0ca00ef 100644 --- a/pkg/frontend/routine_plan_validation.go +++ b/pkg/frontend/routine_plan_validation.go @@ -313,10 +313,10 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan if !strings.EqualFold(revisionSecurityType, baseSecurityType) { return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine %d has inconsistent revision and identity security contracts", id) } - if strings.EqualFold(language, udf.LanguagePython) && !strings.EqualFold(revisionSecurityType, "INVOKER") { + if language == udf.LanguagePython && !strings.EqualFold(revisionSecurityType, "INVOKER") { return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine catalog security type is not INVOKER") } - if strings.EqualFold(language, udf.LanguageSQL) && !strings.EqualFold(revisionSecurityType, "DEFINER") { + if language == udf.LanguageSQL && !strings.EqualFold(revisionSecurityType, "DEFINER") { return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL routine catalog security type is not DEFINER") } identityValid := routinePlanCatalogIdentityValidForLanguage( @@ -372,7 +372,7 @@ func routinePlanCatalogIdentityValidForLanguage( definitionSchema int64, revisionABI, revisionAdapter, revisionSDK, revisionNullPolicy string, ) bool { - if strings.EqualFold(language, udf.LanguageSQL) { + if language == udf.LanguageSQL { expectedFingerprint, err := function.SQLRoutineFingerprint(rawBody, revisionArgTypes, revisionRetType) return err == nil && fingerprint == expectedFingerprint && @@ -380,7 +380,7 @@ func routinePlanCatalogIdentityValidForLanguage( revisionABI == "" && revisionAdapter == "" && revisionSDK == "" && revisionNullPolicy == udf.NullCallHandler } - if !strings.EqualFold(language, udf.LanguagePython) { + if language != udf.LanguagePython { return false } decoded, err := function.DecodePythonRoutineBody(rawBody) diff --git a/pkg/frontend/routine_plan_validation_test.go b/pkg/frontend/routine_plan_validation_test.go index e4e3e4441d857..bcc9cdc1c6c22 100644 --- a/pkg/frontend/routine_plan_validation_test.go +++ b/pkg/frontend/routine_plan_validation_test.go @@ -314,6 +314,12 @@ func TestRoutinePlanCatalogIdentityAcceptsAndRejectsSQLRevision(t *testing.T) { "lua", body, fingerprint, 0, "", "", "", argTypes, retType, udf.SQLDefinitionSchemaVersion, "", "", "", udf.NullCallHandler, )) + require.False(t, routinePlanCatalogIdentityValidForLanguage( + "PYTHON", body, fingerprint, udf.PythonSignatureKeySchemaVersion, + "", "", "", argTypes, retType, udf.PythonDefinitionSchemaVersion, + udf.PythonABIContract, udf.PythonAdapterVersion, udf.PythonSDKVersion, + udf.NullCallHandler, + )) } func TestRoutinePlanDependenciesVisitsSharedQueriesOnce(t *testing.T) { diff --git a/pkg/frontend/snapshot_catalog_restore.go b/pkg/frontend/snapshot_catalog_restore.go index 145fb0187623b..9e7b60658fd62 100644 --- a/pkg/frontend/snapshot_catalog_restore.go +++ b/pkg/frontend/snapshot_catalog_restore.go @@ -209,13 +209,13 @@ func validateRestoredFunctionRevisionCatalog( if err != nil { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored function %d revision %d has an invalid definition schema", functionID, revision) } - if strings.EqualFold(row[8], udf.LanguageSQL) { + if row[8] == udf.LanguageSQL { if err := validateRestoredSQLFunctionRevision(functionID, revision, row, definitionSchema); err != nil { return err } continue } - if !strings.EqualFold(row[8], udf.LanguagePython) || + if row[8] != udf.LanguagePython || definitionSchema != udf.PythonDefinitionSchemaVersion || row[10] != udf.PythonABIContract || row[11] != udf.PythonAdapterVersion || @@ -519,7 +519,7 @@ func publishRestoredPythonArtifacts( if len(row) != 3 { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored revision row %d has %d artifact columns", rowIndex, len(row)) } - if strings.EqualFold(row[0], udf.LanguagePython) { + if row[0] == udf.LanguagePython { needStore = true break } @@ -536,7 +536,7 @@ func publishRestoredPythonArtifacts( return err } for rowIndex, row := range rows { - if !strings.EqualFold(row[0], udf.LanguagePython) { + if row[0] != udf.LanguagePython { continue } body, decodeErr := function.DecodePythonRoutineBody(row[2]) diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index 4816812125009..7a79b9d41476a 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -425,7 +425,7 @@ func (u *Udf) GetArgsPlanType() []*plan.Type { } func (u *Udf) GetRetPlanType() *plan.Type { return type2PlanType(u.GetRetType()) } func (u *Udf) GetArgsType() []types.Type { - if strings.EqualFold(u.Language, "python") { + if u.Language == udf.LanguagePython { // Resolver-created routines always set PythonReturnType when the // canonical descriptor has been loaded. Keeping the fallback makes // the generic Udf value usable by planner tests and by the SQL-side @@ -443,7 +443,7 @@ func (u *Udf) GetArgsType() []types.Type { return u.ArgsType } func (u *Udf) GetRetType() types.Type { - if strings.EqualFold(u.Language, "python") { + if u.Language == udf.LanguagePython { if u.PythonReturnType == nil { return types.Types[u.RetType].ToType() } @@ -457,9 +457,12 @@ func (u *Udf) GetRetType() types.Type { // rejected instead of being reinterpreted through the legacy logical-type // columns. func (u *Udf) LoadPythonTypeContract() error { - if !strings.EqualFold(u.Language, "python") { + if u == nil || u.Language == udf.LanguageSQL { return nil } + if u.Language != udf.LanguagePython { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) + } u.PythonArgTypes = nil u.PythonReturnType = nil body, err := DecodePythonRoutineBody(u.Body) @@ -477,9 +480,12 @@ func (u *Udf) LoadPythonTypeContract() error { // before that decode during lookup, so this second check closes the only point // where an argument list and its exact ABI could otherwise diverge. func (u *Udf) ValidatePythonTypeContract() error { - if !strings.EqualFold(u.Language, "python") { + if u == nil || u.Language == udf.LanguageSQL { return nil } + if u.Language != udf.LanguagePython { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) + } if u.PythonReturnType == nil { return fmt.Errorf("python routine is missing return descriptor") } @@ -501,9 +507,12 @@ func (u *Udf) ValidatePythonTypeContract() error { // they still must agree on the logical OID or a damaged catalog row could be // selected by overload resolution and dispatched with a different ABI. func (u *Udf) ValidatePythonCatalogSignature() error { - if u == nil || !strings.EqualFold(u.Language, "python") { + if u == nil || u.Language == udf.LanguageSQL { return nil } + if u.Language != udf.LanguagePython { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) + } if len(u.Args) != len(u.PythonArgTypes) || u.PythonReturnType == nil { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python catalog signature is incomplete") } diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go index 93ada8b5ebd10..6015e1a3fd12d 100644 --- a/pkg/sql/plan/function/udf_test.go +++ b/pkg/sql/plan/function/udf_test.go @@ -344,6 +344,13 @@ func TestPythonRoutineCallRejectsNoncanonicalLanguage(t *testing.T) { require.ErrorContains(t, err, `routine call has unsupported language "PYTHON"`) } +func TestPythonContractPreflightRejectsNoncanonicalLanguage(t *testing.T) { + routine := &Udf{Language: "PYTHON"} + require.ErrorContains(t, routine.LoadPythonTypeContract(), "unsupported routine language") + require.ErrorContains(t, routine.ValidatePythonTypeContract(), "unsupported routine language") + require.ErrorContains(t, routine.ValidatePythonCatalogSignature(), "unsupported routine language") +} + func TestSQLRoutineFingerprintAndCallUseSharedRevisionContract(t *testing.T) { fingerprint, err := SQLRoutineFingerprint("select value + 1", "[\"bigint\"]", "bigint") require.NoError(t, err) diff --git a/pkg/sql/plan/routine_dependency.go b/pkg/sql/plan/routine_dependency.go index 3245686641d67..f80920cf8f2dd 100644 --- a/pkg/sql/plan/routine_dependency.go +++ b/pkg/sql/plan/routine_dependency.go @@ -10,6 +10,7 @@ import ( "strings" planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" + "github.com/matrixorigin/matrixone/pkg/udf" ) // maxRoutinePlanDependencies bounds the amount of catalog state retained by @@ -25,6 +26,9 @@ func (builder *QueryBuilder) assignRoutineCallsite(call *planpb.RoutineCall) err if builder == nil || call == nil { return nil } + if call.Language != udf.LanguageSQL && call.Language != udf.LanguagePython { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine call language %q is not canonical", call.Language) + } if call.CallsiteId != "" { if len(call.CallsiteId) > 256 || strings.ContainsAny(call.CallsiteId, "\r\n") { return fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine callsite id is too large or invalid") @@ -43,6 +47,9 @@ func (builder *QueryBuilder) recordRoutinePlanDependency(call *planpb.RoutineCal if builder == nil || builder.qry == nil || call == nil || call.FunctionRef == nil { return nil } + if call.Language != udf.LanguageSQL && call.Language != udf.LanguagePython { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine call language %q is not canonical", call.Language) + } ref := call.FunctionRef dependency := &planpb.RoutinePlanDependency{ FunctionRef: &planpb.FunctionRef{ @@ -52,7 +59,7 @@ func (builder *QueryBuilder) recordRoutinePlanDependency(call *planpb.RoutineCal AccountId: ref.AccountId, DatabaseId: ref.DatabaseId, }, - Language: strings.ToLower(call.Language), + Language: call.Language, ContractVersion: call.ContractVersion, DefinitionFingerprint: "", Volatility: call.Volatility, diff --git a/pkg/sql/plan/routine_dependency_test.go b/pkg/sql/plan/routine_dependency_test.go index 4f49ada054540..0a49b099d6e12 100644 --- a/pkg/sql/plan/routine_dependency_test.go +++ b/pkg/sql/plan/routine_dependency_test.go @@ -85,6 +85,14 @@ func TestAssignRoutineCallsiteIsPlanLocalAndIdempotent(t *testing.T) { require.Equal(t, "python/2", second.CallsiteId) } +func TestRoutineDependencyRejectsNoncanonicalLanguage(t *testing.T) { + builder := &QueryBuilder{qry: &planpb.Query{}} + call := testRoutineCallForDependency() + call.Language = "PYTHON" + require.ErrorContains(t, builder.assignRoutineCallsite(call), "language") + require.ErrorContains(t, builder.recordRoutinePlanDependency(call), "language") +} + func TestRecordRoutinePlanDependencyBoundsPlanClosure(t *testing.T) { builder := &QueryBuilder{qry: &planpb.Query{ RoutineDependencies: make([]*planpb.RoutinePlanDependency, maxRoutinePlanDependencies), From f1f2e1328eba4b344875b0b44f2236a0269e1924 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:43:10 +0800 Subject: [PATCH 124/241] fix(udf): validate module handler bindings --- pkg/udf/python/worker/test_worker.py | 29 +++++++++ pkg/udf/python/worker/worker.py | 90 ++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index f850a1b8f4c7f..8777c94263631 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -237,6 +237,35 @@ def test_definition_validation_rejects_handler_rebound_after_definition(self): finally: server.shutdown() + def test_definition_validation_rejects_handler_rebound_in_module_control_flow(self): + sources = ( + "def f(ctx, value): return value\n" + "if True:\n" + " f = 1\n", + "def f(ctx, value): return value\n" + "for f in (1,):\n" + " pass\n", + "def f(ctx, value): return value\n" + "from math import pi as f\n", + ) + for source in sources: + with self.subTest(source=source): + with self.assertRaisesRegex(ValueError, "not a module-level function"): + worker._validate_definition_syntax( + complete_definition_validation_payload(source) + ) + + # A same-named local in a nested function does not rebind the module + # handler and must remain valid. + worker._validate_definition_syntax( + complete_definition_validation_payload( + "def f(ctx, value):\n" + " def inner():\n" + " f = 1\n" + " return value\n" + ) + ) + def test_capability_advertises_worker_instance_lease(self): encoded = worker._encode_capabilities( {"protocol_version": worker.PROTOCOL_VERSION}, lease_epoch=17 diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index ac3d5d8eae6ab..7b24fcd2ecf82 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -952,6 +952,92 @@ def _validate_definition_syntax(value: Dict[str, Any]) -> None: ) tree = ast.parse(value["source"], filename="", mode="exec") binding = None + + class NestedModuleBindingVisitor(ast.NodeVisitor): + """Find handler bindings below a module statement. + + A handler must be established by an unconditional module-level + function definition or lambda assignment. Assignments in control + flow, imports, and pattern targets can otherwise leave CREATE looking + valid while the value exposed by exec() is absent or non-callable. + Function/class bodies and comprehension targets have their own scope + and are deliberately not treated as module rebinding. + """ + + def __init__(self): + self.found = False + + def _mark(self): + self.found = True + + def visit_Name(self, node): + if node.id == handler and isinstance(node.ctx, (ast.Store, ast.Del)): + self._mark() + + def visit_FunctionDef(self, node): + if node.name == handler: + self._mark() + + def visit_AsyncFunctionDef(self, node): + if node.name == handler: + self._mark() + + def visit_ClassDef(self, node): + if node.name == handler: + self._mark() + + def visit_Lambda(self, node): + return + + def visit_ListComp(self, node): + self.visit(node.elt) + for generator in node.generators: + self.visit(generator.iter) + for condition in generator.ifs: + self.visit(condition) + + visit_SetComp = visit_ListComp + visit_GeneratorExp = visit_ListComp + + def visit_DictComp(self, node): + self.visit(node.key) + self.visit(node.value) + for generator in node.generators: + self.visit(generator.iter) + for condition in generator.ifs: + self.visit(condition) + + def visit_Import(self, node): + for alias in node.names: + bound = alias.asname or alias.name.split(".", 1)[0] + if bound == handler: + self._mark() + + def visit_ImportFrom(self, node): + for alias in node.names: + if alias.name == "*" or (alias.asname or alias.name) == handler: + self._mark() + + def visit_ExceptHandler(self, node): + if node.name == handler: + self._mark() + self.visit(node.type) + self.visit_nodes(node.body) + + def visit_MatchAs(self, node): + if node.name == handler: + self._mark() + if node.pattern is not None: + self.visit(node.pattern) + + def visit_MatchStar(self, node): + if node.name == handler: + self._mark() + + def visit_nodes(self, nodes): + for child in nodes: + self.visit(child) + for node in tree.body: if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name == handler: # Continue scanning: a later module-level assignment can replace @@ -973,6 +1059,10 @@ def _validate_definition_syntax(value: Dict[str, Any]) -> None: if any(isinstance(target, ast.Name) and target.id == handler for target in node.targets): binding = "other" continue + visitor = NestedModuleBindingVisitor() + visitor.visit(node) + if visitor.found: + binding = "other" if binding == "async": raise ValueError("USER_CODE: Python handler must be synchronous") if binding not in ("sync", "lambda"): From 0ab238dfeb6874c51d3d452b08d1cac74feece21 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:45:32 +0800 Subject: [PATCH 125/241] fix(udf): bound resolved artifact sources --- pkg/udf/python/gateway.go | 11 +++++++++++ pkg/udf/python/gateway_test.go | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 6667a824e8c2a..20204c132f361 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -1595,6 +1595,17 @@ func validateInvocation(invocation *udf.Invocation) error { if invocation.Source == "" { return fmt.Errorf("python udf: handler and source are required") } + // ArtifactResolver is an execution boundary, so the Gateway must enforce + // the same immutable source contract even when a custom resolver does not + // use FileArtifactStore. Do this before hashing or building the Open frame; + // otherwise an oversized or invalid source can consume a large temporary + // allocation and only fail at the Flight control-size boundary. + if !utf8.ValidString(invocation.Source) { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is not valid UTF-8") + } + if int64(len([]byte(invocation.Source))) > DefaultMaxArtifactBytes { + return fmt.Errorf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", DefaultMaxArtifactBytes) + } if invocation.ArtifactDigest != udf.PythonInlineArtifactDigest(invocation.Handler, invocation.Source) { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") } diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index b9fa665e3e062..6ead77eb9346d 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -220,6 +220,24 @@ func TestValidateInvocationRequiresFrozenContract(t *testing.T) { } } +func TestValidateInvocationBoundsResolvedArtifact(t *testing.T) { + oversized := validInvocation() + oversized.Source = strings.Repeat("x", int(DefaultMaxArtifactBytes)+1) + require.ErrorContains( + t, + validateInvocation(oversized), + "Python artifact exceeds", + ) + + invalidUTF8 := validInvocation() + invalidUTF8.Source = string([]byte{0xff}) + require.ErrorContains( + t, + validateInvocation(invalidUTF8), + "source is not valid UTF-8", + ) +} + func TestGatewayValidatesIdentityBeforeResolvingArtifact(t *testing.T) { resolver := &recordingArtifactResolver{source: validInvocation().Source} gateway, err := NewGatewayWithArtifactStore(ClientConfig{ From d2906d2b475fd4afac2609a2aeb73b4874862cba Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:47:57 +0800 Subject: [PATCH 126/241] fix(udf): align statement timestamp bounds --- pkg/udf/python/worker/test_worker.py | 28 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 13 +++++++++---- pkg/udf/runtime.go | 9 +++++++++ pkg/udf/runtime_test.go | 14 ++++++++++++++ 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 8777c94263631..194d5a244e840 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -371,6 +371,34 @@ def test_typed_statement_context_rejects_timestamp_outside_int64(self): } ) + def test_statement_context_matches_python_datetime_range(self): + for timestamp in ( + worker.MIN_STATEMENT_TIMESTAMP_UTC - 1, + worker.MAX_STATEMENT_TIMESTAMP_UTC + 1, + ): + typed = { + "contract_version": 1, + "statement_timestamp_utc": timestamp, + "timezone_kind": "FIXED_OFFSET", + "timezone_offset_minutes": 0, + "sql_mode": [], + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + with self.assertRaisesRegex(ValueError, "invalid typed statement timestamp"): + worker._typed_statement_context(typed) + with self.assertRaisesRegex(ValueError, "invalid statement_timestamp_utc"): + worker._statement_context( + { + "statement_timestamp_utc": str(timestamp), + "session_timezone_kind": "FIXED_OFFSET", + "session_timezone_offset_minutes": "0", + "sql_mode": "[]", + "current_user": "alice", + "connection_collation": "utf8mb4_bin", + } + ) + def test_typed_contract_versions_require_integer_wire_values(self): typed_context = { "contract_version": True, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 7b24fcd2ecf82..8b130515ac86d 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -77,6 +77,11 @@ class _NoFlightServerBase: MAX_SECURITY_PRINCIPAL_ID = (1 << 32) - 1 MIN_INT64 = -(1 << 63) MAX_INT64 = (1 << 63) - 1 +# StatementContext is materialized as datetime.datetime. This is narrower +# than the wire int64 domain and must match the Go context validator before an +# invocation reaches user code. +MIN_STATEMENT_TIMESTAMP_UTC = -62135596800000000 +MAX_STATEMENT_TIMESTAMP_UTC = 253402300799999999 MIN_INT32 = -(1 << 31) MAX_INT32 = (1 << 31) - 1 # Admission bounds cover active fences and retained terminal tombstones. The @@ -552,8 +557,8 @@ def _typed_statement_context(raw: Any) -> Optional[Dict[str, Any]]: if ( isinstance(timestamp, bool) or not isinstance(timestamp, int) - or timestamp < MIN_INT64 - or timestamp > MAX_INT64 + or timestamp < MIN_STATEMENT_TIMESTAMP_UTC + or timestamp > MAX_STATEMENT_TIMESTAMP_UTC ): raise ValueError("PROTOCOL: invalid typed statement timestamp") timezone_kind = raw.get("timezone_kind") @@ -670,8 +675,8 @@ def _statement_context(raw: Any) -> Optional[StatementContext]: timestamp_text = _required_context_value(raw, "statement_timestamp_utc") try: timestamp_micros = int(timestamp_text, 10) - if timestamp_micros < MIN_INT64 or timestamp_micros > MAX_INT64: - raise ValueError("timestamp is outside int64 range") + if timestamp_micros < MIN_STATEMENT_TIMESTAMP_UTC or timestamp_micros > MAX_STATEMENT_TIMESTAMP_UTC: + raise ValueError("timestamp is outside the Python datetime range") seconds, micros = divmod(timestamp_micros, 1_000_000) timestamp = _datetime.datetime(1970, 1, 1, tzinfo=_datetime.timezone.utc) + _datetime.timedelta(seconds=seconds, microseconds=micros) except (TypeError, ValueError, OverflowError) as exc: diff --git a/pkg/udf/runtime.go b/pkg/udf/runtime.go index e56f5e08b78a7..bdfd87a15d690 100644 --- a/pkg/udf/runtime.go +++ b/pkg/udf/runtime.go @@ -41,6 +41,12 @@ const ( PythonABIContract = "PYTHON_ARROW" PythonAdapterVersion = "2026-09" PythonSDKVersion = "1.0" + // Python materializes statement timestamps as datetime.datetime. Keep the + // Go boundary identical to Python's year-1 through year-9999 UTC range; + // accepting the full int64 domain here would let a plan pass CN validation + // and fail only after the worker starts decoding its context. + minStatementTimestampUTC int64 = -62135596800000000 + maxStatementTimestampUTC int64 = 253402300799999999 // These numeric contracts are persisted in catalog and plan records. They // are intentionally separate from the human-facing adapter/SDK names: // changing a wire or persistent shape must fail closed before user code is @@ -86,6 +92,9 @@ func (c StatementContext) Validate() error { if c.ContractVersion != StatementContextContractVersion { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported statement context contract %d", c.ContractVersion) } + if c.StatementTimestampUTC < minStatementTimestampUTC || c.StatementTimestampUTC > maxStatementTimestampUTC { + return fmt.Errorf("python udf: statement timestamp is outside the Python datetime range") + } if c.CurrentUser == "" || c.ConnectionCollation == "" { return fmt.Errorf("python udf: statement context has no authenticated user or collation") } diff --git a/pkg/udf/runtime_test.go b/pkg/udf/runtime_test.go index 9c937606a8f15..5997e356788f8 100644 --- a/pkg/udf/runtime_test.go +++ b/pkg/udf/runtime_test.go @@ -107,6 +107,20 @@ func TestStatementContextAcceptsUnixEpoch(t *testing.T) { require.NoError(t, snapshot.Validate()) } +func TestStatementContextMatchesPythonDatetimeRange(t *testing.T) { + base := StatementContext{ + ContractVersion: StatementContextContractVersion, + TimezoneKind: "FIXED_OFFSET", + CurrentUser: "alice", + ConnectionCollation: "utf8mb4_bin", + } + for _, timestamp := range []int64{minStatementTimestampUTC - 1, maxStatementTimestampUTC + 1} { + context := base + context.StatementTimestampUTC = timestamp + require.ErrorContains(t, context.Validate(), "outside the Python datetime range") + } +} + func TestSecurityFrameRejectsEffectivePrincipalChange(t *testing.T) { frame := SecurityFrame{ ContractVersion: SecurityFrameContractVersion, From 2cd66813584b5265646ff641a1f38557389c32ea Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:53:51 +0800 Subject: [PATCH 127/241] fix(udf): handle bare except in handler validation --- pkg/udf/python/worker/test_worker.py | 11 +++++++++++ pkg/udf/python/worker/worker.py | 5 ++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 194d5a244e840..76e3986f10ed9 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -266,6 +266,17 @@ def test_definition_validation_rejects_handler_rebound_in_module_control_flow(se ) ) + def test_definition_validation_accepts_bare_except(self): + worker._validate_definition_syntax( + complete_definition_validation_payload( + "def f(ctx, value): return value\n" + "try:\n" + " pass\n" + "except:\n" + " pass\n" + ) + ) + def test_capability_advertises_worker_instance_lease(self): encoded = worker._encode_capabilities( {"protocol_version": worker.PROTOCOL_VERSION}, lease_epoch=17 diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 8b130515ac86d..d42bc59ea3651 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1026,7 +1026,10 @@ def visit_ImportFrom(self, node): def visit_ExceptHandler(self, node): if node.name == handler: self._mark() - self.visit(node.type) + # A bare ``except:`` has no exception-expression node. Keep + # walking its body without asking NodeVisitor to visit None. + if node.type is not None: + self.visit(node.type) self.visit_nodes(node.body) def visit_MatchAs(self, node): From a3eabcba7cb9c4558ee22da0dd81a36e99080cbb Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 11:58:13 +0800 Subject: [PATCH 128/241] fix(udf): bound artifact validation resolution --- pkg/udf/python/gateway.go | 18 ++++++++++--- pkg/udf/python/gateway_test.go | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 20204c132f361..4c529cef3fd7d 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -200,6 +200,12 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin if ctx == nil { ctx = context.Background() } + requestCtx := ctx + var cancel context.CancelFunc + if g.cfg.RequestTimeout > 0 { + requestCtx, cancel = context.WithTimeout(ctx, g.cfg.RequestTimeout) + defer cancel() + } if definition == nil { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: nil Python routine definition") } @@ -262,7 +268,7 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin source := definition.Source if g.artifactResolver != nil { resolved, resolveErr := g.artifactResolver.Resolve( - ctx, definition.AccountID, definition.Handler, definition.ArtifactDigest, + requestCtx, definition.AccountID, definition.Handler, definition.ArtifactDigest, ) if resolveErr != nil { return resolveErr @@ -292,7 +298,7 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin // lease in its request. It must perform its own worker-instance handshake; // relying on a cached readiness result could validate against a replacement // worker with a different contract. - if err := g.ensureCapabilities(ctx, client, true); err != nil { + if err := g.ensureCapabilities(requestCtx, client, true); err != nil { return err } payload, err := json.Marshal(definitionValidationPayload{ @@ -314,8 +320,12 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin if err != nil { return fmt.Errorf("python udf: encode definition validation: %w", err) } - actionCtx, cancel := context.WithTimeout(ctx, g.cfg.RequestTimeout) - defer cancel() + actionCtx := requestCtx + var actionCancel context.CancelFunc + if g.cfg.RequestTimeout > 0 { + actionCtx, actionCancel = context.WithTimeout(requestCtx, g.cfg.RequestTimeout) + defer actionCancel() + } stream, err := client.DoAction(actionCtx, &flight.Action{Type: "ValidatePythonDefinition", Body: payload}) if err != nil { g.invalidateCapabilities() diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index 6ead77eb9346d..27102c5cf3e16 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -61,6 +61,13 @@ type recordingArtifactResolver struct { digest string } +type blockingArtifactResolver struct{} + +func (blockingArtifactResolver) Resolve(ctx context.Context, _ uint64, _, _ string) (string, error) { + <-ctx.Done() + return "", ctx.Err() +} + func (r *recordingArtifactResolver) Resolve(_ context.Context, accountID uint64, handler, digest string) (string, error) { r.calls++ r.account = accountID @@ -69,6 +76,47 @@ func (r *recordingArtifactResolver) Resolve(_ context.Context, accountID uint64, return r.source, nil } +func TestValidateDefinitionBoundsArtifactResolution(t *testing.T) { + invocation := validInvocation() + gateway, err := NewGatewayWithArtifactStore(ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:1", + RequestTimeout: 20 * time.Millisecond, + }, blockingArtifactResolver{}) + require.NoError(t, err) + defer gateway.Close() + + definition := &udf.RoutineDefinition{ + Language: udf.LanguagePython, + AccountID: invocation.FunctionRef.AccountID, + Handler: invocation.Handler, + Args: append([]types.Type(nil), invocation.Args...), + ReturnType: invocation.ReturnType, + Mode: invocation.Mode, + NullPolicy: invocation.NullPolicy, + ABIContract: invocation.ABIContract, + AdapterVersion: invocation.AdapterVersion, + SDKVersion: invocation.SDKVersion, + DefinitionSchemaVersion: invocation.DefinitionSchemaVersion, + ArtifactDigest: invocation.ArtifactDigest, + EnvironmentDigest: invocation.EnvironmentDigest, + DefinitionFingerprint: invocation.DefinitionFingerprint, + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + done := make(chan error, 1) + go func() { done <- gateway.ValidateDefinition(ctx, definition) }() + select { + case err := <-done: + require.ErrorIs(t, err, context.DeadlineExceeded) + case <-time.After(500 * time.Millisecond): + cancel() + require.FailNow(t, "artifact resolution was not bounded by the gateway request timeout") + } +} + func (c *finishAckFlightClient) DoAction( ctx context.Context, action *flight.Action, From 584ff188abdec6149683a4e015cb820d96fafd6b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 12:00:19 +0800 Subject: [PATCH 129/241] fix(udf): inspect mapping pattern handler captures --- pkg/udf/python/worker/test_worker.py | 4 ++++ pkg/udf/python/worker/worker.py | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 76e3986f10ed9..f1e264d7daf82 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -247,6 +247,10 @@ def test_definition_validation_rejects_handler_rebound_in_module_control_flow(se " pass\n", "def f(ctx, value): return value\n" "from math import pi as f\n", + "def f(ctx, value): return value\n" + "match {\"value\": 1, \"other\": 2}:\n" + " case {\"value\": value, **f}:\n" + " pass\n", ) for source in sources: with self.subTest(source=source): diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index d42bc59ea3651..d61aee870a704 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1042,6 +1042,14 @@ def visit_MatchStar(self, node): if node.name == handler: self._mark() + def visit_MatchMapping(self, node): + # ``rest`` is the capture name in a ``**name`` mapping pattern, + # represented as a plain string rather than an ast.Name. + if node.rest == handler: + self._mark() + self.visit_nodes(node.keys) + self.visit_nodes(node.patterns) + def visit_nodes(self, nodes): for child in nodes: self.visit(child) From 5a2d15fb3995772705bdeb6ad4ebcbce7c5b4bee Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 12:02:19 +0800 Subject: [PATCH 130/241] fix(udf): stop cleanup reaper on worker shutdown errors --- pkg/udf/python/worker/test_worker.py | 13 +++++++++++++ pkg/udf/python/worker/worker.py | 15 +++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index f1e264d7daf82..f846ad15946a5 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -301,6 +301,19 @@ def test_capability_advertises_worker_instance_lease(self): {"protocol_version": worker.PROTOCOL_VERSION}, lease_epoch=0 ) + def test_cleanup_reaper_can_be_stopped_independently(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + try: + with server._pending_cleanup_condition: + server._ensure_pending_cleanup_thread_locked() + thread = server._pending_cleanup_thread + server._stop_pending_cleanup_reaper() + self.assertTrue(server._pending_cleanup_stopping) + self.assertIsNotNone(thread) + self.assertFalse(thread.is_alive()) + finally: + server.shutdown() + def test_typed_statement_context_matches_canonical_handler_context(self): typed = { "contract_version": 1, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index d61aee870a704..c5091203e2030 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -3342,9 +3342,10 @@ def _pending_cleanup_loop(self) -> None: finish_error, ) - def shutdown(self): - self._shutdown_event.set() - result = super().shutdown() + def _stop_pending_cleanup_reaper(self) -> None: + # The base Flight server may fail while interrupting an RPC. The + # worker still owns its cleanup reaper in that case, so stopping and + # joining it cannot depend on the base shutdown returning normally. with self._pending_cleanup_condition: self._pending_cleanup_stopping = True self._pending_cleanup_condition.notify_all() @@ -3362,7 +3363,13 @@ def shutdown(self): "Python UDF worker shutdown left %d handler cleanups pending", pending, ) - return result + + def shutdown(self): + self._shutdown_event.set() + try: + return super().shutdown() + finally: + self._stop_pending_cleanup_reaper() def _cleanup_exchange( self, From d8c7d59446f8a27604036f3ab83e5cdaab9ffccc Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 12:05:52 +0800 Subject: [PATCH 131/241] fix(udf): reject null sql mode context --- pkg/udf/runtime.go | 8 ++++++++ pkg/udf/runtime_test.go | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/pkg/udf/runtime.go b/pkg/udf/runtime.go index bdfd87a15d690..ada399a2e5a4a 100644 --- a/pkg/udf/runtime.go +++ b/pkg/udf/runtime.go @@ -160,6 +160,14 @@ func StatementContextFromMap(values map[string]string) (*StatementContext, error if err := json.Unmarshal([]byte(raw), &mode); err != nil { return nil, fmt.Errorf("python udf: invalid statement sql_mode: %w", err) } + // The wire contract is a JSON array, including when it is empty. A + // JSON null decodes successfully into a nil Go slice, but would be + // serialized back as null and rejected by the Python context decoder. + // Reject it at the trusted CN adapter instead of carrying a malformed + // snapshot into the Flight request. + if mode == nil { + return nil, fmt.Errorf("python udf: invalid statement sql_mode: expected a JSON array") + } } context := &StatementContext{ ContractVersion: StatementContextContractVersion, diff --git a/pkg/udf/runtime_test.go b/pkg/udf/runtime_test.go index 5997e356788f8..c5f80fbda6ebf 100644 --- a/pkg/udf/runtime_test.go +++ b/pkg/udf/runtime_test.go @@ -91,6 +91,10 @@ func TestStatementContextFromMapRejectsAmbiguousTimezoneAndMalformedMode(t *test malformed["sql_mode"] = "[\"ANSI\",\"ANSI\"]" _, err = StatementContextFromMap(malformed) require.ErrorContains(t, err, "not canonical") + + malformed["sql_mode"] = "null" + _, err = StatementContextFromMap(malformed) + require.ErrorContains(t, err, "expected a JSON array") } func TestStatementContextAcceptsUnixEpoch(t *testing.T) { From 2391736a841b85648a040571f18ad87f39564a7e Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 12:06:33 +0800 Subject: [PATCH 132/241] fix(udf): validate IANA zones at CN boundary --- pkg/udf/runtime.go | 4 ++++ pkg/udf/runtime_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/pkg/udf/runtime.go b/pkg/udf/runtime.go index ada399a2e5a4a..d68bde7f54323 100644 --- a/pkg/udf/runtime.go +++ b/pkg/udf/runtime.go @@ -27,6 +27,7 @@ import ( "strconv" "strings" "sync" + "time" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" @@ -102,6 +103,9 @@ func (c StatementContext) Validate() error { if c.TimezoneName == "" || c.TimezoneDatabaseVersion == "" || c.TimezoneOffsetMinutes != 0 { return fmt.Errorf("python udf: IANA statement timezone is incomplete") } + if _, err := time.LoadLocation(c.TimezoneName); err != nil { + return fmt.Errorf("python udf: IANA statement timezone is not present in the local tzdb: %w", err) + } } else if c.TimezoneKind == "FIXED_OFFSET" { if c.TimezoneName != "" || c.TimezoneDatabaseVersion != "" || c.TimezoneOffsetMinutes < -839 || c.TimezoneOffsetMinutes > 840 { return fmt.Errorf("python udf: fixed statement timezone is invalid") diff --git a/pkg/udf/runtime_test.go b/pkg/udf/runtime_test.go index c5f80fbda6ebf..3faa79a6dfe99 100644 --- a/pkg/udf/runtime_test.go +++ b/pkg/udf/runtime_test.go @@ -111,6 +111,34 @@ func TestStatementContextAcceptsUnixEpoch(t *testing.T) { require.NoError(t, snapshot.Validate()) } +func TestStatementContextRejectsUnknownIANAZoneBeforeTransport(t *testing.T) { + snapshot := StatementContext{ + ContractVersion: StatementContextContractVersion, + StatementTimestampUTC: 0, + TimezoneKind: "IANA", + TimezoneName: "NoSuch/Zone", + TimezoneDatabaseVersion: "2026a", + CurrentUser: "alice", + ConnectionCollation: "utf8mb4_bin", + } + require.ErrorContains(t, snapshot.Validate(), "not present in the local tzdb") +} + +func TestStatementContextAcceptsKnownIANAZone(t *testing.T) { + version, err := TimezoneDatabaseVersion() + require.NoError(t, err) + snapshot := StatementContext{ + ContractVersion: StatementContextContractVersion, + StatementTimestampUTC: 0, + TimezoneKind: "IANA", + TimezoneName: "UTC", + TimezoneDatabaseVersion: version, + CurrentUser: "alice", + ConnectionCollation: "utf8mb4_bin", + } + require.NoError(t, snapshot.Validate()) +} + func TestStatementContextMatchesPythonDatetimeRange(t *testing.T) { base := StatementContext{ ContractVersion: StatementContextContractVersion, From 840266f4b98f20589ab450889e3d0260dbf2c3bb Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 12:08:25 +0800 Subject: [PATCH 133/241] fix(udf): cap artifact store to wire contract --- pkg/udf/python/artifact.go | 6 ++++++ pkg/udf/python/artifact_test.go | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/pkg/udf/python/artifact.go b/pkg/udf/python/artifact.go index 957eff9deccaf..72912c2173bf0 100644 --- a/pkg/udf/python/artifact.go +++ b/pkg/udf/python/artifact.go @@ -68,6 +68,12 @@ func NewFileArtifactStore(fs fileservice.FileService, maxSize int64) (*FileArtif if maxSize <= 0 { maxSize = DefaultMaxArtifactBytes } + if maxSize > DefaultMaxArtifactBytes { + return nil, fmt.Errorf( + "UNSUPPORTED_ROUTINE_VERSION: Python artifact limit %d exceeds the current contract limit %d", + maxSize, DefaultMaxArtifactBytes, + ) + } return &FileArtifactStore{fs: shared, maxSize: maxSize}, nil } diff --git a/pkg/udf/python/artifact_test.go b/pkg/udf/python/artifact_test.go index cc617f68f52ec..5f56eebd3d568 100644 --- a/pkg/udf/python/artifact_test.go +++ b/pkg/udf/python/artifact_test.go @@ -76,6 +76,11 @@ func TestNewFileArtifactStoreRequiresSharedFileService(t *testing.T) { require.NoError(t, err) _, err = NewFileArtifactStore(local, 0) require.ErrorContains(t, err, "shared FileService") + + shared, err := fileservice.NewMemoryFS(defines.SharedFileServiceName, fileservice.DisabledCacheConfig, nil) + require.NoError(t, err) + _, err = NewFileArtifactStore(shared, DefaultMaxArtifactBytes+1) + require.ErrorContains(t, err, "exceeds the current contract limit") } func TestFileArtifactStoreRejectsInvalidDirectConstruction(t *testing.T) { From 47dd3e4e5f113733e2c376d854188dd1de4b8673 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 12:12:17 +0800 Subject: [PATCH 134/241] fix(udf): bound control JSON nesting --- pkg/udf/protocol/protocol.go | 18 ++++++++++++++-- pkg/udf/protocol/protocol_test.go | 18 ++++++++++++++++ pkg/udf/python/worker/test_worker.py | 19 +++++++++++++++++ pkg/udf/python/worker/worker.py | 31 ++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 2 deletions(-) diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 1d9b4113d13f2..2ada4e2800423 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -44,6 +44,10 @@ const ( // but allowing an unbounded statement/group/invocation string would make // every bounded entry claim an unbounded memory claim. MaxFenceComponentBytes = 256 + // Control JSON is intentionally shallow. The byte bound alone is not a + // stack bound because duplicate-key validation walks nested arrays/objects + // before encoding/json can decode the envelope. + MaxJSONNesting = 64 ) var ( @@ -206,6 +210,9 @@ func validateControlFields(control Control, wire map[string]json.RawMessage) err if err := json.Unmarshal(control.Payload, &payload); err != nil || payload == nil { return fmt.Errorf("%w: control kind %q payload must be a JSON object", ErrProtocol, control.Kind) } + if err := rejectDuplicateJSONKeys(control.Payload); err != nil { + return fmt.Errorf("%w: invalid control payload: %v", ErrProtocol, err) + } } case "InputBatch", "ResultBatch": if control.Sequence == 0 { @@ -368,6 +375,10 @@ func rejectDuplicateJSONKeys(data []byte) error { } func walkJSONValue(decoder *json.Decoder) error { + return walkJSONValueAtDepth(decoder, 0) +} + +func walkJSONValueAtDepth(decoder *json.Decoder, depth int) error { token, err := decoder.Token() if err != nil { return fmt.Errorf("decode control JSON: %v", err) @@ -376,6 +387,9 @@ func walkJSONValue(decoder *json.Decoder) error { if !ok { return nil } + if depth >= MaxJSONNesting { + return fmt.Errorf("control JSON nesting exceeds %d levels", MaxJSONNesting) + } switch delim { case '{': seen := make(map[string]struct{}) @@ -392,7 +406,7 @@ func walkJSONValue(decoder *json.Decoder) error { return fmt.Errorf("duplicate control JSON field %q", key) } seen[key] = struct{}{} - if err := walkJSONValue(decoder); err != nil { + if err := walkJSONValueAtDepth(decoder, depth+1); err != nil { return err } } @@ -400,7 +414,7 @@ func walkJSONValue(decoder *json.Decoder) error { return err case '[': for decoder.More() { - if err := walkJSONValue(decoder); err != nil { + if err := walkJSONValueAtDepth(decoder, depth+1); err != nil { return err } } diff --git a/pkg/udf/protocol/protocol_test.go b/pkg/udf/protocol/protocol_test.go index f03e04e608556..13334a95b6016 100644 --- a/pkg/udf/protocol/protocol_test.go +++ b/pkg/udf/protocol/protocol_test.go @@ -18,6 +18,7 @@ import ( "bytes" "encoding/json" "errors" + "strings" "sync" "sync/atomic" "testing" @@ -70,6 +71,23 @@ func TestControlRejectsDuplicateJSONFields(t *testing.T) { require.ErrorContains(t, err, "duplicate control JSON field") } +func TestControlRejectsExcessiveJSONNesting(t *testing.T) { + deepPayload := `{"value":` + strings.Repeat("[", MaxJSONNesting) + "0" + strings.Repeat("]", MaxJSONNesting) + "}" + wire, err := MarshalControl(Control{ + Kind: "OpenInvocation", + Tuple: testTuple(), + Payload: json.RawMessage(deepPayload), + }) + require.ErrorContains(t, err, "nesting exceeds") + require.Nil(t, wire) + + // The same bound must protect an incoming frame even when it was produced + // by an older or non-Go peer that did not enforce the outbound check. + outer := `{"version":1,"kind":"OpenInvocation","tuple":{"account_id":1,"statement_id":"statement","group_id":"group","group_epoch":2,"invocation_id":"invocation","lease_epoch":3},"payload":` + deepPayload + `}` + _, err = UnmarshalControl([]byte(outer)) + require.ErrorContains(t, err, "nesting exceeds") +} + func TestOpenInvocationPayloadMustBeObject(t *testing.T) { for _, payload := range []string{"null", "[]", `"text"`} { wire := []byte(`{"version":1,"kind":"OpenInvocation","tuple":{"account_id":1,"statement_id":"statement","group_id":"group","group_epoch":2,"invocation_id":"invocation","lease_epoch":3},"payload":` + payload + `}`) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index f846ad15946a5..4d81082cd05c4 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -3873,6 +3873,25 @@ def test_control_rejects_duplicate_json_fields(self): with self.assertRaisesRegex(ValueError, "duplicate control JSON field"): worker._decode_control(wire) + def test_control_rejects_excessive_json_nesting(self): + nested = "[" * worker.MAX_JSON_NESTING + "0" + "]" * worker.MAX_JSON_NESTING + value = { + "version": 1, + "kind": "OpenInvocation", + "tuple": { + "account_id": 1, + "statement_id": "statement", + "group_id": "group", + "group_epoch": 1, + "invocation_id": "invocation", + "lease_epoch": 1, + }, + "payload": {"value": json.loads(nested)}, + } + wire = json.dumps(value, separators=(",", ":")).encode() + with self.assertRaisesRegex(ValueError, "nesting exceeds"): + worker._decode_control(wire) + def test_result_ack_rejects_zero_sequence(self): state = worker._InvocationState({}, 1) state.last_result = 1 diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index c5091203e2030..e5bd4004eace2 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -65,6 +65,11 @@ class _NoFlightServerBase: PROTOCOL_VERSION = 1 MAX_CONTROL_BYTES = 1 << 20 +# Keep control parsing shallow even when the total JSON envelope is below the +# byte limit. This is the Python counterpart of protocol.MaxJSONNesting; a +# byte scanner makes the bound independent of the interpreter's recursion +# limit and ignores bracket characters inside JSON strings. +MAX_JSON_NESTING = 64 # Keep the Python wire boundary identical to protocol.FencingTuple's # component limit. The control frame limit alone is not sufficient: a # single oversized identity would otherwise consume most of every ledger @@ -805,9 +810,35 @@ def _reject_nonstandard_json_constant(value): raise ValueError(f"PROTOCOL: invalid JSON constant {value}") +def _validate_json_nesting(data: bytes) -> None: + depth = 0 + in_string = False + escaped = False + for byte in data: + if in_string: + if escaped: + escaped = False + elif byte == 0x5C: # backslash + escaped = True + elif byte == 0x22: # double quote + in_string = False + continue + if byte == 0x22: + in_string = True + elif byte == 0x7B or byte == 0x5B: # { or [ + depth += 1 + if depth > MAX_JSON_NESTING: + raise ValueError( + f"PROTOCOL: control JSON nesting exceeds {MAX_JSON_NESTING} levels" + ) + elif byte == 0x7D or byte == 0x5D: # } or ] + depth -= 1 + + def _decode_control(data: bytes) -> Dict[str, Any]: if not data or len(data) > MAX_CONTROL_BYTES: raise ValueError("PROTOCOL: invalid control size") + _validate_json_nesting(data) try: text = bytes(data).decode("utf-8") except UnicodeDecodeError as exc: From dedfe617ae8619ab3e487d8a0711f3ef5cdc8674 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 12:12:55 +0800 Subject: [PATCH 135/241] fix(udf): bound validation action JSON --- pkg/udf/python/worker/test_worker.py | 11 +++++++++++ pkg/udf/python/worker/worker.py | 2 ++ 2 files changed, 13 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 4d81082cd05c4..037fb08d6156d 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -3892,6 +3892,17 @@ def test_control_rejects_excessive_json_nesting(self): with self.assertRaisesRegex(ValueError, "nesting exceeds"): worker._decode_control(wire) + def test_action_decoders_reject_excessive_json_nesting(self): + nested = "[" * worker.MAX_JSON_NESTING + "0" + "]" * worker.MAX_JSON_NESTING + with self.assertRaisesRegex(ValueError, "nesting exceeds"): + worker._decode_capability_request( + ('{"protocol_version":1,"extra":' + nested + '}').encode() + ) + with self.assertRaisesRegex(ValueError, "nesting exceeds"): + worker._decode_definition_validation( + ('{"extra":' + nested + '}').encode() + ) + def test_result_ack_rejects_zero_sequence(self): state = worker._InvocationState({}, 1) state.last_result = 1 diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index e5bd4004eace2..a277b0c8bd087 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -871,6 +871,7 @@ def _decode_control(data: bytes) -> Dict[str, Any]: def _decode_capability_request(data: bytes) -> Dict[str, Any]: if not data or len(data) > MAX_CONTROL_BYTES: raise ValueError("PROTOCOL: invalid capability request size") + _validate_json_nesting(data) try: value = json.loads( bytes(data).decode("utf-8"), @@ -890,6 +891,7 @@ def _decode_definition_validation(data: bytes) -> Dict[str, Any]: """Decode the strict, pre-publication definition validation payload.""" if not data or len(data) > MAX_DEFINITION_VALIDATION_BYTES: raise ValueError("PROTOCOL: invalid definition validation size") + _validate_json_nesting(data) try: value = json.loads( bytes(data).decode("utf-8"), From 2133375e7891216bb52be21023ac16956d439c7b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 12:13:54 +0800 Subject: [PATCH 136/241] fix(udf): reject sub-minute session offsets --- pkg/sql/colexec/external_routine_eval.go | 3 +++ pkg/sql/colexec/external_routine_eval_test.go | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index f5274804d779a..d3bf16cfb8c34 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -651,6 +651,9 @@ func buildRoutineContext(proc *process.Process) (map[string]string, error) { } if zoneName == "FixedZone" { _, offset := queryStart.In(location).Zone() + if offset%60 != 0 { + return nil, fmt.Errorf("python udf: fixed session timezone offset must be a whole number of minutes") + } context["session_timezone_kind"] = "FIXED_OFFSET" context["session_timezone_offset_minutes"] = formatTimezoneOffsetMinutes(offset / 60) delete(context, "session_timezone_name") diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index 493d6e3b3e136..39ac13d31f227 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -387,6 +387,15 @@ func TestBuildRoutineContextRejectsUnstableTimezone(t *testing.T) { } } +func TestBuildRoutineContextRejectsSubMinuteFixedTimezone(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + proc.GetSessionInfo().TimeZone = time.FixedZone("FixedZone", 8*60*60+30) + + _, err := buildRoutineContext(proc) + require.ErrorContains(t, err, "whole number of minutes") +} + func testExternalRoutineCall(t *testing.T, mode, nullPolicy string) *planpb.RoutineCall { t.Helper() descriptor, err := function.NewPythonTypeDescriptor(types.T_int64.ToType()) From 9f2e3d8bd8dd68b65841e8e88fbb5e1bfe6ca6e8 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 14:52:09 +0800 Subject: [PATCH 137/241] fix(frontend): stabilize Python replace validation --- pkg/bootstrap/versions/v4_0_7/upgrade_test.go | 8 ++++---- pkg/frontend/authenticate.go | 15 +++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/pkg/bootstrap/versions/v4_0_7/upgrade_test.go b/pkg/bootstrap/versions/v4_0_7/upgrade_test.go index cb15460b65457..b65bd179adc80 100644 --- a/pkg/bootstrap/versions/v4_0_7/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_7/upgrade_test.go @@ -28,14 +28,14 @@ func TestPythonFunctionRevisionUpgradeContract(t *testing.T) { if metadata.Version != "4.0.7" || metadata.MinUpgradeVersion != "4.0.6" { t.Fatalf("unexpected version metadata: %+v", metadata) } - if metadata.UpgradeCluster != versions.No || metadata.UpgradeTenant != versions.Yes { - t.Fatalf("python catalog upgrade must be tenant scoped: %+v", metadata) + if metadata.UpgradeCluster != versions.Yes || metadata.UpgradeTenant != versions.Yes { + t.Fatalf("4.0.7 must run both cluster and tenant upgrades: %+v", metadata) } if metadata.VersionOffset != uint32(len(tenantUpgEntries)) { t.Fatalf("version offset %d does not match tenant entries %d", metadata.VersionOffset, len(tenantUpgEntries)) } - if metadata.RequiredProtocolVersion != defines.MORPCVersion48 { - t.Fatalf("unexpected protocol gate: %v", metadata.RequiredProtocolVersion) + if metadata.RequiredProtocolVersion != defines.MORPCVersion61 { + t.Fatalf("unexpected 4.0.7 protocol gate: %v", metadata.RequiredProtocolVersion) } if len(tenantUpgEntries) != 9 { diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index fa4aed6b959a1..087f6906db849 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -12480,10 +12480,6 @@ func persistUserDefinedFunction( if previousRevision == 0 || previousNamespace == 0 { return moerr.NewInvalidInputNoCtx("UNSUPPORTED_ROUTINE_VERSION: legacy Python definition requires DROP and CREATE") } - definition, err = normalizePythonFunctionDefinition(definition) - if err != nil { - return err - } candidate, err := function.DecodePythonRoutineBody(definition.body) if err != nil { return moerr.NewInvalidInputNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition rejected before publication: %v", err) @@ -12501,6 +12497,17 @@ func persistUserDefinedFunction( "UNSUPPORTED_ROUTINE_VERSION: Python REPLACE cannot change input or return descriptor; use DROP and CREATE", ) } + // Compare the immutable candidate signature with the active revision + // before validating the compatibility columns. A REPLACE that changes + // the descriptor must report the stable identity error even when its + // caller-supplied logical args/return fields are stale; otherwise the + // same invalid operation produces a different error depending on which + // catalog projection is checked first. No catalog write has happened + // at this point. + definition, err = normalizePythonFunctionDefinition(definition) + if err != nil { + return err + } } else if revisionCatalogReady { var readErr error previousRevision, previousNamespace, readErr = readFunctionRevisionHead(ctx, bh, *functionID) From 5a20a3a64bb908810d5f3c5e74f5e4386ed5ca83 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 14:55:27 +0800 Subject: [PATCH 138/241] fix(frontend): reject incomplete Python identities --- pkg/frontend/authenticate.go | 13 +++++++++---- pkg/frontend/python_udf_catalog_test.go | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index 087f6906db849..c26333b15b3a4 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -12335,12 +12335,17 @@ func matchUserDefinedFunctionCandidates( return nil, err } } - if strings.EqualFold(existingLanguage, string(tree.PYTHON)) && existingCanonical != "" { + if strings.EqualFold(existingLanguage, string(tree.PYTHON)) { + if columnCount < 5 || existingCanonical == "" { + return nil, moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: Python function %d has no exact input descriptor", + functionID, + ) + } isMatch = existingCanonical == exactArgTypes } else { - // A legacy/partially upgraded Python row is rejected as the - // same logical identity. It cannot be silently replaced with a - // different exact descriptor. + // SQL and Python share the historical logical namespace. The + // exact descriptor is only authoritative for a Python row. isMatch = existingLogical == logicalArgTypes } } else { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 9f2ac17cbd174..cde653e5b4936 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -993,6 +993,24 @@ func TestMatchUserDefinedFunctionCandidatesUsesExactPythonDescriptor(t *testing. require.Equal(t, []int64{51, 52, 53}, ids) } +func TestMatchUserDefinedFunctionCandidatesRejectsPythonRowWithoutExactDescriptor(t *testing.T) { + result := &MysqlResultSet{} + for _, name := range []string{"function_id", "args", "language", "arg_types", "canonical_input_descriptor"} { + column := &MysqlColumn{} + column.SetName(name) + if name == "function_id" { + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + } else { + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + } + result.AddColumn(column) + } + result.AddRow([]interface{}{int64(54), `[{"name":"value","type":"int"}]`, "python", `["int"]`, ""}) + + _, err := matchUserDefinedFunctionCandidates(context.Background(), []ExecResult{result}, "python", `["int"]`, `{"types":[]}`) + require.ErrorContains(t, err, "has no exact input descriptor") +} + func TestMatchUserDefinedFunctionCandidatesRejectsSplitResultSets(t *testing.T) { result := emptyCatalogProbeResult(5) _, err := matchUserDefinedFunctionCandidates( From 396738f43dd8c48272dcf6494ce9d4ce4faebcd9 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 14:57:28 +0800 Subject: [PATCH 139/241] fix(udf): cancel exchange before releasing admission --- pkg/udf/python/gateway.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 4c529cef3fd7d..8dd8169199b77 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -609,6 +609,12 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul openAttempted := false defer func() { reason := admissionReason(streamCtx, openAttempted, err) + // Cancel the Flight exchange before returning the local K slot and + // terminal-ledger ownership. On an input/send/receive failure the + // worker may still be running; releasing admission first would let a + // replacement invocation start while the old handler has not yet seen + // its cancellation. + cancel() if cleanupErr := admission.finish(openAttempted, reason); err == nil && cleanupErr != nil { err = cleanupErr } From 5113f7c1be99d2f8cb7e4eb8c19844203f4f6bdd Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 15:55:21 +0800 Subject: [PATCH 140/241] fix(udf): keep native Flight readers on RPC thread --- pkg/udf/python/worker/test_worker.py | 60 +++++++++++++++++--- pkg/udf/python/worker/worker.py | 83 ++++++++++++++++++++-------- 2 files changed, 114 insertions(+), 29 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 037fb08d6156d..c37e5677d5db1 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -655,15 +655,32 @@ def test_worker_rejects_a_tuple_from_another_instance(self): with self.assertRaisesRegex(ValueError, "invalid worker lease epoch"): worker.RoutineFlightServer("grpc://127.0.0.1:0", lease_epoch=0) - @unittest.skipUnless(os.name == "posix", "Flight shutdown cancellation test") - def test_flight_shutdown_cancels_an_active_exchange(self): + @unittest.skipUnless(os.name == "posix", "Flight shutdown reader lifetime test") + def test_flight_shutdown_does_not_race_native_input_reader(self): + """A native Flight reader must finish before its RPC is destroyed. + + FlightServerBase.shutdown waits for active callbacks; it does not + cancel a client that still owns the input direction. Close that + direction first, then shut down the server and verify the exchange + has no leftover native reader or ledger owner. The real client-side + cancellation path is covered by the Gateway integration test. + """ entered = threading.Event() + reader_closed = threading.Event() + adapters = [] original_reader = worker._ExchangeInputReader class NotifyingReader(original_reader): def __init__(self, reader): entered.set() super().__init__(reader) + adapters.append(self) + + def close(self): + try: + return super().close() + finally: + reader_closed.set() server = worker.RoutineFlightServer("grpc://127.0.0.1:0") client = flight.FlightClient(("127.0.0.1", server.port)) @@ -716,6 +733,26 @@ def control(kind, **fields): options=flight.FlightCallOptions(timeout=5), ) self.assertTrue(entered.wait(2), "exchange did not reach its input reader") + self.assertEqual(1, len(adapters)) + self.assertIsNone( + adapters[0]._thread, + "native Flight reader must stay on the RPC callback thread", + ) + # FlightServerBase.shutdown does not cancel an active client + # RPC. Close the client channel first; this is the same + # transport cancellation used by Gateway.Close and lets the + # native reader finish on its owning callback thread. + try: + writer.close() + except Exception: + # EndInput is intentionally omitted here; the worker may + # report the protocol error while closing the stream. + pass + client.close() + self.assertTrue( + reader_closed.wait(2), + "client cancellation did not finish the native reader", + ) def shutdown(): try: @@ -2385,7 +2422,10 @@ def test_worker_death_reaps_handler_process_group(self): "import json, os, pathlib, subprocess, sys, time\n" "def f(ctx, x):\n" f" child = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(60)'], stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)\n" - f" pathlib.Path({str(marker)!r}).write_text(json.dumps(dict(handler_pid=os.getpid(), child_pid=child.pid, pgid=os.getpgrp())))\n" + f" marker = pathlib.Path({str(marker)!r})\n" + " temporary = marker.with_suffix('.tmp')\n" + " temporary.write_text(json.dumps(dict(handler_pid=os.getpid(), child_pid=child.pid, pgid=os.getpgrp())))\n" + " os.replace(temporary, marker)\n" " time.sleep(60)\n" " return x\n" )!r}, @@ -2457,7 +2497,7 @@ def test_worker_death_reaps_descendant_after_handler_leader_exits(self): with tempfile.TemporaryDirectory(prefix="mo-udf-leader-exit-") as artifact: marker = pathlib.Path(artifact) / "handler-and-watchdog.json" relay_source = f''' -import importlib.util, json, pathlib, pyarrow as pa, sys, time +import importlib.util, json, os, pathlib, pyarrow as pa, sys, time worker_path = pathlib.Path({str(WORKER_PATH)!r}) spec = importlib.util.spec_from_file_location("relay_worker_leader_exit", worker_path) worker = importlib.util.module_from_spec(spec) @@ -2470,7 +2510,10 @@ def test_worker_death_reaps_descendant_after_handler_leader_exits(self): "import json, os, pathlib, subprocess, sys\n" "def f(ctx, x):\n" f" child = subprocess.Popen([sys.executable, '-c', 'import time; time.sleep(60)'])\n" - f" pathlib.Path({str(marker)!r}).write_text(json.dumps(dict(handler_pid=os.getpid(), child_pid=child.pid, pgid=os.getpgrp())))\n" + f" marker = pathlib.Path({str(marker)!r})\n" + " temporary = marker.with_suffix('.tmp')\n" + " temporary.write_text(json.dumps(dict(handler_pid=os.getpid(), child_pid=child.pid, pgid=os.getpgrp())))\n" + " os.replace(temporary, marker)\n" " os._exit(7)\n" )!r}, "handler": "f", "mode": worker.MODE_SCALAR, "null_policy": worker.NULL_CALL, @@ -2482,9 +2525,12 @@ def test_worker_death_reaps_descendant_after_handler_leader_exits(self): try: session.run(None, request, 60) except Exception: - payload = json.loads(pathlib.Path({str(marker)!r}).read_text()) + marker = pathlib.Path({str(marker)!r}) + payload = json.loads(marker.read_text()) payload["watchdog_pid"] = session._watchdog_process.pid - pathlib.Path({str(marker)!r}).write_text(json.dumps(payload)) + temporary = marker.with_suffix('.watchdog.tmp') + temporary.write_text(json.dumps(payload)) + os.replace(temporary, marker) time.sleep(60) ''' relay = subprocess.Popen( diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index a277b0c8bd087..266e4e89795eb 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -2276,15 +2276,22 @@ def is_cancelled(self) -> bool: class _ExchangeInputReader: - """Make a blocking Flight input read observable to cancellation. - - ``FlightStreamReader.read_chunk`` is a blocking native call. Polling the - Flight context around that call is insufficient: a cancelled RPC can - remain stuck in the native reader and therefore keep the invocation, its - handler, and its ledger entry alive. Keep at most one chunk in flight and - interrupt the native reader through its cancellation API when the server - context is cancelled. The reader thread is bounded by the admitted - exchange, and is joined before the exchange returns. + """Read Flight input without letting native reader ownership escape. + + The reader passed to a Flight server callback is a PyArrow C++ object whose + lifetime is owned by the RPC. It must be read by the callback thread: a + daemon thread that is still inside ``read_chunk`` when + ``FlightServerBase.shutdown`` destroys the RPC can dereference a freed + native reader and crash the worker. The Flight implementation itself + interrupts a direct ``read_chunk`` when the RPC is cancelled. A + ``FlightServerBase.shutdown`` waits for an open input RPC; it is not a + cancellation mechanism, so the owner must cancel the client exchange (or + terminate the worker process) before waiting for server shutdown. + + Some contract tests and non-native adapters expose an explicit + ``cancel``/``close`` operation but do not have Flight's RPC cancellation + semantics. Keep the bounded polling thread only for those cooperative + readers. Never use it for a reader from PyArrow's native Flight module. """ _POLL_SECONDS = 0.05 @@ -2293,12 +2300,31 @@ def __init__(self, reader): self._reader = reader self._stop = threading.Event() self._items = queue.Queue(maxsize=1) - self._thread = threading.Thread( - target=self._read_loop, - name="matrixone-udf-flight-reader", - daemon=True, - ) - self._thread.start() + self._thread = None + self._native_cancel = self._find_cancel(reader) + if not self._is_native_flight_reader(reader) and self._native_cancel is not None: + self._thread = threading.Thread( + target=self._read_loop, + name="matrixone-udf-flight-reader", + daemon=True, + ) + self._thread.start() + + @staticmethod + def _is_native_flight_reader(reader): + # PyArrow exposes the server-side reader as a private extension type + # (currently MetadataRecordBatchReader). The module check is kept at + # this narrow boundary so the execution path does not depend on a + # particular private class name across supported PyArrow releases. + return type(reader).__module__.startswith("pyarrow._flight") + + @staticmethod + def _find_cancel(reader): + cancel = getattr(reader, "cancel", None) + if callable(cancel): + return cancel + close = getattr(reader, "close", None) + return close if callable(close) else None def _publish(self, kind, value=None): item = (kind, value) @@ -2323,18 +2349,29 @@ def _read_loop(self): self._publish("error", exc) def _cancel_native_reader(self): - cancel = getattr(self._reader, "cancel", None) - if not callable(cancel): - cancel = getattr(self._reader, "close", None) - if callable(cancel): + if self._native_cancel is not None: try: - cancel() + self._native_cancel() except Exception: - # The RPC is already being torn down. The join below still - # verifies whether the native read actually returned. + # The RPC may already be tearing down. The join below still + # verifies whether a cooperative reader actually returned. pass def next(self, context): + if self._thread is None: + if _context_is_cancelled(context): + self.cancel() + raise TimeoutError("DEADLINE_EXCEEDED: input stream cancelled") + try: + chunk = self._reader.read_chunk() + except StopIteration: + if _context_is_cancelled(context): + raise TimeoutError("DEADLINE_EXCEEDED: input stream cancelled") + raise + if _context_is_cancelled(context): + self.cancel() + raise TimeoutError("DEADLINE_EXCEEDED: input stream cancelled") + return chunk while True: if _context_is_cancelled(context): self.cancel() @@ -2355,6 +2392,8 @@ def cancel(self): def close(self): self.cancel() + if self._thread is None: + return self._thread.join(timeout=1.0) if self._thread.is_alive(): raise ValueError( From a576b9eb9d328bd7df50264d953d150425359e32 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 16:05:29 +0800 Subject: [PATCH 141/241] fix(udf): distinguish expected worker shutdown --- pkg/udf/python/supervisor.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/supervisor.go b/pkg/udf/python/supervisor.go index 815433db35be7..b16df8411e752 100644 --- a/pkg/udf/python/supervisor.go +++ b/pkg/udf/python/supervisor.go @@ -84,6 +84,7 @@ func (s *Supervisor) Start() error { func (s *Supervisor) wait(cmd *exec.Cmd, done chan struct{}) { err := cmd.Wait() + unplanned := false s.mu.Lock() if s.cmd == cmd { // Keep the terminal state transition and Done close under the same lock. @@ -93,10 +94,14 @@ func (s *Supervisor) wait(cmd *exec.Cmd, done chan struct{}) { // worker. s.cmd = nil s.lastErr = err + // Close marks the supervisor as closing before killing the process + // group. Keep the exit error available through Err(), but do not report + // an intentional SIGKILL as an unexpected worker failure. + unplanned = !s.closing } close(done) s.mu.Unlock() - if err != nil { + if err != nil && unplanned { logutil.Errorf("Python UDF worker exited: %v", err) } } From cae4e3a34899dc9af66cd78e2c3c61a062f75029 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 16:13:00 +0800 Subject: [PATCH 142/241] fix(udf): complete handler response frame writes --- pkg/udf/python/worker/test_worker.py | 20 ++++++++++++++++++++ pkg/udf/python/worker/worker.py | 25 +++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index c37e5677d5db1..eedb77337082f 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1745,6 +1745,26 @@ def test_handler_response_frame_parts_keep_one_wire_frame(self): ) self.assertEqual(struct.pack(">Q", 4) + b"\x01abc", stream.getvalue()) + def test_handler_response_frame_parts_handle_short_writes(self): + class ShortWriter: + def __init__(self): + self.data = bytearray() + + def write(self, value): + value = bytes(value) + count = max(1, len(value) // 2) + self.data.extend(value[:count]) + return count + + def flush(self): + return None + + stream = ShortWriter() + worker._write_execution_frame_parts(stream, (b"\x01", b"abcdef")) + self.assertEqual( + struct.pack(">Q", 7) + b"\x01abcdef", bytes(stream.data) + ) + def test_handler_process_accepts_schema_free_record_batch_messages(self): descriptor = {"type_id": worker.INT64, "offset_width": 32} schema = worker._schema_from_descriptors([descriptor], "arg") diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 266e4e89795eb..300b3e54877da 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -2020,14 +2020,35 @@ def _read_exact(stream, size: int) -> bytearray: return result +def _write_all(stream, data) -> None: + """Write one frame component completely to a byte stream. + + The handler response channel is a pipe-backed ``FileIO`` object. A + blocking write normally transfers all bytes, but the file API still + permits a short write (for example when a signal interrupts a large + transfer). Treating that count as success would publish a truncated + length-prefixed frame and desynchronize every later response. + """ + view = memoryview(data) + try: + offset = 0 + while offset < len(view): + written = stream.write(view[offset:]) + if not isinstance(written, int) or written <= 0 or written > len(view) - offset: + raise OSError("execution frame stream made no valid progress") + offset += written + finally: + view.release() + + def _write_execution_frame_parts(stream, parts: Iterable[bytes]) -> None: parts = tuple(parts) payload_size = sum(len(part) for part in parts) if payload_size > MAX_EXECUTION_FRAME_BYTES: raise ValueError("RESOURCE_EXHAUSTED: execution frame is too large") - stream.write(struct.pack(">Q", payload_size)) + _write_all(stream, struct.pack(">Q", payload_size)) for part in parts: - stream.write(part) + _write_all(stream, part) stream.flush() From d8bb5e6b28b9a469ca9d0c481fc7322312c45d77 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 16:15:41 +0800 Subject: [PATCH 143/241] fix(udf): validate handler binding before loading --- pkg/udf/python/worker/test_worker.py | 16 ++++++++++++++++ pkg/udf/python/worker/worker.py | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index eedb77337082f..01099334f9761 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -785,6 +785,22 @@ def test_inline_contract_rejects_external_handler_import(self): with self.assertRaisesRegex(ValueError, "immutable artifact catalog"): worker._load_handler("def add(ctx, value): return value", "module:add") + def test_handler_load_revalidates_static_binding_before_exec(self): + with tempfile.TemporaryDirectory(prefix="mo-udf-handler-load-") as directory: + marker = pathlib.Path(directory) / "executed" + source = ( + "from pathlib import Path\n" + f"Path({str(marker)!r}).write_text('executed')\n" + "def f(ctx, value): return value\n" + "f = 1\n" + ) + with self.assertRaisesRegex(ValueError, "not a module-level function"): + worker._load_handler(source, "f") + self.assertFalse( + marker.exists(), + "execution must reject invalid handler binding before running module code", + ) + def test_go_python_type_descriptor_fixtures(self): fixture_path = WORKER_PATH.parent.parent / "testdata" / "type_descriptors.json" fixtures = json.loads(fixture_path.read_text()) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 300b3e54877da..94cb90e2d1f76 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1535,6 +1535,11 @@ def _load_handler(source: str, handler: str): raise ValueError( "UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog" ) + # CREATE validates the source without executing it, but execution may be + # reached through a direct Flight request or a stale/malformed caller. + # Reapply the static binding contract before exec so invalid module-level + # rebinding cannot run top-level user code before being rejected. + _validate_definition_syntax({"source": source, "handler": handler}) namespace: Dict[str, Any] = {"__name__": "__matrixone_routine__"} exec(compile(source, "", "exec"), namespace, namespace) function = namespace.get(handler) From 186a00d62f97fd75a414b672e36ca81cd45445e7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 16:19:00 +0800 Subject: [PATCH 144/241] fix(udf): kill handler groups before reaping leaders --- pkg/udf/python/worker/test_worker.py | 16 ++++++++++++++ pkg/udf/python/worker/worker.py | 31 ++++++++++++++++++---------- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 01099334f9761..53bf45c749004 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -2020,6 +2020,22 @@ def test_process_cleanup_falls_back_to_owned_leader_on_group_permission_error(se process.kill.assert_called_once_with() process.wait.assert_called_once_with(timeout=1.0) + @unittest.skipUnless(os.name == "posix", "process-group cleanup after leader exit") + def test_process_cleanup_kills_group_before_reaping_exited_leader(self): + process = mock.Mock(pid=1234) + process.poll.return_value = 7 + process.wait.return_value = 7 + + with mock.patch.object(worker.os, "killpg", side_effect=[None, None]) as killpg: + worker._kill_execution_process(process) + + self.assertEqual( + [mock.call(1234, 0), mock.call(1234, worker.signal.SIGKILL)], + killpg.call_args_list, + ) + process.kill.assert_not_called() + process.wait.assert_called_once_with(timeout=1.0) + def test_handler_close_retains_process_for_a_later_cleanup_retry(self): session = object.__new__(worker._HandlerProcessSession) session._slots = threading.BoundedSemaphore(1) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 94cb90e2d1f76..7c290d73346e1 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -2426,14 +2426,16 @@ def close(self): "RESOURCE_EXHAUSTED: Flight input reader did not stop after cancellation" ) def _kill_execution_process(process: subprocess.Popen) -> None: - # The leader can already have exited while one of its descendants keeps - # the execution alive. The session closes the worker-owned liveness pipe - # before calling this helper, so the watchdog owns that leader-exited - # case. Do not call killpg with a reaped PID: macOS may have already - # reused the process-group id and returns EPERM (or could address an - # unrelated group). An un-reaped leader is still killed as a group. + # Check the process group before reaping the leader. A handler can exit + # while a descendant keeps the group alive; polling first would reap the + # leader and skip killpg, leaving that descendant behind until the + # asynchronous watchdog happens to run. Before process.poll() reaps the + # leader, its PID is still owned by this session and the group identity + # cannot have been reused. if os.name == "posix": - if process.poll() is None: + group_alive = _execution_group_alive(process) + leader_alive = process.poll() is None + if group_alive: try: os.killpg(process.pid, signal.SIGKILL) except ProcessLookupError: @@ -2444,10 +2446,17 @@ def _kill_execution_process(process: subprocess.Popen) -> None: # Kill the Popen child directly so the handler slot is not # stranded; the parent-liveness watchdog remains responsible # for descendants when the group cannot be addressed here. - try: - process.kill() - except ProcessLookupError: - pass + if leader_alive: + try: + process.kill() + except ProcessLookupError: + pass + else: + raise + elif leader_alive: + # The group disappeared in the small race between the liveness + # probe and poll(); still make sure the owned leader is stopped. + process.kill() elif process.poll() is None: process.kill() try: From e59a54c1388f2ddded9537a4dba38e051b20a9fc Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 16:20:28 +0800 Subject: [PATCH 145/241] fix(udf): reject stale result acknowledgements --- pkg/udf/python/worker/test_worker.py | 10 ++++++++++ pkg/udf/python/worker/worker.py | 18 ++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 53bf45c749004..5dd82d43f60c2 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -3730,6 +3730,16 @@ def test_cancellation_after_accepted_finish_ack_keeps_success_idempotent(self): state.ack_finish("finish-race") self.assertEqual(worker._TERMINAL_SUCCESS, state.freeze_terminal()) + def test_frozen_success_rejects_stale_result_ack(self): + state = worker._InvocationState({}, 128) + state.last_result = 2 + state.mark_finish_sent("finish-stale-result") + state.ack_finish("finish-stale-result") + self.assertEqual(worker._TERMINAL_SUCCESS, state.freeze_terminal()) + with self.assertRaisesRegex(ValueError, "completed result"): + state.ack_result(1) + state.ack_result(2) + def test_cancelled_terminal_is_frozen_and_rejects_late_ack(self): server = worker.RoutineFlightServer("grpc://127.0.0.1:0") key = (1, "statement", "cancel-group", 1, "cancelled", 1) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 7c290d73346e1..fd79b97aace0a 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -3087,10 +3087,20 @@ def ack_result(self, sequence: int) -> None: with self.condition: if self.cancelled: raise ValueError("PROTOCOL: invocation terminal outcome is CANCELLED") - if self.terminal_outcome is not None and self.terminal_outcome != _TERMINAL_SUCCESS: - raise ValueError( - f"PROTOCOL: invocation terminal outcome is {self.terminal_outcome}" - ) + if self.terminal_outcome is not None: + if self.terminal_outcome != _TERMINAL_SUCCESS: + raise ValueError( + f"PROTOCOL: invocation terminal outcome is {self.terminal_outcome}" + ) + # An action can retain a state reference while cleanup moves + # that state to the terminal ledger. Once SUCCESS is frozen, + # only the final result sequence is an idempotent confirmation; + # accepting an earlier cumulative ACK would bypass the + # terminal ledger's exact-fence rule. + if sequence != self.last_result: + raise ValueError( + "PROTOCOL: terminal result ACK does not match the completed result" + ) if sequence <= 0 or sequence < self.acked_result or sequence > self.last_result: raise ValueError("PROTOCOL: result ACK is outside the received range") self.acked_result = sequence From f2c097da3264db3723fb515f14fafdd2e705fd02 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 17:54:41 +0800 Subject: [PATCH 146/241] fix(udf): close Docker contract gaps --- pkg/frontend/authenticate.go | 2 +- pkg/frontend/python_udf_catalog_test.go | 31 +++++++++++++++++++ pkg/sql/plan/function/udf.go | 12 +++++++ pkg/sql/plan/function/udf_test.go | 6 ++++ pkg/udf/python/worker/Dockerfile | 18 +++++++++++ .../cases/udf_python/udf_python.result | 14 +++++++++ 6 files changed, 82 insertions(+), 1 deletion(-) diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index c26333b15b3a4..a63110a0c428d 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -12406,7 +12406,7 @@ func normalizePythonFunctionDefinition(definition userDefinedFunctionDefinition) } expectedLogicalTypes := make([]string, len(body.ArgTypes)) for index, descriptor := range body.ArgTypes { - expectedLogicalTypes[index] = strings.ToLower(descriptor.Type().Oid.String()) + expectedLogicalTypes[index] = function.PythonCatalogTypeName(descriptor.Type()) } expectedLogicalArgTypes, err := userDefinedFunctionArgumentTypes(expectedLogicalTypes) if err != nil { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index cde653e5b4936..118a96b2ce759 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -314,6 +314,37 @@ func TestNormalizePythonDefinitionDerivesLogicalSignatureFromTypedBody(t *testin require.Equal(t, `["int"]`, normalized.argTypes) } +func TestNormalizePythonDefinitionAcceptsDecimalLogicalAlias(t *testing.T) { + descriptor, err := function.NewPythonTypeDescriptor(types.New(types.T_decimal128, 38, 10)) + require.NoError(t, err) + source := "def f(ctx, value): return value" + environment, err := udf.PythonEnvironmentDigest() + require.NoError(t, err) + body, err := json.Marshal(function.PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: "f", + Source: source, + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + ArtifactDigest: udf.PythonInlineArtifactDigest("f", source), + EnvironmentDigest: environment, + SDKVersion: udf.PythonSDKVersion, + ArgTypes: []function.PythonTypeDescriptor{descriptor}, + ReturnType: &descriptor, + }) + require.NoError(t, err) + + normalized, err := normalizePythonFunctionDefinition(userDefinedFunctionDefinition{ + args: `[{"name":"value","type":"decimal"}]`, + retType: "decimal", + body: string(body), + }) + require.NoError(t, err) + require.Equal(t, `["decimal"]`, normalized.argTypes) +} + func TestPersistPythonCreateIdentityLookupIncludesLanguage(t *testing.T) { definition := userDefinedFunctionDefinition{ name: "python_identity", diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index 7a79b9d41476a..5e993968aca08 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -539,6 +539,18 @@ func pythonCatalogTypeNameMatches(name string, oid types.T) bool { return name == strings.ToLower(oid.String()) } +// PythonCatalogTypeName returns the logical type name stored in the shared +// catalog signature columns for a Python descriptor. The exact width and +// scale remain in the typed descriptor; the historical logical namespace +// intentionally represents both supported decimal physical widths as +// "decimal". +func PythonCatalogTypeName(typ types.Type) string { + if typ.Oid == types.T_decimal64 || typ.Oid == types.T_decimal128 { + return "decimal" + } + return strings.ToLower(typ.Oid.String()) +} + func validatePythonTypeDescriptor(descriptor PythonTypeDescriptor) error { typ := descriptor.Type() canonical, err := NewPythonTypeDescriptor(typ) diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go index 6015e1a3fd12d..f7e969cbb8c80 100644 --- a/pkg/sql/plan/function/udf_test.go +++ b/pkg/sql/plan/function/udf_test.go @@ -104,6 +104,12 @@ func TestPythonUdfArgTypeCastKeepsDeclaredDescriptorForSameOID(t *testing.T) { require.Nil(t, PythonUdfArgTypeCast([]types.Type{source}, nil)) } +func TestPythonCatalogTypeNamePreservesLogicalDecimalAlias(t *testing.T) { + require.Equal(t, "decimal", PythonCatalogTypeName(types.New(types.T_decimal64, 18, 2))) + require.Equal(t, "decimal", PythonCatalogTypeName(types.New(types.T_decimal128, 38, 10))) + require.Equal(t, "bigint", PythonCatalogTypeName(types.T_int64.ToType())) +} + func TestPythonCatalogSignatureRejectsLogicalDescriptorDrift(t *testing.T) { argument, err := NewPythonTypeDescriptor(types.T_int64.ToType()) require.NoError(t, err) diff --git a/pkg/udf/python/worker/Dockerfile b/pkg/udf/python/worker/Dockerfile index 0a3aab23067dc..f2403bec94263 100644 --- a/pkg/udf/python/worker/Dockerfile +++ b/pkg/udf/python/worker/Dockerfile @@ -2,8 +2,21 @@ # docker build -t mo-python-udf-worker -f ./pkg/udf/python/worker/Dockerfile ./pkg/udf/python/worker/ # docker run -d --network host mo-python-udf-worker +# Keep the worker's IANA database identical to the MatrixOne runtime image. +# The Python and Go base images are allowed to differ in language/runtime +# versions, but an IANA version mismatch would make the capability handshake +# reject the worker or, worse, let an IANA timezone resolve differently on +# the two sides of the boundary. +FROM matrixorigin/ubuntu:22.04 AS matrixone-tzdata + +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata \ + && rm -rf /var/lib/apt/lists/* + FROM python:3.12-slim-bookworm +COPY --from=matrixone-tzdata /usr/share/zoneinfo/ /usr/share/zoneinfo/ + RUN useradd -m -s /bin/bash mo WORKDIR /home/mo @@ -18,6 +31,11 @@ COPY requirements.txt worker.py watchdog.py ./ RUN pip install --no-cache-dir -r requirements.txt +# Fail the image build if the shared tzdata source was not copied into the +# worker image. The Go side performs the same version check at capability +# admission; this makes a broken worker image fail at build time as well. +RUN python -c 'from pathlib import Path; import worker; version = Path("/usr/share/zoneinfo/tzdata.zi").read_text(encoding="utf-8").splitlines()[0].removeprefix("# version ").strip(); assert version and version == worker.TIMEZONE_DATABASE_VERSION, (version, worker.TIMEZONE_DATABASE_VERSION)' + USER mo EXPOSE 50051 diff --git a/test/distributed/cases/udf_python/udf_python.result b/test/distributed/cases/udf_python/udf_python.result index 8534ba2ba2c2d..3f0984316c0bf 100644 --- a/test/distributed/cases/udf_python/udf_python.result +++ b/test/distributed/cases/udf_python/udf_python.result @@ -14,6 +14,20 @@ select case when v is null then 99 else python_bvt_add(v) end as guarded from in 2 𝄀 4 𝄀 99 +create function python_bvt_bad_syntax (x int) returns int language python as 'def python_bvt_bad_syntax(ctx, x) return x' handler 'python_bvt_bad_syntax'; +-- @regex("Python syntax error at line", true) +USER_CODE: Python syntax error at line 1, column 35: expected ':' +create function python_bvt_replace (x int) returns int language python as 'def python_bvt_replace(ctx, x): return x + 10' handler 'python_bvt_replace'; +select python_bvt_replace(1); +➤ python_bvt_replace(1)[4,32,0] 𝄀 +11 +create or replace function python_bvt_replace (x int) returns int language python as 'def python_bvt_replace(ctx, x) return x + 20' handler 'python_bvt_replace'; +-- @regex("Python syntax error at line", true) +USER_CODE: Python syntax error at line 1, column 32: expected ':' +select python_bvt_replace(1); +➤ python_bvt_replace(1)[4,32,0] 𝄀 +11 drop function python_bvt_add(int); +drop function python_bvt_replace(int); drop table input_values; drop database udf_python_bvt; From 1cb0a5fe6565a25dc9aaac4741ae0b547abacd35 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 15 Sep 2026 17:58:20 +0800 Subject: [PATCH 147/241] refactor(udf): centralize logical type mapping --- pkg/sql/plan/function/udf.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index 5e993968aca08..ae19eb8c94de0 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -533,10 +533,7 @@ func (u *Udf) ValidatePythonCatalogSignature() error { func pythonCatalogTypeNameMatches(name string, oid types.T) bool { name = strings.ToLower(strings.TrimSpace(name)) - if name == "decimal" { - return oid == types.T_decimal64 || oid == types.T_decimal128 - } - return name == strings.ToLower(oid.String()) + return name == PythonCatalogTypeName(types.Type{Oid: oid}) } // PythonCatalogTypeName returns the logical type name stored in the shared From e453e7f7131ce048faf24c4317b0c7c01f53c373 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 16 Sep 2026 10:50:13 +0800 Subject: [PATCH 148/241] fix(udf): preserve legacy python heads on restore --- pkg/frontend/python_udf_catalog_test.go | 42 ++++++++++++++++++++++++ pkg/frontend/snapshot_catalog_restore.go | 7 ++-- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 118a96b2ce759..c2cd6c78d87ee 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -873,6 +873,48 @@ func TestValidateRestoredPythonCatalogHeadsBindsIdentityToActiveRevision(t *test ) } +func TestValidateRestoredLegacyPythonHeadIsPreservedButInert(t *testing.T) { + query := `select cast(f.function_id as char), cast(f.active_revision as char), cast(f.namespace_version as char), + cast(coalesce(r.revision, 0) as char), cast(coalesce(r.namespace_version, 0) as char), + f.canonical_input_descriptor, f.return_descriptor, + cast(f.signature_key_schema_version as char), f.signature_fingerprint, + coalesce(r.arg_types, ''), coalesce(r.rettype, ''), coalesce(r.body, ''), + lower(f.language), coalesce(r.definition_fingerprint, ''), + coalesce(r.security_type, ''), coalesce(f.security_type, '') + from mo_catalog.mo_user_defined_function f + left join mo_catalog.mo_function_revisions r + on r.function_id = f.function_id and r.revision = f.active_revision + and r.namespace_version = f.namespace_version + where lower(f.language) in ("python", "sql") + order by f.function_id;` + legacy := func(active, namespace string) *MysqlResultSet { + result := &MysqlResultSet{} + for index := 0; index < 16; index++ { + column := &MysqlColumn{} + column.SetName(fmt.Sprintf("column_%d", index)) + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + result.AddColumn(column) + } + result.AddRow([]interface{}{ + "46", active, namespace, "0", "0", "", "", "0", "", "", "", "", + string(tree.PYTHON), "", "INVOKER", "INVOKER", + }) + return result + } + + b := &backgroundExecTest{} + b.init() + b.sql2result[query] = legacy("0", "0") + require.NoError(t, validateRestoredFunctionCatalogHeads(context.Background(), b, context.Background())) + + b.init() + b.sql2result[query] = legacy("1", "0") + require.ErrorContains(t, + validateRestoredFunctionCatalogHeads(context.Background(), b, context.Background()), + "invalid namespace version", + ) +} + func TestValidateRestoredSharedCatalogHeadsChecksSQLRevision(t *testing.T) { args := `[ {"name":"value","type":"bigint"} ]` argTypes, err := userDefinedFunctionArgumentTypesFromJSON(args) diff --git a/pkg/frontend/snapshot_catalog_restore.go b/pkg/frontend/snapshot_catalog_restore.go index 9e7b60658fd62..d2d90f8f74f34 100644 --- a/pkg/frontend/snapshot_catalog_restore.go +++ b/pkg/frontend/snapshot_catalog_restore.go @@ -336,9 +336,12 @@ func validateRestoredFunctionCatalogHeads( return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored routine function %d has an invalid namespace version: %v", functionID, err) } language := strings.ToLower(row[12]) - if language == udf.LanguageSQL && activeRevision == 0 && namespaceVersion == 0 { + if (language == udf.LanguageSQL || language == udf.LanguagePython) && activeRevision == 0 && namespaceVersion == 0 { // Legacy SQL rows predate the shared revision table and retain their - // old execution path. A current SQL head is validated below. + // old execution path. Legacy Python demo rows are preserved as inert + // catalog data as well: the current Python resolver has no execution + // path for them and rejects them before user code, while DROP/CREATE + // can replace the row explicitly. A current head is validated below. continue } if activeRevision == 0 { From 7d64889a9c87c95f094a7d6bc4fd568d82a6d101 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 16 Sep 2026 10:54:20 +0800 Subject: [PATCH 149/241] fix(udf): enforce descriptor validity at result boundaries --- pkg/udf/python/arrow.go | 7 +++++++ pkg/udf/python/arrow_test.go | 16 ++++++++++++++++ pkg/udf/python/worker/test_worker.py | 10 ++++++++++ pkg/udf/python/worker/worker.py | 5 +++++ 4 files changed, 38 insertions(+) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 0185f4ec768b5..b3217761c53f7 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -1249,6 +1249,13 @@ func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vect if result == nil { return fmt.Errorf("python udf: missing result wrapper") } + // AppendArrowResult is also the public adapter boundary used by runtimes + // other than the Flight Gateway. Do not let an invalid manually-built + // descriptor become executable merely because its Arrow physical type can + // be constructed (for example DECIMAL64 precision 19). + if err := descriptor.Validate(); err != nil { + return err + } if err := validateArrayType(descriptor, input); err != nil { return err } diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 4b1b3de7c1400..fecb17e389558 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -299,6 +299,22 @@ func TestAppendArrowResultValidatesEmptyArrayType(t *testing.T) { require.ErrorContains(t, AppendArrowResult(descriptor, values, result, mp), "Arrow type") } +func TestAppendArrowResultRejectsInvalidSemanticDescriptor(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + result := vector.NewFunctionResultWrapper(types.T_decimal64.ToType(), mp) + defer result.Free() + + decimalType := &arrow.Decimal128Type{Precision: 19, Scale: 0} + builder := array.NewDecimal128Builder(memory.NewGoAllocator(), decimalType) + builder.Append(decimal128.FromI64(1)) + values := builder.NewDecimal128Array() + defer values.Release() + + descriptor := TypeDescriptor{TypeID: int32(types.T_decimal64), Width: 19, OffsetWidth: 32} + require.ErrorContains(t, AppendArrowResult(descriptor, values, result, mp), "decimal precision") +} + func TestZeroArgumentRecordPreservesRows(t *testing.T) { record := array.NewRecordBatch(arrow.NewSchema(nil, nil), nil, 3) defer record.Release() diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 5dd82d43f60c2..7986563889d87 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1196,6 +1196,16 @@ def test_decimal_precision_and_vector_child_validity_are_checked(self): visible = valid.slice(1, 1) self.assertEqual(visible.to_pylist(), worker._output_array(visible, vector_descriptor, 1).to_pylist()) + def test_output_array_rejects_invalid_semantic_descriptor(self): + descriptor = { + "type_id": worker.DECIMAL64, + "width": 19, + "scale": 0, + "offset_width": 32, + } + with self.assertRaisesRegex(ValueError, "precision is outside"): + worker._output_array([__import__("decimal").Decimal("1")], descriptor, 1) + def test_descriptor_rejects_unused_domain_fields(self): invalid = [ {"type_id": worker.DATE, "width": 1, "offset_width": 32, "temporal_encoding": "sql_zero_struct"}, diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index fd79b97aace0a..047d2dc5fdb12 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -1749,6 +1749,11 @@ def _temporal_array(values: list, descriptor: Dict[str, Any]) -> pa.Array: def _output_array(values: Any, descriptor: Dict[str, Any], rows: int) -> pa.Array: + # Keep this helper safe when called directly by a runtime adapter or a + # conformance harness. The normal exchange path validates the Open payload + # first, but _arrow_type alone can construct a physical type for an + # invalid semantic descriptor (for example DECIMAL64 precision 19). + _canonical_descriptor(descriptor) if isinstance(values, pa.ChunkedArray): values = values.combine_chunks() if isinstance(values, pa.Array): From 897adff6a59e57e421ab43d4cb5c574a6f334d95 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 16 Sep 2026 11:04:58 +0800 Subject: [PATCH 150/241] fix(udf): cancel gateway operations on close --- pkg/udf/python/gateway.go | 50 +++++++++++++++++++++++++------- pkg/udf/python/gateway_test.go | 53 ++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 10 deletions(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 8dd8169199b77..45ff234ec5a4c 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -64,6 +64,8 @@ type Gateway struct { conn *grpc.ClientConn flight flight.FlightServiceClient mu sync.Mutex + lifecycleCtx context.Context + lifecycleCancel context.CancelFunc capabilityMu sync.Mutex admissionMu sync.Mutex capabilityReady bool @@ -139,10 +141,13 @@ func newGateway(cfg ClientConfig, resolver ArtifactResolver, allowInlineSource b if err != nil { return nil, err } + lifecycleCtx, lifecycleCancel := context.WithCancel(context.Background()) return &Gateway{ cfg: cfg, artifactResolver: resolver, allowInlineSource: allowInlineSource, + lifecycleCtx: lifecycleCtx, + lifecycleCancel: lifecycleCancel, active: make(chan struct{}, cfg.MaxActiveInvocations), ledger: ledger, ledgerTTL: cfg.TerminalRecordTTL, @@ -168,6 +173,8 @@ func (g *Gateway) CheckLanguageReady(ctx context.Context, language string) error if !g.cfg.AllowUnisolated { return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") } + requestCtx, release := g.withLifecycleContext(ctx) + defer release() client, err := g.flightClient() if err != nil { return err @@ -175,7 +182,7 @@ func (g *Gateway) CheckLanguageReady(ctx context.Context, language string) error // Readiness is an external admission decision. Refresh the worker // capability record so a worker replacement at the same endpoint cannot // inherit a stale success from the previous process. - return g.ensureCapabilities(ctx, client, true) + return g.ensureCapabilities(requestCtx, client, true) } // ValidateDefinition asks the current worker to compile the exact artifact @@ -197,13 +204,11 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin if !g.cfg.AllowUnisolated { return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") } - if ctx == nil { - ctx = context.Background() - } - requestCtx := ctx + requestCtx, release := g.withLifecycleContext(ctx) + defer release() var cancel context.CancelFunc if g.cfg.RequestTimeout > 0 { - requestCtx, cancel = context.WithTimeout(ctx, g.cfg.RequestTimeout) + requestCtx, cancel = context.WithTimeout(requestCtx, g.cfg.RequestTimeout) defer cancel() } if definition == nil { @@ -415,6 +420,9 @@ func (g *Gateway) Close() error { g.mu.Unlock() return nil } + if g.lifecycleCancel != nil { + g.lifecycleCancel() + } // Serialize the close barrier with group admission. Once this lock is // released, no caller can pass the admission check after Close returns. g.admissionMu.Lock() @@ -433,6 +441,29 @@ func (g *Gateway) Close() error { return conn.Close() } +// withLifecycleContext combines a caller's cancellation with the Gateway +// lifetime. A resolver or a readiness action can run before a Flight stream +// exists, so closing the gRPC connection alone cannot interrupt it. The +// returned release function removes the AfterFunc callback and cancels the +// derived context when the operation completes. +func (g *Gateway) withLifecycleContext(parent context.Context) (context.Context, func()) { + if parent == nil { + parent = context.Background() + } + combined, cancel := context.WithCancel(parent) + g.mu.Lock() + lifecycle := g.lifecycleCtx + g.mu.Unlock() + if lifecycle == nil { + return combined, cancel + } + stop := context.AfterFunc(lifecycle, cancel) + return combined, func() { + stop() + cancel() + } +} + type openPayload struct { FunctionRef udf.FunctionRef `json:"function_ref"` Handler string `json:"handler"` @@ -475,10 +506,9 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if !g.cfg.AllowUnisolated { return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") } - if ctx == nil { - ctx = context.Background() - } - streamCtx, cancel := context.WithTimeout(ctx, g.cfg.RequestTimeout) + requestCtx, release := g.withLifecycleContext(ctx) + defer release() + streamCtx, cancel := context.WithTimeout(requestCtx, g.cfg.RequestTimeout) defer cancel() if invocation == nil || result == nil || mp == nil { return fmt.Errorf("python udf: nil invocation, result, or memory pool") diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index 27102c5cf3e16..9803ec6838849 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -68,6 +68,16 @@ func (blockingArtifactResolver) Resolve(ctx context.Context, _ uint64, _, _ stri return "", ctx.Err() } +type closeBlockingArtifactResolver struct { + started chan struct{} +} + +func (r *closeBlockingArtifactResolver) Resolve(ctx context.Context, _ uint64, _, _ string) (string, error) { + close(r.started) + <-ctx.Done() + return "", ctx.Err() +} + func (r *recordingArtifactResolver) Resolve(_ context.Context, accountID uint64, handler, digest string) (string, error) { r.calls++ r.account = accountID @@ -117,6 +127,49 @@ func TestValidateDefinitionBoundsArtifactResolution(t *testing.T) { } } +func TestGatewayCloseCancelsDefinitionResolution(t *testing.T) { + invocation := validInvocation() + resolver := &closeBlockingArtifactResolver{started: make(chan struct{})} + gateway, err := NewGatewayWithArtifactStore(ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:1", + RequestTimeout: 30 * time.Second, + }, resolver) + require.NoError(t, err) + + definition := &udf.RoutineDefinition{ + Language: udf.LanguagePython, + AccountID: invocation.FunctionRef.AccountID, + Handler: invocation.Handler, + Args: append([]types.Type(nil), invocation.Args...), + ReturnType: invocation.ReturnType, + Mode: invocation.Mode, + NullPolicy: invocation.NullPolicy, + ABIContract: invocation.ABIContract, + AdapterVersion: invocation.AdapterVersion, + SDKVersion: invocation.SDKVersion, + DefinitionSchemaVersion: invocation.DefinitionSchemaVersion, + ArtifactDigest: invocation.ArtifactDigest, + EnvironmentDigest: invocation.EnvironmentDigest, + DefinitionFingerprint: invocation.DefinitionFingerprint, + } + done := make(chan error, 1) + go func() { done <- gateway.ValidateDefinition(context.Background(), definition) }() + select { + case <-resolver.started: + case <-time.After(time.Second): + require.FailNow(t, "artifact resolution did not start") + } + require.NoError(t, gateway.Close()) + select { + case err := <-done: + require.ErrorIs(t, err, context.Canceled) + case <-time.After(time.Second): + require.FailNow(t, "Gateway.Close did not cancel artifact resolution") + } +} + func (c *finishAckFlightClient) DoAction( ctx context.Context, action *flight.Action, From 1954adf5e7744d4012b008048c0fe8e8ee4c8201 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 16 Sep 2026 11:08:55 +0800 Subject: [PATCH 151/241] fix(udf): reject incompatible vector descriptor casts --- pkg/sql/plan/base_binder.go | 5 +---- pkg/sql/plan/function/python_udf.go | 34 +++++++++++++++++++++++++++-- pkg/sql/plan/function/udf_test.go | 18 +++++++++++++++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/pkg/sql/plan/base_binder.go b/pkg/sql/plan/base_binder.go index 5a37bcf197cdb..2d2d51bf9ca5a 100644 --- a/pkg/sql/plan/base_binder.go +++ b/pkg/sql/plan/base_binder.go @@ -5463,10 +5463,7 @@ func (b *baseBinder) bindPythonUdf(udf *function.Udf, astArgs []tree.Expr, depth required := udf.GetArgsType()[idx] actual := makeTypeByPlan2Expr(expr) if !actual.Eq(required) { - canCast, _ := function.UdfArgTypeMatch([]types.Type{actual}, []types.T{required.Oid}) - if actual.Oid == required.Oid { - canCast = true - } + canCast, _ := function.PythonUdfArgTypeMatch([]types.Type{actual}, []types.Type{required}) if !canCast { return nil, moerr.NewInvalidInputf(b.GetContext(), "Python routine argument %d has type %s, expected %s", idx+1, actual.String(), required.String()) } diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index 9f4b54554e78e..ddd7764d6a63f 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -39,8 +39,13 @@ func checkPythonUdf(overloads []overload, inputs []types.Type) checkResult { needCast := false for i := 0; i < size; i++ { if !pythonTypesEqual(receivedArgs[i], requiredArgs[i]) { - canCast, _ := fixedImplicitTypeCast(receivedArgs[i], requiredArgs[i].Oid) + canCast := false if receivedArgs[i].Oid == requiredArgs[i].Oid { + canCast = pythonSameOIDCanNormalize(receivedArgs[i], requiredArgs[i]) + } else { + canCast, _ = fixedImplicitTypeCast(receivedArgs[i], requiredArgs[i].Oid) + } + if canCast && receivedArgs[i].Oid == requiredArgs[i].Oid { // SQL's cast executor is also the type normalizer for Python's // frozen descriptor. In particular, DECIMAL scale and precision // must be normalized before Arrow encoding; comparing only OID @@ -89,12 +94,15 @@ func PythonUdfArgTypeMatch(from, to []types.Type) (bool, int) { if pythonTypesEqual(from[index], to[index]) { continue } - if from[index].Oid == to[index].Oid { + if pythonSameOIDCanNormalize(from[index], to[index]) { // A same-OID descriptor change is a SQL cast to the declared // width/scale. It is valid, but less specific than an exact match. cost++ continue } + if from[index].Oid == to[index].Oid { + return false, -1 + } canCast, castCost := fixedImplicitTypeCast(from[index], to[index].Oid) if !canCast { return false, -1 @@ -108,6 +116,25 @@ func PythonUdfArgTypeMatch(from, to []types.Type) (bool, int) { return true, cost } +// pythonSameOIDCanNormalize reports whether a descriptor change with the same +// SQL OID has a meaningful SQL cast. Fixed-size vector dimensions are part of +// the value shape: the existing array->array cast preserves bytes when the +// element OID is unchanged, so accepting VECF32(4) for VECF32(3) would publish +// a value with a descriptor that lies about its child count. Other supported +// same-OID metadata (decimal precision/scale, text width/charset, and temporal +// scale) is normalized by the ordinary SQL cast executor. +func pythonSameOIDCanNormalize(from, to types.Type) bool { + if from.Oid != to.Oid || pythonTypesEqual(from, to) { + return false + } + switch from.Oid { + case types.T_array_float32, types.T_array_float64: + return false + default: + return true + } +} + // PythonUdfArgTypeCast returns the exact descriptor that the Python handler // declared for every argument. The generic UDF cast helper only receives an // OID list, so it intentionally preserves a same-OID source type. That is @@ -125,6 +152,9 @@ func PythonUdfArgTypeCast(from, to []types.Type) []types.Type { castTypes[index] = from[index] continue } + if from[index].Oid == to[index].Oid && !pythonSameOIDCanNormalize(from[index], to[index]) { + return nil + } castTypes[index] = to[index] } return castTypes diff --git a/pkg/sql/plan/function/udf_test.go b/pkg/sql/plan/function/udf_test.go index f7e969cbb8c80..b15f995cc6207 100644 --- a/pkg/sql/plan/function/udf_test.go +++ b/pkg/sql/plan/function/udf_test.go @@ -95,6 +95,24 @@ func TestPythonUdfArgTypeMatchPrefersExactDescriptor(t *testing.T) { require.Less(t, exactCost, coerceCost) } +func TestPythonUdfArgTypeMatchRejectsVectorDimensionChange(t *testing.T) { + source := types.New(types.T_array_float32, 4, 0) + target := types.New(types.T_array_float32, 3, 0) + canMatch, cost := PythonUdfArgTypeMatch([]types.Type{source}, []types.Type{target}) + require.False(t, canMatch) + require.Equal(t, -1, cost) + + inputs := []types.Type{ + types.T_text.ToType(), + source, + target, + types.T_int64.ToType(), + } + result := checkPythonUdf(nil, inputs) + require.Equal(t, failedFunctionParametersWrong, result.status) + require.Nil(t, PythonUdfArgTypeCast([]types.Type{source}, []types.Type{target})) +} + func TestPythonUdfArgTypeCastKeepsDeclaredDescriptorForSameOID(t *testing.T) { source := types.New(types.T_decimal64, 18, 2) target := types.New(types.T_decimal64, 18, 6) From 00eed8b4869b4d93679811f8f1957a47ef03ccff Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 16 Sep 2026 11:22:09 +0800 Subject: [PATCH 152/241] fix(udf): bound handler response buffering --- pkg/udf/python/worker/test_worker.py | 6 ++++++ pkg/udf/python/worker/worker.py | 26 +++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 7986563889d87..b48b2333ed010 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1764,6 +1764,12 @@ def test_handler_response_frame_separates_status_from_payload(self): with self.assertRaisesRegex(ValueError, "empty response"): session._take_response() + def test_handler_response_frame_obeys_batch_byte_limit(self): + session = object.__new__(worker._HandlerProcessSession) + session._response_buffer = bytearray(struct.pack(">Q", 5) + b"\x01abcd") + with self.assertRaisesRegex(ValueError, "execution response is too large"): + session._take_response(4) + def test_handler_response_frame_parts_keep_one_wire_frame(self): stream = io.BytesIO() worker._write_execution_frame_parts( diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 047d2dc5fdb12..df3d63a551f1b 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -2727,11 +2727,11 @@ def should_rollover(self) -> bool: or time.monotonic() - self._burst_started >= DEFAULT_BURST_SECONDS ) - def _take_response(self) -> Optional[tuple[int, bytes]]: + def _take_response(self, max_payload_size: int = MAX_EXECUTION_FRAME_BYTES) -> Optional[tuple[int, bytes]]: if len(self._response_buffer) < 8: return None expected = struct.unpack(">Q", self._response_buffer[:8])[0] - if expected > MAX_EXECUTION_FRAME_BYTES: + if expected > max_payload_size or expected > MAX_EXECUTION_FRAME_BYTES: raise ValueError("RESOURCE_EXHAUSTED: execution response is too large") if len(self._response_buffer) < expected + 8: return None @@ -2761,6 +2761,24 @@ def run(self, context, request: Dict[str, Any], timeout_seconds: float) -> bytes request_parts, request_size = _encode_execution_request( request, compact=self._burst_batches > 0 ) + max_batch_bytes = request.get("max_batch_bytes") + if max_batch_bytes is None: + # Direct helper callers from older tests do not carry the full + # exchange contract. The real do_exchange path always supplies + # this field; retaining the global bound here keeps those helper + # calls diagnostic rather than silently weakening the real path. + response_payload_limit = MAX_EXECUTION_FRAME_BYTES + elif type(max_batch_bytes) is not int or max_batch_bytes <= 0: + raise ValueError("PROTOCOL: handler request has an invalid max_batch_bytes") + else: + # The response payload consists of one status byte followed by + # the schema-free Arrow message. The child checks the same + # max_batch_bytes before serializing, but the parent must bound + # its receive buffer independently in case a mismatched or + # malformed child writes an oversized frame. + response_payload_limit = min( + MAX_EXECUTION_FRAME_BYTES, max_batch_bytes + 1 + ) def check_budget() -> None: if _context_is_cancelled(context): @@ -2779,7 +2797,7 @@ def check_budget() -> None: remaining = deadline - time.monotonic() if remaining <= 0: raise TimeoutError("DEADLINE_EXCEEDED: handler execution timeout") - response = self._take_response() + response = self._take_response(response_payload_limit) if response is not None: break events = self._selector.select(min(remaining, 0.1)) @@ -2819,6 +2837,8 @@ def check_budget() -> None: continue if not chunk: raise ValueError("USER_CODE: handler process exited without a response") + if len(self._response_buffer) + len(chunk) > response_payload_limit + 8: + raise ValueError("RESOURCE_EXHAUSTED: execution response exceeds batch byte limit") self._response_buffer.extend(chunk) if self._process.poll() is not None: if self._process.returncode != 0: From 826c6f7afb146e5283b0d495d169aed20b49d178 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 17 Sep 2026 18:05:50 +0800 Subject: [PATCH 153/241] udf: add runtime status bridge and finish fencing --- pkg/cnservice/server_query.go | 46 + pkg/pb/query/query.pb.go | 2301 ++++++++++++++++++----- pkg/queryservice/client/query_client.go | 1 + pkg/udf/python/gateway.go | 129 +- pkg/udf/python/gateway_test.go | 61 + pkg/udf/runtime.go | 100 + proto/query.proto | 37 + 7 files changed, 2247 insertions(+), 428 deletions(-) diff --git a/pkg/cnservice/server_query.go b/pkg/cnservice/server_query.go index 799f8e41aa990..4e06e769c8720 100644 --- a/pkg/cnservice/server_query.go +++ b/pkg/cnservice/server_query.go @@ -47,6 +47,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/plan/function/ctl" "github.com/matrixorigin/matrixone/pkg/taskservice" "github.com/matrixorigin/matrixone/pkg/txn/client" + "github.com/matrixorigin/matrixone/pkg/udf" "github.com/matrixorigin/matrixone/pkg/util/fault" "github.com/matrixorigin/matrixone/pkg/vm/engine" "github.com/matrixorigin/matrixone/pkg/vm/engine/disttae" @@ -180,6 +181,7 @@ func (s *service) initQueryCommandHandler() { s.addQueryCommandHandler(query.CmdMethod_ISCPDrainConsumer, s.handleISCPDrainConsumer) s.addQueryCommandHandler(query.CmdMethod_IcebergCacheInvalidate, s.handleIcebergCacheInvalidate) s.addQueryCommandHandler(query.CmdMethod_MongoDBClientRetire, s.handleMongoDBClientRetire) + s.addQueryCommandHandler(query.CmdMethod_GetPythonUdfStatus, s.handleGetPythonUdfStatus) } func (s *service) addQueryCommandHandler( @@ -678,6 +680,50 @@ func (s *service) handleGetPipelineInfo(ctx context.Context, req *query.Request, return nil } +// handleGetPythonUdfStatus exposes the CN-local runtime state to the Operator. +// The runtime provider owns the capability handshake and returns only a +// bounded summary; this handler never accepts source or creates invocation +// state. Returning a status payload for a disabled or mismatched runtime lets +// the Operator fail closed for Python while ordinary CN query traffic remains +// available. +func (s *service) handleGetPythonUdfStatus(ctx context.Context, _ *query.Request, resp *query.Response, _ *morpc.Buffer) error { + status := udf.RuntimeStatusSnapshot{ + Language: udf.LanguagePython, + ErrorClass: udf.RuntimeStatusUnavailable, + Reason: udf.RuntimeStatusReasonStatusUnavailable, + } + if provider, ok := s.udfService.(udf.RuntimeStatusProvider); ok { + status = provider.StatusSnapshot(ctx, udf.LanguagePython) + } + resp.GetPythonUdfStatus = query.GetPythonUdfStatusResponse{ + CNUUID: s.metadata.UUID, + Language: status.Language, + Enabled: status.Enabled, + AllowUnisolated: status.AllowUnisolated, + Ready: status.Ready, + ErrorClass: status.ErrorClass, + Reason: status.Reason, + ProtocolVersion: status.ProtocolVersion, + ABIContract: status.ABIContract, + AdapterVersion: status.AdapterVersion, + SDKVersion: status.SDKVersion, + DefinitionSchemaVersion: status.DefinitionSchemaVersion, + PlanContractVersion: status.PlanContractVersion, + TypeDescriptorContract: status.TypeDescriptorContract, + TimezoneDatabaseVersion: status.TimezoneDatabaseVersion, + WindowBatches: status.WindowBatches, + CumulativeAck: status.CumulativeAck, + MaxExecutionFrameBytes: status.MaxExecutionFrameBytes, + MaxHandlerProcesses: status.MaxHandlerProcesses, + MaxAccountHandlerProcesses: status.MaxAccountHandlerProcesses, + MaxOwnerHandlerProcesses: status.MaxOwnerHandlerProcesses, + LeaseEpoch: status.LeaseEpoch, + Modes: append([]string(nil), status.Modes...), + NullPolicies: append([]string(nil), status.NullPolicies...), + } + return nil +} + func (s *service) handleMigrateConnFrom( ctx context.Context, req *query.Request, resp *query.Response, _ *morpc.Buffer, ) error { diff --git a/pkg/pb/query/query.pb.go b/pkg/pb/query/query.pb.go index cd0b54d2d201e..9eab02179e8e0 100644 --- a/pkg/pb/query/query.pb.go +++ b/pkg/pb/query/query.pb.go @@ -6,11 +6,6 @@ package query import ( encoding_binary "encoding/binary" fmt "fmt" - io "io" - math "math" - math_bits "math/bits" - time "time" - _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" @@ -21,6 +16,10 @@ import ( timestamp "github.com/matrixorigin/matrixone/pkg/pb/timestamp" txn "github.com/matrixorigin/matrixone/pkg/pb/txn" _ "google.golang.org/protobuf/types/known/timestamppb" + io "io" + math "math" + math_bits "math/bits" + time "time" ) // Reference imports to suppress errors if they are not otherwise used. @@ -126,6 +125,9 @@ const ( // Current-session SQL authorization and proxy lifecycle cleanup. CmdMethod_KillSession CmdMethod = 45 CmdMethod_DisconnectSession CmdMethod = 46 + // GetPythonUdfStatus returns the bounded, read-only Python runtime status of + // the addressed CN. It is consumed by the Operator for same-Pod workers. + CmdMethod_GetPythonUdfStatus CmdMethod = 47 ) var CmdMethod_name = map[int32]string{ @@ -176,6 +178,7 @@ var CmdMethod_name = map[int32]string{ 44: "GetVectorIndexCacheKeys", 45: "KillSession", 46: "DisconnectSession", + 47: "GetPythonUdfStatus", } var CmdMethod_value = map[string]int32{ @@ -226,6 +229,7 @@ var CmdMethod_value = map[string]int32{ "GetVectorIndexCacheKeys": 44, "KillSession": 45, "DisconnectSession": 46, + "GetPythonUdfStatus": 47, } func (x CmdMethod) String() string { @@ -1409,6 +1413,8 @@ type Request struct { GetVectorIndexCacheKeys GetVectorIndexCacheKeysRequest `protobuf:"bytes,46,opt,name=GetVectorIndexCacheKeys,proto3" json:"GetVectorIndexCacheKeys"` KillSessionRequest *KillSessionRequest `protobuf:"bytes,47,opt,name=KillSessionRequest,proto3" json:"KillSessionRequest,omitempty"` DisconnectSessionRequest *DisconnectSessionRequest `protobuf:"bytes,48,opt,name=DisconnectSessionRequest,proto3" json:"DisconnectSessionRequest,omitempty"` + // GetPythonUdfStatusRequest asks this CN for its local Python runtime state. + GetPythonUdfStatusRequest GetPythonUdfStatusRequest `protobuf:"bytes,49,opt,name=GetPythonUdfStatusRequest,proto3" json:"GetPythonUdfStatusRequest"` } func (m *Request) Reset() { *m = Request{} } @@ -1780,6 +1786,13 @@ func (m *Request) GetDisconnectSessionRequest() *DisconnectSessionRequest { return nil } +func (m *Request) GetGetPythonUdfStatusRequest() GetPythonUdfStatusRequest { + if m != nil { + return m.GetPythonUdfStatusRequest + } + return GetPythonUdfStatusRequest{} +} + // ShowProcessListResponse is the response of command ShowProcessList. type ShowProcessListResponse struct { Sessions []*status.Session `protobuf:"bytes,1,rep,name=Sessions,proto3" json:"Sessions,omitempty"` @@ -1890,6 +1903,8 @@ type Response struct { GetVectorIndexCacheKeys GetVectorIndexCacheKeysResponse `protobuf:"bytes,47,opt,name=GetVectorIndexCacheKeys,proto3" json:"GetVectorIndexCacheKeys"` KillSessionResponse *KillSessionResponse `protobuf:"bytes,48,opt,name=KillSessionResponse,proto3" json:"KillSessionResponse,omitempty"` DisconnectSessionResponse *DisconnectSessionResponse `protobuf:"bytes,49,opt,name=DisconnectSessionResponse,proto3" json:"DisconnectSessionResponse,omitempty"` + // GetPythonUdfStatus is a bounded summary of the CN-local Python contract. + GetPythonUdfStatus GetPythonUdfStatusResponse `protobuf:"bytes,50,opt,name=GetPythonUdfStatus,proto3" json:"GetPythonUdfStatus"` } func (m *Response) Reset() { *m = Response{} } @@ -2268,6 +2283,277 @@ func (m *Response) GetDisconnectSessionResponse() *DisconnectSessionResponse { return nil } +func (m *Response) GetGetPythonUdfStatus() GetPythonUdfStatusResponse { + if m != nil { + return m.GetPythonUdfStatus + } + return GetPythonUdfStatusResponse{} +} + +type GetPythonUdfStatusRequest struct { +} + +func (m *GetPythonUdfStatusRequest) Reset() { *m = GetPythonUdfStatusRequest{} } +func (m *GetPythonUdfStatusRequest) String() string { return proto.CompactTextString(m) } +func (*GetPythonUdfStatusRequest) ProtoMessage() {} +func (*GetPythonUdfStatusRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_5c6ac9b241082464, []int{27} +} +func (m *GetPythonUdfStatusRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetPythonUdfStatusRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetPythonUdfStatusRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetPythonUdfStatusRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetPythonUdfStatusRequest.Merge(m, src) +} +func (m *GetPythonUdfStatusRequest) XXX_Size() int { + return m.ProtoSize() +} +func (m *GetPythonUdfStatusRequest) XXX_DiscardUnknown() { + xxx_messageInfo_GetPythonUdfStatusRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_GetPythonUdfStatusRequest proto.InternalMessageInfo + +type GetPythonUdfStatusResponse struct { + CNUUID string `protobuf:"bytes,1,opt,name=CNUUID,proto3" json:"CNUUID,omitempty"` + Language string `protobuf:"bytes,2,opt,name=Language,proto3" json:"Language,omitempty"` + Enabled bool `protobuf:"varint,3,opt,name=Enabled,proto3" json:"Enabled,omitempty"` + AllowUnisolated bool `protobuf:"varint,4,opt,name=AllowUnisolated,proto3" json:"AllowUnisolated,omitempty"` + Ready bool `protobuf:"varint,5,opt,name=Ready,proto3" json:"Ready,omitempty"` + ErrorClass string `protobuf:"bytes,6,opt,name=ErrorClass,proto3" json:"ErrorClass,omitempty"` + Reason string `protobuf:"bytes,7,opt,name=Reason,proto3" json:"Reason,omitempty"` + ProtocolVersion int32 `protobuf:"varint,8,opt,name=ProtocolVersion,proto3" json:"ProtocolVersion,omitempty"` + ABIContract string `protobuf:"bytes,9,opt,name=ABIContract,proto3" json:"ABIContract,omitempty"` + AdapterVersion string `protobuf:"bytes,10,opt,name=AdapterVersion,proto3" json:"AdapterVersion,omitempty"` + SDKVersion string `protobuf:"bytes,11,opt,name=SDKVersion,proto3" json:"SDKVersion,omitempty"` + DefinitionSchemaVersion int32 `protobuf:"varint,12,opt,name=DefinitionSchemaVersion,proto3" json:"DefinitionSchemaVersion,omitempty"` + PlanContractVersion int32 `protobuf:"varint,13,opt,name=PlanContractVersion,proto3" json:"PlanContractVersion,omitempty"` + TypeDescriptorContract string `protobuf:"bytes,14,opt,name=TypeDescriptorContract,proto3" json:"TypeDescriptorContract,omitempty"` + TimezoneDatabaseVersion string `protobuf:"bytes,15,opt,name=TimezoneDatabaseVersion,proto3" json:"TimezoneDatabaseVersion,omitempty"` + WindowBatches int32 `protobuf:"varint,16,opt,name=WindowBatches,proto3" json:"WindowBatches,omitempty"` + CumulativeAck bool `protobuf:"varint,17,opt,name=CumulativeAck,proto3" json:"CumulativeAck,omitempty"` + MaxExecutionFrameBytes int64 `protobuf:"varint,18,opt,name=MaxExecutionFrameBytes,proto3" json:"MaxExecutionFrameBytes,omitempty"` + MaxHandlerProcesses int32 `protobuf:"varint,19,opt,name=MaxHandlerProcesses,proto3" json:"MaxHandlerProcesses,omitempty"` + MaxAccountHandlerProcesses int32 `protobuf:"varint,20,opt,name=MaxAccountHandlerProcesses,proto3" json:"MaxAccountHandlerProcesses,omitempty"` + MaxOwnerHandlerProcesses int32 `protobuf:"varint,21,opt,name=MaxOwnerHandlerProcesses,proto3" json:"MaxOwnerHandlerProcesses,omitempty"` + LeaseEpoch uint64 `protobuf:"varint,22,opt,name=LeaseEpoch,proto3" json:"LeaseEpoch,omitempty"` + Modes []string `protobuf:"bytes,23,rep,name=Modes,proto3" json:"Modes,omitempty"` + NullPolicies []string `protobuf:"bytes,24,rep,name=NullPolicies,proto3" json:"NullPolicies,omitempty"` +} + +func (m *GetPythonUdfStatusResponse) Reset() { *m = GetPythonUdfStatusResponse{} } +func (m *GetPythonUdfStatusResponse) String() string { return proto.CompactTextString(m) } +func (*GetPythonUdfStatusResponse) ProtoMessage() {} +func (*GetPythonUdfStatusResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_5c6ac9b241082464, []int{28} +} +func (m *GetPythonUdfStatusResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *GetPythonUdfStatusResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_GetPythonUdfStatusResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *GetPythonUdfStatusResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_GetPythonUdfStatusResponse.Merge(m, src) +} +func (m *GetPythonUdfStatusResponse) XXX_Size() int { + return m.ProtoSize() +} +func (m *GetPythonUdfStatusResponse) XXX_DiscardUnknown() { + xxx_messageInfo_GetPythonUdfStatusResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_GetPythonUdfStatusResponse proto.InternalMessageInfo + +func (m *GetPythonUdfStatusResponse) GetCNUUID() string { + if m != nil { + return m.CNUUID + } + return "" +} + +func (m *GetPythonUdfStatusResponse) GetLanguage() string { + if m != nil { + return m.Language + } + return "" +} + +func (m *GetPythonUdfStatusResponse) GetEnabled() bool { + if m != nil { + return m.Enabled + } + return false +} + +func (m *GetPythonUdfStatusResponse) GetAllowUnisolated() bool { + if m != nil { + return m.AllowUnisolated + } + return false +} + +func (m *GetPythonUdfStatusResponse) GetReady() bool { + if m != nil { + return m.Ready + } + return false +} + +func (m *GetPythonUdfStatusResponse) GetErrorClass() string { + if m != nil { + return m.ErrorClass + } + return "" +} + +func (m *GetPythonUdfStatusResponse) GetReason() string { + if m != nil { + return m.Reason + } + return "" +} + +func (m *GetPythonUdfStatusResponse) GetProtocolVersion() int32 { + if m != nil { + return m.ProtocolVersion + } + return 0 +} + +func (m *GetPythonUdfStatusResponse) GetABIContract() string { + if m != nil { + return m.ABIContract + } + return "" +} + +func (m *GetPythonUdfStatusResponse) GetAdapterVersion() string { + if m != nil { + return m.AdapterVersion + } + return "" +} + +func (m *GetPythonUdfStatusResponse) GetSDKVersion() string { + if m != nil { + return m.SDKVersion + } + return "" +} + +func (m *GetPythonUdfStatusResponse) GetDefinitionSchemaVersion() int32 { + if m != nil { + return m.DefinitionSchemaVersion + } + return 0 +} + +func (m *GetPythonUdfStatusResponse) GetPlanContractVersion() int32 { + if m != nil { + return m.PlanContractVersion + } + return 0 +} + +func (m *GetPythonUdfStatusResponse) GetTypeDescriptorContract() string { + if m != nil { + return m.TypeDescriptorContract + } + return "" +} + +func (m *GetPythonUdfStatusResponse) GetTimezoneDatabaseVersion() string { + if m != nil { + return m.TimezoneDatabaseVersion + } + return "" +} + +func (m *GetPythonUdfStatusResponse) GetWindowBatches() int32 { + if m != nil { + return m.WindowBatches + } + return 0 +} + +func (m *GetPythonUdfStatusResponse) GetCumulativeAck() bool { + if m != nil { + return m.CumulativeAck + } + return false +} + +func (m *GetPythonUdfStatusResponse) GetMaxExecutionFrameBytes() int64 { + if m != nil { + return m.MaxExecutionFrameBytes + } + return 0 +} + +func (m *GetPythonUdfStatusResponse) GetMaxHandlerProcesses() int32 { + if m != nil { + return m.MaxHandlerProcesses + } + return 0 +} + +func (m *GetPythonUdfStatusResponse) GetMaxAccountHandlerProcesses() int32 { + if m != nil { + return m.MaxAccountHandlerProcesses + } + return 0 +} + +func (m *GetPythonUdfStatusResponse) GetMaxOwnerHandlerProcesses() int32 { + if m != nil { + return m.MaxOwnerHandlerProcesses + } + return 0 +} + +func (m *GetPythonUdfStatusResponse) GetLeaseEpoch() uint64 { + if m != nil { + return m.LeaseEpoch + } + return 0 +} + +func (m *GetPythonUdfStatusResponse) GetModes() []string { + if m != nil { + return m.Modes + } + return nil +} + +func (m *GetPythonUdfStatusResponse) GetNullPolicies() []string { + if m != nil { + return m.NullPolicies + } + return nil +} + // AlterAccountRequest is the "alter account restricted" query request. type AlterAccountRequest struct { // Tenant is the tenant which to alter. @@ -2280,7 +2566,7 @@ func (m *AlterAccountRequest) Reset() { *m = AlterAccountRequest{} } func (m *AlterAccountRequest) String() string { return proto.CompactTextString(m) } func (*AlterAccountRequest) ProtoMessage() {} func (*AlterAccountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{27} + return fileDescriptor_5c6ac9b241082464, []int{29} } func (m *AlterAccountRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2332,7 +2618,7 @@ func (m *AlterAccountResponse) Reset() { *m = AlterAccountResponse{} } func (m *AlterAccountResponse) String() string { return proto.CompactTextString(m) } func (*AlterAccountResponse) ProtoMessage() {} func (*AlterAccountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{28} + return fileDescriptor_5c6ac9b241082464, []int{30} } func (m *AlterAccountResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2379,7 +2665,7 @@ func (m *KillConnRequest) Reset() { *m = KillConnRequest{} } func (m *KillConnRequest) String() string { return proto.CompactTextString(m) } func (*KillConnRequest) ProtoMessage() {} func (*KillConnRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{29} + return fileDescriptor_5c6ac9b241082464, []int{31} } func (m *KillConnRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2431,7 +2717,7 @@ func (m *KillConnResponse) Reset() { *m = KillConnResponse{} } func (m *KillConnResponse) String() string { return proto.CompactTextString(m) } func (*KillConnResponse) ProtoMessage() {} func (*KillConnResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{30} + return fileDescriptor_5c6ac9b241082464, []int{32} } func (m *KillConnResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2477,7 +2763,7 @@ func (m *CtlReaderRequest) Reset() { *m = CtlReaderRequest{} } func (m *CtlReaderRequest) String() string { return proto.CompactTextString(m) } func (*CtlReaderRequest) ProtoMessage() {} func (*CtlReaderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{31} + return fileDescriptor_5c6ac9b241082464, []int{33} } func (m *CtlReaderRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2535,7 +2821,7 @@ func (m *CtlReaderResponse) Reset() { *m = CtlReaderResponse{} } func (m *CtlReaderResponse) String() string { return proto.CompactTextString(m) } func (*CtlReaderResponse) ProtoMessage() {} func (*CtlReaderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{32} + return fileDescriptor_5c6ac9b241082464, []int{34} } func (m *CtlReaderResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2579,7 +2865,7 @@ func (m *CtlPrefetchOnSubscribedRequest) Reset() { *m = CtlPrefetchOnSub func (m *CtlPrefetchOnSubscribedRequest) String() string { return proto.CompactTextString(m) } func (*CtlPrefetchOnSubscribedRequest) ProtoMessage() {} func (*CtlPrefetchOnSubscribedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{33} + return fileDescriptor_5c6ac9b241082464, []int{35} } func (m *CtlPrefetchOnSubscribedRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2623,7 +2909,7 @@ func (m *CtlPrefetchOnSubscribedResponse) Reset() { *m = CtlPrefetchOnSu func (m *CtlPrefetchOnSubscribedResponse) String() string { return proto.CompactTextString(m) } func (*CtlPrefetchOnSubscribedResponse) ProtoMessage() {} func (*CtlPrefetchOnSubscribedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{34} + return fileDescriptor_5c6ac9b241082464, []int{36} } func (m *CtlPrefetchOnSubscribedResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2672,7 +2958,7 @@ func (m *ISCPDrainConsumerRequest) Reset() { *m = ISCPDrainConsumerReque func (m *ISCPDrainConsumerRequest) String() string { return proto.CompactTextString(m) } func (*ISCPDrainConsumerRequest) ProtoMessage() {} func (*ISCPDrainConsumerRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{35} + return fileDescriptor_5c6ac9b241082464, []int{37} } func (m *ISCPDrainConsumerRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2751,7 +3037,7 @@ func (m *ISCPDrainConsumerResponse) Reset() { *m = ISCPDrainConsumerResp func (m *ISCPDrainConsumerResponse) String() string { return proto.CompactTextString(m) } func (*ISCPDrainConsumerResponse) ProtoMessage() {} func (*ISCPDrainConsumerResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{36} + return fileDescriptor_5c6ac9b241082464, []int{38} } func (m *ISCPDrainConsumerResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2797,7 +3083,7 @@ func (m *TraceSpanRequest) Reset() { *m = TraceSpanRequest{} } func (m *TraceSpanRequest) String() string { return proto.CompactTextString(m) } func (*TraceSpanRequest) ProtoMessage() {} func (*TraceSpanRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{37} + return fileDescriptor_5c6ac9b241082464, []int{39} } func (m *TraceSpanRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2855,7 +3141,7 @@ func (m *TraceSpanResponse) Reset() { *m = TraceSpanResponse{} } func (m *TraceSpanResponse) String() string { return proto.CompactTextString(m) } func (*TraceSpanResponse) ProtoMessage() {} func (*TraceSpanResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{38} + return fileDescriptor_5c6ac9b241082464, []int{40} } func (m *TraceSpanResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2901,7 +3187,7 @@ func (m *GetLockInfoRequest) Reset() { *m = GetLockInfoRequest{} } func (m *GetLockInfoRequest) String() string { return proto.CompactTextString(m) } func (*GetLockInfoRequest) ProtoMessage() {} func (*GetLockInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{39} + return fileDescriptor_5c6ac9b241082464, []int{41} } func (m *GetLockInfoRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2950,7 +3236,7 @@ func (m *LockInfo) Reset() { *m = LockInfo{} } func (m *LockInfo) String() string { return proto.CompactTextString(m) } func (*LockInfo) ProtoMessage() {} func (*LockInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{40} + return fileDescriptor_5c6ac9b241082464, []int{42} } func (m *LockInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3032,7 +3318,7 @@ func (m *GetLockInfoResponse) Reset() { *m = GetLockInfoResponse{} } func (m *GetLockInfoResponse) String() string { return proto.CompactTextString(m) } func (*GetLockInfoResponse) ProtoMessage() {} func (*GetLockInfoResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{41} + return fileDescriptor_5c6ac9b241082464, []int{43} } func (m *GetLockInfoResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3089,7 +3375,7 @@ func (m *GetTxnInfoRequest) Reset() { *m = GetTxnInfoRequest{} } func (m *GetTxnInfoRequest) String() string { return proto.CompactTextString(m) } func (*GetTxnInfoRequest) ProtoMessage() {} func (*GetTxnInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{42} + return fileDescriptor_5c6ac9b241082464, []int{44} } func (m *GetTxnInfoRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3135,7 +3421,7 @@ func (m *TxnLockInfo) Reset() { *m = TxnLockInfo{} } func (m *TxnLockInfo) String() string { return proto.CompactTextString(m) } func (*TxnLockInfo) ProtoMessage() {} func (*TxnLockInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{43} + return fileDescriptor_5c6ac9b241082464, []int{45} } func (m *TxnLockInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3202,7 +3488,7 @@ func (m *TxnInfo) Reset() { *m = TxnInfo{} } func (m *TxnInfo) String() string { return proto.CompactTextString(m) } func (*TxnInfo) ProtoMessage() {} func (*TxnInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{44} + return fileDescriptor_5c6ac9b241082464, []int{46} } func (m *TxnInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3275,7 +3561,7 @@ func (m *GetTxnInfoResponse) Reset() { *m = GetTxnInfoResponse{} } func (m *GetTxnInfoResponse) String() string { return proto.CompactTextString(m) } func (*GetTxnInfoResponse) ProtoMessage() {} func (*GetTxnInfoResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{45} + return fileDescriptor_5c6ac9b241082464, []int{47} } func (m *GetTxnInfoResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3325,7 +3611,7 @@ func (m *GetCacheInfoRequest) Reset() { *m = GetCacheInfoRequest{} } func (m *GetCacheInfoRequest) String() string { return proto.CompactTextString(m) } func (*GetCacheInfoRequest) ProtoMessage() {} func (*GetCacheInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{46} + return fileDescriptor_5c6ac9b241082464, []int{48} } func (m *GetCacheInfoRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3373,7 +3659,7 @@ func (m *CacheInfo) Reset() { *m = CacheInfo{} } func (m *CacheInfo) String() string { return proto.CompactTextString(m) } func (*CacheInfo) ProtoMessage() {} func (*CacheInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{47} + return fileDescriptor_5c6ac9b241082464, []int{49} } func (m *CacheInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3452,7 +3738,7 @@ func (m *GetCacheInfoResponse) Reset() { *m = GetCacheInfoResponse{} } func (m *GetCacheInfoResponse) String() string { return proto.CompactTextString(m) } func (*GetCacheInfoResponse) ProtoMessage() {} func (*GetCacheInfoResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{48} + return fileDescriptor_5c6ac9b241082464, []int{50} } func (m *GetCacheInfoResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3498,7 +3784,7 @@ func (m *RemoveRemoteLockTableRequest) Reset() { *m = RemoveRemoteLockTa func (m *RemoveRemoteLockTableRequest) String() string { return proto.CompactTextString(m) } func (*RemoveRemoteLockTableRequest) ProtoMessage() {} func (*RemoveRemoteLockTableRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{49} + return fileDescriptor_5c6ac9b241082464, []int{51} } func (m *RemoveRemoteLockTableRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3556,7 +3842,7 @@ func (m *RemoveRemoteLockTableResponse) Reset() { *m = RemoveRemoteLockT func (m *RemoveRemoteLockTableResponse) String() string { return proto.CompactTextString(m) } func (*RemoveRemoteLockTableResponse) ProtoMessage() {} func (*RemoveRemoteLockTableResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{50} + return fileDescriptor_5c6ac9b241082464, []int{52} } func (m *RemoveRemoteLockTableResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3601,7 +3887,7 @@ func (m *GetLatestBindRequest) Reset() { *m = GetLatestBindRequest{} } func (m *GetLatestBindRequest) String() string { return proto.CompactTextString(m) } func (*GetLatestBindRequest) ProtoMessage() {} func (*GetLatestBindRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{51} + return fileDescriptor_5c6ac9b241082464, []int{53} } func (m *GetLatestBindRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3652,7 +3938,7 @@ func (m *GetLatestBindResponse) Reset() { *m = GetLatestBindResponse{} } func (m *GetLatestBindResponse) String() string { return proto.CompactTextString(m) } func (*GetLatestBindResponse) ProtoMessage() {} func (*GetLatestBindResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{52} + return fileDescriptor_5c6ac9b241082464, []int{54} } func (m *GetLatestBindResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3701,7 +3987,7 @@ func (m *UnsubscribeTableRequest) Reset() { *m = UnsubscribeTableRequest func (m *UnsubscribeTableRequest) String() string { return proto.CompactTextString(m) } func (*UnsubscribeTableRequest) ProtoMessage() {} func (*UnsubscribeTableRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{53} + return fileDescriptor_5c6ac9b241082464, []int{55} } func (m *UnsubscribeTableRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3753,7 +4039,7 @@ func (m *UnsubscribeTableResponse) Reset() { *m = UnsubscribeTableRespon func (m *UnsubscribeTableResponse) String() string { return proto.CompactTextString(m) } func (*UnsubscribeTableResponse) ProtoMessage() {} func (*UnsubscribeTableResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{54} + return fileDescriptor_5c6ac9b241082464, []int{56} } func (m *UnsubscribeTableResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3799,7 +4085,7 @@ func (m *CacheKey) Reset() { *m = CacheKey{} } func (m *CacheKey) String() string { return proto.CompactTextString(m) } func (*CacheKey) ProtoMessage() {} func (*CacheKey) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{55} + return fileDescriptor_5c6ac9b241082464, []int{57} } func (m *CacheKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3857,7 +4143,7 @@ func (m *CacheKeys) Reset() { *m = CacheKeys{} } func (m *CacheKeys) String() string { return proto.CompactTextString(m) } func (*CacheKeys) ProtoMessage() {} func (*CacheKeys) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{56} + return fileDescriptor_5c6ac9b241082464, []int{58} } func (m *CacheKeys) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3902,7 +4188,7 @@ func (m *RequestCacheKey) Reset() { *m = RequestCacheKey{} } func (m *RequestCacheKey) String() string { return proto.CompactTextString(m) } func (*RequestCacheKey) ProtoMessage() {} func (*RequestCacheKey) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{57} + return fileDescriptor_5c6ac9b241082464, []int{59} } func (m *RequestCacheKey) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -3955,7 +4241,7 @@ func (m *GetCacheDataRequest) Reset() { *m = GetCacheDataRequest{} } func (m *GetCacheDataRequest) String() string { return proto.CompactTextString(m) } func (*GetCacheDataRequest) ProtoMessage() {} func (*GetCacheDataRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{58} + return fileDescriptor_5c6ac9b241082464, []int{60} } func (m *GetCacheDataRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4002,7 +4288,7 @@ func (m *ResponseCacheData) Reset() { *m = ResponseCacheData{} } func (m *ResponseCacheData) String() string { return proto.CompactTextString(m) } func (*ResponseCacheData) ProtoMessage() {} func (*ResponseCacheData) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{59} + return fileDescriptor_5c6ac9b241082464, []int{61} } func (m *ResponseCacheData) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4061,7 +4347,7 @@ func (m *GetCacheDataResponse) Reset() { *m = GetCacheDataResponse{} } func (m *GetCacheDataResponse) String() string { return proto.CompactTextString(m) } func (*GetCacheDataResponse) ProtoMessage() {} func (*GetCacheDataResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{60} + return fileDescriptor_5c6ac9b241082464, []int{62} } func (m *GetCacheDataResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4105,7 +4391,7 @@ func (m *GetStatsInfoRequest) Reset() { *m = GetStatsInfoRequest{} } func (m *GetStatsInfoRequest) String() string { return proto.CompactTextString(m) } func (*GetStatsInfoRequest) ProtoMessage() {} func (*GetStatsInfoRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{61} + return fileDescriptor_5c6ac9b241082464, []int{63} } func (m *GetStatsInfoRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4149,7 +4435,7 @@ func (m *GetStatsInfoResponse) Reset() { *m = GetStatsInfoResponse{} } func (m *GetStatsInfoResponse) String() string { return proto.CompactTextString(m) } func (*GetStatsInfoResponse) ProtoMessage() {} func (*GetStatsInfoResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{62} + return fileDescriptor_5c6ac9b241082464, []int{64} } func (m *GetStatsInfoResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4197,7 +4483,7 @@ func (m *PrepareStmt) Reset() { *m = PrepareStmt{} } func (m *PrepareStmt) String() string { return proto.CompactTextString(m) } func (*PrepareStmt) ProtoMessage() {} func (*PrepareStmt) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{63} + return fileDescriptor_5c6ac9b241082464, []int{65} } func (m *PrepareStmt) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4264,7 +4550,7 @@ func (m *MigrateTempTable) Reset() { *m = MigrateTempTable{} } func (m *MigrateTempTable) String() string { return proto.CompactTextString(m) } func (*MigrateTempTable) ProtoMessage() {} func (*MigrateTempTable) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{64} + return fileDescriptor_5c6ac9b241082464, []int{66} } func (m *MigrateTempTable) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4331,7 +4617,7 @@ func (m *MigrateConnFromRequest) Reset() { *m = MigrateConnFromRequest{} func (m *MigrateConnFromRequest) String() string { return proto.CompactTextString(m) } func (*MigrateConnFromRequest) ProtoMessage() {} func (*MigrateConnFromRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{65} + return fileDescriptor_5c6ac9b241082464, []int{67} } func (m *MigrateConnFromRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4441,7 +4727,7 @@ func (m *MigrateConnFromResponse) Reset() { *m = MigrateConnFromResponse func (m *MigrateConnFromResponse) String() string { return proto.CompactTextString(m) } func (*MigrateConnFromResponse) ProtoMessage() {} func (*MigrateConnFromResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{66} + return fileDescriptor_5c6ac9b241082464, []int{68} } func (m *MigrateConnFromResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4638,7 +4924,7 @@ func (m *MigrateConnToRequest) Reset() { *m = MigrateConnToRequest{} } func (m *MigrateConnToRequest) String() string { return proto.CompactTextString(m) } func (*MigrateConnToRequest) ProtoMessage() {} func (*MigrateConnToRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{67} + return fileDescriptor_5c6ac9b241082464, []int{69} } func (m *MigrateConnToRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4793,7 +5079,7 @@ func (m *MigrateUserDefinedVar) Reset() { *m = MigrateUserDefinedVar{} } func (m *MigrateUserDefinedVar) String() string { return proto.CompactTextString(m) } func (*MigrateUserDefinedVar) ProtoMessage() {} func (*MigrateUserDefinedVar) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{68} + return fileDescriptor_5c6ac9b241082464, []int{70} } func (m *MigrateUserDefinedVar) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4881,7 +5167,7 @@ func (m *UserLevelLock) Reset() { *m = UserLevelLock{} } func (m *UserLevelLock) String() string { return proto.CompactTextString(m) } func (*UserLevelLock) ProtoMessage() {} func (*UserLevelLock) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{69} + return fileDescriptor_5c6ac9b241082464, []int{71} } func (m *UserLevelLock) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4939,7 +5225,7 @@ func (m *MigrateConnToResponse) Reset() { *m = MigrateConnToResponse{} } func (m *MigrateConnToResponse) String() string { return proto.CompactTextString(m) } func (*MigrateConnToResponse) ProtoMessage() {} func (*MigrateConnToResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{70} + return fileDescriptor_5c6ac9b241082464, []int{72} } func (m *MigrateConnToResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4984,7 +5270,7 @@ func (m *ReloadAutoIncrementCacheRequest) Reset() { *m = ReloadAutoIncre func (m *ReloadAutoIncrementCacheRequest) String() string { return proto.CompactTextString(m) } func (*ReloadAutoIncrementCacheRequest) ProtoMessage() {} func (*ReloadAutoIncrementCacheRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{71} + return fileDescriptor_5c6ac9b241082464, []int{73} } func (m *ReloadAutoIncrementCacheRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5028,7 +5314,7 @@ func (m *ReloadAutoIncrementCacheResponse) Reset() { *m = ReloadAutoIncr func (m *ReloadAutoIncrementCacheResponse) String() string { return proto.CompactTextString(m) } func (*ReloadAutoIncrementCacheResponse) ProtoMessage() {} func (*ReloadAutoIncrementCacheResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{72} + return fileDescriptor_5c6ac9b241082464, []int{74} } func (m *ReloadAutoIncrementCacheResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5065,7 +5351,7 @@ func (m *GetReplicaCountRequest) Reset() { *m = GetReplicaCountRequest{} func (m *GetReplicaCountRequest) String() string { return proto.CompactTextString(m) } func (*GetReplicaCountRequest) ProtoMessage() {} func (*GetReplicaCountRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{73} + return fileDescriptor_5c6ac9b241082464, []int{75} } func (m *GetReplicaCountRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5109,7 +5395,7 @@ func (m *GetReplicaCountResponse) Reset() { *m = GetReplicaCountResponse func (m *GetReplicaCountResponse) String() string { return proto.CompactTextString(m) } func (*GetReplicaCountResponse) ProtoMessage() {} func (*GetReplicaCountResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{74} + return fileDescriptor_5c6ac9b241082464, []int{76} } func (m *GetReplicaCountResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5155,7 +5441,7 @@ func (m *ResetSessionRequest) Reset() { *m = ResetSessionRequest{} } func (m *ResetSessionRequest) String() string { return proto.CompactTextString(m) } func (*ResetSessionRequest) ProtoMessage() {} func (*ResetSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{75} + return fileDescriptor_5c6ac9b241082464, []int{77} } func (m *ResetSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5203,7 +5489,7 @@ func (m *ResetSessionResponse) Reset() { *m = ResetSessionResponse{} } func (m *ResetSessionResponse) String() string { return proto.CompactTextString(m) } func (*ResetSessionResponse) ProtoMessage() {} func (*ResetSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{76} + return fileDescriptor_5c6ac9b241082464, []int{78} } func (m *ResetSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5257,7 +5543,7 @@ func (m *GoMaxProcsRequest) Reset() { *m = GoMaxProcsRequest{} } func (m *GoMaxProcsRequest) String() string { return proto.CompactTextString(m) } func (*GoMaxProcsRequest) ProtoMessage() {} func (*GoMaxProcsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{77} + return fileDescriptor_5c6ac9b241082464, []int{79} } func (m *GoMaxProcsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5304,7 +5590,7 @@ func (m *GoMaxProcsResponse) Reset() { *m = GoMaxProcsResponse{} } func (m *GoMaxProcsResponse) String() string { return proto.CompactTextString(m) } func (*GoMaxProcsResponse) ProtoMessage() {} func (*GoMaxProcsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{78} + return fileDescriptor_5c6ac9b241082464, []int{80} } func (m *GoMaxProcsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5348,7 +5634,7 @@ func (m *GoMemLimitRequest) Reset() { *m = GoMemLimitRequest{} } func (m *GoMemLimitRequest) String() string { return proto.CompactTextString(m) } func (*GoMemLimitRequest) ProtoMessage() {} func (*GoMemLimitRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{79} + return fileDescriptor_5c6ac9b241082464, []int{81} } func (m *GoMemLimitRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5395,7 +5681,7 @@ func (m *GoMemLimitResponse) Reset() { *m = GoMemLimitResponse{} } func (m *GoMemLimitResponse) String() string { return proto.CompactTextString(m) } func (*GoMemLimitResponse) ProtoMessage() {} func (*GoMemLimitResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{80} + return fileDescriptor_5c6ac9b241082464, []int{82} } func (m *GoMemLimitResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5442,7 +5728,7 @@ func (m *FileServiceCacheRequest) Reset() { *m = FileServiceCacheRequest func (m *FileServiceCacheRequest) String() string { return proto.CompactTextString(m) } func (*FileServiceCacheRequest) ProtoMessage() {} func (*FileServiceCacheRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{81} + return fileDescriptor_5c6ac9b241082464, []int{83} } func (m *FileServiceCacheRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5496,7 +5782,7 @@ func (m *FileServiceCacheResponse) Reset() { *m = FileServiceCacheRespon func (m *FileServiceCacheResponse) String() string { return proto.CompactTextString(m) } func (*FileServiceCacheResponse) ProtoMessage() {} func (*FileServiceCacheResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{82} + return fileDescriptor_5c6ac9b241082464, []int{84} } func (m *FileServiceCacheResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5554,7 +5840,7 @@ func (m *FileServiceCacheEvictRequest) Reset() { *m = FileServiceCacheEv func (m *FileServiceCacheEvictRequest) String() string { return proto.CompactTextString(m) } func (*FileServiceCacheEvictRequest) ProtoMessage() {} func (*FileServiceCacheEvictRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{83} + return fileDescriptor_5c6ac9b241082464, []int{85} } func (m *FileServiceCacheEvictRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5600,7 +5886,7 @@ func (m *FileServiceCacheEvictResponse) Reset() { *m = FileServiceCacheE func (m *FileServiceCacheEvictResponse) String() string { return proto.CompactTextString(m) } func (*FileServiceCacheEvictResponse) ProtoMessage() {} func (*FileServiceCacheEvictResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{84} + return fileDescriptor_5c6ac9b241082464, []int{86} } func (m *FileServiceCacheEvictResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5658,7 +5944,7 @@ func (m *MetadataCacheRequest) Reset() { *m = MetadataCacheRequest{} } func (m *MetadataCacheRequest) String() string { return proto.CompactTextString(m) } func (*MetadataCacheRequest) ProtoMessage() {} func (*MetadataCacheRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{85} + return fileDescriptor_5c6ac9b241082464, []int{87} } func (m *MetadataCacheRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5702,7 +5988,7 @@ func (m *MetadataCacheResponse) Reset() { *m = MetadataCacheResponse{} } func (m *MetadataCacheResponse) String() string { return proto.CompactTextString(m) } func (*MetadataCacheResponse) ProtoMessage() {} func (*MetadataCacheResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{86} + return fileDescriptor_5c6ac9b241082464, []int{88} } func (m *MetadataCacheResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5752,7 +6038,7 @@ func (m *IcebergCacheInvalidateRequest) Reset() { *m = IcebergCacheInval func (m *IcebergCacheInvalidateRequest) String() string { return proto.CompactTextString(m) } func (*IcebergCacheInvalidateRequest) ProtoMessage() {} func (*IcebergCacheInvalidateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{87} + return fileDescriptor_5c6ac9b241082464, []int{89} } func (m *IcebergCacheInvalidateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5838,7 +6124,7 @@ func (m *IcebergCacheInvalidateResponse) Reset() { *m = IcebergCacheInva func (m *IcebergCacheInvalidateResponse) String() string { return proto.CompactTextString(m) } func (*IcebergCacheInvalidateResponse) ProtoMessage() {} func (*IcebergCacheInvalidateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{88} + return fileDescriptor_5c6ac9b241082464, []int{90} } func (m *IcebergCacheInvalidateResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5882,7 +6168,7 @@ func (m *GoGCPercentRequest) Reset() { *m = GoGCPercentRequest{} } func (m *GoGCPercentRequest) String() string { return proto.CompactTextString(m) } func (*GoGCPercentRequest) ProtoMessage() {} func (*GoGCPercentRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{89} + return fileDescriptor_5c6ac9b241082464, []int{91} } func (m *GoGCPercentRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5929,7 +6215,7 @@ func (m *GoGCPercentResponse) Reset() { *m = GoGCPercentResponse{} } func (m *GoGCPercentResponse) String() string { return proto.CompactTextString(m) } func (*GoGCPercentResponse) ProtoMessage() {} func (*GoGCPercentResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{90} + return fileDescriptor_5c6ac9b241082464, []int{92} } func (m *GoGCPercentResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -5974,7 +6260,7 @@ func (m *FaultInjectRequest) Reset() { *m = FaultInjectRequest{} } func (m *FaultInjectRequest) String() string { return proto.CompactTextString(m) } func (*FaultInjectRequest) ProtoMessage() {} func (*FaultInjectRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{91} + return fileDescriptor_5c6ac9b241082464, []int{93} } func (m *FaultInjectRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6025,7 +6311,7 @@ func (m *FaultInjectResponse) Reset() { *m = FaultInjectResponse{} } func (m *FaultInjectResponse) String() string { return proto.CompactTextString(m) } func (*FaultInjectResponse) ProtoMessage() {} func (*FaultInjectResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{92} + return fileDescriptor_5c6ac9b241082464, []int{94} } func (m *FaultInjectResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6069,7 +6355,7 @@ func (m *CtlMoTableStatsRequest) Reset() { *m = CtlMoTableStatsRequest{} func (m *CtlMoTableStatsRequest) String() string { return proto.CompactTextString(m) } func (*CtlMoTableStatsRequest) ProtoMessage() {} func (*CtlMoTableStatsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{93} + return fileDescriptor_5c6ac9b241082464, []int{95} } func (m *CtlMoTableStatsRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6113,7 +6399,7 @@ func (m *CtlMoTableStatsResponse) Reset() { *m = CtlMoTableStatsResponse func (m *CtlMoTableStatsResponse) String() string { return proto.CompactTextString(m) } func (*CtlMoTableStatsResponse) ProtoMessage() {} func (*CtlMoTableStatsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{94} + return fileDescriptor_5c6ac9b241082464, []int{96} } func (m *CtlMoTableStatsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6158,7 +6444,7 @@ func (m *WorkspaceThresholdRequest) Reset() { *m = WorkspaceThresholdReq func (m *WorkspaceThresholdRequest) String() string { return proto.CompactTextString(m) } func (*WorkspaceThresholdRequest) ProtoMessage() {} func (*WorkspaceThresholdRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{95} + return fileDescriptor_5c6ac9b241082464, []int{97} } func (m *WorkspaceThresholdRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6210,7 +6496,7 @@ func (m *WorkspaceThresholdResponse) Reset() { *m = WorkspaceThresholdRe func (m *WorkspaceThresholdResponse) String() string { return proto.CompactTextString(m) } func (*WorkspaceThresholdResponse) ProtoMessage() {} func (*WorkspaceThresholdResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{96} + return fileDescriptor_5c6ac9b241082464, []int{98} } func (m *WorkspaceThresholdResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6262,7 +6548,7 @@ func (m *MinTimestampResponse) Reset() { *m = MinTimestampResponse{} } func (m *MinTimestampResponse) String() string { return proto.CompactTextString(m) } func (*MinTimestampResponse) ProtoMessage() {} func (*MinTimestampResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{97} + return fileDescriptor_5c6ac9b241082464, []int{99} } func (m *MinTimestampResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6310,7 +6596,7 @@ func (m *MongoDBClientRetireRequest) Reset() { *m = MongoDBClientRetireR func (m *MongoDBClientRetireRequest) String() string { return proto.CompactTextString(m) } func (*MongoDBClientRetireRequest) ProtoMessage() {} func (*MongoDBClientRetireRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{98} + return fileDescriptor_5c6ac9b241082464, []int{100} } func (m *MongoDBClientRetireRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6368,7 +6654,7 @@ func (m *MongoDBClientRetireResponse) Reset() { *m = MongoDBClientRetire func (m *MongoDBClientRetireResponse) String() string { return proto.CompactTextString(m) } func (*MongoDBClientRetireResponse) ProtoMessage() {} func (*MongoDBClientRetireResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{99} + return fileDescriptor_5c6ac9b241082464, []int{101} } func (m *MongoDBClientRetireResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6419,7 +6705,7 @@ func (m *MigrateSystemVariable) Reset() { *m = MigrateSystemVariable{} } func (m *MigrateSystemVariable) String() string { return proto.CompactTextString(m) } func (*MigrateSystemVariable) ProtoMessage() {} func (*MigrateSystemVariable) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{100} + return fileDescriptor_5c6ac9b241082464, []int{102} } func (m *MigrateSystemVariable) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6491,7 +6777,7 @@ func (m *RefreshSessionAuthRequest) Reset() { *m = RefreshSessionAuthReq func (m *RefreshSessionAuthRequest) String() string { return proto.CompactTextString(m) } func (*RefreshSessionAuthRequest) ProtoMessage() {} func (*RefreshSessionAuthRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{101} + return fileDescriptor_5c6ac9b241082464, []int{103} } func (m *RefreshSessionAuthRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6583,7 +6869,7 @@ func (m *RefreshSessionAuthResponse) Reset() { *m = RefreshSessionAuthRe func (m *RefreshSessionAuthResponse) String() string { return proto.CompactTextString(m) } func (*RefreshSessionAuthResponse) ProtoMessage() {} func (*RefreshSessionAuthResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{102} + return fileDescriptor_5c6ac9b241082464, []int{104} } func (m *RefreshSessionAuthResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6654,7 +6940,7 @@ func (m *KillSessionPrincipal) Reset() { *m = KillSessionPrincipal{} } func (m *KillSessionPrincipal) String() string { return proto.CompactTextString(m) } func (*KillSessionPrincipal) ProtoMessage() {} func (*KillSessionPrincipal) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{103} + return fileDescriptor_5c6ac9b241082464, []int{105} } func (m *KillSessionPrincipal) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6729,7 +7015,7 @@ func (m *KillSessionRequest) Reset() { *m = KillSessionRequest{} } func (m *KillSessionRequest) String() string { return proto.CompactTextString(m) } func (*KillSessionRequest) ProtoMessage() {} func (*KillSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{104} + return fileDescriptor_5c6ac9b241082464, []int{106} } func (m *KillSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6794,7 +7080,7 @@ func (m *KillSessionResponse) Reset() { *m = KillSessionResponse{} } func (m *KillSessionResponse) String() string { return proto.CompactTextString(m) } func (*KillSessionResponse) ProtoMessage() {} func (*KillSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{105} + return fileDescriptor_5c6ac9b241082464, []int{107} } func (m *KillSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6839,7 +7125,7 @@ func (m *DisconnectSessionRequest) Reset() { *m = DisconnectSessionReque func (m *DisconnectSessionRequest) String() string { return proto.CompactTextString(m) } func (*DisconnectSessionRequest) ProtoMessage() {} func (*DisconnectSessionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{106} + return fileDescriptor_5c6ac9b241082464, []int{108} } func (m *DisconnectSessionRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6882,7 +7168,7 @@ func (m *DisconnectSessionResponse) Reset() { *m = DisconnectSessionResp func (m *DisconnectSessionResponse) String() string { return proto.CompactTextString(m) } func (*DisconnectSessionResponse) ProtoMessage() {} func (*DisconnectSessionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_5c6ac9b241082464, []int{107} + return fileDescriptor_5c6ac9b241082464, []int{109} } func (m *DisconnectSessionResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -6942,6 +7228,8 @@ func init() { proto.RegisterType((*Request)(nil), "query.Request") proto.RegisterType((*ShowProcessListResponse)(nil), "query.ShowProcessListResponse") proto.RegisterType((*Response)(nil), "query.Response") + proto.RegisterType((*GetPythonUdfStatusRequest)(nil), "query.GetPythonUdfStatusRequest") + proto.RegisterType((*GetPythonUdfStatusResponse)(nil), "query.GetPythonUdfStatusResponse") proto.RegisterType((*AlterAccountRequest)(nil), "query.AlterAccountRequest") proto.RegisterType((*AlterAccountResponse)(nil), "query.AlterAccountResponse") proto.RegisterType((*KillConnRequest)(nil), "query.KillConnRequest") @@ -7028,336 +7316,363 @@ func init() { func init() { proto.RegisterFile("query.proto", fileDescriptor_5c6ac9b241082464) } var fileDescriptor_5c6ac9b241082464 = []byte{ - // 5250 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x5c, 0x4f, 0x73, 0xdc, 0x46, - 0x76, 0xd7, 0x90, 0x43, 0x72, 0xe6, 0xf1, 0x1f, 0xd8, 0xfc, 0x07, 0x51, 0xd4, 0x90, 0x82, 0x65, - 0x89, 0x92, 0x2c, 0x52, 0xcb, 0xb5, 0x64, 0x7b, 0xd7, 0xd9, 0x32, 0x35, 0x23, 0x4a, 0x63, 0x91, - 0x22, 0xd5, 0x43, 0xcb, 0x5e, 0x6f, 0x95, 0x13, 0x70, 0xa6, 0x49, 0xc2, 0x9a, 0x01, 0xc6, 0x00, - 0x46, 0x26, 0x5d, 0xb5, 0x39, 0xed, 0x29, 0x55, 0x71, 0xed, 0x47, 0x48, 0x4e, 0x39, 0x6f, 0x55, - 0x3e, 0x43, 0x6a, 0xab, 0x72, 0xd9, 0x43, 0xaa, 0xb2, 0xa7, 0x4d, 0xca, 0xbe, 0xe6, 0x96, 0x0f, - 0x90, 0x54, 0x37, 0xba, 0x01, 0x34, 0xd0, 0x8d, 0x91, 0x6c, 0xef, 0x85, 0x35, 0xfd, 0xfa, 0xbd, - 0x5f, 0xff, 0x7f, 0xfd, 0xde, 0xc3, 0x6b, 0xc2, 0xe4, 0x57, 0x03, 0xe2, 0x5f, 0x6c, 0xf6, 0x7d, - 0x2f, 0xf4, 0xd0, 0x18, 0x2b, 0xac, 0x4c, 0x05, 0xa1, 0x1d, 0x0e, 0x82, 0x88, 0xb8, 0x02, 0x5d, - 0xaf, 0xfd, 0x92, 0xff, 0xae, 0x86, 0xe7, 0x2e, 0xff, 0x39, 0x1b, 0x3a, 0x3d, 0x12, 0x84, 0x76, - 0xaf, 0x2f, 0x08, 0x54, 0x2a, 0x70, 0xdc, 0x13, 0x4f, 0x08, 0xf6, 0xbb, 0xb6, 0xe0, 0xbe, 0x7b, - 0xea, 0x84, 0x67, 0x83, 0xe3, 0xcd, 0xb6, 0xd7, 0xdb, 0x3a, 0xf5, 0x4e, 0xbd, 0x2d, 0x46, 0x3e, - 0x1e, 0x9c, 0xb0, 0x12, 0x2b, 0xb0, 0x5f, 0x9c, 0x7d, 0xed, 0xd4, 0xf3, 0x4e, 0xbb, 0x24, 0xe1, - 0xca, 0x34, 0x66, 0x5d, 0x87, 0xa9, 0xe7, 0xb4, 0xaf, 0x98, 0x7c, 0x35, 0x20, 0x41, 0x88, 0x16, - 0x60, 0x8c, 0x95, 0xcd, 0xd2, 0x7a, 0x69, 0xa3, 0x8a, 0xa3, 0x82, 0xf5, 0x0c, 0x96, 0x5a, 0x67, - 0xde, 0xd7, 0x87, 0xbe, 0xd7, 0x26, 0x41, 0xb0, 0xe7, 0x04, 0xa1, 0xe0, 0x5f, 0x82, 0xf1, 0x23, - 0xe2, 0xda, 0x6e, 0xc8, 0x05, 0x78, 0x09, 0xad, 0x42, 0xb5, 0x75, 0x11, 0xf0, 0xaa, 0x91, 0xf5, - 0xd2, 0x46, 0x05, 0x27, 0x04, 0xeb, 0x53, 0x98, 0x6b, 0x5d, 0xb8, 0xed, 0xba, 0xd7, 0xeb, 0x39, - 0x31, 0xd4, 0x43, 0x98, 0xd9, 0xb3, 0x43, 0x12, 0x84, 0x11, 0xf9, 0xa8, 0xc5, 0x20, 0x27, 0xb7, - 0x17, 0x36, 0x93, 0x4e, 0x1f, 0x89, 0x5f, 0x0f, 0xcb, 0x7f, 0xfc, 0xcb, 0xda, 0x25, 0x9c, 0x91, - 0xb0, 0x3e, 0x07, 0x94, 0x06, 0x0e, 0xfa, 0x9e, 0x1b, 0x10, 0xd4, 0x80, 0xd9, 0xfa, 0xc0, 0xf7, - 0x89, 0xfb, 0x26, 0xd0, 0x59, 0x11, 0x0b, 0x81, 0xf1, 0x98, 0x84, 0x52, 0x9f, 0xad, 0x5f, 0xc3, - 0x5c, 0x8a, 0xf6, 0x93, 0x36, 0xb7, 0x05, 0x8b, 0x75, 0xcf, 0x27, 0x8d, 0x41, 0xaf, 0x5f, 0xf7, - 0xdc, 0x13, 0xe7, 0x34, 0x35, 0xe5, 0x3b, 0xed, 0xd0, 0xf1, 0x5c, 0x31, 0xe5, 0x51, 0xc9, 0x32, - 0x61, 0x29, 0x2b, 0x10, 0x75, 0xc8, 0xba, 0x02, 0x97, 0x1f, 0x93, 0xf0, 0x90, 0x2e, 0x78, 0xdb, - 0xeb, 0xbe, 0x20, 0x7e, 0xe0, 0x78, 0xae, 0x18, 0xc2, 0x03, 0x58, 0x51, 0x55, 0xf2, 0xb1, 0x98, - 0x30, 0xc1, 0x49, 0xac, 0xb5, 0x51, 0x2c, 0x8a, 0xd6, 0x7d, 0xb8, 0xdc, 0xd2, 0x81, 0x16, 0x88, - 0x3d, 0x81, 0x1b, 0x2d, 0x12, 0xbe, 0x20, 0xed, 0xd0, 0xf3, 0x9b, 0x6e, 0x87, 0x9c, 0xef, 0xfa, - 0x24, 0x38, 0x73, 0x49, 0x10, 0x34, 0xdd, 0x90, 0xf8, 0xaf, 0xec, 0xae, 0xc0, 0xa8, 0x01, 0x08, - 0xd2, 0xb3, 0x80, 0xc3, 0xa4, 0x28, 0x56, 0x13, 0x6e, 0x0e, 0x45, 0xe2, 0xa3, 0x18, 0x06, 0xb5, - 0x0d, 0xb5, 0xc7, 0x12, 0x54, 0xdd, 0x6e, 0x9f, 0x91, 0xa6, 0x7b, 0xe2, 0x89, 0xce, 0x18, 0x30, - 0xfa, 0x94, 0x88, 0x53, 0x41, 0x7f, 0x5a, 0xef, 0xc1, 0x9a, 0x56, 0x86, 0x37, 0xbb, 0x00, 0x63, - 0x75, 0x6f, 0xc0, 0xcf, 0xc6, 0x28, 0x8e, 0x0a, 0xd6, 0x3d, 0x58, 0x7d, 0xf4, 0xca, 0x69, 0xe7, - 0x44, 0xf5, 0x4d, 0x7d, 0x00, 0x57, 0x35, 0x12, 0xc9, 0x2a, 0x31, 0x06, 0xd2, 0x11, 0xd3, 0xcd, - 0x8b, 0xd6, 0xba, 0x72, 0x64, 0x4f, 0xc9, 0x45, 0x20, 0xd6, 0xff, 0xbe, 0x72, 0x1c, 0x11, 0x07, - 0x87, 0x47, 0x50, 0xa6, 0x65, 0xb3, 0xb4, 0x3e, 0xba, 0x51, 0xc5, 0xec, 0x37, 0xdd, 0x36, 0xad, - 0x1f, 0xb2, 0x6d, 0xde, 0x81, 0x19, 0x3c, 0x70, 0x8f, 0xec, 0xe0, 0xa5, 0x18, 0xef, 0x0a, 0x54, - 0x68, 0xb1, 0xee, 0x75, 0x08, 0x63, 0x1e, 0xc3, 0x71, 0xd9, 0xba, 0x05, 0xb3, 0x31, 0x37, 0x87, - 0x5e, 0x82, 0x71, 0x4c, 0x82, 0x41, 0x37, 0xd6, 0x38, 0x51, 0x89, 0x6e, 0x7f, 0xba, 0x8f, 0x9d, - 0x3e, 0xe9, 0x3a, 0x6e, 0x7a, 0xed, 0xac, 0x2d, 0x58, 0xce, 0xd5, 0x14, 0xae, 0xd0, 0xff, 0xd4, - 0x60, 0x42, 0xf4, 0x6e, 0x15, 0xaa, 0xfc, 0x67, 0xb3, 0xc1, 0xb8, 0xca, 0x38, 0x21, 0xa0, 0x4d, - 0xa8, 0xd6, 0x7b, 0x9d, 0x7d, 0x12, 0x9e, 0x79, 0x1d, 0xa6, 0xe6, 0x66, 0xb6, 0x8d, 0xcd, 0xe8, - 0x26, 0x88, 0xe9, 0x38, 0x61, 0x41, 0xef, 0xc9, 0xea, 0xd6, 0x1c, 0x65, 0x7a, 0x61, 0x9e, 0x8b, - 0xa4, 0xab, 0xb0, 0xac, 0x97, 0x3f, 0xd1, 0x69, 0x60, 0xb3, 0xcc, 0x20, 0xae, 0x72, 0x08, 0x35, - 0x13, 0xd6, 0xa9, 0xef, 0x3d, 0x98, 0xdf, 0xe9, 0x86, 0xc4, 0xdf, 0x69, 0xb7, 0xe9, 0xc8, 0x05, - 0xe6, 0x18, 0xc3, 0x5c, 0xe1, 0x98, 0x0a, 0x0e, 0xac, 0x12, 0x43, 0x1f, 0xc1, 0xec, 0x53, 0xa7, - 0xdb, 0xad, 0x7b, 0xae, 0x50, 0x04, 0xe6, 0x38, 0x43, 0x5a, 0xe2, 0x48, 0x99, 0x5a, 0x9c, 0x65, - 0x47, 0x75, 0x30, 0x8e, 0x7c, 0xbb, 0x4d, 0x5a, 0x7d, 0x3b, 0x86, 0x98, 0x60, 0x10, 0xcb, 0x1c, - 0x22, 0x5b, 0x8d, 0x73, 0x02, 0xa8, 0x09, 0xe8, 0x31, 0x09, 0xf7, 0xbc, 0xf6, 0xcb, 0xd4, 0x2e, - 0x30, 0x2b, 0x0c, 0xe6, 0x32, 0x87, 0xc9, 0x33, 0x60, 0x85, 0x10, 0xda, 0x65, 0xfa, 0xfd, 0xe8, - 0xdc, 0x4d, 0x23, 0x55, 0x19, 0x92, 0x99, 0x20, 0xc9, 0xf5, 0x38, 0x2f, 0x42, 0xe7, 0x99, 0xde, - 0x13, 0x19, 0xad, 0x62, 0x82, 0x34, 0xcf, 0x0a, 0x0e, 0xac, 0x12, 0x43, 0xef, 0x03, 0xb4, 0x2e, - 0xda, 0x6e, 0x74, 0x55, 0x98, 0x93, 0x52, 0x77, 0x72, 0xf7, 0x2a, 0x4e, 0xf1, 0xa2, 0xfb, 0x50, - 0x8d, 0xef, 0x2b, 0x73, 0x4a, 0x9a, 0xd8, 0xec, 0xdd, 0x86, 0x13, 0x4e, 0x74, 0xc8, 0x66, 0x34, - 0x73, 0xd8, 0xcd, 0x69, 0x26, 0xbf, 0x9e, 0xc8, 0xab, 0x2f, 0x03, 0xac, 0x90, 0xa5, 0x88, 0x79, - 0xf5, 0x61, 0xce, 0x48, 0x88, 0x2d, 0x3d, 0x62, 0xbe, 0x0a, 0x35, 0x60, 0x46, 0xbe, 0xfe, 0xcc, - 0x59, 0x86, 0xb6, 0x2a, 0xce, 0xa3, 0xea, 0x32, 0xc5, 0x19, 0x19, 0xb4, 0x05, 0x13, 0x5c, 0xe1, - 0x98, 0x06, 0x13, 0x5f, 0xe4, 0xe2, 0xb2, 0xd2, 0xc2, 0x82, 0x0b, 0xfd, 0x1a, 0x16, 0x31, 0xe9, - 0x79, 0xaf, 0x08, 0xfd, 0x1b, 0x12, 0xba, 0x81, 0x8e, 0xec, 0xe3, 0x2e, 0x31, 0xe7, 0x98, 0xf8, - 0x5b, 0x42, 0x5c, 0xc5, 0x23, 0xc0, 0xd4, 0x08, 0x68, 0x07, 0xa6, 0xe9, 0x96, 0x64, 0x16, 0xce, - 0x43, 0xc7, 0xed, 0x98, 0x88, 0x41, 0x5e, 0x49, 0x6d, 0xe1, 0xb8, 0x4e, 0x40, 0xc9, 0x12, 0xe8, - 0x63, 0x30, 0x3e, 0x71, 0x83, 0xc1, 0x71, 0xd0, 0xf6, 0x9d, 0x63, 0x12, 0x75, 0x6c, 0x9e, 0xa1, - 0xd4, 0x38, 0x4a, 0xb6, 0x3a, 0x3e, 0x56, 0xd9, 0x8a, 0xf4, 0x1e, 0x6e, 0xd8, 0xa1, 0x2d, 0xf6, - 0xf0, 0x82, 0x72, 0x0f, 0xa7, 0x38, 0xb0, 0x4a, 0x8c, 0xa3, 0xb5, 0xa8, 0xa9, 0x9b, 0x3e, 0x11, - 0x8b, 0x59, 0xb4, 0x2c, 0x07, 0x56, 0x89, 0x51, 0xf5, 0xa8, 0x56, 0xfe, 0xe6, 0x92, 0xa4, 0x1e, - 0xd5, 0x4c, 0x58, 0x23, 0x4c, 0x61, 0xf7, 0x9d, 0x53, 0xdf, 0x0e, 0x09, 0x55, 0x52, 0xbb, 0xbe, - 0xd7, 0x13, 0xb0, 0xcb, 0x12, 0xac, 0x9a, 0x09, 0x6b, 0x84, 0xd1, 0x01, 0x2c, 0xa4, 0x6a, 0x8e, - 0xe2, 0xbe, 0x9a, 0xd2, 0xfa, 0xaa, 0x58, 0xb0, 0x52, 0x10, 0x1d, 0x83, 0x89, 0x49, 0xd7, 0xb3, - 0x3b, 0x3b, 0x83, 0xd0, 0x6b, 0xba, 0x6d, 0x9f, 0xf4, 0xa8, 0x29, 0x49, 0xe7, 0xdc, 0xbc, 0xcc, - 0x40, 0x6f, 0xc4, 0xfb, 0x50, 0xcd, 0x26, 0xf0, 0xb5, 0x38, 0x54, 0x35, 0xd7, 0xc3, 0x2e, 0x26, - 0x76, 0x87, 0xf8, 0xa2, 0xc3, 0x2b, 0x92, 0x06, 0xc9, 0x56, 0xe3, 0x9c, 0x00, 0xda, 0x87, 0xd9, - 0xc7, 0x24, 0xc4, 0xa4, 0xdf, 0x75, 0xda, 0x76, 0x74, 0xf3, 0x5e, 0xc9, 0x2e, 0x50, 0xba, 0x96, - 0xcb, 0x09, 0x1b, 0x39, 0x53, 0x4b, 0x37, 0x11, 0x26, 0x01, 0x09, 0x5b, 0x24, 0x48, 0xa9, 0x07, - 0x73, 0x55, 0xda, 0x44, 0x0a, 0x0e, 0xac, 0x12, 0x43, 0x7b, 0x30, 0xf7, 0xd8, 0xdb, 0xb7, 0xcf, - 0xe9, 0x3d, 0x29, 0xcc, 0x23, 0xf3, 0xaa, 0xac, 0xec, 0xb3, 0xf5, 0xbc, 0x67, 0x79, 0x41, 0x8e, - 0x46, 0x7a, 0x7b, 0x4e, 0xa2, 0x53, 0xcd, 0x5a, 0x16, 0x4d, 0xae, 0x4f, 0xa1, 0xc9, 0x15, 0xe8, - 0x0b, 0x58, 0xde, 0x75, 0xba, 0xa4, 0x45, 0xfc, 0x57, 0x4e, 0x9b, 0xa4, 0x97, 0xcc, 0x5c, 0x93, - 0xce, 0xb3, 0x86, 0x8b, 0x23, 0xeb, 0x40, 0x50, 0x0f, 0x56, 0xb3, 0x55, 0xcc, 0x84, 0x14, 0x8d, - 0xac, 0x4b, 0xda, 0xac, 0x88, 0x95, 0xb7, 0x54, 0x08, 0x87, 0x3e, 0x81, 0x85, 0x7d, 0x12, 0xda, - 0x1d, 0x3b, 0xb4, 0xa5, 0xb1, 0x5c, 0x93, 0x4f, 0x80, 0x82, 0x85, 0xc3, 0x2b, 0xc5, 0xd1, 0x01, - 0xa0, 0xc7, 0xde, 0xe3, 0xfa, 0x21, 0xf1, 0xdb, 0x24, 0xb1, 0x66, 0x2c, 0xf9, 0xe6, 0xcf, 0x31, - 0x70, 0x48, 0x85, 0x28, 0x35, 0x25, 0x76, 0xed, 0x41, 0x37, 0x6c, 0xba, 0x5f, 0x92, 0x64, 0x32, - 0xde, 0x92, 0x00, 0xf3, 0x0c, 0x58, 0x21, 0x84, 0x7e, 0x03, 0x4b, 0xf5, 0xb0, 0xbb, 0xef, 0x31, - 0x65, 0xca, 0x14, 0x98, 0x80, 0xbb, 0x2e, 0x9d, 0x00, 0x35, 0x13, 0xef, 0xa3, 0x06, 0x02, 0x7d, - 0x01, 0x97, 0x3f, 0xf5, 0xfc, 0x97, 0x41, 0xdf, 0x6e, 0x93, 0xa3, 0x33, 0xea, 0x07, 0x79, 0x5d, - 0x71, 0x27, 0x98, 0x6f, 0x4b, 0xb7, 0xaa, 0x96, 0x0f, 0xeb, 0x21, 0x50, 0x0f, 0x6a, 0xf5, 0xb0, - 0x7b, 0xe8, 0x93, 0x13, 0x12, 0xb6, 0xcf, 0x0e, 0xdc, 0x96, 0xb8, 0x1a, 0xe2, 0x46, 0x6e, 0xb0, - 0x46, 0xde, 0x4e, 0x06, 0x51, 0xc0, 0x8c, 0x87, 0x80, 0xa1, 0xdf, 0x80, 0xd9, 0x6c, 0xd5, 0x0f, - 0x1b, 0xbe, 0xed, 0xb8, 0x75, 0xcf, 0x0d, 0x06, 0xbd, 0x44, 0xe7, 0xdc, 0x64, 0x0d, 0xad, 0xf1, - 0x86, 0x74, 0x6c, 0x58, 0x0b, 0x80, 0xfa, 0x70, 0xb5, 0xd9, 0x26, 0xc7, 0xc4, 0x3f, 0xe5, 0x86, - 0xd5, 0x2b, 0xbb, 0xeb, 0x74, 0xec, 0x30, 0xde, 0x84, 0x1b, 0xac, 0x85, 0xeb, 0xa2, 0x85, 0x22, - 0x5e, 0xbe, 0x2c, 0xc5, 0x80, 0xe8, 0x14, 0x56, 0xf6, 0x3d, 0xf7, 0xd4, 0x6b, 0x3c, 0xac, 0x77, - 0x1d, 0xb6, 0xbb, 0x42, 0xc7, 0x8f, 0x9b, 0xbb, 0xc5, 0x9a, 0xbb, 0x26, 0xf6, 0xbc, 0x96, 0x91, - 0xb7, 0x55, 0x00, 0x45, 0xb7, 0x01, 0x26, 0x27, 0x74, 0xed, 0xb8, 0x6a, 0xdb, 0x19, 0x84, 0x67, - 0xa2, 0x9d, 0xdb, 0xd2, 0x36, 0xd0, 0xf2, 0x61, 0x3d, 0x04, 0xfa, 0x2d, 0xac, 0x0d, 0x71, 0xb9, - 0xcd, 0x3b, 0xac, 0x95, 0xbb, 0x89, 0x09, 0xf7, 0x1a, 0xae, 0x3e, 0x1f, 0xd9, 0x30, 0x6c, 0x44, - 0x98, 0x23, 0xa7, 0x72, 0xb9, 0xcd, 0x77, 0xa4, 0xed, 0x57, 0xec, 0xcc, 0x0b, 0x5d, 0xa8, 0xe1, - 0x42, 0x7f, 0x0b, 0x8b, 0x4a, 0x77, 0xdb, 0xbc, 0x2b, 0x29, 0xc1, 0x22, 0x27, 0x9e, 0x37, 0xa1, - 0xc6, 0xd1, 0x8c, 0x83, 0xb9, 0xd8, 0x9b, 0xc3, 0xc6, 0x91, 0x72, 0xdd, 0x0b, 0xc6, 0x41, 0xb9, - 0xa8, 0xf2, 0xa2, 0xfe, 0x55, 0xe6, 0x72, 0xdc, 0x92, 0x94, 0x57, 0x9e, 0x01, 0x2b, 0x84, 0xe8, - 0x81, 0x6c, 0x38, 0x41, 0xdb, 0x73, 0x5d, 0xd2, 0xce, 0xde, 0xb6, 0xf7, 0xa4, 0x03, 0xa9, 0x63, - 0xc3, 0x5a, 0x00, 0x6b, 0x17, 0x96, 0x73, 0xee, 0x29, 0xf7, 0xcf, 0xef, 0x40, 0x85, 0x33, 0x47, - 0xd1, 0x87, 0xc9, 0xed, 0xd9, 0x4d, 0x1e, 0x54, 0x15, 0x20, 0x31, 0x83, 0xf5, 0xbb, 0x75, 0xa8, - 0xc4, 0x92, 0x3f, 0xad, 0xdf, 0xbe, 0x00, 0x63, 0x8f, 0x7c, 0xdf, 0xf3, 0x99, 0xc3, 0x3e, 0x85, - 0xa3, 0x02, 0xfa, 0x4c, 0xdb, 0x71, 0xee, 0x95, 0xd7, 0x74, 0x5e, 0x79, 0xc4, 0x85, 0xb5, 0xe3, - 0x3e, 0x80, 0x05, 0xd9, 0xc1, 0xe6, 0xb0, 0x63, 0xd2, 0xfd, 0xa8, 0x62, 0xc1, 0x4a, 0x41, 0x6a, - 0xbd, 0x25, 0xbe, 0x36, 0x07, 0x1b, 0x97, 0xac, 0xb7, 0x6c, 0x35, 0xce, 0x09, 0x50, 0x6f, 0x38, - 0xe5, 0x6c, 0x73, 0x94, 0x09, 0xc9, 0xa4, 0xc9, 0xd5, 0xe3, 0xbc, 0x08, 0xb7, 0xfd, 0x13, 0x5f, - 0x9b, 0x23, 0x55, 0xb2, 0xb6, 0x7f, 0x96, 0x03, 0xab, 0xc4, 0xb8, 0xbb, 0x1f, 0x3b, 0xdc, 0x1c, - 0xac, 0x9a, 0x75, 0xf7, 0x33, 0x0c, 0x58, 0x21, 0x44, 0xa7, 0x5d, 0xf6, 0xb7, 0x39, 0x18, 0x64, - 0x1d, 0xaf, 0x1c, 0x0b, 0x56, 0x0a, 0xa2, 0x0f, 0xa8, 0xa7, 0x2e, 0x1c, 0x72, 0xee, 0xa9, 0x5f, - 0x56, 0x78, 0xea, 0x1c, 0x24, 0xc5, 0x8c, 0x1e, 0xe4, 0x5d, 0x75, 0x33, 0xef, 0xaa, 0x73, 0xc1, - 0x94, 0xaf, 0xfe, 0xbc, 0xc0, 0x57, 0xbf, 0x56, 0xe0, 0xab, 0xa7, 0xa6, 0x25, 0xeb, 0x5a, 0x3f, - 0x2f, 0x70, 0xd6, 0xaf, 0x15, 0x38, 0xeb, 0x02, 0x52, 0xe1, 0xad, 0x3f, 0xd2, 0x78, 0xeb, 0x57, - 0x35, 0xde, 0x3a, 0x87, 0xca, 0xba, 0xeb, 0xf7, 0xb2, 0xee, 0xfa, 0x52, 0xd6, 0x5d, 0xe7, 0x82, - 0xb1, 0xbf, 0xfe, 0x79, 0xb1, 0xbf, 0x7e, 0xbd, 0xd8, 0x5f, 0xe7, 0x68, 0x1a, 0x87, 0xfd, 0xa1, - 0xda, 0x61, 0x5f, 0x55, 0x3b, 0xec, 0x1c, 0x2b, 0xe3, 0xb1, 0x3f, 0xd5, 0x7a, 0xec, 0x6b, 0x5a, - 0x8f, 0x5d, 0x1c, 0xd8, 0x9c, 0xcb, 0x9e, 0xda, 0xcf, 0x91, 0xef, 0xcd, 0xf7, 0xf3, 0x82, 0x72, - 0x3f, 0xa7, 0x59, 0xb0, 0x52, 0x90, 0x03, 0xa6, 0xdc, 0x6f, 0x0e, 0xb8, 0x98, 0x05, 0xcc, 0xb1, - 0x60, 0xa5, 0x20, 0x55, 0xa1, 0x9a, 0xd8, 0x2c, 0xf7, 0xdc, 0x6b, 0x3a, 0xcf, 0x5d, 0xa8, 0x50, - 0x5d, 0x68, 0xf7, 0x33, 0x58, 0xce, 0xb9, 0xdf, 0x1c, 0x79, 0x59, 0x42, 0xd6, 0x70, 0x61, 0x9d, - 0x38, 0xc2, 0xb0, 0x98, 0xf1, 0xc2, 0x39, 0xae, 0x29, 0x2d, 0xb7, 0x92, 0x07, 0xab, 0x45, 0x51, - 0x7b, 0xa8, 0x07, 0x7f, 0x73, 0xa8, 0x07, 0xcf, 0x5b, 0xd0, 0xbb, 0xf0, 0xbb, 0x30, 0x97, 0xf2, - 0xc8, 0x79, 0xa7, 0x57, 0x24, 0xd5, 0x92, 0xab, 0xc7, 0x79, 0x11, 0xf4, 0x4c, 0xe7, 0xc5, 0xd7, - 0x74, 0x5e, 0x7c, 0x24, 0xa8, 0x73, 0xe3, 0x0f, 0x60, 0x41, 0xf6, 0xc7, 0x79, 0xd7, 0x56, 0xa5, - 0x5d, 0xa5, 0x62, 0xc1, 0x4a, 0xc1, 0xc8, 0x0f, 0x4c, 0x1c, 0x72, 0x0e, 0x77, 0x35, 0xe3, 0x07, - 0x66, 0x19, 0x12, 0x3f, 0x30, 0x5b, 0xc3, 0x01, 0x63, 0x9f, 0x9c, 0x03, 0xd6, 0xb2, 0x80, 0x19, - 0x86, 0x14, 0x60, 0xa6, 0x06, 0xd9, 0x60, 0xe6, 0x5d, 0x71, 0x0e, 0xbb, 0x26, 0x1d, 0x77, 0x1d, - 0x1b, 0x07, 0xd7, 0xc2, 0x50, 0x3f, 0x47, 0xe3, 0x83, 0xf3, 0x76, 0xd6, 0x25, 0x8d, 0x57, 0xc8, - 0x2b, 0xfc, 0x9c, 0x42, 0x26, 0xf4, 0x19, 0x2c, 0x66, 0xdc, 0x72, 0xde, 0xd2, 0x35, 0xf9, 0x60, - 0xa8, 0x78, 0x84, 0xc5, 0xac, 0xac, 0x44, 0x18, 0xe6, 0x25, 0xef, 0x9c, 0xe3, 0x5a, 0xb2, 0xc5, - 0x90, 0xe7, 0xe0, 0xa8, 0x2a, 0x61, 0x6a, 0x85, 0x48, 0x6e, 0x3a, 0xc7, 0x7c, 0x4b, 0xc2, 0x54, - 0x70, 0x60, 0x95, 0x18, 0xfa, 0x02, 0x96, 0x73, 0xbe, 0x39, 0x47, 0xbc, 0x2e, 0x9d, 0x0d, 0x0d, - 0x97, 0x30, 0xe6, 0x35, 0xd5, 0xc8, 0x86, 0x15, 0x95, 0x7b, 0xce, 0x9b, 0x78, 0x5b, 0xba, 0x8b, - 0xf5, 0x8c, 0xb8, 0x00, 0x24, 0x0a, 0x4b, 0xba, 0xf1, 0x87, 0xe9, 0x18, 0xfc, 0x46, 0x26, 0x2c, - 0x99, 0x67, 0xc1, 0x4a, 0x41, 0xd4, 0x87, 0x35, 0xad, 0xa3, 0xcf, 0xb1, 0x6f, 0x4a, 0xd1, 0xc9, - 0x21, 0xdc, 0x78, 0x18, 0x1c, 0x75, 0x80, 0x15, 0x7e, 0x3f, 0x6f, 0x6b, 0x43, 0x72, 0x80, 0xb5, - 0x7c, 0x58, 0x0f, 0x81, 0x02, 0xa8, 0xe9, 0x5c, 0x7d, 0xde, 0xc8, 0x2d, 0xc9, 0x81, 0x2b, 0x66, - 0xe6, 0x6b, 0x3e, 0x04, 0x12, 0x7d, 0x09, 0x57, 0x94, 0x3e, 0x3f, 0x6f, 0x31, 0xf2, 0xeb, 0xad, - 0xa2, 0xf8, 0x81, 0xd4, 0x5c, 0x11, 0x18, 0xdd, 0x66, 0x2a, 0xf7, 0x9f, 0x37, 0x75, 0x47, 0xda, - 0x66, 0x7a, 0x46, 0x5c, 0x00, 0x82, 0xfe, 0x7e, 0x78, 0x10, 0x21, 0xf2, 0xe6, 0x37, 0x5f, 0x37, - 0x88, 0x20, 0x0d, 0x6f, 0x68, 0x14, 0xe1, 0x44, 0x1f, 0x45, 0xb8, 0x2b, 0xed, 0xc6, 0x21, 0x9f, - 0xf7, 0x87, 0x85, 0x11, 0xfe, 0x4e, 0x17, 0x46, 0xd8, 0x94, 0xf4, 0x6e, 0xe1, 0x97, 0xfd, 0xe2, - 0x38, 0xc2, 0x89, 0x3e, 0x8e, 0xb0, 0x35, 0x6c, 0x24, 0xe9, 0x0f, 0xfc, 0xc3, 0x02, 0x09, 0x7b, - 0x30, 0x2f, 0xc5, 0x04, 0xf8, 0x6e, 0xb8, 0x27, 0x69, 0x4a, 0x05, 0x07, 0x56, 0x89, 0xd1, 0x33, - 0xaa, 0x08, 0x05, 0x70, 0xcc, 0x9f, 0x49, 0x67, 0x54, 0xcb, 0x87, 0xf5, 0x10, 0x56, 0x53, 0xf9, - 0x4d, 0x9b, 0xa5, 0x19, 0xb0, 0xec, 0xa3, 0xa6, 0x48, 0x92, 0x88, 0xcb, 0x68, 0x09, 0xc6, 0x5b, - 0x2c, 0xaa, 0xc0, 0xfc, 0xfb, 0x2a, 0xe6, 0x25, 0xeb, 0x17, 0x6a, 0x37, 0x1c, 0x59, 0x30, 0x65, - 0x53, 0x7a, 0x6b, 0xd0, 0xa6, 0xae, 0x3b, 0xc3, 0xab, 0x60, 0x89, 0x66, 0x35, 0x73, 0x1f, 0xc3, - 0xd1, 0x2a, 0x54, 0x39, 0x12, 0x8f, 0x49, 0x8c, 0xe2, 0x84, 0x90, 0xce, 0x99, 0x18, 0x61, 0xf1, - 0x8a, 0x54, 0xce, 0x44, 0xde, 0x17, 0x37, 0x61, 0x42, 0x6e, 0x5d, 0x14, 0xad, 0xbd, 0xfc, 0x87, - 0x1a, 0x64, 0xc0, 0x68, 0xbd, 0xd7, 0x11, 0x39, 0x25, 0xf5, 0x5e, 0x87, 0x51, 0x4e, 0x4e, 0x59, - 0x4b, 0x94, 0x72, 0x72, 0xca, 0x62, 0x1c, 0xe7, 0xa1, 0x6f, 0xc7, 0x31, 0x0e, 0x5a, 0xb0, 0x6e, - 0x2a, 0x6c, 0x46, 0x84, 0xa0, 0x4c, 0x7f, 0x73, 0x3c, 0xf6, 0xdb, 0xfa, 0x70, 0x58, 0x88, 0x98, - 0xae, 0xc0, 0xa1, 0x1d, 0x86, 0xc4, 0x77, 0x45, 0x2a, 0x49, 0x5c, 0xb6, 0xee, 0x0f, 0xbd, 0x2a, - 0x94, 0x8d, 0xfe, 0x47, 0x49, 0x1f, 0x29, 0xce, 0x4f, 0xf7, 0x74, 0x66, 0xba, 0xd9, 0x35, 0xdb, - 0x6c, 0x88, 0xe9, 0xe6, 0x45, 0x5a, 0xf3, 0xb1, 0x77, 0xfc, 0xcc, 0xee, 0x11, 0xbe, 0x1d, 0x44, - 0x91, 0x4e, 0xd1, 0xc7, 0xde, 0x71, 0xb3, 0xc1, 0xc2, 0x3b, 0x65, 0x1c, 0x15, 0xd0, 0x06, 0xcc, - 0x46, 0xfe, 0xe0, 0x2e, 0x71, 0xdb, 0xe4, 0xc0, 0xed, 0x5e, 0xb0, 0x38, 0x4d, 0x05, 0x67, 0xc9, - 0xe8, 0x06, 0xcc, 0x60, 0xe2, 0x92, 0xaf, 0x13, 0xc6, 0x71, 0xc6, 0x98, 0xa1, 0x5a, 0xf7, 0x0b, - 0xae, 0xb1, 0x82, 0x95, 0xff, 0x2c, 0x9f, 0x3d, 0xa1, 0x58, 0xf9, 0x05, 0x18, 0xa3, 0x0c, 0x01, - 0x5f, 0xfb, 0xa8, 0x40, 0x27, 0x2b, 0xb6, 0x08, 0xd8, 0xb0, 0x47, 0x71, 0x42, 0xa0, 0xbb, 0x20, - 0x1f, 0xc6, 0x51, 0x2d, 0xc8, 0xfb, 0xaa, 0xdc, 0x0b, 0x7a, 0x5e, 0x9a, 0x1d, 0xe2, 0x86, 0x4e, - 0x78, 0xc1, 0x46, 0xcd, 0xcf, 0x4b, 0x9a, 0x66, 0xfd, 0xb9, 0x04, 0x15, 0x21, 0x97, 0x2c, 0x4e, - 0x87, 0xc7, 0xee, 0x44, 0x31, 0xce, 0x45, 0x1a, 0x59, 0x1f, 0xdd, 0x98, 0x8a, 0x72, 0x91, 0xd0, - 0xed, 0x48, 0x72, 0xdf, 0xeb, 0x44, 0x2b, 0x36, 0xb3, 0x3d, 0xb3, 0xc9, 0x92, 0x2d, 0x05, 0x15, - 0xc7, 0xf5, 0x68, 0x1d, 0x26, 0x9d, 0x00, 0xdb, 0xee, 0x29, 0xf3, 0xdb, 0xd9, 0x42, 0x56, 0x70, - 0x9a, 0x84, 0x6e, 0xc2, 0xc4, 0x13, 0xaf, 0xdb, 0x21, 0x7e, 0x60, 0x8e, 0xb1, 0x90, 0xe3, 0x74, - 0x04, 0xf6, 0xa9, 0xed, 0x84, 0x47, 0xe7, 0x2e, 0x16, 0xb5, 0x94, 0x91, 0xd2, 0x28, 0xe3, 0xb8, - 0x92, 0x91, 0xd7, 0x5a, 0xbf, 0x2b, 0x29, 0x03, 0x5e, 0x74, 0x2c, 0x75, 0xb7, 0x29, 0x16, 0x87, - 0xfd, 0x46, 0x3f, 0x87, 0x29, 0xc1, 0xb7, 0xe7, 0x04, 0x21, 0x1b, 0xe7, 0xe4, 0xf6, 0x2c, 0x57, - 0x88, 0x31, 0x84, 0xc4, 0x84, 0xae, 0xc3, 0x34, 0x2d, 0x73, 0xcb, 0xbc, 0xd9, 0xe0, 0xfb, 0x56, - 0x26, 0x5a, 0xf3, 0x8a, 0x64, 0x16, 0xeb, 0x0c, 0x26, 0x8f, 0xce, 0xdd, 0xd7, 0x9b, 0x78, 0xec, - 0x7d, 0x1d, 0x4f, 0x3c, 0xfd, 0x8d, 0xee, 0xc0, 0xc4, 0x41, 0x3f, 0x64, 0xd1, 0xd9, 0x28, 0x93, - 0x69, 0x2e, 0x99, 0x77, 0x5e, 0x81, 0x05, 0x87, 0xf5, 0x9f, 0x25, 0x98, 0xe0, 0x8d, 0xa3, 0x8f, - 0xa0, 0x52, 0xf7, 0x89, 0x1d, 0x92, 0x9d, 0x90, 0xe7, 0x46, 0xae, 0x6c, 0x46, 0xa9, 0xaa, 0x9b, - 0x22, 0x55, 0x35, 0x95, 0x21, 0x59, 0xa1, 0xd7, 0xd3, 0xef, 0xff, 0x6b, 0xad, 0x84, 0x63, 0x29, - 0xb4, 0x0e, 0x65, 0xea, 0x2a, 0xb0, 0x4d, 0x3c, 0xb9, 0x3d, 0xb5, 0x19, 0x9e, 0xbb, 0x9b, 0x47, - 0xe7, 0x2e, 0xa5, 0x61, 0x56, 0x43, 0x87, 0xf2, 0x49, 0x40, 0xfc, 0xa3, 0x73, 0x97, 0x75, 0xae, - 0x82, 0x45, 0x11, 0xdd, 0x83, 0x2a, 0x5d, 0x1a, 0xda, 0xcb, 0xc0, 0x2c, 0xb3, 0x09, 0x46, 0x22, - 0x7e, 0x99, 0xcc, 0x05, 0x4e, 0x98, 0x64, 0x55, 0x32, 0x96, 0x51, 0x25, 0xd6, 0xe7, 0xaa, 0x08, - 0xa4, 0x72, 0x75, 0xef, 0xb1, 0xd9, 0xce, 0x2c, 0xee, 0x4c, 0xd2, 0x36, 0x03, 0x48, 0xb3, 0x58, - 0x8b, 0xca, 0xcc, 0x21, 0xeb, 0x9f, 0x4b, 0x50, 0x4d, 0x4c, 0x8d, 0x15, 0xa8, 0x3c, 0xf3, 0x3a, - 0xe4, 0xe8, 0xa2, 0x4f, 0x78, 0x73, 0x71, 0x99, 0xde, 0x6d, 0xf4, 0x77, 0xb3, 0xc3, 0xcf, 0x3b, - 0x2f, 0xd1, 0x21, 0x31, 0x00, 0x26, 0x14, 0xed, 0x97, 0x84, 0x40, 0x3b, 0xff, 0x49, 0x40, 0x3a, - 0x5c, 0xd1, 0xb1, 0xdf, 0x94, 0xb6, 0xeb, 0x93, 0x28, 0x08, 0x5d, 0xc6, 0xec, 0x37, 0x6d, 0xf9, - 0x89, 0x13, 0x62, 0x3b, 0x74, 0x3c, 0xa6, 0xcb, 0x46, 0x70, 0x5c, 0xb6, 0x9e, 0xa9, 0xa3, 0xa9, - 0xe8, 0x01, 0x4c, 0xc7, 0x44, 0x36, 0x0d, 0x51, 0x64, 0x3f, 0x0e, 0xc0, 0xc7, 0x02, 0x32, 0x9b, - 0xd5, 0x85, 0xd5, 0xa2, 0x34, 0x1a, 0xba, 0xe0, 0x8f, 0x7d, 0x6f, 0xd0, 0x8f, 0xb5, 0xbd, 0x28, - 0x16, 0xeb, 0x7a, 0x71, 0xe9, 0x8e, 0xca, 0x97, 0xee, 0x7d, 0xb8, 0x5a, 0x18, 0x04, 0x94, 0x73, - 0x07, 0xc7, 0x44, 0xee, 0xe0, 0xc7, 0x6c, 0xd0, 0xb9, 0xc4, 0x9c, 0x1f, 0xd2, 0x39, 0xeb, 0x0e, - 0x2c, 0x2a, 0x63, 0x86, 0x74, 0x25, 0x58, 0x7c, 0x91, 0x6f, 0x2d, 0xfa, 0xdb, 0x6a, 0xc1, 0xb2, - 0x26, 0x97, 0x07, 0xd5, 0x00, 0x1a, 0x76, 0x68, 0x1f, 0xdb, 0x01, 0x89, 0x3f, 0x86, 0xa4, 0x28, - 0x05, 0x3d, 0x78, 0x17, 0x4c, 0x5d, 0xb8, 0xb1, 0xe0, 0x1e, 0xda, 0x85, 0x8a, 0x30, 0x1e, 0x69, - 0x57, 0x0f, 0xed, 0xf0, 0x4c, 0x74, 0x95, 0xfe, 0xa6, 0x5b, 0xf2, 0xe0, 0xe4, 0x24, 0x20, 0x51, - 0x66, 0xf8, 0x28, 0xe6, 0x25, 0x34, 0x03, 0x23, 0xad, 0x6f, 0xf8, 0xe5, 0x33, 0xd2, 0xfa, 0xc6, - 0x7a, 0xc0, 0xb7, 0x28, 0x53, 0xf2, 0xb7, 0xa0, 0xfc, 0x52, 0x24, 0xa1, 0x26, 0x0a, 0x51, 0xd4, - 0x73, 0x13, 0x96, 0xb1, 0x58, 0x47, 0xf4, 0x42, 0x66, 0x43, 0x8f, 0xbb, 0xb1, 0x00, 0x63, 0xcc, - 0xa8, 0x15, 0x8b, 0xc5, 0x0a, 0xe8, 0x4e, 0xd2, 0x51, 0xae, 0x48, 0xb2, 0xb8, 0x38, 0x66, 0xb0, - 0x3e, 0x55, 0xe6, 0x3f, 0xa1, 0x8f, 0x72, 0x8d, 0xf1, 0x2e, 0xc6, 0xa1, 0x68, 0xb9, 0x16, 0x67, - 0xd9, 0xad, 0x03, 0x98, 0x13, 0x93, 0x1a, 0xa3, 0x6b, 0x3a, 0x6c, 0xc0, 0xe8, 0x13, 0x47, 0x24, - 0xd4, 0xd3, 0x9f, 0x74, 0x7e, 0x29, 0x3f, 0x37, 0xda, 0xd8, 0x6f, 0xeb, 0x0b, 0x75, 0xd8, 0x17, - 0xed, 0x2a, 0x1a, 0xe2, 0x9d, 0x35, 0x93, 0x20, 0x9b, 0x5c, 0x8f, 0xf3, 0x22, 0x16, 0x56, 0xe6, - 0x6e, 0xa1, 0x5f, 0xc2, 0x54, 0x4c, 0x13, 0x19, 0xcc, 0x93, 0xdb, 0xcb, 0x9b, 0xc9, 0x7b, 0x86, - 0x74, 0x35, 0x96, 0x98, 0xf9, 0xb9, 0xc9, 0x07, 0x88, 0xb7, 0xa1, 0x1a, 0x13, 0xe3, 0x34, 0x7a, - 0x05, 0x22, 0x4e, 0xd8, 0xac, 0x7f, 0x2c, 0xc1, 0xe4, 0xa1, 0x4f, 0xfa, 0xb6, 0x4f, 0x5a, 0x61, - 0x8f, 0xcd, 0x11, 0xb3, 0xe6, 0xf8, 0x1e, 0x64, 0xa6, 0x9c, 0x01, 0xa3, 0xad, 0xe7, 0x7b, 0xc2, - 0xfe, 0x6d, 0x3d, 0xdf, 0xa3, 0xa7, 0xe4, 0xd0, 0xf6, 0xed, 0x1e, 0xd5, 0x7f, 0x01, 0x9f, 0xcf, - 0x14, 0x05, 0xbd, 0x0f, 0xcb, 0x74, 0xa4, 0x8e, 0x4f, 0x3a, 0xd9, 0x4f, 0x21, 0x65, 0xb6, 0x65, - 0x75, 0xd5, 0xd6, 0x19, 0x18, 0x3c, 0xea, 0x7b, 0x44, 0x7a, 0xfd, 0x28, 0x34, 0xbf, 0x02, 0x15, - 0x71, 0x02, 0x85, 0xca, 0x16, 0x65, 0xba, 0xf6, 0x3b, 0x5d, 0xc7, 0x8e, 0x2d, 0x34, 0x56, 0xa0, - 0x46, 0xd4, 0xe1, 0xd9, 0x45, 0xe0, 0xb4, 0xed, 0x6e, 0xca, 0x36, 0x95, 0x68, 0xd6, 0xbf, 0x8d, - 0xe8, 0x32, 0xd6, 0xe8, 0xa1, 0xa3, 0xa4, 0x58, 0xff, 0xf0, 0x12, 0x7a, 0x37, 0x7e, 0x4e, 0x10, - 0x7d, 0x07, 0x5d, 0x55, 0x87, 0xc5, 0x23, 0x1e, 0xf1, 0xd8, 0x00, 0x7d, 0x04, 0x57, 0xe2, 0xb1, - 0x44, 0x9c, 0x8e, 0xe7, 0xb6, 0x06, 0xfd, 0xbe, 0xe7, 0x87, 0xfc, 0xda, 0xa8, 0xe0, 0x22, 0x16, - 0xb4, 0x0b, 0xb5, 0x3d, 0x3b, 0x08, 0x9b, 0x6e, 0x40, 0xfc, 0xb0, 0xd9, 0x50, 0x80, 0x44, 0x46, - 0xf4, 0x10, 0x2e, 0xf4, 0x0c, 0x2c, 0xbe, 0xd6, 0x1d, 0xba, 0x03, 0x58, 0xb8, 0x5b, 0x2c, 0x40, - 0x82, 0x15, 0xd9, 0xd9, 0xaf, 0xc1, 0xf9, 0x71, 0xb9, 0x32, 0x6a, 0x94, 0xad, 0x6f, 0xab, 0xda, - 0xcf, 0x07, 0x54, 0x4d, 0x35, 0x1e, 0xf2, 0x45, 0x1b, 0x69, 0x3c, 0x44, 0x0f, 0x60, 0x2a, 0xb5, - 0xdb, 0x02, 0x7e, 0xab, 0x0b, 0x8b, 0x22, 0x55, 0x85, 0x25, 0x3e, 0x74, 0x1b, 0x0c, 0x3a, 0xb6, - 0x9d, 0x93, 0x13, 0xd2, 0x0e, 0x49, 0x87, 0x59, 0x57, 0x91, 0xf2, 0xcb, 0xd1, 0xd1, 0x87, 0x30, - 0x43, 0xad, 0x97, 0x3d, 0xf2, 0x8a, 0x74, 0xd3, 0x76, 0xcb, 0x82, 0xf8, 0x28, 0x94, 0xae, 0xc4, - 0x19, 0x5e, 0xd4, 0x80, 0xab, 0x32, 0x03, 0xe9, 0x12, 0x3b, 0x20, 0xd9, 0xa9, 0x2e, 0x66, 0x42, - 0xbb, 0x30, 0x4b, 0x19, 0x1a, 0xe4, 0xc4, 0x71, 0x49, 0xe7, 0x85, 0x1d, 0xdb, 0xbd, 0x99, 0x2d, - 0x23, 0x33, 0xe1, 0xac, 0x10, 0x3d, 0x48, 0x19, 0xd2, 0xa3, 0x73, 0xde, 0x8f, 0x09, 0xd6, 0x0f, - 0x5d, 0x35, 0xed, 0x41, 0xeb, 0x22, 0x08, 0x49, 0xef, 0x85, 0xed, 0x3b, 0x74, 0x5f, 0x05, 0x66, - 0x45, 0xd5, 0x03, 0x99, 0x09, 0x67, 0x85, 0x68, 0x0f, 0x32, 0xa4, 0xb8, 0x07, 0xd5, 0xa8, 0x07, - 0x9a, 0x6a, 0xf4, 0x21, 0x5c, 0xce, 0x74, 0x0e, 0x93, 0x7e, 0xd7, 0xbe, 0x60, 0xdf, 0xe9, 0x80, - 0xc9, 0xea, 0x19, 0xa8, 0x74, 0x06, 0x38, 0x25, 0x3d, 0x19, 0x49, 0x6b, 0x19, 0xd0, 0x13, 0x58, - 0xcb, 0x54, 0xb6, 0x5c, 0xbb, 0x1f, 0x9c, 0x79, 0xe1, 0x91, 0xe7, 0xed, 0xd9, 0xfe, 0x29, 0x61, - 0xdf, 0x89, 0x2b, 0x78, 0x18, 0x1b, 0x45, 0xca, 0x74, 0x32, 0x87, 0x34, 0x1d, 0x21, 0x0d, 0x61, - 0xa3, 0x7a, 0x20, 0x39, 0x53, 0xbd, 0x70, 0xcf, 0x73, 0x4f, 0xa9, 0x1a, 0xab, 0x9f, 0x91, 0xf6, - 0x4b, 0xd2, 0x61, 0xdf, 0x88, 0x2b, 0xb8, 0x88, 0x85, 0xda, 0xa1, 0xbb, 0xde, 0xc0, 0x8d, 0xb6, - 0xff, 0x6c, 0x94, 0xa8, 0x11, 0x13, 0xd0, 0x7b, 0x00, 0xb1, 0x12, 0x09, 0x4c, 0x83, 0x2d, 0xf6, - 0xb2, 0xbc, 0xd8, 0x71, 0x3d, 0x4e, 0xb1, 0xa2, 0x07, 0xb0, 0x14, 0x97, 0xd8, 0x69, 0x8f, 0x57, - 0x78, 0x8e, 0xf5, 0x49, 0x53, 0x8b, 0x7e, 0x05, 0x2b, 0xe9, 0xde, 0xd6, 0x07, 0x7e, 0xe0, 0xf9, - 0x81, 0x18, 0xcf, 0x02, 0x93, 0x2d, 0xe0, 0xa0, 0x5a, 0x3a, 0xad, 0xb0, 0xd8, 0x27, 0xe0, 0x32, - 0x96, 0x68, 0x68, 0x1b, 0x16, 0xd2, 0xe5, 0xb8, 0x67, 0xf3, 0x0c, 0x5d, 0x59, 0x67, 0xfd, 0x61, - 0x5c, 0x9d, 0x34, 0xac, 0xd5, 0xeb, 0x91, 0x96, 0x1a, 0x89, 0xb5, 0xd4, 0x3a, 0x4c, 0xb6, 0x48, - 0xf8, 0xc2, 0xf6, 0x23, 0x25, 0x35, 0xca, 0x02, 0x30, 0x69, 0x52, 0x4e, 0x8f, 0x95, 0x7f, 0x84, - 0x1e, 0x1b, 0x7b, 0x6d, 0x3d, 0x36, 0xfe, 0x06, 0x7a, 0x4c, 0xa1, 0x81, 0x26, 0x7e, 0x62, 0x0d, - 0x54, 0x79, 0x63, 0x0d, 0x54, 0xfd, 0x89, 0x35, 0x10, 0xfc, 0x08, 0x0d, 0x34, 0xf9, 0xa3, 0x34, - 0xd0, 0xd4, 0x30, 0x0d, 0x24, 0x9d, 0xd5, 0xe9, 0xe2, 0xb3, 0x3a, 0xf3, 0xfa, 0x67, 0x35, 0x7b, - 0x66, 0x66, 0xdf, 0xe0, 0xcc, 0x18, 0x05, 0x67, 0xe6, 0x7f, 0x4b, 0xf1, 0x97, 0x7a, 0x79, 0x46, - 0x94, 0x16, 0xe1, 0x3a, 0x8c, 0xbd, 0xb0, 0xbb, 0x03, 0xc2, 0x3d, 0x01, 0xd8, 0x64, 0xcf, 0x6e, - 0x1f, 0x9d, 0xf7, 0x7d, 0x1c, 0x55, 0x30, 0x9b, 0xf1, 0xab, 0x2e, 0x37, 0xbc, 0xe8, 0x4f, 0x66, - 0xa5, 0x07, 0x0f, 0x1d, 0x97, 0x1b, 0x3c, 0x51, 0x81, 0x1e, 0x08, 0x7e, 0x40, 0x98, 0xf9, 0xf8, - 0x94, 0xba, 0x6a, 0x51, 0xd0, 0x20, 0x47, 0x47, 0x35, 0x28, 0x33, 0x0f, 0x7c, 0x3c, 0xdd, 0x28, - 0xa5, 0x60, 0x46, 0x47, 0xf7, 0x60, 0x1e, 0x0f, 0xdc, 0xd0, 0xe9, 0x91, 0x56, 0xe8, 0x3b, 0xee, - 0x69, 0xc3, 0xeb, 0xd9, 0x8e, 0xcb, 0x2e, 0xca, 0x69, 0xac, 0xaa, 0xb2, 0x9e, 0xc3, 0xb4, 0x74, - 0x6c, 0x94, 0x83, 0x8d, 0x9d, 0xd7, 0xc8, 0xe1, 0x8b, 0x0a, 0xec, 0x35, 0xef, 0xb9, 0xdb, 0x6c, - 0x44, 0xea, 0x61, 0x0a, 0xf3, 0x92, 0xf5, 0x33, 0x4d, 0xc6, 0x43, 0x81, 0x0f, 0xf8, 0x4b, 0x58, - 0x1b, 0xf2, 0xd6, 0x20, 0xed, 0x76, 0x96, 0x64, 0xb7, 0xd3, 0x82, 0xf5, 0x61, 0x69, 0x0e, 0xd6, - 0x06, 0x7b, 0xf2, 0xa1, 0x78, 0x2c, 0x40, 0x35, 0x5f, 0xfd, 0x99, 0xb0, 0xcf, 0xea, 0xcf, 0xf8, - 0xfb, 0x3f, 0x55, 0x42, 0x82, 0xe6, 0xfd, 0xdf, 0x5d, 0xe5, 0xb3, 0x02, 0x9d, 0xa6, 0xb5, 0x0e, - 0xd5, 0xe9, 0x0b, 0xfa, 0xc9, 0xa1, 0xae, 0xc6, 0xce, 0x20, 0x3c, 0x8b, 0x96, 0x8d, 0x2d, 0xc1, - 0x14, 0x4e, 0x51, 0xac, 0x2d, 0xc5, 0x4b, 0x04, 0xea, 0x31, 0x08, 0x92, 0x78, 0x27, 0x29, 0xca, - 0xd6, 0x3d, 0x55, 0xc2, 0x43, 0xa1, 0xc4, 0x07, 0x8a, 0xe7, 0x09, 0xe8, 0x3a, 0x4c, 0x0b, 0xd2, - 0xc3, 0x8b, 0x90, 0x88, 0xa7, 0xb2, 0x32, 0xd1, 0xfa, 0x85, 0x2a, 0x19, 0xe2, 0x35, 0x65, 0xcf, - 0xb4, 0xef, 0x18, 0xd0, 0x16, 0x3f, 0x09, 0x25, 0xe6, 0x86, 0x5c, 0xd1, 0xa4, 0x25, 0xa4, 0x8e, - 0x86, 0x88, 0x60, 0xb5, 0x9c, 0x6f, 0x08, 0x8f, 0x24, 0x24, 0x04, 0xeb, 0x5c, 0x9f, 0x61, 0x21, - 0x4b, 0x96, 0x32, 0x92, 0x74, 0x24, 0xac, 0x50, 0xb7, 0xfb, 0x76, 0xdb, 0x09, 0x2f, 0x38, 0xb6, - 0x4c, 0xa4, 0xab, 0xbb, 0x4f, 0x82, 0xc0, 0x3e, 0x8d, 0xbf, 0x12, 0xf0, 0xa2, 0x75, 0x50, 0xfc, - 0x96, 0xe2, 0x8d, 0x07, 0x6a, 0xfd, 0x76, 0x48, 0x26, 0xc7, 0x5f, 0x79, 0x3c, 0xef, 0xaa, 0x1f, - 0x6b, 0x14, 0xb7, 0x6a, 0xfd, 0x8d, 0x26, 0x19, 0x24, 0xdf, 0x9d, 0x92, 0xa2, 0x3b, 0xd6, 0xff, - 0x95, 0x86, 0xa4, 0xe9, 0x0f, 0xf9, 0xbc, 0xc3, 0x3a, 0x17, 0xda, 0x5d, 0xef, 0x34, 0x8e, 0x6a, - 0x25, 0x04, 0x5a, 0x4b, 0xd5, 0x20, 0x4b, 0x84, 0x10, 0xc1, 0xcf, 0x98, 0x40, 0xb5, 0x42, 0x94, - 0x78, 0x57, 0x8e, 0xfc, 0xef, 0xc8, 0x63, 0xaf, 0x01, 0x08, 0xf3, 0x97, 0x07, 0x81, 0x47, 0x71, - 0x8a, 0x42, 0x6f, 0x28, 0x31, 0xe0, 0x3d, 0xaf, 0xcd, 0xbc, 0xd4, 0x27, 0x76, 0x70, 0xc6, 0x34, - 0x7b, 0x15, 0x2b, 0xeb, 0xe8, 0x09, 0x8d, 0xd2, 0x36, 0x9b, 0x0d, 0xa6, 0xd2, 0xab, 0x38, 0x2e, - 0x5b, 0x4f, 0x86, 0xe5, 0x1a, 0x44, 0x9f, 0x93, 0x7a, 0xde, 0x2b, 0xd2, 0x79, 0xe4, 0x86, 0xbe, - 0x13, 0x9f, 0xb9, 0x0c, 0xd5, 0xda, 0x54, 0x3d, 0x8b, 0xa1, 0x0b, 0xce, 0x29, 0x5c, 0x39, 0x88, - 0xa2, 0xb5, 0xa5, 0xcc, 0xb6, 0x29, 0x10, 0xd8, 0x53, 0x3d, 0x93, 0xa1, 0xfa, 0x92, 0x67, 0x58, - 0xf3, 0x97, 0xda, 0x3c, 0x99, 0x5a, 0x04, 0x5a, 0x08, 0xfb, 0x74, 0x12, 0x59, 0xa8, 0x29, 0x8a, - 0x75, 0x4b, 0x99, 0x98, 0xa3, 0xfc, 0xdc, 0x74, 0x5b, 0xf7, 0xa8, 0x26, 0xff, 0xdd, 0xcb, 0xba, - 0xab, 0xcd, 0xd0, 0x51, 0x42, 0xf7, 0x0a, 0x9e, 0xd4, 0xa0, 0x0d, 0x98, 0xe5, 0xff, 0xa8, 0x21, - 0xfe, 0x66, 0x16, 0x5d, 0x61, 0x59, 0x32, 0x5d, 0xa3, 0x4f, 0x7d, 0x27, 0x4c, 0x20, 0xf8, 0x66, - 0xcc, 0x50, 0x2d, 0xb7, 0x28, 0xbf, 0xe7, 0xaf, 0xd0, 0xde, 0x0b, 0x75, 0xb2, 0x0f, 0xfa, 0x15, - 0x4c, 0xa5, 0xe9, 0xaf, 0xf1, 0x9f, 0x2b, 0x24, 0x7e, 0xeb, 0x1f, 0x4a, 0x45, 0x8f, 0x5d, 0x86, - 0x1c, 0x5a, 0x0b, 0xa6, 0xea, 0xd1, 0x47, 0x7d, 0xc7, 0x73, 0xe3, 0x73, 0x2b, 0xd1, 0xa8, 0x71, - 0xc5, 0xe3, 0x6a, 0x8f, 0xce, 0xdb, 0xdd, 0x41, 0xe0, 0xbc, 0x22, 0x3c, 0x74, 0x9f, 0xa3, 0x5b, - 0xef, 0x15, 0x66, 0xce, 0x14, 0x58, 0x2f, 0xff, 0x92, 0x58, 0x8e, 0xb2, 0x35, 0xfc, 0x03, 0x2d, - 0xc7, 0x0d, 0x98, 0x7d, 0x46, 0xce, 0xc3, 0x23, 0xdf, 0x76, 0x03, 0x3b, 0x8a, 0xb6, 0x45, 0xdf, - 0xa4, 0xb2, 0x64, 0xb4, 0x09, 0x53, 0xdc, 0xa8, 0x8b, 0x20, 0xcb, 0x39, 0x48, 0xa9, 0xde, 0xfa, - 0xf7, 0x52, 0xc1, 0x9b, 0x1f, 0xad, 0x73, 0xb8, 0x0a, 0x55, 0x6a, 0x23, 0x36, 0xdd, 0xfe, 0x20, - 0xe4, 0x27, 0x30, 0x21, 0x48, 0xb1, 0xc9, 0xd1, 0x4c, 0x6c, 0xd2, 0x82, 0x29, 0x29, 0x25, 0xa8, - 0xcc, 0x8c, 0x17, 0x89, 0x46, 0xe7, 0xa8, 0x65, 0x77, 0xa3, 0x7f, 0x23, 0x30, 0x85, 0xd9, 0x6f, - 0xa6, 0xf5, 0xd9, 0x1a, 0xec, 0x74, 0x3a, 0x3e, 0x9d, 0xf1, 0x48, 0x2d, 0xca, 0x44, 0xeb, 0x5f, - 0x4b, 0x45, 0xf9, 0x47, 0x3f, 0xdc, 0xa2, 0xa2, 0xca, 0x99, 0x96, 0x88, 0x1b, 0x3a, 0x91, 0xfa, - 0xdd, 0xb5, 0x9d, 0x2e, 0xe9, 0xf0, 0x55, 0x50, 0xd6, 0x45, 0xdf, 0xf5, 0xa3, 0xc7, 0x2b, 0xe4, - 0x4b, 0xe6, 0xc2, 0x72, 0x33, 0x3f, 0x4b, 0xb6, 0xbe, 0x2d, 0xc1, 0x42, 0x2a, 0xd5, 0xe5, 0xd0, - 0x77, 0xdc, 0xb6, 0xd3, 0xb7, 0xbb, 0x43, 0xb6, 0xfb, 0x12, 0x8c, 0xb3, 0x49, 0x8f, 0x36, 0xfa, - 0x34, 0xe6, 0x25, 0x3a, 0x4c, 0xce, 0x24, 0xae, 0x62, 0x5e, 0xe4, 0x9f, 0xe5, 0x7c, 0x7e, 0x31, - 0xb1, 0xdf, 0xd1, 0x87, 0xd9, 0x6e, 0xf4, 0x59, 0x8e, 0x2a, 0x2f, 0xaf, 0x4b, 0xac, 0x3f, 0x94, - 0x54, 0x6f, 0x7f, 0x32, 0xdb, 0xa1, 0x1c, 0x6f, 0x87, 0x1b, 0x30, 0x23, 0x12, 0x4c, 0x48, 0x12, - 0x0b, 0xae, 0xe0, 0x0c, 0x95, 0xc5, 0x10, 0x44, 0xe4, 0x34, 0xfe, 0xca, 0x9c, 0x26, 0xa1, 0x0f, - 0xa0, 0x1a, 0x8f, 0x9e, 0xef, 0xdd, 0x2b, 0xf9, 0x04, 0xa1, 0x98, 0x05, 0x27, 0xdc, 0xd6, 0x1d, - 0x65, 0x96, 0x11, 0xbd, 0x8c, 0x99, 0x8b, 0xc9, 0x57, 0x3c, 0x2a, 0x58, 0xdb, 0xfa, 0x07, 0x49, - 0x5a, 0x3b, 0xfd, 0x4a, 0x41, 0xe2, 0xd1, 0xed, 0xbf, 0x4c, 0xa4, 0x9e, 0x04, 0xa1, 0x2a, 0xff, - 0x37, 0x48, 0xc6, 0x25, 0x34, 0x0f, 0xb3, 0x99, 0x57, 0x3a, 0x46, 0x09, 0x19, 0x30, 0x95, 0x4e, - 0x0c, 0x32, 0x46, 0xd0, 0x14, 0x54, 0xc4, 0x64, 0x19, 0xa3, 0x68, 0x1a, 0xaa, 0x71, 0xbe, 0x84, - 0x51, 0x46, 0xb3, 0x30, 0x99, 0xfa, 0xfe, 0x6f, 0x8c, 0xa1, 0x19, 0x80, 0xe4, 0x8b, 0xb1, 0x31, - 0x4e, 0xf1, 0xd2, 0x9f, 0x4a, 0x8d, 0x09, 0xca, 0x91, 0x3c, 0x06, 0x31, 0x2a, 0x14, 0x31, 0x7e, - 0xe3, 0x61, 0x54, 0xd1, 0x92, 0xea, 0x95, 0x87, 0x01, 0x94, 0x9e, 0x7f, 0x6d, 0x61, 0x4c, 0x22, - 0x94, 0x7d, 0x6f, 0x61, 0x4c, 0xa1, 0xc9, 0xf8, 0xf1, 0x84, 0x31, 0x8d, 0x2e, 0x6b, 0xde, 0x45, - 0x18, 0x33, 0x68, 0x2e, 0xf3, 0xac, 0xc1, 0x98, 0x45, 0x0b, 0xf9, 0x57, 0x0a, 0x86, 0x91, 0x1e, - 0x05, 0xd5, 0x17, 0xc6, 0x1c, 0xa7, 0xc4, 0x5f, 0x66, 0x0c, 0x44, 0xa7, 0x33, 0x93, 0xb1, 0x6f, - 0xcc, 0x53, 0x62, 0x26, 0xd8, 0x6e, 0x2c, 0xd0, 0x66, 0x25, 0xa7, 0xd3, 0x58, 0x44, 0xab, 0xfa, - 0x2c, 0x79, 0x63, 0x89, 0x4e, 0x51, 0x9c, 0xaa, 0x64, 0x2c, 0xf3, 0x96, 0xd2, 0x6e, 0x9f, 0x61, - 0xd2, 0x0e, 0xa5, 0x7d, 0x35, 0xe3, 0x32, 0x5b, 0x8a, 0x83, 0xfd, 0x9d, 0xcf, 0x0e, 0xf1, 0x41, - 0xbd, 0x65, 0xac, 0xf0, 0xf2, 0xa3, 0xfd, 0xbd, 0xe6, 0x7e, 0xf3, 0xc8, 0xb8, 0x42, 0x87, 0x9a, - 0x35, 0xbe, 0x8d, 0x55, 0x3a, 0x5d, 0x4a, 0x93, 0xdc, 0xb8, 0xca, 0xfa, 0x9d, 0x36, 0x7c, 0x8d, - 0x1a, 0x5b, 0xff, 0x83, 0xd8, 0xa0, 0x32, 0xd6, 0x28, 0x21, 0x65, 0xe2, 0x18, 0xeb, 0xb4, 0xb3, - 0x19, 0xe3, 0xc4, 0xb8, 0x46, 0x17, 0x33, 0x6f, 0x13, 0x18, 0x16, 0x1d, 0x44, 0xfa, 0xce, 0x35, - 0xde, 0x42, 0x57, 0x98, 0x6d, 0xa3, 0x4a, 0x9f, 0x32, 0xae, 0xa3, 0x45, 0x98, 0xcb, 0x65, 0x13, - 0x19, 0x6f, 0xa3, 0x15, 0x58, 0x52, 0xdb, 0x97, 0xc6, 0x0d, 0xb4, 0x0c, 0xf3, 0x8a, 0x8b, 0xd3, - 0xb8, 0x49, 0xbb, 0x94, 0xd7, 0xcf, 0xc6, 0x06, 0x7a, 0x6b, 0x68, 0x52, 0xa7, 0x71, 0x8b, 0xf6, - 0x52, 0x93, 0x2c, 0x69, 0xdc, 0xa6, 0x33, 0xaa, 0xcc, 0x72, 0x34, 0xee, 0x68, 0xe4, 0x9e, 0x92, - 0x8b, 0xc0, 0x78, 0x87, 0x4e, 0x65, 0x4a, 0x6d, 0x18, 0x77, 0xe9, 0x70, 0x73, 0xc7, 0xdc, 0xd8, - 0xbc, 0xfd, 0x6d, 0x49, 0x0a, 0x62, 0x24, 0xdf, 0xb4, 0x68, 0xcb, 0x99, 0x8a, 0x28, 0x82, 0x64, - 0x5c, 0x42, 0x77, 0xe0, 0x66, 0xa6, 0xaa, 0xf5, 0xd2, 0xe9, 0xab, 0x3e, 0x93, 0x18, 0x25, 0x74, - 0x17, 0x6e, 0x65, 0x71, 0x5c, 0xba, 0x9c, 0x4a, 0xf6, 0x91, 0xdb, 0xef, 0xc0, 0x82, 0xca, 0xe7, - 0x43, 0x40, 0xcd, 0xe6, 0x9e, 0xc7, 0x94, 0x4f, 0x05, 0xca, 0x0d, 0x27, 0x78, 0x69, 0x94, 0x1e, - 0xee, 0xfd, 0xf1, 0xbb, 0x5a, 0xe9, 0x4f, 0xdf, 0xd5, 0x4a, 0xff, 0xfd, 0x5d, 0xed, 0xd2, 0xef, - 0xbf, 0xaf, 0x5d, 0xfa, 0xa7, 0xef, 0x6b, 0xa5, 0x3f, 0x7d, 0x5f, 0xbb, 0xf4, 0xe7, 0xef, 0x6b, - 0x97, 0x3e, 0xdf, 0x4c, 0xfd, 0x5b, 0xb8, 0x9e, 0x1d, 0xfa, 0xce, 0xb9, 0xe7, 0x3b, 0xa7, 0x8e, - 0x2b, 0x0a, 0x2e, 0xd9, 0xea, 0xbf, 0x3c, 0xdd, 0xea, 0x1f, 0x6f, 0x31, 0x5d, 0x7c, 0x3c, 0xce, - 0xb2, 0x6c, 0x7e, 0xfe, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x02, 0x73, 0xa3, 0xf8, 0xb6, 0x4e, - 0x00, 0x00, + // 5688 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x7c, 0x5b, 0x6f, 0x1c, 0x47, + 0x76, 0xbf, 0x46, 0x1c, 0x92, 0x33, 0x87, 0xb7, 0x56, 0xf1, 0xd6, 0xa2, 0x28, 0x92, 0x6a, 0xcb, + 0xba, 0x5a, 0xa4, 0x96, 0xbb, 0x92, 0xd7, 0x5e, 0xff, 0x0d, 0x93, 0x43, 0x51, 0x1a, 0x8b, 0x37, + 0xd5, 0x50, 0x92, 0xd7, 0x0b, 0xf8, 0x9f, 0xe6, 0x4c, 0x91, 0x6c, 0xab, 0xa7, 0x7b, 0xdc, 0xdd, + 0x23, 0x91, 0x06, 0x36, 0x4f, 0x79, 0x0a, 0x10, 0x63, 0x3f, 0x42, 0xf2, 0x94, 0xe7, 0x05, 0xf2, + 0x19, 0x82, 0x05, 0xf2, 0xb2, 0x08, 0x02, 0x64, 0x5f, 0x92, 0x2c, 0xec, 0x8f, 0x10, 0x20, 0xaf, + 0x09, 0xaa, 0xba, 0xaa, 0xbb, 0xab, 0xbb, 0xaa, 0x47, 0xbe, 0xec, 0x0b, 0x31, 0x75, 0xea, 0x9c, + 0x5f, 0x55, 0xd7, 0xe5, 0xd4, 0x39, 0xa7, 0x4e, 0x11, 0xc6, 0xbe, 0xea, 0x93, 0xe0, 0x7c, 0xb5, + 0x17, 0xf8, 0x91, 0x8f, 0x86, 0x59, 0x61, 0x61, 0x3c, 0x8c, 0xec, 0xa8, 0x1f, 0xc6, 0xc4, 0x05, + 0x70, 0xfd, 0xf6, 0x2b, 0xfe, 0xbb, 0x1e, 0x9d, 0x79, 0xfc, 0xe7, 0x54, 0xe4, 0x74, 0x49, 0x18, + 0xd9, 0xdd, 0x9e, 0x20, 0x50, 0xa9, 0xd0, 0xf1, 0x8e, 0x7d, 0x21, 0xd8, 0x73, 0x6d, 0xc1, 0x7d, + 0xef, 0xc4, 0x89, 0x4e, 0xfb, 0x47, 0xab, 0x6d, 0xbf, 0xbb, 0x76, 0xe2, 0x9f, 0xf8, 0x6b, 0x8c, + 0x7c, 0xd4, 0x3f, 0x66, 0x25, 0x56, 0x60, 0xbf, 0x38, 0xfb, 0xf2, 0x89, 0xef, 0x9f, 0xb8, 0x24, + 0xe5, 0xca, 0x35, 0x66, 0x5d, 0x87, 0xf1, 0x67, 0xb4, 0xaf, 0x98, 0x7c, 0xd5, 0x27, 0x61, 0x84, + 0x66, 0x60, 0x98, 0x95, 0xcd, 0xca, 0x4a, 0xe5, 0x56, 0x1d, 0xc7, 0x05, 0x6b, 0x0f, 0xe6, 0x5a, + 0xa7, 0xfe, 0x9b, 0x83, 0xc0, 0x6f, 0x93, 0x30, 0xdc, 0x71, 0xc2, 0x48, 0xf0, 0xcf, 0xc1, 0xc8, + 0x21, 0xf1, 0x6c, 0x2f, 0xe2, 0x02, 0xbc, 0x84, 0x16, 0xa1, 0xde, 0x3a, 0x0f, 0x79, 0xd5, 0xc5, + 0x95, 0xca, 0xad, 0x1a, 0x4e, 0x09, 0xd6, 0x4b, 0xb8, 0xd4, 0x3a, 0xf7, 0xda, 0x0d, 0xbf, 0xdb, + 0x75, 0x12, 0xa8, 0x4d, 0x98, 0xdc, 0xb1, 0x23, 0x12, 0x46, 0x31, 0xf9, 0xb0, 0xc5, 0x20, 0xc7, + 0xd6, 0x67, 0x56, 0xd3, 0x4e, 0x1f, 0x8a, 0x5f, 0x9b, 0xd5, 0x3f, 0xfc, 0xe7, 0xf2, 0x05, 0x9c, + 0x93, 0xb0, 0x3e, 0x07, 0x94, 0x05, 0x0e, 0x7b, 0xbe, 0x17, 0x12, 0xb4, 0x05, 0x53, 0x8d, 0x7e, + 0x10, 0x10, 0xef, 0xfb, 0x40, 0xe7, 0x45, 0x2c, 0x04, 0xc6, 0x63, 0x12, 0x49, 0x7d, 0xb6, 0x7e, + 0x0d, 0x97, 0x32, 0xb4, 0x9f, 0xb4, 0xb9, 0x35, 0x98, 0x6d, 0xf8, 0x01, 0xd9, 0xea, 0x77, 0x7b, + 0x0d, 0xdf, 0x3b, 0x76, 0x4e, 0x32, 0x43, 0xbe, 0xd1, 0x8e, 0x1c, 0xdf, 0x13, 0x43, 0x1e, 0x97, + 0x2c, 0x13, 0xe6, 0xf2, 0x02, 0x71, 0x87, 0xac, 0x2b, 0x70, 0xf9, 0x31, 0x89, 0x0e, 0xe8, 0x84, + 0xb7, 0x7d, 0xf7, 0x05, 0x09, 0x42, 0xc7, 0xf7, 0xc4, 0x27, 0x3c, 0x84, 0x05, 0x55, 0x25, 0xff, + 0x16, 0x13, 0x46, 0x39, 0x89, 0xb5, 0x36, 0x84, 0x45, 0xd1, 0x7a, 0x00, 0x97, 0x5b, 0x3a, 0xd0, + 0x12, 0xb1, 0x27, 0x70, 0xa3, 0x45, 0xa2, 0x17, 0xa4, 0x1d, 0xf9, 0x41, 0xd3, 0xeb, 0x90, 0xb3, + 0xed, 0x80, 0x84, 0xa7, 0x1e, 0x09, 0xc3, 0xa6, 0x17, 0x91, 0xe0, 0xb5, 0xed, 0x0a, 0x8c, 0x25, + 0x00, 0x41, 0xda, 0x0b, 0x39, 0x4c, 0x86, 0x62, 0x35, 0xe1, 0xe6, 0x40, 0x24, 0xfe, 0x15, 0x83, + 0xa0, 0xd6, 0x61, 0xe9, 0xb1, 0x04, 0xd5, 0xb0, 0xdb, 0xa7, 0xa4, 0xe9, 0x1d, 0xfb, 0xa2, 0x33, + 0x06, 0x0c, 0x3d, 0x25, 0x62, 0x57, 0xd0, 0x9f, 0xd6, 0xfb, 0xb0, 0xac, 0x95, 0xe1, 0xcd, 0xce, + 0xc0, 0x70, 0xc3, 0xef, 0xf3, 0xbd, 0x31, 0x84, 0xe3, 0x82, 0x75, 0x1f, 0x16, 0x1f, 0xbd, 0x76, + 0xda, 0x05, 0x51, 0x7d, 0x53, 0x1f, 0xc0, 0x55, 0x8d, 0x44, 0x3a, 0x4b, 0x8c, 0x81, 0x74, 0xc4, + 0x70, 0xf3, 0xa2, 0xb5, 0xa2, 0xfc, 0xb2, 0xa7, 0xe4, 0x3c, 0x14, 0xf3, 0xff, 0x40, 0xf9, 0x1d, + 0x31, 0x07, 0x87, 0x47, 0x50, 0xa5, 0x65, 0xb3, 0xb2, 0x32, 0x74, 0xab, 0x8e, 0xd9, 0x6f, 0xba, + 0x6c, 0x5a, 0x3f, 0x64, 0xd9, 0xbc, 0x07, 0x93, 0xb8, 0xef, 0x1d, 0xda, 0xe1, 0x2b, 0xf1, 0xbd, + 0x0b, 0x50, 0xa3, 0xc5, 0x86, 0xdf, 0x21, 0x8c, 0x79, 0x18, 0x27, 0x65, 0xeb, 0x36, 0x4c, 0x25, + 0xdc, 0x1c, 0x7a, 0x0e, 0x46, 0x30, 0x09, 0xfb, 0x6e, 0xa2, 0x71, 0xe2, 0x12, 0x5d, 0xfe, 0x74, + 0x1d, 0x3b, 0x3d, 0xe2, 0x3a, 0x5e, 0x76, 0xee, 0xac, 0x35, 0x98, 0x2f, 0xd4, 0x94, 0xce, 0xd0, + 0xbf, 0x2e, 0xc3, 0xa8, 0xe8, 0xdd, 0x22, 0xd4, 0xf9, 0xcf, 0xe6, 0x16, 0xe3, 0xaa, 0xe2, 0x94, + 0x80, 0x56, 0xa1, 0xde, 0xe8, 0x76, 0x76, 0x49, 0x74, 0xea, 0x77, 0x98, 0x9a, 0x9b, 0x5c, 0x37, + 0x56, 0xe3, 0x93, 0x20, 0xa1, 0xe3, 0x94, 0x05, 0xbd, 0x2f, 0xab, 0x5b, 0x73, 0x88, 0xe9, 0x85, + 0x69, 0x2e, 0x92, 0xad, 0xc2, 0xb2, 0x5e, 0x7e, 0xae, 0xd3, 0xc0, 0x66, 0x95, 0x41, 0x5c, 0xe5, + 0x10, 0x6a, 0x26, 0xac, 0x53, 0xdf, 0x3b, 0x30, 0xbd, 0xe1, 0x46, 0x24, 0xd8, 0x68, 0xb7, 0xe9, + 0x97, 0x0b, 0xcc, 0x61, 0x86, 0xb9, 0xc0, 0x31, 0x15, 0x1c, 0x58, 0x25, 0x86, 0x3e, 0x81, 0xa9, + 0xa7, 0x8e, 0xeb, 0x36, 0x7c, 0x4f, 0x28, 0x02, 0x73, 0x84, 0x21, 0xcd, 0x71, 0xa4, 0x5c, 0x2d, + 0xce, 0xb3, 0xa3, 0x06, 0x18, 0x87, 0x81, 0xdd, 0x26, 0xad, 0x9e, 0x9d, 0x40, 0x8c, 0x32, 0x88, + 0x79, 0x0e, 0x91, 0xaf, 0xc6, 0x05, 0x01, 0xd4, 0x04, 0xf4, 0x98, 0x44, 0x3b, 0x7e, 0xfb, 0x55, + 0x66, 0x15, 0x98, 0x35, 0x06, 0x73, 0x99, 0xc3, 0x14, 0x19, 0xb0, 0x42, 0x08, 0x6d, 0x33, 0xfd, + 0x7e, 0x78, 0xe6, 0x65, 0x91, 0xea, 0x0c, 0xc9, 0x4c, 0x91, 0xe4, 0x7a, 0x5c, 0x14, 0xa1, 0xe3, + 0x4c, 0xcf, 0x89, 0x9c, 0x56, 0x31, 0x41, 0x1a, 0x67, 0x05, 0x07, 0x56, 0x89, 0xa1, 0x5f, 0x02, + 0xb4, 0xce, 0xdb, 0x5e, 0x7c, 0x54, 0x98, 0x63, 0x52, 0x77, 0x0a, 0xe7, 0x2a, 0xce, 0xf0, 0xa2, + 0x07, 0x50, 0x4f, 0xce, 0x2b, 0x73, 0x5c, 0x1a, 0xd8, 0xfc, 0xd9, 0x86, 0x53, 0x4e, 0x74, 0xc0, + 0x46, 0x34, 0xb7, 0xd9, 0xcd, 0x09, 0x26, 0xbf, 0x92, 0xca, 0xab, 0x0f, 0x03, 0xac, 0x90, 0xa5, + 0x88, 0x45, 0xf5, 0x61, 0x4e, 0x4a, 0x88, 0x2d, 0x3d, 0x62, 0xb1, 0x0a, 0x6d, 0xc1, 0xa4, 0x7c, + 0xfc, 0x99, 0x53, 0x0c, 0x6d, 0x51, 0xec, 0x47, 0xd5, 0x61, 0x8a, 0x73, 0x32, 0x68, 0x0d, 0x46, + 0xb9, 0xc2, 0x31, 0x0d, 0x26, 0x3e, 0xcb, 0xc5, 0x65, 0xa5, 0x85, 0x05, 0x17, 0xfa, 0x35, 0xcc, + 0x62, 0xd2, 0xf5, 0x5f, 0x13, 0xfa, 0x37, 0x22, 0x74, 0x01, 0x1d, 0xda, 0x47, 0x2e, 0x31, 0x2f, + 0x31, 0xf1, 0x77, 0x84, 0xb8, 0x8a, 0x47, 0x80, 0xa9, 0x11, 0xd0, 0x06, 0x4c, 0xd0, 0x25, 0xc9, + 0x2c, 0x9c, 0x4d, 0xc7, 0xeb, 0x98, 0x88, 0x41, 0x5e, 0xc9, 0x2c, 0xe1, 0xa4, 0x4e, 0x40, 0xc9, + 0x12, 0xe8, 0x53, 0x30, 0x9e, 0x7b, 0x61, 0xff, 0x28, 0x6c, 0x07, 0xce, 0x11, 0x89, 0x3b, 0x36, + 0xcd, 0x50, 0x96, 0x38, 0x4a, 0xbe, 0x3a, 0xd9, 0x56, 0xf9, 0x8a, 0xec, 0x1a, 0xde, 0xb2, 0x23, + 0x5b, 0xac, 0xe1, 0x19, 0xe5, 0x1a, 0xce, 0x70, 0x60, 0x95, 0x18, 0x47, 0x6b, 0x51, 0x53, 0x37, + 0xbb, 0x23, 0x66, 0xf3, 0x68, 0x79, 0x0e, 0xac, 0x12, 0xa3, 0xea, 0x51, 0xad, 0xfc, 0xcd, 0x39, + 0x49, 0x3d, 0xaa, 0x99, 0xb0, 0x46, 0x98, 0xc2, 0xee, 0x3a, 0x27, 0x81, 0x1d, 0x11, 0xaa, 0xa4, + 0xb6, 0x03, 0xbf, 0x2b, 0x60, 0xe7, 0x25, 0x58, 0x35, 0x13, 0xd6, 0x08, 0xa3, 0x7d, 0x98, 0xc9, + 0xd4, 0x1c, 0x26, 0x7d, 0x35, 0xa5, 0xf9, 0x55, 0xb1, 0x60, 0xa5, 0x20, 0x3a, 0x02, 0x13, 0x13, + 0xd7, 0xb7, 0x3b, 0x1b, 0xfd, 0xc8, 0x6f, 0x7a, 0xed, 0x80, 0x74, 0xa9, 0x29, 0x49, 0xc7, 0xdc, + 0xbc, 0xcc, 0x40, 0x6f, 0x24, 0xeb, 0x50, 0xcd, 0x26, 0xf0, 0xb5, 0x38, 0x54, 0x35, 0x37, 0x22, + 0x17, 0x13, 0xbb, 0x43, 0x02, 0xd1, 0xe1, 0x05, 0x49, 0x83, 0xe4, 0xab, 0x71, 0x41, 0x00, 0xed, + 0xc2, 0xd4, 0x63, 0x12, 0x61, 0xd2, 0x73, 0x9d, 0xb6, 0x1d, 0x9f, 0xbc, 0x57, 0xf2, 0x13, 0x94, + 0xad, 0xe5, 0x72, 0xc2, 0x46, 0xce, 0xd5, 0xd2, 0x45, 0x84, 0x49, 0x48, 0xa2, 0x16, 0x09, 0x33, + 0xea, 0xc1, 0x5c, 0x94, 0x16, 0x91, 0x82, 0x03, 0xab, 0xc4, 0xd0, 0x0e, 0x5c, 0x7a, 0xec, 0xef, + 0xda, 0x67, 0xf4, 0x9c, 0x14, 0xe6, 0x91, 0x79, 0x55, 0x56, 0xf6, 0xf9, 0x7a, 0xde, 0xb3, 0xa2, + 0x20, 0x47, 0x23, 0xdd, 0x1d, 0x27, 0xd5, 0xa9, 0xe6, 0x52, 0x1e, 0x4d, 0xae, 0xcf, 0xa0, 0xc9, + 0x15, 0xe8, 0x0b, 0x98, 0xdf, 0x76, 0x5c, 0xd2, 0x22, 0xc1, 0x6b, 0xa7, 0x4d, 0xb2, 0x53, 0x66, + 0x2e, 0x4b, 0xfb, 0x59, 0xc3, 0xc5, 0x91, 0x75, 0x20, 0xa8, 0x0b, 0x8b, 0xf9, 0x2a, 0x66, 0x42, + 0x8a, 0x46, 0x56, 0x24, 0x6d, 0x56, 0xc6, 0xca, 0x5b, 0x2a, 0x85, 0x43, 0xcf, 0x61, 0x66, 0x97, + 0x44, 0x76, 0xc7, 0x8e, 0x6c, 0xe9, 0x5b, 0xae, 0xc9, 0x3b, 0x40, 0xc1, 0xc2, 0xe1, 0x95, 0xe2, + 0x68, 0x1f, 0xd0, 0x63, 0xff, 0x71, 0xe3, 0x80, 0x04, 0x6d, 0x92, 0x5a, 0x33, 0x96, 0x7c, 0xf2, + 0x17, 0x18, 0x38, 0xa4, 0x42, 0x94, 0x9a, 0x12, 0xdb, 0x76, 0xdf, 0x8d, 0x9a, 0xde, 0x97, 0x24, + 0x1d, 0x8c, 0x77, 0x24, 0xc0, 0x22, 0x03, 0x56, 0x08, 0xa1, 0xdf, 0xc0, 0x5c, 0x23, 0x72, 0x77, + 0x7d, 0xa6, 0x4c, 0x99, 0x02, 0x13, 0x70, 0xd7, 0xa5, 0x1d, 0xa0, 0x66, 0xe2, 0x7d, 0xd4, 0x40, + 0xa0, 0x2f, 0xe0, 0xf2, 0x4b, 0x3f, 0x78, 0x15, 0xf6, 0xec, 0x36, 0x39, 0x3c, 0xa5, 0x7e, 0x90, + 0xef, 0x8a, 0x33, 0xc1, 0x7c, 0x57, 0x3a, 0x55, 0xb5, 0x7c, 0x58, 0x0f, 0x81, 0xba, 0xb0, 0xd4, + 0x88, 0xdc, 0x83, 0x80, 0x1c, 0x93, 0xa8, 0x7d, 0xba, 0xef, 0xb5, 0xc4, 0xd1, 0x90, 0x34, 0x72, + 0x83, 0x35, 0xf2, 0x6e, 0xfa, 0x11, 0x25, 0xcc, 0x78, 0x00, 0x18, 0xfa, 0x0d, 0x98, 0xcd, 0x56, + 0xe3, 0x60, 0x2b, 0xb0, 0x1d, 0xaf, 0xe1, 0x7b, 0x61, 0xbf, 0x9b, 0xea, 0x9c, 0x9b, 0xac, 0xa1, + 0x65, 0xde, 0x90, 0x8e, 0x0d, 0x6b, 0x01, 0x50, 0x0f, 0xae, 0x36, 0xdb, 0xe4, 0x88, 0x04, 0x27, + 0xdc, 0xb0, 0x7a, 0x6d, 0xbb, 0x4e, 0xc7, 0x8e, 0x92, 0x45, 0x78, 0x8b, 0xb5, 0x70, 0x5d, 0xb4, + 0x50, 0xc6, 0xcb, 0xa7, 0xa5, 0x1c, 0x10, 0x9d, 0xc0, 0xc2, 0xae, 0xef, 0x9d, 0xf8, 0x5b, 0x9b, + 0x0d, 0xd7, 0x61, 0xab, 0x2b, 0x72, 0x82, 0xa4, 0xb9, 0xdb, 0xac, 0xb9, 0x6b, 0x62, 0xcd, 0x6b, + 0x19, 0x79, 0x5b, 0x25, 0x50, 0x74, 0x19, 0x60, 0x72, 0x4c, 0xe7, 0x8e, 0xab, 0xb6, 0x8d, 0x7e, + 0x74, 0x2a, 0xda, 0xb9, 0x23, 0x2d, 0x03, 0x2d, 0x1f, 0xd6, 0x43, 0xa0, 0xdf, 0xc2, 0xf2, 0x00, + 0x97, 0xdb, 0xbc, 0xcb, 0x5a, 0xb9, 0x97, 0x9a, 0x70, 0x6f, 0xe1, 0xea, 0xf3, 0x2f, 0x1b, 0x84, + 0x8d, 0x08, 0x73, 0xe4, 0x54, 0x2e, 0xb7, 0xf9, 0x9e, 0xb4, 0xfc, 0xca, 0x9d, 0x79, 0xa1, 0x0b, + 0x35, 0x5c, 0xe8, 0xff, 0xc3, 0xac, 0xd2, 0xdd, 0x36, 0xef, 0x49, 0x4a, 0xb0, 0xcc, 0x89, 0xe7, + 0x4d, 0xa8, 0x71, 0x34, 0xdf, 0xc1, 0x5c, 0xec, 0xd5, 0x41, 0xdf, 0x91, 0x71, 0xdd, 0x4b, 0xbe, + 0x83, 0x72, 0x51, 0xe5, 0x45, 0xfd, 0xab, 0xdc, 0xe1, 0xb8, 0x26, 0x29, 0xaf, 0x22, 0x03, 0x56, + 0x08, 0xd1, 0x0d, 0xb9, 0xe5, 0x84, 0x6d, 0xdf, 0xf3, 0x48, 0x3b, 0x7f, 0xda, 0xde, 0x97, 0x36, + 0xa4, 0x8e, 0x0d, 0x6b, 0x01, 0x50, 0x27, 0x0e, 0x4f, 0x9d, 0x47, 0xa7, 0xbe, 0xf7, 0xbc, 0x73, + 0xdc, 0x62, 0x41, 0x53, 0x81, 0xfe, 0xb3, 0x82, 0x93, 0xa1, 0xe4, 0xe3, 0x63, 0xa1, 0x07, 0xb2, + 0xb6, 0x61, 0xbe, 0xe0, 0x04, 0xf3, 0x28, 0xc0, 0x5d, 0xa8, 0xf1, 0x2e, 0xc5, 0x31, 0x8e, 0xb1, + 0xf5, 0xa9, 0x55, 0x1e, 0xba, 0x15, 0x5d, 0x4d, 0x18, 0xac, 0xff, 0x58, 0x81, 0x5a, 0x22, 0xf9, + 0xd3, 0x46, 0x07, 0x66, 0x60, 0xf8, 0x51, 0x10, 0xf8, 0x01, 0x0b, 0x0b, 0x8c, 0xe3, 0xb8, 0x80, + 0x3e, 0xd3, 0x76, 0x9c, 0xfb, 0xfe, 0x4b, 0x3a, 0xdf, 0x3f, 0xe6, 0xc2, 0xda, 0xef, 0xde, 0x87, + 0x19, 0xd9, 0x8d, 0xe7, 0xb0, 0xc3, 0xd2, 0x29, 0xac, 0x62, 0xc1, 0x4a, 0x41, 0x6a, 0x23, 0xa6, + 0x1e, 0x3d, 0x07, 0x1b, 0x91, 0x6c, 0xc4, 0x7c, 0x35, 0x2e, 0x08, 0x50, 0x9f, 0x3b, 0xe3, 0xd2, + 0x73, 0x94, 0x51, 0xc9, 0x70, 0x2a, 0xd4, 0xe3, 0xa2, 0x08, 0xf7, 0x30, 0x52, 0x8f, 0x9e, 0x23, + 0xd5, 0xf2, 0x1e, 0x46, 0x9e, 0x03, 0xab, 0xc4, 0x78, 0x50, 0x21, 0x71, 0xeb, 0x39, 0x58, 0x3d, + 0x1f, 0x54, 0xc8, 0x31, 0x60, 0x85, 0x10, 0x1d, 0x76, 0xd9, 0xab, 0xe7, 0x60, 0x90, 0x77, 0xef, + 0x0a, 0x2c, 0x58, 0x29, 0x88, 0x3e, 0x00, 0x48, 0xdd, 0x7e, 0x1e, 0x0f, 0xb8, 0xac, 0x88, 0x07, + 0x70, 0x90, 0x0c, 0x33, 0x7a, 0x58, 0x0c, 0x08, 0x98, 0xc5, 0x80, 0x00, 0x17, 0xcc, 0x44, 0x04, + 0x9e, 0x95, 0x44, 0x04, 0xae, 0x95, 0x44, 0x04, 0x32, 0xc3, 0x92, 0x77, 0xe0, 0x9f, 0x95, 0x84, + 0x04, 0xae, 0x95, 0x84, 0x04, 0x04, 0xa4, 0x22, 0x26, 0xf0, 0x48, 0x13, 0x13, 0xb8, 0xaa, 0x89, + 0x09, 0x70, 0xa8, 0x7c, 0x50, 0xe0, 0x7e, 0x3e, 0x28, 0x30, 0x97, 0x0f, 0x0a, 0x70, 0xc1, 0x24, + 0x2a, 0xf0, 0x79, 0x79, 0x54, 0xe0, 0x7a, 0x79, 0x54, 0x80, 0xa3, 0x69, 0xc2, 0x02, 0x9b, 0xea, + 0xb0, 0xc0, 0xa2, 0x3a, 0x2c, 0xc0, 0xb1, 0x72, 0x71, 0x81, 0xa7, 0xda, 0xb8, 0xc0, 0xb2, 0x36, + 0x2e, 0x20, 0x36, 0x6c, 0x21, 0x30, 0x90, 0x59, 0xcf, 0xb1, 0x87, 0xcf, 0xd7, 0xf3, 0x8c, 0x72, + 0x3d, 0x67, 0x59, 0xb0, 0x52, 0x90, 0x03, 0x66, 0x9c, 0x7c, 0x0e, 0x38, 0x9b, 0x07, 0x2c, 0xb0, + 0x60, 0xa5, 0x20, 0x55, 0xa1, 0x9a, 0x08, 0x30, 0x8f, 0x0f, 0x2c, 0xe9, 0xe2, 0x03, 0x42, 0x85, + 0xea, 0x02, 0xc8, 0x9f, 0xc1, 0x7c, 0xc1, 0xc9, 0xe7, 0xc8, 0xf3, 0x12, 0xb2, 0x86, 0x0b, 0xeb, + 0xc4, 0x11, 0x86, 0xd9, 0x9c, 0xaf, 0xcf, 0x71, 0x4d, 0x69, 0xba, 0x95, 0x3c, 0x58, 0x2d, 0x8a, + 0xda, 0x03, 0xe3, 0x04, 0x37, 0x07, 0xc6, 0x09, 0x78, 0x0b, 0xfa, 0x40, 0xc1, 0x36, 0x5c, 0xca, + 0xf8, 0xfd, 0xbc, 0xd3, 0x0b, 0x92, 0x6a, 0x29, 0xd4, 0xe3, 0xa2, 0x08, 0xda, 0xd3, 0xc5, 0x0a, + 0x96, 0x74, 0xb1, 0x82, 0x58, 0x50, 0x17, 0x2c, 0xd8, 0x87, 0x19, 0xd9, 0xeb, 0xe7, 0x5d, 0x5b, + 0x94, 0x56, 0x95, 0x8a, 0x05, 0x2b, 0x05, 0x63, 0x6f, 0x33, 0x75, 0xfb, 0x39, 0xdc, 0xd5, 0x9c, + 0xb7, 0x99, 0x67, 0x48, 0xbd, 0xcd, 0x7c, 0x0d, 0x07, 0x4c, 0x3c, 0x7f, 0x0e, 0xb8, 0x94, 0x07, + 0xcc, 0x31, 0x64, 0x00, 0x73, 0x35, 0xc8, 0x06, 0xb3, 0xe8, 0xf0, 0x73, 0xd8, 0x65, 0x69, 0xbb, + 0xeb, 0xd8, 0x38, 0xb8, 0x16, 0x86, 0x7a, 0x53, 0x1a, 0x4f, 0x9f, 0xb7, 0xb3, 0x22, 0x69, 0xbc, + 0x52, 0x5e, 0xe1, 0x4d, 0x95, 0x32, 0xa1, 0xcf, 0x60, 0x36, 0xe7, 0xfc, 0xf3, 0x96, 0xae, 0xc9, + 0x1b, 0x43, 0xc5, 0x23, 0xec, 0x72, 0x65, 0x25, 0xc2, 0x30, 0x2d, 0xc5, 0x00, 0x38, 0xae, 0x25, + 0x5b, 0x0c, 0x45, 0x0e, 0x8e, 0xaa, 0x12, 0xa6, 0x56, 0x88, 0x14, 0x0c, 0xe0, 0x98, 0xef, 0x48, + 0x98, 0x0a, 0x0e, 0xac, 0x12, 0x43, 0x5f, 0xc0, 0x7c, 0x21, 0x02, 0xc0, 0x11, 0xaf, 0x4b, 0x7b, + 0x43, 0xc3, 0x25, 0x5c, 0x06, 0x4d, 0x35, 0xb2, 0x61, 0x41, 0x15, 0x04, 0xe0, 0x4d, 0xbc, 0x2b, + 0x9d, 0xc5, 0x7a, 0x46, 0x5c, 0x02, 0x12, 0x07, 0x3f, 0xbd, 0xe4, 0xfa, 0x3b, 0x01, 0xbf, 0x91, + 0x0b, 0x7e, 0x16, 0x59, 0xb0, 0x52, 0x10, 0xf5, 0x60, 0x59, 0x1b, 0x4e, 0xe0, 0xd8, 0x37, 0xa5, + 0x18, 0xe8, 0x00, 0x6e, 0x3c, 0x08, 0x8e, 0xba, 0xd9, 0x8a, 0xe8, 0x02, 0x6f, 0xeb, 0x96, 0xe4, + 0xb0, 0x68, 0xf9, 0xb0, 0x1e, 0x02, 0x85, 0xb0, 0xa4, 0x0b, 0x28, 0xf0, 0x46, 0x6e, 0x4b, 0x6e, + 0x62, 0x39, 0x33, 0x9f, 0xf3, 0x01, 0x90, 0xe8, 0x4b, 0xb8, 0xa2, 0x8c, 0x2c, 0xf0, 0x16, 0xe3, + 0xe8, 0x81, 0x55, 0x16, 0xa5, 0x90, 0x9a, 0x2b, 0x03, 0xa3, 0xcb, 0x4c, 0x15, 0x64, 0xe0, 0x4d, + 0xdd, 0x95, 0x96, 0x99, 0x9e, 0x11, 0x97, 0x80, 0xa0, 0xbf, 0x1e, 0x1c, 0xaa, 0x88, 0x63, 0x06, + 0xab, 0x6f, 0x1b, 0xaa, 0x90, 0x3e, 0x6f, 0x60, 0xac, 0xe2, 0x58, 0x1f, 0xab, 0xb8, 0x27, 0xad, + 0xc6, 0x01, 0x49, 0x04, 0x83, 0x82, 0x15, 0x7f, 0xa5, 0x0b, 0x56, 0xac, 0x4a, 0x7a, 0xb7, 0x34, + 0x7f, 0xa0, 0x3c, 0x5a, 0x71, 0xac, 0x8f, 0x56, 0xac, 0x0d, 0xfa, 0x92, 0x6c, 0x1a, 0xc1, 0xa0, + 0x70, 0xc5, 0x0e, 0x4c, 0x4b, 0x91, 0x07, 0xbe, 0x1a, 0xee, 0x4b, 0x9a, 0x52, 0xc1, 0x81, 0x55, + 0x62, 0x74, 0x8f, 0x2a, 0x02, 0x0e, 0x1c, 0x53, 0x0e, 0x2a, 0x68, 0xf9, 0xb0, 0x1e, 0x02, 0xbd, + 0x8c, 0x1d, 0x20, 0x39, 0xd6, 0x60, 0xae, 0x17, 0x1c, 0xa0, 0x7c, 0x30, 0x22, 0x77, 0x66, 0x17, + 0x38, 0x44, 0xb2, 0x8e, 0x3a, 0x88, 0xf1, 0xe7, 0xd1, 0x38, 0x5b, 0x47, 0x8d, 0x8a, 0xe6, 0x60, + 0xa4, 0xb1, 0xf7, 0xfc, 0x39, 0x8f, 0x45, 0xd4, 0x31, 0x2f, 0xa1, 0x05, 0xa8, 0xed, 0xd8, 0xde, + 0x49, 0xdf, 0x3e, 0x21, 0x2c, 0x0e, 0x51, 0xc7, 0x49, 0x99, 0xe5, 0x8e, 0x78, 0xf4, 0x24, 0xe8, + 0xb0, 0xb0, 0x43, 0x0d, 0x8b, 0x22, 0xba, 0x05, 0x53, 0x1b, 0xae, 0xeb, 0xbf, 0x79, 0xee, 0x39, + 0xa1, 0xef, 0xda, 0x11, 0xe9, 0xb0, 0x80, 0x43, 0x0d, 0xe7, 0xc9, 0x68, 0x06, 0x86, 0xa9, 0xf1, + 0x76, 0xce, 0x22, 0x07, 0x35, 0x1c, 0x17, 0xd0, 0x12, 0x00, 0x8b, 0x60, 0x34, 0x5c, 0x3b, 0x0c, + 0x59, 0x1c, 0xa0, 0x8e, 0x33, 0x94, 0x38, 0x93, 0xc3, 0x0e, 0x7d, 0x8f, 0x79, 0xf7, 0x2c, 0x93, + 0x83, 0x96, 0x68, 0xbb, 0x79, 0x2f, 0xb0, 0xc6, 0xf2, 0x42, 0xf2, 0x64, 0xb4, 0x02, 0x63, 0x1b, + 0x9b, 0xcd, 0x86, 0xef, 0x45, 0x81, 0xdd, 0x8e, 0x2f, 0xe6, 0xeb, 0x38, 0x4b, 0x42, 0x37, 0x60, + 0x72, 0xa3, 0x63, 0xf7, 0x22, 0x12, 0x08, 0x28, 0x60, 0x4c, 0x39, 0x2a, 0xed, 0x6b, 0x6b, 0xeb, + 0xa9, 0xe0, 0x19, 0x8b, 0xfb, 0x9a, 0x52, 0xd0, 0x2f, 0x61, 0x7e, 0x8b, 0x1c, 0x3b, 0x9e, 0x13, + 0x39, 0xbe, 0xd7, 0x6a, 0x9f, 0x92, 0xae, 0x2d, 0x98, 0xc7, 0x59, 0xdf, 0x74, 0xd5, 0xe8, 0x3e, + 0x4c, 0x1f, 0xb8, 0xb6, 0x27, 0x7a, 0x94, 0x75, 0x95, 0x87, 0xb1, 0xaa, 0x0a, 0x3d, 0x84, 0xb9, + 0xc3, 0xf3, 0x1e, 0xd9, 0x22, 0xf4, 0xdc, 0xe9, 0x45, 0x7e, 0x90, 0x7c, 0xe0, 0x24, 0xeb, 0x97, + 0xa6, 0x96, 0xf6, 0x91, 0x9e, 0x8e, 0x5f, 0xfb, 0x1e, 0x73, 0xa7, 0x8e, 0xec, 0x90, 0x88, 0xd6, + 0xa6, 0x98, 0xa0, 0xae, 0x1a, 0x5d, 0x87, 0x89, 0x97, 0x8e, 0xd7, 0xf1, 0xdf, 0x6c, 0xda, 0x51, + 0xfb, 0x94, 0x84, 0xcc, 0xcd, 0x1d, 0xc6, 0x32, 0x91, 0x72, 0x35, 0xfa, 0xdd, 0xbe, 0x6b, 0x47, + 0xce, 0x6b, 0xb2, 0xd1, 0x7e, 0xc5, 0x9c, 0xd9, 0x1a, 0x96, 0x89, 0xb4, 0xf7, 0xbb, 0xf6, 0xd9, + 0xa3, 0x33, 0xd2, 0xee, 0xd3, 0xc1, 0xd8, 0x0e, 0xec, 0x2e, 0xd9, 0x3c, 0x8f, 0x48, 0xc8, 0xfc, + 0xd4, 0x21, 0xac, 0xa9, 0xa5, 0xe3, 0xb4, 0x6b, 0x9f, 0x3d, 0xb1, 0xbd, 0x8e, 0x4b, 0x02, 0x1e, + 0xad, 0x22, 0x21, 0xf3, 0x4a, 0x87, 0xb1, 0xaa, 0x0a, 0x7d, 0x0c, 0x0b, 0xbb, 0xf6, 0x19, 0x8f, + 0x41, 0x15, 0x04, 0x67, 0x98, 0x60, 0x09, 0x07, 0xfa, 0x10, 0xcc, 0x5d, 0xfb, 0x6c, 0xff, 0x8d, + 0x47, 0x82, 0x82, 0xf4, 0x2c, 0x93, 0xd6, 0xd6, 0xd3, 0xf5, 0xb2, 0x43, 0xec, 0x90, 0x3c, 0xea, + 0xf9, 0xed, 0x53, 0xe6, 0x44, 0x56, 0x71, 0x86, 0x42, 0x77, 0xc4, 0xae, 0xdf, 0x21, 0xa1, 0x39, + 0xcf, 0x72, 0xa6, 0xe2, 0x02, 0xb2, 0x60, 0x7c, 0xaf, 0xef, 0xba, 0x07, 0xbe, 0xeb, 0xb4, 0x1d, + 0x12, 0x9a, 0x26, 0xab, 0x94, 0x68, 0x56, 0x53, 0x99, 0x92, 0xc3, 0xb2, 0xa4, 0x58, 0xf2, 0x64, + 0x53, 0xe4, 0x78, 0x25, 0x65, 0xba, 0x91, 0xb8, 0xfe, 0x19, 0x8a, 0x37, 0x12, 0x57, 0x25, 0x1f, + 0xaa, 0xe3, 0x7b, 0xb4, 0x1b, 0x36, 0xa5, 0xb7, 0xfa, 0x6d, 0xfa, 0x39, 0x0c, 0xaf, 0x86, 0x25, + 0x9a, 0xd5, 0x2c, 0xe4, 0xf2, 0xa0, 0x45, 0xa8, 0x73, 0x24, 0xae, 0x60, 0x86, 0x70, 0x4a, 0xc8, + 0xa6, 0x7c, 0x5d, 0x64, 0xc3, 0x91, 0x49, 0xf9, 0x2a, 0x06, 0xf9, 0x4c, 0x18, 0x95, 0x5b, 0x17, + 0x45, 0x6b, 0xa7, 0x78, 0xcf, 0x8c, 0x0c, 0x18, 0x6a, 0x74, 0x3b, 0x22, 0x25, 0xae, 0xd1, 0xed, + 0x30, 0xca, 0xf1, 0x09, 0x57, 0x66, 0xf4, 0x27, 0x0b, 0x9e, 0x9e, 0x45, 0x81, 0x9d, 0x04, 0x4f, + 0x69, 0xc1, 0xba, 0xa9, 0x70, 0x46, 0x11, 0x82, 0x2a, 0xfd, 0xcd, 0xf1, 0xd8, 0x6f, 0xeb, 0xa3, + 0x41, 0x37, 0x5c, 0x74, 0x06, 0x0e, 0xec, 0x28, 0x22, 0x81, 0x27, 0x32, 0xe1, 0x92, 0xb2, 0xf5, + 0x60, 0xa0, 0x0d, 0xaa, 0x6c, 0xf4, 0xdf, 0x2a, 0xfa, 0x8b, 0xae, 0xe2, 0x70, 0x4f, 0xe4, 0x86, + 0x9b, 0xd9, 0xef, 0xcd, 0x2d, 0x31, 0xdc, 0xbc, 0x48, 0x6b, 0x3e, 0xf5, 0x8f, 0xf6, 0xec, 0x2e, + 0xe1, 0xcb, 0x41, 0x14, 0xe9, 0x10, 0x7d, 0xea, 0x1f, 0x35, 0xb7, 0x98, 0x1a, 0xaf, 0xe2, 0xb8, + 0x40, 0xd5, 0x6d, 0x1c, 0x68, 0xda, 0x26, 0x5e, 0x9b, 0xec, 0x7b, 0xae, 0x50, 0xe3, 0x79, 0x32, + 0x55, 0xa6, 0x98, 0x78, 0xe4, 0x4d, 0xca, 0x38, 0xc2, 0x18, 0x73, 0x54, 0xeb, 0x41, 0x89, 0x7d, + 0x5c, 0x32, 0xf3, 0x9f, 0x15, 0x93, 0xbf, 0x14, 0x33, 0x3f, 0x03, 0xc3, 0x94, 0x21, 0xe4, 0x73, + 0x1f, 0x17, 0xe8, 0x60, 0x25, 0xae, 0x06, 0xfb, 0xec, 0x21, 0x9c, 0x12, 0xe8, 0x2a, 0x28, 0xc6, + 0x87, 0x55, 0x13, 0xf2, 0x4b, 0x55, 0xea, 0x18, 0xdd, 0x2f, 0xcd, 0x0e, 0xf1, 0x22, 0x27, 0x3a, + 0x67, 0x5f, 0xcd, 0xf7, 0x4b, 0x96, 0x66, 0xfd, 0xa9, 0x02, 0x35, 0x21, 0x97, 0x4e, 0x4e, 0x87, + 0x5f, 0x0a, 0x88, 0x62, 0x92, 0x4a, 0x79, 0x71, 0x65, 0xe8, 0xd6, 0x78, 0x9c, 0x4a, 0x89, 0xee, + 0xc4, 0x92, 0x54, 0x45, 0xb0, 0xae, 0x4f, 0xae, 0x4f, 0xae, 0xb2, 0x5c, 0x71, 0x41, 0xc5, 0x49, + 0x3d, 0x3d, 0xf1, 0x9c, 0x10, 0xdb, 0xde, 0x09, 0x0b, 0x08, 0xf2, 0xf3, 0x38, 0x4b, 0x42, 0x37, + 0x61, 0xf4, 0x89, 0xef, 0x76, 0x48, 0x10, 0x9a, 0xc3, 0xec, 0x2e, 0x63, 0x22, 0x06, 0x7b, 0x69, + 0x3b, 0xd1, 0xe1, 0x99, 0x87, 0x45, 0x2d, 0x65, 0xa4, 0x34, 0xca, 0x38, 0xa2, 0x64, 0xe4, 0xb5, + 0xd6, 0xdf, 0x54, 0x94, 0x91, 0x74, 0xfa, 0x2d, 0x0d, 0xaf, 0x29, 0x26, 0x87, 0xfd, 0x46, 0x3f, + 0x87, 0x71, 0xc1, 0xb7, 0xe3, 0x84, 0x11, 0xfb, 0xce, 0xb1, 0xf5, 0x29, 0x6e, 0x10, 0x25, 0x10, + 0x12, 0x13, 0x3d, 0x58, 0x68, 0x99, 0xbb, 0xfc, 0xcd, 0x2d, 0xbe, 0x6e, 0x65, 0xa2, 0x35, 0xad, + 0xc8, 0xc5, 0xb3, 0x4e, 0x61, 0xec, 0xf0, 0xcc, 0x7b, 0xbb, 0x81, 0xc7, 0xfe, 0x9b, 0x64, 0xe0, + 0xe9, 0x6f, 0x74, 0x17, 0x46, 0xf7, 0x7b, 0x11, 0xbb, 0xf6, 0x89, 0x13, 0x31, 0x2f, 0xa5, 0xe3, + 0xce, 0x2b, 0xb0, 0xe0, 0xb0, 0xfe, 0xbd, 0x02, 0xa3, 0xbc, 0x71, 0xf4, 0x09, 0xd4, 0x1a, 0x01, + 0xb1, 0x23, 0xb2, 0x11, 0xf1, 0xd4, 0xee, 0x85, 0xd5, 0x38, 0xd3, 0x7e, 0x55, 0x64, 0xda, 0x67, + 0x12, 0xbc, 0x6b, 0xd4, 0xd6, 0xfb, 0xdd, 0x7f, 0x2d, 0x57, 0x70, 0x22, 0x85, 0x56, 0xa0, 0xba, + 0x4b, 0x22, 0x9b, 0x2d, 0xe2, 0xb1, 0xf5, 0xf1, 0xd5, 0xe8, 0xcc, 0x5b, 0x3d, 0x3c, 0xf3, 0x28, + 0x0d, 0xb3, 0x1a, 0xfa, 0x29, 0xcf, 0x43, 0x12, 0x1c, 0x9e, 0x79, 0xc2, 0x2e, 0xe3, 0x45, 0x74, + 0x1f, 0xea, 0x74, 0x6a, 0x68, 0x2f, 0x43, 0xb3, 0xca, 0x06, 0x18, 0x89, 0x8b, 0x91, 0x74, 0x2c, + 0x70, 0xca, 0x24, 0xab, 0x92, 0xe1, 0x9c, 0x2a, 0xb1, 0x3e, 0x57, 0x5d, 0x6d, 0x28, 0x67, 0xf7, + 0x3e, 0x1b, 0xed, 0xdc, 0xe4, 0x4e, 0xa6, 0x6d, 0x33, 0x80, 0x2c, 0x8b, 0x35, 0xab, 0x4c, 0x7c, + 0xb4, 0xfe, 0xa1, 0x02, 0xf5, 0xd4, 0x87, 0x59, 0x80, 0xda, 0x9e, 0xdf, 0x21, 0xd4, 0xac, 0xe1, + 0xcd, 0x25, 0x65, 0x7a, 0xb6, 0xd1, 0xdf, 0xcd, 0x0e, 0xdf, 0xef, 0xbc, 0x44, 0x3f, 0x89, 0x01, + 0x30, 0xa1, 0x78, 0xbd, 0xa4, 0x04, 0xda, 0xf9, 0xe7, 0x21, 0xb7, 0x57, 0xab, 0x98, 0xfd, 0xa6, + 0xb4, 0xed, 0x80, 0xc4, 0xb7, 0x5b, 0x55, 0xcc, 0x7e, 0xd3, 0x96, 0x9f, 0x38, 0x11, 0xb6, 0x23, + 0xc7, 0x67, 0xba, 0xec, 0x22, 0x4e, 0xca, 0xd6, 0x9e, 0xfa, 0x9a, 0x06, 0x3d, 0x84, 0x89, 0x84, + 0xc8, 0x86, 0x21, 0xbe, 0x32, 0x4c, 0x6e, 0xf6, 0x12, 0x01, 0x99, 0xcd, 0x72, 0x61, 0xb1, 0x2c, + 0x0b, 0x90, 0x4e, 0xf8, 0xe3, 0xc0, 0xef, 0xf7, 0x12, 0x6d, 0x2f, 0x8a, 0xe5, 0xba, 0x5e, 0x1c, + 0xba, 0x43, 0xf2, 0xa1, 0xfb, 0x00, 0xae, 0x96, 0xde, 0x2e, 0xc8, 0xa9, 0xcf, 0xc3, 0x22, 0xf5, + 0xf9, 0x53, 0xf6, 0xd1, 0x85, 0xbc, 0xc2, 0x1f, 0xd2, 0x39, 0xeb, 0x2e, 0xcc, 0x2a, 0x2f, 0x23, + 0xe8, 0x4c, 0xb0, 0x8b, 0x0b, 0xbe, 0xb4, 0xe8, 0x6f, 0xab, 0x05, 0xf3, 0x9a, 0x54, 0x44, 0x6a, + 0x6b, 0x09, 0x83, 0x35, 0xb9, 0x65, 0xcd, 0x50, 0x4a, 0x7a, 0xf0, 0x0b, 0x30, 0x75, 0xf7, 0x18, + 0x25, 0xe7, 0xd0, 0x36, 0xd4, 0x84, 0x57, 0x4a, 0xbb, 0x7a, 0x60, 0x47, 0xa7, 0xa2, 0xab, 0xf4, + 0x37, 0x5d, 0x92, 0xfb, 0xc7, 0xc7, 0x21, 0x89, 0x1f, 0xb6, 0x0c, 0x61, 0x5e, 0x42, 0x93, 0x70, + 0xb1, 0xf5, 0x35, 0x3f, 0x7c, 0x2e, 0xb6, 0xbe, 0xb6, 0x1e, 0xf2, 0x25, 0xca, 0x94, 0xfc, 0x6d, + 0xa8, 0xbe, 0x12, 0x39, 0xf4, 0xa9, 0x42, 0x14, 0xf5, 0xdc, 0x1f, 0x64, 0x2c, 0xd6, 0x21, 0x3d, + 0x90, 0xd9, 0xa7, 0x27, 0xdd, 0x98, 0x81, 0x61, 0xe6, 0x2d, 0x8b, 0xc9, 0x62, 0x05, 0x74, 0x37, + 0xed, 0x28, 0x57, 0x24, 0x79, 0x5c, 0x9c, 0x30, 0x58, 0x2f, 0x95, 0xe9, 0x9b, 0xe8, 0x93, 0x42, + 0x63, 0xbc, 0x8b, 0xc9, 0x1d, 0x97, 0x5c, 0x8b, 0xf3, 0xec, 0xd6, 0x3e, 0x5c, 0x12, 0x83, 0x9a, + 0xa0, 0x6b, 0x3a, 0x6c, 0xc0, 0xd0, 0x13, 0x47, 0xbc, 0x07, 0xa2, 0x3f, 0xe9, 0xf8, 0x52, 0x7e, + 0x6e, 0xb4, 0xb1, 0xdf, 0xd6, 0x17, 0xea, 0xfb, 0x24, 0xb4, 0xad, 0x68, 0x88, 0x77, 0xd6, 0x4c, + 0xa3, 0xf7, 0x72, 0x3d, 0x2e, 0x8a, 0x58, 0x58, 0x99, 0x7a, 0x8a, 0x7e, 0x05, 0xe3, 0x09, 0x4d, + 0x3c, 0xc0, 0x18, 0x5b, 0x9f, 0x5f, 0x4d, 0x9f, 0x63, 0x65, 0xab, 0xb1, 0xc4, 0xcc, 0xf7, 0x4d, + 0xf1, 0xe6, 0x69, 0x1d, 0xea, 0x09, 0x31, 0x79, 0x05, 0xa4, 0x40, 0xc4, 0x29, 0x9b, 0xf5, 0x77, + 0x15, 0x18, 0x3b, 0x08, 0x48, 0xcf, 0x0e, 0x48, 0x2b, 0xea, 0xb2, 0x31, 0x62, 0xd6, 0x1c, 0x5f, + 0x83, 0xcc, 0x94, 0x33, 0x60, 0xa8, 0xf5, 0x6c, 0x47, 0xd8, 0xbf, 0xad, 0x67, 0x3b, 0x74, 0x97, + 0x1c, 0xd8, 0x81, 0xdd, 0xa5, 0xfa, 0x2f, 0xe4, 0xe3, 0x99, 0xa1, 0x50, 0xef, 0x90, 0x7e, 0xa9, + 0x13, 0x90, 0x4e, 0xde, 0xbb, 0xae, 0xb2, 0x25, 0xab, 0xab, 0xb6, 0x4e, 0xc1, 0xe0, 0xd7, 0x49, + 0x87, 0xa4, 0xdb, 0x8b, 0xef, 0xfc, 0x16, 0xa0, 0x26, 0x76, 0xa0, 0x50, 0xd9, 0xa2, 0x4c, 0xe7, + 0x7e, 0xc3, 0x75, 0xec, 0xc4, 0x42, 0x63, 0x05, 0x6a, 0x44, 0x1d, 0x9c, 0x9e, 0x87, 0x4e, 0xdb, + 0x76, 0x33, 0xb6, 0xa9, 0x44, 0xb3, 0xfe, 0xf9, 0xa2, 0x2e, 0xe1, 0x96, 0x85, 0x36, 0x7c, 0xcf, + 0x4b, 0xf4, 0x0f, 0x2f, 0xa1, 0x5f, 0x24, 0xaf, 0xa1, 0xe2, 0x04, 0x8b, 0x45, 0xf5, 0x7d, 0x5b, + 0xcc, 0x23, 0xde, 0x4a, 0xa1, 0x4f, 0xe0, 0x4a, 0xf2, 0x2d, 0x31, 0x27, 0xf5, 0xdb, 0xfb, 0xbd, + 0x9e, 0x1f, 0xa4, 0x61, 0x8e, 0x32, 0x16, 0xb4, 0x0d, 0x4b, 0x3b, 0x76, 0x18, 0x35, 0xbd, 0x90, + 0x04, 0x51, 0x73, 0x4b, 0x01, 0x12, 0x1b, 0xd1, 0x03, 0xb8, 0xd0, 0x1e, 0x58, 0x7c, 0xae, 0x3b, + 0x74, 0x05, 0xb0, 0x7b, 0x34, 0x31, 0x01, 0x29, 0x56, 0x6c, 0x67, 0xbf, 0x05, 0xe7, 0xa7, 0xd5, + 0xda, 0x90, 0x51, 0xb5, 0xbe, 0xa9, 0x6b, 0xef, 0x25, 0xa9, 0x9a, 0xda, 0xda, 0xe4, 0x93, 0x76, + 0x71, 0x6b, 0x13, 0x3d, 0x84, 0xf1, 0xcc, 0x6a, 0x0b, 0xf9, 0xa9, 0x2e, 0x2c, 0x8a, 0x4c, 0x15, + 0x96, 0xf8, 0xd0, 0x1d, 0x30, 0xe8, 0xb7, 0x6d, 0x1c, 0x1f, 0x93, 0x76, 0x44, 0x3a, 0xcc, 0xba, + 0x8a, 0x95, 0x5f, 0x81, 0x8e, 0x3e, 0x82, 0x49, 0x6a, 0xbd, 0xec, 0x90, 0xd7, 0xc4, 0xcd, 0xda, + 0x2d, 0x33, 0xe2, 0xb6, 0x39, 0x5b, 0x89, 0x73, 0xbc, 0x68, 0x0b, 0xae, 0xca, 0x0c, 0xc4, 0xa5, + 0x9e, 0x76, 0x7e, 0xa8, 0xcb, 0x99, 0xd0, 0x36, 0x4c, 0x51, 0x06, 0x16, 0xa7, 0x21, 0x9d, 0x17, + 0x76, 0x62, 0xf7, 0xe6, 0x96, 0x8c, 0xcc, 0x84, 0xf3, 0x42, 0x74, 0x23, 0xe5, 0x48, 0x8f, 0xce, + 0x78, 0x3f, 0x46, 0x59, 0x3f, 0x74, 0xd5, 0xb4, 0x07, 0xad, 0xf3, 0x30, 0x22, 0xdd, 0x17, 0x76, + 0xe0, 0xd0, 0x75, 0x15, 0x9a, 0x35, 0x55, 0x0f, 0x64, 0x26, 0x9c, 0x17, 0xa2, 0x3d, 0xc8, 0x91, + 0x92, 0x1e, 0xd4, 0xe3, 0x1e, 0x68, 0xaa, 0xd1, 0x47, 0x70, 0x39, 0xd7, 0x39, 0x4c, 0x7a, 0xae, + 0x7d, 0xce, 0x12, 0x00, 0x80, 0xc9, 0xea, 0x19, 0xa8, 0x74, 0x0e, 0x38, 0x23, 0x3d, 0x16, 0x4b, + 0x6b, 0x19, 0xd0, 0x13, 0x58, 0xce, 0x55, 0xb6, 0x3c, 0xbb, 0x17, 0x9e, 0xfa, 0xd1, 0xa1, 0xef, + 0xef, 0xd8, 0xc1, 0x09, 0x61, 0xa1, 0xb4, 0x1a, 0x1e, 0xc4, 0x46, 0x91, 0x72, 0x9d, 0x2c, 0x20, + 0x4d, 0xc4, 0x48, 0x03, 0xd8, 0xa8, 0x1e, 0x48, 0xf7, 0x54, 0x37, 0xda, 0xf1, 0xbd, 0x13, 0xaa, + 0xc6, 0x1a, 0xa7, 0xa4, 0xfd, 0x8a, 0x74, 0x58, 0xbc, 0xad, 0x86, 0xcb, 0x58, 0xa8, 0x1d, 0xba, + 0xed, 0xf7, 0xbd, 0x78, 0xf9, 0x4f, 0xc5, 0x19, 0x60, 0x09, 0x01, 0xbd, 0x0f, 0x90, 0x28, 0x91, + 0xd0, 0x34, 0xd8, 0x64, 0xcf, 0xcb, 0x93, 0x9d, 0xd4, 0xe3, 0x0c, 0x2b, 0x8b, 0x01, 0x8a, 0x12, + 0xdb, 0xed, 0xc9, 0x0c, 0xc7, 0x41, 0x37, 0x4d, 0x2d, 0xfa, 0x18, 0x16, 0xb2, 0xbd, 0x6d, 0xf4, + 0x83, 0xd0, 0x0f, 0x42, 0xf1, 0x3d, 0x33, 0x4c, 0xb6, 0x84, 0x83, 0x6a, 0xe9, 0xac, 0xc2, 0x62, + 0x31, 0xbb, 0x2a, 0x96, 0x68, 0x68, 0x1d, 0x66, 0xb2, 0xe5, 0xa4, 0x67, 0xd3, 0x0c, 0x5d, 0x59, + 0x67, 0xfd, 0x7e, 0x44, 0xfd, 0xe6, 0x41, 0xab, 0xd7, 0x63, 0x2d, 0x75, 0x31, 0xd1, 0x52, 0x2b, + 0x30, 0xd6, 0x22, 0xd1, 0x0b, 0x3b, 0x88, 0x95, 0xd4, 0x10, 0x0b, 0xc0, 0x64, 0x49, 0x05, 0x3d, + 0x56, 0xfd, 0x11, 0x7a, 0x6c, 0xf8, 0xad, 0xf5, 0xd8, 0xc8, 0xf7, 0xd0, 0x63, 0x0a, 0x0d, 0x34, + 0xfa, 0x13, 0x6b, 0xa0, 0xda, 0xf7, 0xd6, 0x40, 0xf5, 0x9f, 0x58, 0x03, 0xc1, 0x8f, 0xd0, 0x40, + 0x63, 0x3f, 0x4a, 0x03, 0x8d, 0x0f, 0xd2, 0x40, 0xd2, 0x5e, 0x9d, 0x28, 0xdf, 0xab, 0x93, 0x6f, + 0xbf, 0x57, 0xf3, 0x7b, 0x66, 0xea, 0x7b, 0xec, 0x19, 0xa3, 0x64, 0xcf, 0xfc, 0x77, 0x25, 0x49, + 0x01, 0x92, 0x47, 0x44, 0x69, 0x11, 0xae, 0xc0, 0xf0, 0x0b, 0xdb, 0xed, 0x13, 0xee, 0x09, 0xc0, + 0x2a, 0xfb, 0xaf, 0x01, 0x8f, 0xce, 0x7a, 0x01, 0x8e, 0x2b, 0x98, 0xcd, 0xf8, 0x95, 0xcb, 0x0d, + 0x2f, 0xfa, 0x93, 0x59, 0xe9, 0xe1, 0xa6, 0xe3, 0x71, 0x83, 0x27, 0x2e, 0xd0, 0x0d, 0xc1, 0x37, + 0x08, 0x33, 0x1f, 0x9f, 0x52, 0x57, 0x2d, 0x0e, 0x1a, 0x14, 0xe8, 0x68, 0x09, 0xaa, 0xcc, 0x03, + 0x1f, 0xc9, 0x36, 0x4a, 0x29, 0x98, 0xd1, 0xd1, 0x7d, 0x98, 0xc6, 0x7d, 0x2f, 0x72, 0xba, 0xa4, + 0x15, 0x05, 0x8e, 0x77, 0xb2, 0xe5, 0x77, 0x6d, 0x27, 0xbe, 0xf0, 0x99, 0xc0, 0xaa, 0x2a, 0xeb, + 0x19, 0x4c, 0x48, 0xdb, 0x46, 0xf9, 0xb1, 0x89, 0xf3, 0x1a, 0x3b, 0x7c, 0x71, 0x81, 0xfd, 0x33, + 0x82, 0x33, 0xaf, 0xb9, 0x15, 0xab, 0x87, 0x71, 0xcc, 0x4b, 0xd6, 0xcf, 0x34, 0xa9, 0x54, 0x25, + 0x3e, 0xe0, 0xaf, 0x60, 0x79, 0xc0, 0x53, 0xa9, 0xac, 0xdb, 0x59, 0x91, 0xdd, 0x4e, 0x0b, 0x56, + 0x06, 0xe5, 0x4f, 0x59, 0xb7, 0xd8, 0x8b, 0x35, 0xc5, 0x5b, 0x27, 0xaa, 0xf9, 0x1a, 0x7b, 0xc2, + 0x3e, 0x6b, 0xec, 0xf1, 0xe7, 0xcb, 0xaa, 0x4c, 0x27, 0xcd, 0xf3, 0xe5, 0x7b, 0xca, 0x57, 0x51, + 0x3a, 0x4d, 0x6b, 0x1d, 0xa8, 0xf3, 0xa2, 0xf4, 0x83, 0x43, 0x5d, 0x8d, 0x8d, 0x7e, 0x74, 0x1a, + 0x4f, 0x1b, 0x9b, 0x82, 0x71, 0x9c, 0xa1, 0x58, 0x6b, 0x8a, 0x87, 0x54, 0xd4, 0x63, 0x10, 0x24, + 0xf1, 0xcc, 0x5b, 0x94, 0xad, 0xfb, 0xaa, 0x4c, 0xaa, 0x52, 0x89, 0x0f, 0x14, 0xaf, 0xab, 0xd0, + 0x75, 0x98, 0x10, 0xa4, 0xf8, 0xc6, 0x29, 0x1e, 0x16, 0x99, 0x68, 0x7d, 0xa8, 0xca, 0xb2, 0x7a, + 0x4b, 0xd9, 0x53, 0xed, 0x33, 0x2c, 0xb4, 0xc6, 0x77, 0x42, 0x85, 0xb9, 0x21, 0x57, 0x34, 0xf9, + 0x4e, 0x99, 0xad, 0x21, 0x22, 0x58, 0x2d, 0xe7, 0x6b, 0xc2, 0x23, 0x09, 0x29, 0xc1, 0x3a, 0xd3, + 0xa7, 0x6e, 0xc9, 0x92, 0x95, 0x9c, 0x24, 0xbb, 0xa6, 0xa3, 0x85, 0x86, 0xdd, 0xb3, 0xdb, 0x4e, + 0x74, 0xce, 0xb1, 0x65, 0x22, 0x9d, 0xdd, 0x5d, 0x12, 0x86, 0xf6, 0x49, 0x72, 0x4b, 0xc0, 0x8b, + 0xd6, 0x7e, 0xf9, 0x53, 0xb0, 0xef, 0xfd, 0xa1, 0xd6, 0x6f, 0x07, 0xa4, 0x88, 0xfd, 0x85, 0xbf, + 0xe7, 0x17, 0xea, 0xb7, 0x66, 0xe5, 0xad, 0x5a, 0xff, 0x4f, 0x93, 0x65, 0x56, 0xec, 0x4e, 0x45, + 0xd1, 0x1d, 0xeb, 0x7f, 0x2b, 0x03, 0x5e, 0x19, 0x0d, 0xb8, 0xde, 0x61, 0x9d, 0x8b, 0x6c, 0xd7, + 0x3f, 0x49, 0xa2, 0x5a, 0x29, 0x81, 0xd6, 0x52, 0x35, 0xc8, 0x32, 0xac, 0x44, 0xf0, 0x33, 0x21, + 0x50, 0xad, 0x10, 0x67, 0xf4, 0x56, 0x63, 0xff, 0x3b, 0xf6, 0xd8, 0x97, 0x00, 0x84, 0xf9, 0xcb, + 0x83, 0xc0, 0x43, 0x38, 0x43, 0xa1, 0x27, 0x94, 0xf8, 0xe0, 0x1d, 0xbf, 0xcd, 0xbc, 0xd4, 0x27, + 0x76, 0x78, 0xca, 0xef, 0xed, 0x95, 0x75, 0x74, 0x87, 0xc6, 0xf9, 0xe0, 0xcd, 0x2d, 0x7e, 0x87, + 0x9f, 0x94, 0xad, 0x27, 0x83, 0x92, 0x98, 0xe2, 0xeb, 0xa4, 0xae, 0xff, 0x9a, 0x74, 0x1e, 0x79, + 0x51, 0xe0, 0x24, 0x7b, 0x2e, 0x47, 0xb5, 0x56, 0x55, 0xaf, 0xfa, 0xe8, 0x84, 0x73, 0x0a, 0x57, + 0x0e, 0xa2, 0x68, 0xad, 0x29, 0xd3, 0xf8, 0x4a, 0x04, 0x76, 0x54, 0xaf, 0xfc, 0xa8, 0xbe, 0xe4, + 0x4f, 0x37, 0x78, 0x32, 0x05, 0x7f, 0xa5, 0x21, 0x02, 0x2d, 0x84, 0x5d, 0x9d, 0xc4, 0x16, 0x6a, + 0x86, 0x62, 0xdd, 0x56, 0x66, 0xfc, 0x29, 0xaf, 0x9b, 0xee, 0xe8, 0xde, 0x04, 0x16, 0xef, 0xbd, + 0xac, 0x7b, 0xda, 0xd4, 0x3f, 0x25, 0x74, 0xb7, 0xe4, 0x45, 0x20, 0xba, 0x05, 0x53, 0xfc, 0xff, + 0xcc, 0x24, 0x77, 0x66, 0xf1, 0x11, 0x96, 0x27, 0xd3, 0x39, 0x7a, 0x19, 0x38, 0x51, 0x0a, 0xc1, + 0x17, 0x63, 0x8e, 0x6a, 0x79, 0x65, 0x89, 0x83, 0x7f, 0x81, 0xf6, 0x5e, 0xa8, 0xb3, 0x08, 0xd1, + 0xc7, 0x30, 0x9e, 0xa5, 0xbf, 0xc5, 0x3f, 0xde, 0x91, 0xf8, 0xad, 0xbf, 0xad, 0x94, 0xbd, 0xd5, + 0x1b, 0xb0, 0x69, 0x2d, 0x18, 0x6f, 0xc4, 0xd9, 0x42, 0x8e, 0xef, 0x25, 0xfb, 0x56, 0xa2, 0x51, + 0xe3, 0x8a, 0xc7, 0xd5, 0x1e, 0x9d, 0xb5, 0xdd, 0x7e, 0xe8, 0xbc, 0x26, 0x3c, 0x74, 0x5f, 0xa0, + 0x5b, 0xef, 0x97, 0xa6, 0xe4, 0x95, 0x58, 0x2f, 0xff, 0x98, 0x5a, 0x8e, 0xb2, 0x35, 0xfc, 0x03, + 0x2d, 0xc7, 0x5b, 0x30, 0xb5, 0x47, 0xce, 0xa2, 0xc3, 0xc0, 0xf6, 0x42, 0x3b, 0x8e, 0xb6, 0xc5, + 0x77, 0x52, 0x79, 0x32, 0x5a, 0x85, 0x71, 0x6e, 0xd4, 0xc5, 0x90, 0xd5, 0x02, 0xa4, 0x54, 0x6f, + 0xfd, 0x4b, 0xa5, 0xe4, 0xc9, 0xa2, 0xd6, 0x39, 0x5c, 0x84, 0x3a, 0xb5, 0x11, 0x9b, 0x5e, 0xaf, + 0x1f, 0xf1, 0x1d, 0x98, 0x12, 0xa4, 0xd8, 0xe4, 0x50, 0x2e, 0x36, 0x69, 0xc1, 0xb8, 0x94, 0x6b, + 0x58, 0x65, 0xc6, 0x8b, 0x44, 0xa3, 0x63, 0xd4, 0xb2, 0xdd, 0xf8, 0xbf, 0xa0, 0x8c, 0x63, 0xf6, + 0x9b, 0x69, 0x7d, 0x36, 0x07, 0x1b, 0x9d, 0x4e, 0x40, 0x92, 0x74, 0x26, 0x99, 0x68, 0xfd, 0x53, + 0xa5, 0x2c, 0xb1, 0xf1, 0x87, 0x5b, 0x54, 0x54, 0x39, 0xd3, 0x12, 0xf1, 0x22, 0x27, 0x56, 0xbf, + 0xdb, 0xb6, 0x93, 0x66, 0x6c, 0x29, 0xeb, 0xe2, 0x7b, 0xfd, 0xf8, 0xed, 0x1d, 0xf9, 0x92, 0xb9, + 0xb0, 0x22, 0x7d, 0x2b, 0x47, 0xb6, 0xbe, 0xa9, 0xc0, 0x4c, 0x26, 0x87, 0xee, 0x20, 0x70, 0xbc, + 0xb6, 0xd3, 0xb3, 0xdd, 0x01, 0xcb, 0x7d, 0x0e, 0x46, 0xd8, 0xa0, 0xc7, 0x0b, 0x7d, 0x02, 0xf3, + 0x12, 0xfd, 0x4c, 0xce, 0x24, 0x8e, 0x62, 0x5e, 0xe4, 0xd7, 0x72, 0x01, 0x3f, 0x98, 0xd8, 0xef, + 0xf8, 0x62, 0xd6, 0x8d, 0xaf, 0xe5, 0xa8, 0xf2, 0xf2, 0x5d, 0x62, 0xfd, 0xbe, 0xa2, 0x7a, 0xba, + 0x98, 0x5b, 0x0e, 0xd5, 0x64, 0x39, 0xdc, 0x80, 0x49, 0x91, 0x60, 0x42, 0xd2, 0x58, 0x70, 0x0d, + 0xe7, 0xa8, 0x2c, 0x86, 0x20, 0x22, 0xa7, 0xc9, 0x2d, 0x73, 0x96, 0x84, 0x3e, 0x80, 0x7a, 0xf2, + 0xf5, 0x7c, 0xed, 0x5e, 0x29, 0x66, 0x1e, 0x26, 0x2c, 0x38, 0xe5, 0xb6, 0xee, 0x2a, 0xd3, 0x17, + 0xe9, 0x61, 0xcc, 0x5c, 0x4c, 0x3e, 0xe3, 0x71, 0xc1, 0x5a, 0xd7, 0xbf, 0xa7, 0xd4, 0xda, 0xe9, + 0x57, 0x4a, 0x32, 0x1a, 0xef, 0xfc, 0xcf, 0x68, 0xe6, 0xad, 0x21, 0xaa, 0xf3, 0xff, 0xe2, 0x66, + 0x5c, 0x40, 0xd3, 0x30, 0x95, 0x7b, 0xfe, 0x67, 0x54, 0x90, 0x01, 0xe3, 0xd9, 0xc4, 0x20, 0xe3, + 0x22, 0x1a, 0x87, 0x9a, 0x18, 0x2c, 0x63, 0x08, 0x4d, 0x40, 0x3d, 0xc9, 0x97, 0x30, 0xaa, 0x68, + 0x0a, 0xc6, 0x32, 0xf7, 0xff, 0xc6, 0x30, 0x9a, 0x04, 0x48, 0x6f, 0x8c, 0x8d, 0x11, 0x8a, 0x97, + 0xbd, 0x2a, 0x35, 0x46, 0x29, 0x47, 0xfa, 0xca, 0xcc, 0xa8, 0x51, 0xc4, 0xe4, 0xf1, 0x98, 0x51, + 0x47, 0x73, 0xaa, 0xe7, 0x63, 0x06, 0x50, 0x7a, 0xf1, 0x19, 0x97, 0x31, 0x86, 0x50, 0xfe, 0x21, + 0x97, 0x31, 0x8e, 0xc6, 0x92, 0x57, 0x59, 0xc6, 0x04, 0xba, 0xac, 0x79, 0x70, 0x65, 0x4c, 0xa2, + 0x4b, 0xb9, 0xf7, 0x52, 0xc6, 0x14, 0x9a, 0x29, 0x3e, 0x7f, 0x32, 0x8c, 0xec, 0x57, 0x50, 0x7d, + 0x61, 0x5c, 0xe2, 0x94, 0xe4, 0x66, 0xc6, 0x40, 0x74, 0x38, 0x73, 0x4f, 0x81, 0x8c, 0x69, 0x4a, + 0xcc, 0x05, 0xdb, 0x8d, 0x19, 0xda, 0xac, 0xe4, 0x74, 0x1a, 0xb3, 0x68, 0x51, 0xff, 0xfc, 0xc6, + 0x98, 0xa3, 0x43, 0x94, 0xa4, 0x2a, 0x19, 0xf3, 0xbc, 0xa5, 0xac, 0xdb, 0x67, 0x98, 0xb4, 0x43, + 0x59, 0x5f, 0xcd, 0xb8, 0xcc, 0xa6, 0x62, 0x7f, 0x77, 0xe3, 0xb3, 0x03, 0xbc, 0xdf, 0x68, 0x19, + 0x0b, 0xbc, 0xfc, 0x68, 0x77, 0xa7, 0xb9, 0xdb, 0x3c, 0x34, 0xae, 0xd0, 0x4f, 0xcd, 0x1b, 0xdf, + 0xc6, 0x22, 0x1d, 0x2e, 0xa5, 0x49, 0x6e, 0x5c, 0x65, 0xfd, 0xce, 0x1a, 0xbe, 0xc6, 0x12, 0x9b, + 0xff, 0xfd, 0xc4, 0xa0, 0x32, 0x96, 0x29, 0x21, 0x63, 0xe2, 0x18, 0x2b, 0xb4, 0xb3, 0x39, 0xe3, + 0xc4, 0xb8, 0x46, 0x27, 0xb3, 0x68, 0x13, 0x18, 0x16, 0xfd, 0x88, 0xec, 0x99, 0x6b, 0xbc, 0x83, + 0xae, 0x30, 0xdb, 0x46, 0x95, 0x3e, 0x65, 0x5c, 0x47, 0xb3, 0x70, 0xa9, 0x90, 0x4d, 0x64, 0xbc, + 0x8b, 0x16, 0x60, 0x4e, 0x6d, 0x5f, 0x1a, 0x37, 0xd0, 0x3c, 0x4c, 0x2b, 0x0e, 0x4e, 0xe3, 0x26, + 0xed, 0x52, 0x51, 0x3f, 0x1b, 0xb7, 0xd0, 0x3b, 0x03, 0xb3, 0xc5, 0x8d, 0xdb, 0xb4, 0x97, 0x9a, + 0x2c, 0x6c, 0xe3, 0x0e, 0x1d, 0x51, 0x65, 0xfa, 0xb4, 0x71, 0x57, 0x23, 0xf7, 0x94, 0x9c, 0x87, + 0xc6, 0x7b, 0x74, 0x28, 0x33, 0x6a, 0xc3, 0xb8, 0x47, 0x3f, 0xb7, 0xb0, 0xcd, 0x8d, 0x55, 0xb1, + 0x63, 0xe4, 0xc4, 0x5f, 0x63, 0xed, 0xce, 0x37, 0x15, 0x29, 0xb8, 0x91, 0xde, 0x75, 0xd1, 0x1e, + 0xe5, 0x2a, 0xe2, 0xc8, 0x92, 0x71, 0x01, 0xdd, 0x85, 0x9b, 0xb9, 0xaa, 0xd6, 0x2b, 0xa7, 0xa7, + 0xba, 0x3e, 0x31, 0x2a, 0xe8, 0x1e, 0xdc, 0xce, 0xe3, 0xb0, 0x04, 0x61, 0x25, 0xfb, 0xc5, 0x3b, + 0xef, 0xc1, 0x8c, 0xca, 0x17, 0x44, 0x40, 0xcd, 0xe9, 0xae, 0xcf, 0x94, 0x52, 0x0d, 0xaa, 0x5b, + 0x4e, 0xf8, 0xca, 0xa8, 0x6c, 0xee, 0xfc, 0xe1, 0xdb, 0xa5, 0xca, 0x1f, 0xbf, 0x5d, 0xaa, 0xfc, + 0xf9, 0xdb, 0xa5, 0x0b, 0xbf, 0xfb, 0x6e, 0xe9, 0xc2, 0xdf, 0x7f, 0xb7, 0x54, 0xf9, 0xe3, 0x77, + 0x4b, 0x17, 0xfe, 0xf4, 0xdd, 0xd2, 0x85, 0xcf, 0x57, 0x33, 0xff, 0xed, 0xb2, 0x6b, 0x47, 0x81, + 0x73, 0xe6, 0x07, 0xce, 0x89, 0xe3, 0x89, 0x82, 0x47, 0xd6, 0x7a, 0xaf, 0x4e, 0xd6, 0x7a, 0x47, + 0x6b, 0x4c, 0x47, 0x1f, 0x8d, 0xb0, 0xec, 0x9b, 0x9f, 0xff, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xfb, 0xaf, 0x6c, 0x6d, 0x8d, 0x53, 0x00, 0x00, } func (m *QueryRequest) Marshal() (dAtA []byte, err error) { @@ -8068,6 +8383,18 @@ func (m *Request) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.GetPythonUdfStatusRequest.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3 + i-- + dAtA[i] = 0x8a if m.DisconnectSessionRequest != nil { { size, err := m.DisconnectSessionRequest.MarshalToSizedBuffer(dAtA[:i]) @@ -8728,6 +9055,18 @@ func (m *Response) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.GetPythonUdfStatus.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x3 + i-- + dAtA[i] = 0x92 if m.DisconnectSessionResponse != nil { { size, err := m.DisconnectSessionResponse.MarshalToSizedBuffer(dAtA[:i]) @@ -9340,6 +9679,236 @@ func (m *Response) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *GetPythonUdfStatusRequest) Marshal() (dAtA []byte, err error) { + size := m.ProtoSize() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetPythonUdfStatusRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.ProtoSize() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetPythonUdfStatusRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *GetPythonUdfStatusResponse) Marshal() (dAtA []byte, err error) { + size := m.ProtoSize() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *GetPythonUdfStatusResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.ProtoSize() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *GetPythonUdfStatusResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.NullPolicies) > 0 { + for iNdEx := len(m.NullPolicies) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.NullPolicies[iNdEx]) + copy(dAtA[i:], m.NullPolicies[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.NullPolicies[iNdEx]))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xc2 + } + } + if len(m.Modes) > 0 { + for iNdEx := len(m.Modes) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Modes[iNdEx]) + copy(dAtA[i:], m.Modes[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Modes[iNdEx]))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xba + } + } + if m.LeaseEpoch != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.LeaseEpoch)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xb0 + } + if m.MaxOwnerHandlerProcesses != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.MaxOwnerHandlerProcesses)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa8 + } + if m.MaxAccountHandlerProcesses != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.MaxAccountHandlerProcesses)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa0 + } + if m.MaxHandlerProcesses != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.MaxHandlerProcesses)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x98 + } + if m.MaxExecutionFrameBytes != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.MaxExecutionFrameBytes)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x90 + } + if m.CumulativeAck { + i-- + if m.CumulativeAck { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x88 + } + if m.WindowBatches != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.WindowBatches)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x80 + } + if len(m.TimezoneDatabaseVersion) > 0 { + i -= len(m.TimezoneDatabaseVersion) + copy(dAtA[i:], m.TimezoneDatabaseVersion) + i = encodeVarintQuery(dAtA, i, uint64(len(m.TimezoneDatabaseVersion))) + i-- + dAtA[i] = 0x7a + } + if len(m.TypeDescriptorContract) > 0 { + i -= len(m.TypeDescriptorContract) + copy(dAtA[i:], m.TypeDescriptorContract) + i = encodeVarintQuery(dAtA, i, uint64(len(m.TypeDescriptorContract))) + i-- + dAtA[i] = 0x72 + } + if m.PlanContractVersion != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.PlanContractVersion)) + i-- + dAtA[i] = 0x68 + } + if m.DefinitionSchemaVersion != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.DefinitionSchemaVersion)) + i-- + dAtA[i] = 0x60 + } + if len(m.SDKVersion) > 0 { + i -= len(m.SDKVersion) + copy(dAtA[i:], m.SDKVersion) + i = encodeVarintQuery(dAtA, i, uint64(len(m.SDKVersion))) + i-- + dAtA[i] = 0x5a + } + if len(m.AdapterVersion) > 0 { + i -= len(m.AdapterVersion) + copy(dAtA[i:], m.AdapterVersion) + i = encodeVarintQuery(dAtA, i, uint64(len(m.AdapterVersion))) + i-- + dAtA[i] = 0x52 + } + if len(m.ABIContract) > 0 { + i -= len(m.ABIContract) + copy(dAtA[i:], m.ABIContract) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ABIContract))) + i-- + dAtA[i] = 0x4a + } + if m.ProtocolVersion != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.ProtocolVersion)) + i-- + dAtA[i] = 0x40 + } + if len(m.Reason) > 0 { + i -= len(m.Reason) + copy(dAtA[i:], m.Reason) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Reason))) + i-- + dAtA[i] = 0x3a + } + if len(m.ErrorClass) > 0 { + i -= len(m.ErrorClass) + copy(dAtA[i:], m.ErrorClass) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ErrorClass))) + i-- + dAtA[i] = 0x32 + } + if m.Ready { + i-- + if m.Ready { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + if m.AllowUnisolated { + i-- + if m.AllowUnisolated { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if m.Enabled { + i-- + if m.Enabled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x18 + } + if len(m.Language) > 0 { + i -= len(m.Language) + copy(dAtA[i:], m.Language) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Language))) + i-- + dAtA[i] = 0x12 + } + if len(m.CNUUID) > 0 { + i -= len(m.CNUUID) + copy(dAtA[i:], m.CNUUID) + i = encodeVarintQuery(dAtA, i, uint64(len(m.CNUUID))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *AlterAccountRequest) Marshal() (dAtA []byte, err error) { size := m.ProtoSize() dAtA = make([]byte, size) @@ -10077,12 +10646,12 @@ func (m *TxnInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x12 } - n98, err98 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreateAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreateAt):]) - if err98 != nil { - return 0, err98 + n100, err100 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.CreateAt, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.CreateAt):]) + if err100 != nil { + return 0, err100 } - i -= n98 - i = encodeVarintQuery(dAtA, i, uint64(n98)) + i -= n100 + i = encodeVarintQuery(dAtA, i, uint64(n100)) i-- dAtA[i] = 0xa return len(dAtA) - i, nil @@ -13259,6 +13828,8 @@ func (m *Request) ProtoSize() (n int) { l = m.DisconnectSessionRequest.ProtoSize() n += 2 + l + sovQuery(uint64(l)) } + l = m.GetPythonUdfStatusRequest.ProtoSize() + n += 2 + l + sovQuery(uint64(l)) return n } @@ -13449,20 +14020,127 @@ func (m *Response) ProtoSize() (n int) { l = m.DisconnectSessionResponse.ProtoSize() n += 2 + l + sovQuery(uint64(l)) } + l = m.GetPythonUdfStatus.ProtoSize() + n += 2 + l + sovQuery(uint64(l)) return n } -func (m *AlterAccountRequest) ProtoSize() (n int) { +func (m *GetPythonUdfStatusRequest) ProtoSize() (n int) { if m == nil { return 0 } var l int _ = l - if m.TenantId != 0 { - n += 1 + sovQuery(uint64(m.TenantId)) - } - l = len(m.Status) - if l > 0 { + return n +} + +func (m *GetPythonUdfStatusResponse) ProtoSize() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.CNUUID) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Language) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.Enabled { + n += 2 + } + if m.AllowUnisolated { + n += 2 + } + if m.Ready { + n += 2 + } + l = len(m.ErrorClass) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.Reason) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.ProtocolVersion != 0 { + n += 1 + sovQuery(uint64(m.ProtocolVersion)) + } + l = len(m.ABIContract) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.AdapterVersion) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.SDKVersion) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.DefinitionSchemaVersion != 0 { + n += 1 + sovQuery(uint64(m.DefinitionSchemaVersion)) + } + if m.PlanContractVersion != 0 { + n += 1 + sovQuery(uint64(m.PlanContractVersion)) + } + l = len(m.TypeDescriptorContract) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.TimezoneDatabaseVersion) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if m.WindowBatches != 0 { + n += 2 + sovQuery(uint64(m.WindowBatches)) + } + if m.CumulativeAck { + n += 3 + } + if m.MaxExecutionFrameBytes != 0 { + n += 2 + sovQuery(uint64(m.MaxExecutionFrameBytes)) + } + if m.MaxHandlerProcesses != 0 { + n += 2 + sovQuery(uint64(m.MaxHandlerProcesses)) + } + if m.MaxAccountHandlerProcesses != 0 { + n += 2 + sovQuery(uint64(m.MaxAccountHandlerProcesses)) + } + if m.MaxOwnerHandlerProcesses != 0 { + n += 2 + sovQuery(uint64(m.MaxOwnerHandlerProcesses)) + } + if m.LeaseEpoch != 0 { + n += 2 + sovQuery(uint64(m.LeaseEpoch)) + } + if len(m.Modes) > 0 { + for _, s := range m.Modes { + l = len(s) + n += 2 + l + sovQuery(uint64(l)) + } + } + if len(m.NullPolicies) > 0 { + for _, s := range m.NullPolicies { + l = len(s) + n += 2 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *AlterAccountRequest) ProtoSize() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.TenantId != 0 { + n += 1 + sovQuery(uint64(m.TenantId)) + } + l = len(m.Status) + if l > 0 { n += 1 + l + sovQuery(uint64(l)) } return n @@ -18322,6 +19000,39 @@ func (m *Request) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 49: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GetPythonUdfStatusRequest", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.GetPythonUdfStatusRequest.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) @@ -20142,6 +20853,742 @@ func (m *Response) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 50: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GetPythonUdfStatus", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.GetPythonUdfStatus.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetPythonUdfStatusRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetPythonUdfStatusRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetPythonUdfStatusRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *GetPythonUdfStatusResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: GetPythonUdfStatusResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: GetPythonUdfStatusResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field CNUUID", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.CNUUID = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Language", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Language = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Enabled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Enabled = bool(v != 0) + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AllowUnisolated", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.AllowUnisolated = bool(v != 0) + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Ready", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Ready = bool(v != 0) + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ErrorClass", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ErrorClass = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Reason", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Reason = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ProtocolVersion", wireType) + } + m.ProtocolVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ProtocolVersion |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ABIContract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ABIContract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AdapterVersion", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AdapterVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SDKVersion", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SDKVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 12: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DefinitionSchemaVersion", wireType) + } + m.DefinitionSchemaVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.DefinitionSchemaVersion |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 13: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PlanContractVersion", wireType) + } + m.PlanContractVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PlanContractVersion |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 14: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TypeDescriptorContract", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TypeDescriptorContract = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TimezoneDatabaseVersion", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.TimezoneDatabaseVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 16: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field WindowBatches", wireType) + } + m.WindowBatches = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.WindowBatches |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 17: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CumulativeAck", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CumulativeAck = bool(v != 0) + case 18: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxExecutionFrameBytes", wireType) + } + m.MaxExecutionFrameBytes = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxExecutionFrameBytes |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 19: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxHandlerProcesses", wireType) + } + m.MaxHandlerProcesses = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxHandlerProcesses |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 20: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxAccountHandlerProcesses", wireType) + } + m.MaxAccountHandlerProcesses = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxAccountHandlerProcesses |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 21: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxOwnerHandlerProcesses", wireType) + } + m.MaxOwnerHandlerProcesses = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.MaxOwnerHandlerProcesses |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 22: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field LeaseEpoch", wireType) + } + m.LeaseEpoch = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.LeaseEpoch |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 23: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Modes", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Modes = append(m.Modes, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 24: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NullPolicies", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NullPolicies = append(m.NullPolicies, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index ae211142faca0..202fe94d4b43e 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,6 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion72, } type queryClient struct { diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 45ff234ec5a4c..1b4e04bc445c0 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -56,6 +56,7 @@ const ( var errGatewayClosed = errors.New("python udf gateway is closed") var _ udf.RuntimeDefinitionValidator = (*Gateway)(nil) +var _ udf.RuntimeStatusProvider = (*Gateway)(nil) type Gateway struct { cfg ClientConfig @@ -70,6 +71,7 @@ type Gateway struct { admissionMu sync.Mutex capabilityReady bool workerLeaseEpoch uint64 + capability *capabilityResponse closed bool active chan struct{} ledger *protocol.TerminalLedger @@ -185,6 +187,101 @@ func (g *Gateway) CheckLanguageReady(ctx context.Context, language string) error return g.ensureCapabilities(requestCtx, client, true) } +// StatusSnapshot is the control-plane view of the current Python runtime. It +// deliberately reuses CheckLanguageReady, so the status reported for a +// same-Pod CN is the same capability handshake that gates an invocation. The +// action only probes the worker and does not acquire an invocation, handler, +// input credit, or terminal-ledger entry. +func (g *Gateway) StatusSnapshot(ctx context.Context, language string) udf.RuntimeStatusSnapshot { + if ctx == nil { + ctx = context.Background() + } + snapshot := udf.RuntimeStatusSnapshot{ + Language: language, + Enabled: g.cfg.Enabled, + AllowUnisolated: g.cfg.AllowUnisolated, + } + if language != udf.LanguagePython { + snapshot.ErrorClass = udf.RuntimeStatusInvalid + snapshot.Reason = udf.RuntimeStatusReasonInvalidLanguage + return snapshot + } + if !g.cfg.Enabled { + snapshot.ErrorClass = udf.RuntimeStatusDisabled + snapshot.Reason = udf.RuntimeStatusReasonRuntimeDisabled + return snapshot + } + if !g.cfg.AllowUnisolated { + snapshot.ErrorClass = udf.RuntimeStatusNotAllowed + snapshot.Reason = udf.RuntimeStatusReasonUnisolatedNotAllowed + return snapshot + } + + err := g.CheckLanguageReady(ctx, language) + g.mu.Lock() + capability := g.capability + ready := g.capabilityReady && g.workerLeaseEpoch != 0 && !g.closed + if capability != nil { + snapshot.ProtocolVersion = int32(capability.ProtocolVersion) + snapshot.ABIContract = capability.ABIContract + snapshot.AdapterVersion = capability.AdapterVersion + snapshot.SDKVersion = capability.SDKVersion + snapshot.DefinitionSchemaVersion = int32(capability.DefinitionSchemaVersion) + snapshot.PlanContractVersion = int32(capability.PlanContractVersion) + snapshot.TypeDescriptorContract = capability.TypeDescriptorContract + snapshot.TimezoneDatabaseVersion = capability.TimezoneDatabaseVersion + snapshot.WindowBatches = int32(capability.WindowBatches) + snapshot.CumulativeAck = capability.CumulativeAck + snapshot.MaxExecutionFrameBytes = capability.MaxExecutionFrameBytes + snapshot.MaxHandlerProcesses = int32(capability.MaxHandlerProcesses) + snapshot.MaxAccountHandlerProcesses = int32(capability.MaxAccountHandlerProcesses) + snapshot.MaxOwnerHandlerProcesses = int32(capability.MaxOwnerHandlerProcesses) + snapshot.LeaseEpoch = capability.LeaseEpoch + snapshot.Modes = append([]string(nil), capability.Modes...) + snapshot.NullPolicies = append([]string(nil), capability.NullPolicies...) + } + g.mu.Unlock() + + if err == nil && ready { + snapshot.Ready = true + snapshot.ErrorClass = "" + snapshot.Reason = udf.RuntimeStatusReasonReady + return snapshot + } + if err == nil { + snapshot.ErrorClass = udf.RuntimeStatusUnavailable + snapshot.Reason = udf.RuntimeStatusReasonWorkerUnavailable + return snapshot + } + snapshot.ErrorClass, snapshot.Reason = classifyStatusError(err) + return snapshot +} + +func classifyStatusError(err error) (string, string) { + if err == nil { + return "", udf.RuntimeStatusReasonReady + } + if errors.Is(err, context.DeadlineExceeded) { + return udf.RuntimeStatusTimeout, udf.RuntimeStatusReasonRequestTimeout + } + if errors.Is(err, errGatewayClosed) { + return udf.RuntimeStatusClosed, udf.RuntimeStatusReasonRuntimeClosed + } + message := strings.ToLower(err.Error()) + switch { + case strings.Contains(message, "contract does not match"), + strings.Contains(message, "capability set does not match"): + return udf.RuntimeStatusContractMismatch, udf.RuntimeStatusReasonCapabilityMismatch + case strings.Contains(message, "deadline exceeded"), strings.Contains(message, "timeout"): + return udf.RuntimeStatusTimeout, udf.RuntimeStatusReasonRequestTimeout + case strings.Contains(message, "connection"), strings.Contains(message, "transport"), + strings.Contains(message, "flight"), strings.Contains(message, "unavailable"): + return udf.RuntimeStatusUnavailable, udf.RuntimeStatusReasonWorkerUnavailable + default: + return udf.RuntimeStatusInternal, udf.RuntimeStatusReasonRuntimeError + } +} + // ValidateDefinition asks the current worker to compile the exact artifact // that a CREATE or REPLACE is about to publish. This action has no // FunctionRef, invocation lease, handler slot, or ledger entry: a definition @@ -1145,6 +1242,7 @@ func (g *Gateway) ensureCapabilities(ctx context.Context, client flight.FlightSe // success that could authorize a lease-less Flight Action. g.capabilityReady = false g.workerLeaseEpoch = 0 + g.capability = nil } ready := g.capabilityReady closed := g.closed @@ -1203,6 +1301,10 @@ func (g *Gateway) ensureCapabilities(ctx context.Context, client flight.FlightSe if !g.closed { g.capabilityReady = true g.workerLeaseEpoch = response.LeaseEpoch + capability := response + capability.Modes = append([]string(nil), response.Modes...) + capability.NullPolicies = append([]string(nil), response.NullPolicies...) + g.capability = &capability } g.mu.Unlock() return nil @@ -1219,6 +1321,7 @@ func (g *Gateway) invalidateCapabilities() { g.mu.Lock() g.capabilityReady = false g.workerLeaseEpoch = 0 + g.capability = nil g.mu.Unlock() } @@ -1605,13 +1708,37 @@ func (g *Gateway) receiveFinish( if control.LastResultSequence != lastResult { return fmt.Errorf("python udf: invalid Finish result sequence %d, expected %d", control.LastResultSequence, lastResult) } - return g.acknowledgeFinish(ctx, client, "AcknowledgeFinish", protocol.Control{Kind: "AcknowledgeFinish", Tuple: tuple, FinishID: control.FinishID}) + if err := g.acknowledgeFinish(ctx, client, "AcknowledgeFinish", protocol.Control{Kind: "AcknowledgeFinish", Tuple: tuple, FinishID: control.FinishID}); err != nil { + return err + } + // AcknowledgeFinish is accepted by the worker's action RPC before + // the DoExchange callback runs its finally block. The callback owns + // the input reader, handler process, and worker group fence, so the + // action ACK alone is not a safe re-entry boundary. Wait for the + // exchange to reach EOF; Flight reports EOF only after the callback + // has returned and its cleanup owner has completed. + return g.waitExchangeEOF(ctx, stream) default: return fmt.Errorf("python udf: unexpected control %q", control.Kind) } } } +func (g *Gateway) waitExchangeEOF(ctx context.Context, stream flight.FlightService_DoExchangeClient) error { + for { + data, err := stream.Recv() + if err == io.EOF { + return nil + } + if err != nil { + return fmt.Errorf("python udf: wait for exchange completion: %w", err) + } + if data == nil || len(data.DataHeader) != 0 || len(data.DataBody) != 0 || len(data.AppMetadata) != 0 { + return fmt.Errorf("python udf: exchange returned data after Finish ACK") + } + } +} + // acknowledgeFinish retries only the idempotent terminal ACK. A lost ACK // request or response must not replay any STARTED input or handler work. // Once the request budget is exhausted the caller preserves the distinction diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index 9803ec6838849..fc47c4d3e48ea 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -10,6 +10,7 @@ import ( "errors" "io" "strings" + "sync" "testing" "time" @@ -29,6 +30,15 @@ type gatewayResultStream struct { index int } +type gatedGatewayResultStream struct { + grpc.ClientStream + results []*flight.FlightData + index int + release <-chan struct{} + waiting chan<- struct{} + waitOnce sync.Once +} + type finishAckActionStream struct { grpc.ClientStream result *flight.Result @@ -203,6 +213,21 @@ func (s *gatewayResultStream) Send(*flight.FlightData) error { return nil } +func (s *gatedGatewayResultStream) Recv() (*flight.FlightData, error) { + if s.index < len(s.results) { + result := s.results[s.index] + s.index++ + return result, nil + } + s.waitOnce.Do(func() { close(s.waiting) }) + <-s.release + return nil, io.EOF +} + +func (s *gatedGatewayResultStream) Send(*flight.FlightData) error { + return nil +} + func gatewayControl(t *testing.T, kind string, tuple protocol.FencingTuple, fields ...func(*protocol.Control)) *flight.FlightData { t.Helper() control := protocol.Control{Kind: kind, Tuple: tuple} @@ -560,6 +585,42 @@ func TestGatewayFinishRejectsLateHalfStreamControls(t *testing.T) { } } +func TestGatewayFinishWaitsForExchangeEOF(t *testing.T) { + tuple := validInvocation().Tuple + sequence := protocol.Sequence{} + require.NoError(t, sequence.AcceptInput(1)) + require.NoError(t, sequence.EndInput(1)) + require.NoError(t, sequence.AcceptResult(1)) + require.NoError(t, sequence.AcknowledgeResults(1)) + finish := gatewayControl(t, "Finish", tuple, func(value *protocol.Control) { + value.Status = statusOK + value.FinishID = "finish-1" + value.LastSequence = 1 + value.LastResultSequence = 1 + }) + release := make(chan struct{}) + waiting := make(chan struct{}) + stream := &gatedGatewayResultStream{ + results: []*flight.FlightData{finish}, + release: release, + waiting: waiting, + } + gateway := &Gateway{cfg: ClientConfig{RequestTimeout: time.Second}} + done := make(chan error, 1) + go func() { + done <- gateway.receiveFinish(context.Background(), &finishAckFlightClient{}, stream, tuple, 1, 1, &sequence) + }() + + <-waiting + select { + case err := <-done: + require.Failf(t, "Finish returned before the exchange reached EOF", "%v", err) + default: + } + close(release) + require.NoError(t, <-done) +} + func TestGatewayRejectsArrowBodyOnControlFrame(t *testing.T) { tuple := validInvocation().Tuple sequence := protocol.Sequence{} diff --git a/pkg/udf/runtime.go b/pkg/udf/runtime.go index d68bde7f54323..72b3881f83bcc 100644 --- a/pkg/udf/runtime.go +++ b/pkg/udf/runtime.go @@ -300,6 +300,68 @@ type RuntimeReadiness interface { CheckLanguageReady(context.Context, string) error } +// RuntimeStatusSnapshot is the bounded, read-only state exposed to control +// planes that need to observe a language runtime without entering the +// invocation path. A snapshot never contains source, artifacts, secrets, or +// invocation identifiers. The capability fields are a summary of the +// already negotiated worker contract; the runtime remains responsible for +// deciding whether the summary is valid. +type RuntimeStatusSnapshot struct { + Language string + Enabled bool + AllowUnisolated bool + Ready bool + ErrorClass string + Reason string + ProtocolVersion int32 + ABIContract string + AdapterVersion string + SDKVersion string + DefinitionSchemaVersion int32 + PlanContractVersion int32 + TypeDescriptorContract string + TimezoneDatabaseVersion string + WindowBatches int32 + CumulativeAck bool + MaxExecutionFrameBytes int64 + MaxHandlerProcesses int32 + MaxAccountHandlerProcesses int32 + MaxOwnerHandlerProcesses int32 + LeaseEpoch uint64 + Modes []string + NullPolicies []string +} + +const ( + RuntimeStatusReady = "READY" + RuntimeStatusDisabled = "DISABLED" + RuntimeStatusNotAllowed = "NOT_ALLOWED" + RuntimeStatusUnavailable = "UNAVAILABLE" + RuntimeStatusContractMismatch = "CONTRACT_MISMATCH" + RuntimeStatusTimeout = "TIMEOUT" + RuntimeStatusClosed = "CLOSED" + RuntimeStatusInvalid = "INVALID" + RuntimeStatusInternal = "INTERNAL" + + RuntimeStatusReasonReady = "CapabilityHandshakeReady" + RuntimeStatusReasonRuntimeDisabled = "RuntimeDisabled" + RuntimeStatusReasonUnisolatedNotAllowed = "UnisolatedExecutionNotAllowed" + RuntimeStatusReasonWorkerUnavailable = "WorkerUnavailable" + RuntimeStatusReasonCapabilityMismatch = "CapabilityContractMismatch" + RuntimeStatusReasonRequestTimeout = "CapabilityRequestTimeout" + RuntimeStatusReasonRuntimeClosed = "RuntimeClosed" + RuntimeStatusReasonStatusUnavailable = "RuntimeStatusUnavailable" + RuntimeStatusReasonInvalidLanguage = "InvalidLanguage" + RuntimeStatusReasonRuntimeError = "RuntimeError" +) + +// RuntimeStatusProvider supplies the bounded status view used by the CN query +// service. Implementations may refresh a capability handshake, but must not +// execute user code or allocate invocation/ledger state. +type RuntimeStatusProvider interface { + StatusSnapshot(context.Context, string) RuntimeStatusSnapshot +} + // RoutineDefinition is the typed, pre-publication contract handed to a // language runtime for definition validation. It is deliberately separate // from Invocation: a CREATE or REPLACE has no FunctionRef/revision yet and @@ -389,6 +451,44 @@ func (r *runtimeRegistry) CheckLanguageReady(ctx context.Context, language strin return readiness.CheckLanguageReady(ctx, language) } +func (r *runtimeRegistry) StatusSnapshot(ctx context.Context, language string) RuntimeStatusSnapshot { + runtime := r.byLanguage[language] + if runtime == nil { + return RuntimeStatusSnapshot{ + Language: language, + ErrorClass: RuntimeStatusDisabled, + Reason: RuntimeStatusReasonRuntimeDisabled, + } + } + if provider, ok := runtime.(RuntimeStatusProvider); ok { + return provider.StatusSnapshot(ctx, language) + } + readiness, ok := runtime.(RuntimeReadiness) + if !ok { + return RuntimeStatusSnapshot{ + Language: language, + Enabled: true, + ErrorClass: RuntimeStatusUnavailable, + Reason: RuntimeStatusReasonStatusUnavailable, + } + } + if err := readiness.CheckLanguageReady(ctx, language); err != nil { + return RuntimeStatusSnapshot{ + Language: language, + Enabled: true, + ErrorClass: RuntimeStatusUnavailable, + Reason: RuntimeStatusReasonWorkerUnavailable, + } + } + return RuntimeStatusSnapshot{ + Language: language, + Enabled: true, + Ready: true, + ErrorClass: "", + Reason: RuntimeStatusReasonReady, + } +} + func (r *runtimeRegistry) ValidateDefinition(ctx context.Context, definition *RoutineDefinition) error { if definition == nil { return moerr.NewInvalidInputNoCtx("nil UDF routine definition") diff --git a/proto/query.proto b/proto/query.proto index 4627c9f6b8952..3ae270329747e 100644 --- a/proto/query.proto +++ b/proto/query.proto @@ -125,6 +125,9 @@ enum CmdMethod { // Current-session SQL authorization and proxy lifecycle cleanup. KillSession = 45; DisconnectSession = 46; + // GetPythonUdfStatus returns the bounded, read-only Python runtime status of + // the addressed CN. It is consumed by the Operator for same-Pod workers. + GetPythonUdfStatus = 47; } // QueryRequest is the common query request. It contains the query @@ -314,6 +317,8 @@ message Request { GetVectorIndexCacheKeysRequest GetVectorIndexCacheKeys = 46 [ (gogoproto.nullable) = false ]; KillSessionRequest KillSessionRequest = 47; DisconnectSessionRequest DisconnectSessionRequest = 48; + // GetPythonUdfStatusRequest asks this CN for its local Python runtime state. + GetPythonUdfStatusRequest GetPythonUdfStatusRequest = 49 [ (gogoproto.nullable) = false ]; } // ShowProcessListResponse is the response of command ShowProcessList. @@ -390,6 +395,38 @@ message Response { GetVectorIndexCacheKeysResponse GetVectorIndexCacheKeys = 47 [ (gogoproto.nullable) = false ]; KillSessionResponse KillSessionResponse = 48; DisconnectSessionResponse DisconnectSessionResponse = 49; + // GetPythonUdfStatus is a bounded summary of the CN-local Python contract. + GetPythonUdfStatusResponse GetPythonUdfStatus = 50 [ (gogoproto.nullable) = false ]; +} + +message GetPythonUdfStatusRequest { +} + +message GetPythonUdfStatusResponse { + string CNUUID = 1; + string Language = 2; + bool Enabled = 3; + bool AllowUnisolated = 4; + bool Ready = 5; + string ErrorClass = 6; + string Reason = 7; + int32 ProtocolVersion = 8; + string ABIContract = 9; + string AdapterVersion = 10; + string SDKVersion = 11; + int32 DefinitionSchemaVersion = 12; + int32 PlanContractVersion = 13; + string TypeDescriptorContract = 14; + string TimezoneDatabaseVersion = 15; + int32 WindowBatches = 16; + bool CumulativeAck = 17; + int64 MaxExecutionFrameBytes = 18; + int32 MaxHandlerProcesses = 19; + int32 MaxAccountHandlerProcesses = 20; + int32 MaxOwnerHandlerProcesses = 21; + uint64 LeaseEpoch = 22; + repeated string Modes = 23; + repeated string NullPolicies = 24; } // AlterAccountRequest is the "alter account restricted" query request. From e27e234a34c2ce66c2cc0a442c86b493a5e3da18 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 10:59:30 +0800 Subject: [PATCH 154/241] test: add Arrow compute correctness cases for Python UDF --- test/distributed/cases/udf_python/README.md | 18 +++++++--- .../arrow_compute_arithmetic.result | 33 +++++++++++++++++ .../udf_python/arrow_compute_arithmetic.sql | 35 +++++++++++++++++++ .../udf_python/arrow_compute_selection.result | 30 ++++++++++++++++ .../udf_python/arrow_compute_selection.sql | 33 +++++++++++++++++ .../udf_python/arrow_compute_strings.result | 30 ++++++++++++++++ .../udf_python/arrow_compute_strings.sql | 32 +++++++++++++++++ 7 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 test/distributed/cases/udf_python/arrow_compute_arithmetic.result create mode 100644 test/distributed/cases/udf_python/arrow_compute_arithmetic.sql create mode 100644 test/distributed/cases/udf_python/arrow_compute_selection.result create mode 100644 test/distributed/cases/udf_python/arrow_compute_selection.sql create mode 100644 test/distributed/cases/udf_python/arrow_compute_strings.result create mode 100644 test/distributed/cases/udf_python/arrow_compute_strings.sql diff --git a/test/distributed/cases/udf_python/README.md b/test/distributed/cases/udf_python/README.md index 8e93f01a90baa..8b698862c6ef6 100644 --- a/test/distributed/cases/udf_python/README.md +++ b/test/distributed/cases/udf_python/README.md @@ -51,11 +51,19 @@ The cases keep the data sets small and target contract boundaries: prepared-plan invalidation, drop, and recreate on the same SQL signature. - `vector_mode.sql` checks Arrow VECTOR handlers, zero-argument batch shape, NULL policies, and handler validation during create and replace. +- `arrow_compute_arithmetic.sql` checks `pyarrow.compute` arithmetic, + conditional, fill-null, and validity kernels while preserving NULLs and + batch length. +- `arrow_compute_selection.sql` checks Arrow take, sort-indices, comparison, + and physical cast kernels with indexed and NULL input. +- `arrow_compute_strings.sql` checks UTF-8 uppercasing, substring matching, + replacement, and code-point length for empty, Unicode, and NULL values. The shape follows established correctness coverage from [DuckDB's scalar UDF tests](https://github.com/duckdb/duckdb-go/blob/main/scalar_udf_test.go) -(NULLs, multiple rows, multiple arguments, and errors) and -[Apache Arrow's extension type tests](https://github.com/apache/arrow/blob/main/python/pyarrow/tests/test_extension_type.py) -(null-aware arrays, fixed-size binary values, and type validation). The SQL -cases adapt those ideas to MatrixOne's Python Arrow boundary rather than -copying another project's implementation. +(NULLs, multiple rows, multiple arguments, and errors), and the added compute +cases use the common kernels documented by +[PyArrow's compute API](https://arrow.apache.org/docs/python/compute.html) +(arithmetic, validity, selection, cast, and UTF-8). The SQL cases adapt those +ideas to MatrixOne's Python Arrow boundary rather than copying another +project's implementation. diff --git a/test/distributed/cases/udf_python/arrow_compute_arithmetic.result b/test/distributed/cases/udf_python/arrow_compute_arithmetic.result new file mode 100644 index 0000000000000..14900615bc75c --- /dev/null +++ b/test/distributed/cases/udf_python/arrow_compute_arithmetic.result @@ -0,0 +1,33 @@ +drop database if exists udf_python_arrow_compute_arithmetic_bvt; +create database udf_python_arrow_compute_arithmetic_bvt; +use udf_python_arrow_compute_arithmetic_bvt; +create function python_bvt_pc_add (x int) returns bigint language python as 'python_bvt_pc_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, 10)' handler 'python_bvt_pc_add' mode vector; +create function python_bvt_pc_multiply (x int, y int) returns int language python as 'python_bvt_pc_multiply = lambda ctx, left, right: __import__("pyarrow.compute", fromlist=["multiply"]).multiply(left, right)' handler 'python_bvt_pc_multiply' mode vector; +create function python_bvt_pc_if_else (flag bool, x int, y int) returns int language python as 'python_bvt_pc_if_else = lambda ctx, flag, left, right: __import__("pyarrow.compute", fromlist=["if_else"]).if_else(flag, left, right)' handler 'python_bvt_pc_if_else' mode vector; +create function python_bvt_pc_fill_null (x int) returns int language python as 'python_bvt_pc_fill_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["fill_null"]).fill_null(values, -7)' handler 'python_bvt_pc_fill_null' mode vector; +create function python_bvt_pc_is_null (x int) returns bool language python as 'python_bvt_pc_is_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["is_null"]).is_null(values)' handler 'python_bvt_pc_is_null' mode vector; +create table arithmetic_values (id int, flag bool, left_value int, right_value int); +insert into arithmetic_values values +(1, true, 1, 10), +(2, false, null, 20), +(3, null, 3, null), +(4, true, null, null); +select id, +python_bvt_pc_add(left_value) as added, +python_bvt_pc_multiply(left_value, right_value) as multiplied, +python_bvt_pc_if_else(flag, left_value, right_value) as selected, +python_bvt_pc_fill_null(left_value) as filled, +python_bvt_pc_is_null(left_value) as is_null +from arithmetic_values order by id; +➤ id[4,32,0] ¦ added[-5,64,0] ¦ multiplied[4,32,0] ¦ selected[4,32,0] ¦ filled[4,32,0] ¦ is_null[-7,1,0] 𝄀 +1 ¦ 11 ¦ 10 ¦ 1 ¦ 1 ¦ 0 𝄀 +2 ¦ null ¦ null ¦ 20 ¦ -7 ¦ 1 𝄀 +3 ¦ 13 ¦ null ¦ null ¦ 3 ¦ 0 𝄀 +4 ¦ null ¦ null ¦ null ¦ -7 ¦ 1 +drop function python_bvt_pc_add(int); +drop function python_bvt_pc_multiply(int, int); +drop function python_bvt_pc_if_else(bool, int, int); +drop function python_bvt_pc_fill_null(int); +drop function python_bvt_pc_is_null(int); +drop table arithmetic_values; +drop database udf_python_arrow_compute_arithmetic_bvt; diff --git a/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql b/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql new file mode 100644 index 0000000000000..cfea5b0c1a3e7 --- /dev/null +++ b/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql @@ -0,0 +1,35 @@ +-- Arrow compute arithmetic and validity kernels through the SQL UDF boundary. +drop database if exists udf_python_arrow_compute_arithmetic_bvt; +create database udf_python_arrow_compute_arithmetic_bvt; +use udf_python_arrow_compute_arithmetic_bvt; + +create function python_bvt_pc_add (x int) returns bigint language python as 'python_bvt_pc_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, 10)' handler 'python_bvt_pc_add' mode vector; +create function python_bvt_pc_multiply (x int, y int) returns int language python as 'python_bvt_pc_multiply = lambda ctx, left, right: __import__("pyarrow.compute", fromlist=["multiply"]).multiply(left, right)' handler 'python_bvt_pc_multiply' mode vector; +create function python_bvt_pc_if_else (flag bool, x int, y int) returns int language python as 'python_bvt_pc_if_else = lambda ctx, flag, left, right: __import__("pyarrow.compute", fromlist=["if_else"]).if_else(flag, left, right)' handler 'python_bvt_pc_if_else' mode vector; +create function python_bvt_pc_fill_null (x int) returns int language python as 'python_bvt_pc_fill_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["fill_null"]).fill_null(values, -7)' handler 'python_bvt_pc_fill_null' mode vector; +create function python_bvt_pc_is_null (x int) returns bool language python as 'python_bvt_pc_is_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["is_null"]).is_null(values)' handler 'python_bvt_pc_is_null' mode vector; + +create table arithmetic_values (id int, flag bool, left_value int, right_value int); +insert into arithmetic_values values + (1, true, 1, 10), + (2, false, null, 20), + (3, null, 3, null), + (4, true, null, null); + +-- These kernels must preserve Arrow validity instead of converting NULL to a +-- value or changing the batch length. +select id, + python_bvt_pc_add(left_value) as added, + python_bvt_pc_multiply(left_value, right_value) as multiplied, + python_bvt_pc_if_else(flag, left_value, right_value) as selected, + python_bvt_pc_fill_null(left_value) as filled, + python_bvt_pc_is_null(left_value) as is_null +from arithmetic_values order by id; + +drop function python_bvt_pc_add(int); +drop function python_bvt_pc_multiply(int, int); +drop function python_bvt_pc_if_else(bool, int, int); +drop function python_bvt_pc_fill_null(int); +drop function python_bvt_pc_is_null(int); +drop table arithmetic_values; +drop database udf_python_arrow_compute_arithmetic_bvt; diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.result b/test/distributed/cases/udf_python/arrow_compute_selection.result new file mode 100644 index 0000000000000..4c320f4d1e4c2 --- /dev/null +++ b/test/distributed/cases/udf_python/arrow_compute_selection.result @@ -0,0 +1,30 @@ +drop database if exists udf_python_arrow_compute_selection_bvt; +create database udf_python_arrow_compute_selection_bvt; +use udf_python_arrow_compute_selection_bvt; +create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices)' handler 'python_bvt_pc_take' mode vector; +create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values))' handler 'python_bvt_pc_sort_take' mode vector; +create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, 20)' handler 'python_bvt_pc_equal' mode vector; +create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64())' handler 'python_bvt_pc_cast' mode vector; +create table selection_values (id int, value int, index_value int); +insert into selection_values values +(1, 30, 2), +(2, null, 0), +(3, 20, 1), +(4, 10, 3); +select id, +python_bvt_pc_take(value, index_value) as taken, +python_bvt_pc_sort_take(value) as sorted_value, +python_bvt_pc_equal(value) as equals_twenty, +python_bvt_pc_cast(value) as cast_value +from selection_values order by id; +➤ id[4,32,0] ¦ taken[4,32,0] ¦ sorted_value[4,32,0] ¦ equals_twenty[-7,1,0] ¦ cast_value[-5,64,0] 𝄀 +1 ¦ 20 ¦ 10 ¦ 0 ¦ 30 𝄀 +2 ¦ 30 ¦ 20 ¦ null ¦ null 𝄀 +3 ¦ null ¦ 30 ¦ 1 ¦ 20 𝄀 +4 ¦ 10 ¦ null ¦ 0 ¦ 10 +drop function python_bvt_pc_take(int, int); +drop function python_bvt_pc_sort_take(int); +drop function python_bvt_pc_equal(int); +drop function python_bvt_pc_cast(int); +drop table selection_values; +drop database udf_python_arrow_compute_selection_bvt; diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.sql b/test/distributed/cases/udf_python/arrow_compute_selection.sql new file mode 100644 index 0000000000000..a548dc0275272 --- /dev/null +++ b/test/distributed/cases/udf_python/arrow_compute_selection.sql @@ -0,0 +1,33 @@ +-- Arrow compute selection, ordering, comparison, and cast kernels. +drop database if exists udf_python_arrow_compute_selection_bvt; +create database udf_python_arrow_compute_selection_bvt; +use udf_python_arrow_compute_selection_bvt; + +create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices)' handler 'python_bvt_pc_take' mode vector; +create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values))' handler 'python_bvt_pc_sort_take' mode vector; +create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, 20)' handler 'python_bvt_pc_equal' mode vector; +create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64())' handler 'python_bvt_pc_cast' mode vector; + +create table selection_values (id int, value int, index_value int); +insert into selection_values values + (1, 30, 2), + (2, null, 0), + (3, 20, 1), + (4, 10, 3); + +-- take uses an Arrow index array, sort_indices keeps NULL placement explicit, +-- and cast proves that the physical Arrow type can change within the declared +-- SQL type contract. +select id, + python_bvt_pc_take(value, index_value) as taken, + python_bvt_pc_sort_take(value) as sorted_value, + python_bvt_pc_equal(value) as equals_twenty, + python_bvt_pc_cast(value) as cast_value +from selection_values order by id; + +drop function python_bvt_pc_take(int, int); +drop function python_bvt_pc_sort_take(int); +drop function python_bvt_pc_equal(int); +drop function python_bvt_pc_cast(int); +drop table selection_values; +drop database udf_python_arrow_compute_selection_bvt; diff --git a/test/distributed/cases/udf_python/arrow_compute_strings.result b/test/distributed/cases/udf_python/arrow_compute_strings.result new file mode 100644 index 0000000000000..1e757796a0e5b --- /dev/null +++ b/test/distributed/cases/udf_python/arrow_compute_strings.result @@ -0,0 +1,30 @@ +drop database if exists udf_python_arrow_compute_strings_bvt; +create database udf_python_arrow_compute_strings_bvt; +use udf_python_arrow_compute_strings_bvt; +create function python_bvt_pc_upper (x varchar(64)) returns varchar(64) language python as 'python_bvt_pc_upper = lambda ctx, values: __import__("pyarrow.compute", fromlist=["utf8_upper"]).utf8_upper(values)' handler 'python_bvt_pc_upper' mode vector; +create function python_bvt_pc_contains (x varchar(64)) returns bool language python as 'python_bvt_pc_contains = lambda ctx, values: __import__("pyarrow.compute", fromlist=["match_substring"]).match_substring(values, "a")' handler 'python_bvt_pc_contains' mode vector; +create function python_bvt_pc_replace (x varchar(64)) returns varchar(64) language python as 'python_bvt_pc_replace = lambda ctx, values: __import__("pyarrow.compute", fromlist=["replace_substring"]).replace_substring(values, "a", "X")' handler 'python_bvt_pc_replace' mode vector; +create function python_bvt_pc_length (x varchar(64)) returns int language python as 'python_bvt_pc_length = lambda ctx, values: __import__("pyarrow.compute", fromlist=["utf8_length"]).utf8_length(values)' handler 'python_bvt_pc_length' mode vector; +create table string_values (id int, value varchar(64)); +insert into string_values values +(1, ''), +(2, 'Alpha'), +(3, '中a😀'), +(4, null); +select id, +python_bvt_pc_upper(value) as upper_value, +python_bvt_pc_contains(value) as contains_a, +python_bvt_pc_replace(value) as replaced_value, +python_bvt_pc_length(value) as codepoint_length +from string_values order by id; +➤ id[4,32,0] ¦ upper_value[12,64,0] ¦ contains_a[-7,1,0] ¦ replaced_value[12,64,0] ¦ codepoint_length[4,32,0] 𝄀 +1 ¦ ¦ 0 ¦ ¦ 0 𝄀 +2 ¦ ALPHA ¦ 1 ¦ AlphX ¦ 5 𝄀 +3 ¦ 中A😀 ¦ 1 ¦ 中X😀 ¦ 3 𝄀 +4 ¦ null ¦ null ¦ null ¦ null +drop function python_bvt_pc_upper(varchar(64)); +drop function python_bvt_pc_contains(varchar(64)); +drop function python_bvt_pc_replace(varchar(64)); +drop function python_bvt_pc_length(varchar(64)); +drop table string_values; +drop database udf_python_arrow_compute_strings_bvt; diff --git a/test/distributed/cases/udf_python/arrow_compute_strings.sql b/test/distributed/cases/udf_python/arrow_compute_strings.sql new file mode 100644 index 0000000000000..1b8f54964894f --- /dev/null +++ b/test/distributed/cases/udf_python/arrow_compute_strings.sql @@ -0,0 +1,32 @@ +-- Arrow UTF-8 compute kernels with empty, Unicode, and NULL values. +drop database if exists udf_python_arrow_compute_strings_bvt; +create database udf_python_arrow_compute_strings_bvt; +use udf_python_arrow_compute_strings_bvt; + +create function python_bvt_pc_upper (x varchar(64)) returns varchar(64) language python as 'python_bvt_pc_upper = lambda ctx, values: __import__("pyarrow.compute", fromlist=["utf8_upper"]).utf8_upper(values)' handler 'python_bvt_pc_upper' mode vector; +create function python_bvt_pc_contains (x varchar(64)) returns bool language python as 'python_bvt_pc_contains = lambda ctx, values: __import__("pyarrow.compute", fromlist=["match_substring"]).match_substring(values, "a")' handler 'python_bvt_pc_contains' mode vector; +create function python_bvt_pc_replace (x varchar(64)) returns varchar(64) language python as 'python_bvt_pc_replace = lambda ctx, values: __import__("pyarrow.compute", fromlist=["replace_substring"]).replace_substring(values, "a", "X")' handler 'python_bvt_pc_replace' mode vector; +create function python_bvt_pc_length (x varchar(64)) returns int language python as 'python_bvt_pc_length = lambda ctx, values: __import__("pyarrow.compute", fromlist=["utf8_length"]).utf8_length(values)' handler 'python_bvt_pc_length' mode vector; + +create table string_values (id int, value varchar(64)); +insert into string_values values + (1, ''), + (2, 'Alpha'), + (3, '中a😀'), + (4, null); + +-- The kernels must preserve empty strings and NULL validity. utf8_length +-- counts Unicode code points, so the final non-NULL value has length three. +select id, + python_bvt_pc_upper(value) as upper_value, + python_bvt_pc_contains(value) as contains_a, + python_bvt_pc_replace(value) as replaced_value, + python_bvt_pc_length(value) as codepoint_length +from string_values order by id; + +drop function python_bvt_pc_upper(varchar(64)); +drop function python_bvt_pc_contains(varchar(64)); +drop function python_bvt_pc_replace(varchar(64)); +drop function python_bvt_pc_length(varchar(64)); +drop table string_values; +drop database udf_python_arrow_compute_strings_bvt; From 0642f3c7ddc4067618115d9e56e4dd3a27209a25 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:01:11 +0800 Subject: [PATCH 155/241] test: make Arrow sort null placement explicit --- .../distributed/cases/udf_python/arrow_compute_selection.result | 2 +- test/distributed/cases/udf_python/arrow_compute_selection.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.result b/test/distributed/cases/udf_python/arrow_compute_selection.result index 4c320f4d1e4c2..3fff0e8668889 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.result +++ b/test/distributed/cases/udf_python/arrow_compute_selection.result @@ -2,7 +2,7 @@ drop database if exists udf_python_arrow_compute_selection_bvt; create database udf_python_arrow_compute_selection_bvt; use udf_python_arrow_compute_selection_bvt; create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices)' handler 'python_bvt_pc_take' mode vector; -create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values))' handler 'python_bvt_pc_sort_take' mode vector; +create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end"))' handler 'python_bvt_pc_sort_take' mode vector; create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, 20)' handler 'python_bvt_pc_equal' mode vector; create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64())' handler 'python_bvt_pc_cast' mode vector; create table selection_values (id int, value int, index_value int); diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.sql b/test/distributed/cases/udf_python/arrow_compute_selection.sql index a548dc0275272..d1348d7a67ebd 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.sql +++ b/test/distributed/cases/udf_python/arrow_compute_selection.sql @@ -4,7 +4,7 @@ create database udf_python_arrow_compute_selection_bvt; use udf_python_arrow_compute_selection_bvt; create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices)' handler 'python_bvt_pc_take' mode vector; -create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values))' handler 'python_bvt_pc_sort_take' mode vector; +create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end"))' handler 'python_bvt_pc_sort_take' mode vector; create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, 20)' handler 'python_bvt_pc_equal' mode vector; create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64())' handler 'python_bvt_pc_cast' mode vector; From e76e4f49fdd064e75abd4151fbbbcba8f0da51d7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:02:04 +0800 Subject: [PATCH 156/241] test: cover null Arrow take indices --- .../cases/udf_python/arrow_compute_selection.result | 6 ++++-- .../cases/udf_python/arrow_compute_selection.sql | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.result b/test/distributed/cases/udf_python/arrow_compute_selection.result index 3fff0e8668889..2bc3a00a5c475 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.result +++ b/test/distributed/cases/udf_python/arrow_compute_selection.result @@ -10,7 +10,8 @@ insert into selection_values values (1, 30, 2), (2, null, 0), (3, 20, 1), -(4, 10, 3); +(4, 10, 3), +(5, 40, null); select id, python_bvt_pc_take(value, index_value) as taken, python_bvt_pc_sort_take(value) as sorted_value, @@ -21,7 +22,8 @@ from selection_values order by id; 1 ¦ 20 ¦ 10 ¦ 0 ¦ 30 𝄀 2 ¦ 30 ¦ 20 ¦ null ¦ null 𝄀 3 ¦ null ¦ 30 ¦ 1 ¦ 20 𝄀 -4 ¦ 10 ¦ null ¦ 0 ¦ 10 +4 ¦ 10 ¦ 40 ¦ 0 ¦ 10 𝄀 +5 ¦ null ¦ null ¦ 0 ¦ 40 drop function python_bvt_pc_take(int, int); drop function python_bvt_pc_sort_take(int); drop function python_bvt_pc_equal(int); diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.sql b/test/distributed/cases/udf_python/arrow_compute_selection.sql index d1348d7a67ebd..350ee35af2917 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.sql +++ b/test/distributed/cases/udf_python/arrow_compute_selection.sql @@ -13,7 +13,8 @@ insert into selection_values values (1, 30, 2), (2, null, 0), (3, 20, 1), - (4, 10, 3); + (4, 10, 3), + (5, 40, null); -- take uses an Arrow index array, sort_indices keeps NULL placement explicit, -- and cast proves that the physical Arrow type can change within the declared From 032a27e10510a3007a3b0fb2df8223cf01f9d328 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:04:23 +0800 Subject: [PATCH 157/241] test: make Arrow arithmetic scalar type explicit --- .../cases/udf_python/arrow_compute_arithmetic.result | 4 ++-- .../distributed/cases/udf_python/arrow_compute_arithmetic.sql | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/distributed/cases/udf_python/arrow_compute_arithmetic.result b/test/distributed/cases/udf_python/arrow_compute_arithmetic.result index 14900615bc75c..7ea3ab8da1444 100644 --- a/test/distributed/cases/udf_python/arrow_compute_arithmetic.result +++ b/test/distributed/cases/udf_python/arrow_compute_arithmetic.result @@ -1,7 +1,7 @@ drop database if exists udf_python_arrow_compute_arithmetic_bvt; create database udf_python_arrow_compute_arithmetic_bvt; use udf_python_arrow_compute_arithmetic_bvt; -create function python_bvt_pc_add (x int) returns bigint language python as 'python_bvt_pc_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, 10)' handler 'python_bvt_pc_add' mode vector; +create function python_bvt_pc_add (x int) returns int language python as 'python_bvt_pc_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, __import__("pyarrow").scalar(10, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_add' mode vector; create function python_bvt_pc_multiply (x int, y int) returns int language python as 'python_bvt_pc_multiply = lambda ctx, left, right: __import__("pyarrow.compute", fromlist=["multiply"]).multiply(left, right)' handler 'python_bvt_pc_multiply' mode vector; create function python_bvt_pc_if_else (flag bool, x int, y int) returns int language python as 'python_bvt_pc_if_else = lambda ctx, flag, left, right: __import__("pyarrow.compute", fromlist=["if_else"]).if_else(flag, left, right)' handler 'python_bvt_pc_if_else' mode vector; create function python_bvt_pc_fill_null (x int) returns int language python as 'python_bvt_pc_fill_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["fill_null"]).fill_null(values, -7)' handler 'python_bvt_pc_fill_null' mode vector; @@ -19,7 +19,7 @@ python_bvt_pc_if_else(flag, left_value, right_value) as selected, python_bvt_pc_fill_null(left_value) as filled, python_bvt_pc_is_null(left_value) as is_null from arithmetic_values order by id; -➤ id[4,32,0] ¦ added[-5,64,0] ¦ multiplied[4,32,0] ¦ selected[4,32,0] ¦ filled[4,32,0] ¦ is_null[-7,1,0] 𝄀 +➤ id[4,32,0] ¦ added[4,32,0] ¦ multiplied[4,32,0] ¦ selected[4,32,0] ¦ filled[4,32,0] ¦ is_null[-7,1,0] 𝄀 1 ¦ 11 ¦ 10 ¦ 1 ¦ 1 ¦ 0 𝄀 2 ¦ null ¦ null ¦ 20 ¦ -7 ¦ 1 𝄀 3 ¦ 13 ¦ null ¦ null ¦ 3 ¦ 0 𝄀 diff --git a/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql b/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql index cfea5b0c1a3e7..e5134d2bc41e8 100644 --- a/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql +++ b/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql @@ -3,7 +3,7 @@ drop database if exists udf_python_arrow_compute_arithmetic_bvt; create database udf_python_arrow_compute_arithmetic_bvt; use udf_python_arrow_compute_arithmetic_bvt; -create function python_bvt_pc_add (x int) returns bigint language python as 'python_bvt_pc_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, 10)' handler 'python_bvt_pc_add' mode vector; +create function python_bvt_pc_add (x int) returns int language python as 'python_bvt_pc_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, __import__("pyarrow").scalar(10, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_add' mode vector; create function python_bvt_pc_multiply (x int, y int) returns int language python as 'python_bvt_pc_multiply = lambda ctx, left, right: __import__("pyarrow.compute", fromlist=["multiply"]).multiply(left, right)' handler 'python_bvt_pc_multiply' mode vector; create function python_bvt_pc_if_else (flag bool, x int, y int) returns int language python as 'python_bvt_pc_if_else = lambda ctx, flag, left, right: __import__("pyarrow.compute", fromlist=["if_else"]).if_else(flag, left, right)' handler 'python_bvt_pc_if_else' mode vector; create function python_bvt_pc_fill_null (x int) returns int language python as 'python_bvt_pc_fill_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["fill_null"]).fill_null(values, -7)' handler 'python_bvt_pc_fill_null' mode vector; From d0aacfbc0316e67ca2260c145c583217811da885 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:05:18 +0800 Subject: [PATCH 158/241] test: make Arrow string options explicit --- .../distributed/cases/udf_python/arrow_compute_strings.result | 4 ++-- test/distributed/cases/udf_python/arrow_compute_strings.sql | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/distributed/cases/udf_python/arrow_compute_strings.result b/test/distributed/cases/udf_python/arrow_compute_strings.result index 1e757796a0e5b..41d40829f5eb1 100644 --- a/test/distributed/cases/udf_python/arrow_compute_strings.result +++ b/test/distributed/cases/udf_python/arrow_compute_strings.result @@ -2,8 +2,8 @@ drop database if exists udf_python_arrow_compute_strings_bvt; create database udf_python_arrow_compute_strings_bvt; use udf_python_arrow_compute_strings_bvt; create function python_bvt_pc_upper (x varchar(64)) returns varchar(64) language python as 'python_bvt_pc_upper = lambda ctx, values: __import__("pyarrow.compute", fromlist=["utf8_upper"]).utf8_upper(values)' handler 'python_bvt_pc_upper' mode vector; -create function python_bvt_pc_contains (x varchar(64)) returns bool language python as 'python_bvt_pc_contains = lambda ctx, values: __import__("pyarrow.compute", fromlist=["match_substring"]).match_substring(values, "a")' handler 'python_bvt_pc_contains' mode vector; -create function python_bvt_pc_replace (x varchar(64)) returns varchar(64) language python as 'python_bvt_pc_replace = lambda ctx, values: __import__("pyarrow.compute", fromlist=["replace_substring"]).replace_substring(values, "a", "X")' handler 'python_bvt_pc_replace' mode vector; +create function python_bvt_pc_contains (x varchar(64)) returns bool language python as 'python_bvt_pc_contains = lambda ctx, values: __import__("pyarrow.compute", fromlist=["match_substring"]).match_substring(values, "a", ignore_case=False)' handler 'python_bvt_pc_contains' mode vector; +create function python_bvt_pc_replace (x varchar(64)) returns varchar(64) language python as 'python_bvt_pc_replace = lambda ctx, values: __import__("pyarrow.compute", fromlist=["replace_substring"]).replace_substring(values, "a", "X", max_replacements=-1)' handler 'python_bvt_pc_replace' mode vector; create function python_bvt_pc_length (x varchar(64)) returns int language python as 'python_bvt_pc_length = lambda ctx, values: __import__("pyarrow.compute", fromlist=["utf8_length"]).utf8_length(values)' handler 'python_bvt_pc_length' mode vector; create table string_values (id int, value varchar(64)); insert into string_values values diff --git a/test/distributed/cases/udf_python/arrow_compute_strings.sql b/test/distributed/cases/udf_python/arrow_compute_strings.sql index 1b8f54964894f..0d9ad9c0a5284 100644 --- a/test/distributed/cases/udf_python/arrow_compute_strings.sql +++ b/test/distributed/cases/udf_python/arrow_compute_strings.sql @@ -4,8 +4,8 @@ create database udf_python_arrow_compute_strings_bvt; use udf_python_arrow_compute_strings_bvt; create function python_bvt_pc_upper (x varchar(64)) returns varchar(64) language python as 'python_bvt_pc_upper = lambda ctx, values: __import__("pyarrow.compute", fromlist=["utf8_upper"]).utf8_upper(values)' handler 'python_bvt_pc_upper' mode vector; -create function python_bvt_pc_contains (x varchar(64)) returns bool language python as 'python_bvt_pc_contains = lambda ctx, values: __import__("pyarrow.compute", fromlist=["match_substring"]).match_substring(values, "a")' handler 'python_bvt_pc_contains' mode vector; -create function python_bvt_pc_replace (x varchar(64)) returns varchar(64) language python as 'python_bvt_pc_replace = lambda ctx, values: __import__("pyarrow.compute", fromlist=["replace_substring"]).replace_substring(values, "a", "X")' handler 'python_bvt_pc_replace' mode vector; +create function python_bvt_pc_contains (x varchar(64)) returns bool language python as 'python_bvt_pc_contains = lambda ctx, values: __import__("pyarrow.compute", fromlist=["match_substring"]).match_substring(values, "a", ignore_case=False)' handler 'python_bvt_pc_contains' mode vector; +create function python_bvt_pc_replace (x varchar(64)) returns varchar(64) language python as 'python_bvt_pc_replace = lambda ctx, values: __import__("pyarrow.compute", fromlist=["replace_substring"]).replace_substring(values, "a", "X", max_replacements=-1)' handler 'python_bvt_pc_replace' mode vector; create function python_bvt_pc_length (x varchar(64)) returns int language python as 'python_bvt_pc_length = lambda ctx, values: __import__("pyarrow.compute", fromlist=["utf8_length"]).utf8_length(values)' handler 'python_bvt_pc_length' mode vector; create table string_values (id int, value varchar(64)); From fc004c2112fcb9134559f8cf840a9df581a94317 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:06:07 +0800 Subject: [PATCH 159/241] test: make Arrow selection safety explicit --- .../cases/udf_python/arrow_compute_selection.result | 4 ++-- test/distributed/cases/udf_python/arrow_compute_selection.sql | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.result b/test/distributed/cases/udf_python/arrow_compute_selection.result index 2bc3a00a5c475..db81049257e13 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.result +++ b/test/distributed/cases/udf_python/arrow_compute_selection.result @@ -1,10 +1,10 @@ drop database if exists udf_python_arrow_compute_selection_bvt; create database udf_python_arrow_compute_selection_bvt; use udf_python_arrow_compute_selection_bvt; -create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices)' handler 'python_bvt_pc_take' mode vector; +create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices, boundscheck=True)' handler 'python_bvt_pc_take' mode vector; create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end"))' handler 'python_bvt_pc_sort_take' mode vector; create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, 20)' handler 'python_bvt_pc_equal' mode vector; -create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64())' handler 'python_bvt_pc_cast' mode vector; +create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64(), safe=True)' handler 'python_bvt_pc_cast' mode vector; create table selection_values (id int, value int, index_value int); insert into selection_values values (1, 30, 2), diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.sql b/test/distributed/cases/udf_python/arrow_compute_selection.sql index 350ee35af2917..8671c6cadd10b 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.sql +++ b/test/distributed/cases/udf_python/arrow_compute_selection.sql @@ -3,10 +3,10 @@ drop database if exists udf_python_arrow_compute_selection_bvt; create database udf_python_arrow_compute_selection_bvt; use udf_python_arrow_compute_selection_bvt; -create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices)' handler 'python_bvt_pc_take' mode vector; +create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices, boundscheck=True)' handler 'python_bvt_pc_take' mode vector; create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end"))' handler 'python_bvt_pc_sort_take' mode vector; create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, 20)' handler 'python_bvt_pc_equal' mode vector; -create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64())' handler 'python_bvt_pc_cast' mode vector; +create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64(), safe=True)' handler 'python_bvt_pc_cast' mode vector; create table selection_values (id int, value int, index_value int); insert into selection_values values From 89f2c97ce18d1ac258108939348ea5b8d8eaed55 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:07:21 +0800 Subject: [PATCH 160/241] test: cover Arrow vector cardinality rejection --- .../cases/udf_python/arrow_compute_selection.result | 4 ++++ .../cases/udf_python/arrow_compute_selection.sql | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.result b/test/distributed/cases/udf_python/arrow_compute_selection.result index db81049257e13..957f0633c16cb 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.result +++ b/test/distributed/cases/udf_python/arrow_compute_selection.result @@ -5,6 +5,7 @@ create function python_bvt_pc_take (x int, index_value int) returns int language create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end"))' handler 'python_bvt_pc_sort_take' mode vector; create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, 20)' handler 'python_bvt_pc_equal' mode vector; create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64(), safe=True)' handler 'python_bvt_pc_cast' mode vector; +create function python_bvt_pc_filter (x int) returns int language python as 'python_bvt_pc_filter = lambda ctx, values: __import__("pyarrow.compute", fromlist=["filter"]).filter(values, __import__("pyarrow.compute", fromlist=["greater_equal"]).greater_equal(values, 20), null_selection_behavior="drop")' handler 'python_bvt_pc_filter' mode vector; create table selection_values (id int, value int, index_value int); insert into selection_values values (1, 30, 2), @@ -24,9 +25,12 @@ from selection_values order by id; 3 ¦ null ¦ 30 ¦ 1 ¦ 20 𝄀 4 ¦ 10 ¦ 40 ¦ 0 ¦ 10 𝄀 5 ¦ null ¦ null ¦ 0 ¦ 40 +select python_bvt_pc_filter(value) from selection_values order by id; +python udf: worker error: TYPE_CONTRACT: result length does not match input rows drop function python_bvt_pc_take(int, int); drop function python_bvt_pc_sort_take(int); drop function python_bvt_pc_equal(int); drop function python_bvt_pc_cast(int); +drop function python_bvt_pc_filter(int); drop table selection_values; drop database udf_python_arrow_compute_selection_bvt; diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.sql b/test/distributed/cases/udf_python/arrow_compute_selection.sql index 8671c6cadd10b..9ec43226facf1 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.sql +++ b/test/distributed/cases/udf_python/arrow_compute_selection.sql @@ -7,6 +7,7 @@ create function python_bvt_pc_take (x int, index_value int) returns int language create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end"))' handler 'python_bvt_pc_sort_take' mode vector; create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, 20)' handler 'python_bvt_pc_equal' mode vector; create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64(), safe=True)' handler 'python_bvt_pc_cast' mode vector; +create function python_bvt_pc_filter (x int) returns int language python as 'python_bvt_pc_filter = lambda ctx, values: __import__("pyarrow.compute", fromlist=["filter"]).filter(values, __import__("pyarrow.compute", fromlist=["greater_equal"]).greater_equal(values, 20), null_selection_behavior="drop")' handler 'python_bvt_pc_filter' mode vector; create table selection_values (id int, value int, index_value int); insert into selection_values values @@ -26,9 +27,15 @@ select id, python_bvt_pc_cast(value) as cast_value from selection_values order by id; +-- A filtering kernel shortens the Arrow array. The external evaluator must +-- reject the result instead of silently misaligning rows. +--error +select python_bvt_pc_filter(value) from selection_values order by id; + drop function python_bvt_pc_take(int, int); drop function python_bvt_pc_sort_take(int); drop function python_bvt_pc_equal(int); drop function python_bvt_pc_cast(int); +drop function python_bvt_pc_filter(int); drop table selection_values; drop database udf_python_arrow_compute_selection_bvt; From c3e22ca2f2b4831c6ca577d5492a022045081bb7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:08:30 +0800 Subject: [PATCH 161/241] test: distinguish Arrow string option semantics --- .../cases/udf_python/arrow_compute_strings.result | 8 ++++++-- .../cases/udf_python/arrow_compute_strings.sql | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/test/distributed/cases/udf_python/arrow_compute_strings.result b/test/distributed/cases/udf_python/arrow_compute_strings.result index 41d40829f5eb1..0e094d9bbad58 100644 --- a/test/distributed/cases/udf_python/arrow_compute_strings.result +++ b/test/distributed/cases/udf_python/arrow_compute_strings.result @@ -10,7 +10,9 @@ insert into string_values values (1, ''), (2, 'Alpha'), (3, '中a😀'), -(4, null); +(4, 'banana'), +(5, 'A'), +(6, null); select id, python_bvt_pc_upper(value) as upper_value, python_bvt_pc_contains(value) as contains_a, @@ -21,7 +23,9 @@ from string_values order by id; 1 ¦ ¦ 0 ¦ ¦ 0 𝄀 2 ¦ ALPHA ¦ 1 ¦ AlphX ¦ 5 𝄀 3 ¦ 中A😀 ¦ 1 ¦ 中X😀 ¦ 3 𝄀 -4 ¦ null ¦ null ¦ null ¦ null +4 ¦ BANANA ¦ 1 ¦ bXnXnX ¦ 6 𝄀 +5 ¦ A ¦ 0 ¦ A ¦ 1 𝄀 +6 ¦ null ¦ null ¦ null ¦ null drop function python_bvt_pc_upper(varchar(64)); drop function python_bvt_pc_contains(varchar(64)); drop function python_bvt_pc_replace(varchar(64)); diff --git a/test/distributed/cases/udf_python/arrow_compute_strings.sql b/test/distributed/cases/udf_python/arrow_compute_strings.sql index 0d9ad9c0a5284..eb5c01dd20040 100644 --- a/test/distributed/cases/udf_python/arrow_compute_strings.sql +++ b/test/distributed/cases/udf_python/arrow_compute_strings.sql @@ -13,10 +13,14 @@ insert into string_values values (1, ''), (2, 'Alpha'), (3, '中a😀'), - (4, null); + (4, 'banana'), + (5, 'A'), + (6, null); -- The kernels must preserve empty strings and NULL validity. utf8_length --- counts Unicode code points, so the final non-NULL value has length three. +-- counts Unicode code points, so the Unicode value has length three. The +-- repeated and uppercase samples distinguish all-replacement behavior from +-- a single replacement and case-sensitive matching from case folding. select id, python_bvt_pc_upper(value) as upper_value, python_bvt_pc_contains(value) as contains_a, From 0cf13de2b82b3648dde78c8f93a4544aed4080c7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:09:52 +0800 Subject: [PATCH 162/241] test: bind Arrow scalar arguments to SQL types --- .../cases/udf_python/arrow_compute_arithmetic.result | 2 +- test/distributed/cases/udf_python/arrow_compute_arithmetic.sql | 2 +- .../distributed/cases/udf_python/arrow_compute_selection.result | 2 +- test/distributed/cases/udf_python/arrow_compute_selection.sql | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/distributed/cases/udf_python/arrow_compute_arithmetic.result b/test/distributed/cases/udf_python/arrow_compute_arithmetic.result index 7ea3ab8da1444..578de28fd8075 100644 --- a/test/distributed/cases/udf_python/arrow_compute_arithmetic.result +++ b/test/distributed/cases/udf_python/arrow_compute_arithmetic.result @@ -4,7 +4,7 @@ use udf_python_arrow_compute_arithmetic_bvt; create function python_bvt_pc_add (x int) returns int language python as 'python_bvt_pc_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, __import__("pyarrow").scalar(10, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_add' mode vector; create function python_bvt_pc_multiply (x int, y int) returns int language python as 'python_bvt_pc_multiply = lambda ctx, left, right: __import__("pyarrow.compute", fromlist=["multiply"]).multiply(left, right)' handler 'python_bvt_pc_multiply' mode vector; create function python_bvt_pc_if_else (flag bool, x int, y int) returns int language python as 'python_bvt_pc_if_else = lambda ctx, flag, left, right: __import__("pyarrow.compute", fromlist=["if_else"]).if_else(flag, left, right)' handler 'python_bvt_pc_if_else' mode vector; -create function python_bvt_pc_fill_null (x int) returns int language python as 'python_bvt_pc_fill_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["fill_null"]).fill_null(values, -7)' handler 'python_bvt_pc_fill_null' mode vector; +create function python_bvt_pc_fill_null (x int) returns int language python as 'python_bvt_pc_fill_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["fill_null"]).fill_null(values, __import__("pyarrow").scalar(-7, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_fill_null' mode vector; create function python_bvt_pc_is_null (x int) returns bool language python as 'python_bvt_pc_is_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["is_null"]).is_null(values)' handler 'python_bvt_pc_is_null' mode vector; create table arithmetic_values (id int, flag bool, left_value int, right_value int); insert into arithmetic_values values diff --git a/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql b/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql index e5134d2bc41e8..f1fbc290852ae 100644 --- a/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql +++ b/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql @@ -6,7 +6,7 @@ use udf_python_arrow_compute_arithmetic_bvt; create function python_bvt_pc_add (x int) returns int language python as 'python_bvt_pc_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, __import__("pyarrow").scalar(10, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_add' mode vector; create function python_bvt_pc_multiply (x int, y int) returns int language python as 'python_bvt_pc_multiply = lambda ctx, left, right: __import__("pyarrow.compute", fromlist=["multiply"]).multiply(left, right)' handler 'python_bvt_pc_multiply' mode vector; create function python_bvt_pc_if_else (flag bool, x int, y int) returns int language python as 'python_bvt_pc_if_else = lambda ctx, flag, left, right: __import__("pyarrow.compute", fromlist=["if_else"]).if_else(flag, left, right)' handler 'python_bvt_pc_if_else' mode vector; -create function python_bvt_pc_fill_null (x int) returns int language python as 'python_bvt_pc_fill_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["fill_null"]).fill_null(values, -7)' handler 'python_bvt_pc_fill_null' mode vector; +create function python_bvt_pc_fill_null (x int) returns int language python as 'python_bvt_pc_fill_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["fill_null"]).fill_null(values, __import__("pyarrow").scalar(-7, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_fill_null' mode vector; create function python_bvt_pc_is_null (x int) returns bool language python as 'python_bvt_pc_is_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["is_null"]).is_null(values)' handler 'python_bvt_pc_is_null' mode vector; create table arithmetic_values (id int, flag bool, left_value int, right_value int); diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.result b/test/distributed/cases/udf_python/arrow_compute_selection.result index 957f0633c16cb..d522ea6b4e069 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.result +++ b/test/distributed/cases/udf_python/arrow_compute_selection.result @@ -3,7 +3,7 @@ create database udf_python_arrow_compute_selection_bvt; use udf_python_arrow_compute_selection_bvt; create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices, boundscheck=True)' handler 'python_bvt_pc_take' mode vector; create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end"))' handler 'python_bvt_pc_sort_take' mode vector; -create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, 20)' handler 'python_bvt_pc_equal' mode vector; +create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, __import__("pyarrow").scalar(20, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_equal' mode vector; create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64(), safe=True)' handler 'python_bvt_pc_cast' mode vector; create function python_bvt_pc_filter (x int) returns int language python as 'python_bvt_pc_filter = lambda ctx, values: __import__("pyarrow.compute", fromlist=["filter"]).filter(values, __import__("pyarrow.compute", fromlist=["greater_equal"]).greater_equal(values, 20), null_selection_behavior="drop")' handler 'python_bvt_pc_filter' mode vector; create table selection_values (id int, value int, index_value int); diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.sql b/test/distributed/cases/udf_python/arrow_compute_selection.sql index 9ec43226facf1..3a90980dac758 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.sql +++ b/test/distributed/cases/udf_python/arrow_compute_selection.sql @@ -5,7 +5,7 @@ use udf_python_arrow_compute_selection_bvt; create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices, boundscheck=True)' handler 'python_bvt_pc_take' mode vector; create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end"))' handler 'python_bvt_pc_sort_take' mode vector; -create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, 20)' handler 'python_bvt_pc_equal' mode vector; +create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, __import__("pyarrow").scalar(20, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_equal' mode vector; create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64(), safe=True)' handler 'python_bvt_pc_cast' mode vector; create function python_bvt_pc_filter (x int) returns int language python as 'python_bvt_pc_filter = lambda ctx, values: __import__("pyarrow.compute", fromlist=["filter"]).filter(values, __import__("pyarrow.compute", fromlist=["greater_equal"]).greater_equal(values, 20), null_selection_behavior="drop")' handler 'python_bvt_pc_filter' mode vector; From 934fa75a9e61ae64b27c0b10274896b4d77f4b27 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:10:23 +0800 Subject: [PATCH 163/241] docs: describe Arrow cardinality coverage --- test/distributed/cases/udf_python/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/distributed/cases/udf_python/README.md b/test/distributed/cases/udf_python/README.md index 8b698862c6ef6..5bf9621efe91c 100644 --- a/test/distributed/cases/udf_python/README.md +++ b/test/distributed/cases/udf_python/README.md @@ -55,9 +55,11 @@ The cases keep the data sets small and target contract boundaries: conditional, fill-null, and validity kernels while preserving NULLs and batch length. - `arrow_compute_selection.sql` checks Arrow take, sort-indices, comparison, - and physical cast kernels with indexed and NULL input. -- `arrow_compute_strings.sql` checks UTF-8 uppercasing, substring matching, - replacement, and code-point length for empty, Unicode, and NULL values. + physical cast kernels with indexed and NULL input, and rejects a shortened + vector result. +- `arrow_compute_strings.sql` checks UTF-8 uppercasing, case-sensitive + substring matching, repeated replacement, and code-point length for empty, + Unicode, and NULL values. The shape follows established correctness coverage from [DuckDB's scalar UDF tests](https://github.com/duckdb/duckdb-go/blob/main/scalar_udf_test.go) From c20690f5da514790e8d34a0fd158777580975f40 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:19:00 +0800 Subject: [PATCH 164/241] test: clean up BVT service processes --- optools/run_bvt.sh | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index ed1d3f19f8cf5..2782e6200855b 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -22,6 +22,30 @@ PROXY=${3:-} LAUNCH_CONFIG=$LAUNCH MO_PID="" +function cleanup_mo() { + if [[ -z "$MO_PID" ]]; then + return + fi + if kill -0 "$MO_PID" 2>/dev/null; then + kill -TERM "$MO_PID" 2>/dev/null || true + for _ in {1..30}; do + if ! kill -0 "$MO_PID" 2>/dev/null; then + break + fi + sleep 1 + done + if kill -0 "$MO_PID" 2>/dev/null; then + kill -KILL "$MO_PID" 2>/dev/null || true + fi + fi + wait "$MO_PID" 2>/dev/null || true + MO_PID="" +} + +trap cleanup_mo EXIT +trap 'exit 130' INT +trap 'exit 143' TERM + function launch_mo() { cd $MO_WORKSPACE # Ordinary launch BVT remains the single CI entry point, but its Python @@ -39,7 +63,7 @@ function launch_mo() { function wait_system_init() { for num in {1..300} do - if MYSQL_PWD=111 mysql -h 127.0.0.1 -P 6001 -u dump -e "show databases;"; then + if MYSQL_PWD=111 mysql --connect-timeout=2 -h 127.0.0.1 -P 6001 -u dump -e "show databases;"; then echo "ok, cost $num seconds" return 0 fi From 5b298ae6e4e395f684e7cf594b3df1793529353a Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:22:41 +0800 Subject: [PATCH 165/241] test: reap BVT child services --- optools/run_bvt.sh | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index 2782e6200855b..b87daab0088eb 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -21,11 +21,24 @@ LAUNCH=$2 PROXY=${3:-} LAUNCH_CONFIG=$LAUNCH MO_PID="" +JSTFU_PID="" + +function collect_descendants() { + local parent="$1" + local child + for child in $(pgrep -P "$parent" 2>/dev/null || true); do + BVT_CHILD_PIDS+=("$child") + collect_descendants "$child" + done +} function cleanup_mo() { if [[ -z "$MO_PID" ]]; then return fi + local pid="$MO_PID" + local -a BVT_CHILD_PIDS=() + collect_descendants "$pid" if kill -0 "$MO_PID" 2>/dev/null; then kill -TERM "$MO_PID" 2>/dev/null || true for _ in {1..30}; do @@ -38,11 +51,39 @@ function cleanup_mo() { kill -KILL "$MO_PID" 2>/dev/null || true fi fi - wait "$MO_PID" 2>/dev/null || true + for child in "${BVT_CHILD_PIDS[@]}"; do + kill -KILL "$child" 2>/dev/null || true + done + wait "$pid" 2>/dev/null || true MO_PID="" } -trap cleanup_mo EXIT +function cleanup_jstfu() { + if [[ -z "$JSTFU_PID" ]]; then + return + fi + if kill -0 "$JSTFU_PID" 2>/dev/null; then + kill -TERM "$JSTFU_PID" 2>/dev/null || true + for _ in {1..15}; do + if ! kill -0 "$JSTFU_PID" 2>/dev/null; then + break + fi + sleep 1 + done + if kill -0 "$JSTFU_PID" 2>/dev/null; then + kill -KILL "$JSTFU_PID" 2>/dev/null || true + fi + fi + wait "$JSTFU_PID" 2>/dev/null || true + JSTFU_PID="" +} + +function cleanup_all() { + cleanup_jstfu + cleanup_mo +} + +trap cleanup_all EXIT trap 'exit 130' INT trap 'exit 143' TERM @@ -119,6 +160,7 @@ function launch_jstfu() { } fi nohup ./optools/jstfu_bvt.sh "$MO_WORKSPACE/test/distributed/resources" 127.0.0.1:6001 &>jstfu.log & + JSTFU_PID=$! for _ in {1..30}; do if bash -c 'exec 3<>/dev/tcp/127.0.0.1/4444' 2>/dev/null; then echo "jstfu ready on :4444" From a4d81c1627a941a891584ddb63375e64d333beeb Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:24:24 +0800 Subject: [PATCH 166/241] test: wait for Python UDF capability handshake --- optools/run_bvt.sh | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index b87daab0088eb..15a06ad901d10 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -128,13 +128,40 @@ function wait_python_udf_worker() { tail -n 160 mo-service.log >&2 || true return 1 fi - if bash -c 'exec 3<>/dev/tcp/127.0.0.1/50051' 2>/dev/null; then - echo "Python UDF worker is ready, cost $num seconds" + if python3 - <<'PY' +import json +import signal + +import pyarrow.flight as flight + + +def _timeout(_signum, _frame): + raise TimeoutError("capability probe timed out") + + +signal.signal(signal.SIGALRM, _timeout) +signal.alarm(2) +try: + client = flight.FlightClient("grpc://127.0.0.1:50051") + reader = client.do_action( + flight.Action("GetPythonCapabilities", b'{"protocol_version":1}') + ) + result = next(iter(reader), None) + if result is None: + raise RuntimeError("empty capability response") + response = json.loads(bytes(result.body)) + if response.get("protocol_version") != 1: + raise RuntimeError("unsupported capability protocol version") +finally: + signal.alarm(0) +PY + then + echo "Python UDF capability handshake is ready, cost $num seconds" return 0 fi sleep 1 done - echo "Python UDF worker did not become ready on 127.0.0.1:50051" >&2 + echo "Python UDF capability handshake did not become ready on 127.0.0.1:50051" >&2 tail -n 160 mo-service.log >&2 || true return 1 } From a19bcc5e480694e76b1ec6e0b96ea22ee6d85099 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:25:22 +0800 Subject: [PATCH 167/241] test: cover Arrow take bounds errors --- .../cases/udf_python/arrow_compute_selection.result | 5 +++++ .../cases/udf_python/arrow_compute_selection.sql | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.result b/test/distributed/cases/udf_python/arrow_compute_selection.result index d522ea6b4e069..98b7cbefa3b36 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.result +++ b/test/distributed/cases/udf_python/arrow_compute_selection.result @@ -27,10 +27,15 @@ from selection_values order by id; 5 ¦ null ¦ null ¦ 0 ¦ 40 select python_bvt_pc_filter(value) from selection_values order by id; python udf: worker error: TYPE_CONTRACT: result length does not match input rows +create table invalid_selection_values (value int, index_value int); +insert into invalid_selection_values values (30, 99); +select python_bvt_pc_take(value, index_value) from invalid_selection_values; +python udf: worker error: USER_CODE: handler or runtime failed drop function python_bvt_pc_take(int, int); drop function python_bvt_pc_sort_take(int); drop function python_bvt_pc_equal(int); drop function python_bvt_pc_cast(int); drop function python_bvt_pc_filter(int); +drop table invalid_selection_values; drop table selection_values; drop database udf_python_arrow_compute_selection_bvt; diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.sql b/test/distributed/cases/udf_python/arrow_compute_selection.sql index 3a90980dac758..1693664b4f53a 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.sql +++ b/test/distributed/cases/udf_python/arrow_compute_selection.sql @@ -32,10 +32,18 @@ from selection_values order by id; --error select python_bvt_pc_filter(value) from selection_values order by id; +create table invalid_selection_values (value int, index_value int); +insert into invalid_selection_values values (30, 99); + +-- boundscheck=True must turn an out-of-range index into a handler error. +--error +select python_bvt_pc_take(value, index_value) from invalid_selection_values; + drop function python_bvt_pc_take(int, int); drop function python_bvt_pc_sort_take(int); drop function python_bvt_pc_equal(int); drop function python_bvt_pc_cast(int); drop function python_bvt_pc_filter(int); +drop table invalid_selection_values; drop table selection_values; drop database udf_python_arrow_compute_selection_bvt; From e1b02969b93c8e97bc4341ba3ca7bf01b8c66424 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:28:34 +0800 Subject: [PATCH 168/241] test: verify Arrow sort index positions --- .../udf_python/arrow_compute_selection.result | 15 +++++++++------ .../cases/udf_python/arrow_compute_selection.sql | 3 +++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.result b/test/distributed/cases/udf_python/arrow_compute_selection.result index 98b7cbefa3b36..52ab101d55735 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.result +++ b/test/distributed/cases/udf_python/arrow_compute_selection.result @@ -3,6 +3,7 @@ create database udf_python_arrow_compute_selection_bvt; use udf_python_arrow_compute_selection_bvt; create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices, boundscheck=True)' handler 'python_bvt_pc_take' mode vector; create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end"))' handler 'python_bvt_pc_sort_take' mode vector; +create function python_bvt_pc_sort_indices (x int) returns bigint unsigned language python as 'python_bvt_pc_sort_indices = lambda ctx, values: __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end")' handler 'python_bvt_pc_sort_indices' mode vector; create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, __import__("pyarrow").scalar(20, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_equal' mode vector; create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64(), safe=True)' handler 'python_bvt_pc_cast' mode vector; create function python_bvt_pc_filter (x int) returns int language python as 'python_bvt_pc_filter = lambda ctx, values: __import__("pyarrow.compute", fromlist=["filter"]).filter(values, __import__("pyarrow.compute", fromlist=["greater_equal"]).greater_equal(values, 20), null_selection_behavior="drop")' handler 'python_bvt_pc_filter' mode vector; @@ -16,15 +17,16 @@ insert into selection_values values select id, python_bvt_pc_take(value, index_value) as taken, python_bvt_pc_sort_take(value) as sorted_value, +python_bvt_pc_sort_indices(value) as sorted_index, python_bvt_pc_equal(value) as equals_twenty, python_bvt_pc_cast(value) as cast_value from selection_values order by id; -➤ id[4,32,0] ¦ taken[4,32,0] ¦ sorted_value[4,32,0] ¦ equals_twenty[-7,1,0] ¦ cast_value[-5,64,0] 𝄀 -1 ¦ 20 ¦ 10 ¦ 0 ¦ 30 𝄀 -2 ¦ 30 ¦ 20 ¦ null ¦ null 𝄀 -3 ¦ null ¦ 30 ¦ 1 ¦ 20 𝄀 -4 ¦ 10 ¦ 40 ¦ 0 ¦ 10 𝄀 -5 ¦ null ¦ null ¦ 0 ¦ 40 +➤ id[4,32,0] ¦ taken[4,32,0] ¦ sorted_value[4,32,0] ¦ sorted_index[-5,64,0] ¦ equals_twenty[-7,1,0] ¦ cast_value[-5,64,0] 𝄀 +1 ¦ 20 ¦ 10 ¦ 3 ¦ 0 ¦ 30 𝄀 +2 ¦ 30 ¦ 20 ¦ 2 ¦ null ¦ null 𝄀 +3 ¦ null ¦ 30 ¦ 0 ¦ 1 ¦ 20 𝄀 +4 ¦ 10 ¦ 40 ¦ 4 ¦ 0 ¦ 10 𝄀 +5 ¦ null ¦ null ¦ 1 ¦ 0 ¦ 40 select python_bvt_pc_filter(value) from selection_values order by id; python udf: worker error: TYPE_CONTRACT: result length does not match input rows create table invalid_selection_values (value int, index_value int); @@ -33,6 +35,7 @@ select python_bvt_pc_take(value, index_value) from invalid_selection_values; python udf: worker error: USER_CODE: handler or runtime failed drop function python_bvt_pc_take(int, int); drop function python_bvt_pc_sort_take(int); +drop function python_bvt_pc_sort_indices(int); drop function python_bvt_pc_equal(int); drop function python_bvt_pc_cast(int); drop function python_bvt_pc_filter(int); diff --git a/test/distributed/cases/udf_python/arrow_compute_selection.sql b/test/distributed/cases/udf_python/arrow_compute_selection.sql index 1693664b4f53a..224caf9f4fe51 100644 --- a/test/distributed/cases/udf_python/arrow_compute_selection.sql +++ b/test/distributed/cases/udf_python/arrow_compute_selection.sql @@ -5,6 +5,7 @@ use udf_python_arrow_compute_selection_bvt; create function python_bvt_pc_take (x int, index_value int) returns int language python as 'python_bvt_pc_take = lambda ctx, values, indices: __import__("pyarrow.compute", fromlist=["take"]).take(values, indices, boundscheck=True)' handler 'python_bvt_pc_take' mode vector; create function python_bvt_pc_sort_take (x int) returns int language python as 'python_bvt_pc_sort_take = lambda ctx, values: __import__("pyarrow.compute", fromlist=["take"]).take(values, __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end"))' handler 'python_bvt_pc_sort_take' mode vector; +create function python_bvt_pc_sort_indices (x int) returns bigint unsigned language python as 'python_bvt_pc_sort_indices = lambda ctx, values: __import__("pyarrow.compute", fromlist=["sort_indices"]).sort_indices(values, null_placement="at_end")' handler 'python_bvt_pc_sort_indices' mode vector; create function python_bvt_pc_equal (x int) returns bool language python as 'python_bvt_pc_equal = lambda ctx, values: __import__("pyarrow.compute", fromlist=["equal"]).equal(values, __import__("pyarrow").scalar(20, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_equal' mode vector; create function python_bvt_pc_cast (x int) returns bigint language python as 'python_bvt_pc_cast = lambda ctx, values: __import__("pyarrow.compute", fromlist=["cast"]).cast(values, __import__("pyarrow").int64(), safe=True)' handler 'python_bvt_pc_cast' mode vector; create function python_bvt_pc_filter (x int) returns int language python as 'python_bvt_pc_filter = lambda ctx, values: __import__("pyarrow.compute", fromlist=["filter"]).filter(values, __import__("pyarrow.compute", fromlist=["greater_equal"]).greater_equal(values, 20), null_selection_behavior="drop")' handler 'python_bvt_pc_filter' mode vector; @@ -23,6 +24,7 @@ insert into selection_values values select id, python_bvt_pc_take(value, index_value) as taken, python_bvt_pc_sort_take(value) as sorted_value, + python_bvt_pc_sort_indices(value) as sorted_index, python_bvt_pc_equal(value) as equals_twenty, python_bvt_pc_cast(value) as cast_value from selection_values order by id; @@ -41,6 +43,7 @@ select python_bvt_pc_take(value, index_value) from invalid_selection_values; drop function python_bvt_pc_take(int, int); drop function python_bvt_pc_sort_take(int); +drop function python_bvt_pc_sort_indices(int); drop function python_bvt_pc_equal(int); drop function python_bvt_pc_cast(int); drop function python_bvt_pc_filter(int); From 32d8d410774a37906169668dfd93924316123673 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:29:42 +0800 Subject: [PATCH 169/241] test: cover Arrow float arithmetic --- .../udf_python/arrow_compute_arithmetic.result | 18 ++++++++++++++++++ .../udf_python/arrow_compute_arithmetic.sql | 16 ++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/test/distributed/cases/udf_python/arrow_compute_arithmetic.result b/test/distributed/cases/udf_python/arrow_compute_arithmetic.result index 578de28fd8075..69ee2d94e0b96 100644 --- a/test/distributed/cases/udf_python/arrow_compute_arithmetic.result +++ b/test/distributed/cases/udf_python/arrow_compute_arithmetic.result @@ -6,6 +6,8 @@ create function python_bvt_pc_multiply (x int, y int) returns int language pytho create function python_bvt_pc_if_else (flag bool, x int, y int) returns int language python as 'python_bvt_pc_if_else = lambda ctx, flag, left, right: __import__("pyarrow.compute", fromlist=["if_else"]).if_else(flag, left, right)' handler 'python_bvt_pc_if_else' mode vector; create function python_bvt_pc_fill_null (x int) returns int language python as 'python_bvt_pc_fill_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["fill_null"]).fill_null(values, __import__("pyarrow").scalar(-7, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_fill_null' mode vector; create function python_bvt_pc_is_null (x int) returns bool language python as 'python_bvt_pc_is_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["is_null"]).is_null(values)' handler 'python_bvt_pc_is_null' mode vector; +create function python_bvt_pc_float_add (x float) returns float language python as 'python_bvt_pc_float_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, __import__("pyarrow").scalar(0.5, type=__import__("pyarrow").float32()))' handler 'python_bvt_pc_float_add' mode vector; +create function python_bvt_pc_double_add (x double) returns double language python as 'python_bvt_pc_double_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, __import__("pyarrow").scalar(0.5, type=__import__("pyarrow").float64()))' handler 'python_bvt_pc_double_add' mode vector; create table arithmetic_values (id int, flag bool, left_value int, right_value int); insert into arithmetic_values values (1, true, 1, 10), @@ -24,10 +26,26 @@ from arithmetic_values order by id; 2 ¦ null ¦ null ¦ 20 ¦ -7 ¦ 1 𝄀 3 ¦ 13 ¦ null ¦ null ¦ 3 ¦ 0 𝄀 4 ¦ null ¦ null ¦ null ¦ -7 ¦ 1 +create table float_values (id int, float_value float, double_value double); +insert into float_values values +(1, -1.25, 1.0), +(2, null, -2.5), +(3, 3.5, null); +select id, +python_bvt_pc_float_add(float_value) as float_added, +python_bvt_pc_double_add(double_value) as double_added +from float_values order by id; +➤ id[4,32,0] ¦ float_added[7,23,31] ¦ double_added[8,53,31] 𝄀 +1 ¦ -0.75 ¦ 1.5 𝄀 +2 ¦ null ¦ -2.0 𝄀 +3 ¦ 4.0 ¦ null drop function python_bvt_pc_add(int); drop function python_bvt_pc_multiply(int, int); drop function python_bvt_pc_if_else(bool, int, int); drop function python_bvt_pc_fill_null(int); drop function python_bvt_pc_is_null(int); +drop function python_bvt_pc_float_add(float); +drop function python_bvt_pc_double_add(double); +drop table float_values; drop table arithmetic_values; drop database udf_python_arrow_compute_arithmetic_bvt; diff --git a/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql b/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql index f1fbc290852ae..65f164f789c3e 100644 --- a/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql +++ b/test/distributed/cases/udf_python/arrow_compute_arithmetic.sql @@ -8,6 +8,8 @@ create function python_bvt_pc_multiply (x int, y int) returns int language pytho create function python_bvt_pc_if_else (flag bool, x int, y int) returns int language python as 'python_bvt_pc_if_else = lambda ctx, flag, left, right: __import__("pyarrow.compute", fromlist=["if_else"]).if_else(flag, left, right)' handler 'python_bvt_pc_if_else' mode vector; create function python_bvt_pc_fill_null (x int) returns int language python as 'python_bvt_pc_fill_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["fill_null"]).fill_null(values, __import__("pyarrow").scalar(-7, type=__import__("pyarrow").int32()))' handler 'python_bvt_pc_fill_null' mode vector; create function python_bvt_pc_is_null (x int) returns bool language python as 'python_bvt_pc_is_null = lambda ctx, values: __import__("pyarrow.compute", fromlist=["is_null"]).is_null(values)' handler 'python_bvt_pc_is_null' mode vector; +create function python_bvt_pc_float_add (x float) returns float language python as 'python_bvt_pc_float_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, __import__("pyarrow").scalar(0.5, type=__import__("pyarrow").float32()))' handler 'python_bvt_pc_float_add' mode vector; +create function python_bvt_pc_double_add (x double) returns double language python as 'python_bvt_pc_double_add = lambda ctx, values: __import__("pyarrow.compute", fromlist=["add"]).add(values, __import__("pyarrow").scalar(0.5, type=__import__("pyarrow").float64()))' handler 'python_bvt_pc_double_add' mode vector; create table arithmetic_values (id int, flag bool, left_value int, right_value int); insert into arithmetic_values values @@ -26,10 +28,24 @@ select id, python_bvt_pc_is_null(left_value) as is_null from arithmetic_values order by id; +create table float_values (id int, float_value float, double_value double); +insert into float_values values + (1, -1.25, 1.0), + (2, null, -2.5), + (3, 3.5, null); + +select id, + python_bvt_pc_float_add(float_value) as float_added, + python_bvt_pc_double_add(double_value) as double_added +from float_values order by id; + drop function python_bvt_pc_add(int); drop function python_bvt_pc_multiply(int, int); drop function python_bvt_pc_if_else(bool, int, int); drop function python_bvt_pc_fill_null(int); drop function python_bvt_pc_is_null(int); +drop function python_bvt_pc_float_add(float); +drop function python_bvt_pc_double_add(double); +drop table float_values; drop table arithmetic_values; drop database udf_python_arrow_compute_arithmetic_bvt; From 7c8f890238d4eb60c358611b0615590db955df2e Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:44:58 +0800 Subject: [PATCH 170/241] fix: preserve vector size during Python UDF binding --- pkg/frontend/compiler_context.go | 18 ++++++++++++------ .../cases/udf_python/vector_mode.result | 16 ++++++++++++++++ .../cases/udf_python/vector_mode.sql | 15 +++++++++++++++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/pkg/frontend/compiler_context.go b/pkg/frontend/compiler_context.go index 80729831ccf07..626ce2d7cafde 100644 --- a/pkg/frontend/compiler_context.go +++ b/pkg/frontend/compiler_context.go @@ -948,12 +948,18 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex if execResultArrayHasData(erArray) { fromList := make([]types.Type, len(args)) for i, arg := range args { - fromList[i] = types.Type{ - Oid: types.T(arg.Typ.Id), - Charset: uint8(arg.Typ.Charset), - Width: arg.Typ.Width, - Scale: arg.Typ.Scale, - } + // Reconstruct the complete SQL type instead of filling only the + // plan-visible fields. Type.Eq includes the physical size, which is + // not serialized in plan.Type but is required for exact Python ABI + // matching. In particular, a vector type built with Size == 0 is + // rejected against the declared VECF32/VECF64 descriptor because its + // fixed child width is no longer comparable. + fromList[i] = types.NewWithCharset( + types.T(arg.Typ.Id), + arg.Typ.Width, + arg.Typ.Scale, + uint8(arg.Typ.Charset), + ) argTypeStr += strings.ToLower(fromList[i].String()) if i+1 != len(args) { diff --git a/test/distributed/cases/udf_python/vector_mode.result b/test/distributed/cases/udf_python/vector_mode.result index 3c7c9bd29c6e5..aed22dc97f8b7 100644 --- a/test/distributed/cases/udf_python/vector_mode.result +++ b/test/distributed/cases/udf_python/vector_mode.result @@ -4,6 +4,8 @@ use udf_python_vector_bvt; create function python_bvt_vector (x int) returns int language python as 'python_bvt_vector = lambda ctx, values: __import__("pyarrow").array([-99 if value.as_py() is None else value.as_py() + 10 for value in values], type=__import__("pyarrow").int32())' handler 'python_bvt_vector' mode vector; create function python_bvt_vector_strict (x int) returns int language python as 'python_bvt_vector_strict = lambda ctx, values: __import__("pyarrow").array([value.as_py() + 10 for value in values], type=__import__("pyarrow").int32())' handler 'python_bvt_vector_strict' mode vector returns null on null input; create function python_bvt_zero_vector () returns int language python as 'python_bvt_zero_vector = lambda ctx: __import__("pyarrow").array([7] * ctx.num_rows, type=__import__("pyarrow").int32())' handler 'python_bvt_zero_vector' mode vector; +create function python_bvt_vecf32_identity (x vecf32(3)) returns vecf32(3) language python as 'python_bvt_vecf32_identity = lambda ctx, values: values' handler 'python_bvt_vecf32_identity' mode vector; +create function python_bvt_vecf64_identity (x vecf64(3)) returns vecf64(3) language python as 'python_bvt_vecf64_identity = lambda ctx, values: values' handler 'python_bvt_vecf64_identity' mode vector; create table vector_values (id int, value int); insert into vector_values values (1, 1), (2, null), (3, 2); select id, python_bvt_vector(value) as called_result @@ -24,8 +26,22 @@ from vector_values order by id; 1 ¦ 7 𝄀 2 ¦ 7 𝄀 3 ¦ 7 +create table vector_array_values (id int, f32 vecf32(3), f64 vecf64(3)); +insert into vector_array_values values +(1, cast("[1,2,3]" as vecf32(3)), cast("[1.5,2.5,3.5]" as vecf64(3))), +(2, null, null); +select id, +python_bvt_vecf32_identity(f32) as f32_identity, +python_bvt_vecf64_identity(f64) as f64_identity +from vector_array_values order by id; +➤ id[4,32,0] ¦ f32_identity[12,3,0] ¦ f64_identity[12,3,0] 𝄀 +1 ¦ [1, 2, 3] ¦ [1.5, 2.5, 3.5] 𝄀 +2 ¦ null ¦ null drop function python_bvt_vector(int); drop function python_bvt_vector_strict(int); drop function python_bvt_zero_vector(); +drop function python_bvt_vecf32_identity(vecf32(3)); +drop function python_bvt_vecf64_identity(vecf64(3)); +drop table vector_array_values; drop table vector_values; drop database udf_python_vector_bvt; diff --git a/test/distributed/cases/udf_python/vector_mode.sql b/test/distributed/cases/udf_python/vector_mode.sql index 6051e26aa69ab..e3b8d90525587 100644 --- a/test/distributed/cases/udf_python/vector_mode.sql +++ b/test/distributed/cases/udf_python/vector_mode.sql @@ -7,6 +7,8 @@ use udf_python_vector_bvt; create function python_bvt_vector (x int) returns int language python as 'python_bvt_vector = lambda ctx, values: __import__("pyarrow").array([-99 if value.as_py() is None else value.as_py() + 10 for value in values], type=__import__("pyarrow").int32())' handler 'python_bvt_vector' mode vector; create function python_bvt_vector_strict (x int) returns int language python as 'python_bvt_vector_strict = lambda ctx, values: __import__("pyarrow").array([value.as_py() + 10 for value in values], type=__import__("pyarrow").int32())' handler 'python_bvt_vector_strict' mode vector returns null on null input; create function python_bvt_zero_vector () returns int language python as 'python_bvt_zero_vector = lambda ctx: __import__("pyarrow").array([7] * ctx.num_rows, type=__import__("pyarrow").int32())' handler 'python_bvt_zero_vector' mode vector; +create function python_bvt_vecf32_identity (x vecf32(3)) returns vecf32(3) language python as 'python_bvt_vecf32_identity = lambda ctx, values: values' handler 'python_bvt_vecf32_identity' mode vector; +create function python_bvt_vecf64_identity (x vecf64(3)) returns vecf64(3) language python as 'python_bvt_vecf64_identity = lambda ctx, values: values' handler 'python_bvt_vecf64_identity' mode vector; create table vector_values (id int, value int); insert into vector_values values (1, 1), (2, null), (3, 2); @@ -24,8 +26,21 @@ from vector_values order by id; select id, python_bvt_zero_vector() as zero_result from vector_values order by id; +create table vector_array_values (id int, f32 vecf32(3), f64 vecf64(3)); +insert into vector_array_values values + (1, cast("[1,2,3]" as vecf32(3)), cast("[1.5,2.5,3.5]" as vecf64(3))), + (2, null, null); + +select id, + python_bvt_vecf32_identity(f32) as f32_identity, + python_bvt_vecf64_identity(f64) as f64_identity +from vector_array_values order by id; + drop function python_bvt_vector(int); drop function python_bvt_vector_strict(int); drop function python_bvt_zero_vector(); +drop function python_bvt_vecf32_identity(vecf32(3)); +drop function python_bvt_vecf64_identity(vecf64(3)); +drop table vector_array_values; drop table vector_values; drop database udf_python_vector_bvt; From 2fa16e2af7c49a5b5fe2494bf5c57c077a17963d Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:49:55 +0800 Subject: [PATCH 171/241] fix: keep BVT services alive for test runner --- optools/run_bvt.sh | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index 15a06ad901d10..2a8104fec57dd 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -83,9 +83,8 @@ function cleanup_all() { cleanup_mo } -trap cleanup_all EXIT -trap 'exit 130' INT -trap 'exit 143' TERM +trap 'cleanup_all; exit 130' INT +trap 'cleanup_all; exit 143' TERM function launch_mo() { cd $MO_WORKSPACE @@ -204,11 +203,28 @@ launch_mo if [[ "${SKIP_JSTFU:-false}" == "true" ]]; then echo "skip jstfu for this BVT suite" else - launch_jstfu || exit $? + launch_jstfu + status=$? + if [[ "$status" -ne 0 ]]; then + cleanup_all + exit "$status" + fi fi wait_system_init -if [[ "$?" -ne 0 ]]; then +status=$? +if [[ "$status" -ne 0 ]]; then + cleanup_all exit 1 fi wait_python_udf_worker -exit $? +status=$? +if [[ "$status" -ne 0 ]]; then + cleanup_all + exit "$status" +fi + +# This script is a launcher: its caller runs mo-tester after this command +# returns. Keep the services alive on a successful return; signal and startup +# failure paths above own cleanup because no caller can use the deployment in +# those cases. +exit 0 From 8c439144e4a05d7d84d3b6244134f408dccc8ef9 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 11:59:53 +0800 Subject: [PATCH 172/241] fix: clean BVT services after test completion --- optools/bvt_ut/entrypoint.sh | 6 +++++- optools/run_bvt.sh | 11 ++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/optools/bvt_ut/entrypoint.sh b/optools/bvt_ut/entrypoint.sh index e048892438fc9..12c42fba39ada 100755 --- a/optools/bvt_ut/entrypoint.sh +++ b/optools/bvt_ut/entrypoint.sh @@ -40,7 +40,11 @@ function run_bvt() { make build echo ">>>>>>>>>>>>>>>>>>>>>>>> start mo service" - ./optools/run_bvt.sh ./ "${LAUNCH}" + # Source the launcher so this entrypoint owns the service children until + # mo-tester finishes. A standalone run_bvt.sh invocation still returns + # with services alive for callers that launch the tester separately. + source ./optools/run_bvt.sh ./ "${LAUNCH}" + trap 'cleanup_all; packLog' EXIT echo ">>>>>>>>>>>>>>>>>>>>>>>> start bvt" # use test/distributed/cases as default test cases diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index 2a8104fec57dd..dae492f5d098c 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -51,9 +51,11 @@ function cleanup_mo() { kill -KILL "$MO_PID" 2>/dev/null || true fi fi - for child in "${BVT_CHILD_PIDS[@]}"; do - kill -KILL "$child" 2>/dev/null || true - done + if ((${#BVT_CHILD_PIDS[@]} > 0)); then + for child in "${BVT_CHILD_PIDS[@]}"; do + kill -KILL "$child" 2>/dev/null || true + done + fi wait "$pid" 2>/dev/null || true MO_PID="" } @@ -227,4 +229,7 @@ fi # returns. Keep the services alive on a successful return; signal and startup # failure paths above own cleanup because no caller can use the deployment in # those cases. +if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then + return 0 +fi exit 0 From b30194a021e7f807b7aa35e4511cae9ed8e1cd19 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 14:30:56 +0800 Subject: [PATCH 173/241] fix: harden BVT launcher argument handling --- optools/run_bvt.sh | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index dae492f5d098c..8de68313867c8 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -16,9 +16,15 @@ set -o nounset +if (( $# < 2 )); then + echo "usage: $0 [proxy-args ...]" >&2 + exit 2 +fi + MO_WORKSPACE=$1 LAUNCH=$2 -PROXY=${3:-} +shift 2 +PROXY_ARGS=("$@") LAUNCH_CONFIG=$LAUNCH MO_PID="" JSTFU_PID="" @@ -89,7 +95,7 @@ trap 'cleanup_all; exit 130' INT trap 'cleanup_all; exit 143' TERM function launch_mo() { - cd $MO_WORKSPACE + cd "$MO_WORKSPACE" # Ordinary launch BVT remains the single CI entry point, but its Python # cases opt into the worker-enabled manifest explicitly. The generic # etc/launch manifest stays safe for users who start mo-service directly. @@ -97,7 +103,11 @@ function launch_mo() { if [[ "$LAUNCH" == "launch" ]]; then LAUNCH_CONFIG=launch-with-python-udf-worker fi - ./mo-service -debug-http=:12345 -launch ./etc/$LAUNCH_CONFIG/launch.toml $PROXY &>mo-service.log & + if ((${#PROXY_ARGS[@]} > 0)); then + ./mo-service -debug-http=:12345 -launch "./etc/${LAUNCH_CONFIG}/launch.toml" "${PROXY_ARGS[@]}" &>mo-service.log & + else + ./mo-service -debug-http=:12345 -launch "./etc/${LAUNCH_CONFIG}/launch.toml" &>mo-service.log & + fi MO_PID=$! } @@ -126,7 +136,7 @@ function wait_python_udf_worker() { do if [[ -n "$MO_PID" ]] && ! kill -0 "$MO_PID" 2>/dev/null; then echo "MatrixOne exited before Python UDF worker became ready" >&2 - tail -n 160 mo-service.log >&2 || true + tail -n 160 "$MO_WORKSPACE/mo-service.log" >&2 || true return 1 fi if python3 - <<'PY' @@ -163,7 +173,7 @@ PY sleep 1 done echo "Python UDF capability handshake did not become ready on 127.0.0.1:50051" >&2 - tail -n 160 mo-service.log >&2 || true + tail -n 160 "$MO_WORKSPACE/mo-service.log" >&2 || true return 1 } @@ -175,7 +185,7 @@ PY # the Maven wrapper bootstraps its own Maven, and the pom emits Java 8 # bytecode on any JDK. function launch_jstfu() { - cd $MO_WORKSPACE + cd "$MO_WORKSPACE" if bash -c 'exec 3<>/dev/tcp/127.0.0.1/4444' 2>/dev/null; then echo "jstfu already listening on :4444, skip" return 0 From 306f3306c16a940a33328834208a61f79e02f6f7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 14:37:55 +0800 Subject: [PATCH 174/241] fix: freeze complete Arrow result frames --- pkg/udf/python/gateway.go | 53 +++++++++++++++++++++++++--------- pkg/udf/python/gateway_test.go | 17 +++++++++++ 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 1b4e04bc445c0..c619d59137d3e 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -1540,22 +1540,19 @@ func (g *Gateway) receiveResultBatch( if err := sequence.AcceptResult(control.Sequence); err != nil { return 0, err } - snapshot, err := protocol.FreezeOutput(data.DataBody, g.cfg.MaxBatchBytes) + headerSnapshot, bodySnapshot, err := freezeResultFrames( + data.DataHeader, + data.DataBody, + g.cfg.MaxBatchBytes, + ) if err != nil { return 0, err } - // FreezeOutput already stores the digest of its private copy. An - // empty expectedDigest still makes Validate rehash that same - // backing and detect any trusted-boundary mutation, without - // allocating the hexadecimal digest string twice on every batch. - if err := snapshot.Validate(len(data.DataBody), ""); err != nil { - return 0, err - } - // DecodeRecordBatch consumes the result header synchronously before - // the next Recv. The schema header is retained across batches, but - // this per-batch header has no cross-call lifetime, so keep the - // Flight-owned slice and avoid a redundant allocation/copy. - decoded, err := DecodeRecordBatch(**schemaFrame, ArrowFrame{Header: data.DataHeader, Body: snapshot.TrustedBytes()}, g.cfg.MaxBatchBytes) + // Both Flight buffers are now private snapshots. DecodeRecordBatch + // consumes exactly those validated backings; no later mutation of the + // received FlightData can change the bytes that crossed the trusted + // validation/publication boundary. + decoded, err := DecodeRecordBatch(**schemaFrame, ArrowFrame{Header: headerSnapshot.TrustedBytes(), Body: bodySnapshot.TrustedBytes()}, g.cfg.MaxBatchBytes) if err != nil { return 0, fmt.Errorf("python udf: decode result: %w", err) } @@ -1628,6 +1625,36 @@ func (g *Gateway) receiveResultBatch( } } +// freezeResultFrames takes ownership of both IPC pieces before either one is +// validated or decoded. MaxBatchBytes describes the complete per-batch +// payload, including the record message header and body; otherwise a large +// header could bypass the body-only limit used by the old result path. +func freezeResultFrames(header, body []byte, maxBytes int64) (*protocol.OutputSnapshot, *protocol.OutputSnapshot, error) { + if maxBytes <= 0 { + return nil, nil, fmt.Errorf("invalid Python UDF result batch limit") + } + headerBytes := int64(len(header)) + bodyBytes := int64(len(body)) + if headerBytes > maxBytes || bodyBytes > maxBytes-headerBytes { + return nil, nil, fmt.Errorf("RESOURCE_EXHAUSTED: Arrow result batch exceeds %d bytes", maxBytes) + } + headerSnapshot, err := protocol.FreezeOutput(header, maxBytes) + if err != nil { + return nil, nil, err + } + bodySnapshot, err := protocol.FreezeOutput(body, maxBytes) + if err != nil { + return nil, nil, err + } + if err := headerSnapshot.Validate(len(header), headerSnapshot.Digest()); err != nil { + return nil, nil, err + } + if err := bodySnapshot.Validate(len(body), bodySnapshot.Digest()); err != nil { + return nil, nil, err + } + return headerSnapshot, bodySnapshot, nil +} + type executionBudget struct { rows int64 maxRows int64 diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index fc47c4d3e48ea..3a9c2cb07e823 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -643,3 +643,20 @@ func TestGatewayRejectsArrowBodyOnControlFrame(t *testing.T) { ) require.ErrorContains(t, err, "unexpected Arrow data") } + +func TestFreezeResultFramesFreezesBothPartsAndChargesTotal(t *testing.T) { + header := []byte("record-header") + body := []byte("record-body") + headerSnapshot, bodySnapshot, err := freezeResultFrames(header, body, int64(len(header)+len(body))) + require.NoError(t, err) + require.NoError(t, headerSnapshot.Validate(len(header), headerSnapshot.Digest())) + require.NoError(t, bodySnapshot.Validate(len(body), bodySnapshot.Digest())) + + header[0] = 'X' + body[0] = 'Y' + require.Equal(t, "record-header", string(headerSnapshot.TrustedBytes())) + require.Equal(t, "record-body", string(bodySnapshot.TrustedBytes())) + + _, _, err = freezeResultFrames(header, body, int64(len(header)+len(body)-1)) + require.ErrorContains(t, err, "exceeds") +} From b0606fb9fd91b5c7b56ab6601dd2d04e57c26e9a Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 14:39:52 +0800 Subject: [PATCH 175/241] fix: verify BVT service liveness during startup --- optools/run_bvt.sh | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index 8de68313867c8..4c3bda99b063a 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -115,15 +115,36 @@ function launch_mo() { function wait_system_init() { for num in {1..300} do + if [[ -z "$MO_PID" ]] || ! process_is_alive "$MO_PID"; then + echo "MatrixOne exited before SQL readiness" >&2 + tail -n 160 "$MO_WORKSPACE/mo-service.log" >&2 || true + return 1 + fi if MYSQL_PWD=111 mysql --connect-timeout=2 -h 127.0.0.1 -P 6001 -u dump -e "show databases;"; then - echo "ok, cost $num seconds" - return 0 + if process_is_alive "$MO_PID"; then + echo "ok, cost $num seconds" + return 0 + fi + echo "MatrixOne exited while SQL readiness was being verified" >&2 + tail -n 160 "$MO_WORKSPACE/mo-service.log" >&2 || true + return 1 fi sleep 1 done return 1 } +function process_is_alive() { + local pid="$1" + local state + if ! kill -0 "$pid" 2>/dev/null; then + return 1 + fi + state=$(ps -o stat= -p "$pid" 2>/dev/null || true) + state=${state//[[:space:]]/} + [[ -n "$state" && "$state" != Z* ]] +} + # MySQL readiness only proves that the CN frontend accepted connections. The # worker is a separately started service, so Python UDF DDL/execution can still # race its Flight listener. Keep this in the existing BVT launcher instead of @@ -134,7 +155,7 @@ function wait_python_udf_worker() { fi for num in {1..120} do - if [[ -n "$MO_PID" ]] && ! kill -0 "$MO_PID" 2>/dev/null; then + if [[ -n "$MO_PID" ]] && ! process_is_alive "$MO_PID"; then echo "MatrixOne exited before Python UDF worker became ready" >&2 tail -n 160 "$MO_WORKSPACE/mo-service.log" >&2 || true return 1 From 718961c420a3c172d4ef508b95b2145db152e920 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 14:41:51 +0800 Subject: [PATCH 176/241] docs: fix Python UDF BVT generation example --- test/distributed/cases/udf_python/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/distributed/cases/udf_python/README.md b/test/distributed/cases/udf_python/README.md index 5bf9621efe91c..087f65dd69de4 100644 --- a/test/distributed/cases/udf_python/README.md +++ b/test/distributed/cases/udf_python/README.md @@ -22,7 +22,7 @@ the normal worker-enabled launch running and use `mo-tester`'s `genrs` mode: ```bash SKIP_JSTFU=true ./optools/run_bvt.sh . launch cd /path/to/mo-tester -./run.sh -p /path/to/matrixone/test/distributed/cases/udf_python/example.sql -m genrs -g +./run.sh -p /path/to/matrixone/test/distributed/cases/udf_python/control_flow.sql -m genrs -g ``` The ordinary BVT launch starts one worker for the single CN. Compose BVT starts From 66134ef8f3c98025d960fd01eceb40a4913c1dad Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 14:43:34 +0800 Subject: [PATCH 177/241] test: make compose worker readiness verify capabilities --- etc/launch-tae-compose/compose.yaml | 7 +-- pkg/udf/python/worker/Dockerfile | 2 +- pkg/udf/python/worker/healthcheck.py | 33 ++++++++++++ pkg/udf/python/worker/test_healthcheck.py | 64 +++++++++++++++++++++++ 4 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 pkg/udf/python/worker/healthcheck.py create mode 100644 pkg/udf/python/worker/test_healthcheck.py diff --git a/etc/launch-tae-compose/compose.yaml b/etc/launch-tae-compose/compose.yaml index de18214d88376..ea14e1051f7d5 100644 --- a/etc/launch-tae-compose/compose.yaml +++ b/etc/launch-tae-compose/compose.yaml @@ -35,10 +35,11 @@ x-python-udf-worker: &python-udf-worker - launch - launch-multi-cn healthcheck: - test: ["CMD", "python", "-c", "import socket; s=socket.create_connection(('127.0.0.1', 50051), 1); s.close()"] - interval: 1s - timeout: 2s + test: ["CMD", "python", "healthcheck.py"] + interval: 2s + timeout: 3s retries: 30 + start_period: 1s services: diff --git a/pkg/udf/python/worker/Dockerfile b/pkg/udf/python/worker/Dockerfile index f2403bec94263..4fbcaf7784120 100644 --- a/pkg/udf/python/worker/Dockerfile +++ b/pkg/udf/python/worker/Dockerfile @@ -27,7 +27,7 @@ WORKDIR /home/mo # && apt-get update \ # && apt-get install -y vim -COPY requirements.txt worker.py watchdog.py ./ +COPY requirements.txt worker.py watchdog.py healthcheck.py ./ RUN pip install --no-cache-dir -r requirements.txt diff --git a/pkg/udf/python/worker/healthcheck.py b/pkg/udf/python/worker/healthcheck.py new file mode 100644 index 0000000000000..05cfaab270bae --- /dev/null +++ b/pkg/udf/python/worker/healthcheck.py @@ -0,0 +1,33 @@ +"""Capability health check used by the container orchestrator.""" + +import json + +import pyarrow.flight as flight + + +PROTOCOL_VERSION = 1 +CAPABILITY_ACTION = "GetPythonCapabilities" + + +def check_capabilities( + address="grpc://127.0.0.1:50051", client_factory=flight.FlightClient +): + client = client_factory(address) + reader = client.do_action( + flight.Action(CAPABILITY_ACTION, b'{"protocol_version":1}') + ) + result = next(iter(reader), None) + if result is None: + raise RuntimeError("empty capability response") + capabilities = json.loads(bytes(result.body)) + if capabilities.get("protocol_version") != PROTOCOL_VERSION: + raise RuntimeError("unsupported capability protocol version") + return capabilities + + +def main(): + check_capabilities() + + +if __name__ == "__main__": + main() diff --git a/pkg/udf/python/worker/test_healthcheck.py b/pkg/udf/python/worker/test_healthcheck.py new file mode 100644 index 0000000000000..4cd0fa1dc843e --- /dev/null +++ b/pkg/udf/python/worker/test_healthcheck.py @@ -0,0 +1,64 @@ +import unittest + +import healthcheck + + +class _Result: + def __init__(self, body): + self.body = body + + +class _Reader: + def __init__(self, results): + self.results = iter(results) + + def __iter__(self): + return self + + def __next__(self): + return next(self.results) + + +class _Client: + def __init__(self, address, results): + self.address = address + self.results = results + self.action = None + + def do_action(self, action): + self.action = action + return _Reader(self.results) + + +class HealthcheckTest(unittest.TestCase): + def test_accepts_current_capability_protocol(self): + clients = [] + + def factory(address): + client = _Client( + address, [_Result(b'{"protocol_version":1}')] + ) + clients.append(client) + return client + + capabilities = healthcheck.check_capabilities( + "grpc://worker:50051", client_factory=factory + ) + + self.assertEqual(capabilities["protocol_version"], 1) + self.assertEqual(clients[0].address, "grpc://worker:50051") + self.assertEqual(clients[0].action.type, "GetPythonCapabilities") + self.assertEqual(clients[0].action.body, b'{"protocol_version":1}') + + def test_rejects_empty_or_unknown_protocol(self): + for response in (None, b'{"protocol_version":2}'): + def factory(address, response=response): + results = [] if response is None else [_Result(response)] + return _Client(address, results) + + with self.assertRaises(RuntimeError): + healthcheck.check_capabilities(client_factory=factory) + + +if __name__ == "__main__": + unittest.main() From 568f54e6129ba81cc5dd82c4f515e66a23004711 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 15:45:07 +0800 Subject: [PATCH 178/241] fix: clean BVT services on startup failure --- optools/run_bvt.sh | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index 4c3bda99b063a..93548b124991f 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -236,23 +236,38 @@ launch_mo if [[ "${SKIP_JSTFU:-false}" == "true" ]]; then echo "skip jstfu for this BVT suite" else - launch_jstfu - status=$? - if [[ "$status" -ne 0 ]]; then + # Keep the command in an if condition. The BVT entrypoint sources this + # file with `set -e`; a bare failing function call would exit before the + # cleanup block below can reclaim the already-started services. + if launch_jstfu; then + : + else + status=$? cleanup_all + if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then + return "$status" + fi exit "$status" fi fi -wait_system_init -status=$? -if [[ "$status" -ne 0 ]]; then +if wait_system_init; then + : +else + status=$? cleanup_all - exit 1 + if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then + return "$status" + fi + exit "$status" fi -wait_python_udf_worker -status=$? -if [[ "$status" -ne 0 ]]; then +if wait_python_udf_worker; then + : +else + status=$? cleanup_all + if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then + return "$status" + fi exit "$status" fi From 5d29955c0cc6574e941961658a726f8ad94488ba Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 15:45:59 +0800 Subject: [PATCH 179/241] ci: preserve BVT logs when setup fails --- optools/bvt_ut/entrypoint.sh | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/optools/bvt_ut/entrypoint.sh b/optools/bvt_ut/entrypoint.sh index 12c42fba39ada..581c5b715de95 100755 --- a/optools/bvt_ut/entrypoint.sh +++ b/optools/bvt_ut/entrypoint.sh @@ -4,18 +4,32 @@ set -euo pipefail SECONDS=0 -# mv log to mount path +# Move logs to the mounted path without masking the original CI failure when +# preparation or compilation stops before one of the normal artifacts exists. function packLog() { - mv /matrixone-test/mo-service.log /matrixone-test/tester-log - mv /matrixone-test/mo-tester/report /matrixone-test/tester-log - mv /root/scratch /matrixone-test/tester-log + local log_dir=/matrixone-test/tester-log + if ! mkdir -p "$log_dir"; then + echo "failed to create $log_dir; preserving the original CI failure" >&2 + return 0 + fi + for artifact in \ + /matrixone-test/mo-service.log \ + /matrixone-test/mo-tester/report \ + /root/scratch; do + if [[ ! -e "$artifact" ]]; then + continue + fi + if ! mv "$artifact" "$log_dir"; then + echo "failed to archive $artifact" >&2 + fi + done duration=$SECONDS echo "$(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed." } function prepare() { - mkdir /root/scratch + mkdir -p /root/scratch echo ">>>>>>>>>>>>>>>>>>>>>>>> show locale" echo `locale` From 1091fa7bbc0cb0269de095d43d3e6b1f4ec82f9c Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 15:54:02 +0800 Subject: [PATCH 180/241] fix: avoid waiting on exited BVT processes --- optools/run_bvt.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/optools/run_bvt.sh b/optools/run_bvt.sh index 93548b124991f..ea243b05d4ed9 100755 --- a/optools/run_bvt.sh +++ b/optools/run_bvt.sh @@ -45,15 +45,15 @@ function cleanup_mo() { local pid="$MO_PID" local -a BVT_CHILD_PIDS=() collect_descendants "$pid" - if kill -0 "$MO_PID" 2>/dev/null; then + if process_is_alive "$MO_PID"; then kill -TERM "$MO_PID" 2>/dev/null || true for _ in {1..30}; do - if ! kill -0 "$MO_PID" 2>/dev/null; then + if ! process_is_alive "$MO_PID"; then break fi sleep 1 done - if kill -0 "$MO_PID" 2>/dev/null; then + if process_is_alive "$MO_PID"; then kill -KILL "$MO_PID" 2>/dev/null || true fi fi @@ -70,15 +70,15 @@ function cleanup_jstfu() { if [[ -z "$JSTFU_PID" ]]; then return fi - if kill -0 "$JSTFU_PID" 2>/dev/null; then + if process_is_alive "$JSTFU_PID"; then kill -TERM "$JSTFU_PID" 2>/dev/null || true for _ in {1..15}; do - if ! kill -0 "$JSTFU_PID" 2>/dev/null; then + if ! process_is_alive "$JSTFU_PID"; then break fi sleep 1 done - if kill -0 "$JSTFU_PID" 2>/dev/null; then + if process_is_alive "$JSTFU_PID"; then kill -KILL "$JSTFU_PID" 2>/dev/null || true fi fi From dc25cd95cfe06e5fd35f2594036ddecc1aad650b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 15:58:16 +0800 Subject: [PATCH 181/241] fix: keep handler quota ownership retryable --- pkg/udf/python/worker/test_worker.py | 19 +++++++++++++++++++ pkg/udf/python/worker/worker.py | 7 ++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index b48b2333ed010..a0bd3ec02fd6e 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -1938,6 +1938,25 @@ def test_handler_quota_is_scoped_by_account_and_owner(self): third.release() self.assertEqual(({}, {}), quota.counts()) + def test_handler_quota_release_can_retry_after_counter_failure(self): + quota = worker._HandlerQuota(max_account_handlers=1, max_owner_handlers=1) + lease = quota.acquire(1, "alice") + real_release = quota._release + attempts = 0 + + def fail_once(account_id, owner_id): + nonlocal attempts + attempts += 1 + if attempts == 1: + raise RuntimeError("injected release failure") + return real_release(account_id, owner_id) + + with mock.patch.object(quota, "_release", side_effect=fail_once): + with self.assertRaisesRegex(RuntimeError, "injected release failure"): + lease.release() + lease.release() + self.assertEqual(({}, {}), quota.counts()) + def test_handler_initialization_closes_partial_pipe_ownership(self): real_pipe = os.pipe for failure in ("second_pipe", "watchdog_dup"): diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index df3d63a551f1b..0a081de3e83e8 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -2519,8 +2519,13 @@ def release(self) -> None: with self._lock: if self._released: return + # Keep ownership until the quota counter has actually been + # decremented. Cleanup callers retry a failed release; marking + # this token first would turn a transient quota error into a + # permanent handler-budget leak because the retry would become a + # no-op. + self._quota._release(self._account_id, self._owner_id) self._released = True - self._quota._release(self._account_id, self._owner_id) class _HandlerQuota: From a7c3e61eb2a4af24be57f100ed19d54d5746c0e3 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 16:20:23 +0800 Subject: [PATCH 182/241] fix: degrade python runtime initialization failures --- pkg/cnservice/python_runtime.go | 105 +++++++++++++++++++++++++++ pkg/cnservice/python_runtime_test.go | 44 +++++++++++ pkg/cnservice/server.go | 23 ++---- 3 files changed, 155 insertions(+), 17 deletions(-) create mode 100644 pkg/cnservice/python_runtime.go create mode 100644 pkg/cnservice/python_runtime_test.go diff --git a/pkg/cnservice/python_runtime.go b/pkg/cnservice/python_runtime.go new file mode 100644 index 0000000000000..d168e583b3e05 --- /dev/null +++ b/pkg/cnservice/python_runtime.go @@ -0,0 +1,105 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package cnservice + +import ( + "context" + "fmt" + + "go.uber.org/zap" + + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/fileservice" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/matrixorigin/matrixone/pkg/udf/python" +) + +// buildCNRuntime builds the language registry used by the CN. A Python +// initialization failure is kept as a language-scoped unavailable runtime so +// the feature gate remains fail-closed without taking ordinary SQL down with +// it. Config validation still happens before NewService and remains fatal for +// malformed CN configuration. +func buildCNRuntime(cfg python.ClientConfig, fileService fileservice.FileService, logger *zap.Logger) (udf.Runtime, error) { + if !cfg.Enabled { + return udf.NewRuntime() + } + + artifactStore, err := python.NewFileArtifactStore(fileService, python.DefaultMaxArtifactBytes) + if err != nil { + logPythonRuntimeDegraded(logger, err) + return udf.NewRuntime(&unavailablePythonRuntime{cause: err}) + } + runtime, err := python.NewGatewayWithArtifactStore(cfg, artifactStore) + if err != nil { + logPythonRuntimeDegraded(logger, err) + return udf.NewRuntime(&unavailablePythonRuntime{cause: err}) + } + return udf.NewRuntime(runtime) +} + +func logPythonRuntimeDegraded(logger *zap.Logger, err error) { + if logger != nil { + logger.Warn("python udf runtime is unavailable; ordinary SQL remains enabled", zap.Error(err)) + } +} + +// unavailablePythonRuntime preserves a stable language entry in the registry +// after initialization failed. It prevents a caller from mistaking an +// enabled-but-broken feature for a legacy fallback: every Python operation is +// rejected before user code, while StatusSnapshot exposes UNAVAILABLE. +type unavailablePythonRuntime struct { + cause error +} + +var _ udf.Runtime = (*unavailablePythonRuntime)(nil) +var _ udf.RuntimeReadiness = (*unavailablePythonRuntime)(nil) +var _ udf.RuntimeDefinitionValidator = (*unavailablePythonRuntime)(nil) +var _ udf.RuntimeStatusProvider = (*unavailablePythonRuntime)(nil) + +func (r *unavailablePythonRuntime) Language() string { return udf.LanguagePython } + +func (r *unavailablePythonRuntime) unavailableError() error { + if r == nil || r.cause == nil { + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime initialization failed") + } + return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime initialization failed: %w", r.cause) +} + +func (r *unavailablePythonRuntime) Execute(context.Context, *udf.Invocation, vector.FunctionResultWrapper, *mpool.MPool) error { + return r.unavailableError() +} + +func (r *unavailablePythonRuntime) CheckLanguageReady(ctx context.Context, language string) error { + if language != udf.LanguagePython { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported readiness language %q", language) + } + if ctx != nil { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + } + return r.unavailableError() +} + +func (r *unavailablePythonRuntime) ValidateDefinition(ctx context.Context, definition *udf.RoutineDefinition) error { + if definition == nil || definition.Language != udf.LanguagePython { + return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: invalid Python definition") + } + return r.CheckLanguageReady(ctx, udf.LanguagePython) +} + +func (r *unavailablePythonRuntime) StatusSnapshot(context.Context, string) udf.RuntimeStatusSnapshot { + return udf.RuntimeStatusSnapshot{ + Language: udf.LanguagePython, + Enabled: true, + Ready: false, + ErrorClass: udf.RuntimeStatusUnavailable, + Reason: udf.RuntimeStatusReasonWorkerUnavailable, + } +} diff --git a/pkg/cnservice/python_runtime_test.go b/pkg/cnservice/python_runtime_test.go new file mode 100644 index 0000000000000..1da63a1bd3de6 --- /dev/null +++ b/pkg/cnservice/python_runtime_test.go @@ -0,0 +1,44 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package cnservice + +import ( + "context" + "testing" + + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/matrixorigin/matrixone/pkg/udf/python" + "github.com/stretchr/testify/require" +) + +func TestBuildCNRuntimeDegradesPythonWhenArtifactServiceIsUnavailable(t *testing.T) { + cfg := python.ClientConfig{ + Enabled: true, + AllowUnisolated: true, + ServerAddress: "127.0.0.1:50051", + } + runtime, err := buildCNRuntime(cfg, nil, nil) + require.NoError(t, err) + + readiness, ok := runtime.(udf.RuntimeReadiness) + require.True(t, ok) + require.ErrorContains(t, readiness.CheckLanguageReady(context.Background(), udf.LanguagePython), "RESOURCE_UNAVAILABLE") + + status, ok := runtime.(udf.RuntimeStatusProvider) + require.True(t, ok) + snapshot := status.StatusSnapshot(context.Background(), udf.LanguagePython) + require.True(t, snapshot.Enabled) + require.False(t, snapshot.Ready) + require.Equal(t, udf.RuntimeStatusUnavailable, snapshot.ErrorClass) +} + +func TestBuildCNRuntimeDisabledDoesNotCreatePythonRuntime(t *testing.T) { + runtime, err := buildCNRuntime(python.ClientConfig{}, nil, nil) + require.NoError(t, err) + readiness, ok := runtime.(udf.RuntimeReadiness) + require.True(t, ok) + require.ErrorContains(t, readiness.CheckLanguageReady(context.Background(), udf.LanguagePython), "not enabled") +} diff --git a/pkg/cnservice/server.go b/pkg/cnservice/server.go index 93156c000f6ef..aafed2e53091d 100644 --- a/pkg/cnservice/server.go +++ b/pkg/cnservice/server.go @@ -69,7 +69,6 @@ import ( "github.com/matrixorigin/matrixone/pkg/txn/clock" "github.com/matrixorigin/matrixone/pkg/txn/rpc" "github.com/matrixorigin/matrixone/pkg/udf" - "github.com/matrixorigin/matrixone/pkg/udf/python" "github.com/matrixorigin/matrixone/pkg/util/address" "github.com/matrixorigin/matrixone/pkg/util/executor" v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2" @@ -251,22 +250,12 @@ func NewService( MaxSize: pu.SV.AutoIncrCacheSize, } - // init UdfService - var udfServices []udf.Runtime - // add python client to handle python udf - if srv.cfg.PythonUdfClient.Enabled { - artifactStore, storeErr := python.NewFileArtifactStore(srv.fileService, python.DefaultMaxArtifactBytes) - if storeErr != nil { - panic(storeErr) - } - var pc *python.Gateway - pc, err = python.NewGatewayWithArtifactStore(srv.cfg.PythonUdfClient, artifactStore) - if err != nil { - return nil, err - } - udfServices = append(udfServices, pc) - } - srv.udfService, err = udf.NewRuntime(udfServices...) + // init UdfService. Python is an opt-in feature and its transport or + // artifact dependencies must not turn an otherwise usable CN into a + // process-wide crash loop. buildCNRuntime keeps the language gate visible + // to CREATE/EXECUTE while ordinary SQL continues with the runtime in an + // explicit UNAVAILABLE state. + srv.udfService, err = buildCNRuntime(srv.cfg.PythonUdfClient, srv.fileService, srv.logger) if err != nil { return nil, err } From 4e9206eb026ab8422c6af76c0f4a2436c2e299c3 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 16:24:12 +0800 Subject: [PATCH 183/241] fix: clean up compose BVT services --- optools/compose_bvt/compose_bvt.sh | 47 +++++++++++++++++++++++------- optools/compose_bvt/entrypoint.sh | 6 +++- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/optools/compose_bvt/compose_bvt.sh b/optools/compose_bvt/compose_bvt.sh index dce8d7ca4ccb8..b729250898e8d 100755 --- a/optools/compose_bvt/compose_bvt.sh +++ b/optools/compose_bvt/compose_bvt.sh @@ -1,29 +1,56 @@ #!/bin/bash -set -e +set -euo pipefail + +if (( $# < 2 )); then + echo "usage: $0 " >&2 + exit 2 +fi MO_WORKSPACE=$1 COMPOSE_LAUNCH=$2 +COMPOSE_FILE="${MO_WORKSPACE}/etc/launch-tae-compose/compose.yaml" function export_logs() { - cd ${MO_WORKSPACE} - curl http://localhost:12345/debug/pprof/goroutine\?debug=2 -o docker-compose-log/cn-0-dump-stacks - curl http://localhost:22345/debug/pprof/goroutine\?debug=2 -o docker-compose-log/cn-1-dump-stacks + cd -- "${MO_WORKSPACE}" || return 0 + curl --fail --silent --show-error "http://localhost:12345/debug/pprof/goroutine?debug=2" \ + -o docker-compose-log/cn-0-dump-stacks || true + curl --fail --silent --show-error "http://localhost:22345/debug/pprof/goroutine?debug=2" \ + -o docker-compose-log/cn-1-dump-stacks || true +} + +function cleanup_compose() { + # Preserve the tester's exit status while making service teardown + # best-effort. This trap owns every service started by this script, + # including both CN-local Python workers. + set +e + export_logs + docker compose -f "${COMPOSE_FILE}" --profile "${COMPOSE_LAUNCH}" down --remove-orphans } function compose_bvt() { - trap "export_logs" EXIT + trap cleanup_compose EXIT - cd ${MO_WORKSPACE} + cd -- "${MO_WORKSPACE}" - docker compose -f etc/launch-tae-compose/compose.yaml --profile "${COMPOSE_LAUNCH}" up -d --build + docker compose -f "${COMPOSE_FILE}" --profile "${COMPOSE_LAUNCH}" up -d --build docker build -t matrixorigin/compose-tester:local -f optools/compose_bvt/Dockerfile.tester . - docker run -it --name compose-tester --privileged --network launch-tae-compose_monet -v ${MO_WORKSPACE}/docker-compose-log:/test --rm matrixorigin/compose-tester:local - exit 0 + docker run -it --name compose-tester --privileged --network launch-tae-compose_monet \ + -v "${MO_WORKSPACE}/docker-compose-log:/test" --rm matrixorigin/compose-tester:local } #create the dir for export logs -rm -rf ${MO_WORKSPACE}/docker-compose-log && mkdir -p ${MO_WORKSPACE}/docker-compose-log +python3 - "${MO_WORKSPACE}/docker-compose-log" <<'PY' +import pathlib +import shutil +import sys + +target = pathlib.Path(sys.argv[1]).resolve() +if target == target.parent or target == pathlib.Path("/"): + raise SystemExit(f"refusing unsafe log directory: {target}") +shutil.rmtree(target, ignore_errors=True) +target.mkdir(parents=True, exist_ok=True) +PY compose_bvt diff --git a/optools/compose_bvt/entrypoint.sh b/optools/compose_bvt/entrypoint.sh index edff22b51a6f0..797faa5633cd1 100755 --- a/optools/compose_bvt/entrypoint.sh +++ b/optools/compose_bvt/entrypoint.sh @@ -6,7 +6,11 @@ SECONDS=0 # mv log to mount path function packLog() { - mv /mo-tester/report /test/ + if [[ -e /mo-tester/report ]]; then + mv /mo-tester/report /test/ + else + echo "mo-tester did not produce a report; preserving the original test status" >&2 + fi duration=$SECONDS echo "$(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed." From 7791c9786f68b2b6bc2a85d42dbe06a65e0f2544 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 18 Sep 2026 16:25:55 +0800 Subject: [PATCH 184/241] test: execute scalar Python UDF BVT case --- test/distributed/cases/udf_python/control_flow.result | 6 ++++++ test/distributed/cases/udf_python/control_flow.sql | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/test/distributed/cases/udf_python/control_flow.result b/test/distributed/cases/udf_python/control_flow.result index 1c55957986b2c..10afe7303cdae 100644 --- a/test/distributed/cases/udf_python/control_flow.result +++ b/test/distributed/cases/udf_python/control_flow.result @@ -18,6 +18,12 @@ from control_values order by id; 1 ¦ 𝄀 2 ¦ <中😀> 𝄀 3 ¦ +select id, python_bvt_add_one(value) as plus_one +from control_values order by id; +➤ id[4,32,0] ¦ plus_one[4,32,0] 𝄀 +1 ¦ 2 𝄀 +2 ¦ 3 𝄀 +3 ¦ null select id, python_bvt_zero_arg() as constant from control_values order by id; ➤ id[4,32,0] ¦ constant[4,32,0] 𝄀 diff --git a/test/distributed/cases/udf_python/control_flow.sql b/test/distributed/cases/udf_python/control_flow.sql index c60cb08619d8a..5b133dbdc9d70 100644 --- a/test/distributed/cases/udf_python/control_flow.sql +++ b/test/distributed/cases/udf_python/control_flow.sql @@ -21,6 +21,10 @@ insert into control_values values select id, python_bvt_mark_null(label) as marked from control_values order by id; +-- A scalar handler must be invoked once per row and preserve a handler NULL. +select id, python_bvt_add_one(value) as plus_one +from control_values order by id; + -- A zero-argument scalar still produces one result per input row. select id, python_bvt_zero_arg() as constant from control_values order by id; From 79b14e37289657519ff17659591ea076191f02ac Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 20 Sep 2026 12:29:12 +0800 Subject: [PATCH 185/241] fix(udf): validate overload namespaces and cancel capability waits --- docs/design/routine_namespace_validation.md | 48 + pkg/frontend/compiler_context.go | 13 +- pkg/frontend/routine_namespace.go | 170 ++ pkg/frontend/routine_namespace_test.go | 167 ++ pkg/frontend/routine_plan_validation.go | 82 +- pkg/frontend/routine_plan_validation_test.go | 24 +- pkg/pb/plan/plan.pb.go | 2528 +++++++++-------- pkg/sql/plan/function/udf.go | 17 +- pkg/sql/plan/routine_dependency.go | 4 +- pkg/udf/python/capability_lifecycle_test.go | 198 ++ pkg/udf/python/gateway.go | 228 +- pkg/udf/runtime_status_wire_test.go | 39 + pkg/udf/testdata/python_status_wire.json | 52 + proto/plan.proto | 4 + .../cases/udf/overload_namespace.result | 57 + .../cases/udf/overload_namespace.sql | 35 + .../udf_python/overload_namespace.result | 57 + .../cases/udf_python/overload_namespace.sql | 35 + 18 files changed, 2418 insertions(+), 1340 deletions(-) create mode 100644 docs/design/routine_namespace_validation.md create mode 100644 pkg/frontend/routine_namespace.go create mode 100644 pkg/frontend/routine_namespace_test.go create mode 100644 pkg/udf/python/capability_lifecycle_test.go create mode 100644 pkg/udf/runtime_status_wire_test.go create mode 100644 pkg/udf/testdata/python_status_wire.json create mode 100644 test/distributed/cases/udf/overload_namespace.result create mode 100644 test/distributed/cases/udf/overload_namespace.sql create mode 100644 test/distributed/cases/udf_python/overload_namespace.result create mode 100644 test/distributed/cases/udf_python/overload_namespace.sql diff --git a/docs/design/routine_namespace_validation.md b/docs/design/routine_namespace_validation.md new file mode 100644 index 0000000000000..51ccfb771db19 --- /dev/null +++ b/docs/design/routine_namespace_validation.md @@ -0,0 +1,48 @@ +# Routine overload namespace validation + +A cached or prepared routine call depends on two distinct things: + +* the exact selected FunctionRef and immutable revision contracts; +* the complete candidate set for its account/database/name at binding time. + +The revision-local `namespace_version` stored on an identity/revision cannot be +used as the second dependency: CREATE of a sibling does not update that tuple. +Updating all sibling heads would make them disagree with immutable revisions. + +`RoutineCall.namespace_fingerprint` and `RoutinePlanDependency.namespace_fingerprint` +now carry a separate state fingerprint. The resolver and reuse validator read +all same-name candidates, across SQL/Python and signatures, in their catalog +read transaction (and with the explicit historical snapshot when applicable). +The internal reads are marked derived after BEGIN and restored before finishTxn, +so READ COMMITTED cannot advance the snapshot between enumeration and digest +capture. Database identity uses the same read transaction and snapshot tenant. +The selected ID locates the namespace; account context and the independently +validated database ID fence its scope. Execution continues to use the exact +FunctionRef, never a name or a latest-revision lookup. + +The query deduplicates namespaces before joining candidates, and projects fixed-width +SHA-256 hashes of text/JSON metadata instead of transferring source bodies. +The canonical encoding hashes a versioned JSON tuple per candidate: identity, +active revision, revision-local namespace, base arguments/body/language/return/ +database/SQL mode/security, plus effective revision arguments/body/language/ +return/security. Sorted fixed-length candidate digests form the namespace +state digest. Thus newly introduced better/ambiguous matches invalidate even +when the selected identity is unchanged. DROP, replacement, clone and restore +follow visible catalog state. Restoring exactly the same candidates need not +invalidate: this is not an event counter. Selected revision integrity and +security checks still run independently. + +There is no new persistent catalog or backfill. Older plans without the digest +cannot be reused; the normal bind path regenerates the dependency. A missing +selected identity invalidates rather than reporting catalog corruption. Empty +candidate results are distinct from malformed multi-result responses. + +Validation reads are bounded to 65,536 candidate rows (an extra row detects +overflow) and 64 MiB of decoded metadata per read. Exceeding either marks the plan non-reusable and forces rebind, +never accepts a truncated digest and does not reject otherwise valid SQL. This increases reuse validation cost with the +number of overloads and their definition size. It does not add worker RPCs or +per-row lookups. Dependency count/serialized-byte bounds remain in force. + +This replaces the earlier proposal to advance a separate mutable namespace +generation for every overload-set change. It preserves that proposal's cache +correctness property without introducing a second publication/restore index. diff --git a/pkg/frontend/compiler_context.go b/pkg/frontend/compiler_context.go index 626ce2d7cafde..40b65f2a8eda5 100644 --- a/pkg/frontend/compiler_context.go +++ b/pkg/frontend/compiler_context.go @@ -923,6 +923,7 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex } } + defer pinRoutineCatalogReads(bh)() snapshot := tcc.GetSnapshot() if sub := tcc.GetQueryingSubscription(); sub != nil && snapshot != nil { // The subscriber owns the snapshot name; publisher UDFs live in the @@ -1121,12 +1122,22 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex if accountErr != nil { return nil, accountErr } - databaseID, databaseErr := tcc.GetDatabaseId(matchedList[0].Udf.Db, tcc.GetSnapshot()) + accountID = routineCatalogAccountID(accountID, tcc.GetSnapshot()) + databaseID, databaseErr := routineCatalogDatabaseID(queryCtx, bh, matchedList[0].Udf.Db, accountID, tcc.GetSnapshot()) if databaseErr != nil { return nil, fmt.Errorf("python routine database identity: %w", databaseErr) } matchedList[0].Udf.AccountID = uint64(accountID) matchedList[0].Udf.DatabaseID = databaseID + namespaces, namespaceErr := readRoutineNamespaces(queryCtx, bh, []uint64{uint64(matchedList[0].Udf.FunctionID)}, tcc.GetSnapshot()) + if namespaceErr != nil && !errors.Is(namespaceErr, errRoutineNamespaceBudget) { + return nil, namespaceErr + } + matchedList[0].Udf.NamespaceFingerprint = namespaces[uint64(matchedList[0].Udf.FunctionID)] + if namespaceErr == nil && matchedList[0].Udf.NamespaceFingerprint == "" { + return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: missing routine namespace") + } + } return matchedList[0].Udf, err } diff --git a/pkg/frontend/routine_namespace.go b/pkg/frontend/routine_namespace.go new file mode 100644 index 0000000000000..89e494ba8b40f --- /dev/null +++ b/pkg/frontend/routine_namespace.go @@ -0,0 +1,170 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package frontend + +import ( + "context" + "crypto/sha256" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "sort" + "strconv" + "strings" + + planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" +) + +var errRoutineNamespaceBudget = errors.New("routine namespace cache budget exceeded") + +const maxRoutineNamespaceRows = 65536 +const maxRoutineNamespaceBytes = 64 << 20 + +// readRoutineNamespaces reads the complete candidate set, not just matching +// signatures. The selected identity locates its database/name under the tenant +// context; all languages participate. Revision-local namespace_version remains +// immutable. The separate digest is state-based and naturally follows rollback, +// snapshot/PITR and clone publication without a second mutable catalog index. +func readRoutineNamespaces(ctx context.Context, bh BackgroundExec, ids []uint64, snapshot *planpb.Snapshot) (map[uint64]string, error) { + bh.ClearExecResultSet() + if err := bh.Exec(ctx, routineNamespacesSQL(ids, snapshot)); err != nil { + return nil, err + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return nil, err + } + row, err := candidateCatalogResultSet(rows, "routine namespaces") + if err != nil { + return nil, err + } + if row == nil { + return map[uint64]string{}, nil + } + return decodeRoutineNamespaces(ctx, row) +} + +func routineNamespacesSQL(ids []uint64, snapshot *planpb.Snapshot) string { + values := make([]string, len(ids)) + for i, id := range ids { + values[i] = strconv.FormatUint(id, 10) + } + suffix := "" + if snapshot != nil && snapshot.TS != nil { + suffix = fmt.Sprintf(" {MO_TS = %d}", snapshot.TS.PhysicalTime) + } + // Read both base and revision metadata: legacy SQL resolves the base, typed + // SQL/Python resolves the immutable revision. Never drop an unmatching sibling. + + return fmt.Sprintf(`select selected.function_id, f.function_id, f.active_revision, f.namespace_version, + sha2(cast(f.args as varchar),256), sha2(f.body,256), sha2(f.language,256), sha2(f.rettype,256), sha2(f.db,256), sha2(f.sql_mode,256), sha2(f.security_type,256), + sha2(cast(coalesce(r.args,'[]') as varchar),256), sha2(coalesce(r.body,''),256), sha2(coalesce(r.language,''),256), sha2(coalesce(r.rettype,''),256), sha2(coalesce(r.security_type,''),256) + from (select db,name,min(function_id) as function_id from mo_catalog.mo_user_defined_function%s where function_id in (%s) group by db,name) selected + join mo_catalog.mo_user_defined_function%s f on f.db=selected.db and f.name=selected.name + left join mo_catalog.mo_function_revisions%s r on r.function_id=f.function_id and r.revision=f.active_revision and r.namespace_version=f.namespace_version + limit %d;`, suffix, strings.Join(values, ","), suffix, suffix, maxRoutineNamespaceRows+1) +} + +func decodeRoutineNamespaces(ctx context.Context, rows ExecResult) (map[uint64]string, error) { + if rows.GetRowCount() > maxRoutineNamespaceRows { + return nil, fmt.Errorf("%w: namespace rows exceed %d", errRoutineNamespaceBudget, maxRoutineNamespaceRows) + } + groups := make(map[uint64]map[uint64]string) + remaining := maxRoutineNamespaceBytes + for row := uint64(0); row < rows.GetRowCount(); row++ { + var numbers [4]uint64 + for col := range numbers { + value, err := rows.GetUint64(ctx, row, uint64(col)) + if err != nil { + return nil, err + } + numbers[col] = value + } + var fields [12]string + for col := range fields { + value, err := rows.GetString(ctx, row, uint64(col+4)) + if err != nil { + return nil, err + } + if len(value) > remaining { + return nil, fmt.Errorf("%w: namespace bytes exceed %d", errRoutineNamespaceBudget, maxRoutineNamespaceBytes) + } + remaining -= len(value) + fields[col] = value + } + // JSON arrays give unambiguous length/escaping, with fixed version/domain. + // Exclude selected id so different overloads in one namespace share a token. + encoded, err := json.Marshal(struct { + Version int + Identity [3]uint64 + Fields [12]string + }{1, [3]uint64{numbers[1], numbers[2], numbers[3]}, fields}) + if err != nil { + return nil, err + } + digest := sha256.Sum256(encoded) + if groups[numbers[0]] == nil { + groups[numbers[0]] = make(map[uint64]string) + } + if _, duplicate := groups[numbers[0]][numbers[1]]; duplicate { + return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: duplicate routine namespace member") + } + groups[numbers[0]][numbers[1]] = hex.EncodeToString(digest[:]) + } + result := make(map[uint64]string, len(groups)) + for _, members := range groups { + fingerprints := make([]string, 0, len(members)) + for _, fp := range members { + fingerprints = append(fingerprints, fp) + } + sort.Strings(fingerprints) + digest := sha256.Sum256([]byte("mo-routine-namespace-state/1\x00" + strings.Join(fingerprints, ""))) + for id := range members { + result[id] = hex.EncodeToString(digest[:]) + } + } + return result, nil +} + +// begin creates the catalog read transaction. Mark its internal SELECTs derived +// until finishTxn so READ COMMITTED cannot advance between enumeration, revision +// reads and the namespace fence. Restore before COMMIT/ROLLBACK and Close. +func pinRoutineCatalogReads(bh BackgroundExec) func() { + if back, ok := bh.(*backExec); ok { + previous := back.backSes.ReplaceDerivedStmt(true) + return func() { back.backSes.ReplaceDerivedStmt(previous) } + } + // Non-engine executors are deterministic unit-test readers. + return func() {} +} + +func routineCatalogDatabaseID(ctx context.Context, bh BackgroundExec, database string, accountID uint32, snapshot *planpb.Snapshot) (uint64, error) { + table := "mo_catalog.mo_database" + if snapshot != nil && snapshot.TS != nil { + table += fmt.Sprintf(" {MO_TS = %d}", snapshot.TS.PhysicalTime) + } + bh.ClearExecResultSet() + if err := bh.Exec(ctx, fmt.Sprintf("select dat_id from %s where datname = '%s' and account_id = %d;", table, strings.ReplaceAll(database, "'", "''"), accountID)); err != nil { + return 0, err + } + rows, err := getResultSet(ctx, bh) + if err != nil { + return 0, err + } + row, err := exactlyOneCatalogRow(ctx, rows, "routine database identity") + if err != nil { + return 0, err + } + return row.GetUint64(ctx, 0, 0) +} + +func routineCatalogAccountID(sessionAccount uint32, snapshot *planpb.Snapshot) uint32 { + if snapshot != nil && snapshot.Tenant != nil { + return snapshot.Tenant.TenantID + } + return sessionAccount +} diff --git a/pkg/frontend/routine_namespace_test.go b/pkg/frontend/routine_namespace_test.go new file mode 100644 index 0000000000000..e8531c811613a --- /dev/null +++ b/pkg/frontend/routine_namespace_test.go @@ -0,0 +1,167 @@ +// Copyright 2026 Matrix Origin +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +package frontend + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/gogo/protobuf/proto" + "github.com/golang/mock/gomock" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/defines" + mock_frontend "github.com/matrixorigin/matrixone/pkg/frontend/test" + planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" + "github.com/matrixorigin/matrixone/pkg/pb/txn" + "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + "github.com/matrixorigin/matrixone/pkg/txn/client" + "github.com/stretchr/testify/require" +) + +func namespaceRows(data ...[]interface{}) *MysqlResultSet { + r := &MysqlResultSet{} + for i := 0; i < 16; i++ { + c := &MysqlColumn{} + c.SetName(fmt.Sprint(i)) + c.SetColumnType(defines.MYSQL_TYPE_VARCHAR) + if i < 4 { + c.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + } + r.AddColumn(c) + } + for _, row := range data { + r.AddRow(row) + } + return r +} +func namespaceMember(id uint64, arg string) []interface{} { + return []interface{}{uint64(41), id, uint64(1), uint64(1), arg, "body", "python", "bigint", "db", "", "INVOKER", arg, "body", "python", "bigint", "INVOKER"} +} +func TestRoutineNamespaceInvalidatesBetterOverload(t *testing.T) { + input := []types.Type{types.T_int16.ToType()} + oldMatch, oldCost := function.PythonUdfArgTypeMatch(input, []types.Type{types.T_int64.ToType()}) + newMatch, newCost := function.PythonUdfArgTypeMatch(input, input) + require.True(t, oldMatch && newMatch) + require.Less(t, newCost, oldCost) + old := namespaceMember(41, "bigint") + sibling := namespaceMember(42, "smallint") + before, err := decodeRoutineNamespaces(context.Background(), namespaceRows(old)) + require.NoError(t, err) + after, err := decodeRoutineNamespaces(context.Background(), namespaceRows(old, sibling)) + require.NoError(t, err) + dependency := testRoutinePlanDependency() + dependency.NamespaceFingerprint = before[41] + state := testRoutinePlanState() + state.namespaceFingerprint = before[41] + require.False(t, routinePlanDependenciesChanged([]*planpb.RoutinePlanDependency{dependency}, map[uint64]routinePlanCatalogState{41: state})) + state.namespaceFingerprint = after[41] + require.True(t, routinePlanDependenciesChanged([]*planpb.RoutinePlanDependency{dependency}, map[uint64]routinePlanCatalogState{41: state}), "selected identity unchanged, but new better overload must invalidate") + // Rollback/restoring the identical candidate state preserves the dependency. + restored, err := decodeRoutineNamespaces(context.Background(), namespaceRows(old)) + require.NoError(t, err) + require.Equal(t, before, restored) + reordered, err := decodeRoutineNamespaces(context.Background(), namespaceRows(sibling, old)) + require.NoError(t, err) + require.Equal(t, after, reordered) + require.Equal(t, after[41], after[42], "all selected siblings reuse one namespace hash") + // Drop and replace of an unselected member change the name dependency. + sibling[2] = uint64(2) + replaced, err := decodeRoutineNamespaces(context.Background(), namespaceRows(old, sibling)) + require.NoError(t, err) + require.NotEqual(t, after, replaced) + // Effective revision metadata, rather than only initial head projection. + sibling[11] = "int" + effective, err := decodeRoutineNamespaces(context.Background(), namespaceRows(old, sibling)) + require.NoError(t, err) + require.NotEqual(t, replaced, effective) + _, err = decodeRoutineNamespaces(context.Background(), namespaceRows(old, old)) + require.ErrorContains(t, err, "duplicate") + data, err := proto.Marshal(dependency) + require.NoError(t, err) + var decoded planpb.RoutinePlanDependency + require.NoError(t, proto.Unmarshal(data, &decoded)) + require.Equal(t, dependency.NamespaceFingerprint, decoded.NamespaceFingerprint) + decoded.NamespaceFingerprint = "" + require.ErrorContains(t, validateRoutinePlanDependencyShape(&decoded, 9), "incomplete") +} +func TestRoutineNamespaceQueryReadsAllLanguagesAndSignatures(t *testing.T) { + query := routineNamespacesSQL([]uint64{41, 42}, nil) + require.Contains(t, query, "f.db=selected.db and f.name=selected.name") + require.Contains(t, query, "where function_id in (41,42) group by db,name") + require.NotContains(t, query, "f.language =") + require.NotContains(t, query, "f.arg_types =") + require.Contains(t, query, "limit 65537") +} +func TestRoutineNamespaceReadIsBounded(t *testing.T) { + oversized := namespaceMember(41, "bigint") + oversized[5] = strings.Repeat("x", maxRoutineNamespaceBytes+1) + _, err := decodeRoutineNamespaces(context.Background(), namespaceRows(oversized)) + require.ErrorContains(t, err, "namespace bytes") +} + +type routineSnapshotWorkspace struct { + client.Workspace + advances int +} + +func (w *routineSnapshotWorkspace) IncrStatementID(context.Context, bool) error { + w.advances++ + return fmt.Errorf("snapshot advanced") +} + +func TestRoutineCatalogReadsKeepRCSnapshotUntilFinish(t *testing.T) { + ctrl := gomock.NewController(t) + op := mock_frontend.NewMockTxnOperator(ctrl) + workspace := &routineSnapshotWorkspace{} + op.EXPECT().GetWorkspace().Return(workspace).AnyTimes() + op.EXPECT().Status().Return(txn.TxnStatus_Active).AnyTimes() + back := &backExec{backSes: &backSession{}} + restore := pinRoutineCatalogReads(back) + // This is the real statement boundary that would advance an RC snapshot. + // A concurrent DDL commit between these internal SELECTs cannot invoke it. + for i := 0; i < 3; i++ { + require.NoError(t, executeStmtWithIncrStmt(back.backSes, nil, nil, op)) + } + require.Zero(t, workspace.advances) + restore() + require.False(t, back.backSes.IsDerivedStmt()) + err := executeStmtWithIncrStmt(back.backSes, nil, &ExecCtx{reqCtx: context.Background()}, op) + require.ErrorContains(t, err, "snapshot advanced") + require.Equal(t, 1, workspace.advances) + // Nested shared readers restore the existing derived state rather than + // committing/advancing their caller's statement on return. + back.backSes.ReplaceDerivedStmt(true) + restore = pinRoutineCatalogReads(back) + restore() + require.True(t, back.backSes.IsDerivedStmt()) +} + +type namespaceValidationSession struct{ FeSession } + +func (*namespaceValidationSession) GetTxnCompileCtx() *TxnCompilerContext { return nil } +func (*namespaceValidationSession) GetAccountId() uint32 { return 9 } +func TestRoutinePlanWithoutNamespaceRebinds(t *testing.T) { + dependency := testRoutinePlanDependency() + dependency.NamespaceFingerprint = "" + p := &planpb.Plan{Plan: &planpb.Plan_Query{Query: &planpb.Query{RoutineDependencies: []*planpb.RoutinePlanDependency{dependency}}}} + changed, err := validateRoutinePlanDependencies(context.Background(), &namespaceValidationSession{}, p) + require.NoError(t, err) + require.True(t, changed) +} + +func TestRoutineCatalogDatabaseUsesSnapshotTenant(t *testing.T) { + snapshot := &planpb.Snapshot{Tenant: &planpb.SnapshotTenant{TenantID: 7}} + require.Equal(t, uint32(7), routineCatalogAccountID(0, snapshot)) + require.Equal(t, uint32(9), routineCatalogAccountID(9, nil)) + bh := &backgroundExecTestWithHistory{} + bh.init() + bh.sql2result["select dat_id from mo_catalog.mo_database where datname = 'source_db' and account_id = 7;"] = singleInt64Result("dat_id", 88) + ctx := defines.AttachAccountId(context.Background(), 7) + id, err := routineCatalogDatabaseID(ctx, bh, "source_db", routineCatalogAccountID(0, snapshot), snapshot) + require.NoError(t, err) + require.Equal(t, uint64(88), id) + require.Contains(t, bh.executedSqls[0], "account_id = 7") +} diff --git a/pkg/frontend/routine_plan_validation.go b/pkg/frontend/routine_plan_validation.go index 49979f0ca00ef..99ae6506cff28 100644 --- a/pkg/frontend/routine_plan_validation.go +++ b/pkg/frontend/routine_plan_validation.go @@ -7,6 +7,7 @@ package frontend import ( "context" + "errors" "fmt" "sort" "strconv" @@ -30,19 +31,20 @@ const ( ) type routinePlanCatalogState struct { - activeRevision uint64 - namespaceVersion uint64 - databaseID uint64 - revision uint64 - language string - volatility string - nullPolicy string - fingerprint string - artifactDigest string - environmentDigest string - securityType string - identityChecked bool - identityValid bool + namespaceFingerprint string + activeRevision uint64 + namespaceVersion uint64 + databaseID uint64 + revision uint64 + language string + volatility string + nullPolicy string + fingerprint string + artifactDigest string + environmentDigest string + securityType string + identityChecked bool + identityValid bool } func cachedRoutinePlanDependenciesCurrent(ses *Session, cached *cachedPlan) bool { @@ -165,10 +167,17 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan if ses == nil { return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation has no session") } - accountID := ses.GetAccountId() + var snapshot *planpb.Snapshot + if tcc := ses.GetTxnCompileCtx(); tcc != nil { + snapshot = tcc.GetSnapshot() + } + accountID := routineCatalogAccountID(ses.GetAccountId(), snapshot) ids := make([]uint64, 0, len(dependencies)) seen := make(map[uint64]struct{}, len(dependencies)) for _, dependency := range dependencies { + if dependency != nil && dependency.NamespaceFingerprint == "" { + return true, nil + } if err := validateRoutinePlanDependencyShape(dependency, accountID); err != nil { return false, err } @@ -191,15 +200,31 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan // implemented for both client and background sessions; rejecting the latter // here would make a valid typed routine fail only when a statement is // executed through a nested frontend pipeline. - bh := ses.GetBackgroundExec(ctx) + + useCallerTxn := resolvesUdfInCallerTxn(ctx) + var bh BackgroundExec + if useCallerTxn { + bh = ses.GetShareTxnBackgroundExec(ctx, false) + } else { + bh = ses.GetBackgroundExec(ctx) + } defer bh.Close() - if err = bh.Exec(ctx, "begin;"); err != nil { - return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation could not start: %w", err) + if !useCallerTxn { + if err = bh.Exec(ctx, "begin;"); err != nil { + return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation could not start: %w", err) + } + defer func() { err = finishTxn(ctx, bh, err) }() } - defer func() { err = finishTxn(ctx, bh, err) }() + defer pinRoutineCatalogReads(bh)() bh.ClearExecResultSet() query := routinePlanCatalogSQL(ids, accountID) + if snapshot != nil && snapshot.TS != nil { + for _, table := range []string{"mo_user_defined_function", "mo_database", "mo_function_revisions"} { + name := "mo_catalog." + table + query = strings.ReplaceAll(query, name+" ", fmt.Sprintf("%s {MO_TS = %d} ", name, snapshot.TS.PhysicalTime)) + } + } if err = bh.Exec(ctx, query); err != nil { return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation failed: %w", err) } @@ -207,10 +232,13 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan if err != nil { return false, err } - catalogResult, err := exactlyOneCatalogResultSet(ctx, rows, "routine dependency catalog") + catalogResult, err := candidateCatalogResultSet(rows, "routine dependency catalog") if err != nil { return false, err } + if catalogResult == nil { + return true, nil + } states := make(map[uint64]routinePlanCatalogState, len(rows)) if catalogResult.GetRowCount() != 0 { for row := uint64(0); row < catalogResult.GetRowCount(); row++ { @@ -339,6 +367,17 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan } } } + namespaces, namespaceErr := readRoutineNamespaces(ctx, bh, ids, snapshot) + if errors.Is(namespaceErr, errRoutineNamespaceBudget) { + return true, nil + } + if namespaceErr != nil { + return false, namespaceErr + } + for id, state := range states { + state.namespaceFingerprint = namespaces[id] + states[id] = state + } return routinePlanDependenciesChanged(dependencies, states), nil } @@ -450,7 +489,7 @@ func validateRoutinePlanDependencyShape(dependency *planpb.RoutinePlanDependency return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency has an invalid catalog identity") } if dependency.ContractVersion != udf.RoutinePlanContractVersion || - !udf.IsSHA256Digest(dependency.DefinitionFingerprint) { + !udf.IsSHA256Digest(dependency.DefinitionFingerprint) || !udf.IsSHA256Digest(dependency.NamespaceFingerprint) { return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency contract is incomplete") } if dependency.Volatility == "" || dependency.NullPolicy == "" || !dependency.MayError || dependency.Leakproof { @@ -497,7 +536,8 @@ func routinePlanDependenciesChanged( if expectedSecurityMode == "" { return true } - if state.activeRevision != ref.Revision || state.revision != ref.Revision || + if state.namespaceFingerprint != dependency.NamespaceFingerprint || !udf.IsSHA256Digest(dependency.NamespaceFingerprint) || + state.activeRevision != ref.Revision || state.revision != ref.Revision || state.databaseID != ref.DatabaseId || state.namespaceVersion != ref.NamespaceVersion || state.volatility != dependency.Volatility || diff --git a/pkg/frontend/routine_plan_validation_test.go b/pkg/frontend/routine_plan_validation_test.go index bcc9cdc1c6c22..22369c04d2597 100644 --- a/pkg/frontend/routine_plan_validation_test.go +++ b/pkg/frontend/routine_plan_validation_test.go @@ -39,6 +39,7 @@ func testRoutinePlanDependency() *planpb.RoutinePlanDependency { }, Language: udf.LanguagePython, ContractVersion: udf.PythonPlanContractVersion, + NamespaceFingerprint: strings.Repeat("d", 64), DefinitionFingerprint: strings.Repeat("a", 64), ArtifactDigest: strings.Repeat("b", 64), EnvironmentDigest: strings.Repeat("c", 64), @@ -52,17 +53,18 @@ func testRoutinePlanDependency() *planpb.RoutinePlanDependency { func testRoutinePlanState() routinePlanCatalogState { return routinePlanCatalogState{ - activeRevision: 7, - namespaceVersion: 12, - databaseID: 8, - revision: 7, - language: udf.LanguagePython, - volatility: "VOLATILE", - nullPolicy: udf.NullCallHandler, - fingerprint: strings.Repeat("a", 64), - artifactDigest: strings.Repeat("b", 64), - environmentDigest: strings.Repeat("c", 64), - securityType: "INVOKER", + namespaceFingerprint: strings.Repeat("d", 64), + activeRevision: 7, + namespaceVersion: 12, + databaseID: 8, + revision: 7, + language: udf.LanguagePython, + volatility: "VOLATILE", + nullPolicy: udf.NullCallHandler, + fingerprint: strings.Repeat("a", 64), + artifactDigest: strings.Repeat("b", 64), + environmentDigest: strings.Repeat("c", 64), + securityType: "INVOKER", } } diff --git a/pkg/pb/plan/plan.pb.go b/pkg/pb/plan/plan.pb.go index d95416fecf92f..5da253fe10795 100644 --- a/pkg/pb/plan/plan.pb.go +++ b/pkg/pb/plan/plan.pb.go @@ -17448,10 +17448,13 @@ type RoutineCall struct { // These fields are the common semantic contract. They must survive SQL // lowering and expression/plan cloning; the optimizer may only move a // routine call when the attached contract permits it. - CallsiteId string `protobuf:"bytes,11,opt,name=callsite_id,json=callsiteId,proto3" json:"callsite_id,omitempty"` - MayError bool `protobuf:"varint,12,opt,name=may_error,json=mayError,proto3" json:"may_error,omitempty"` - SecurityMode string `protobuf:"bytes,13,opt,name=security_mode,json=securityMode,proto3" json:"security_mode,omitempty"` - Leakproof bool `protobuf:"varint,14,opt,name=leakproof,proto3" json:"leakproof,omitempty"` + CallsiteId string `protobuf:"bytes,11,opt,name=callsite_id,json=callsiteId,proto3" json:"callsite_id,omitempty"` + MayError bool `protobuf:"varint,12,opt,name=may_error,json=mayError,proto3" json:"may_error,omitempty"` + SecurityMode string `protobuf:"bytes,13,opt,name=security_mode,json=securityMode,proto3" json:"security_mode,omitempty"` + Leakproof bool `protobuf:"varint,14,opt,name=leakproof,proto3" json:"leakproof,omitempty"` + // State fingerprint of the complete overload namespace at binding snapshot. + // Separate from the selected immutable FunctionRef; missing means no reuse. + NamespaceFingerprint string `protobuf:"bytes,15,opt,name=namespace_fingerprint,json=namespaceFingerprint,proto3" json:"namespace_fingerprint,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -17612,6 +17615,13 @@ func (m *RoutineCall) GetLeakproof() bool { return false } +func (m *RoutineCall) GetNamespaceFingerprint() string { + if m != nil { + return m.NamespaceFingerprint + } + return "" +} + // XXX_OneofWrappers is for the internal use of the proto package. func (*RoutineCall) XXX_OneofWrappers() []interface{} { return []interface{}{ @@ -17636,6 +17646,7 @@ type RoutinePlanDependency struct { MayError bool `protobuf:"varint,9,opt,name=may_error,json=mayError,proto3" json:"may_error,omitempty"` SecurityMode string `protobuf:"bytes,10,opt,name=security_mode,json=securityMode,proto3" json:"security_mode,omitempty"` Leakproof bool `protobuf:"varint,11,opt,name=leakproof,proto3" json:"leakproof,omitempty"` + NamespaceFingerprint string `protobuf:"bytes,12,opt,name=namespace_fingerprint,json=namespaceFingerprint,proto3" json:"namespace_fingerprint,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -17751,6 +17762,13 @@ func (m *RoutinePlanDependency) GetLeakproof() bool { return false } +func (m *RoutinePlanDependency) GetNamespaceFingerprint() string { + if m != nil { + return m.NamespaceFingerprint + } + return "" +} + // A zero version represents a legacy database without a persisted default. // Names are derived display values; identity/revision own the effective domain. type DatabaseDefaults struct { @@ -18062,1213 +18080,1215 @@ func init() { func init() { proto.RegisterFile("plan.proto", fileDescriptor_2d655ab2f7683c23) } var fileDescriptor_2d655ab2f7683c23 = []byte{ - // 19294 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0xbd, 0x6d, 0x8c, 0x1c, 0xd9, - 0x96, 0x20, 0xe4, 0xac, 0xcc, 0xaa, 0xca, 0x3c, 0xf9, 0x51, 0x51, 0xd7, 0x65, 0x3b, 0xed, 0x76, - 0xdb, 0xee, 0x68, 0x77, 0xb7, 0xdb, 0xdd, 0xed, 0xee, 0xb6, 0xfb, 0xc3, 0xdd, 0xef, 0xcd, 0xbc, - 0x97, 0x95, 0x95, 0xe5, 0x4a, 0x3b, 0x2b, 0xb3, 0x5e, 0x64, 0x96, 0xdd, 0xfd, 0x66, 0x87, 0x50, - 0x54, 0x66, 0x54, 0x55, 0x74, 0x45, 0x46, 0x64, 0x47, 0x44, 0xba, 0xaa, 0x9e, 0x16, 0xf1, 0x84, - 0x04, 0xcb, 0x00, 0x5a, 0xad, 0xb4, 0x62, 0x05, 0x42, 0x82, 0x01, 0x69, 0x85, 0xb4, 0x20, 0x21, - 0x56, 0x2b, 0x86, 0x0f, 0xf1, 0xb1, 0x80, 0xc4, 0xf2, 0x21, 0x34, 0xb0, 0xc0, 0x02, 0x8b, 0x16, - 0x98, 0xf9, 0xc1, 0x4f, 0x84, 0xf8, 0x90, 0xd8, 0x3f, 0xa0, 0x73, 0xce, 0xbd, 0xf1, 0x91, 0x99, - 0x65, 0x77, 0xbf, 0x99, 0x91, 0xf8, 0x53, 0x95, 0xf7, 0x9c, 0x73, 0x6f, 0xdc, 0xcf, 0x73, 0xcf, - 0x39, 0xf7, 0xdc, 0x73, 0x01, 0x26, 0xae, 0xe5, 0x3d, 0x98, 0x04, 0x7e, 0xe4, 0x8b, 0x02, 0xfe, - 0xbe, 0xf1, 0xd1, 0x91, 0x13, 0x1d, 0x4f, 0x0f, 0x1e, 0x0c, 0xfd, 0xf1, 0xc7, 0x47, 0xfe, 0x91, - 0xff, 0x31, 0x21, 0x0f, 0xa6, 0x87, 0x94, 0xa2, 0x04, 0xfd, 0xe2, 0x4c, 0x37, 0xc0, 0xf5, 0x87, - 0x27, 0xf2, 0xf7, 0x5a, 0xe4, 0x8c, 0xed, 0x30, 0xb2, 0xc6, 0x13, 0x06, 0xe8, 0xff, 0x69, 0x1e, - 0x0a, 0x83, 0xf3, 0x89, 0x2d, 0x6a, 0xb0, 0xe4, 0x8c, 0xea, 0xb9, 0x3b, 0xb9, 0x7b, 0xcb, 0xc6, - 0x92, 0x33, 0x12, 0x77, 0xa0, 0xec, 0xf9, 0x51, 0x77, 0xea, 0xba, 0xd6, 0x81, 0x6b, 0xd7, 0x97, - 0xee, 0xe4, 0xee, 0x15, 0x8d, 0x34, 0x48, 0xbc, 0x01, 0x25, 0x6b, 0x1a, 0xf9, 0xa6, 0xe3, 0x0d, - 0x83, 0x7a, 0x9e, 0xf0, 0x45, 0x04, 0xb4, 0xbd, 0x61, 0x20, 0x36, 0x60, 0xf9, 0xd4, 0x19, 0x45, - 0xc7, 0xf5, 0x02, 0x95, 0xc8, 0x09, 0x84, 0x86, 0x43, 0xcb, 0xb5, 0xeb, 0xcb, 0x0c, 0xa5, 0x04, - 0x42, 0x23, 0xfa, 0xc8, 0xca, 0x9d, 0xdc, 0xbd, 0x92, 0xc1, 0x09, 0x71, 0x0b, 0xc0, 0xf6, 0xa6, - 0xe3, 0x97, 0x96, 0x3b, 0xb5, 0xc3, 0xfa, 0x2a, 0xa1, 0x52, 0x10, 0x51, 0x87, 0xd5, 0xe1, 0xb1, - 0x15, 0x84, 0x76, 0x54, 0x2f, 0xde, 0xc9, 0xdd, 0xab, 0x1a, 0x2a, 0x89, 0x15, 0x9b, 0x58, 0x23, - 0x33, 0x9c, 0x58, 0x43, 0xbb, 0x5e, 0xe2, 0x8a, 0x4d, 0xac, 0x51, 0x1f, 0xd3, 0xe2, 0x73, 0xb8, - 0x3a, 0xf4, 0x5d, 0xd7, 0x8a, 0x1c, 0xdf, 0x33, 0x87, 0xbe, 0x1d, 0x0c, 0x9d, 0x03, 0xc7, 0x75, - 0xa2, 0xf3, 0x3a, 0x50, 0x29, 0x57, 0x62, 0x6c, 0x33, 0x85, 0x14, 0x3f, 0x85, 0x1b, 0x8b, 0xb3, - 0x99, 0x58, 0x81, 0x32, 0x7d, 0xa4, 0xbe, 0x30, 0x6b, 0xdf, 0x8e, 0xc4, 0x63, 0x48, 0x70, 0xe6, - 0xd8, 0x0e, 0x8e, 0x6c, 0x73, 0xe8, 0x7b, 0x87, 0xae, 0x33, 0x8c, 0xea, 0x15, 0xca, 0x9b, 0x54, - 0x6a, 0x17, 0xd1, 0x4d, 0x89, 0x15, 0x1f, 0xc0, 0x7a, 0x92, 0xf3, 0xa5, 0x1d, 0x84, 0x8e, 0xef, - 0xd5, 0xab, 0x54, 0x53, 0x2d, 0x46, 0x3c, 0x67, 0xb8, 0xfe, 0x33, 0x28, 0x8d, 0xc3, 0xa3, 0x1d, - 0xdb, 0x1a, 0xd9, 0x81, 0xb8, 0x06, 0xab, 0xe3, 0xf0, 0xc8, 0x8c, 0xac, 0x23, 0x39, 0xaa, 0x2b, - 0xe3, 0xf0, 0x68, 0x60, 0x1d, 0x89, 0xeb, 0x50, 0x24, 0xc4, 0xf9, 0x84, 0x87, 0x75, 0xd9, 0x40, - 0x42, 0x9c, 0x04, 0xfa, 0x1f, 0xae, 0xc2, 0x6a, 0xc7, 0x89, 0xec, 0xc0, 0x72, 0xc5, 0x55, 0x58, - 0x71, 0x42, 0x6f, 0xea, 0xba, 0x94, 0xbd, 0x68, 0xc8, 0x94, 0xb8, 0x0a, 0xcb, 0xce, 0xe3, 0x97, - 0x96, 0xcb, 0x79, 0x77, 0x2e, 0x19, 0x9c, 0x14, 0x75, 0x58, 0x71, 0x3e, 0xfd, 0x02, 0x11, 0x79, - 0x89, 0x90, 0x69, 0xc2, 0x3c, 0x7a, 0x88, 0x98, 0x42, 0x8c, 0xa1, 0x34, 0x61, 0xbe, 0xf8, 0x0c, - 0x31, 0x38, 0x21, 0xf2, 0x84, 0xa1, 0x34, 0x7e, 0x65, 0x4a, 0x5f, 0xc1, 0x39, 0x51, 0xc5, 0xaf, - 0x4c, 0xd5, 0x57, 0xa6, 0xfc, 0x95, 0x55, 0x89, 0x90, 0x69, 0xc2, 0xf0, 0x57, 0x8a, 0x31, 0x26, - 0xfe, 0xca, 0x94, 0xbf, 0x82, 0x93, 0xa1, 0x40, 0x18, 0xfe, 0xca, 0x06, 0x14, 0x46, 0x08, 0xc7, - 0xa1, 0xcf, 0xed, 0x5c, 0x32, 0x28, 0x85, 0xd0, 0x10, 0xa1, 0x38, 0xaa, 0x25, 0x84, 0x86, 0x12, - 0x7a, 0x80, 0x50, 0x1a, 0x2f, 0x84, 0x1e, 0x48, 0xe8, 0x21, 0x42, 0x71, 0x48, 0x96, 0x10, 0x8a, - 0x29, 0x71, 0x03, 0x56, 0x47, 0x56, 0x64, 0x23, 0xa2, 0x26, 0x9b, 0xac, 0x00, 0x88, 0xc3, 0x45, - 0x88, 0xb8, 0x35, 0xd9, 0x68, 0x05, 0x10, 0x3a, 0x94, 0x91, 0x4c, 0xe1, 0x35, 0x89, 0x4f, 0x03, - 0xc5, 0xe7, 0x50, 0x19, 0xd9, 0x43, 0x67, 0x6c, 0xb9, 0xdc, 0xa6, 0xf5, 0x3b, 0xb9, 0x7b, 0xe5, - 0x87, 0x6b, 0x0f, 0x88, 0x4d, 0xc4, 0x98, 0x9d, 0x4b, 0x46, 0x86, 0x4c, 0x3c, 0x86, 0xaa, 0x4c, - 0x7f, 0xfa, 0x90, 0x3a, 0x56, 0x50, 0x3e, 0x2d, 0x93, 0xef, 0xd3, 0x87, 0x8f, 0x77, 0x2e, 0x19, - 0x59, 0x42, 0x71, 0x17, 0x2a, 0x31, 0xd7, 0xc0, 0x8c, 0x97, 0x65, 0xad, 0x32, 0x50, 0x6c, 0xd6, - 0x77, 0xa1, 0xef, 0x21, 0xc1, 0x86, 0xec, 0x37, 0x05, 0x10, 0x77, 0x00, 0x46, 0xf6, 0xa1, 0x35, - 0x75, 0x23, 0x44, 0x5f, 0x91, 0x1d, 0x98, 0x82, 0x89, 0x5b, 0x50, 0x9a, 0x4e, 0xb0, 0x95, 0xcf, - 0x2d, 0xb7, 0x7e, 0x55, 0x12, 0x24, 0x20, 0x2c, 0x1d, 0x97, 0x3e, 0x62, 0xaf, 0xc9, 0xd1, 0x55, - 0x00, 0x1c, 0xde, 0x97, 0xf6, 0x10, 0x51, 0x75, 0xf9, 0x61, 0x99, 0x46, 0xc6, 0xe2, 0x84, 0x9b, - 0x8e, 0x57, 0xbf, 0x4e, 0x33, 0x98, 0x13, 0xe2, 0x26, 0xe4, 0xc3, 0x60, 0x58, 0xbf, 0x41, 0xed, - 0x07, 0x6e, 0x7f, 0xeb, 0x6c, 0x12, 0x18, 0x08, 0x16, 0x6f, 0x43, 0xd5, 0x09, 0xcd, 0xd0, 0x0e, - 0x1c, 0xcb, 0x75, 0x7e, 0x65, 0x8f, 0xea, 0x6f, 0x50, 0xde, 0x8a, 0x13, 0xf6, 0x63, 0x98, 0xf8, - 0x1a, 0x2a, 0x2e, 0x2f, 0x13, 0xf3, 0xd0, 0x0f, 0xc6, 0xf5, 0x9b, 0x77, 0x72, 0xf7, 0x6a, 0x0f, - 0xaf, 0x71, 0x59, 0xfd, 0x28, 0x70, 0xbc, 0x23, 0xb9, 0x8c, 0xb6, 0xfd, 0x60, 0x6c, 0x94, 0xdd, - 0x24, 0x81, 0x1f, 0x08, 0x89, 0xc2, 0x0c, 0xfd, 0x69, 0x30, 0xb4, 0xeb, 0x6f, 0xd2, 0x6a, 0xae, - 0x30, 0xb0, 0x4f, 0x30, 0xf1, 0x33, 0xb8, 0x29, 0x07, 0xc1, 0x54, 0x1f, 0x0a, 0xec, 0xef, 0xa7, - 0x4e, 0x60, 0x87, 0xe6, 0xcb, 0xc7, 0x0f, 0xeb, 0xb7, 0xa8, 0x52, 0xd7, 0x25, 0x8d, 0xfc, 0x96, - 0x21, 0x29, 0x9e, 0x3f, 0x7e, 0xb8, 0xb9, 0x0a, 0xcb, 0xc4, 0x27, 0xf5, 0x9b, 0x50, 0xdc, 0xb3, - 0x02, 0x6b, 0x6c, 0xd8, 0x87, 0x42, 0x83, 0xfc, 0xc4, 0x0f, 0x25, 0x3b, 0xc0, 0x9f, 0xfa, 0x9f, - 0x87, 0x95, 0xe7, 0x56, 0x80, 0x38, 0x01, 0x05, 0xcf, 0x1a, 0xdb, 0x84, 0x2c, 0x19, 0xf4, 0x1b, - 0x59, 0x40, 0x78, 0x1e, 0x46, 0xf6, 0x58, 0xb2, 0x7f, 0x99, 0x42, 0xf8, 0x91, 0xeb, 0x1f, 0xc8, - 0xa5, 0x5e, 0x34, 0x64, 0x4a, 0x3c, 0x80, 0xcb, 0x07, 0xfe, 0xd4, 0x1b, 0x99, 0xb2, 0x81, 0x23, - 0x7f, 0x6c, 0x39, 0x1e, 0xad, 0xfa, 0xaa, 0xb1, 0x4e, 0x28, 0xee, 0x9c, 0x2d, 0x42, 0xe8, 0xff, - 0x70, 0x0e, 0x56, 0x9a, 0xbe, 0x8b, 0x9f, 0xbf, 0x06, 0xab, 0x81, 0xed, 0x9a, 0x49, 0xf5, 0x56, - 0x02, 0xdb, 0xdd, 0xf3, 0x43, 0x44, 0x0c, 0x7d, 0x46, 0x30, 0xb3, 0x5a, 0x19, 0xfa, 0x84, 0x50, - 0x15, 0xce, 0xa7, 0x2a, 0x7c, 0x1d, 0x8a, 0xd1, 0x81, 0x6b, 0x12, 0xbc, 0x40, 0xf0, 0xd5, 0xe8, - 0xc0, 0xed, 0x22, 0xea, 0x1a, 0xac, 0x8e, 0x0e, 0x18, 0xb3, 0x4c, 0x98, 0x95, 0xd1, 0x01, 0x22, - 0xf4, 0xaf, 0xa0, 0x64, 0x58, 0xa7, 0xb2, 0x1a, 0x57, 0x60, 0x05, 0x0b, 0x90, 0x3b, 0x61, 0xc1, - 0x58, 0x8e, 0x0e, 0xdc, 0xf6, 0x08, 0xc1, 0x58, 0x09, 0x67, 0x44, 0x75, 0x28, 0x18, 0xcb, 0x43, - 0xdf, 0x6d, 0x8f, 0xf4, 0x01, 0x40, 0xd3, 0x0f, 0x82, 0xdf, 0xb8, 0x09, 0x1b, 0xb0, 0x3c, 0xb2, - 0x27, 0xd1, 0x31, 0x73, 0x4c, 0x83, 0x13, 0xfa, 0x7d, 0x28, 0xe2, 0x74, 0xec, 0x38, 0x61, 0x24, - 0x6e, 0x41, 0xc1, 0x75, 0xc2, 0xa8, 0x9e, 0xbb, 0x93, 0x9f, 0x99, 0xac, 0x04, 0xd7, 0xef, 0x40, - 0x71, 0xd7, 0x3a, 0x7b, 0x8e, 0x23, 0x8d, 0xa5, 0xd1, 0x90, 0xcb, 0x21, 0x94, 0xe3, 0x5f, 0x01, - 0x18, 0x58, 0xc1, 0x91, 0x1d, 0x11, 0x83, 0xff, 0x3f, 0x72, 0x50, 0xee, 0x4f, 0x0f, 0xbe, 0x9f, - 0xda, 0xc1, 0x39, 0xd6, 0xf9, 0x1e, 0xe4, 0xa3, 0xf3, 0x09, 0xe5, 0xa8, 0x3d, 0xbc, 0x2a, 0xe7, - 0x6f, 0x82, 0x7f, 0x80, 0x99, 0x0c, 0x24, 0xc1, 0x46, 0x78, 0xfe, 0xc8, 0x56, 0x7d, 0xb0, 0x6c, - 0xac, 0x60, 0xb2, 0x3d, 0x42, 0xc1, 0xc1, 0x9f, 0xc8, 0x51, 0x58, 0xf2, 0x27, 0xe2, 0x0e, 0x2c, - 0x0f, 0x8f, 0x1d, 0x77, 0x44, 0x03, 0x90, 0xad, 0x33, 0x23, 0x70, 0x94, 0x02, 0xff, 0xd4, 0x0c, - 0x9d, 0x5f, 0x29, 0x41, 0x60, 0x35, 0xf0, 0x4f, 0xfb, 0xce, 0xaf, 0x6c, 0x7d, 0x20, 0xa5, 0x11, - 0x80, 0x95, 0x7e, 0xb3, 0xd1, 0x69, 0x18, 0xda, 0x25, 0xfc, 0xdd, 0xfa, 0xa6, 0xdd, 0x1f, 0xf4, - 0xb5, 0x9c, 0xa8, 0x01, 0x74, 0x7b, 0x03, 0x53, 0xa6, 0x97, 0xc4, 0x0a, 0x2c, 0xb5, 0xbb, 0x5a, - 0x1e, 0x69, 0x10, 0xde, 0xee, 0x6a, 0x05, 0xb1, 0x0a, 0xf9, 0x46, 0xf7, 0x5b, 0x6d, 0x99, 0x7e, - 0x74, 0x3a, 0xda, 0x8a, 0xfe, 0xf7, 0x97, 0xa0, 0xd4, 0x3b, 0xf8, 0xce, 0x1e, 0x46, 0xd8, 0x66, - 0x9c, 0xd5, 0x76, 0xf0, 0xd2, 0x0e, 0xa8, 0xd9, 0x79, 0x43, 0xa6, 0xb0, 0x21, 0xa3, 0x03, 0x6a, - 0x5c, 0xde, 0x58, 0x1a, 0x1d, 0x10, 0xdd, 0xf0, 0xd8, 0x1e, 0x5b, 0xd4, 0x38, 0xa4, 0xa3, 0x14, - 0xae, 0x22, 0xff, 0xe0, 0x3b, 0x6a, 0x5e, 0xde, 0xc0, 0x9f, 0xe2, 0x36, 0x94, 0xb9, 0x8c, 0xf4, - 0xfc, 0x02, 0x06, 0xcd, 0x4e, 0xbe, 0x95, 0xf4, 0xe4, 0xa3, 0x9c, 0x54, 0x2a, 0x23, 0xa5, 0x94, - 0xc3, 0xa0, 0xae, 0x9c, 0xd1, 0xfe, 0xc1, 0x77, 0x8c, 0x2d, 0xf2, 0x8c, 0xf6, 0x0f, 0xbe, 0x23, - 0xd4, 0x07, 0xb0, 0x1e, 0x4e, 0x0f, 0xc2, 0x61, 0xe0, 0x4c, 0x48, 0x3a, 0x20, 0x9a, 0x12, 0xd1, - 0x68, 0x69, 0x04, 0x11, 0xdf, 0x83, 0xe2, 0x64, 0x7a, 0x60, 0x3a, 0xde, 0xa1, 0x4f, 0xbb, 0x5d, - 0xf9, 0x61, 0x95, 0x07, 0x66, 0x6f, 0x7a, 0xd0, 0xf6, 0x0e, 0x7d, 0x63, 0x75, 0xc2, 0x3f, 0x84, - 0x0e, 0x55, 0xcf, 0x8f, 0x4c, 0x14, 0x1a, 0xcd, 0xb1, 0x1d, 0x59, 0x52, 0xb8, 0x41, 0xd1, 0xaf, - 0xe3, 0x0f, 0x4f, 0x76, 0xed, 0xc8, 0x12, 0xf7, 0xa1, 0x18, 0x7a, 0xd6, 0x24, 0x3c, 0xf6, 0x59, - 0x7e, 0x29, 0x3f, 0xac, 0xc9, 0xb9, 0x23, 0xa1, 0x46, 0x8c, 0xd7, 0xdf, 0x85, 0x55, 0xf9, 0x0d, - 0x14, 0xcc, 0x22, 0xdb, 0xb3, 0xbc, 0xc8, 0x8c, 0x45, 0xcd, 0x22, 0x03, 0xda, 0x23, 0xfd, 0x6f, - 0xe4, 0x40, 0xeb, 0xa7, 0xaa, 0x4d, 0x1f, 0x5a, 0xc4, 0x95, 0xde, 0x04, 0xb0, 0x86, 0x43, 0x7f, - 0xca, 0xc5, 0xf0, 0x64, 0x2c, 0x49, 0x48, 0x7b, 0x94, 0xee, 0xeb, 0x7c, 0xa6, 0xaf, 0xdf, 0x82, - 0x8a, 0xca, 0x97, 0x62, 0x10, 0x65, 0x09, 0x53, 0xbd, 0x1d, 0x4e, 0x33, 0x5c, 0x62, 0x35, 0x9c, - 0x72, 0xee, 0xab, 0xb0, 0x42, 0x72, 0x69, 0xa8, 0x46, 0x90, 0x53, 0xfa, 0xdf, 0xc9, 0x41, 0xb5, - 0xed, 0x8d, 0xec, 0xb3, 0xfe, 0xd0, 0xf2, 0x54, 0x07, 0x3a, 0xa1, 0xe9, 0x20, 0xcc, 0x0c, 0x87, - 0x96, 0x27, 0xe5, 0xa7, 0xb2, 0x13, 0xc6, 0x74, 0xd8, 0x06, 0x26, 0xa0, 0x4f, 0x2d, 0x51, 0x89, - 0x25, 0x82, 0xd0, 0xc7, 0xde, 0x85, 0xb5, 0x03, 0xdb, 0xf5, 0xbd, 0x23, 0x33, 0xf2, 0x4d, 0x96, - 0x8d, 0xb9, 0x2d, 0x55, 0x06, 0x0f, 0xfc, 0x01, 0xc9, 0xc8, 0x1b, 0xb0, 0x3c, 0xb1, 0x82, 0x28, - 0xac, 0x17, 0xee, 0xe4, 0x71, 0xc9, 0x53, 0x02, 0xbb, 0xd9, 0x09, 0xcd, 0xa9, 0xe7, 0x7c, 0x3f, - 0xe5, 0x66, 0x14, 0x8d, 0xa2, 0x13, 0xee, 0x53, 0x5a, 0xdc, 0x03, 0x8d, 0xbf, 0x4c, 0xc5, 0xa6, - 0xe7, 0x64, 0x8d, 0xe0, 0x54, 0x30, 0x31, 0xc6, 0xff, 0x3a, 0x0f, 0xc5, 0xed, 0xa9, 0x37, 0xc4, - 0xc1, 0x10, 0x6f, 0x43, 0xe1, 0x70, 0xea, 0x0d, 0xa9, 0x2d, 0xb1, 0xb4, 0x11, 0xaf, 0x29, 0x83, - 0x90, 0xc8, 0xad, 0xac, 0xe0, 0x08, 0xb9, 0xdc, 0x1c, 0xb7, 0x42, 0x38, 0x8d, 0xdc, 0xd1, 0x11, - 0x89, 0xbe, 0xce, 0x11, 0xb5, 0xa8, 0x62, 0x94, 0xac, 0xa3, 0xa3, 0x26, 0x01, 0x44, 0x03, 0xd6, - 0x12, 0x34, 0xcb, 0xa7, 0x05, 0x62, 0x4c, 0xd7, 0xb9, 0xa4, 0xc6, 0xd1, 0x51, 0x60, 0x1f, 0x59, - 0x91, 0xcd, 0xf4, 0xc4, 0x9b, 0xaa, 0x71, 0x76, 0xe2, 0x1b, 0x9f, 0xc0, 0x46, 0x78, 0xee, 0x45, - 0xd6, 0x99, 0x69, 0x9f, 0x4d, 0x5c, 0x67, 0xe8, 0x44, 0xe6, 0xd0, 0x0a, 0x23, 0xd9, 0x0b, 0x82, - 0x71, 0x2d, 0x89, 0x6a, 0x5a, 0x61, 0x24, 0x3e, 0x83, 0x4a, 0xe0, 0x4f, 0x23, 0xc7, 0xb3, 0xcd, - 0xa1, 0xe5, 0xb2, 0xbc, 0x59, 0x7e, 0xb8, 0xce, 0x5f, 0x34, 0x18, 0xd3, 0xb4, 0x5c, 0xd7, 0x28, - 0x07, 0x49, 0x42, 0xff, 0x37, 0x72, 0xdc, 0x37, 0xdb, 0xae, 0x75, 0x24, 0x8a, 0x50, 0xe8, 0xf6, - 0xba, 0x2d, 0xed, 0x92, 0xa8, 0x40, 0xb1, 0xdd, 0x1d, 0xb4, 0x8c, 0x6e, 0xa3, 0xa3, 0xe5, 0x88, - 0x89, 0x0d, 0x1a, 0x9b, 0x9d, 0x96, 0xb6, 0x84, 0x98, 0xe7, 0xbd, 0x4e, 0x63, 0xd0, 0xee, 0xb4, - 0xb4, 0x02, 0x63, 0x8c, 0x76, 0x73, 0xa0, 0x15, 0x85, 0x06, 0x95, 0x3d, 0xa3, 0xb7, 0xb5, 0xdf, - 0x6c, 0x99, 0xdd, 0xfd, 0x4e, 0x47, 0xd3, 0xc4, 0x65, 0x58, 0x8b, 0x21, 0x3d, 0x06, 0xde, 0xc1, - 0x2c, 0xcf, 0x1b, 0x46, 0xc3, 0x78, 0xa2, 0xfd, 0x5c, 0x14, 0x21, 0xdf, 0x78, 0xf2, 0x44, 0xfb, - 0x35, 0xf2, 0xc3, 0xd2, 0x8b, 0x76, 0xd7, 0x7c, 0xde, 0xe8, 0xec, 0xb7, 0xb4, 0x5f, 0x2f, 0xa9, - 0x74, 0xcf, 0xd8, 0x6a, 0x19, 0xda, 0xaf, 0x0b, 0x62, 0x1d, 0x2a, 0xbf, 0xec, 0x75, 0x5b, 0xbb, - 0x8d, 0xbd, 0x3d, 0xaa, 0xc8, 0xaf, 0x8b, 0xfa, 0x7f, 0xb2, 0x0c, 0xd7, 0xf6, 0x02, 0x7b, 0x62, - 0x05, 0xf6, 0xa8, 0x3b, 0x1d, 0xdb, 0x81, 0x33, 0xc4, 0xa5, 0x36, 0xb2, 0x22, 0x4b, 0xdc, 0x80, - 0xe2, 0xa1, 0xe5, 0xba, 0x07, 0xd6, 0xf0, 0x44, 0xce, 0xda, 0x38, 0xcd, 0x5a, 0x55, 0x60, 0x8d, - 0x53, 0xfb, 0x58, 0x91, 0x00, 0xb8, 0x93, 0xbd, 0x07, 0x6b, 0x8a, 0x50, 0x89, 0x35, 0x2c, 0x1a, - 0xd4, 0x14, 0x58, 0x0a, 0x36, 0x9f, 0xc3, 0xb5, 0x19, 0x42, 0x53, 0x6d, 0x2b, 0xac, 0x29, 0x6e, - 0x64, 0x33, 0x74, 0x79, 0x93, 0x59, 0x90, 0x4d, 0x6d, 0xa9, 0xcb, 0x8b, 0xb2, 0x35, 0x79, 0x83, - 0xfd, 0x02, 0xae, 0x4d, 0x02, 0xff, 0xa5, 0x83, 0xda, 0x11, 0x89, 0x50, 0xe1, 0xd4, 0x95, 0x33, - 0x62, 0x85, 0xaa, 0x77, 0x25, 0x85, 0x36, 0x08, 0x4b, 0x93, 0x62, 0x71, 0xbe, 0x89, 0x6d, 0x07, - 0xc4, 0xa2, 0x17, 0xe5, 0xdb, 0xb3, 0xed, 0x40, 0x6c, 0xc1, 0xed, 0x0b, 0xf2, 0xd1, 0x74, 0xc6, - 0x56, 0x16, 0xa9, 0xba, 0x6f, 0x2c, 0xcc, 0x8f, 0x53, 0xb8, 0x3d, 0x12, 0x0d, 0x78, 0xf3, 0xa2, - 0x52, 0x58, 0xa7, 0x2e, 0x51, 0x19, 0x37, 0x16, 0x96, 0xf1, 0x82, 0x14, 0xed, 0x57, 0x14, 0xc1, - 0x0a, 0x38, 0xbc, 0xa2, 0x88, 0x3e, 0x69, 0xe5, 0x3f, 0x85, 0x8d, 0x8c, 0x18, 0xa7, 0xc6, 0xb5, - 0x3c, 0xb7, 0xad, 0x8b, 0x30, 0x25, 0xd4, 0xc9, 0x71, 0x7e, 0x00, 0x97, 0x9d, 0x43, 0xd4, 0x17, - 0xcd, 0xa1, 0x3f, 0x1e, 0xa3, 0xee, 0x4a, 0xa2, 0x09, 0x2b, 0xbb, 0xeb, 0x8c, 0x6a, 0x12, 0x86, - 0x85, 0x97, 0xcf, 0xe0, 0xea, 0x24, 0xf0, 0x91, 0x9d, 0xd8, 0xa3, 0x6c, 0x96, 0x2a, 0x65, 0xd9, - 0x88, 0xb1, 0xa9, 0x5c, 0xfa, 0x3f, 0xbf, 0x02, 0x05, 0xac, 0x82, 0xd0, 0x13, 0x39, 0x26, 0xae, - 0x1b, 0xf6, 0xe6, 0x66, 0xe1, 0x6f, 0xfd, 0xbd, 0xdb, 0x97, 0x58, 0x82, 0x79, 0x0b, 0xf2, 0xae, - 0x13, 0xd1, 0xd4, 0x8d, 0x77, 0x3f, 0x29, 0x39, 0xef, 0x5c, 0x32, 0x10, 0x27, 0x6e, 0x41, 0x8e, - 0x45, 0x99, 0x78, 0x43, 0x53, 0xb2, 0xf3, 0xce, 0x25, 0x23, 0x37, 0x11, 0x37, 0x21, 0xf7, 0x52, - 0xca, 0x35, 0x15, 0xc6, 0xb3, 0xf4, 0x8c, 0xd8, 0x97, 0xe2, 0x0e, 0xe4, 0x87, 0x3e, 0xab, 0xb2, - 0x31, 0x9e, 0x65, 0x43, 0x2c, 0x7f, 0xe8, 0xbb, 0xe2, 0x6d, 0xc8, 0x07, 0xd6, 0xa9, 0xe4, 0x31, - 0x92, 0x89, 0xc6, 0xc2, 0x27, 0x12, 0x05, 0xd6, 0x29, 0x56, 0xe2, 0x90, 0xa6, 0x59, 0x5c, 0x09, - 0xc5, 0x85, 0xf1, 0x33, 0x87, 0xe2, 0x0e, 0xe4, 0x4e, 0x69, 0x1a, 0xc5, 0xda, 0xdb, 0x0b, 0xc7, - 0x1b, 0xf9, 0xa7, 0xfd, 0x89, 0x3d, 0x44, 0x8a, 0x53, 0xf1, 0x0e, 0xe4, 0xc3, 0xe9, 0x01, 0x4d, - 0x93, 0x98, 0x95, 0xa5, 0xa4, 0x3a, 0xfc, 0x50, 0x38, 0x3d, 0x10, 0xef, 0x42, 0x61, 0xe8, 0x07, - 0x81, 0x94, 0x07, 0x34, 0x55, 0x61, 0x25, 0xd0, 0xa2, 0x36, 0x8b, 0x78, 0xfc, 0x60, 0x24, 0x87, - 0x5d, 0x12, 0x25, 0x12, 0x25, 0x7e, 0x30, 0x12, 0x77, 0xa5, 0x98, 0x9a, 0x91, 0x05, 0x94, 0x10, - 0x8b, 0xe5, 0x20, 0x16, 0x07, 0x69, 0x6c, 0x9d, 0xd1, 0x80, 0xc6, 0x44, 0x4a, 0x7a, 0xc5, 0x3a, - 0x8d, 0xad, 0x33, 0x71, 0x17, 0xf2, 0x2f, 0xed, 0x21, 0x69, 0xcd, 0xf1, 0xd7, 0xe4, 0x20, 0x3d, - 0xa7, 0xe6, 0x21, 0x9a, 0x76, 0x23, 0xdf, 0x1d, 0x91, 0x02, 0x1d, 0x8f, 0xe5, 0xb6, 0xef, 0x8e, - 0x9e, 0xd3, 0x58, 0x12, 0x52, 0x3c, 0x82, 0xd2, 0xc8, 0x9e, 0xd8, 0xde, 0xc8, 0xf6, 0x22, 0x52, - 0x0d, 0xcb, 0x0f, 0x2f, 0x33, 0xe5, 0x96, 0x02, 0x63, 0x15, 0x51, 0xd1, 0x8c, 0xe9, 0xc4, 0x07, - 0x50, 0x08, 0x5d, 0x3f, 0x22, 0x8d, 0xb1, 0xfc, 0xf0, 0x4a, 0xd2, 0x27, 0x36, 0x9b, 0x5a, 0xfa, - 0xae, 0x4f, 0x0d, 0x42, 0x22, 0x54, 0x0b, 0xac, 0xe9, 0x19, 0xae, 0x6a, 0x8d, 0x05, 0x78, 0x6b, - 0x7a, 0xd6, 0x1e, 0xa1, 0x80, 0xe8, 0x8d, 0x5e, 0x92, 0x62, 0x9e, 0x33, 0xf0, 0xa7, 0xb8, 0x83, - 0x02, 0xa2, 0x6b, 0x0f, 0x23, 0xe7, 0xa5, 0x13, 0x9d, 0x93, 0xea, 0x9d, 0x33, 0xd2, 0x20, 0xb1, - 0x03, 0xda, 0x44, 0x32, 0x65, 0xd3, 0x63, 0xae, 0x4c, 0x8a, 0x76, 0xf9, 0xe1, 0x9b, 0x72, 0x22, - 0x2e, 0x66, 0xd9, 0xc6, 0xda, 0x24, 0x8b, 0xd8, 0x5c, 0x81, 0x82, 0x7d, 0x36, 0x09, 0x9e, 0x16, - 0x8a, 0x1b, 0x5a, 0x5d, 0x7f, 0x0a, 0x6b, 0x33, 0xb5, 0xc7, 0x5d, 0x78, 0x12, 0xf8, 0x47, 0xc8, - 0xca, 0xa5, 0x18, 0x56, 0x35, 0x4a, 0x12, 0xd2, 0x1e, 0x89, 0x3a, 0xac, 0xfa, 0xc1, 0xc8, 0xf1, - 0xa4, 0x85, 0xa7, 0x6a, 0xa8, 0xa4, 0xfe, 0x17, 0x97, 0xa0, 0x9a, 0xe9, 0xba, 0xd7, 0x15, 0xf5, - 0x36, 0x54, 0xfd, 0xe1, 0x70, 0x1a, 0x04, 0xb6, 0x37, 0x8c, 0x35, 0x87, 0xaa, 0x51, 0x49, 0x80, - 0x6d, 0xd2, 0x06, 0xc2, 0xc8, 0x3a, 0x22, 0x7c, 0x9e, 0x3f, 0x48, 0xe9, 0xf6, 0x48, 0x7c, 0x82, - 0x1a, 0xd5, 0x68, 0x3a, 0xb4, 0x03, 0x29, 0x08, 0x5c, 0xa4, 0xa1, 0x28, 0x32, 0xa1, 0xc3, 0x8a, - 0xe3, 0x4d, 0xa6, 0x11, 0x6e, 0x0b, 0xb3, 0x32, 0x88, 0xc4, 0xa0, 0xfe, 0xef, 0x1e, 0xa3, 0x18, - 0x37, 0x4b, 0x80, 0x60, 0x71, 0x1f, 0x60, 0xe8, 0x8f, 0x27, 0x56, 0xe0, 0x84, 0xbe, 0x27, 0x97, - 0x61, 0x9a, 0x28, 0x85, 0xd5, 0xff, 0x99, 0x1c, 0x88, 0x54, 0xef, 0xee, 0x71, 0xc3, 0x71, 0xa7, - 0x0c, 0x7c, 0x3f, 0xa2, 0x8d, 0x4d, 0x89, 0xb9, 0x08, 0xc0, 0xbd, 0x4c, 0x7c, 0x0a, 0x65, 0xaa, - 0x07, 0x6d, 0x08, 0x33, 0xa2, 0x52, 0x8a, 0x63, 0x01, 0x11, 0x21, 0x20, 0x14, 0x8f, 0xa0, 0xe2, - 0x4f, 0xa3, 0x24, 0x4f, 0xfe, 0x82, 0x3c, 0x65, 0xa6, 0xa2, 0x4c, 0xfa, 0xff, 0x9e, 0x03, 0x2d, - 0x3d, 0xf2, 0xd8, 0xa5, 0x38, 0x5e, 0xfe, 0xa9, 0x87, 0x7a, 0x4a, 0x52, 0xb5, 0x12, 0x41, 0xa8, - 0x6e, 0x1f, 0x43, 0xe1, 0xc4, 0xf1, 0x78, 0x98, 0x6a, 0x0f, 0xdf, 0x98, 0x9f, 0xfc, 0x58, 0xc8, - 0x83, 0x67, 0x8e, 0x37, 0x32, 0x88, 0x90, 0x8c, 0x25, 0x63, 0x1c, 0x3b, 0x65, 0x99, 0xe4, 0x01, - 0xac, 0x10, 0x50, 0x59, 0x25, 0x8f, 0xa1, 0x80, 0x59, 0x44, 0x09, 0x96, 0xdb, 0xdd, 0xbd, 0xfd, - 0x81, 0x76, 0x49, 0x54, 0xa1, 0xf4, 0xb4, 0xd7, 0xee, 0x9a, 0x7b, 0x8d, 0xb6, 0xa1, 0xe5, 0x10, - 0xf3, 0xc4, 0xe8, 0xed, 0xef, 0x69, 0x4b, 0x28, 0x0d, 0xbd, 0x68, 0x77, 0xb7, 0x7a, 0x2f, 0xcc, - 0x7e, 0x6b, 0xb0, 0xbf, 0xa7, 0xe5, 0x51, 0xe5, 0x93, 0x10, 0xa3, 0xf7, 0x42, 0x2b, 0x60, 0xba, - 0xd1, 0xef, 0xb7, 0x9f, 0x74, 0x77, 0x5b, 0xdd, 0x81, 0xb6, 0x8c, 0x99, 0x8d, 0xde, 0xfe, 0xa0, - 0xa5, 0xad, 0xe8, 0xff, 0x63, 0x2e, 0x3b, 0xdb, 0x27, 0xf6, 0x10, 0xa7, 0xb3, 0xaa, 0x1c, 0xcf, - 0x4f, 0x95, 0x44, 0x49, 0x98, 0xf6, 0x35, 0xd9, 0xb7, 0x61, 0x64, 0x4f, 0xa4, 0x5c, 0x53, 0x43, - 0x78, 0x8f, 0xc0, 0xfd, 0xc8, 0x9e, 0x90, 0x96, 0x16, 0xd9, 0x13, 0x93, 0x7a, 0x8a, 0xfb, 0xbf, - 0x6a, 0x00, 0x82, 0x7a, 0x04, 0x11, 0x9f, 0x41, 0x51, 0xce, 0x7a, 0x16, 0xc5, 0xcb, 0x0f, 0xeb, - 0x73, 0x9d, 0x27, 0x67, 0x87, 0x11, 0x53, 0x8a, 0x07, 0xb0, 0x42, 0x33, 0x5d, 0x4d, 0xd6, 0xab, - 0x8b, 0x3b, 0xdc, 0x90, 0x54, 0xfa, 0x0e, 0xac, 0x4a, 0x1e, 0x37, 0x67, 0xad, 0xbf, 0x0e, 0x45, - 0x27, 0x44, 0xc9, 0x39, 0x8c, 0xa4, 0xad, 0x66, 0xd5, 0x09, 0x9b, 0x98, 0x44, 0x15, 0x0a, 0x19, - 0x85, 0x14, 0xb7, 0xe9, 0xb7, 0xfe, 0xef, 0xe4, 0x00, 0x12, 0xae, 0x8a, 0x0c, 0xcb, 0xb5, 0x3d, - 0x65, 0x17, 0x72, 0x6d, 0x2f, 0xce, 0xb4, 0x94, 0x64, 0x9a, 0xb7, 0x8c, 0xe5, 0x17, 0x58, 0xc6, - 0xe6, 0xac, 0x5b, 0x85, 0xdf, 0xc0, 0xba, 0xb5, 0xfc, 0x1a, 0xeb, 0x96, 0x7e, 0x1d, 0x59, 0xbb, - 0x34, 0x6e, 0x8a, 0x0a, 0xe4, 0x2c, 0xa9, 0xca, 0xe7, 0x2c, 0xfd, 0x1e, 0x40, 0x62, 0xbe, 0xcc, - 0xe2, 0x30, 0xa5, 0x14, 0xfc, 0xdc, 0x81, 0xfe, 0x53, 0xa8, 0x48, 0x91, 0xcf, 0x77, 0xb7, 0xec, - 0x43, 0xf1, 0x21, 0x40, 0x9c, 0x0e, 0xa5, 0xc5, 0x25, 0xd9, 0xc5, 0xb7, 0xec, 0x43, 0x23, 0x85, - 0xd7, 0xff, 0xd7, 0x65, 0xb2, 0x5d, 0x6d, 0xb1, 0xd1, 0x48, 0x5a, 0x87, 0x72, 0x29, 0xeb, 0x50, - 0xac, 0xbb, 0x2e, 0x65, 0x2d, 0x6a, 0xc7, 0xce, 0x68, 0x64, 0x7b, 0xca, 0x72, 0xc6, 0x29, 0xdc, - 0xf6, 0x2c, 0xf7, 0x48, 0x72, 0x39, 0xa1, 0x3e, 0x3a, 0x9e, 0x04, 0x76, 0x18, 0xb2, 0x0d, 0xc6, - 0x72, 0x8f, 0x94, 0x94, 0xb3, 0xfc, 0x2a, 0x29, 0xe7, 0x3a, 0x14, 0x51, 0x7d, 0x27, 0xc3, 0x3d, - 0xcb, 0xb8, 0xab, 0xf2, 0xd0, 0x46, 0xbc, 0x07, 0xab, 0xd2, 0xe4, 0x2a, 0xf9, 0x5a, 0x55, 0x6d, - 0x87, 0x04, 0x34, 0x14, 0x96, 0x8e, 0x56, 0xfc, 0xf1, 0x18, 0xf7, 0x4d, 0x69, 0x73, 0x90, 0x49, - 0xf1, 0x01, 0x94, 0x7c, 0xcf, 0x64, 0xbb, 0xac, 0x94, 0x2f, 0xe4, 0x46, 0xde, 0xf3, 0xf6, 0x09, - 0x6a, 0x14, 0x7d, 0xf9, 0x0b, 0xab, 0xe2, 0xfa, 0xa7, 0xe6, 0xd0, 0x0a, 0x46, 0x24, 0x63, 0x14, - 0x8d, 0x55, 0xd7, 0x3f, 0x6d, 0x5a, 0xc1, 0x88, 0x6d, 0x30, 0xdf, 0x7b, 0xd3, 0x31, 0xc9, 0x15, - 0x55, 0x43, 0xa6, 0xc4, 0x4d, 0x28, 0x0d, 0xdd, 0x69, 0x18, 0xd9, 0xc1, 0xe6, 0xb9, 0x14, 0x16, - 0x13, 0x00, 0xd6, 0x6b, 0x12, 0x38, 0x63, 0x2b, 0x38, 0x97, 0x52, 0xa1, 0x4a, 0x92, 0x22, 0x7c, - 0xe2, 0x8c, 0xce, 0xd8, 0xdc, 0x6e, 0x70, 0x02, 0xe9, 0x8f, 0xe9, 0x30, 0x24, 0x24, 0x49, 0xa1, - 0x68, 0xa8, 0x24, 0x8d, 0x03, 0xfd, 0xa4, 0x9d, 0xbb, 0x64, 0xc8, 0x54, 0xc6, 0x80, 0xb8, 0x7e, - 0xa1, 0x01, 0x51, 0xcc, 0xda, 0x70, 0xfc, 0xc0, 0x39, 0x72, 0xa4, 0x05, 0xe6, 0x32, 0xdb, 0x70, - 0x18, 0x44, 0x04, 0x5f, 0x42, 0xf5, 0xc8, 0xf6, 0xec, 0xc0, 0x62, 0xd9, 0x96, 0x0d, 0xe4, 0x65, - 0x35, 0xcc, 0x4f, 0x14, 0x0a, 0xa5, 0xae, 0xca, 0x51, 0x2a, 0x85, 0xb5, 0x94, 0x5a, 0xfc, 0x15, - 0x9e, 0x2d, 0x9c, 0x12, 0xef, 0xc2, 0x9a, 0xfc, 0x62, 0x5c, 0xd9, 0xab, 0x6c, 0x1e, 0x60, 0xf0, - 0x40, 0x56, 0x79, 0x0b, 0x84, 0x52, 0x79, 0x7c, 0x77, 0x3a, 0xf6, 0x4c, 0xe2, 0xee, 0xd7, 0xd2, - 0x5b, 0x69, 0x3c, 0xa3, 0xa7, 0x63, 0x8f, 0x18, 0xbb, 0x16, 0xcc, 0x40, 0xf4, 0xef, 0x61, 0x55, - 0xce, 0x10, 0x54, 0xf0, 0x51, 0xb6, 0xc8, 0xca, 0xd9, 0xac, 0xe0, 0x23, 0x9c, 0x36, 0x7c, 0xae, - 0x18, 0xaf, 0x77, 0x39, 0xf7, 0x2b, 0x0c, 0x64, 0xdb, 0xaf, 0x78, 0x0b, 0x2a, 0xa4, 0x18, 0x58, - 0xf2, 0xdc, 0x2d, 0x2f, 0xed, 0x4b, 0x53, 0xd7, 0x6d, 0x30, 0x48, 0xef, 0x41, 0x51, 0xcd, 0xa7, - 0x3f, 0x95, 0x6f, 0xea, 0x13, 0xa8, 0xa4, 0xfb, 0xf9, 0x4f, 0xa7, 0x21, 0x6c, 0x67, 0x09, 0x23, - 0x3f, 0x88, 0x99, 0x61, 0xd1, 0x09, 0xfb, 0x94, 0xd6, 0x7f, 0x7f, 0x09, 0xca, 0x64, 0xef, 0xe9, - 0x91, 0x35, 0x4b, 0x7c, 0x08, 0x62, 0x18, 0xd8, 0x56, 0x64, 0x9b, 0xf6, 0x59, 0x14, 0x58, 0xd2, - 0xaa, 0xc3, 0x4a, 0xb6, 0xc6, 0x98, 0x16, 0x22, 0xd8, 0xb0, 0x73, 0x1b, 0xca, 0x13, 0x2b, 0x08, - 0x95, 0x45, 0x91, 0xbf, 0x0e, 0x0c, 0x92, 0xf6, 0x3c, 0xcd, 0x23, 0xb9, 0x2b, 0xf2, 0x4f, 0x6c, - 0x8f, 0x6d, 0xa9, 0x6c, 0x45, 0xae, 0x11, 0x7c, 0x80, 0xe0, 0xbe, 0xf3, 0x2b, 0xd4, 0xe3, 0x00, - 0x55, 0x3c, 0xd9, 0xd9, 0xcc, 0x61, 0x6e, 0x72, 0x83, 0x53, 0xf5, 0x7b, 0xf0, 0x3c, 0xa6, 0x31, - 0x52, 0xf4, 0xfa, 0x2f, 0x01, 0x12, 0x8c, 0xb8, 0x01, 0x57, 0x9f, 0xb7, 0xfb, 0xed, 0xcd, 0x76, - 0xa7, 0x3d, 0xf8, 0xd6, 0xdc, 0xef, 0xf6, 0xf7, 0x5a, 0xcd, 0xf6, 0x76, 0xbb, 0xb5, 0xa5, 0x5d, - 0x12, 0x57, 0x41, 0xa4, 0x70, 0xf4, 0xb3, 0xd3, 0xd2, 0x72, 0xa2, 0x0e, 0x1b, 0x29, 0x78, 0xbb, - 0xab, 0x30, 0x4b, 0xfa, 0xff, 0x90, 0x83, 0xea, 0x1e, 0x2f, 0xe0, 0x67, 0xf6, 0xf9, 0x16, 0x1f, - 0x42, 0x0c, 0x15, 0xf3, 0x2d, 0x18, 0xf4, 0x5b, 0xdc, 0x82, 0xf2, 0xe4, 0xc4, 0x3e, 0x37, 0x33, - 0x06, 0xf8, 0x12, 0x82, 0x9a, 0xc4, 0x66, 0xdf, 0x87, 0x15, 0x9f, 0x9a, 0x20, 0x15, 0xb7, 0xf5, - 0xb9, 0xb6, 0x19, 0x92, 0x40, 0xe8, 0x50, 0x8d, 0x8b, 0x4a, 0x9b, 0x00, 0x65, 0x61, 0xd4, 0xb1, - 0x1b, 0xb0, 0x8c, 0x28, 0xde, 0x93, 0x4b, 0x06, 0x27, 0xc4, 0x27, 0x50, 0x45, 0xb9, 0xcf, 0x54, - 0xd9, 0xa5, 0x0a, 0x97, 0xdd, 0x1e, 0xca, 0x48, 0xb2, 0xc7, 0x65, 0xe9, 0xff, 0x77, 0x1e, 0x8a, - 0x54, 0x07, 0xb9, 0x43, 0x38, 0xa3, 0x33, 0xb5, 0x43, 0x94, 0x8c, 0x65, 0x67, 0x84, 0x8a, 0xc2, - 0x6b, 0xac, 0x80, 0xb1, 0x75, 0x2f, 0x9f, 0xb6, 0xee, 0x25, 0x4c, 0xa1, 0x90, 0x61, 0x0a, 0x8b, - 0x0c, 0x7b, 0xcb, 0x8b, 0x0c, 0x7b, 0x38, 0xb9, 0x98, 0xc6, 0x3e, 0x73, 0x62, 0x4b, 0x08, 0x10, - 0xa8, 0x85, 0x90, 0x34, 0xff, 0x5f, 0xcd, 0xf2, 0x7f, 0x94, 0xa6, 0x70, 0x3a, 0xb8, 0x6c, 0x8d, - 0x2e, 0x1a, 0x2a, 0x99, 0x1a, 0x86, 0xd2, 0xeb, 0x86, 0x21, 0x6e, 0xb6, 0xe5, 0x1e, 0xb1, 0x35, - 0x5a, 0x35, 0xbb, 0xe1, 0x1e, 0xf9, 0xe2, 0x53, 0xb8, 0x92, 0xa0, 0x65, 0x6b, 0xc8, 0x18, 0x48, - 0xe7, 0xb1, 0x86, 0x88, 0x29, 0xa9, 0x45, 0x64, 0xf6, 0xbb, 0x0f, 0xeb, 0xa9, 0x2c, 0x64, 0x95, - 0x0a, 0x69, 0xfb, 0x28, 0x19, 0x6b, 0x31, 0x39, 0xa9, 0xf2, 0xa1, 0x78, 0x1f, 0xfb, 0x69, 0xe8, - 0x4e, 0x47, 0xcc, 0x8c, 0xa7, 0x63, 0x2f, 0xac, 0x57, 0xa9, 0x83, 0xd7, 0x14, 0x9c, 0x99, 0x1f, - 0xd9, 0x2b, 0x71, 0xbc, 0x0f, 0xfd, 0x60, 0x6c, 0x45, 0xb4, 0x85, 0x54, 0x8d, 0xd2, 0x89, 0x7d, - 0xbe, 0x4d, 0x80, 0xa7, 0x85, 0x62, 0x4d, 0x5b, 0x33, 0x6a, 0xc9, 0x6a, 0x31, 0x43, 0x3b, 0xd2, - 0x7f, 0x6f, 0x19, 0xaa, 0xdb, 0x7e, 0x60, 0x3b, 0x47, 0x5e, 0x32, 0xab, 0xe7, 0x8c, 0xd8, 0x6a, - 0xa6, 0x2f, 0xa5, 0x66, 0xfa, 0x6d, 0x28, 0x1f, 0x72, 0x46, 0xe4, 0xeb, 0x34, 0x9d, 0x0b, 0x06, - 0x48, 0xd0, 0xe0, 0xc0, 0x45, 0xce, 0xa9, 0x08, 0x28, 0x73, 0x81, 0x32, 0xab, 0x4c, 0x28, 0x96, - 0x88, 0xaf, 0x69, 0x83, 0x1e, 0xd9, 0xae, 0x1d, 0xf1, 0xf0, 0xd7, 0x94, 0x02, 0x99, 0xa9, 0xd3, - 0x03, 0xc3, 0x3e, 0x6c, 0x90, 0x4d, 0x01, 0xf7, 0xeb, 0x2d, 0x22, 0x97, 0x79, 0xe5, 0xe6, 0xbe, - 0xf2, 0x03, 0xf3, 0x4a, 0x2e, 0xfd, 0x10, 0xae, 0x04, 0xf6, 0xa1, 0x4d, 0x4a, 0xdd, 0xc8, 0x4c, - 0xcd, 0x6a, 0x9e, 0x40, 0x97, 0x13, 0x64, 0x3b, 0x9e, 0xdf, 0xbb, 0xa0, 0xc5, 0x75, 0x35, 0x99, - 0xb3, 0xd2, 0xac, 0xaa, 0x3d, 0x7c, 0xfb, 0x95, 0x9f, 0xed, 0x11, 0xa9, 0x51, 0x53, 0x15, 0xe7, - 0xb4, 0x2c, 0x8e, 0xab, 0xaf, 0x8a, 0x2b, 0xfd, 0xa8, 0xe2, 0xb8, 0x2d, 0x9c, 0xd6, 0x07, 0x50, - 0x8a, 0x49, 0x44, 0x05, 0x8a, 0x46, 0x4b, 0x9a, 0x6c, 0x2f, 0x89, 0x32, 0xac, 0x36, 0x1b, 0xfd, - 0x66, 0x63, 0x0b, 0xf9, 0x5b, 0x05, 0x8a, 0xfd, 0xd6, 0x80, 0xcd, 0xb4, 0x4b, 0x62, 0x0d, 0xca, - 0x98, 0xda, 0x6a, 0x6d, 0x37, 0xf6, 0x3b, 0x03, 0x2d, 0x8f, 0xaa, 0x4e, 0xb7, 0x67, 0x36, 0x9a, - 0x83, 0x76, 0xaf, 0xab, 0x15, 0x74, 0x17, 0xd6, 0x66, 0x3e, 0x8c, 0x4c, 0x95, 0xd1, 0x66, 0xcf, - 0x68, 0x3f, 0x69, 0x77, 0xcd, 0xd6, 0x37, 0x7b, 0x9d, 0x76, 0xb3, 0x8d, 0x5f, 0xba, 0x0e, 0x57, - 0xb2, 0x38, 0x55, 0x70, 0x4e, 0xe8, 0x70, 0x2b, 0x8b, 0xea, 0xb4, 0x9e, 0x34, 0x9a, 0xdf, 0x9a, - 0x8d, 0xdd, 0xcd, 0xf6, 0x93, 0xfd, 0xde, 0x7e, 0x5f, 0x5b, 0xd2, 0x4d, 0x28, 0x36, 0x8f, 0xed, - 0xe1, 0xc9, 0x45, 0xb3, 0x90, 0xce, 0xea, 0xec, 0xe1, 0x89, 0x34, 0x8a, 0xcd, 0x9c, 0xd5, 0xd9, - 0xc3, 0x13, 0xd2, 0x18, 0xe5, 0x46, 0xf8, 0xbd, 0x2b, 0x0f, 0x21, 0x4a, 0x72, 0x17, 0xfc, 0xde, - 0xd5, 0x5b, 0x50, 0xda, 0xb3, 0x82, 0xc8, 0xa1, 0x4e, 0x7a, 0x0c, 0xd5, 0x38, 0xb1, 0x65, 0x1f, - 0x2a, 0x19, 0x5a, 0xc4, 0x96, 0xb4, 0x18, 0x65, 0x64, 0x09, 0xf5, 0x0f, 0xa1, 0x92, 0x06, 0xa0, - 0x8a, 0x3e, 0xb2, 0x0f, 0x17, 0xec, 0xce, 0x08, 0xd6, 0x9f, 0x43, 0xa5, 0xa9, 0x64, 0xc2, 0x8b, - 0x5a, 0xf6, 0x10, 0x6a, 0xc4, 0xb0, 0x87, 0x07, 0x8a, 0x63, 0x2f, 0x2d, 0xe0, 0xd8, 0x15, 0xa4, - 0x69, 0x1e, 0x48, 0x96, 0xfd, 0x39, 0x94, 0xf7, 0x02, 0x7f, 0x62, 0x07, 0x11, 0x15, 0xab, 0x41, - 0xfe, 0xc4, 0x3e, 0x97, 0xa5, 0xe2, 0xcf, 0xe4, 0x84, 0x75, 0x29, 0x7d, 0xc2, 0xfa, 0x10, 0x8a, - 0x2a, 0xdb, 0x0f, 0xce, 0xf3, 0x33, 0xdc, 0xf9, 0x28, 0x8f, 0x63, 0x87, 0xf8, 0xb1, 0x07, 0x64, - 0x49, 0x91, 0x00, 0xd9, 0x71, 0xca, 0x04, 0x29, 0x0b, 0x37, 0x52, 0x14, 0xfa, 0x9b, 0xb0, 0xfa, - 0xdc, 0xb1, 0x4f, 0x65, 0xf3, 0x5f, 0x3a, 0xf6, 0xa9, 0x6a, 0x3e, 0xfe, 0xd6, 0xff, 0x52, 0x19, - 0x8a, 0xc4, 0x1e, 0xb7, 0x2e, 0x3e, 0xd4, 0xfe, 0x31, 0xfa, 0xc9, 0x1d, 0xc9, 0xae, 0x0a, 0x0b, - 0xb4, 0x22, 0x66, 0x5e, 0x6f, 0x02, 0xa4, 0x58, 0x35, 0x6f, 0x3c, 0xa5, 0x28, 0xe6, 0xd0, 0x28, - 0xd8, 0x93, 0x90, 0x83, 0xd3, 0x88, 0xcf, 0x9b, 0x12, 0x80, 0x78, 0xc0, 0x62, 0x37, 0x9d, 0x30, - 0xad, 0xa6, 0x2d, 0x75, 0xd4, 0x06, 0x65, 0xfe, 0x24, 0x59, 0x1c, 0x13, 0x69, 0xa5, 0xbe, 0x98, - 0x55, 0xea, 0xdf, 0x83, 0x02, 0xee, 0xd1, 0xd2, 0x5c, 0x79, 0x59, 0xf5, 0x60, 0x4a, 0xc8, 0x30, - 0x88, 0x40, 0xdc, 0x83, 0x55, 0xe2, 0x52, 0x36, 0x6e, 0x14, 0xa9, 0xde, 0x56, 0x7b, 0xb6, 0xa1, - 0xd0, 0xe2, 0x7d, 0x58, 0x3e, 0x3c, 0xb1, 0xcf, 0x79, 0x97, 0x88, 0xcb, 0xcc, 0x30, 0x13, 0x83, - 0x29, 0xc4, 0x5d, 0xa8, 0x05, 0xf6, 0xa1, 0x49, 0xc7, 0xdc, 0xc8, 0xc3, 0xc3, 0x7a, 0x8d, 0x58, - 0x74, 0x25, 0xb0, 0x0f, 0x9b, 0x08, 0x1c, 0x1c, 0xb8, 0xa1, 0x78, 0x17, 0x56, 0x68, 0x71, 0xa1, - 0x56, 0x92, 0xfa, 0xb2, 0x5a, 0xa9, 0x86, 0xc4, 0x8a, 0x4f, 0x01, 0xa4, 0xee, 0x63, 0x1e, 0x9c, - 0x93, 0x84, 0x1f, 0x2f, 0xa6, 0xf4, 0xfc, 0x4f, 0x6b, 0x48, 0xef, 0xc1, 0x32, 0x4e, 0x92, 0xb0, - 0x7e, 0x8d, 0x4a, 0x5e, 0xcf, 0xce, 0x20, 0xaa, 0x29, 0xe1, 0xc5, 0x3d, 0x28, 0xe2, 0x44, 0xa1, - 0x55, 0x5d, 0x4f, 0x2b, 0x83, 0x72, 0x56, 0xe1, 0xc6, 0x6e, 0x9f, 0xf6, 0xbf, 0x77, 0xc5, 0x7d, - 0x28, 0x8c, 0x70, 0x31, 0x5f, 0x4f, 0xdb, 0x28, 0xd4, 0xdc, 0x42, 0xdd, 0x91, 0xf4, 0x53, 0xa2, - 0x11, 0x3b, 0x50, 0xc3, 0x69, 0xf4, 0x90, 0x64, 0x35, 0xec, 0xbe, 0xfa, 0x0d, 0xca, 0xf5, 0xd6, - 0x4c, 0xae, 0xae, 0x24, 0xa2, 0xce, 0x6e, 0x79, 0x51, 0x70, 0x6e, 0x54, 0xbd, 0x34, 0x4c, 0xdc, - 0x80, 0xa2, 0x13, 0x76, 0xfc, 0xe1, 0x49, 0xec, 0x81, 0x13, 0xa7, 0xc5, 0x57, 0x50, 0xa5, 0x89, - 0x85, 0x49, 0xfc, 0xb8, 0x74, 0xbf, 0x49, 0x4f, 0x19, 0x85, 0x32, 0xb2, 0x94, 0xb8, 0x83, 0x3a, - 0xa1, 0x19, 0xd9, 0xe3, 0x89, 0x1f, 0xa0, 0x1a, 0xf9, 0xa6, 0x3a, 0x9a, 0x1d, 0x28, 0x10, 0xca, - 0x51, 0xb1, 0x5b, 0xa3, 0xe9, 0x1f, 0x1e, 0x86, 0x76, 0x44, 0xee, 0x36, 0x05, 0xa3, 0xa6, 0xbc, - 0x1b, 0x7b, 0x04, 0x25, 0x39, 0x26, 0x34, 0x47, 0xe7, 0x9e, 0x35, 0x76, 0x86, 0xf5, 0xdb, 0xac, - 0xad, 0x3a, 0xe1, 0x16, 0x03, 0xd2, 0x0a, 0xe3, 0x9d, 0x8c, 0xc2, 0x78, 0x19, 0x96, 0x47, 0x07, - 0xb8, 0x1c, 0xdf, 0xa2, 0x62, 0x0b, 0xa3, 0x83, 0xf6, 0x48, 0x7c, 0x44, 0xc7, 0x6b, 0xcc, 0x02, - 0xeb, 0x7a, 0xfa, 0x80, 0x20, 0xe6, 0x8c, 0x46, 0x42, 0x21, 0xee, 0x40, 0x79, 0xdb, 0xb6, 0xa2, - 0x69, 0x60, 0x6f, 0xbb, 0xd6, 0x51, 0xfd, 0x6d, 0x2a, 0x29, 0x0d, 0xc2, 0xda, 0xb9, 0xfe, 0x91, - 0x33, 0xb4, 0x68, 0xe5, 0xdf, 0x65, 0xb1, 0x59, 0x42, 0xa4, 0x6d, 0x96, 0xd8, 0xb8, 0x25, 0x65, - 0xe1, 0x77, 0xd2, 0x1a, 0x8e, 0xe5, 0xaa, 0x73, 0xe8, 0xa4, 0x2f, 0xec, 0x89, 0x3f, 0x3c, 0xae, - 0xbf, 0x4b, 0xeb, 0xad, 0xaa, 0xba, 0xa2, 0x85, 0x40, 0xf1, 0x1e, 0xac, 0x49, 0xdb, 0x81, 0xa9, - 0x7c, 0x32, 0xdf, 0x23, 0xba, 0x9a, 0x04, 0x37, 0xa5, 0x6b, 0xa6, 0x0e, 0x55, 0x2e, 0x70, 0x64, - 0x0e, 0xad, 0xe1, 0xb1, 0x5d, 0xbf, 0xc7, 0x15, 0xa7, 0xe2, 0x46, 0x4d, 0x04, 0xcd, 0x48, 0x5d, - 0xef, 0xcf, 0x48, 0x5d, 0x8b, 0x3d, 0x22, 0xef, 0x2f, 0xf6, 0x88, 0xbc, 0xf1, 0x84, 0x74, 0x57, - 0x1a, 0xfa, 0xcf, 0x67, 0x38, 0x6c, 0x86, 0x3f, 0xa4, 0x58, 0xf1, 0xce, 0xa5, 0x34, 0xa3, 0xdd, - 0x5c, 0xa6, 0xad, 0xe8, 0xc6, 0xcf, 0x41, 0xcc, 0x4f, 0xda, 0xd7, 0xb1, 0xfb, 0x65, 0xc9, 0xee, - 0xbf, 0x5e, 0x7a, 0x9c, 0xd3, 0xff, 0x89, 0x1c, 0x54, 0x33, 0xec, 0x6c, 0xe1, 0xbe, 0xc5, 0x32, - 0xbf, 0x35, 0x96, 0x96, 0x37, 0x4e, 0x28, 0x4d, 0xd3, 0xf1, 0x8e, 0x5c, 0x3b, 0xa5, 0x69, 0x52, - 0xfa, 0x69, 0xa1, 0x58, 0xd0, 0x96, 0x9f, 0x16, 0x8a, 0xcb, 0xda, 0x8a, 0x71, 0xf9, 0x70, 0xea, - 0xba, 0x91, 0x7d, 0x16, 0xa9, 0x53, 0xd2, 0xc0, 0x3e, 0x34, 0x44, 0x0c, 0x64, 0xb9, 0x2c, 0xb0, - 0x0f, 0xf5, 0xff, 0x22, 0x0f, 0x95, 0x1d, 0x2b, 0x3c, 0xde, 0xb5, 0x26, 0xfd, 0xc8, 0x8a, 0x42, - 0x5c, 0x19, 0xc7, 0x56, 0x78, 0x3c, 0xb6, 0x26, 0xac, 0x4c, 0xe6, 0xf8, 0x8c, 0x42, 0xc2, 0x48, - 0x93, 0xbc, 0x01, 0x45, 0x4c, 0xf6, 0xbc, 0xbd, 0x67, 0xd2, 0xc8, 0x18, 0xa7, 0x91, 0x23, 0x87, - 0xc7, 0xd3, 0xc3, 0xc3, 0xb8, 0x7e, 0x2a, 0x29, 0xee, 0x42, 0x55, 0xfe, 0x24, 0x7d, 0xed, 0x4c, - 0x9e, 0xf3, 0x66, 0x81, 0xe2, 0x11, 0x94, 0x25, 0x60, 0xa0, 0xf6, 0x8f, 0x5a, 0x7c, 0x74, 0x95, - 0x20, 0x8c, 0x34, 0x95, 0xf8, 0x05, 0x5c, 0x49, 0x25, 0xb7, 0xfd, 0x60, 0x77, 0xea, 0x46, 0x4e, - 0xb3, 0x2b, 0x85, 0xd7, 0x37, 0xe6, 0xb2, 0x27, 0x24, 0xc6, 0xe2, 0x9c, 0xd9, 0xda, 0xee, 0x3a, - 0x7c, 0x02, 0x90, 0x37, 0xb2, 0xc0, 0x19, 0x2a, 0xeb, 0x8c, 0x76, 0xa1, 0x2c, 0x95, 0x75, 0x86, - 0x7c, 0x4a, 0x02, 0x76, 0xed, 0xe8, 0xd8, 0x1f, 0x49, 0x69, 0xf4, 0x72, 0xa6, 0x5a, 0x8c, 0x32, - 0xb2, 0x94, 0xd8, 0x9d, 0xde, 0xd4, 0x75, 0x87, 0x5e, 0x44, 0xfa, 0x51, 0xde, 0x50, 0x49, 0xdc, - 0xa1, 0x03, 0xcb, 0x3b, 0xb2, 0xc3, 0x7a, 0xf9, 0x4e, 0xfe, 0x5e, 0xce, 0x90, 0x29, 0xfd, 0xaf, - 0x2e, 0xc1, 0x32, 0x8f, 0xe4, 0x1b, 0x50, 0x3a, 0x20, 0xef, 0x1d, 0x6f, 0x3a, 0x56, 0xc7, 0x0f, - 0x04, 0xe8, 0x4e, 0xc7, 0xac, 0x77, 0x48, 0x23, 0x71, 0xce, 0xa0, 0xdf, 0x58, 0xa4, 0x3f, 0x8d, - 0xf0, 0x5b, 0x79, 0x82, 0xca, 0x14, 0x56, 0x22, 0xf0, 0x4f, 0x69, 0x36, 0x14, 0x08, 0xa1, 0x92, - 0xe4, 0xc8, 0x43, 0x9b, 0x3d, 0x66, 0x5a, 0x26, 0x5c, 0x91, 0x00, 0x4d, 0x2f, 0x9a, 0x3d, 0xec, - 0x5a, 0x99, 0x3f, 0xec, 0xba, 0x05, 0xa8, 0xd5, 0x0c, 0xed, 0x9e, 0x67, 0x37, 0xbb, 0xf2, 0x44, - 0x3d, 0x05, 0xc1, 0x65, 0x35, 0xf2, 0x27, 0xf2, 0xa8, 0x1c, 0x7f, 0x8a, 0x2f, 0xe2, 0xd9, 0x49, - 0x6d, 0x94, 0x3a, 0xa6, 0xdc, 0x0c, 0xd3, 0xf3, 0xd8, 0xc8, 0xd0, 0x61, 0x49, 0xb8, 0xc3, 0xb1, - 0x8e, 0x89, 0x3f, 0xf5, 0x16, 0x80, 0xe1, 0x9f, 0x86, 0x36, 0x1f, 0x60, 0x5d, 0xa3, 0x26, 0x66, - 0x7c, 0xf6, 0xfc, 0xd3, 0x3d, 0x3f, 0x8c, 0x0d, 0x44, 0x4b, 0x8b, 0x0d, 0x44, 0xfa, 0xc7, 0xb0, - 0x8a, 0xe2, 0x8f, 0x15, 0x59, 0xe2, 0xae, 0xb4, 0x95, 0xb3, 0xd0, 0xa6, 0x29, 0xcf, 0x11, 0xf5, - 0x0d, 0x69, 0x72, 0xef, 0xa8, 0xef, 0x52, 0x9e, 0xb7, 0x52, 0x86, 0x8e, 0x78, 0xeb, 0x95, 0x05, - 0x4a, 0x81, 0x8a, 0x4e, 0x91, 0x4e, 0x4d, 0x72, 0x4e, 0x52, 0xfe, 0x16, 0x81, 0x7f, 0xda, 0xc4, - 0xb4, 0xfe, 0x77, 0x73, 0x50, 0xee, 0x05, 0x23, 0xdc, 0xf3, 0xe9, 0x94, 0xe3, 0x75, 0xf6, 0x2c, - 0x14, 0xbf, 0x14, 0x6f, 0x54, 0x86, 0x86, 0x18, 0x20, 0x3e, 0x85, 0xc2, 0x21, 0xee, 0x22, 0xf9, - 0xb4, 0xce, 0x97, 0x2a, 0x5e, 0xfd, 0xc6, 0x7d, 0xc5, 0x20, 0x52, 0xfd, 0x77, 0xe2, 0xef, 0xd3, - 0x66, 0x93, 0x76, 0x7c, 0xb9, 0x44, 0x8e, 0x77, 0xfd, 0xa6, 0x96, 0x13, 0x45, 0x28, 0x6c, 0xb5, - 0xfa, 0x4d, 0xd6, 0x8b, 0x50, 0x43, 0xea, 0x9b, 0xdb, 0x6d, 0xa3, 0x3f, 0xe0, 0x63, 0x1c, 0x06, - 0x74, 0x1a, 0xfd, 0x81, 0x56, 0x14, 0x00, 0x2b, 0xfb, 0xdd, 0xf6, 0x2f, 0xf6, 0x5b, 0x9a, 0xa6, - 0xff, 0xed, 0x1c, 0x40, 0x72, 0xa6, 0x2d, 0x3e, 0x80, 0xf2, 0x29, 0xa5, 0xcc, 0x94, 0x0b, 0x52, - 0xe6, 0x4c, 0x8e, 0xd1, 0x24, 0x1a, 0x7e, 0x04, 0x95, 0x78, 0x97, 0x44, 0xb1, 0x69, 0xde, 0x17, - 0xa9, 0x1c, 0xe3, 0x37, 0xcf, 0xc5, 0x87, 0x50, 0xf4, 0xb1, 0x1d, 0x48, 0x9a, 0x4f, 0xcb, 0x4c, - 0xa9, 0xe6, 0xd3, 0x09, 0xa8, 0x12, 0xaf, 0x0e, 0x03, 0x65, 0x38, 0x8a, 0x49, 0xb7, 0x11, 0xd4, - 0x74, 0xad, 0x69, 0x68, 0x1b, 0x8c, 0x8f, 0x59, 0xfb, 0x72, 0xc2, 0xda, 0xf5, 0x5f, 0x42, 0xad, - 0x6f, 0x8d, 0x27, 0xbc, 0x01, 0x50, 0xc3, 0x04, 0x14, 0x70, 0x4e, 0xc8, 0xa9, 0x47, 0xbf, 0x71, - 0xd1, 0xed, 0xd9, 0xc1, 0xd0, 0xf6, 0xd4, 0x1a, 0x55, 0x49, 0x64, 0xbf, 0xfb, 0xb8, 0x05, 0x18, - 0xfe, 0xa9, 0xda, 0x03, 0x54, 0x5a, 0xff, 0x57, 0x72, 0x50, 0x4e, 0x55, 0x43, 0x7c, 0x0c, 0x05, - 0x92, 0xc3, 0x73, 0x69, 0x46, 0x98, 0x22, 0xe0, 0xdf, 0x2c, 0xb9, 0x21, 0xa1, 0x78, 0x17, 0x96, - 0xc3, 0xc8, 0x0a, 0x94, 0x7b, 0x84, 0x96, 0xca, 0xb1, 0xe9, 0x4f, 0xbd, 0x91, 0xc1, 0x68, 0xa1, - 0x43, 0xde, 0xf6, 0x46, 0xd2, 0xd4, 0x36, 0x4f, 0x85, 0x48, 0xfd, 0x0e, 0x94, 0xe2, 0xe2, 0x71, - 0x0a, 0x18, 0xbd, 0x17, 0x7d, 0xed, 0x12, 0x1d, 0xd4, 0x35, 0xba, 0x4f, 0x5a, 0x5a, 0x4e, 0xff, - 0x1b, 0x39, 0x80, 0x24, 0x97, 0x78, 0x90, 0xa9, 0xed, 0x8d, 0xd9, 0x52, 0x1f, 0xd0, 0xdf, 0x54, - 0x65, 0x6f, 0x42, 0x69, 0xea, 0x11, 0xd0, 0x1e, 0xc9, 0x9d, 0x28, 0x01, 0xa0, 0xf2, 0xa8, 0x6e, - 0x21, 0xcc, 0x28, 0x8f, 0x2f, 0x2d, 0x57, 0xff, 0x1a, 0x4a, 0x71, 0x71, 0xa8, 0x9c, 0x6f, 0xf7, - 0x3a, 0x9d, 0xde, 0x8b, 0x76, 0xf7, 0x09, 0x1f, 0x4b, 0xee, 0x19, 0xad, 0x66, 0x6b, 0x0b, 0x93, - 0x39, 0x9c, 0xb3, 0xcd, 0x7d, 0xc3, 0x68, 0x75, 0x07, 0x74, 0xf4, 0xb8, 0xa4, 0xff, 0x85, 0x1c, - 0x54, 0x7b, 0xee, 0xa8, 0xe9, 0xbb, 0x4d, 0x6b, 0x82, 0x82, 0x96, 0xf8, 0x19, 0xac, 0x1f, 0x4c, - 0x51, 0xd8, 0x9f, 0xb8, 0xd6, 0xd0, 0x3e, 0xf6, 0xdd, 0x91, 0xad, 0x16, 0x61, 0xc6, 0x01, 0x44, - 0x9e, 0xd0, 0x68, 0x44, 0xbc, 0x97, 0xd0, 0x8a, 0xcf, 0xa1, 0x32, 0x09, 0xfc, 0x03, 0x5b, 0x1d, - 0x97, 0x2d, 0x5d, 0x98, 0xb7, 0x4c, 0x74, 0x7c, 0x82, 0xa6, 0xff, 0xc7, 0xcb, 0x50, 0xd9, 0xb2, - 0x47, 0xd3, 0xc9, 0x53, 0xdf, 0xf1, 0x9a, 0xd1, 0x99, 0xf8, 0x0c, 0x2a, 0xbe, 0x4b, 0x06, 0x2d, - 0x33, 0xe5, 0x30, 0xbc, 0xa8, 0x1c, 0xf0, 0xa9, 0x05, 0xe4, 0x5e, 0xfc, 0x11, 0x5c, 0x96, 0xf6, - 0x12, 0xb6, 0xae, 0x9e, 0x71, 0x66, 0x5c, 0x33, 0xcb, 0x86, 0xc6, 0x28, 0xde, 0xa0, 0x89, 0xfc, - 0x27, 0xb0, 0x91, 0x22, 0x47, 0xc6, 0xc2, 0xf4, 0xf9, 0xb9, 0x35, 0xb6, 0x1e, 0xe7, 0x8d, 0x5d, - 0x99, 0x9f, 0xc2, 0x86, 0xaa, 0xe1, 0x90, 0x7b, 0x8f, 0x33, 0x17, 0xd2, 0x5a, 0x55, 0xa6, 0x77, - 0x65, 0x85, 0xd7, 0xfd, 0x34, 0x90, 0xca, 0xfa, 0x14, 0xae, 0x8c, 0xb0, 0xf5, 0x26, 0x77, 0xfe, - 0x89, 0x6d, 0x4f, 0x4c, 0x37, 0xe5, 0xe7, 0x47, 0xc8, 0x4d, 0xc4, 0x3d, 0xb3, 0xed, 0x49, 0xc7, - 0x0a, 0x23, 0xf1, 0x18, 0xd6, 0xad, 0xc3, 0x43, 0xf6, 0x2f, 0xc2, 0x6d, 0x6c, 0xa1, 0x15, 0xd7, - 0xb0, 0x0f, 0x8d, 0x35, 0x45, 0x86, 0xcb, 0xb1, 0xe9, 0xbb, 0xe2, 0x09, 0x5c, 0x9f, 0x1c, 0x9f, - 0x87, 0x24, 0x49, 0x0f, 0x8f, 0x71, 0xb7, 0x4d, 0x95, 0xb0, 0xba, 0xa0, 0x84, 0xab, 0x8a, 0xbc, - 0xc9, 0xd4, 0xaa, 0xa0, 0xc7, 0x70, 0x5d, 0x75, 0x1f, 0x2a, 0x78, 0xd9, 0x3e, 0x2f, 0x52, 0x9f, - 0x5f, 0x91, 0xfd, 0x86, 0xf8, 0x54, 0xc7, 0xdf, 0x03, 0x8d, 0x1d, 0x57, 0x0f, 0xc9, 0xbd, 0x1e, - 0xbf, 0x2e, 0x2f, 0x36, 0xd5, 0x08, 0xbe, 0x4d, 0x8b, 0x0f, 0xd9, 0xc7, 0x3d, 0xd0, 0xec, 0xb1, - 0x13, 0x99, 0x16, 0x89, 0x98, 0x4c, 0xc9, 0x67, 0x6f, 0x35, 0x84, 0x4b, 0xbb, 0x1d, 0x52, 0x7e, - 0x01, 0x9a, 0x24, 0x3a, 0x24, 0x25, 0x00, 0x5b, 0x53, 0x5e, 0xd0, 0x9a, 0x1a, 0x53, 0x6d, 0x23, - 0x11, 0xb6, 0x62, 0x17, 0x84, 0x32, 0x42, 0x92, 0x69, 0x85, 0x35, 0x59, 0xd6, 0xa1, 0xa5, 0xa3, - 0x66, 0x6f, 0xeb, 0xd9, 0x7e, 0xa2, 0x1f, 0x53, 0x63, 0xd4, 0x02, 0x38, 0xcc, 0x82, 0x43, 0xfd, - 0x3f, 0x58, 0x81, 0x12, 0xdb, 0xdd, 0x70, 0x1a, 0xdf, 0x83, 0x55, 0xff, 0xe0, 0x3b, 0x94, 0x50, - 0x2f, 0xf2, 0x34, 0x5d, 0xf1, 0x0f, 0xbe, 0x33, 0xec, 0x43, 0xf1, 0x81, 0x12, 0x41, 0x46, 0xf6, - 0xa1, 0x5c, 0x35, 0xb5, 0xac, 0x96, 0x29, 0x45, 0x92, 0x2d, 0xfb, 0x10, 0xa5, 0x4b, 0xc7, 0x0b, - 0xed, 0x20, 0x62, 0xbb, 0xe9, 0xea, 0xc5, 0x8b, 0x83, 0xc9, 0xc8, 0x94, 0xfa, 0x08, 0xca, 0xd2, - 0x36, 0x49, 0x99, 0x8a, 0x17, 0x67, 0x62, 0x32, 0xca, 0xf4, 0x15, 0xd4, 0x92, 0xed, 0x87, 0xf2, - 0x95, 0x2e, 0xcc, 0x57, 0x8d, 0x29, 0x29, 0xeb, 0x43, 0xb8, 0x1a, 0x9e, 0x38, 0x13, 0x53, 0xd6, - 0xd4, 0xf7, 0xe8, 0x10, 0xd7, 0x9c, 0x9c, 0xc8, 0x01, 0x14, 0x88, 0x6d, 0x13, 0xb2, 0xe7, 0x75, - 0xa7, 0xae, 0xbb, 0x77, 0x22, 0xde, 0x87, 0x75, 0x49, 0x3e, 0x89, 0xe7, 0x13, 0x8d, 0xe2, 0xb2, - 0x51, 0x63, 0xc4, 0x9e, 0x9c, 0x47, 0xe2, 0x4b, 0xa8, 0xf3, 0x1c, 0x92, 0x8d, 0xe2, 0x69, 0xce, - 0x33, 0x84, 0x4f, 0x5a, 0xaf, 0x10, 0x9e, 0x6d, 0xaa, 0x0d, 0xc2, 0xd2, 0x44, 0xf9, 0x04, 0x36, - 0x9c, 0x23, 0xcf, 0x0f, 0x54, 0x16, 0x39, 0xfd, 0xe5, 0x11, 0xac, 0x60, 0x5c, 0x23, 0xb5, 0x68, - 0xb0, 0x25, 0x72, 0x79, 0x9e, 0x9b, 0x11, 0xb9, 0x8a, 0x61, 0x0e, 0x54, 0x43, 0x6b, 0xe9, 0xf5, - 0x79, 0xce, 0x6e, 0x64, 0x86, 0x7f, 0xda, 0x1e, 0xe1, 0x92, 0x96, 0xa4, 0x6a, 0x8d, 0x44, 0x67, - 0xd4, 0x9a, 0x35, 0x6a, 0x8d, 0x60, 0x64, 0x3c, 0x53, 0xb0, 0x45, 0x3f, 0x07, 0x31, 0xb7, 0xa4, - 0xc3, 0xba, 0x76, 0x61, 0x7f, 0x6b, 0x33, 0x2b, 0x9b, 0xd6, 0xc0, 0xdc, 0x8a, 0x5e, 0x5f, 0xb4, - 0x06, 0x86, 0xd9, 0x95, 0xdc, 0x82, 0x7a, 0xf6, 0xcb, 0xa7, 0xb6, 0x73, 0x74, 0x4c, 0xb3, 0x4b, - 0xde, 0xab, 0xca, 0xe6, 0xbf, 0x92, 0xfe, 0xf2, 0x0b, 0xa2, 0x7d, 0x2d, 0x67, 0xb9, 0xfc, 0xc3, - 0x39, 0x8b, 0xfe, 0xaf, 0xe5, 0xa0, 0xc4, 0x33, 0x03, 0x17, 0xd1, 0x5b, 0x90, 0x7f, 0xc5, 0x02, - 0x42, 0x9c, 0xb8, 0x0f, 0xeb, 0xd6, 0x68, 0x34, 0x33, 0xa0, 0xbc, 0x93, 0xae, 0x59, 0xa3, 0x51, - 0x66, 0x34, 0xef, 0x81, 0xe6, 0x84, 0xa6, 0xb2, 0x44, 0x25, 0xde, 0xe8, 0x45, 0xa3, 0xe6, 0x84, - 0xd2, 0x10, 0xc5, 0xa7, 0x96, 0x99, 0x35, 0x59, 0x78, 0xf5, 0x9a, 0xd4, 0x05, 0x80, 0x61, 0xd3, - 0xb6, 0xd9, 0x8c, 0xce, 0x9e, 0x16, 0x8a, 0x39, 0x0d, 0xf4, 0xff, 0xac, 0x0c, 0xe5, 0x86, 0x67, - 0xb9, 0xe7, 0xbf, 0xb2, 0xc9, 0x95, 0x9e, 0x4e, 0x8a, 0x26, 0x53, 0x39, 0x4b, 0xd9, 0x8f, 0xa3, - 0x44, 0x10, 0xaa, 0xd9, 0x6d, 0x90, 0x2e, 0x4f, 0x49, 0xfd, 0xf3, 0x06, 0x30, 0x88, 0x08, 0xe2, - 0xfc, 0xf1, 0xf9, 0xa8, 0xca, 0x4f, 0x0a, 0x6d, 0x92, 0x3f, 0x56, 0x72, 0xe2, 0xfc, 0x44, 0xf0, - 0x36, 0x54, 0x23, 0x67, 0x4c, 0x97, 0x35, 0xc3, 0xe9, 0xd8, 0x1e, 0xf1, 0x35, 0x45, 0xbe, 0xf9, - 0xd6, 0x94, 0x30, 0x2c, 0x65, 0x6c, 0x8f, 0xfd, 0xe0, 0x9c, 0x4b, 0x59, 0xe1, 0x52, 0x18, 0x44, - 0xa5, 0x7c, 0x08, 0xe2, 0xd4, 0x72, 0x22, 0x33, 0x5b, 0x14, 0x2b, 0x96, 0x1a, 0x62, 0x06, 0xe9, - 0xe2, 0xae, 0xc2, 0xca, 0xc8, 0x09, 0x4f, 0xda, 0x3d, 0xa9, 0x54, 0xca, 0x14, 0xb6, 0x25, 0x1c, - 0x5a, 0x28, 0xd3, 0x46, 0x36, 0x73, 0xff, 0xbc, 0x51, 0x42, 0xc8, 0x26, 0x02, 0x50, 0x26, 0xf2, - 0xec, 0xe8, 0xd4, 0x0f, 0x30, 0x27, 0xeb, 0x8c, 0x09, 0x00, 0x65, 0x47, 0x24, 0xc5, 0x0f, 0x11, - 0x7b, 0xc8, 0x1b, 0x71, 0x1a, 0xb5, 0x31, 0x66, 0x15, 0x84, 0xad, 0x70, 0xf5, 0x13, 0x88, 0xb8, - 0x0b, 0x35, 0xaa, 0x3e, 0xe9, 0x94, 0xd8, 0x06, 0x5a, 0xf9, 0x79, 0xa3, 0x82, 0x50, 0xb2, 0xac, - 0x21, 0xd5, 0x57, 0x70, 0x3d, 0xd3, 0x3e, 0xd3, 0x0a, 0x02, 0xeb, 0xdc, 0x1c, 0x5b, 0xdf, 0xf9, - 0x01, 0x59, 0x41, 0xf3, 0xc6, 0xd5, 0x74, 0xb7, 0x35, 0x10, 0xbd, 0x8b, 0xd8, 0x0b, 0xb3, 0x3a, - 0x9e, 0x1f, 0x90, 0x89, 0x74, 0x61, 0x56, 0xc4, 0x92, 0x3d, 0x8f, 0x06, 0x98, 0x14, 0xdc, 0x90, - 0x6f, 0x4c, 0x1a, 0xec, 0x61, 0xb7, 0x49, 0x20, 0x54, 0xf1, 0xc2, 0x47, 0xbc, 0xc7, 0xae, 0xcb, - 0x7b, 0x3c, 0x8f, 0x68, 0x53, 0x65, 0xc4, 0xb1, 0x6d, 0x8d, 0x68, 0xcd, 0x12, 0x62, 0xc7, 0xb6, - 0xe8, 0xb6, 0x57, 0xf8, 0xc8, 0x9c, 0x4c, 0x23, 0xbe, 0xea, 0x68, 0x2c, 0x87, 0x8f, 0xf6, 0xa6, - 0x91, 0x04, 0x1f, 0xd9, 0x11, 0xf9, 0x6f, 0x10, 0xf8, 0x09, 0xdf, 0x36, 0x0e, 0x1f, 0xa9, 0x13, - 0xb7, 0x2b, 0xb2, 0x6f, 0x1f, 0xc9, 0x23, 0x35, 0x1d, 0xaa, 0x31, 0xd2, 0x1c, 0x4f, 0xf9, 0x6e, - 0x63, 0xde, 0x28, 0x2b, 0x82, 0xdd, 0xa9, 0x8b, 0x03, 0x4b, 0xb6, 0x30, 0x33, 0xc0, 0xaa, 0x5c, - 0xe3, 0xa1, 0x23, 0x88, 0x81, 0xb5, 0x79, 0x03, 0x38, 0x61, 0x1e, 0x3b, 0xec, 0xc6, 0x9a, 0x37, - 0x8a, 0x04, 0xd8, 0x71, 0x22, 0x5c, 0xc7, 0x8c, 0x94, 0x33, 0x90, 0x8a, 0xb8, 0x4e, 0x44, 0x6b, - 0x84, 0xd8, 0x25, 0x38, 0x15, 0x84, 0x42, 0x44, 0x9a, 0x16, 0xcb, 0xbb, 0x41, 0xa4, 0xb5, 0x14, - 0x29, 0x96, 0xfa, 0x2e, 0x70, 0x66, 0x13, 0xa7, 0x1e, 0x97, 0xf9, 0x06, 0x1b, 0x38, 0x08, 0xbc, - 0xe5, 0x84, 0x27, 0x54, 0xe2, 0x5d, 0xa8, 0xa5, 0xe8, 0xb0, 0xbc, 0x9b, 0x3c, 0x33, 0x62, 0xb2, - 0x4c, 0x1d, 0x03, 0x7b, 0xec, 0x47, 0xb2, 0x99, 0x6f, 0xa6, 0xea, 0x68, 0x10, 0x3c, 0x5b, 0x47, - 0x49, 0x8b, 0x65, 0xde, 0x4a, 0xd5, 0x91, 0x49, 0xb1, 0xd4, 0xb7, 0xa0, 0x72, 0x1a, 0x38, 0x51, - 0x64, 0x4b, 0x21, 0xe7, 0x36, 0x77, 0xac, 0x84, 0xd1, 0xea, 0x7f, 0x0b, 0x2a, 0xdc, 0xf3, 0x92, - 0xbf, 0xdd, 0x61, 0x12, 0x09, 0x53, 0x0c, 0x42, 0xf6, 0xc6, 0xd8, 0xf1, 0xc8, 0x1e, 0x9b, 0x37, - 0x4a, 0x0c, 0xd9, 0x75, 0xbc, 0x34, 0xda, 0x3a, 0x23, 0xab, 0x6c, 0x82, 0xb6, 0xce, 0x68, 0x49, - 0x4e, 0x1c, 0xd7, 0xe5, 0x85, 0xff, 0xb6, 0x5c, 0x92, 0x08, 0xa1, 0x75, 0x1f, 0xa3, 0xe9, 0xeb, - 0x77, 0x53, 0x68, 0xfa, 0x36, 0x4e, 0x1c, 0x42, 0xe3, 0xa7, 0xdf, 0x91, 0x13, 0x07, 0x01, 0xf8, - 0xe5, 0x04, 0x69, 0x9d, 0x91, 0xcd, 0x35, 0x46, 0x5a, 0x67, 0x92, 0x6f, 0xd1, 0x4e, 0x81, 0x79, - 0xdf, 0x8b, 0xf9, 0x16, 0x82, 0x30, 0x77, 0x9a, 0xc0, 0x3a, 0x23, 0x23, 0x6b, 0x8a, 0xc0, 0x3a, - 0x23, 0xe3, 0x82, 0x6d, 0x8d, 0xb8, 0xe2, 0xef, 0x73, 0xf1, 0x08, 0xa0, 0x7a, 0xdf, 0x81, 0x4a, - 0xf8, 0xc8, 0x4c, 0xf0, 0xf7, 0x39, 0x7b, 0xf8, 0xc8, 0x50, 0x14, 0x77, 0xa1, 0x16, 0x4f, 0x0d, - 0xa6, 0xf9, 0x80, 0x07, 0x7e, 0x24, 0xa7, 0x06, 0x5d, 0xe6, 0xfb, 0x75, 0x0e, 0x6e, 0xf0, 0x19, - 0x27, 0xb1, 0xff, 0x5d, 0x3b, 0x0c, 0xad, 0x23, 0x7b, 0xdb, 0x0f, 0xb6, 0xa7, 0xbf, 0xfa, 0xd5, - 0xb9, 0xb8, 0x07, 0x6b, 0x7b, 0x56, 0x60, 0x7b, 0x51, 0xec, 0x99, 0x20, 0x2d, 0xa1, 0xb3, 0x60, - 0xf1, 0x18, 0x34, 0x06, 0xf1, 0x1d, 0xa6, 0xa6, 0x3a, 0x38, 0x9f, 0x3d, 0x89, 0x9a, 0xa3, 0xd2, - 0xff, 0x6e, 0x0e, 0x4a, 0x5b, 0x4e, 0x18, 0x19, 0xb8, 0x5d, 0x8a, 0xaf, 0x40, 0x73, 0xfd, 0x53, - 0x54, 0xf6, 0x49, 0x8c, 0x4e, 0xe9, 0x9c, 0x72, 0x97, 0x4c, 0x14, 0xcd, 0x1a, 0x11, 0x26, 0x9a, - 0xe2, 0x57, 0xa0, 0x4d, 0x27, 0x93, 0x6c, 0xd6, 0xa5, 0x0b, 0xb2, 0x12, 0x61, 0x92, 0xf5, 0x03, - 0x28, 0xa7, 0xbe, 0xba, 0x40, 0x2f, 0x85, 0xe4, 0x5b, 0x48, 0x9c, 0xfa, 0xce, 0x82, 0x3b, 0x94, - 0x90, 0x94, 0xae, 0xff, 0xeb, 0x4b, 0xa0, 0x91, 0x35, 0xda, 0x20, 0xef, 0x35, 0x72, 0x70, 0xc8, - 0x58, 0x34, 0x72, 0xaf, 0xb5, 0x68, 0xdc, 0x81, 0x65, 0xd7, 0x19, 0xc7, 0xd7, 0x22, 0x32, 0x27, - 0xc0, 0x84, 0xc0, 0xb1, 0xf6, 0x03, 0xe7, 0x88, 0x6c, 0x2f, 0xe9, 0x6b, 0x75, 0x74, 0x52, 0xb0, - 0x3d, 0xf5, 0x86, 0x34, 0x44, 0x0f, 0x00, 0x46, 0x4e, 0x18, 0x99, 0x64, 0x8d, 0x94, 0xd5, 0x96, - 0x3d, 0x13, 0xf7, 0xbf, 0x51, 0x1a, 0xc5, 0x43, 0x71, 0x0f, 0xb4, 0x94, 0x9c, 0xec, 0xc5, 0x86, - 0xc4, 0x65, 0x23, 0x91, 0x9f, 0x9b, 0x5e, 0xd3, 0x8b, 0xe6, 0x28, 0x51, 0x26, 0x5c, 0x99, 0xa3, - 0x44, 0x79, 0xf0, 0x1e, 0x68, 0xfe, 0x4b, 0x3b, 0x30, 0x0f, 0xed, 0x68, 0x78, 0x6c, 0x72, 0xb3, - 0x56, 0xf9, 0xe4, 0x06, 0xe1, 0xdb, 0x08, 0xee, 0x20, 0x54, 0x3f, 0x83, 0xcb, 0xd4, 0x6f, 0x3b, - 0x74, 0xba, 0x49, 0x13, 0x4d, 0xde, 0x81, 0x0e, 0x7c, 0x37, 0x36, 0xc8, 0xe3, 0x6f, 0xf1, 0x1e, - 0xa0, 0xc6, 0x61, 0x0f, 0x55, 0x0f, 0x2d, 0x54, 0x48, 0xec, 0x21, 0xf6, 0xd3, 0x72, 0x22, 0x1b, - 0xcd, 0x0b, 0x3e, 0x8c, 0xd4, 0xff, 0xaf, 0x15, 0x58, 0xe3, 0x6b, 0x80, 0xb6, 0x15, 0x0c, 0x8f, - 0xe9, 0x32, 0xe0, 0x43, 0xa8, 0x48, 0x6b, 0x7d, 0xe2, 0x14, 0xb6, 0xe0, 0x43, 0x65, 0x26, 0x62, - 0x51, 0xeb, 0x31, 0x68, 0xe9, 0x3c, 0xaf, 0xd0, 0x82, 0x6a, 0xa9, 0x6c, 0xa8, 0x0b, 0xdd, 0x85, - 0x65, 0x3e, 0x9a, 0xcb, 0xd4, 0x33, 0x3e, 0xf6, 0x64, 0xa4, 0xf8, 0x6d, 0xa8, 0xf2, 0xd1, 0xaf, - 0x29, 0x6f, 0x3d, 0x16, 0xd2, 0x0a, 0xde, 0x82, 0xce, 0x33, 0x2a, 0xc7, 0x49, 0x3a, 0x14, 0x1f, - 0x43, 0x95, 0x5c, 0xf4, 0xcd, 0x89, 0x75, 0xee, 0xfa, 0xd6, 0x28, 0xeb, 0xb4, 0x4a, 0xf3, 0xab, - 0x42, 0x04, 0x7b, 0x8c, 0x17, 0x1f, 0xc0, 0x3a, 0xce, 0x0e, 0xcb, 0x1b, 0xda, 0x34, 0xd5, 0xc8, - 0x52, 0xc9, 0x07, 0xc5, 0x9a, 0x42, 0xc4, 0x27, 0x27, 0x3f, 0x81, 0xd2, 0xc8, 0x09, 0x6c, 0x26, - 0x5a, 0xfd, 0x21, 0x56, 0xcb, 0x84, 0x5e, 0x3c, 0xc2, 0xdd, 0xcd, 0x1b, 0x39, 0xa4, 0x65, 0xf0, - 0x2c, 0x29, 0xce, 0x55, 0xae, 0x16, 0x93, 0xd0, 0x8c, 0x11, 0x5f, 0x10, 0xc7, 0xe3, 0xea, 0xf1, - 0x1c, 0x2f, 0x2d, 0x9e, 0xe3, 0x55, 0x45, 0xc6, 0xf3, 0xfc, 0x03, 0x28, 0x4f, 0x02, 0xdb, 0x3c, - 0x74, 0xdc, 0xc8, 0x0e, 0x50, 0x15, 0x9f, 0xb5, 0x94, 0xc0, 0x24, 0xb0, 0xb7, 0x19, 0xbb, 0xd0, - 0x35, 0xa9, 0xbc, 0xd8, 0x35, 0xe9, 0x11, 0x54, 0x49, 0x1a, 0x8c, 0xaf, 0xe1, 0x6a, 0x0b, 0xaf, - 0xe1, 0x56, 0x90, 0x48, 0xa5, 0xc4, 0x23, 0xb8, 0x3a, 0xf1, 0xc3, 0x48, 0xd6, 0xc6, 0x4c, 0x16, - 0x0b, 0x49, 0x46, 0x45, 0xe3, 0x32, 0x62, 0xb9, 0x32, 0x3d, 0xb5, 0x60, 0xc4, 0x17, 0x40, 0x52, - 0xa6, 0x89, 0x92, 0xa4, 0x54, 0x6e, 0xd2, 0xb3, 0x20, 0x99, 0xc7, 0x2f, 0xfc, 0xe0, 0x84, 0xc5, - 0x4a, 0xfc, 0x45, 0xd7, 0x6d, 0xdd, 0x23, 0xdf, 0x64, 0xa7, 0xaf, 0x90, 0x64, 0xa9, 0x8a, 0x51, - 0x46, 0x18, 0xfb, 0x83, 0x61, 0x7b, 0x81, 0x48, 0xec, 0xb3, 0x49, 0x10, 0xd6, 0x37, 0xe6, 0xfa, - 0xa6, 0x84, 0x58, 0xfc, 0x15, 0xd2, 0x49, 0xa4, 0x22, 0x35, 0xd9, 0x41, 0xef, 0x0a, 0xf5, 0x4c, - 0x55, 0xd1, 0x20, 0x1b, 0x0a, 0x9f, 0x16, 0x8a, 0x15, 0xad, 0xfa, 0xb4, 0x50, 0xac, 0x6a, 0x35, - 0xf6, 0xcf, 0x7a, 0x5a, 0x28, 0xae, 0x69, 0x9a, 0xfe, 0xd7, 0x3f, 0x82, 0x02, 0xdd, 0x71, 0xf8, - 0x04, 0x4a, 0x74, 0xe1, 0x30, 0xc5, 0xfc, 0xa5, 0xed, 0x09, 0xd1, 0xf4, 0x87, 0xb8, 0x78, 0xd1, - 0x93, 0xbf, 0x2e, 0xbe, 0xf9, 0xfe, 0x16, 0xd9, 0x4c, 0xc9, 0x3f, 0x0f, 0x7b, 0xa5, 0xac, 0xc2, - 0x3f, 0x58, 0x51, 0x68, 0x30, 0x06, 0xe5, 0x6e, 0x72, 0x06, 0x08, 0x6c, 0x8f, 0x56, 0xd0, 0xb2, - 0x11, 0xa7, 0xc9, 0x52, 0xcd, 0x97, 0xda, 0x58, 0x3a, 0x5d, 0x5e, 0x60, 0xa9, 0x66, 0x3c, 0x89, - 0xab, 0x9f, 0x40, 0xe9, 0x3b, 0xdf, 0xf1, 0xb8, 0xe2, 0x2b, 0x73, 0x15, 0x7f, 0xea, 0x3b, 0x1e, - 0x57, 0xfc, 0x3b, 0xf9, 0x4b, 0xbc, 0x0d, 0xab, 0xbe, 0xc7, 0x65, 0xaf, 0xce, 0xdf, 0x86, 0xf1, - 0xbd, 0x0e, 0x5f, 0xca, 0xaa, 0x3a, 0xa1, 0x19, 0x90, 0xfa, 0x8a, 0x39, 0xa5, 0x5f, 0x5f, 0xd9, - 0x09, 0x0d, 0x84, 0x61, 0xb1, 0x38, 0x89, 0xe5, 0x94, 0xa1, 0xc2, 0x4a, 0xf3, 0x93, 0x98, 0xd1, - 0x54, 0xe0, 0x3b, 0x50, 0x3c, 0x0a, 0x7c, 0x52, 0xfe, 0x17, 0x4c, 0xf7, 0x55, 0xc2, 0x6d, 0x9e, - 0xa3, 0x6a, 0x45, 0x3f, 0x1d, 0xef, 0xc8, 0xa4, 0xc3, 0x07, 0x9c, 0xe8, 0x45, 0xa3, 0xa2, 0x80, - 0x74, 0xac, 0xf0, 0x0e, 0x14, 0xad, 0xa3, 0x23, 0x53, 0xde, 0x2d, 0x9b, 0x2b, 0xcb, 0x3a, 0x3a, - 0xa2, 0x4f, 0x3e, 0x80, 0xea, 0xa9, 0xe3, 0x99, 0xe1, 0xc4, 0x1e, 0x32, 0x6d, 0x75, 0xbe, 0x2b, - 0x4f, 0x1d, 0xba, 0x0f, 0x42, 0xf4, 0xe9, 0x2d, 0xb2, 0xf6, 0xc3, 0xb7, 0xc8, 0xb5, 0x8b, 0xb6, - 0x48, 0x1d, 0x56, 0xa4, 0xa3, 0x80, 0x36, 0x47, 0x22, 0x31, 0xe2, 0x53, 0x28, 0x07, 0x96, 0x77, - 0x22, 0x97, 0x43, 0xfd, 0xdb, 0xb4, 0x01, 0xdd, 0xb0, 0xbc, 0x13, 0xe9, 0x23, 0x09, 0x41, 0xfc, - 0x3b, 0xab, 0x4e, 0xaf, 0xbf, 0xc6, 0xc4, 0x95, 0xb2, 0x9c, 0x89, 0x57, 0x5b, 0xce, 0x3e, 0x27, - 0x13, 0x95, 0xed, 0x45, 0xa6, 0xca, 0x70, 0x79, 0x71, 0x86, 0x0a, 0x93, 0xf5, 0x38, 0x1b, 0x36, - 0x80, 0x0e, 0xb0, 0x4c, 0x3a, 0xed, 0xda, 0xc8, 0x34, 0x20, 0x3e, 0xd9, 0x32, 0x20, 0x48, 0x4e, - 0xb9, 0x1a, 0xb0, 0x96, 0x5c, 0x83, 0xe7, 0xd8, 0x03, 0x57, 0xd2, 0xe7, 0xee, 0x99, 0x7b, 0xf3, - 0xca, 0x28, 0xe6, 0x64, 0x2e, 0xd3, 0xbf, 0x0d, 0x55, 0xf6, 0x97, 0x56, 0x6c, 0x84, 0x1d, 0xdd, - 0x2b, 0x04, 0x54, 0x7c, 0x04, 0x85, 0x0f, 0x69, 0xa9, 0x8b, 0xce, 0x48, 0x83, 0x4a, 0x18, 0x33, - 0x9b, 0xe6, 0xa2, 0x33, 0xa3, 0x34, 0x52, 0x3f, 0x91, 0x35, 0x1d, 0x38, 0xde, 0x08, 0xa7, 0x5e, - 0x64, 0x1d, 0x85, 0xf5, 0x3a, 0xad, 0xcc, 0xb2, 0x84, 0x0d, 0xac, 0xa3, 0x50, 0x7c, 0x06, 0x15, - 0x8b, 0x0d, 0x11, 0x5c, 0xef, 0xeb, 0xe9, 0x03, 0x9f, 0x94, 0x89, 0xc2, 0x28, 0x5b, 0x29, 0x7b, - 0xc5, 0x97, 0x20, 0x94, 0x1f, 0x53, 0xca, 0x3c, 0x7e, 0x63, 0x6e, 0x36, 0xae, 0x49, 0x47, 0xa6, - 0xd8, 0x38, 0x7e, 0x1b, 0xe4, 0xee, 0xce, 0xd7, 0x90, 0xde, 0xa0, 0x0a, 0x01, 0x83, 0xe8, 0x0a, - 0xd2, 0x97, 0x50, 0xcd, 0x5a, 0x60, 0x6e, 0x2e, 0x70, 0x07, 0xe2, 0xbd, 0xb8, 0x32, 0x4c, 0xdb, - 0x64, 0xde, 0xe6, 0x70, 0x0e, 0xa4, 0x3d, 0x51, 0x46, 0x76, 0x79, 0xa9, 0x78, 0x7e, 0xd4, 0x54, - 0x30, 0xec, 0x40, 0x65, 0x1f, 0x8d, 0xce, 0x48, 0xe1, 0x8a, 0x3b, 0x30, 0x36, 0x2b, 0x19, 0x25, - 0x27, 0xb6, 0x30, 0x6d, 0x81, 0x50, 0xae, 0x04, 0x28, 0x78, 0xb2, 0xc7, 0x2d, 0xe9, 0x57, 0xb1, - 0x87, 0xd0, 0xac, 0x5c, 0x6a, 0xb0, 0x77, 0x72, 0x5a, 0x52, 0x7d, 0x0c, 0x35, 0xdc, 0x1b, 0x53, - 0x5f, 0xd6, 0xd3, 0x8d, 0xda, 0x0b, 0xec, 0xe4, 0xe3, 0x95, 0x49, 0x2a, 0x25, 0x7e, 0x06, 0xeb, - 0xa9, 0x9c, 0xd3, 0x13, 0xca, 0xfc, 0x36, 0x65, 0xde, 0x98, 0xc9, 0xbc, 0x7f, 0x82, 0xd9, 0x6b, - 0x93, 0x4c, 0x5a, 0x6c, 0xc0, 0x72, 0x3b, 0x6c, 0x79, 0x23, 0xd2, 0xbb, 0x8a, 0x06, 0x27, 0xc4, - 0x23, 0xa8, 0xb0, 0x91, 0x83, 0x6c, 0x8d, 0x61, 0xfd, 0xdd, 0xf4, 0x89, 0x2e, 0x59, 0x3a, 0xd8, - 0x60, 0x59, 0x76, 0xe3, 0xdf, 0xa1, 0xf8, 0x02, 0xd6, 0xf9, 0xb8, 0x3d, 0xcd, 0x22, 0xdf, 0x9b, - 0x1f, 0x72, 0x22, 0xda, 0x4e, 0xf8, 0xa4, 0x01, 0xd7, 0x83, 0xa9, 0x47, 0x86, 0x0f, 0x99, 0x93, - 0x0f, 0x82, 0x28, 0xff, 0x3d, 0xca, 0x2f, 0x03, 0x0a, 0x19, 0x4c, 0xc6, 0x79, 0x89, 0x37, 0x5d, - 0x0d, 0xd2, 0xa0, 0x3d, 0xcc, 0x77, 0x41, 0x99, 0x7c, 0x40, 0x42, 0x65, 0xbe, 0xff, 0x63, 0xca, - 0xa4, 0xc3, 0x13, 0x2a, 0x53, 0x40, 0x61, 0x3a, 0x75, 0x46, 0xa4, 0x05, 0x56, 0x0c, 0xfa, 0x2d, - 0xde, 0x81, 0x5a, 0x60, 0x0f, 0xa7, 0x41, 0xe8, 0xbc, 0xb4, 0xcd, 0xd0, 0xf1, 0x4e, 0x48, 0xff, - 0x2b, 0x1a, 0xd5, 0x18, 0xda, 0x77, 0xbc, 0x13, 0x64, 0x19, 0xf6, 0x59, 0x64, 0x07, 0x1e, 0xc7, - 0xc1, 0xf8, 0x30, 0xcd, 0x32, 0x5a, 0x84, 0xc0, 0x75, 0x6e, 0x80, 0x1d, 0xff, 0x9e, 0x19, 0xd9, - 0x90, 0x47, 0xf6, 0xc1, 0x0f, 0x1a, 0xd9, 0x3e, 0x8d, 0xec, 0xbb, 0x50, 0x74, 0xbc, 0xc8, 0x0e, - 0x5e, 0x5a, 0x6e, 0xfd, 0xe3, 0x39, 0x6e, 0x1c, 0xe3, 0xc4, 0x5d, 0x58, 0x0d, 0x5d, 0x07, 0xd7, - 0x7b, 0xfd, 0x93, 0x39, 0x32, 0x85, 0x12, 0xf7, 0xa0, 0x14, 0x47, 0xb9, 0xaa, 0x7f, 0x3a, 0x47, - 0x97, 0x20, 0xc5, 0x2d, 0x28, 0x9c, 0xe2, 0x84, 0x7a, 0x38, 0x7f, 0x02, 0x8f, 0x70, 0xdc, 0xbe, - 0x0f, 0x51, 0x9f, 0xa7, 0xed, 0xfb, 0xd1, 0xdc, 0xf6, 0xbd, 0xed, 0xb8, 0x2e, 0x6f, 0xdf, 0x87, - 0xf2, 0x17, 0x6e, 0x7e, 0x94, 0x03, 0x5b, 0xf2, 0xd9, 0xfc, 0xe6, 0x87, 0xb8, 0xe7, 0x14, 0x0f, - 0xac, 0x1c, 0xd2, 0xb1, 0x32, 0x9f, 0x8e, 0x7f, 0x9e, 0xee, 0xab, 0xec, 0x79, 0xb3, 0x01, 0x61, - 0x9c, 0x16, 0x6f, 0x82, 0x3c, 0x35, 0x27, 0x85, 0xea, 0x0b, 0xbe, 0x0a, 0xca, 0x10, 0xd4, 0xa5, - 0x3e, 0x81, 0xaa, 0xf2, 0x87, 0x26, 0x01, 0xac, 0xfe, 0xe5, 0x5c, 0x0d, 0xb2, 0x04, 0x62, 0x0b, - 0x2a, 0x87, 0xa8, 0xd7, 0x8f, 0x59, 0xcd, 0xaf, 0x3f, 0xa6, 0x8a, 0xdc, 0x51, 0x1b, 0xeb, 0x45, - 0x66, 0x00, 0x23, 0x93, 0x4b, 0x3c, 0x00, 0xe1, 0x1c, 0xf2, 0x78, 0x6e, 0x07, 0xfe, 0x98, 0x55, - 0xf9, 0xfa, 0x57, 0xf2, 0xa8, 0x61, 0x0e, 0x43, 0x3e, 0x36, 0xb6, 0x37, 0x32, 0xc7, 0xa1, 0x14, - 0x13, 0xbe, 0xa6, 0x7a, 0x4a, 0xe6, 0x15, 0x47, 0xc3, 0x53, 0x67, 0xa8, 0x48, 0xbb, 0x1b, 0xb2, - 0xd4, 0xf0, 0x15, 0xe0, 0x74, 0x7d, 0x99, 0x64, 0xfd, 0xc9, 0x2b, 0xb3, 0x22, 0xad, 0xca, 0xfa, - 0x18, 0x6a, 0x7c, 0xc0, 0x41, 0x12, 0x19, 0x4e, 0xd1, 0x9f, 0xa6, 0x39, 0x57, 0xfa, 0x64, 0xd6, - 0xa8, 0x8c, 0xd2, 0xe7, 0xb4, 0x5f, 0xc2, 0x5a, 0xea, 0x7c, 0x83, 0x3e, 0xfb, 0x5b, 0xe9, 0xcf, - 0xc6, 0x07, 0x1c, 0x46, 0x75, 0xaa, 0x7e, 0xd2, 0x27, 0xe7, 0x04, 0xfe, 0xdf, 0xfe, 0x01, 0x02, - 0xff, 0xdb, 0x90, 0xac, 0x48, 0x73, 0x18, 0xd9, 0xf5, 0x9f, 0x31, 0xf3, 0x8f, 0x81, 0xcd, 0xc8, - 0x16, 0x8f, 0x00, 0xac, 0xc9, 0xc4, 0x3d, 0xe7, 0xa9, 0xf9, 0x73, 0x9a, 0x9a, 0x1b, 0xa9, 0xa9, - 0xd9, 0x40, 0x24, 0xcd, 0xcd, 0x92, 0xa5, 0x7e, 0xa2, 0xce, 0x4a, 0xaa, 0xc4, 0x68, 0xec, 0x52, - 0xfb, 0x1b, 0xe9, 0xb5, 0xbd, 0xe7, 0x87, 0xd1, 0xd6, 0xd8, 0xc5, 0x56, 0xc0, 0x24, 0xfe, 0x2d, - 0x3a, 0x70, 0xd9, 0xf7, 0xcc, 0xd1, 0x74, 0xe2, 0x3a, 0x43, 0xec, 0x01, 0x3e, 0x58, 0xac, 0x6f, - 0xa6, 0xaf, 0x24, 0xd1, 0x17, 0x7b, 0xde, 0x96, 0x22, 0x92, 0x07, 0x96, 0xeb, 0xfe, 0x2c, 0x88, - 0x6c, 0x50, 0x34, 0x06, 0xf1, 0x6d, 0x9e, 0x26, 0x8b, 0x06, 0x04, 0x55, 0xd7, 0x79, 0x1e, 0xc3, - 0x5a, 0x42, 0xc5, 0xd7, 0xa7, 0xb7, 0x2e, 0xb8, 0x3e, 0x5d, 0x55, 0x19, 0xf9, 0xd6, 0x35, 0xf6, - 0x9d, 0xef, 0xba, 0xd3, 0x89, 0x64, 0xa5, 0xf5, 0x96, 0xec, 0x3b, 0x02, 0x32, 0x97, 0x4c, 0x99, - 0xe9, 0xec, 0x71, 0x7d, 0x3b, 0x6d, 0xa6, 0xb3, 0xc7, 0xa2, 0x09, 0x75, 0x62, 0xc5, 0x72, 0x9d, - 0x65, 0xdc, 0x52, 0xda, 0x73, 0xcb, 0xe9, 0x0a, 0xd2, 0xb2, 0xd7, 0xcb, 0x5e, 0xca, 0x41, 0xe5, - 0xe7, 0xf0, 0xe6, 0xe2, 0x42, 0x54, 0xfc, 0x93, 0xa7, 0x24, 0x2b, 0x5c, 0x5f, 0x90, 0x5b, 0x06, - 0x41, 0xf9, 0x1a, 0xaa, 0x47, 0x16, 0xb5, 0xc2, 0x35, 0xc7, 0xfe, 0xc8, 0xae, 0x3f, 0x4b, 0x5f, - 0x00, 0xa4, 0x0e, 0x7f, 0x62, 0x61, 0x83, 0xdc, 0x5d, 0x7f, 0x64, 0x1b, 0xe5, 0xa3, 0x24, 0x21, - 0x1e, 0x43, 0x3d, 0x99, 0x40, 0x53, 0x0f, 0xbf, 0x8b, 0xfa, 0xad, 0xe3, 0x0d, 0xa3, 0x7a, 0x87, - 0x03, 0x57, 0xc6, 0xf8, 0x7d, 0x44, 0x6f, 0x49, 0xac, 0x68, 0x82, 0x46, 0x0b, 0x5b, 0xee, 0x40, - 0xa1, 0x33, 0xb2, 0xeb, 0xbb, 0xe9, 0x68, 0x3e, 0xcc, 0xf6, 0x90, 0x84, 0xf6, 0x9a, 0xbe, 0x33, - 0xb2, 0x8d, 0xda, 0x61, 0x26, 0x2d, 0xde, 0x87, 0x75, 0xa5, 0x4b, 0x98, 0xc7, 0x56, 0x78, 0x6c, - 0x9e, 0xd8, 0xe7, 0xf5, 0x2e, 0x35, 0xb8, 0x26, 0x15, 0x89, 0x1d, 0x2b, 0x3c, 0x7e, 0x66, 0x9f, - 0x8b, 0xfb, 0xb0, 0x2e, 0xb7, 0x3c, 0x27, 0x34, 0x0f, 0xac, 0x20, 0x70, 0xec, 0xa0, 0xde, 0xe3, - 0x13, 0x2d, 0x46, 0xb4, 0xc3, 0x4d, 0x06, 0x8b, 0x0f, 0x41, 0xa4, 0x07, 0x43, 0xfa, 0x58, 0xed, - 0x11, 0x0f, 0xd4, 0x52, 0xde, 0x41, 0xe4, 0x6b, 0x25, 0x3e, 0x81, 0x5a, 0xdc, 0x7f, 0xec, 0x23, - 0xf3, 0x8b, 0x79, 0x5b, 0x86, 0xec, 0xb4, 0x3e, 0x39, 0xc9, 0x7c, 0x08, 0x95, 0x38, 0x87, 0xed, - 0x8d, 0xea, 0xc6, 0xbc, 0x15, 0x4f, 0xd2, 0xe3, 0xce, 0xf0, 0x39, 0x5c, 0xe3, 0x29, 0xca, 0x27, - 0x19, 0x27, 0xf6, 0x79, 0x1c, 0xbc, 0xa9, 0xcf, 0xb1, 0x4f, 0x08, 0xdd, 0x46, 0xec, 0x33, 0xfb, - 0x3c, 0x8c, 0x39, 0xdf, 0x75, 0x3a, 0xe9, 0x1f, 0xca, 0x6b, 0xc2, 0x6c, 0xe5, 0x96, 0x6d, 0x19, - 0xf0, 0xd8, 0x20, 0x41, 0x33, 0xc6, 0x1b, 0xd2, 0x7b, 0x4c, 0x34, 0xd4, 0x75, 0xa9, 0x90, 0x94, - 0x77, 0xde, 0x9d, 0xf7, 0xd3, 0x11, 0x2f, 0x66, 0x54, 0x7b, 0x79, 0x8b, 0x2a, 0x65, 0xb3, 0x7a, - 0x02, 0x37, 0xe2, 0xa3, 0x4b, 0xfb, 0xfb, 0xa9, 0x45, 0xd7, 0x9f, 0x4e, 0xec, 0x73, 0x66, 0x69, - 0x2f, 0xe6, 0x66, 0xf7, 0x35, 0x45, 0xdd, 0x92, 0xc4, 0xcf, 0xec, 0x73, 0xe2, 0x6b, 0x77, 0xa1, - 0x66, 0x85, 0xfe, 0xa1, 0xd4, 0x40, 0x87, 0xbe, 0x5b, 0x7f, 0x4e, 0xe3, 0x50, 0x41, 0xa8, 0xa1, - 0x4e, 0x4a, 0xbb, 0x70, 0x39, 0x19, 0x31, 0xd4, 0xf8, 0x03, 0x27, 0x3a, 0x1e, 0xd7, 0x7f, 0x99, - 0x36, 0xfd, 0xd0, 0x84, 0x8a, 0x27, 0x7f, 0x43, 0x11, 0x19, 0xc9, 0x58, 0xc7, 0x30, 0xf1, 0x18, - 0xae, 0x27, 0xe5, 0x45, 0xfe, 0xc4, 0xf4, 0xcc, 0x53, 0x27, 0x3a, 0x36, 0xc9, 0x37, 0xf8, 0x77, - 0x64, 0x88, 0x1f, 0x45, 0x30, 0xf0, 0x27, 0xdd, 0x17, 0x4e, 0x74, 0x3c, 0x70, 0xec, 0x50, 0x6c, - 0xc2, 0x2d, 0x6b, 0x64, 0x4d, 0x22, 0x5c, 0x10, 0x98, 0x31, 0x0e, 0x4b, 0xe4, 0x7b, 0xa6, 0x3d, - 0x9e, 0x44, 0xe7, 0xf5, 0x3f, 0x47, 0xd9, 0x6f, 0x28, 0xaa, 0x81, 0x3f, 0xd9, 0x96, 0x34, 0x3d, - 0xaf, 0x85, 0x14, 0xe2, 0x11, 0x5c, 0x7d, 0x69, 0x0f, 0x23, 0x3f, 0x30, 0xd9, 0x46, 0x26, 0x45, - 0x7f, 0x67, 0x54, 0xff, 0x5d, 0x6a, 0xfb, 0x65, 0xc6, 0xfe, 0x02, 0x91, 0xec, 0xf0, 0xd3, 0x1e, - 0xa1, 0x36, 0x48, 0x1e, 0xfb, 0x13, 0x2b, 0x3a, 0xae, 0xff, 0x03, 0xe9, 0x8b, 0x03, 0xcf, 0x1d, - 0xfb, 0x14, 0x95, 0x04, 0x83, 0x5c, 0xfa, 0xf7, 0xac, 0xe8, 0x58, 0x3c, 0x54, 0x6c, 0x0f, 0x87, - 0x84, 0xcd, 0x2b, 0xe6, 0xfc, 0x06, 0x4e, 0x24, 0xcf, 0xec, 0x73, 0xda, 0xc0, 0xf5, 0xbf, 0xb8, - 0x02, 0x45, 0x65, 0xfe, 0x10, 0x65, 0x58, 0xdd, 0xef, 0x3e, 0xeb, 0xf6, 0x5e, 0x74, 0x39, 0x02, - 0x5f, 0xa3, 0xdf, 0x6f, 0x19, 0x03, 0x6d, 0x24, 0x6a, 0x00, 0x14, 0x6d, 0xca, 0xec, 0x37, 0x1b, - 0x5d, 0x8e, 0xc8, 0x47, 0x31, 0xae, 0x38, 0xbd, 0x24, 0xd6, 0xa1, 0xba, 0xbd, 0xdf, 0xe5, 0x8b, - 0x49, 0x04, 0xca, 0x23, 0xa8, 0xf5, 0x0d, 0x3b, 0x07, 0x32, 0xa8, 0x80, 0xa0, 0xdd, 0xc6, 0xa0, - 0x65, 0xb4, 0x15, 0x68, 0x59, 0x5c, 0x81, 0xf5, 0x98, 0x4a, 0x95, 0xa0, 0xad, 0x22, 0xb8, 0xdd, - 0xdd, 0x6a, 0x7d, 0x63, 0xf6, 0x5b, 0x0d, 0xa3, 0xb9, 0xc3, 0xd4, 0x45, 0xac, 0xdf, 0x9e, 0xd1, - 0x7b, 0xda, 0x6a, 0x0e, 0x34, 0x20, 0x7f, 0xc3, 0x27, 0x4f, 0xb4, 0xb2, 0xa8, 0x40, 0x71, 0xab, - 0xdd, 0x1f, 0xb4, 0xbb, 0xcd, 0x81, 0x56, 0xc1, 0x6a, 0x6f, 0xb7, 0x3b, 0x83, 0x96, 0xa1, 0x55, - 0x45, 0x11, 0x0a, 0x4f, 0x7b, 0xed, 0xae, 0x56, 0xa3, 0xd8, 0x5b, 0x8d, 0xdd, 0xbd, 0x4e, 0x4b, - 0x5b, 0x43, 0x68, 0xbf, 0x67, 0x0c, 0x34, 0x0d, 0xa1, 0x1c, 0x65, 0x42, 0x5b, 0x17, 0x25, 0x58, - 0xde, 0xef, 0xe2, 0xd7, 0x85, 0xa8, 0x42, 0x89, 0x7e, 0x9a, 0x8d, 0x4e, 0x47, 0xbb, 0x9c, 0x72, - 0x52, 0xdc, 0x40, 0x14, 0xb9, 0x3c, 0xf6, 0xb1, 0x0e, 0x57, 0xb0, 0x45, 0x71, 0x92, 0xa8, 0xaf, - 0x62, 0x39, 0xbb, 0xed, 0xee, 0x7e, 0x5f, 0xbb, 0x86, 0xc4, 0xf4, 0x93, 0x30, 0x75, 0x2c, 0xa7, - 0xdd, 0xa5, 0x0e, 0xbd, 0x85, 0xbf, 0xb7, 0x5a, 0x9d, 0xd6, 0xa0, 0xa5, 0xdd, 0xc6, 0x56, 0x75, - 0x7a, 0xcd, 0x67, 0x66, 0x6f, 0x4f, 0x7b, 0x0b, 0x7b, 0x76, 0xcf, 0x68, 0x99, 0x92, 0xf0, 0x6d, - 0xa1, 0x41, 0x65, 0x7b, 0xff, 0x97, 0xbf, 0xfc, 0xd6, 0x94, 0x8d, 0x7a, 0x07, 0xbf, 0x99, 0x50, - 0x98, 0xfb, 0xcf, 0xb4, 0x77, 0x67, 0x40, 0xfd, 0x67, 0xda, 0x7b, 0xd8, 0x29, 0xaa, 0xaf, 0xb5, - 0x7b, 0x48, 0x60, 0xb4, 0x9a, 0xfb, 0x46, 0xbf, 0xfd, 0xbc, 0x65, 0x36, 0x07, 0x2d, 0xed, 0x7d, - 0xea, 0x85, 0x76, 0xf7, 0x99, 0x76, 0x1f, 0xab, 0x89, 0xbf, 0xb8, 0x93, 0x3f, 0x10, 0x02, 0x6a, - 0x09, 0x2d, 0xc1, 0x3e, 0x44, 0x92, 0x4d, 0xa3, 0xd7, 0xd8, 0x6a, 0x36, 0xfa, 0x03, 0xed, 0x23, - 0x6c, 0x63, 0x7f, 0xaf, 0xd3, 0x1e, 0x68, 0x0f, 0xb0, 0x21, 0x4f, 0x1a, 0x83, 0x9d, 0x96, 0xa1, - 0x7d, 0x2c, 0xd6, 0xa0, 0x3c, 0x68, 0xef, 0xb6, 0x4c, 0xd9, 0xa7, 0x0f, 0xf1, 0x1b, 0xdb, 0xed, - 0x4e, 0x47, 0x7b, 0x44, 0x4e, 0x76, 0x0d, 0x63, 0xd0, 0xa6, 0xf1, 0xfd, 0x0c, 0x0b, 0x68, 0xec, - 0xed, 0x75, 0xbe, 0xd5, 0x3e, 0xc7, 0x06, 0xee, 0xee, 0x77, 0x06, 0x6d, 0x73, 0x7f, 0x6f, 0xab, - 0x31, 0x68, 0x69, 0x5f, 0xd0, 0x28, 0xf7, 0xfa, 0x83, 0xad, 0xdd, 0x8e, 0xf6, 0x25, 0x95, 0x49, - 0x33, 0xad, 0xd9, 0xe9, 0x75, 0x5b, 0xda, 0x63, 0xa4, 0x6f, 0x6c, 0x35, 0xf6, 0x06, 0x58, 0xbb, - 0x41, 0x6f, 0x4f, 0xfb, 0x4a, 0x6c, 0x80, 0xf6, 0xbc, 0xd5, 0x1c, 0xf4, 0x0c, 0xf3, 0x17, 0xfb, - 0x2d, 0xe3, 0x5b, 0x82, 0x7e, 0x2d, 0xae, 0xc1, 0xe5, 0x0c, 0xb4, 0xdf, 0xdb, 0x37, 0x9a, 0x2d, - 0xed, 0x27, 0x7a, 0xa1, 0xb8, 0xa2, 0xad, 0xe8, 0x85, 0xe2, 0x1d, 0xed, 0x8e, 0x5e, 0x28, 0xea, - 0x9a, 0x7e, 0xbf, 0xcc, 0x38, 0x6a, 0xac, 0xfe, 0x57, 0x72, 0x50, 0x54, 0x66, 0x35, 0x8e, 0x5e, - 0xd2, 0x6d, 0x19, 0xda, 0x25, 0x6c, 0x4b, 0xa7, 0xb5, 0x3d, 0xe0, 0xc0, 0x25, 0x46, 0xfb, 0xc9, - 0xce, 0x40, 0x5b, 0xc2, 0x9f, 0xbd, 0x7d, 0x1c, 0x96, 0x3c, 0xf5, 0x67, 0x6b, 0xb7, 0xad, 0x15, - 0xf0, 0x57, 0xa3, 0x3b, 0x68, 0x6b, 0xcb, 0x34, 0xeb, 0xda, 0xdd, 0x27, 0x9d, 0x96, 0xb6, 0x82, - 0xd0, 0xdd, 0x86, 0xf1, 0x4c, 0x5b, 0xe5, 0x42, 0xb7, 0x5a, 0xdf, 0x68, 0x45, 0xb1, 0x02, 0x4b, - 0x9d, 0x87, 0x5a, 0x09, 0x41, 0x5b, 0xad, 0xad, 0xfd, 0x3d, 0x0d, 0x28, 0x77, 0xbf, 0xb7, 0xad, - 0x95, 0xb1, 0xcf, 0xf0, 0x97, 0x49, 0x9f, 0xad, 0xe8, 0xf7, 0x60, 0xb5, 0x71, 0x74, 0x44, 0x1b, - 0x34, 0xf6, 0xeb, 0x7e, 0xa7, 0xc3, 0x8b, 0x74, 0xb3, 0x37, 0x18, 0xf4, 0x76, 0xb5, 0x1c, 0x2e, - 0x08, 0x6c, 0xfa, 0x92, 0xde, 0x86, 0xa2, 0xd2, 0x2c, 0x52, 0x61, 0xea, 0x8a, 0x50, 0xd8, 0x33, - 0x5a, 0xcf, 0xd9, 0x41, 0xb7, 0xdb, 0xfa, 0x06, 0xeb, 0x8f, 0xbf, 0xb0, 0xa0, 0x3c, 0xd6, 0x80, - 0xe3, 0xc9, 0x51, 0x9c, 0xba, 0x4e, 0xbb, 0xdb, 0x6a, 0x18, 0xda, 0xb2, 0xfe, 0x18, 0xca, 0x29, - 0x31, 0x01, 0xe7, 0xd1, 0x93, 0xc6, 0x1e, 0xce, 0xc5, 0x8e, 0x29, 0x8b, 0xbd, 0x0a, 0x22, 0x06, - 0x25, 0x43, 0x9c, 0xd3, 0x3f, 0x87, 0xf5, 0x39, 0x89, 0x8e, 0x2a, 0xde, 0x68, 0xcb, 0x8a, 0xb7, - 0x9f, 0x74, 0x7b, 0x46, 0x8b, 0x43, 0xe6, 0xc9, 0xc1, 0x5f, 0xd2, 0x3f, 0x80, 0x52, 0x2c, 0x7a, - 0xe2, 0x62, 0x68, 0x1a, 0xbd, 0x7e, 0x9f, 0xe7, 0xca, 0x25, 0x4c, 0x53, 0x77, 0x73, 0x3a, 0xa7, - 0x3b, 0x50, 0xcb, 0xca, 0x12, 0xe2, 0x0e, 0xdc, 0xe4, 0xe5, 0xb2, 0xb9, 0xdf, 0xee, 0x6c, 0x99, - 0xfd, 0xf6, 0x56, 0x6b, 0xe6, 0xc6, 0xfa, 0x0d, 0xb8, 0x3a, 0x47, 0xc1, 0xf1, 0xfa, 0x72, 0xe2, - 0x3a, 0x5c, 0x99, 0xc3, 0xd1, 0x22, 0x59, 0xd2, 0xf7, 0x40, 0xcc, 0xef, 0x32, 0xe2, 0x26, 0xd4, - 0xe3, 0x36, 0x9b, 0x8d, 0xce, 0x93, 0x9e, 0xd1, 0x1e, 0xec, 0xec, 0x9a, 0xc4, 0x5e, 0x2e, 0x5d, - 0x84, 0xdd, 0x69, 0xf4, 0x77, 0xb4, 0xdc, 0xd3, 0x42, 0xf1, 0xb6, 0x76, 0xe7, 0x69, 0xa1, 0x78, - 0x57, 0x7b, 0xe7, 0x69, 0xa1, 0xf8, 0x44, 0xdb, 0x79, 0x5a, 0x28, 0xee, 0x68, 0x6d, 0xbd, 0x0f, - 0xeb, 0x4a, 0x94, 0xa7, 0xd8, 0x00, 0x64, 0x63, 0xda, 0x80, 0xe5, 0x8e, 0xfd, 0xd2, 0x76, 0xd5, - 0x55, 0x72, 0x4a, 0x20, 0xb4, 0x77, 0xf0, 0x5d, 0x3b, 0x0e, 0x50, 0x4b, 0x09, 0xd4, 0xdd, 0xbb, - 0xa9, 0x18, 0xb9, 0x14, 0xd6, 0xf1, 0x9f, 0xca, 0x41, 0x31, 0x56, 0x10, 0xee, 0xc2, 0xd2, 0xa0, - 0x2f, 0x0f, 0x9c, 0x36, 0x1e, 0x24, 0xc1, 0xe1, 0x07, 0xea, 0x97, 0xb1, 0x34, 0xe8, 0x8b, 0x0f, - 0x61, 0x85, 0xc3, 0x74, 0xca, 0x23, 0xa6, 0x8d, 0xac, 0xd2, 0x31, 0x20, 0x9c, 0x21, 0x69, 0xc4, - 0xe7, 0x50, 0x8a, 0x6b, 0x2b, 0x4d, 0xe3, 0xd7, 0xb2, 0x19, 0x62, 0xb4, 0x91, 0x50, 0xea, 0x1d, - 0xa8, 0x65, 0x0b, 0x14, 0xb7, 0x00, 0xb8, 0xc8, 0xd4, 0xd9, 0x70, 0x0a, 0x22, 0x6e, 0x80, 0x8a, - 0x1e, 0xba, 0x25, 0x23, 0x4b, 0xc5, 0x69, 0xfd, 0x5f, 0x5e, 0x06, 0x48, 0x4c, 0x0c, 0xd8, 0x11, - 0xb1, 0xc1, 0x7f, 0x59, 0x7a, 0x11, 0xbf, 0x01, 0x25, 0xd7, 0xb7, 0x46, 0xe9, 0x40, 0xe8, 0x45, - 0x04, 0xd0, 0x7c, 0x4b, 0x47, 0xcd, 0x29, 0xc9, 0x00, 0x38, 0x57, 0x61, 0x45, 0x5e, 0x4a, 0xe2, - 0xb8, 0x01, 0x32, 0x45, 0x81, 0x71, 0xc8, 0x09, 0x6e, 0x64, 0xba, 0x8e, 0x67, 0x73, 0x48, 0xc2, - 0x82, 0x51, 0x91, 0xc0, 0x0e, 0xc2, 0xc4, 0x6d, 0x28, 0xdb, 0xde, 0xd0, 0xf5, 0x51, 0x4e, 0x3b, - 0xe0, 0x5b, 0x11, 0x15, 0x03, 0x14, 0x68, 0xf3, 0x9c, 0x5b, 0x1b, 0x8c, 0x1d, 0xcf, 0x8a, 0xa4, - 0x77, 0x10, 0xb5, 0x56, 0x41, 0xb0, 0xba, 0xdf, 0x85, 0xbe, 0xb4, 0xff, 0x73, 0x58, 0x96, 0x22, - 0x02, 0xa8, 0xba, 0x6f, 0x02, 0xd8, 0xe1, 0xd0, 0x9a, 0x70, 0xe1, 0x25, 0x8e, 0xac, 0x29, 0x21, - 0x9b, 0xe7, 0xa2, 0x03, 0xb5, 0xc1, 0x01, 0x6a, 0x36, 0xfe, 0x96, 0x15, 0x59, 0x4d, 0xdf, 0x95, - 0x96, 0xf9, 0xbb, 0xb3, 0xb6, 0x98, 0x07, 0x59, 0x32, 0xbe, 0x9a, 0x37, 0x93, 0x57, 0x7c, 0x06, - 0x15, 0x67, 0x68, 0x1f, 0xd8, 0xc1, 0x11, 0x4b, 0x8e, 0xe5, 0xcc, 0x85, 0x7f, 0xc6, 0x90, 0xd4, - 0x58, 0x76, 0x92, 0x04, 0x6a, 0x8c, 0x63, 0xdf, 0x3b, 0xf2, 0x47, 0x07, 0x9c, 0xab, 0x92, 0xb6, - 0x32, 0xee, 0x22, 0x86, 0xf3, 0x48, 0x22, 0xca, 0xf3, 0x5b, 0xb0, 0x86, 0x3d, 0x1f, 0x46, 0x81, - 0x6d, 0x8d, 0x39, 0x5b, 0x35, 0x3d, 0x03, 0xb1, 0x46, 0x7d, 0x42, 0x52, 0xde, 0x5a, 0x42, 0x4c, - 0xd9, 0x3f, 0x4b, 0xee, 0xcb, 0x53, 0xde, 0x5a, 0xc6, 0x6b, 0x9f, 0x31, 0xfc, 0xd1, 0xc3, 0x24, - 0x21, 0x1e, 0x00, 0x9c, 0x58, 0x87, 0x27, 0x16, 0xe7, 0x59, 0x4b, 0x57, 0xf3, 0x19, 0xc2, 0x29, - 0x47, 0xe9, 0x44, 0xfd, 0xbc, 0xd1, 0x80, 0xcb, 0x0b, 0x7a, 0xed, 0x47, 0xdd, 0x0d, 0xfb, 0x6b, - 0x39, 0xa8, 0x65, 0xdb, 0x32, 0x13, 0xa5, 0xb8, 0x14, 0x47, 0x29, 0x16, 0x50, 0x98, 0xf8, 0x81, - 0xba, 0x11, 0x42, 0xbf, 0x93, 0x07, 0x14, 0xf2, 0xe9, 0x07, 0x14, 0xea, 0xb0, 0x1a, 0xd8, 0x7c, - 0xbd, 0x9b, 0x23, 0x45, 0xa8, 0x24, 0x4e, 0xd8, 0xc9, 0x34, 0x3c, 0xb6, 0x47, 0x4a, 0xb5, 0xe5, - 0x6b, 0x0a, 0x15, 0x06, 0x4a, 0xd5, 0xf6, 0x1a, 0xac, 0x5a, 0x13, 0x87, 0x34, 0x2e, 0x19, 0xf1, - 0xd6, 0x9a, 0x38, 0xcf, 0xec, 0x73, 0xfd, 0x57, 0x50, 0x4e, 0xf5, 0x1d, 0x56, 0x88, 0xc2, 0xca, - 0xc8, 0x43, 0x73, 0x8a, 0x0b, 0x76, 0x15, 0x56, 0x64, 0x90, 0x57, 0xbe, 0x6b, 0x22, 0x53, 0xf8, - 0x61, 0x75, 0x4f, 0x90, 0x24, 0x5f, 0xe5, 0x4a, 0x20, 0x81, 0x24, 0xf0, 0xe2, 0xb2, 0xc6, 0x8a, - 0x8c, 0xfc, 0x53, 0x4f, 0x56, 0x3c, 0x4e, 0xeb, 0xff, 0xde, 0x12, 0x94, 0xe2, 0x41, 0xc0, 0x16, - 0x1e, 0x04, 0xfe, 0x89, 0x1d, 0x84, 0xf2, 0xeb, 0x2a, 0x49, 0x3d, 0xe2, 0x4f, 0x9c, 0xa1, 0xba, - 0x75, 0x4d, 0x09, 0x71, 0x33, 0x7d, 0xc7, 0x92, 0xa3, 0xa5, 0xa4, 0xae, 0x54, 0xde, 0x02, 0xb0, - 0xa6, 0x91, 0x3f, 0xf4, 0xc7, 0x63, 0x27, 0x92, 0x5f, 0x4e, 0x41, 0xb0, 0x4c, 0xd2, 0x39, 0x65, - 0x6f, 0x71, 0x22, 0xc5, 0x14, 0x56, 0x32, 0x4c, 0xe1, 0x26, 0x94, 0x42, 0x7b, 0x62, 0x05, 0x56, - 0xe4, 0x07, 0x72, 0x35, 0x27, 0x00, 0x19, 0xf4, 0x2e, 0x88, 0x54, 0x44, 0xd0, 0x3c, 0x05, 0xbd, - 0x0b, 0xa2, 0xf6, 0x48, 0xdc, 0xa1, 0xab, 0x4e, 0x66, 0x8c, 0x66, 0x3f, 0x6f, 0x38, 0xb6, 0xc2, - 0xbe, 0xa4, 0x10, 0x50, 0x20, 0x9f, 0x1b, 0xf6, 0xf2, 0xa3, 0xdf, 0xe2, 0x3d, 0xa0, 0xa7, 0x3d, - 0xfc, 0x69, 0x64, 0x86, 0xf6, 0xd0, 0xf7, 0x46, 0xa1, 0xf4, 0xf3, 0xab, 0x49, 0x70, 0x9f, 0xa1, - 0xfa, 0x7f, 0xbe, 0x04, 0xe5, 0xd4, 0x1a, 0x25, 0x17, 0x27, 0x6b, 0x42, 0xc7, 0x70, 0xf1, 0x05, - 0xf1, 0x92, 0x84, 0x70, 0x88, 0x92, 0xa1, 0x15, 0x59, 0xae, 0x7f, 0x94, 0x0a, 0xbe, 0x22, 0x21, - 0xed, 0x11, 0x79, 0x1d, 0x5a, 0x63, 0x9b, 0x9f, 0xda, 0x90, 0xd1, 0x01, 0x62, 0x40, 0x32, 0x2f, - 0x0b, 0xe9, 0x79, 0xa9, 0xb1, 0x7b, 0x2a, 0xf7, 0x22, 0x79, 0xa3, 0xde, 0x86, 0xb2, 0x32, 0x6b, - 0xe1, 0x57, 0xa4, 0x07, 0xa5, 0x02, 0xb5, 0x47, 0xe2, 0x5d, 0x48, 0x1e, 0x2e, 0x31, 0xad, 0xd0, - 0xf4, 0x0f, 0xd5, 0xbd, 0xbc, 0x18, 0xdc, 0x08, 0x7b, 0x87, 0xb1, 0x5b, 0x13, 0x99, 0x39, 0x24, - 0x8f, 0x44, 0x00, 0x49, 0x2c, 0x0f, 0xe0, 0x72, 0x12, 0x62, 0xf4, 0xd0, 0xb1, 0xdd, 0x91, 0xe9, - 0x8c, 0xd8, 0x3f, 0x7b, 0xd9, 0x58, 0x8f, 0x51, 0xdb, 0x88, 0x69, 0x8f, 0xc8, 0x00, 0x24, 0x2d, - 0x0a, 0x23, 0xe7, 0xc8, 0x0e, 0x23, 0x79, 0x8b, 0xac, 0xc2, 0xc0, 0x2d, 0x82, 0xe9, 0xff, 0xcf, - 0x0a, 0x94, 0x62, 0xe6, 0xf5, 0xba, 0xce, 0x7c, 0x1b, 0xaa, 0x43, 0xdf, 0xf3, 0xd8, 0x0f, 0x21, - 0xe9, 0xcf, 0x4a, 0x02, 0xa4, 0x8b, 0xc0, 0x22, 0x45, 0x94, 0x0e, 0xac, 0x57, 0x30, 0xd6, 0x13, - 0x8c, 0xbc, 0xe1, 0x8a, 0xab, 0x05, 0xb9, 0xde, 0x81, 0x15, 0xaa, 0x6e, 0x8e, 0xd3, 0x38, 0xa3, - 0x87, 0xbe, 0xeb, 0x4a, 0x3f, 0x09, 0x19, 0x96, 0x3c, 0x81, 0x88, 0x87, 0x14, 0x98, 0x9e, 0xdc, - 0x0c, 0x56, 0xd2, 0x51, 0xeb, 0xa8, 0x41, 0xec, 0x69, 0xb0, 0xcb, 0x95, 0x37, 0x14, 0xa1, 0xf8, - 0x19, 0x68, 0x92, 0x77, 0x4c, 0x02, 0x7b, 0x44, 0x12, 0x9d, 0xbc, 0x04, 0xb1, 0x91, 0xca, 0xbc, - 0xa7, 0x70, 0xc6, 0x1a, 0x53, 0xc7, 0x00, 0x9c, 0xa9, 0xc9, 0x30, 0xa0, 0x32, 0xcb, 0xae, 0xf5, - 0x25, 0xa3, 0x16, 0x83, 0x51, 0x85, 0x0d, 0xc5, 0x67, 0x70, 0x35, 0xb0, 0x43, 0x67, 0x34, 0xb5, - 0x5c, 0x33, 0x3b, 0x10, 0x1c, 0xe4, 0x7c, 0x43, 0x61, 0xb7, 0x53, 0x03, 0x82, 0xc5, 0x8f, 0xad, - 0x33, 0x3a, 0x91, 0x72, 0x5d, 0xdb, 0x75, 0xc2, 0xb1, 0x8c, 0x75, 0x5b, 0x1b, 0x5b, 0x67, 0x7b, - 0x09, 0x94, 0x6e, 0x3c, 0x4d, 0x5c, 0x67, 0x26, 0xb2, 0x29, 0x8f, 0x25, 0xc2, 0x0d, 0x46, 0x0b, - 0x1d, 0xaa, 0x58, 0x20, 0x19, 0x5f, 0x63, 0x67, 0xf9, 0xbc, 0x51, 0x1e, 0x5b, 0x74, 0x4a, 0x49, - 0xae, 0x7c, 0x77, 0xa1, 0x16, 0xd3, 0xb0, 0x7f, 0xae, 0x74, 0x91, 0x95, 0x44, 0xec, 0xa2, 0x4b, - 0x55, 0xe3, 0xd9, 0xa1, 0x86, 0xb5, 0xc6, 0xee, 0x49, 0x12, 0xac, 0xc6, 0xf4, 0x3a, 0xf0, 0xb9, - 0x2e, 0x4e, 0x91, 0x35, 0xa2, 0x58, 0xa5, 0x34, 0xaf, 0x84, 0x69, 0x68, 0x2b, 0xc3, 0x01, 0x31, - 0x5e, 0x8e, 0x3d, 0x5a, 0x45, 0x30, 0x31, 0x50, 0x0a, 0xb6, 0x78, 0x0f, 0x34, 0xa2, 0x53, 0xc7, - 0x40, 0xa1, 0xef, 0xd1, 0x11, 0x72, 0xc5, 0xa8, 0x21, 0x5c, 0x1e, 0xf2, 0x84, 0xbe, 0x27, 0xbe, - 0x84, 0x3a, 0x51, 0x4e, 0x9c, 0x89, 0x8d, 0xe2, 0x8b, 0xc9, 0xd1, 0x38, 0x29, 0x87, 0xb8, 0x93, - 0xbf, 0x57, 0x31, 0xae, 0x20, 0x7e, 0x4f, 0xa2, 0x29, 0x24, 0x21, 0x65, 0xbc, 0x0f, 0xeb, 0xa9, - 0xaa, 0xc8, 0xa1, 0xe1, 0xe8, 0x67, 0x6b, 0x71, 0x65, 0xe4, 0xa8, 0x7c, 0x02, 0x1b, 0xd2, 0x83, - 0x45, 0x92, 0xf3, 0x74, 0xa2, 0x53, 0xe4, 0xa2, 0x21, 0x24, 0x8e, 0x72, 0xf0, 0xbc, 0x13, 0x6f, - 0x41, 0x85, 0xcc, 0x29, 0x32, 0x76, 0xb1, 0x8c, 0x80, 0x56, 0x26, 0x18, 0x07, 0x2d, 0xd3, 0xff, - 0x52, 0x0e, 0xc4, 0xfc, 0x54, 0xbd, 0x28, 0xdc, 0x0e, 0xd9, 0x4d, 0x64, 0xac, 0x0b, 0xfc, 0x2d, - 0xde, 0x87, 0xd5, 0xb1, 0xcf, 0xe2, 0x54, 0xfe, 0x82, 0x88, 0x7a, 0x2b, 0x63, 0x9f, 0xc4, 0xab, - 0xf7, 0x60, 0x6d, 0xe8, 0x7b, 0x72, 0xd0, 0x98, 0xbb, 0xf0, 0x5a, 0xab, 0x25, 0x60, 0xe4, 0x31, - 0xfa, 0xbf, 0x9b, 0x83, 0x5a, 0x76, 0x01, 0x88, 0x77, 0xe9, 0x7d, 0x84, 0xcc, 0x0b, 0x0b, 0x59, - 0x8a, 0xde, 0x84, 0xde, 0x4d, 0x58, 0x54, 0xc5, 0x37, 0x01, 0x48, 0x48, 0xe0, 0xd1, 0x90, 0x01, - 0xd3, 0x09, 0x42, 0x23, 0x70, 0x1b, 0xca, 0xfc, 0x18, 0x12, 0xe3, 0x0b, 0x34, 0x5a, 0x9c, 0x23, - 0x24, 0x82, 0x4f, 0x52, 0xee, 0x27, 0xec, 0x5e, 0xb2, 0x78, 0x91, 0xc6, 0x54, 0xfa, 0x1f, 0xe4, - 0x00, 0x92, 0x35, 0x80, 0x33, 0xf1, 0xc4, 0x3e, 0x67, 0x9b, 0x93, 0xdc, 0x62, 0x4f, 0xec, 0xf3, - 0x3d, 0x59, 0x37, 0xe9, 0xd6, 0x18, 0xca, 0x3b, 0xa5, 0x15, 0xa3, 0xc4, 0x9e, 0x8c, 0x21, 0x07, - 0x79, 0x92, 0x8e, 0x8c, 0xa9, 0xaa, 0xb3, 0xef, 0x62, 0x48, 0x71, 0x3a, 0xd6, 0x38, 0x37, 0x0d, - 0x7d, 0xe8, 0xbc, 0x54, 0xe1, 0xac, 0xd8, 0xf1, 0xb2, 0xad, 0xa0, 0x48, 0xc8, 0xe5, 0x24, 0x84, - 0x7c, 0xc9, 0x8b, 0xdd, 0x2c, 0x63, 0x42, 0xdd, 0x55, 0x02, 0x7f, 0x23, 0x8a, 0x68, 0x83, 0x8d, - 0xcf, 0x05, 0x72, 0x2a, 0x86, 0x15, 0x1f, 0x09, 0xbc, 0x41, 0x77, 0x61, 0x65, 0x7c, 0x0a, 0x29, - 0xf7, 0xc7, 0x71, 0x27, 0xde, 0xc5, 0x91, 0x76, 0xd5, 0xf6, 0x10, 0xfb, 0xc9, 0x2d, 0x1b, 0xd5, - 0xa1, 0xef, 0xf2, 0xd6, 0x80, 0x40, 0xfd, 0xbf, 0x5c, 0x06, 0x48, 0x4e, 0x84, 0x33, 0x2b, 0x36, - 0x97, 0x5d, 0xb1, 0x0f, 0xe1, 0xaa, 0x8c, 0x52, 0x18, 0x5f, 0xf8, 0x72, 0x3c, 0xf3, 0xc0, 0x52, - 0x22, 0x9c, 0x90, 0x58, 0xbe, 0xa6, 0xd3, 0xf6, 0x36, 0xad, 0x48, 0x3c, 0x46, 0x1e, 0x99, 0xe4, - 0x89, 0xce, 0x27, 0x17, 0x4e, 0xd1, 0x6a, 0x92, 0x7d, 0x70, 0x3e, 0x11, 0x9f, 0x50, 0x1c, 0xa6, - 0xc0, 0x0e, 0x8f, 0xcd, 0x28, 0x4c, 0x7f, 0x8c, 0x6f, 0xdd, 0xaf, 0x4b, 0xe4, 0x20, 0x8c, 0xbf, - 0xf5, 0x09, 0x5c, 0x91, 0x4c, 0x62, 0xa6, 0x7a, 0xec, 0x8e, 0x29, 0xad, 0xea, 0xe9, 0xda, 0xd1, - 0xc8, 0xd3, 0x31, 0xb9, 0x7a, 0xb4, 0xab, 0x88, 0x23, 0x8f, 0x9d, 0x21, 0x1f, 0x25, 0xa0, 0xb3, - 0x6e, 0x29, 0xb9, 0x70, 0x42, 0xe8, 0x50, 0xc0, 0x15, 0x42, 0xcc, 0xb8, 0xf6, 0xb0, 0xf6, 0x80, - 0x1e, 0x25, 0xa3, 0x07, 0x25, 0xfc, 0x91, 0x6d, 0x10, 0x4e, 0x7c, 0x84, 0x3b, 0x74, 0xd2, 0x6c, - 0xf5, 0x9a, 0x4a, 0x59, 0x1a, 0xe6, 0xe3, 0x86, 0x1a, 0xfc, 0xae, 0xca, 0x07, 0x20, 0x52, 0x35, - 0x57, 0xd4, 0x15, 0xa2, 0x5e, 0x8b, 0xab, 0x2d, 0x89, 0xdf, 0x03, 0xaa, 0x62, 0x72, 0x75, 0x69, - 0xe6, 0x60, 0x18, 0x91, 0xf2, 0xba, 0xd3, 0x95, 0xa4, 0x75, 0xa6, 0x15, 0x99, 0xd1, 0xb1, 0x4d, - 0x56, 0x7c, 0xbe, 0xbb, 0xb4, 0x1e, 0x37, 0xb4, 0x11, 0x0d, 0x8e, 0xed, 0x16, 0xf1, 0xda, 0xd8, - 0xf5, 0x66, 0xed, 0xd5, 0xae, 0x37, 0x5f, 0x40, 0x3d, 0x7b, 0x80, 0x93, 0xea, 0x6e, 0x66, 0xe3, - 0x1b, 0xe9, 0x3b, 0x61, 0x71, 0x8f, 0xdf, 0x87, 0x75, 0x94, 0x09, 0x33, 0x79, 0xa5, 0xcf, 0xde, - 0xda, 0xb1, 0x15, 0xa6, 0x4f, 0x7c, 0xd8, 0x5d, 0xcd, 0x3c, 0xb5, 0x9c, 0x88, 0x1c, 0x81, 0x8a, - 0xc6, 0x8a, 0xe7, 0xbf, 0xb0, 0x1c, 0xf6, 0x31, 0x39, 0x71, 0x26, 0x74, 0x8f, 0xc3, 0x1e, 0x11, - 0xa7, 0x2e, 0x1a, 0x80, 0x20, 0x8e, 0xab, 0xa2, 0xff, 0x23, 0xab, 0x50, 0xcb, 0x9e, 0xae, 0x73, - 0x24, 0x38, 0x96, 0x10, 0x72, 0x24, 0x27, 0xc5, 0x72, 0xc0, 0x1b, 0x50, 0xe2, 0x2b, 0x67, 0xc8, - 0xc6, 0xd5, 0x73, 0x00, 0x27, 0x92, 0x79, 0xbf, 0x0f, 0xab, 0x93, 0x93, 0xd7, 0xb0, 0xd6, 0x09, - 0x47, 0x64, 0x79, 0x1f, 0x56, 0xa7, 0x27, 0xc9, 0x63, 0x0f, 0x0b, 0x49, 0xa7, 0x27, 0xd2, 0x07, - 0xfb, 0xba, 0xf4, 0x0b, 0x90, 0xf7, 0xd1, 0xc6, 0x53, 0x37, 0x72, 0x4c, 0xb2, 0x62, 0x4b, 0xa6, - 0x70, 0x95, 0x09, 0xda, 0x84, 0xa7, 0x98, 0x0e, 0x74, 0x16, 0x8b, 0x6d, 0x97, 0x71, 0xa0, 0x62, - 0x69, 0x67, 0xd9, 0x00, 0x8e, 0xfb, 0x44, 0xcd, 0x79, 0x1f, 0x34, 0xf5, 0x22, 0x5b, 0x4c, 0xb5, - 0x4a, 0x54, 0x6b, 0x0a, 0xae, 0x48, 0xdf, 0x81, 0x9a, 0xbc, 0x35, 0xa4, 0x08, 0x39, 0x50, 0x41, - 0x95, 0xa1, 0x8a, 0xec, 0x0b, 0xb8, 0xe6, 0x8f, 0x4e, 0xa6, 0xea, 0x02, 0x9c, 0x15, 0x1c, 0x38, - 0x51, 0x60, 0xc5, 0x11, 0xf2, 0x8a, 0xc6, 0x15, 0x44, 0x33, 0xff, 0x68, 0x24, 0x48, 0x2c, 0x5e, - 0x66, 0x51, 0xc5, 0x03, 0xd5, 0xa3, 0xca, 0x50, 0x55, 0xfc, 0x67, 0x70, 0x35, 0x0e, 0xcd, 0x62, - 0x8f, 0x6d, 0x2f, 0x32, 0x03, 0x9b, 0x3c, 0xd6, 0xe4, 0x7b, 0x2d, 0x1b, 0x2a, 0x42, 0x0b, 0x21, - 0x0d, 0xc6, 0x89, 0x87, 0x70, 0x65, 0x26, 0x97, 0x1c, 0x41, 0x5e, 0x35, 0x97, 0x33, 0x99, 0xe4, - 0x60, 0xb6, 0xe0, 0xf6, 0x4c, 0x9e, 0x4c, 0x34, 0x53, 0xcc, 0x5d, 0xa5, 0xdc, 0x37, 0x33, 0xb9, - 0xd3, 0xf1, 0x36, 0xb1, 0x98, 0x2f, 0xa1, 0x3e, 0x53, 0x0c, 0x8e, 0x08, 0xb3, 0x58, 0x8e, 0xda, - 0x7a, 0x25, 0x93, 0xff, 0x99, 0x7d, 0xce, 0x2c, 0xf9, 0x67, 0x70, 0x73, 0x26, 0x63, 0xa6, 0xfb, - 0xe5, 0x05, 0xc1, 0xeb, 0x99, 0xcc, 0xbd, 0xd4, 0x50, 0xe0, 0x54, 0xc5, 0x4f, 0xb1, 0xd7, 0xa8, - 0x46, 0xb2, 0x26, 0xee, 0x6a, 0xe4, 0x30, 0x8a, 0x7c, 0x01, 0x91, 0x7c, 0x34, 0xbc, 0x3e, 0x7b, - 0x34, 0x4c, 0x84, 0x7c, 0x1e, 0xfc, 0x2e, 0xac, 0x29, 0x42, 0x3e, 0x64, 0x0b, 0x49, 0x3c, 0x5a, - 0x36, 0xaa, 0x92, 0x84, 0xce, 0xd6, 0x42, 0xf1, 0x73, 0xd8, 0x40, 0xba, 0x91, 0x63, 0x1d, 0x79, - 0x7e, 0x18, 0x39, 0x43, 0x79, 0xfe, 0x72, 0x39, 0x7d, 0x64, 0xa3, 0x1c, 0xbf, 0x0c, 0x71, 0x62, - 0x9f, 0x6f, 0xc5, 0xa4, 0x7c, 0x10, 0xf3, 0x97, 0x97, 0xa1, 0x92, 0x76, 0x7e, 0xfa, 0x21, 0x17, - 0xfa, 0x7e, 0xd4, 0x75, 0x58, 0xa9, 0x62, 0x52, 0xaf, 0x22, 0x27, 0xc9, 0xc7, 0x2a, 0x66, 0x63, - 0x1a, 0xa1, 0x34, 0x45, 0x6a, 0x9f, 0xef, 0xaa, 0xf0, 0x47, 0xbc, 0x77, 0xe0, 0xae, 0x29, 0x23, - 0x1f, 0x7d, 0x22, 0xa3, 0xab, 0x4d, 0xd4, 0xf1, 0xd2, 0x22, 0xf7, 0x6e, 0x15, 0x0d, 0x93, 0x02, - 0x6d, 0x3c, 0x84, 0xb5, 0x24, 0x96, 0x15, 0x67, 0x59, 0x99, 0xcb, 0x52, 0x8d, 0x03, 0x59, 0xc9, - 0x47, 0x1d, 0xaa, 0x4e, 0x68, 0xfa, 0xee, 0x48, 0xc5, 0x24, 0x5c, 0x55, 0xae, 0xa9, 0x3d, 0x77, - 0x24, 0xe3, 0x0e, 0x32, 0x8d, 0x67, 0x9f, 0x2a, 0x9a, 0xd8, 0x7d, 0xb5, 0x6b, 0x9f, 0x4a, 0x9a, - 0x07, 0x70, 0x19, 0x9b, 0x2b, 0x57, 0x15, 0x07, 0x22, 0xf1, 0x03, 0xb9, 0x0a, 0x91, 0xb1, 0xf2, - 0x22, 0xec, 0x4b, 0x44, 0xea, 0x2a, 0x6a, 0xe0, 0x9f, 0x9a, 0xde, 0x74, 0x7c, 0xc0, 0x5b, 0x8c, - 0x54, 0x24, 0xe4, 0x55, 0x54, 0xc3, 0x3f, 0xed, 0x12, 0x0a, 0xfb, 0xeb, 0x3e, 0xac, 0xab, 0x75, - 0x3e, 0xa4, 0xa3, 0x41, 0x75, 0x9b, 0x7a, 0xd9, 0x58, 0x63, 0x44, 0x83, 0xe0, 0x48, 0xfb, 0x7e, - 0x4c, 0xcb, 0x97, 0x62, 0x89, 0x96, 0xd7, 0x5f, 0x2d, 0x4a, 0x6e, 0xc4, 0x22, 0x69, 0x13, 0x6e, - 0x45, 0x81, 0x35, 0x3c, 0x31, 0x2f, 0x5a, 0x80, 0xf2, 0x12, 0xee, 0x1b, 0x44, 0xd5, 0x58, 0xb8, - 0xfc, 0x7e, 0xc8, 0xfa, 0xad, 0xbd, 0x7e, 0xfd, 0xea, 0xbf, 0x57, 0x80, 0xf5, 0x39, 0xaf, 0x31, - 0x54, 0xe6, 0x93, 0x17, 0x26, 0xf1, 0x27, 0x0a, 0xee, 0x63, 0x2b, 0x1a, 0x1e, 0xa3, 0x7e, 0x78, - 0xe8, 0x9c, 0xa9, 0x97, 0x43, 0x09, 0xb6, 0x47, 0x20, 0xe4, 0xc6, 0x2c, 0xd3, 0xb1, 0x5f, 0x2d, - 0x0b, 0x58, 0x2c, 0x2e, 0xb2, 0xb7, 0xbd, 0x0a, 0x67, 0x52, 0xb8, 0x20, 0x9c, 0xc9, 0x0d, 0x28, - 0x79, 0x3e, 0x5d, 0x91, 0x9e, 0x9c, 0x48, 0xce, 0xbf, 0xea, 0xf9, 0x51, 0xcf, 0xdb, 0x3b, 0x41, - 0x16, 0x37, 0x0d, 0xe9, 0x92, 0xdb, 0x81, 0x1d, 0x84, 0xc7, 0x4e, 0xec, 0xbf, 0xc1, 0x82, 0xca, - 0xe5, 0x69, 0x68, 0xef, 0xc6, 0x38, 0x69, 0xeb, 0x6a, 0x40, 0x85, 0x66, 0xb2, 0x37, 0xf4, 0xc9, - 0x23, 0x8c, 0xaf, 0x14, 0xdc, 0x5a, 0xe0, 0x2a, 0xf7, 0xcc, 0x3e, 0x6f, 0x49, 0x2a, 0x03, 0xb7, - 0x14, 0x95, 0x10, 0xef, 0x53, 0x78, 0xa9, 0x03, 0x3b, 0xb1, 0xcf, 0x66, 0x19, 0x49, 0x89, 0xb0, - 0xb4, 0x8f, 0x3d, 0x83, 0xeb, 0xbc, 0x19, 0x8d, 0x27, 0xbe, 0x87, 0xe3, 0x91, 0x64, 0x0c, 0xb3, - 0xce, 0xd5, 0xa9, 0x4d, 0xf0, 0x2a, 0x6d, 0x56, 0x32, 0xc7, 0x9e, 0x2a, 0x8b, 0x7c, 0xe8, 0xd9, - 0xc3, 0x82, 0x3a, 0x0c, 0xe6, 0x5d, 0xd4, 0x08, 0x4b, 0xeb, 0xe9, 0x7d, 0xd0, 0xc2, 0xa1, 0xe5, - 0x5a, 0x41, 0x4a, 0x75, 0xe7, 0xcd, 0x62, 0x8d, 0xe1, 0x89, 0xd2, 0xf2, 0x26, 0xc0, 0x78, 0x1a, - 0x46, 0x26, 0x39, 0xfc, 0xa8, 0x40, 0xdc, 0x08, 0xa1, 0x13, 0x19, 0xfd, 0x26, 0xac, 0xb4, 0x63, - 0xef, 0xc0, 0x38, 0xde, 0x44, 0x5e, 0x3e, 0x4a, 0xe7, 0x43, 0x89, 0x5d, 0x4f, 0x76, 0xad, 0x89, - 0xb8, 0x0f, 0xf9, 0xb1, 0x35, 0x91, 0x37, 0x91, 0xe2, 0xa8, 0xf8, 0x12, 0xfb, 0x60, 0xd7, 0x9a, - 0xb0, 0x8d, 0x19, 0x89, 0x6e, 0x7c, 0x01, 0x45, 0x05, 0xf8, 0x51, 0xe6, 0xd3, 0xff, 0x76, 0x09, - 0x4a, 0x5b, 0x69, 0xef, 0x5e, 0xd4, 0xc3, 0xa3, 0x60, 0xea, 0x51, 0x13, 0xe5, 0xf3, 0x5b, 0x43, - 0xcb, 0x1b, 0x48, 0x90, 0x62, 0xa8, 0x4b, 0xaf, 0x60, 0xa8, 0x37, 0x01, 0xe4, 0xf2, 0x74, 0x46, - 0x4a, 0x07, 0x28, 0x06, 0xb8, 0x30, 0xdb, 0xa3, 0xb3, 0xc5, 0xf7, 0xa7, 0x0b, 0x3f, 0xfc, 0xfe, - 0xf4, 0xf2, 0xc2, 0xfb, 0xd3, 0xef, 0x26, 0x62, 0x3f, 0xed, 0x8d, 0xa3, 0x33, 0xf9, 0xd4, 0x8f, - 0x12, 0xf2, 0x71, 0x4f, 0x1c, 0x9d, 0x89, 0xaf, 0xa1, 0xa6, 0x5a, 0x27, 0xcb, 0x83, 0x4c, 0xd0, - 0x44, 0x89, 0x63, 0x77, 0xe0, 0x6a, 0x94, 0x4e, 0x66, 0x37, 0x8a, 0xf2, 0x6b, 0xee, 0x68, 0xff, - 0x0b, 0x39, 0x10, 0xd2, 0x99, 0x6b, 0x7b, 0xea, 0xba, 0x03, 0xfb, 0x8c, 0xf6, 0xa3, 0xfb, 0xb0, - 0x9e, 0xb9, 0x7c, 0x94, 0xd2, 0xb2, 0xd6, 0x52, 0xb7, 0x8d, 0x54, 0xa0, 0xea, 0xb9, 0xb0, 0xc4, - 0x4b, 0x0b, 0xc3, 0x12, 0x2f, 0x0e, 0x77, 0x7c, 0x1b, 0xca, 0xe9, 0xa0, 0xbe, 0xac, 0x76, 0xd3, - 0xb5, 0x11, 0x8e, 0xe7, 0xab, 0xff, 0xf7, 0x4b, 0x00, 0x89, 0xc3, 0xd9, 0x9f, 0xf6, 0xe5, 0xf7, - 0x05, 0x43, 0x92, 0x5f, 0x34, 0x24, 0xf7, 0x40, 0x4b, 0xd3, 0xa5, 0xa2, 0x4b, 0xd7, 0x12, 0x42, - 0xa5, 0x7e, 0x3a, 0x61, 0x3a, 0x42, 0x2f, 0xc5, 0x72, 0x93, 0xf7, 0x85, 0x19, 0xc9, 0x42, 0xac, - 0x64, 0x58, 0x45, 0x27, 0x64, 0x49, 0x80, 0xe4, 0x5f, 0x95, 0x93, 0xdc, 0x55, 0xfc, 0x69, 0x14, - 0xdf, 0x2c, 0x5a, 0x95, 0xf2, 0xaf, 0x2c, 0xe9, 0x05, 0xa3, 0xd5, 0xcd, 0xa2, 0xcf, 0xa1, 0x74, - 0x38, 0x75, 0x5d, 0x33, 0xb2, 0xcf, 0xd4, 0x6d, 0xa7, 0x7a, 0xc6, 0x57, 0x2f, 0x35, 0xbc, 0x46, - 0xf1, 0x50, 0x26, 0xf4, 0x7f, 0xba, 0x08, 0xcb, 0x6c, 0x94, 0xff, 0x02, 0x4a, 0x61, 0x34, 0x8e, - 0xd2, 0xd7, 0x66, 0xa4, 0x1f, 0x17, 0xe1, 0xe9, 0xd6, 0x0b, 0x6d, 0x1b, 0x2c, 0x35, 0x21, 0x2d, - 0xf1, 0xba, 0x0d, 0x58, 0x0e, 0x23, 0x7b, 0x12, 0xca, 0x98, 0x32, 0x9c, 0x10, 0x77, 0x60, 0xd9, - 0xf3, 0x47, 0xb3, 0x4f, 0x99, 0x74, 0x51, 0x13, 0x64, 0x84, 0xd0, 0x61, 0x25, 0x1e, 0xf1, 0xb9, - 0xab, 0x2b, 0x8c, 0xa1, 0x78, 0x74, 0xb6, 0x85, 0xdc, 0x57, 0x45, 0xeb, 0x8e, 0xd3, 0xa8, 0xb8, - 0xd0, 0x59, 0x9e, 0x75, 0xa4, 0x5e, 0x41, 0x90, 0x49, 0x71, 0x07, 0xca, 0xf8, 0xf3, 0x45, 0xe0, - 0x44, 0x76, 0xff, 0x91, 0x92, 0x29, 0x52, 0x20, 0x71, 0x0b, 0x60, 0x64, 0x47, 0xf6, 0x30, 0xea, - 0x7f, 0xef, 0x2a, 0xe3, 0x64, 0x0a, 0x22, 0xbe, 0x06, 0x71, 0x60, 0x0d, 0x4f, 0x8e, 0x02, 0xba, - 0x0a, 0xfa, 0xfd, 0xd4, 0x0e, 0x9c, 0x98, 0x71, 0x97, 0x53, 0x9d, 0x62, 0xac, 0x27, 0x64, 0xbf, - 0x60, 0x2a, 0x71, 0x15, 0x56, 0xc6, 0xd6, 0xd9, 0x96, 0x3f, 0x91, 0xd6, 0x7b, 0x99, 0x12, 0x8f, - 0xe0, 0x2a, 0xca, 0x28, 0xe9, 0xc8, 0x2a, 0xd2, 0x3d, 0x92, 0x39, 0x34, 0x4a, 0x30, 0x49, 0x48, - 0x15, 0x79, 0x86, 0xbe, 0x09, 0x1b, 0xca, 0x38, 0xaf, 0x5e, 0x30, 0x1a, 0x3a, 0x71, 0x40, 0xd3, - 0xb9, 0xc9, 0x7f, 0x59, 0x12, 0x6f, 0xa5, 0x68, 0xc5, 0xdb, 0x50, 0xc5, 0x0f, 0x07, 0x76, 0x34, - 0x0d, 0x3c, 0xdc, 0xfb, 0x58, 0xa2, 0x40, 0x01, 0xd1, 0x50, 0x30, 0xf6, 0xf7, 0x96, 0x09, 0xbe, - 0xa1, 0xc0, 0x12, 0x43, 0x35, 0x86, 0xd2, 0x25, 0x85, 0x47, 0x70, 0x95, 0x3d, 0x49, 0xc3, 0xef, - 0x5d, 0x29, 0x67, 0x99, 0xc9, 0xd5, 0x99, 0xa2, 0x71, 0x99, 0xb0, 0xfd, 0xef, 0x5d, 0x16, 0xb5, - 0x78, 0xaf, 0xef, 0xc1, 0xd5, 0xa9, 0x17, 0xd8, 0xa1, 0xef, 0xbe, 0x8c, 0x23, 0x47, 0x1f, 0x3b, - 0x28, 0x5e, 0x6b, 0xe9, 0x2b, 0x87, 0xfb, 0x31, 0x8d, 0xbc, 0x7c, 0xe8, 0x45, 0xc6, 0xc6, 0x74, - 0x1e, 0x18, 0x8a, 0xdf, 0x86, 0x9b, 0xe4, 0x28, 0x35, 0x96, 0x4f, 0x24, 0xc9, 0xbe, 0x09, 0x51, - 0x5c, 0x98, 0x8e, 0x0e, 0xa5, 0xde, 0x5c, 0x47, 0x1a, 0xf5, 0x8a, 0x12, 0xf7, 0x48, 0xd8, 0xf3, - 0xf6, 0x47, 0x87, 0xe2, 0xa7, 0xb0, 0x46, 0xf9, 0xe3, 0x90, 0xd5, 0x2c, 0xe8, 0xc7, 0xec, 0xf5, - 0xb9, 0x63, 0x9f, 0x1a, 0x0a, 0x67, 0xd4, 0x5e, 0xa6, 0x93, 0xa1, 0xf8, 0x12, 0xca, 0xc3, 0xe4, - 0x01, 0x17, 0x79, 0xb5, 0x66, 0xc1, 0x3b, 0x52, 0x13, 0x7b, 0x68, 0xa4, 0x29, 0x45, 0x17, 0x36, - 0xd4, 0x43, 0x84, 0x99, 0xc1, 0xe4, 0x6b, 0x71, 0x6f, 0x64, 0x1e, 0x24, 0xdc, 0x73, 0x2d, 0x2f, - 0x1e, 0xc5, 0x73, 0xe3, 0xb2, 0xcc, 0x98, 0x1e, 0x58, 0xfd, 0x77, 0xa1, 0x9a, 0x59, 0x94, 0x73, - 0x2e, 0x5d, 0xfd, 0x56, 0xa7, 0xd5, 0x1c, 0xb0, 0xd3, 0x85, 0x74, 0x32, 0x5a, 0x4a, 0x79, 0x23, - 0x15, 0x52, 0xce, 0x18, 0xf4, 0xca, 0xce, 0x6e, 0xcb, 0x78, 0xd2, 0x22, 0x7f, 0x99, 0xbc, 0x96, - 0xd7, 0xff, 0xc5, 0x25, 0x58, 0x1f, 0x04, 0x96, 0x17, 0xca, 0x07, 0xcf, 0xbd, 0x28, 0xf0, 0x5d, - 0xf1, 0x35, 0x14, 0xa3, 0xa1, 0x9b, 0xe6, 0x12, 0xb7, 0xd5, 0x9e, 0x34, 0x43, 0xfa, 0x60, 0x30, - 0x64, 0x87, 0xf7, 0xd5, 0x88, 0x7f, 0x88, 0x8f, 0x60, 0xf9, 0xc0, 0x3e, 0x72, 0x3c, 0xb9, 0x2d, - 0x5f, 0x99, 0xcd, 0xb8, 0x89, 0xc8, 0x9d, 0x4b, 0x06, 0x53, 0x89, 0x4f, 0x60, 0x45, 0x1e, 0xd5, - 0xe5, 0xd3, 0xf7, 0x4e, 0xd2, 0x1f, 0x42, 0xec, 0xce, 0x25, 0x43, 0xd2, 0x89, 0x2f, 0xa0, 0x18, - 0xf8, 0xf2, 0x75, 0xc3, 0x42, 0x9a, 0x07, 0x26, 0x79, 0x0c, 0x89, 0xdf, 0xb9, 0x64, 0xc4, 0xb4, - 0xfa, 0x03, 0x58, 0x95, 0x95, 0xc5, 0x6e, 0xd8, 0x6c, 0x3d, 0x69, 0xcb, 0x1e, 0x6c, 0xf6, 0x76, - 0x77, 0xdb, 0x03, 0x8e, 0x01, 0x6e, 0xf4, 0x3a, 0x9d, 0xcd, 0x46, 0xf3, 0x99, 0xb6, 0xb4, 0x59, - 0x84, 0x15, 0x5e, 0xbb, 0xfa, 0x3f, 0x9a, 0x83, 0xb5, 0x99, 0x06, 0x88, 0xc7, 0x50, 0x18, 0xab, - 0xd7, 0x97, 0x6a, 0xea, 0x04, 0x7e, 0x86, 0x28, 0x95, 0x66, 0xf3, 0x18, 0xe6, 0xd0, 0xbf, 0x82, - 0x5a, 0x16, 0x9e, 0x72, 0xe9, 0xa9, 0x42, 0xc9, 0x68, 0x35, 0xb6, 0xcc, 0x5e, 0xb7, 0xf3, 0x2d, - 0x7b, 0xe5, 0x51, 0xf2, 0x85, 0xd1, 0x26, 0x5f, 0x9a, 0xdf, 0x01, 0x6d, 0xb6, 0x63, 0xc4, 0x13, - 0x58, 0x43, 0x11, 0xd4, 0xb5, 0xd9, 0x09, 0x32, 0x19, 0xb2, 0x5b, 0x0b, 0x7a, 0x52, 0x92, 0xf1, - 0x05, 0xf7, 0x61, 0x26, 0xad, 0xff, 0x2e, 0x88, 0xf9, 0x1e, 0xfc, 0xd3, 0x2b, 0xfe, 0xff, 0xcc, - 0x41, 0x01, 0x27, 0xbc, 0x78, 0x1b, 0x96, 0xf9, 0xd4, 0x38, 0x97, 0xbe, 0x6f, 0x49, 0xac, 0x16, - 0xa7, 0x05, 0xe1, 0xc4, 0x07, 0x90, 0x8f, 0x86, 0x2a, 0xda, 0xf7, 0xb5, 0x0b, 0x26, 0xdf, 0xce, - 0x25, 0x03, 0xa9, 0xc4, 0x3d, 0xc8, 0x8f, 0x46, 0x2a, 0x54, 0x5c, 0xca, 0xa7, 0x60, 0xcb, 0x3e, - 0x74, 0x3c, 0x47, 0x3e, 0xb9, 0x87, 0x24, 0xe2, 0x1d, 0xc8, 0x8f, 0x86, 0x6e, 0x36, 0xee, 0x1f, - 0x1f, 0xf7, 0xc7, 0x05, 0x8e, 0x86, 0x2e, 0xaa, 0xa3, 0x51, 0x70, 0x6e, 0x06, 0x53, 0x8f, 0x22, - 0xa5, 0xa8, 0xd7, 0x29, 0xcb, 0x28, 0xe2, 0x4e, 0x29, 0xdc, 0x4a, 0x28, 0xc3, 0x06, 0xcb, 0x67, - 0xdb, 0x94, 0xf9, 0xd4, 0x09, 0xe5, 0x03, 0x6f, 0x9b, 0x2b, 0x50, 0xc0, 0xd2, 0xf5, 0x0f, 0xe9, - 0x55, 0xa1, 0xe9, 0xd8, 0xc3, 0xbd, 0x50, 0xea, 0x69, 0xf3, 0xcf, 0x40, 0x4b, 0x8c, 0xfe, 0xf7, - 0xf2, 0x50, 0x4e, 0xd5, 0x47, 0x7c, 0x06, 0xc5, 0x51, 0x76, 0x21, 0x5e, 0x9f, 0xab, 0xf4, 0x83, - 0x2d, 0xb5, 0x04, 0x47, 0x72, 0x7a, 0xd3, 0x6d, 0x8a, 0xc8, 0x7c, 0x69, 0x05, 0x0e, 0xdf, 0xfa, - 0x5e, 0x4a, 0x5f, 0x6b, 0xe8, 0xdb, 0xd1, 0x73, 0x85, 0xd9, 0xb9, 0x64, 0x54, 0xc2, 0x54, 0x9a, - 0x4c, 0x7e, 0xb2, 0x49, 0xf9, 0xcc, 0xfb, 0xc2, 0x0c, 0xdc, 0xb9, 0x64, 0x28, 0x3c, 0x92, 0xda, - 0x67, 0xf6, 0x70, 0x1a, 0x29, 0x93, 0x5f, 0x55, 0x35, 0x88, 0x80, 0xf4, 0xb6, 0x3b, 0xff, 0x14, - 0x0f, 0x71, 0x2b, 0xb6, 0x5c, 0xd7, 0x27, 0x49, 0x7e, 0x39, 0x7d, 0x52, 0xb7, 0x15, 0xc3, 0xf9, - 0x2d, 0x79, 0x95, 0x12, 0xef, 0xc2, 0xb2, 0x1f, 0x1d, 0xdb, 0xca, 0xc0, 0xa0, 0xde, 0x27, 0x42, - 0xd0, 0x56, 0xb3, 0x83, 0x33, 0x85, 0xd0, 0xfa, 0xef, 0xe7, 0x60, 0x55, 0xf6, 0x80, 0x58, 0x87, - 0x6a, 0xbf, 0x35, 0x30, 0x9f, 0x37, 0x8c, 0x76, 0x63, 0xb3, 0xd3, 0x92, 0xe1, 0x0a, 0x9f, 0x18, - 0x8d, 0xae, 0x64, 0x90, 0x46, 0xeb, 0x79, 0xef, 0x59, 0x8b, 0xfd, 0xe4, 0xb6, 0x5a, 0xdd, 0x6f, - 0xb5, 0x3c, 0xbb, 0xa0, 0xb6, 0xf6, 0x1a, 0x06, 0xf2, 0xca, 0x32, 0xac, 0xb6, 0xbe, 0x69, 0x35, - 0xf7, 0x89, 0x59, 0xd6, 0x00, 0xb6, 0x5a, 0x8d, 0x4e, 0xa7, 0xd7, 0x44, 0xe6, 0xb9, 0x22, 0x04, - 0xd4, 0x9a, 0x46, 0xab, 0x31, 0x68, 0x99, 0x8d, 0x66, 0xb3, 0xb7, 0xdf, 0x1d, 0x68, 0xab, 0xf8, - 0xc5, 0x46, 0x67, 0xd0, 0x32, 0x62, 0x10, 0xbd, 0x04, 0xbb, 0x65, 0xf4, 0xf6, 0x62, 0x48, 0x69, - 0xb3, 0x04, 0xab, 0x43, 0x1e, 0x2b, 0xfd, 0xdf, 0x5e, 0x67, 0x17, 0x91, 0x64, 0x6a, 0x8a, 0x2f, - 0xa1, 0x38, 0x1a, 0x65, 0xc6, 0xf8, 0xe6, 0xa2, 0x29, 0xfc, 0x60, 0x6b, 0xa4, 0x86, 0x99, 0x7f, - 0x88, 0xb7, 0xd4, 0x42, 0x5a, 0x9a, 0x5b, 0x48, 0x6a, 0x19, 0xfd, 0x0c, 0xd6, 0xe4, 0x73, 0x35, - 0xf1, 0xe9, 0x72, 0x66, 0x95, 0x34, 0x09, 0xb9, 0x25, 0x71, 0x3b, 0x97, 0x8c, 0xda, 0x30, 0x03, - 0x11, 0x3f, 0x85, 0x9a, 0xc5, 0x67, 0xb6, 0xe9, 0xd3, 0xe9, 0x78, 0x13, 0x6d, 0xd0, 0x91, 0x6d, - 0x92, 0xbd, 0x6a, 0xa5, 0x01, 0x38, 0x11, 0x47, 0x81, 0x3f, 0x49, 0x32, 0x2f, 0x67, 0xee, 0xd7, - 0x04, 0xfe, 0x24, 0x95, 0xb7, 0x32, 0x4a, 0xa5, 0xc5, 0x17, 0x50, 0x91, 0x35, 0x4f, 0xce, 0x27, - 0xe2, 0x25, 0xcb, 0xd5, 0x26, 0x9d, 0x63, 0xe7, 0x92, 0x51, 0x1e, 0x26, 0x49, 0xf1, 0x08, 0x15, - 0x8d, 0x44, 0x43, 0x5b, 0x4d, 0xcf, 0x35, 0xaa, 0xad, 0xca, 0x05, 0x56, 0x9c, 0x12, 0x9f, 0x00, - 0x50, 0x3d, 0x39, 0x4f, 0x31, 0x73, 0xf3, 0x34, 0xf0, 0x27, 0x2a, 0x4b, 0x69, 0xa4, 0x12, 0xa9, - 0xea, 0xb1, 0xe9, 0xb3, 0x34, 0x5f, 0x3d, 0x96, 0x65, 0xe2, 0xea, 0xb1, 0x15, 0x34, 0xae, 0x1e, - 0x67, 0x83, 0xb9, 0xea, 0xa9, 0x5c, 0x5c, 0x3d, 0xce, 0xa4, 0xaa, 0xc7, 0x79, 0xca, 0xb3, 0xd5, - 0x53, 0x59, 0xa8, 0x7a, 0x9c, 0xe3, 0xa7, 0x73, 0xaa, 0x65, 0xe5, 0x42, 0xd5, 0x12, 0x87, 0x2d, - 0xab, 0x5c, 0xfe, 0x14, 0x6a, 0xe1, 0xb1, 0x7f, 0x9a, 0x62, 0x20, 0xd5, 0x74, 0xee, 0xfe, 0xb1, - 0x7f, 0x9a, 0xe6, 0x20, 0xd5, 0x30, 0x0d, 0xc0, 0xda, 0x72, 0x13, 0xe9, 0x39, 0x83, 0x5a, 0xba, - 0xb6, 0xd4, 0x42, 0x14, 0xbc, 0xb0, 0xb6, 0x96, 0x4a, 0x60, 0xa7, 0x24, 0x67, 0x35, 0xa1, 0x3c, - 0x7d, 0xc9, 0xdc, 0xd7, 0x94, 0x5f, 0x82, 0xf8, 0xd4, 0x26, 0xc4, 0xb9, 0x35, 0xf5, 0xd2, 0xd9, - 0xb4, 0xf4, 0xdc, 0xda, 0xf7, 0x32, 0x19, 0x2b, 0x4c, 0x2a, 0xb3, 0x26, 0xab, 0x22, 0xb4, 0xbf, - 0x9f, 0xa2, 0xc0, 0x27, 0xef, 0x65, 0x67, 0x56, 0x45, 0x5f, 0xe2, 0x92, 0x55, 0xa1, 0x20, 0xf1, - 0xbc, 0x8e, 0xb3, 0x8b, 0xd9, 0x79, 0x9d, 0xca, 0x4c, 0xf3, 0x3a, 0xce, 0x1a, 0x2f, 0xa8, 0x38, - 0xef, 0xe5, 0xb9, 0x05, 0x95, 0xca, 0xcc, 0x0b, 0x2a, 0xce, 0xfd, 0x08, 0xe4, 0x6c, 0xe2, 0xce, - 0xcd, 0xdc, 0xde, 0xe6, 0x5a, 0xcb, 0xde, 0x85, 0x61, 0x9c, 0xc2, 0xb9, 0x1a, 0xd8, 0xa8, 0xca, - 0xca, 0xa9, 0x70, 0x25, 0xf3, 0x36, 0x36, 0x61, 0xe2, 0xa5, 0x14, 0x24, 0xc9, 0xd4, 0xc7, 0x26, - 0x4e, 0x14, 0xd4, 0x47, 0xf3, 0x1f, 0xdb, 0x73, 0xa2, 0x20, 0xf9, 0x18, 0xa6, 0xc4, 0x47, 0x40, - 0xd3, 0x90, 0xb3, 0xd8, 0x69, 0xd6, 0x8d, 0xdd, 0x22, 0x33, 0x14, 0x47, 0xf2, 0x37, 0x4e, 0x16, - 0xf9, 0x8d, 0xe1, 0x68, 0x58, 0x3f, 0x4c, 0x4f, 0x16, 0xfe, 0x44, 0x73, 0xab, 0x89, 0x93, 0x85, - 0x89, 0x9a, 0xa3, 0xa1, 0xb8, 0x0f, 0x94, 0x9b, 0xe8, 0x8f, 0x32, 0xef, 0xdf, 0x05, 0xfe, 0x84, - 0xa9, 0x57, 0x91, 0x00, 0x69, 0xb1, 0x05, 0xae, 0xef, 0xa9, 0x86, 0x1f, 0x67, 0x5a, 0x80, 0x88, - 0x98, 0x19, 0x0c, 0xe3, 0x94, 0xfe, 0x8f, 0xaf, 0xc0, 0xaa, 0xe4, 0xb5, 0xe2, 0x32, 0xac, 0x49, - 0x96, 0xbf, 0xd5, 0x18, 0x34, 0x36, 0x1b, 0x7d, 0x14, 0xd2, 0x04, 0xd4, 0x98, 0xe7, 0xc7, 0xb0, - 0x1c, 0xee, 0x03, 0xc4, 0xf4, 0x63, 0x10, 0xbd, 0x81, 0x29, 0xf3, 0xb2, 0x37, 0x72, 0x5e, 0xac, - 0x41, 0x99, 0x33, 0x32, 0x80, 0xa2, 0x27, 0x53, 0x2e, 0x4e, 0x2f, 0xa7, 0xb2, 0xb0, 0x3f, 0xf9, - 0x4a, 0x92, 0x85, 0x01, 0xab, 0x71, 0x16, 0xe5, 0x70, 0x2e, 0xa0, 0x36, 0x30, 0xf6, 0xbb, 0xcd, - 0xe4, 0x3b, 0x25, 0x8a, 0x78, 0xcb, 0xc5, 0x3c, 0x6f, 0xb7, 0x5e, 0x68, 0x40, 0x8f, 0x6d, 0x52, - 0x29, 0x94, 0x26, 0x47, 0x74, 0x2a, 0x84, 0x92, 0x15, 0x71, 0x0d, 0x2e, 0xf7, 0x77, 0x7a, 0x2f, - 0x4c, 0xce, 0x14, 0x37, 0xa1, 0x2a, 0x36, 0x40, 0x4b, 0x21, 0xb8, 0xf8, 0x1a, 0x7e, 0x92, 0xa0, - 0x8a, 0xb0, 0xaf, 0xad, 0xd1, 0x83, 0x39, 0x08, 0x1b, 0xf0, 0xbe, 0xab, 0x61, 0x53, 0x38, 0x6b, - 0xaf, 0xb3, 0xbf, 0xdb, 0xed, 0x6b, 0xeb, 0x58, 0x09, 0x82, 0x70, 0xcd, 0x45, 0x5c, 0x4c, 0xb2, - 0x5b, 0x5f, 0xa6, 0x0d, 0x1c, 0x61, 0x2f, 0x1a, 0x46, 0xb7, 0xdd, 0x7d, 0xd2, 0xd7, 0x36, 0xe2, - 0x92, 0x5b, 0x86, 0xd1, 0x33, 0xfa, 0xda, 0x95, 0x18, 0xd0, 0x1f, 0x34, 0x06, 0xfb, 0x7d, 0xed, - 0x6a, 0x5c, 0xcb, 0x3d, 0xa3, 0xd7, 0x6c, 0xf5, 0xfb, 0x9d, 0x76, 0x7f, 0xa0, 0x5d, 0x13, 0x57, - 0x60, 0x3d, 0xa9, 0x91, 0x22, 0xae, 0xa7, 0x2a, 0x6a, 0x3c, 0x69, 0x0d, 0xb4, 0xeb, 0x71, 0x35, - 0x9a, 0xbd, 0x4e, 0xa7, 0x41, 0xae, 0xee, 0x37, 0x90, 0x88, 0x2e, 0x70, 0xc8, 0xd6, 0xbc, 0x81, - 0xf5, 0xda, 0xef, 0xa6, 0x41, 0x37, 0x53, 0x53, 0xa3, 0xdf, 0xfa, 0xc5, 0x7e, 0xab, 0xdb, 0x6c, - 0x69, 0x6f, 0x26, 0x53, 0x23, 0x86, 0xdd, 0x8a, 0xa7, 0x46, 0x0c, 0xba, 0x1d, 0x7f, 0x53, 0x81, - 0xfa, 0xda, 0x9d, 0xb8, 0xc3, 0xf6, 0xf7, 0x9e, 0x18, 0x8d, 0xad, 0x96, 0xa6, 0x23, 0xc4, 0x68, - 0x75, 0x1b, 0xbb, 0x6a, 0x60, 0xdf, 0x4e, 0x0d, 0xec, 0x5e, 0x7b, 0x60, 0x68, 0x77, 0xe3, 0x81, - 0xa4, 0xe4, 0x3b, 0xe2, 0x0d, 0xb8, 0x96, 0x9e, 0x72, 0xe6, 0x8b, 0xf6, 0x60, 0x47, 0xde, 0xb3, - 0x78, 0x97, 0x7d, 0xef, 0x09, 0xd9, 0xdc, 0x6a, 0xf2, 0x85, 0x12, 0xca, 0x8b, 0xa9, 0x7b, 0x7a, - 0xa1, 0xf8, 0x96, 0xf6, 0xd6, 0xfd, 0x35, 0xd9, 0x15, 0xdd, 0x2e, 0xdd, 0xb4, 0xe8, 0x6f, 0x56, - 0x50, 0x72, 0x53, 0x22, 0x88, 0xfe, 0x14, 0x44, 0x7f, 0x7a, 0x10, 0x0e, 0x03, 0x87, 0x42, 0x36, - 0xc8, 0x00, 0x17, 0x02, 0x0a, 0x87, 0x81, 0x3f, 0x56, 0x9e, 0x3a, 0xf8, 0x5b, 0xdc, 0x81, 0xf2, - 0x64, 0x7a, 0x40, 0x57, 0x05, 0x92, 0x58, 0xe5, 0x69, 0x90, 0xfe, 0xbf, 0xe4, 0xa0, 0x96, 0x15, - 0x3f, 0xe8, 0x14, 0xe8, 0xd0, 0xf4, 0xfc, 0x88, 0x9f, 0x34, 0x0b, 0x95, 0xcd, 0xd7, 0x39, 0xec, - 0xfa, 0x11, 0xbd, 0x69, 0x16, 0x66, 0x1c, 0xe5, 0x96, 0x66, 0x1c, 0xe5, 0xda, 0x70, 0x39, 0x4c, - 0x55, 0xcf, 0xcc, 0x3c, 0x28, 0x57, 0x8f, 0x1f, 0x1d, 0x9e, 0xa9, 0xbf, 0x21, 0xc2, 0xf9, 0x36, - 0xc9, 0x88, 0xf3, 0x85, 0x38, 0xe2, 0xbc, 0x78, 0x08, 0x45, 0xe9, 0xdf, 0x1a, 0x4a, 0x31, 0xe6, - 0x6a, 0x22, 0xa6, 0xe1, 0xe7, 0xe5, 0xeb, 0x8a, 0xa1, 0x11, 0xd3, 0xe9, 0x7f, 0x1e, 0xaa, 0x19, - 0x09, 0x89, 0x0c, 0x83, 0x87, 0xd9, 0xd6, 0x15, 0x9d, 0xc3, 0x1f, 0xd0, 0xb4, 0xf4, 0xd7, 0xf3, - 0x3f, 0xf0, 0xeb, 0x7f, 0x2d, 0x07, 0x95, 0xb4, 0x8c, 0xf5, 0x9b, 0x7f, 0xfd, 0x36, 0x94, 0xd5, - 0x6f, 0xf5, 0xbe, 0x73, 0xc1, 0x00, 0x05, 0x22, 0x6f, 0xd7, 0x32, 0x1f, 0xdc, 0x6d, 0x9f, 0xf4, - 0xe3, 0x6e, 0x4b, 0x83, 0xc8, 0x89, 0xf1, 0xd8, 0x1e, 0x9e, 0x6c, 0x3f, 0x43, 0x02, 0xe5, 0xc4, - 0x18, 0x43, 0xf4, 0xdb, 0x50, 0xda, 0x3e, 0x51, 0xd7, 0x7d, 0xd3, 0x0f, 0x08, 0x96, 0x38, 0x90, - 0xbe, 0xfe, 0x07, 0x39, 0xa8, 0x25, 0xa6, 0x33, 0xba, 0x43, 0x51, 0x83, 0xa5, 0xd1, 0x81, 0x9c, - 0x76, 0x4b, 0xa3, 0x83, 0xc4, 0x51, 0x75, 0x29, 0xed, 0xa8, 0xfa, 0xb6, 0x2c, 0x2c, 0x9f, 0xde, - 0x5c, 0xe2, 0x6f, 0xc9, 0x30, 0xfd, 0x8f, 0xa0, 0x82, 0xff, 0xc9, 0x02, 0x14, 0xd8, 0xa3, 0x6c, - 0xe8, 0xb3, 0x84, 0x38, 0x43, 0x44, 0xda, 0xa4, 0x74, 0x81, 0xbd, 0xe0, 0x41, 0x21, 0x7a, 0xe8, - 0xea, 0xef, 0x2f, 0x43, 0x39, 0x25, 0xb1, 0xfe, 0xa0, 0x69, 0x7e, 0x13, 0x4a, 0xc9, 0xf3, 0x36, - 0x32, 0x36, 0x7a, 0x0c, 0xc8, 0x8c, 0x55, 0x7e, 0x66, 0xac, 0xc8, 0x5f, 0x9c, 0x02, 0xb2, 0x26, - 0xfe, 0xe2, 0x94, 0xcc, 0x9e, 0x19, 0x2c, 0xbf, 0xe6, 0x70, 0xf9, 0x53, 0xa8, 0xa4, 0x0c, 0xfe, - 0xca, 0xb3, 0x74, 0x96, 0xbe, 0x9c, 0x18, 0xff, 0x43, 0x71, 0x05, 0x56, 0x0e, 0x4f, 0xcc, 0xd1, - 0x01, 0xbb, 0x5c, 0x94, 0x8c, 0xe5, 0xc3, 0x93, 0xad, 0x03, 0x72, 0x31, 0x39, 0x8c, 0x85, 0x34, - 0x36, 0xc3, 0x16, 0x0f, 0x95, 0x28, 0x76, 0x0f, 0x56, 0x0f, 0x4f, 0xd2, 0x11, 0x96, 0xe7, 0xba, - 0x7c, 0xe5, 0xf0, 0x84, 0x82, 0xfc, 0x7e, 0x0c, 0x1b, 0x52, 0x52, 0xb0, 0x42, 0x65, 0x95, 0xc4, - 0x25, 0xca, 0xcf, 0x09, 0xae, 0x33, 0xae, 0x11, 0xb2, 0x4d, 0x12, 0x67, 0x9c, 0x0e, 0x95, 0xd4, - 0x04, 0x64, 0x73, 0x6a, 0xc9, 0xc8, 0xc0, 0xc4, 0x63, 0xa8, 0x1c, 0x9e, 0xf0, 0x80, 0x0e, 0xfc, - 0x5d, 0x5b, 0x46, 0x1c, 0xda, 0x98, 0x1d, 0x4a, 0xba, 0xe4, 0x92, 0xa1, 0x14, 0x57, 0x61, 0xc5, - 0xb0, 0x4e, 0xfb, 0xbf, 0xe8, 0x90, 0xb8, 0x5a, 0x32, 0x64, 0x4a, 0x34, 0xe1, 0x4a, 0xca, 0x0e, - 0x7a, 0x78, 0x62, 0x72, 0xf4, 0x1d, 0x65, 0x06, 0x9d, 0xb7, 0xe6, 0x26, 0xd4, 0xdb, 0x27, 0x1c, - 0xf8, 0x30, 0x14, 0x5f, 0xc2, 0xda, 0xe1, 0x09, 0x9d, 0x3e, 0x98, 0x32, 0x9a, 0x8d, 0x14, 0x50, - 0xd7, 0x12, 0x87, 0x2b, 0x79, 0x2c, 0x74, 0x78, 0x82, 0xbd, 0xb4, 0xc9, 0x54, 0xa2, 0x09, 0xeb, - 0xf1, 0x42, 0x8d, 0xf9, 0x85, 0x78, 0x25, 0xbf, 0xd0, 0x46, 0x33, 0x10, 0xd1, 0x82, 0xdb, 0xc3, - 0xc8, 0x0a, 0x4d, 0xd6, 0xde, 0x91, 0x91, 0x4e, 0x02, 0x3f, 0xf2, 0x87, 0xbe, 0x1b, 0x3b, 0xbc, - 0x72, 0x44, 0xd5, 0x9b, 0x48, 0xd6, 0x52, 0x54, 0x7b, 0x92, 0x48, 0xba, 0xbf, 0x72, 0xdc, 0x2e, - 0xfd, 0x3f, 0xcc, 0x41, 0x2d, 0xd1, 0xbb, 0x90, 0x1d, 0x89, 0xfb, 0xfc, 0xfe, 0x31, 0xeb, 0xba, - 0xf5, 0x59, 0xd5, 0x0c, 0x49, 0x1e, 0x0c, 0xce, 0x27, 0xfc, 0x0e, 0xf2, 0xa2, 0xd7, 0xcd, 0x16, - 0x9d, 0x45, 0xe5, 0x17, 0x9d, 0x45, 0xe9, 0x4f, 0x20, 0x3f, 0x38, 0x9f, 0xb0, 0x8d, 0x0f, 0xc5, - 0x10, 0xb6, 0x07, 0xb0, 0x00, 0x42, 0xd7, 0xeb, 0x9e, 0xb5, 0xbe, 0xe5, 0x57, 0x2d, 0xf6, 0x8c, - 0xf6, 0x6e, 0xc3, 0xf8, 0xd6, 0x44, 0x00, 0x09, 0x6a, 0xdb, 0x3d, 0xa3, 0xd5, 0x7e, 0xd2, 0x25, - 0x40, 0x81, 0x2c, 0x80, 0x49, 0x15, 0x1b, 0xa3, 0xd1, 0xf6, 0x49, 0xfa, 0x61, 0xa8, 0x5c, 0xe6, - 0x61, 0xa8, 0xf8, 0x0d, 0xb5, 0xf4, 0x7b, 0xa0, 0x51, 0x7c, 0x40, 0x26, 0x62, 0x7e, 0x14, 0x33, - 0x37, 0xf1, 0x1e, 0x14, 0x0e, 0x4f, 0xec, 0xf3, 0xac, 0x72, 0x9d, 0x65, 0x25, 0x44, 0xa0, 0xff, - 0x51, 0x0e, 0x44, 0xa6, 0x22, 0xac, 0xef, 0xfd, 0xa6, 0x75, 0xf9, 0x12, 0xea, 0xea, 0x09, 0x62, - 0xa2, 0x4a, 0x1d, 0x7e, 0xc9, 0x2e, 0xbd, 0xe2, 0x27, 0x31, 0x3f, 0x92, 0x07, 0xd8, 0xc4, 0xc7, - 0xc0, 0x4f, 0x7d, 0xd2, 0xed, 0xb0, 0xc2, 0x05, 0xba, 0xb9, 0x91, 0xd0, 0x24, 0x6f, 0x7b, 0xa6, - 0xdf, 0x2c, 0xe5, 0x73, 0xb3, 0xb5, 0x64, 0xd4, 0x88, 0xfb, 0xe9, 0x7f, 0x25, 0x07, 0x97, 0xb3, - 0x13, 0xe2, 0x4f, 0xd6, 0xca, 0xec, 0x03, 0xad, 0xf9, 0xd9, 0x07, 0x5a, 0x17, 0xcd, 0xa7, 0xc2, - 0xc2, 0xf9, 0xf4, 0x17, 0x72, 0xb0, 0x91, 0xea, 0xfd, 0x44, 0x43, 0xff, 0x33, 0xaa, 0x59, 0xea, - 0x9d, 0xd6, 0x42, 0xe6, 0x9d, 0x56, 0xfd, 0xef, 0xe4, 0xe0, 0xea, 0x4c, 0x4d, 0x0c, 0xfb, 0xcf, - 0xb4, 0x2e, 0xd9, 0xf7, 0x5c, 0xe9, 0xec, 0x4e, 0xbd, 0xfc, 0x80, 0xbc, 0x40, 0x64, 0x1f, 0x68, - 0x25, 0xaf, 0x82, 0x37, 0xe5, 0x03, 0x41, 0x66, 0x78, 0xee, 0x0d, 0xe5, 0x60, 0x97, 0x08, 0xd2, - 0x3f, 0xf7, 0x86, 0xb8, 0x5d, 0x8f, 0xed, 0xe0, 0x48, 0x19, 0x4f, 0x39, 0xa1, 0xff, 0x9b, 0x39, - 0xb8, 0x3e, 0xd3, 0xb2, 0xc6, 0x34, 0xf2, 0xa5, 0x13, 0xd0, 0x9f, 0x51, 0xe3, 0x6e, 0x03, 0xbd, - 0x5d, 0xa6, 0xbc, 0x8f, 0x52, 0xb7, 0x86, 0xe4, 0x77, 0x35, 0xc8, 0x8f, 0xac, 0x73, 0x19, 0x38, - 0x1c, 0x7f, 0xe2, 0x32, 0x3e, 0xf6, 0xa7, 0x81, 0xbc, 0xe6, 0x42, 0xbf, 0xf5, 0xcf, 0x60, 0x3d, - 0xa9, 0x7a, 0x53, 0x3e, 0xb6, 0x7b, 0x1b, 0xca, 0x9e, 0x7d, 0x6a, 0xaa, 0xa7, 0x78, 0xe5, 0x05, - 0x48, 0xcf, 0x3e, 0x95, 0x04, 0xfa, 0x76, 0x9a, 0x43, 0x52, 0x75, 0xae, 0x43, 0xd1, 0x77, 0x47, - 0x19, 0xb7, 0x67, 0xdf, 0x1d, 0x29, 0x14, 0x96, 0x96, 0x6a, 0xe5, 0xaa, 0x67, 0x9f, 0xd2, 0xec, - 0x3c, 0x95, 0xe5, 0x34, 0x46, 0xca, 0x59, 0x6f, 0x91, 0x0f, 0xfd, 0x75, 0x28, 0x4e, 0x82, 0x4c, - 0x37, 0xad, 0x4e, 0x02, 0xfe, 0xec, 0x5d, 0x79, 0xbd, 0xf2, 0x22, 0x67, 0x4f, 0xbe, 0x70, 0xa9, - 0x41, 0x7e, 0xe2, 0x87, 0xd2, 0x9b, 0x0c, 0x7f, 0xea, 0x9f, 0x4b, 0xe6, 0x48, 0x1a, 0x38, 0x7f, - 0x59, 0x83, 0xbc, 0x33, 0x3a, 0xa3, 0x0f, 0x57, 0x0d, 0xfc, 0x49, 0x12, 0xb5, 0xfd, 0xbd, 0xbc, - 0xe1, 0x89, 0x3f, 0xf5, 0x4d, 0x28, 0x1b, 0x19, 0x73, 0x43, 0x25, 0x65, 0xb9, 0x0b, 0xb3, 0x0f, - 0x31, 0x25, 0x1d, 0x64, 0x94, 0x13, 0xc3, 0x5d, 0xa8, 0x87, 0x92, 0x1d, 0x3e, 0xb7, 0x82, 0xe1, - 0xb1, 0x15, 0x74, 0x6c, 0xef, 0x28, 0x3a, 0xc6, 0x2e, 0x97, 0x4f, 0xa5, 0xa7, 0x9a, 0x0f, 0x0c, - 0x52, 0xd3, 0x01, 0x7b, 0xd1, 0x25, 0x72, 0xe9, 0x89, 0x52, 0xf2, 0xec, 0x53, 0x99, 0xff, 0x4d, - 0x00, 0xec, 0x7f, 0x89, 0x96, 0x57, 0xcc, 0x7c, 0x77, 0xc4, 0x68, 0x7d, 0x5d, 0xb6, 0x57, 0x06, - 0xbe, 0xdf, 0xb2, 0x0f, 0x75, 0x57, 0x8e, 0x3c, 0x37, 0x48, 0x76, 0xc2, 0x6f, 0x34, 0x8c, 0xe2, - 0x2d, 0xa8, 0x28, 0xdb, 0x10, 0xbd, 0xfd, 0xc5, 0x9f, 0x2f, 0x2b, 0x58, 0x77, 0x3a, 0xd6, 0xff, - 0xad, 0x02, 0x54, 0x1a, 0xec, 0x18, 0x3d, 0x39, 0xef, 0x4d, 0x22, 0xf1, 0xbb, 0x70, 0x85, 0x9c, - 0x82, 0x39, 0xe0, 0x08, 0xf9, 0x23, 0xb3, 0x3f, 0x2d, 0x77, 0xe2, 0xfd, 0x54, 0x27, 0xca, 0x2c, - 0x0f, 0xfa, 0x27, 0xce, 0x84, 0x63, 0x90, 0xb4, 0x47, 0x67, 0xe4, 0x5e, 0xcb, 0x2e, 0x3c, 0xf4, - 0x3e, 0x45, 0x16, 0x41, 0xf1, 0xcf, 0xb1, 0xf8, 0xc9, 0x89, 0x2c, 0x56, 0x7a, 0x83, 0x21, 0x70, - 0xef, 0x84, 0x69, 0x12, 0xdf, 0xb9, 0xb9, 0x6d, 0x59, 0xfa, 0xce, 0x25, 0xf3, 0xbb, 0x0f, 0xeb, - 0xf2, 0x8d, 0x0c, 0x7a, 0x9b, 0xd3, 0x1c, 0xfa, 0x93, 0x73, 0xe9, 0x21, 0xf0, 0xde, 0x05, 0x55, - 0x6d, 0x33, 0x29, 0x82, 0xb8, 0x9e, 0x6b, 0x61, 0x16, 0x2a, 0x9e, 0x83, 0xc0, 0x2e, 0x9d, 0xb8, - 0x53, 0xdc, 0xcf, 0xd4, 0xab, 0xa0, 0x7c, 0x5f, 0xe2, 0xde, 0x82, 0x52, 0xbb, 0xf6, 0xe9, 0x1e, - 0xd1, 0xca, 0x42, 0xb8, 0x58, 0xcd, 0x9b, 0x01, 0xdf, 0x68, 0xc1, 0xb5, 0x0b, 0xfa, 0xea, 0x75, - 0xde, 0x4d, 0xc5, 0x94, 0x77, 0xd3, 0x8d, 0x4d, 0xd8, 0x58, 0xd4, 0x8e, 0x1f, 0x55, 0x46, 0x13, - 0xae, 0x2c, 0xac, 0xf5, 0x8f, 0x29, 0x44, 0xff, 0x0b, 0x35, 0x80, 0x64, 0x39, 0x65, 0x74, 0x89, - 0xdc, 0x8c, 0x2e, 0xf1, 0xa3, 0xdc, 0x51, 0x3f, 0x83, 0x1a, 0x8e, 0x63, 0x2a, 0x92, 0xf1, 0xe2, - 0x10, 0xca, 0x15, 0xa4, 0x1a, 0x24, 0x01, 0x2f, 0xe7, 0xdd, 0xaa, 0x0a, 0x0b, 0xdd, 0xaa, 0x3e, - 0x85, 0x55, 0x3e, 0x8f, 0x55, 0x83, 0x7a, 0x6d, 0x96, 0x35, 0x3c, 0x90, 0x61, 0xa6, 0x14, 0x9d, - 0x68, 0x41, 0x2d, 0x8e, 0x32, 0x93, 0x8e, 0xb8, 0x7a, 0x6b, 0x3e, 0xa7, 0x22, 0xe3, 0xe7, 0x46, - 0xad, 0x74, 0x32, 0xa5, 0x7a, 0x44, 0x63, 0x79, 0x48, 0x40, 0xaa, 0xc7, 0x6a, 0x5a, 0xf5, 0x18, - 0x8c, 0xf9, 0x68, 0x00, 0x55, 0x8f, 0x8f, 0xe0, 0xb2, 0x74, 0x71, 0xc7, 0x0c, 0xe4, 0xbd, 0x80, - 0xf4, 0x7c, 0x95, 0x51, 0x93, 0x8f, 0x32, 0x8c, 0x49, 0x31, 0x47, 0xf2, 0x6f, 0x60, 0x83, 0xdf, - 0x0d, 0x31, 0xa3, 0x03, 0x7a, 0xc1, 0xa7, 0x3d, 0x32, 0xc7, 0xd6, 0x44, 0x6a, 0x44, 0xef, 0xcd, - 0x55, 0x96, 0x9f, 0x0d, 0x19, 0x1c, 0xb8, 0x74, 0xb9, 0x20, 0x76, 0xbe, 0x5b, 0x1f, 0xce, 0xc2, - 0x67, 0x7c, 0x60, 0x60, 0xce, 0x07, 0x66, 0x56, 0x47, 0x2a, 0x2f, 0xd0, 0x91, 0x12, 0x4d, 0xa7, - 0x92, 0xd1, 0x74, 0x3e, 0x84, 0x55, 0x19, 0xb9, 0x53, 0x1e, 0x0f, 0x88, 0xf9, 0x45, 0x66, 0x28, - 0x12, 0xfc, 0x92, 0xf2, 0xc8, 0xa2, 0xc0, 0xef, 0x35, 0xfe, 0x52, 0x1a, 0x26, 0x36, 0xa5, 0x6d, - 0x3c, 0xbe, 0x08, 0x21, 0x8f, 0x02, 0x6e, 0xa4, 0x0a, 0x8e, 0x71, 0xd2, 0x78, 0x33, 0x93, 0xe3, - 0xc6, 0x5f, 0x5e, 0x85, 0x15, 0xe9, 0x57, 0x73, 0x1f, 0x0a, 0xa3, 0x40, 0x5e, 0xda, 0x8a, 0x95, - 0xba, 0xac, 0x5c, 0xb9, 0x73, 0xc9, 0x20, 0x1a, 0xf1, 0x00, 0x56, 0xac, 0x11, 0xea, 0x6b, 0x59, - 0xb7, 0x85, 0x19, 0x99, 0x7f, 0xe7, 0x92, 0xb1, 0x6c, 0x91, 0xf0, 0xff, 0x25, 0x94, 0x90, 0x3e, - 0x1d, 0x82, 0xbb, 0xbe, 0x20, 0x8b, 0x3a, 0x9a, 0x29, 0x5a, 0x4a, 0x52, 0xff, 0xad, 0xec, 0x01, - 0x50, 0x61, 0xae, 0x81, 0x33, 0xa2, 0xe5, 0xcc, 0x51, 0xd0, 0x6f, 0x03, 0x9f, 0x08, 0xc4, 0xe2, - 0xc4, 0x72, 0xfa, 0x84, 0x7c, 0x4e, 0xf8, 0xd8, 0xb9, 0x64, 0xf0, 0xa6, 0xaa, 0x84, 0x91, 0xcf, - 0xd5, 0xe1, 0x0c, 0xb1, 0xe7, 0x95, 0xc5, 0x3d, 0x83, 0x3c, 0x3a, 0x3e, 0xa1, 0x21, 0x86, 0x8d, - 0xd9, 0x46, 0xb1, 0x9f, 0xf1, 0xea, 0x5c, 0xb6, 0x58, 0xe4, 0xa0, 0x6c, 0xb1, 0xfc, 0xf1, 0x18, - 0xca, 0x6c, 0xab, 0xe7, 0x7c, 0xc5, 0xb9, 0xae, 0x4d, 0x24, 0x06, 0x3a, 0xfd, 0x4d, 0xe4, 0x87, - 0xa6, 0x6a, 0x67, 0x60, 0xa7, 0x0f, 0xd8, 0x6e, 0x2e, 0xec, 0x28, 0x23, 0x3e, 0x6b, 0xe3, 0xc6, - 0x1a, 0x9c, 0x47, 0x74, 0x60, 0x43, 0x9e, 0x44, 0xb1, 0x74, 0xa0, 0x36, 0x74, 0x98, 0x1b, 0xaf, - 0x8c, 0xf8, 0xb0, 0x73, 0xc9, 0x10, 0xd6, 0xbc, 0x50, 0xd1, 0x84, 0x75, 0x55, 0x25, 0xda, 0xf6, - 0x53, 0xae, 0x97, 0xe9, 0x26, 0x25, 0x42, 0xc1, 0xce, 0x25, 0x63, 0xcd, 0xca, 0x82, 0x44, 0x1b, - 0x2e, 0xab, 0x42, 0x48, 0xbd, 0x4f, 0xdd, 0xdb, 0xc8, 0x8e, 0x62, 0x5a, 0x90, 0xd8, 0xb9, 0x64, - 0xac, 0x5b, 0x73, 0xd2, 0xc5, 0xae, 0xaa, 0x4f, 0x5a, 0x72, 0xe5, 0x95, 0x78, 0x7b, 0x61, 0x37, - 0x25, 0x62, 0x74, 0x5c, 0xb3, 0x94, 0x64, 0xfd, 0x0b, 0xd5, 0x59, 0x59, 0x2f, 0x73, 0x79, 0x80, - 0xf7, 0xe6, 0x5c, 0x89, 0x69, 0x27, 0xf3, 0xb8, 0xc7, 0x32, 0xd0, 0xc4, 0x83, 0xe6, 0x86, 0x01, - 0x57, 0x17, 0x33, 0xad, 0xf4, 0xce, 0x55, 0xe0, 0x9d, 0x4b, 0x4f, 0xef, 0x5c, 0xb3, 0x6f, 0x43, - 0xa4, 0xf6, 0xb1, 0x9f, 0x43, 0x35, 0xc3, 0xb5, 0x45, 0x19, 0x56, 0xd5, 0xbb, 0xfa, 0x14, 0x1c, - 0xa7, 0xd9, 0xdb, 0xfb, 0x56, 0xcb, 0x21, 0xb8, 0xdd, 0xed, 0x0f, 0x1a, 0xdd, 0x81, 0xb6, 0xc4, - 0x89, 0xbd, 0x4e, 0xa3, 0xd9, 0xd2, 0xf2, 0xfa, 0xdf, 0xcc, 0x43, 0x29, 0x3e, 0xdf, 0xfd, 0xcd, - 0xad, 0xa3, 0x8b, 0xe3, 0x36, 0xcc, 0x28, 0xbc, 0x7c, 0x6d, 0xa5, 0xa0, 0xc2, 0xc0, 0xa7, 0xd5, - 0xca, 0x70, 0x3e, 0x2c, 0xf0, 0xf2, 0x0f, 0x0c, 0x0b, 0x9c, 0xbe, 0xb0, 0xb8, 0x92, 0xbd, 0xb0, - 0x78, 0x1b, 0x54, 0x38, 0x0c, 0xdc, 0x55, 0xc8, 0x24, 0x57, 0xa0, 0xe7, 0x59, 0x11, 0x34, 0x38, - 0x70, 0x91, 0xaf, 0x3b, 0xe1, 0x73, 0xc7, 0x3e, 0x95, 0x57, 0x28, 0x64, 0x2a, 0xbb, 0xe9, 0xc3, - 0x6b, 0x36, 0xfd, 0x1f, 0xb2, 0x81, 0x3c, 0x84, 0x8d, 0xc3, 0x93, 0xf8, 0xdd, 0xf4, 0xc4, 0xd8, - 0x56, 0xa1, 0x2a, 0x2d, 0xc4, 0x89, 0xf7, 0x60, 0x25, 0x52, 0x47, 0xcf, 0xf9, 0x05, 0xa7, 0xf1, - 0x86, 0x44, 0xeb, 0x7f, 0x39, 0x07, 0x90, 0x9c, 0x7c, 0xfe, 0x89, 0x8f, 0x10, 0x52, 0xd6, 0xd3, - 0xfc, 0x2b, 0xac, 0xa7, 0xaf, 0x7b, 0x15, 0xeb, 0x7b, 0x28, 0xc5, 0x67, 0xdd, 0xbf, 0xf9, 0xc4, - 0xfa, 0x51, 0x9f, 0xfc, 0x07, 0xd5, 0x71, 0x4a, 0x7c, 0x58, 0xfc, 0x27, 0xed, 0x8b, 0xcc, 0xe7, - 0xf3, 0xaf, 0xf9, 0xfc, 0x19, 0x9f, 0x35, 0xc4, 0x1f, 0xff, 0x53, 0x5e, 0x4d, 0xe9, 0x89, 0x5e, - 0xc8, 0x4c, 0x74, 0x7d, 0x2a, 0x0f, 0x59, 0xfe, 0xe4, 0x9f, 0xfe, 0x51, 0x0d, 0xfe, 0xdf, 0x72, - 0xca, 0xaa, 0x1f, 0x3f, 0x75, 0x7f, 0xa1, 0x1c, 0xbd, 0xf8, 0x60, 0xe2, 0xc7, 0x7c, 0xee, 0x95, - 0x96, 0xba, 0xc2, 0xab, 0x2c, 0x75, 0xef, 0xa9, 0x87, 0x42, 0x96, 0x2f, 0xb2, 0xd2, 0xc9, 0xb7, - 0x42, 0x6e, 0x43, 0x39, 0x6d, 0x9b, 0x63, 0xa3, 0x0c, 0x1b, 0x55, 0xd8, 0x2c, 0xa7, 0x4b, 0xbd, - 0x81, 0xdb, 0xbb, 0xa1, 0xca, 0x95, 0x01, 0xac, 0x28, 0xa1, 0xff, 0x39, 0xe6, 0xa8, 0xbf, 0x69, - 0x97, 0xbc, 0xda, 0x4c, 0xa3, 0xff, 0xbf, 0x39, 0xa8, 0x66, 0x7c, 0x57, 0x7e, 0x83, 0x4f, 0x2c, - 0xe4, 0xcb, 0xf9, 0xff, 0x1f, 0xf1, 0xe5, 0xcc, 0xcd, 0x82, 0x62, 0xf6, 0x66, 0x01, 0xb2, 0xbb, - 0x4a, 0x46, 0x2b, 0x5a, 0xa4, 0x3f, 0xe5, 0x16, 0xea, 0x4f, 0xb7, 0x00, 0xac, 0x21, 0x5d, 0x79, - 0x6c, 0x6f, 0xb1, 0x23, 0x7f, 0xd5, 0x48, 0x41, 0xc4, 0x57, 0x70, 0x5d, 0x1a, 0x4d, 0xb8, 0x7f, - 0xfc, 0x43, 0x53, 0x61, 0x47, 0xd2, 0x08, 0x71, 0x95, 0x09, 0x68, 0x74, 0x7b, 0x87, 0x0d, 0x85, - 0xd5, 0xdb, 0x50, 0xcd, 0x38, 0x05, 0xe1, 0xde, 0x72, 0xe4, 0xfa, 0x07, 0x96, 0x2b, 0xeb, 0x22, - 0x53, 0xe2, 0x0e, 0x2c, 0x9f, 0x1e, 0xdb, 0x81, 0xbd, 0xe0, 0x3d, 0x67, 0x46, 0xe8, 0x3f, 0x85, - 0x4a, 0xda, 0x41, 0x51, 0x7c, 0x08, 0xcb, 0x4e, 0x64, 0x8f, 0x95, 0x39, 0xe8, 0xea, 0xbc, 0x0f, - 0x63, 0x3b, 0xb2, 0xc7, 0x06, 0x13, 0xe9, 0xbf, 0x9f, 0x03, 0x6d, 0x16, 0x47, 0x31, 0x98, 0xce, - 0xc3, 0xc8, 0x1e, 0xab, 0xca, 0x70, 0x2a, 0x55, 0xc9, 0xa5, 0x4c, 0x25, 0x95, 0xd5, 0x2c, 0x9f, - 0xb2, 0x9a, 0xdd, 0x51, 0x42, 0xc9, 0xfc, 0x5d, 0x36, 0x46, 0x88, 0x77, 0xa1, 0x18, 0xd8, 0x14, - 0xdd, 0x69, 0xd1, 0x2b, 0x39, 0x31, 0x4e, 0xff, 0xbd, 0x1c, 0xac, 0x4a, 0x6f, 0xca, 0x85, 0xf6, - 0xb9, 0xf7, 0x61, 0x35, 0x1c, 0x1e, 0xdb, 0x63, 0x4b, 0x3d, 0x8e, 0x35, 0x77, 0x64, 0xa4, 0xf0, - 0xe2, 0x16, 0xfb, 0x98, 0x66, 0xed, 0x75, 0x7b, 0xae, 0xe5, 0x19, 0x04, 0xc7, 0xa9, 0xc6, 0x76, - 0x5a, 0xbe, 0x93, 0xc6, 0x2f, 0x97, 0x00, 0x81, 0xe8, 0xd6, 0x99, 0xfe, 0x5b, 0xb0, 0x2a, 0xbd, - 0x35, 0x17, 0x56, 0xe5, 0x16, 0x14, 0xac, 0xe0, 0x28, 0x5c, 0x30, 0x58, 0x04, 0xd7, 0xef, 0x00, - 0x24, 0xee, 0x9b, 0x8b, 0x4a, 0xd0, 0xef, 0x43, 0x51, 0x79, 0x6c, 0xe2, 0xfc, 0x4b, 0x3e, 0x2d, - 0xef, 0xa1, 0xa7, 0x2b, 0xe3, 0x42, 0x95, 0x26, 0x6a, 0xc7, 0x1f, 0x9e, 0xd0, 0x91, 0xc1, 0xc7, - 0x40, 0xd7, 0xf9, 0x07, 0x73, 0x4f, 0xbc, 0xc4, 0x64, 0x7c, 0x4b, 0x45, 0x11, 0x89, 0xfb, 0x10, - 0xf3, 0xcb, 0xd7, 0x59, 0x2b, 0xf4, 0x86, 0x0a, 0xfc, 0x40, 0xb3, 0xec, 0x91, 0xb4, 0x1e, 0x77, - 0xe8, 0xf9, 0xc1, 0x5c, 0xfa, 0x9e, 0x40, 0xa6, 0x4e, 0x46, 0x8a, 0x4c, 0xaf, 0x41, 0x25, 0xed, - 0x66, 0xa6, 0x37, 0x60, 0x5d, 0xdd, 0x44, 0x50, 0x0f, 0x5f, 0xf0, 0xfc, 0xc5, 0x1f, 0xd9, 0xf9, - 0x3b, 0x4b, 0x67, 0x30, 0x91, 0xfe, 0x37, 0x0b, 0xa0, 0xcd, 0xe2, 0x5e, 0x15, 0x04, 0xe3, 0x36, - 0x94, 0xf9, 0xdd, 0xaa, 0xb4, 0x25, 0x11, 0x18, 0x94, 0xba, 0xa6, 0xc4, 0x6f, 0x3a, 0xa9, 0xe7, - 0xc6, 0x9d, 0x90, 0xdf, 0x7c, 0x12, 0xd7, 0x38, 0xe2, 0x81, 0xeb, 0x0f, 0x69, 0x5a, 0x57, 0x28, - 0xc0, 0x41, 0xc7, 0x1f, 0x52, 0x6c, 0x0d, 0x69, 0xf0, 0x60, 0x67, 0x87, 0x8a, 0x51, 0x94, 0x56, - 0x0e, 0x3a, 0xcf, 0x95, 0x97, 0x97, 0xa2, 0x50, 0x06, 0xc0, 0x2b, 0x32, 0x60, 0x10, 0xaa, 0x97, - 0xf8, 0x87, 0x5e, 0x24, 0x43, 0x3b, 0xad, 0x04, 0xfe, 0x69, 0xd3, 0xa3, 0xd0, 0x1a, 0xf4, 0x0e, - 0x2e, 0x62, 0x64, 0xa8, 0x2c, 0x4c, 0x23, 0x8a, 0xe2, 0x29, 0x71, 0x74, 0x63, 0x7e, 0x85, 0xae, - 0x24, 0x9f, 0x1f, 0x94, 0xc0, 0xf8, 0x91, 0x4f, 0xde, 0xff, 0x52, 0x41, 0xb3, 0x80, 0x41, 0x44, - 0x70, 0x1d, 0x8a, 0xbf, 0xf2, 0x3d, 0x9b, 0x0c, 0x27, 0x65, 0xaa, 0xd5, 0x2a, 0xa6, 0x77, 0xad, - 0x09, 0x6e, 0x04, 0x2e, 0xc5, 0x5a, 0xe4, 0xeb, 0xb9, 0x9c, 0xd0, 0xff, 0x9b, 0x1c, 0x6c, 0xcc, - 0xf6, 0x35, 0x4d, 0xa3, 0x0a, 0x14, 0x9b, 0xbd, 0x8e, 0xd9, 0x6d, 0xec, 0xb6, 0xb4, 0x4b, 0x62, - 0x0d, 0xca, 0xbd, 0xcd, 0xa7, 0xad, 0xe6, 0x80, 0x01, 0x39, 0x8a, 0x18, 0xdb, 0x37, 0x77, 0xda, - 0x5b, 0x5b, 0xad, 0x2e, 0x6b, 0x14, 0xbd, 0xcd, 0xa7, 0x66, 0xa7, 0xd7, 0xd4, 0xf2, 0x88, 0x53, - 0x0e, 0x38, 0x7d, 0xad, 0x40, 0xee, 0x39, 0x74, 0x0d, 0x03, 0x93, 0xcb, 0x7c, 0xbf, 0xe0, 0x45, - 0xdf, 0x6c, 0x76, 0x07, 0xda, 0x0a, 0xa6, 0xba, 0xfb, 0x9d, 0x0e, 0xa5, 0xc8, 0x91, 0xb8, 0xd9, - 0xdb, 0xdd, 0x33, 0x5a, 0xfd, 0xbe, 0xd9, 0x6f, 0xff, 0xb2, 0xa5, 0x15, 0xe9, 0xcb, 0x46, 0xfb, - 0x49, 0xbb, 0xcb, 0x80, 0x92, 0x58, 0x85, 0xfc, 0x6e, 0xbb, 0xcb, 0x91, 0x72, 0x77, 0x1b, 0xdf, - 0x68, 0x65, 0xfc, 0xd1, 0xdf, 0xdf, 0xd5, 0x2a, 0xa2, 0x04, 0xcb, 0x9d, 0xd6, 0xf3, 0x56, 0x47, - 0xab, 0xea, 0xff, 0x53, 0x5e, 0x49, 0xc4, 0xe4, 0x61, 0xf7, 0x43, 0xa4, 0xc0, 0x45, 0xa7, 0xac, - 0x71, 0xa7, 0xe5, 0x53, 0x9d, 0x46, 0xcf, 0x41, 0x31, 0xdb, 0x4f, 0x9f, 0x93, 0x95, 0x25, 0x8c, - 0xa6, 0xdc, 0xdb, 0x50, 0x8d, 0xcf, 0xa0, 0x53, 0xaf, 0xe7, 0x57, 0x14, 0x70, 0xc1, 0x71, 0xcd, - 0xca, 0x82, 0xe3, 0x9a, 0x89, 0x13, 0xa1, 0xe2, 0x8e, 0x3c, 0x97, 0x67, 0x52, 0x09, 0x21, 0xcf, - 0x89, 0xd7, 0xbe, 0x01, 0x94, 0x30, 0xa7, 0x9e, 0x7c, 0xf5, 0xab, 0x64, 0x14, 0x11, 0xb0, 0xef, - 0x71, 0x80, 0x8c, 0xb4, 0xb3, 0x4a, 0x69, 0xce, 0x59, 0x25, 0xbd, 0x39, 0x43, 0x76, 0x73, 0x7e, - 0x33, 0xde, 0x23, 0x11, 0x59, 0xa6, 0xb3, 0x8a, 0x52, 0xbc, 0x0b, 0x8a, 0x0f, 0x41, 0x0c, 0xa7, - 0x01, 0x3d, 0xba, 0x93, 0x22, 0xab, 0x10, 0x99, 0x26, 0x31, 0xf1, 0xae, 0x48, 0xe1, 0x86, 0xb2, - 0xd4, 0xa4, 0x9e, 0x97, 0x8c, 0x5a, 0x96, 0x54, 0x3c, 0x80, 0xcb, 0x72, 0x6e, 0x67, 0xfa, 0x56, - 0x46, 0x2a, 0x61, 0x54, 0x23, 0xe9, 0x61, 0xfd, 0x27, 0x50, 0x54, 0xce, 0x94, 0xaf, 0x16, 0x76, - 0x17, 0x8c, 0xab, 0xfe, 0xd7, 0x97, 0xa0, 0x14, 0xbb, 0x56, 0xfe, 0xa0, 0xd9, 0xf1, 0x06, 0xca, - 0xa9, 0xe1, 0x49, 0x9a, 0xc5, 0x14, 0x11, 0xa0, 0x46, 0x4a, 0x5e, 0x22, 0x9d, 0x06, 0x8e, 0x92, - 0xd8, 0x18, 0xb2, 0x1f, 0x38, 0x14, 0x59, 0xdf, 0xf1, 0x52, 0x91, 0x41, 0x4a, 0x46, 0x11, 0x01, - 0xb4, 0xd0, 0xae, 0x03, 0xfd, 0xa6, 0x9c, 0x3c, 0x49, 0x56, 0x31, 0x8d, 0xf9, 0xae, 0xc6, 0xfa, - 0x9f, 0x8c, 0xc7, 0x17, 0xc5, 0x82, 0x85, 0xf4, 0xea, 0x62, 0x1f, 0x13, 0x99, 0xc2, 0xef, 0x50, - 0x14, 0x2b, 0xaa, 0xa3, 0x9c, 0x11, 0x08, 0x50, 0x75, 0x4c, 0x0d, 0x57, 0x69, 0x76, 0x54, 0x67, - 0xe7, 0x34, 0xcc, 0xcd, 0x69, 0x3d, 0x82, 0x55, 0xe9, 0x5e, 0xfa, 0xea, 0x0e, 0x7f, 0x65, 0x57, - 0x69, 0x90, 0xb7, 0x5c, 0x15, 0xa6, 0x01, 0x7f, 0xce, 0x54, 0xac, 0x30, 0x53, 0x31, 0xfd, 0x5f, - 0x5a, 0x02, 0x48, 0xdc, 0x54, 0xc5, 0x47, 0x33, 0x2e, 0xf1, 0xb9, 0xb9, 0x6d, 0x7f, 0xc6, 0x13, - 0x7e, 0xe6, 0xa9, 0x89, 0xa5, 0x1f, 0xf0, 0xd4, 0xc4, 0x43, 0xa8, 0x86, 0xc1, 0xf0, 0xb5, 0x36, - 0xfc, 0x72, 0x18, 0x0c, 0x63, 0x13, 0xfe, 0xc7, 0x80, 0x49, 0x7a, 0x86, 0x2a, 0x51, 0x54, 0xe7, - 0xa4, 0x96, 0x52, 0x18, 0x0c, 0x7b, 0x07, 0xdf, 0x6d, 0xf1, 0xcd, 0xdd, 0x51, 0x18, 0x99, 0x8b, - 0xb8, 0xc4, 0xda, 0x28, 0x8c, 0xb6, 0xd2, 0x8c, 0xe2, 0x2e, 0xd4, 0x90, 0x76, 0x8e, 0x59, 0x54, - 0x46, 0x61, 0x72, 0xa0, 0xa4, 0xff, 0x63, 0xea, 0x60, 0x7e, 0xc6, 0x3c, 0x2c, 0xbe, 0x90, 0x8a, - 0x78, 0x4a, 0x88, 0xa8, 0x2f, 0xb2, 0x26, 0xf3, 0xe5, 0xfe, 0x98, 0x54, 0x3c, 0x86, 0x6a, 0x8c, - 0xdb, 0xb2, 0x0f, 0x95, 0x0c, 0xa4, 0xde, 0x34, 0x4a, 0xa1, 0x8c, 0x2c, 0xa1, 0xfe, 0x18, 0x20, - 0x79, 0x08, 0x0c, 0x57, 0x60, 0x7c, 0x4d, 0xac, 0xc4, 0x17, 0xc0, 0x70, 0x0e, 0x7b, 0x14, 0x2b, - 0x40, 0x3e, 0x75, 0x2d, 0x53, 0xfa, 0x63, 0xb8, 0x76, 0x81, 0x7d, 0x4d, 0x9d, 0x57, 0xca, 0x40, - 0x1e, 0x32, 0x22, 0xa1, 0x67, 0x9f, 0x72, 0x20, 0x0f, 0xdd, 0x83, 0xcb, 0x0b, 0x1e, 0xeb, 0x17, - 0x77, 0xc8, 0xa9, 0x8d, 0x4e, 0x03, 0xe3, 0xdb, 0xfd, 0xcb, 0x74, 0x0e, 0xda, 0x1e, 0xf1, 0x73, - 0x24, 0x9f, 0xc3, 0x9a, 0xed, 0x3a, 0x47, 0xce, 0x81, 0x43, 0x91, 0xff, 0x87, 0xbe, 0x3b, 0x67, - 0x75, 0xa3, 0x87, 0xd3, 0x53, 0x44, 0x4d, 0xdf, 0xd5, 0xff, 0xc9, 0x9c, 0x7c, 0x79, 0x33, 0xfb, - 0x6c, 0x20, 0xbf, 0xbc, 0x29, 0x9f, 0xf8, 0xce, 0x19, 0xf4, 0x1b, 0x5b, 0x2b, 0x5f, 0x75, 0x96, - 0xcf, 0xee, 0x71, 0x4a, 0x7c, 0x0c, 0x1b, 0x32, 0x7a, 0x3e, 0x85, 0xda, 0x33, 0x27, 0x76, 0x60, - 0x06, 0xfe, 0x29, 0x4d, 0xb8, 0x9c, 0xb1, 0xce, 0x38, 0x8a, 0xb8, 0xb7, 0x67, 0x07, 0x86, 0x7f, - 0x2a, 0xea, 0x24, 0xad, 0xd8, 0xc3, 0x48, 0x9d, 0x3d, 0xab, 0xa4, 0xfe, 0x3b, 0x70, 0x79, 0xc1, - 0xbd, 0x52, 0xf1, 0x8e, 0xd2, 0xff, 0x2e, 0xb8, 0x45, 0xbe, 0x50, 0xe7, 0x5c, 0x9a, 0xd5, 0x39, - 0xbb, 0x50, 0xcd, 0x5c, 0x15, 0xcd, 0x46, 0xf0, 0x2f, 0xbc, 0x3a, 0x82, 0x3f, 0x3d, 0x88, 0xbe, - 0xf4, 0xb4, 0x50, 0x5c, 0xd2, 0xf2, 0x4f, 0x0b, 0xc5, 0xbc, 0x56, 0xd0, 0xff, 0x6a, 0x0e, 0x8a, - 0x8a, 0x70, 0x7e, 0xaf, 0xcc, 0x2d, 0xd8, 0x2b, 0xdf, 0x90, 0x1f, 0x4c, 0x33, 0x15, 0x04, 0x10, - 0xf2, 0x3e, 0x14, 0xe3, 0x05, 0x9e, 0x5f, 0xb8, 0xc0, 0x63, 0xbc, 0xf8, 0x00, 0xd6, 0x33, 0xfe, - 0xb1, 0xa9, 0x1d, 0x5c, 0x4b, 0x23, 0xa8, 0xdd, 0x7f, 0x90, 0x83, 0xb2, 0x7a, 0xa9, 0xd3, 0xe0, - 0xe8, 0x9e, 0xea, 0x41, 0xcf, 0x24, 0x3c, 0x1a, 0x28, 0x50, 0x7b, 0x84, 0xaa, 0x78, 0x60, 0xbf, - 0x74, 0x42, 0xe5, 0xef, 0x5b, 0x30, 0xe2, 0x34, 0x7e, 0x39, 0x8e, 0x27, 0x3a, 0x13, 0x0c, 0x53, - 0x8b, 0x11, 0x2a, 0x6e, 0xe2, 0x3c, 0x57, 0x2c, 0xa4, 0xd9, 0xf5, 0xcc, 0xfe, 0xbe, 0x3c, 0xbb, - 0xbf, 0xeb, 0xff, 0x5c, 0x0e, 0xea, 0xfd, 0xef, 0x5d, 0x79, 0xc9, 0xb6, 0x3d, 0x9e, 0xb8, 0xb4, - 0x88, 0xf8, 0x7e, 0xee, 0xe7, 0x70, 0x35, 0x71, 0x68, 0x36, 0x0f, 0x1d, 0xef, 0xc8, 0x0e, 0x26, - 0x81, 0x23, 0x1d, 0x33, 0x2a, 0xc6, 0x95, 0x04, 0xbb, 0x9d, 0x20, 0xc5, 0x33, 0xd0, 0x43, 0x7b, - 0x6c, 0x79, 0x91, 0x33, 0x34, 0x53, 0xf9, 0x59, 0x13, 0x8b, 0x5b, 0xc4, 0x33, 0xfc, 0xb6, 0xa2, - 0x4c, 0x2e, 0x6f, 0xf5, 0x89, 0x4e, 0x36, 0x50, 0xff, 0xf7, 0xf3, 0xf0, 0xc6, 0xde, 0x79, 0x74, - 0xec, 0x7b, 0x8b, 0xeb, 0x58, 0x87, 0xd5, 0x63, 0xcb, 0x1b, 0xb9, 0x71, 0xd4, 0x60, 0x95, 0x14, - 0x37, 0x60, 0x85, 0xf7, 0x56, 0x9e, 0x07, 0x9b, 0x4b, 0xf5, 0x9c, 0x21, 0x21, 0xb4, 0x8d, 0x1d, - 0x38, 0x26, 0xdd, 0x34, 0xb3, 0x86, 0x91, 0xdc, 0x8b, 0xcb, 0xd6, 0x81, 0xd3, 0x94, 0x20, 0x94, - 0x48, 0xe8, 0x3d, 0x0b, 0x3b, 0x88, 0xab, 0x2c, 0x1d, 0x9d, 0x24, 0x58, 0x0d, 0x01, 0x12, 0x06, - 0x91, 0x73, 0x68, 0x0d, 0x23, 0x15, 0x12, 0x72, 0x59, 0x12, 0x4a, 0xb0, 0x8c, 0x08, 0xf9, 0x11, - 0x08, 0xdb, 0x7b, 0xe9, 0x04, 0xbe, 0x47, 0x21, 0x69, 0x24, 0x2d, 0xb3, 0xe8, 0xf5, 0x14, 0x46, - 0x92, 0xdf, 0x86, 0x72, 0x38, 0x3a, 0x89, 0x3f, 0x2e, 0xc3, 0x63, 0x87, 0xa3, 0x13, 0xf5, 0xe1, - 0xaf, 0xe1, 0xfa, 0xc5, 0xdd, 0xcb, 0x01, 0xba, 0xae, 0x8d, 0x16, 0x77, 0x6b, 0xcc, 0x6b, 0x4b, - 0x29, 0x5e, 0x7b, 0x1b, 0xca, 0xa4, 0x76, 0x4c, 0x7c, 0xd7, 0x19, 0x9e, 0xcb, 0xad, 0x1d, 0x10, - 0xb4, 0x47, 0x90, 0x57, 0xcc, 0x07, 0x76, 0x2c, 0x5d, 0x3c, 0x1f, 0xf4, 0x7f, 0x75, 0x19, 0xca, - 0x72, 0xf0, 0x9a, 0xb8, 0x93, 0x73, 0xe0, 0x31, 0xea, 0xe5, 0xb8, 0xba, 0x1c, 0x4d, 0x67, 0x4d, - 0xc1, 0x55, 0x35, 0x3f, 0x83, 0x4a, 0xbc, 0x90, 0x92, 0xf0, 0x25, 0x2a, 0x9c, 0x75, 0xb2, 0xe2, - 0x8c, 0x78, 0xbd, 0xe1, 0xf2, 0xbb, 0x01, 0x45, 0xd7, 0xf2, 0x8e, 0xa6, 0xd6, 0x51, 0xec, 0xf2, - 0xab, 0xd2, 0xe2, 0x53, 0xa8, 0x59, 0xc1, 0xd1, 0x94, 0x46, 0x20, 0x51, 0xf5, 0xb3, 0x81, 0x6b, - 0xaa, 0x8a, 0x82, 0xe3, 0xcd, 0x7c, 0x0a, 0x65, 0xbe, 0xf4, 0xcf, 0x92, 0xd9, 0xf2, 0x05, 0x1e, - 0x3f, 0xc0, 0x44, 0xb4, 0x25, 0xde, 0x02, 0x78, 0xe9, 0xbb, 0x56, 0x44, 0xbb, 0x80, 0x1c, 0xe2, - 0x14, 0x64, 0xb6, 0xab, 0x57, 0xe7, 0xba, 0xfa, 0x21, 0xfb, 0xd4, 0xf3, 0x29, 0xa0, 0x3c, 0x82, - 0xbf, 0x68, 0x9d, 0xee, 0x5c, 0x62, 0xaf, 0xfb, 0x9f, 0xc0, 0xca, 0x84, 0x56, 0x8a, 0x3c, 0x00, - 0x7c, 0x4b, 0x6e, 0xc0, 0x17, 0xaf, 0x9e, 0x9d, 0x4b, 0x86, 0xcc, 0x22, 0x7e, 0xca, 0xf7, 0x2e, - 0xed, 0xb3, 0x48, 0x06, 0x4a, 0xbf, 0x95, 0xb9, 0x7e, 0x8f, 0x03, 0xf7, 0xa0, 0xc9, 0x04, 0x74, - 0x18, 0x45, 0xcb, 0x49, 0x65, 0x21, 0x27, 0x22, 0xcb, 0x75, 0x43, 0x27, 0xb2, 0x95, 0x32, 0x50, - 0x32, 0x40, 0x81, 0xda, 0x14, 0xca, 0x7d, 0x6c, 0x9d, 0x9b, 0x76, 0x10, 0xf8, 0x81, 0x0c, 0xae, - 0x53, 0x1c, 0x5b, 0xe7, 0x2d, 0x4c, 0x23, 0x67, 0x0f, 0xed, 0xe1, 0x34, 0xc0, 0x6d, 0x95, 0x66, - 0x25, 0x8b, 0xfe, 0x15, 0x05, 0xa4, 0x8b, 0xdf, 0x37, 0xa1, 0xe4, 0xda, 0xd6, 0xc9, 0x24, 0xf0, - 0xfd, 0x43, 0x29, 0xee, 0x27, 0x80, 0x1b, 0x5f, 0x43, 0x25, 0x5d, 0xbb, 0xd7, 0x39, 0x79, 0x94, - 0x52, 0x87, 0x63, 0x9b, 0x1a, 0xd4, 0x9c, 0x4c, 0xb7, 0xe8, 0xff, 0x51, 0x1e, 0xae, 0x2c, 0x8c, - 0x3b, 0x30, 0x37, 0x21, 0x73, 0x3f, 0x7a, 0x42, 0x2e, 0xcd, 0x4c, 0xc8, 0x45, 0xab, 0x21, 0xbf, - 0x78, 0x35, 0x5c, 0xbc, 0xfe, 0x0a, 0xaf, 0x58, 0x7f, 0x7f, 0x66, 0x0c, 0x2a, 0x3b, 0xc9, 0x57, - 0x5f, 0x37, 0xc9, 0x8b, 0x73, 0x93, 0x3c, 0x33, 0x29, 0x4a, 0xaf, 0x9b, 0x14, 0xf0, 0xba, 0x49, - 0x51, 0x9e, 0x99, 0x14, 0xfa, 0x1f, 0xe5, 0x40, 0x9b, 0xf5, 0xe1, 0x9e, 0xdd, 0x12, 0x73, 0x73, - 0x2a, 0xef, 0xdb, 0x50, 0x1d, 0x1e, 0x5b, 0xd8, 0xef, 0x74, 0xf3, 0x30, 0x92, 0x23, 0x56, 0x89, - 0x81, 0x7d, 0x9b, 0x62, 0x9d, 0x0f, 0x7d, 0x57, 0x46, 0xbc, 0x90, 0x9a, 0x5c, 0x0c, 0x20, 0x5f, - 0xd4, 0xd4, 0x9e, 0x51, 0x30, 0x54, 0x92, 0x22, 0x35, 0x29, 0x32, 0xb5, 0x23, 0x57, 0x8d, 0x72, - 0x0c, 0x53, 0xd1, 0xb0, 0x15, 0x49, 0x2c, 0x25, 0xac, 0x10, 0xe1, 0x7a, 0x8c, 0x31, 0x24, 0xe2, - 0xfe, 0x3f, 0x9b, 0x83, 0xf5, 0x7e, 0x14, 0x38, 0xde, 0x51, 0xc7, 0x89, 0xec, 0xc0, 0x72, 0xb7, - 0xfd, 0x60, 0x4c, 0xd7, 0xd4, 0x06, 0x46, 0xbb, 0xfb, 0xc4, 0xec, 0xb4, 0x07, 0x2d, 0xa3, 0x11, - 0xbf, 0x58, 0x32, 0x8f, 0x18, 0xb4, 0xbe, 0x19, 0x68, 0x39, 0x71, 0x17, 0xee, 0xcc, 0x20, 0x36, - 0xdb, 0xdd, 0x86, 0xf1, 0xad, 0xd9, 0xee, 0x0e, 0x8c, 0xde, 0xd6, 0x7e, 0xb3, 0x65, 0x68, 0x4b, - 0xe2, 0x2a, 0x88, 0x19, 0xaa, 0x9d, 0xd6, 0x37, 0x5a, 0x7e, 0x01, 0x7c, 0xb3, 0x3d, 0xd0, 0x0a, - 0xf7, 0x77, 0xe1, 0x72, 0xe3, 0xe8, 0x28, 0xb0, 0x8f, 0x50, 0x87, 0xa6, 0x88, 0xf8, 0xea, 0xae, - 0x60, 0xe3, 0xc9, 0x13, 0xb3, 0xd9, 0xeb, 0x6e, 0xb7, 0x9f, 0xa8, 0xaa, 0xbd, 0x05, 0x6f, 0xa6, - 0x80, 0x4f, 0x8c, 0xde, 0xfe, 0x1e, 0x26, 0x9a, 0x8d, 0x81, 0xd9, 0x33, 0xb6, 0x5a, 0x86, 0x96, - 0xbb, 0xff, 0x16, 0x2e, 0x73, 0xb6, 0x74, 0xc5, 0x0f, 0xbc, 0xf8, 0x9e, 0xad, 0x5d, 0x12, 0xab, - 0x90, 0xef, 0xfc, 0xea, 0x33, 0x2d, 0x77, 0x3f, 0x00, 0x8d, 0x83, 0x25, 0xf3, 0xd1, 0x3f, 0x85, - 0x86, 0xbe, 0x05, 0x37, 0x8c, 0x56, 0x7f, 0xbf, 0x33, 0x90, 0x57, 0xec, 0xcc, 0x67, 0xed, 0xee, - 0x96, 0x99, 0x84, 0x06, 0x79, 0x13, 0xae, 0x2f, 0xc0, 0xf7, 0x07, 0x3d, 0xa3, 0xb5, 0xa5, 0xe5, - 0xc4, 0x6d, 0x78, 0x63, 0x01, 0xba, 0xd9, 0xdb, 0xdd, 0xdb, 0x1f, 0xb4, 0xb6, 0xb4, 0xa5, 0xfb, - 0x3a, 0x94, 0xfb, 0xc7, 0xd3, 0xc3, 0x43, 0xd7, 0x56, 0xb5, 0xda, 0xb1, 0xc2, 0x63, 0xf6, 0xa0, - 0xa7, 0x47, 0xd1, 0xb5, 0xdc, 0xfd, 0x77, 0xa1, 0x2a, 0x69, 0x76, 0xed, 0xe8, 0xd8, 0x1f, 0x09, - 0x80, 0x95, 0xae, 0x1f, 0x8c, 0x2d, 0x57, 0xd2, 0xd9, 0xd3, 0x10, 0xe9, 0x3e, 0x86, 0x2b, 0xa9, - 0xb2, 0xb6, 0xfd, 0x80, 0x62, 0x7a, 0x36, 0xbb, 0x14, 0xbf, 0x84, 0xf8, 0x14, 0x47, 0xe2, 0xd8, - 0x39, 0x3f, 0x08, 0x9c, 0x91, 0x96, 0xbb, 0xff, 0x18, 0x4a, 0x9b, 0xfe, 0xd4, 0xe3, 0x47, 0x3c, - 0xe8, 0xf5, 0xa6, 0xcd, 0xde, 0x7e, 0x77, 0x8b, 0xde, 0x7b, 0xa1, 0x17, 0x9b, 0x9a, 0x9d, 0xfd, - 0x7e, 0xfb, 0xb9, 0x34, 0xc7, 0xb5, 0xbe, 0x51, 0xc9, 0xa5, 0xfb, 0xbf, 0x97, 0x53, 0x01, 0x84, - 0x55, 0xb5, 0x3b, 0xbd, 0xc6, 0x16, 0xdb, 0xf1, 0xe2, 0x87, 0xa9, 0x06, 0x9b, 0x5a, 0x0e, 0x01, - 0xb2, 0x07, 0xe4, 0x9b, 0x57, 0x35, 0x80, 0x76, 0xb3, 0xb5, 0xd9, 0x32, 0x9e, 0x20, 0x41, 0x1e, - 0xd3, 0xbb, 0xbd, 0xee, 0x93, 0xde, 0xd6, 0x26, 0xa6, 0xe9, 0xb5, 0xab, 0xad, 0xc6, 0xa0, 0xd1, - 0x1f, 0x18, 0xad, 0xc6, 0x2e, 0x82, 0x28, 0x44, 0x80, 0xba, 0x28, 0x30, 0xd8, 0x64, 0x9b, 0xde, - 0xb3, 0xc6, 0xf6, 0xb3, 0x06, 0xa6, 0x56, 0xef, 0xff, 0x57, 0x4b, 0xa0, 0xcd, 0x06, 0x89, 0x16, - 0x6f, 0xc0, 0x35, 0x2a, 0xd5, 0xdc, 0x33, 0x5a, 0x5b, 0xed, 0x26, 0x5f, 0xf6, 0x7c, 0xde, 0xe8, - 0xb4, 0xb7, 0x78, 0x26, 0xcf, 0x22, 0x1b, 0xdd, 0x2d, 0x7e, 0xc8, 0x66, 0x16, 0xd1, 0xfa, 0xc5, - 0x7e, 0xa3, 0xa3, 0x2d, 0xe1, 0x40, 0xcf, 0xa2, 0xba, 0xbd, 0x81, 0x44, 0xe7, 0x45, 0x1d, 0x36, - 0x66, 0xd1, 0x9d, 0x56, 0xbf, 0xaf, 0x15, 0x70, 0x06, 0x2d, 0xc2, 0xc8, 0x9c, 0xcb, 0x8b, 0x6a, - 0xfa, 0x84, 0x8c, 0x9b, 0x86, 0xb6, 0x82, 0x13, 0xfb, 0x02, 0xa4, 0xcc, 0xbf, 0x8a, 0xeb, 0x67, - 0xbe, 0xa5, 0x5a, 0x71, 0x61, 0x0f, 0xf4, 0x4d, 0x7a, 0xb6, 0xa8, 0x84, 0xf3, 0x72, 0x11, 0xb2, - 0x37, 0x60, 0x02, 0xb8, 0xff, 0xb7, 0x73, 0x50, 0xbf, 0x28, 0x96, 0x9f, 0xd0, 0xe1, 0x96, 0xb1, - 0xdf, 0xa5, 0x37, 0xab, 0xf8, 0x79, 0x2d, 0xf3, 0x59, 0xeb, 0xdb, 0x99, 0xf7, 0x82, 0x70, 0x61, - 0xcc, 0xd3, 0x18, 0x8d, 0x17, 0xe6, 0xf3, 0x4f, 0xb5, 0x9c, 0xf8, 0x00, 0xde, 0x5b, 0x80, 0xde, - 0xee, 0xf4, 0x1a, 0x03, 0xf3, 0x97, 0x2d, 0xa3, 0x67, 0x36, 0x3b, 0xbd, 0x7e, 0x6b, 0x0b, 0x89, - 0x97, 0xc4, 0x1d, 0xb8, 0xb9, 0x80, 0xb8, 0xcf, 0x2f, 0xa2, 0x3d, 0xff, 0x54, 0xcb, 0x8b, 0x77, - 0xe0, 0xad, 0x8b, 0x29, 0xb6, 0xf7, 0x3b, 0x44, 0x56, 0xb8, 0xff, 0x73, 0xa8, 0x5f, 0x14, 0x49, - 0x05, 0x17, 0x52, 0x73, 0xa7, 0x41, 0xd1, 0x6a, 0x2a, 0x50, 0xec, 0xf6, 0x4c, 0x4e, 0x91, 0x67, - 0x8b, 0xd1, 0xea, 0xb4, 0xe8, 0xba, 0xf1, 0xfd, 0x5f, 0xe7, 0x52, 0xe7, 0x27, 0x2a, 0x1a, 0x46, - 0x0c, 0x90, 0x1c, 0x25, 0x0d, 0x32, 0x6c, 0x6b, 0xa4, 0xe5, 0x70, 0x94, 0x32, 0xa0, 0x8e, 0x3f, - 0xb4, 0x5c, 0x6d, 0x89, 0x2e, 0x16, 0x2b, 0x38, 0x85, 0xd4, 0xd2, 0xf2, 0xd8, 0x75, 0x31, 0xac, - 0xe3, 0x9f, 0xee, 0x05, 0x8e, 0x8f, 0xdb, 0x16, 0xa3, 0x0b, 0xf7, 0xff, 0x21, 0xe9, 0x8c, 0x9d, - 0xb1, 0xaa, 0xe0, 0x07, 0x1a, 0xa3, 0x51, 0x02, 0x23, 0x43, 0x1e, 0xcf, 0x75, 0xb2, 0x62, 0xce, - 0x20, 0x72, 0x38, 0x3f, 0xd4, 0x21, 0xef, 0x2c, 0x72, 0x09, 0x91, 0x86, 0x4d, 0x32, 0xc1, 0x1c, - 0x32, 0xbf, 0xf9, 0xec, 0x6f, 0xfd, 0xd1, 0xad, 0xdc, 0x1f, 0xfe, 0xd1, 0xad, 0xdc, 0xff, 0xfc, - 0x47, 0xb7, 0x2e, 0xfd, 0xa5, 0x3f, 0xbe, 0x95, 0xfb, 0xfd, 0x3f, 0xbe, 0x95, 0xfb, 0xc3, 0x3f, - 0xbe, 0x95, 0xfb, 0xef, 0xfe, 0xf8, 0x56, 0xee, 0x97, 0x1f, 0x1d, 0x39, 0xd1, 0xf1, 0xf4, 0xe0, - 0xc1, 0xd0, 0x1f, 0x7f, 0x3c, 0xb6, 0xa2, 0xc0, 0x39, 0x63, 0xd3, 0xaa, 0x4a, 0x78, 0xf6, 0xc7, - 0x93, 0x93, 0xa3, 0x8f, 0x27, 0x07, 0x1f, 0xa3, 0xe4, 0x73, 0xb0, 0x42, 0xb7, 0x9e, 0x1e, 0xfd, - 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x60, 0xde, 0x28, 0xe5, 0xba, 0xc7, 0x00, 0x00, + // 19314 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0xbd, 0x5b, 0x6c, 0x1c, 0xd9, + 0x92, 0x20, 0xa6, 0x62, 0x15, 0xc9, 0xaa, 0xa8, 0x07, 0x93, 0x47, 0x94, 0x54, 0x52, 0xab, 0x25, + 0x75, 0xb6, 0xba, 0x5b, 0xad, 0xee, 0x56, 0x77, 0x4b, 0xfd, 0x50, 0xf7, 0xbd, 0x33, 0xf7, 0x16, + 0x8b, 0x45, 0xb1, 0xa4, 0x62, 0x15, 0x6f, 0x56, 0x51, 0xea, 0xbe, 0xb3, 0xe3, 0x44, 0xb2, 0x2a, + 0x49, 0x66, 0x33, 0x2b, 0xb3, 0x3a, 0x33, 0x4b, 0x24, 0x2f, 0xd6, 0xf0, 0x85, 0x01, 0x7b, 0x3d, + 0xb6, 0xb1, 0x58, 0x60, 0xe1, 0x85, 0x0d, 0x03, 0xf6, 0xd8, 0xc0, 0xc2, 0xc0, 0xda, 0x3f, 0x5e, + 0x2c, 0x3c, 0x7e, 0xc0, 0x8f, 0xb5, 0x3f, 0xbc, 0x7e, 0xc0, 0x18, 0x7b, 0x6d, 0xaf, 0xed, 0x35, + 0xd6, 0xf6, 0x8c, 0x01, 0x7f, 0x1a, 0x86, 0x1f, 0xc0, 0xee, 0x8f, 0x8d, 0x88, 0x38, 0x27, 0x1f, + 0x55, 0x45, 0xa9, 0xfb, 0xce, 0x0c, 0xe0, 0x1f, 0xb2, 0x4e, 0x44, 0x9c, 0x93, 0xe7, 0x19, 0x27, + 0x22, 0x4e, 0x9c, 0x38, 0x00, 0x13, 0xd7, 0xf2, 0x1e, 0x4c, 0x02, 0x3f, 0xf2, 0x45, 0x01, 0x7f, + 0xdf, 0xf8, 0xe8, 0xc8, 0x89, 0x8e, 0xa7, 0x07, 0x0f, 0x86, 0xfe, 0xf8, 0xe3, 0x23, 0xff, 0xc8, + 0xff, 0x98, 0x90, 0x07, 0xd3, 0x43, 0x4a, 0x51, 0x82, 0x7e, 0x71, 0xa6, 0x1b, 0xe0, 0xfa, 0xc3, + 0x13, 0xf9, 0x7b, 0x2d, 0x72, 0xc6, 0x76, 0x18, 0x59, 0xe3, 0x09, 0x03, 0xf4, 0xff, 0x34, 0x0f, + 0x85, 0xc1, 0xf9, 0xc4, 0x16, 0x35, 0x58, 0x72, 0x46, 0xf5, 0xdc, 0x9d, 0xdc, 0xbd, 0x65, 0x63, + 0xc9, 0x19, 0x89, 0x3b, 0x50, 0xf6, 0xfc, 0xa8, 0x3b, 0x75, 0x5d, 0xeb, 0xc0, 0xb5, 0xeb, 0x4b, + 0x77, 0x72, 0xf7, 0x8a, 0x46, 0x1a, 0x24, 0xde, 0x80, 0x92, 0x35, 0x8d, 0x7c, 0xd3, 0xf1, 0x86, + 0x41, 0x3d, 0x4f, 0xf8, 0x22, 0x02, 0xda, 0xde, 0x30, 0x10, 0x1b, 0xb0, 0x7c, 0xea, 0x8c, 0xa2, + 0xe3, 0x7a, 0x81, 0x4a, 0xe4, 0x04, 0x42, 0xc3, 0xa1, 0xe5, 0xda, 0xf5, 0x65, 0x86, 0x52, 0x02, + 0xa1, 0x11, 0x7d, 0x64, 0xe5, 0x4e, 0xee, 0x5e, 0xc9, 0xe0, 0x84, 0xb8, 0x05, 0x60, 0x7b, 0xd3, + 0xf1, 0x4b, 0xcb, 0x9d, 0xda, 0x61, 0x7d, 0x95, 0x50, 0x29, 0x88, 0xa8, 0xc3, 0xea, 0xf0, 0xd8, + 0x0a, 0x42, 0x3b, 0xaa, 0x17, 0xef, 0xe4, 0xee, 0x55, 0x0d, 0x95, 0xc4, 0x8a, 0x4d, 0xac, 0x91, + 0x19, 0x4e, 0xac, 0xa1, 0x5d, 0x2f, 0x71, 0xc5, 0x26, 0xd6, 0xa8, 0x8f, 0x69, 0xf1, 0x39, 0x5c, + 0x1d, 0xfa, 0xae, 0x6b, 0x45, 0x8e, 0xef, 0x99, 0x43, 0xdf, 0x0e, 0x86, 0xce, 0x81, 0xe3, 0x3a, + 0xd1, 0x79, 0x1d, 0xa8, 0x94, 0x2b, 0x31, 0xb6, 0x99, 0x42, 0x8a, 0x9f, 0xc2, 0x8d, 0xc5, 0xd9, + 0x4c, 0xac, 0x40, 0x99, 0x3e, 0x52, 0x5f, 0x98, 0xb5, 0x6f, 0x47, 0xe2, 0x31, 0x24, 0x38, 0x73, + 0x6c, 0x07, 0x47, 0xb6, 0x39, 0xf4, 0xbd, 0x43, 0xd7, 0x19, 0x46, 0xf5, 0x0a, 0xe5, 0x4d, 0x2a, + 0xb5, 0x8b, 0xe8, 0xa6, 0xc4, 0x8a, 0x0f, 0x60, 0x3d, 0xc9, 0xf9, 0xd2, 0x0e, 0x42, 0xc7, 0xf7, + 0xea, 0x55, 0xaa, 0xa9, 0x16, 0x23, 0x9e, 0x33, 0x5c, 0xff, 0x19, 0x94, 0xc6, 0xe1, 0xd1, 0x8e, + 0x6d, 0x8d, 0xec, 0x40, 0x5c, 0x83, 0xd5, 0x71, 0x78, 0x64, 0x46, 0xd6, 0x91, 0x1c, 0xd5, 0x95, + 0x71, 0x78, 0x34, 0xb0, 0x8e, 0xc4, 0x75, 0x28, 0x12, 0xe2, 0x7c, 0xc2, 0xc3, 0xba, 0x6c, 0x20, + 0x21, 0x4e, 0x02, 0xfd, 0x0f, 0x57, 0x61, 0xb5, 0xe3, 0x44, 0x76, 0x60, 0xb9, 0xe2, 0x2a, 0xac, + 0x38, 0xa1, 0x37, 0x75, 0x5d, 0xca, 0x5e, 0x34, 0x64, 0x4a, 0x5c, 0x85, 0x65, 0xe7, 0xf1, 0x4b, + 0xcb, 0xe5, 0xbc, 0x3b, 0x97, 0x0c, 0x4e, 0x8a, 0x3a, 0xac, 0x38, 0x9f, 0x7e, 0x81, 0x88, 0xbc, + 0x44, 0xc8, 0x34, 0x61, 0x1e, 0x3d, 0x44, 0x4c, 0x21, 0xc6, 0x50, 0x9a, 0x30, 0x5f, 0x7c, 0x86, + 0x18, 0x9c, 0x10, 0x79, 0xc2, 0x50, 0x1a, 0xbf, 0x32, 0xa5, 0xaf, 0xe0, 0x9c, 0xa8, 0xe2, 0x57, + 0xa6, 0xea, 0x2b, 0x53, 0xfe, 0xca, 0xaa, 0x44, 0xc8, 0x34, 0x61, 0xf8, 0x2b, 0xc5, 0x18, 0x13, + 0x7f, 0x65, 0xca, 0x5f, 0xc1, 0xc9, 0x50, 0x20, 0x0c, 0x7f, 0x65, 0x03, 0x0a, 0x23, 0x84, 0xe3, + 0xd0, 0xe7, 0x76, 0x2e, 0x19, 0x94, 0x42, 0x68, 0x88, 0x50, 0x1c, 0xd5, 0x12, 0x42, 0x43, 0x09, + 0x3d, 0x40, 0x28, 0x8d, 0x17, 0x42, 0x0f, 0x24, 0xf4, 0x10, 0xa1, 0x38, 0x24, 0x4b, 0x08, 0xc5, + 0x94, 0xb8, 0x01, 0xab, 0x23, 0x2b, 0xb2, 0x11, 0x51, 0x93, 0x4d, 0x56, 0x00, 0xc4, 0xe1, 0x22, + 0x44, 0xdc, 0x9a, 0x6c, 0xb4, 0x02, 0x08, 0x1d, 0xca, 0x48, 0xa6, 0xf0, 0x9a, 0xc4, 0xa7, 0x81, + 0xe2, 0x73, 0xa8, 0x8c, 0xec, 0xa1, 0x33, 0xb6, 0x5c, 0x6e, 0xd3, 0xfa, 0x9d, 0xdc, 0xbd, 0xf2, + 0xc3, 0xb5, 0x07, 0xc4, 0x26, 0x62, 0xcc, 0xce, 0x25, 0x23, 0x43, 0x26, 0x1e, 0x43, 0x55, 0xa6, + 0x3f, 0x7d, 0x48, 0x1d, 0x2b, 0x28, 0x9f, 0x96, 0xc9, 0xf7, 0xe9, 0xc3, 0xc7, 0x3b, 0x97, 0x8c, + 0x2c, 0xa1, 0xb8, 0x0b, 0x95, 0x98, 0x6b, 0x60, 0xc6, 0xcb, 0xb2, 0x56, 0x19, 0x28, 0x36, 0xeb, + 0xbb, 0xd0, 0xf7, 0x90, 0x60, 0x43, 0xf6, 0x9b, 0x02, 0x88, 0x3b, 0x00, 0x23, 0xfb, 0xd0, 0x9a, + 0xba, 0x11, 0xa2, 0xaf, 0xc8, 0x0e, 0x4c, 0xc1, 0xc4, 0x2d, 0x28, 0x4d, 0x27, 0xd8, 0xca, 0xe7, + 0x96, 0x5b, 0xbf, 0x2a, 0x09, 0x12, 0x10, 0x96, 0x8e, 0x4b, 0x1f, 0xb1, 0xd7, 0xe4, 0xe8, 0x2a, + 0x00, 0x0e, 0xef, 0x4b, 0x7b, 0x88, 0xa8, 0xba, 0xfc, 0xb0, 0x4c, 0x23, 0x63, 0x71, 0xc2, 0x4d, + 0xc7, 0xab, 0x5f, 0xa7, 0x19, 0xcc, 0x09, 0x71, 0x13, 0xf2, 0x61, 0x30, 0xac, 0xdf, 0xa0, 0xf6, + 0x03, 0xb7, 0xbf, 0x75, 0x36, 0x09, 0x0c, 0x04, 0x8b, 0xb7, 0xa1, 0xea, 0x84, 0x66, 0x68, 0x07, + 0x8e, 0xe5, 0x3a, 0xbf, 0xb2, 0x47, 0xf5, 0x37, 0x28, 0x6f, 0xc5, 0x09, 0xfb, 0x31, 0x4c, 0x7c, + 0x0d, 0x15, 0x97, 0x97, 0x89, 0x79, 0xe8, 0x07, 0xe3, 0xfa, 0xcd, 0x3b, 0xb9, 0x7b, 0xb5, 0x87, + 0xd7, 0xb8, 0xac, 0x7e, 0x14, 0x38, 0xde, 0x91, 0x5c, 0x46, 0xdb, 0x7e, 0x30, 0x36, 0xca, 0x6e, + 0x92, 0xc0, 0x0f, 0x84, 0x44, 0x61, 0x86, 0xfe, 0x34, 0x18, 0xda, 0xf5, 0x37, 0x69, 0x35, 0x57, + 0x18, 0xd8, 0x27, 0x98, 0xf8, 0x19, 0xdc, 0x94, 0x83, 0x60, 0xaa, 0x0f, 0x05, 0xf6, 0xf7, 0x53, + 0x27, 0xb0, 0x43, 0xf3, 0xe5, 0xe3, 0x87, 0xf5, 0x5b, 0x54, 0xa9, 0xeb, 0x92, 0x46, 0x7e, 0xcb, + 0x90, 0x14, 0xcf, 0x1f, 0x3f, 0xdc, 0x5c, 0x85, 0x65, 0xe2, 0x93, 0xfa, 0x4d, 0x28, 0xee, 0x59, + 0x81, 0x35, 0x36, 0xec, 0x43, 0xa1, 0x41, 0x7e, 0xe2, 0x87, 0x92, 0x1d, 0xe0, 0x4f, 0xfd, 0xcf, + 0xc3, 0xca, 0x73, 0x2b, 0x40, 0x9c, 0x80, 0x82, 0x67, 0x8d, 0x6d, 0x42, 0x96, 0x0c, 0xfa, 0x8d, + 0x2c, 0x20, 0x3c, 0x0f, 0x23, 0x7b, 0x2c, 0xd9, 0xbf, 0x4c, 0x21, 0xfc, 0xc8, 0xf5, 0x0f, 0xe4, + 0x52, 0x2f, 0x1a, 0x32, 0x25, 0x1e, 0xc0, 0xe5, 0x03, 0x7f, 0xea, 0x8d, 0x4c, 0xd9, 0xc0, 0x91, + 0x3f, 0xb6, 0x1c, 0x8f, 0x56, 0x7d, 0xd5, 0x58, 0x27, 0x14, 0x77, 0xce, 0x16, 0x21, 0xf4, 0x7f, + 0x34, 0x07, 0x2b, 0x4d, 0xdf, 0xc5, 0xcf, 0x5f, 0x83, 0xd5, 0xc0, 0x76, 0xcd, 0xa4, 0x7a, 0x2b, + 0x81, 0xed, 0xee, 0xf9, 0x21, 0x22, 0x86, 0x3e, 0x23, 0x98, 0x59, 0xad, 0x0c, 0x7d, 0x42, 0xa8, + 0x0a, 0xe7, 0x53, 0x15, 0xbe, 0x0e, 0xc5, 0xe8, 0xc0, 0x35, 0x09, 0x5e, 0x20, 0xf8, 0x6a, 0x74, + 0xe0, 0x76, 0x11, 0x75, 0x0d, 0x56, 0x47, 0x07, 0x8c, 0x59, 0x26, 0xcc, 0xca, 0xe8, 0x00, 0x11, + 0xfa, 0x57, 0x50, 0x32, 0xac, 0x53, 0x59, 0x8d, 0x2b, 0xb0, 0x82, 0x05, 0xc8, 0x9d, 0xb0, 0x60, + 0x2c, 0x47, 0x07, 0x6e, 0x7b, 0x84, 0x60, 0xac, 0x84, 0x33, 0xa2, 0x3a, 0x14, 0x8c, 0xe5, 0xa1, + 0xef, 0xb6, 0x47, 0xfa, 0x00, 0xa0, 0xe9, 0x07, 0xc1, 0x6f, 0xdc, 0x84, 0x0d, 0x58, 0x1e, 0xd9, + 0x93, 0xe8, 0x98, 0x39, 0xa6, 0xc1, 0x09, 0xfd, 0x3e, 0x14, 0x71, 0x3a, 0x76, 0x9c, 0x30, 0x12, + 0xb7, 0xa0, 0xe0, 0x3a, 0x61, 0x54, 0xcf, 0xdd, 0xc9, 0xcf, 0x4c, 0x56, 0x82, 0xeb, 0x77, 0xa0, + 0xb8, 0x6b, 0x9d, 0x3d, 0xc7, 0x91, 0xc6, 0xd2, 0x68, 0xc8, 0xe5, 0x10, 0xca, 0xf1, 0xaf, 0x00, + 0x0c, 0xac, 0xe0, 0xc8, 0x8e, 0x88, 0xc1, 0xff, 0x9f, 0x39, 0x28, 0xf7, 0xa7, 0x07, 0xdf, 0x4f, + 0xed, 0xe0, 0x1c, 0xeb, 0x7c, 0x0f, 0xf2, 0xd1, 0xf9, 0x84, 0x72, 0xd4, 0x1e, 0x5e, 0x95, 0xf3, + 0x37, 0xc1, 0x3f, 0xc0, 0x4c, 0x06, 0x92, 0x60, 0x23, 0x3c, 0x7f, 0x64, 0xab, 0x3e, 0x58, 0x36, + 0x56, 0x30, 0xd9, 0x1e, 0xa1, 0xe0, 0xe0, 0x4f, 0xe4, 0x28, 0x2c, 0xf9, 0x13, 0x71, 0x07, 0x96, + 0x87, 0xc7, 0x8e, 0x3b, 0xa2, 0x01, 0xc8, 0xd6, 0x99, 0x11, 0x38, 0x4a, 0x81, 0x7f, 0x6a, 0x86, + 0xce, 0xaf, 0x94, 0x20, 0xb0, 0x1a, 0xf8, 0xa7, 0x7d, 0xe7, 0x57, 0xb6, 0x3e, 0x90, 0xd2, 0x08, + 0xc0, 0x4a, 0xbf, 0xd9, 0xe8, 0x34, 0x0c, 0xed, 0x12, 0xfe, 0x6e, 0x7d, 0xd3, 0xee, 0x0f, 0xfa, + 0x5a, 0x4e, 0xd4, 0x00, 0xba, 0xbd, 0x81, 0x29, 0xd3, 0x4b, 0x62, 0x05, 0x96, 0xda, 0x5d, 0x2d, + 0x8f, 0x34, 0x08, 0x6f, 0x77, 0xb5, 0x82, 0x58, 0x85, 0x7c, 0xa3, 0xfb, 0xad, 0xb6, 0x4c, 0x3f, + 0x3a, 0x1d, 0x6d, 0x45, 0xff, 0x07, 0x4b, 0x50, 0xea, 0x1d, 0x7c, 0x67, 0x0f, 0x23, 0x6c, 0x33, + 0xce, 0x6a, 0x3b, 0x78, 0x69, 0x07, 0xd4, 0xec, 0xbc, 0x21, 0x53, 0xd8, 0x90, 0xd1, 0x01, 0x35, + 0x2e, 0x6f, 0x2c, 0x8d, 0x0e, 0x88, 0x6e, 0x78, 0x6c, 0x8f, 0x2d, 0x6a, 0x1c, 0xd2, 0x51, 0x0a, + 0x57, 0x91, 0x7f, 0xf0, 0x1d, 0x35, 0x2f, 0x6f, 0xe0, 0x4f, 0x71, 0x1b, 0xca, 0x5c, 0x46, 0x7a, + 0x7e, 0x01, 0x83, 0x66, 0x27, 0xdf, 0x4a, 0x7a, 0xf2, 0x51, 0x4e, 0x2a, 0x95, 0x91, 0x52, 0xca, + 0x61, 0x50, 0x57, 0xce, 0x68, 0xff, 0xe0, 0x3b, 0xc6, 0x16, 0x79, 0x46, 0xfb, 0x07, 0xdf, 0x11, + 0xea, 0x03, 0x58, 0x0f, 0xa7, 0x07, 0xe1, 0x30, 0x70, 0x26, 0x24, 0x1d, 0x10, 0x4d, 0x89, 0x68, + 0xb4, 0x34, 0x82, 0x88, 0xef, 0x41, 0x71, 0x32, 0x3d, 0x30, 0x1d, 0xef, 0xd0, 0xa7, 0xdd, 0xae, + 0xfc, 0xb0, 0xca, 0x03, 0xb3, 0x37, 0x3d, 0x68, 0x7b, 0x87, 0xbe, 0xb1, 0x3a, 0xe1, 0x1f, 0x42, + 0x87, 0xaa, 0xe7, 0x47, 0x26, 0x0a, 0x8d, 0xe6, 0xd8, 0x8e, 0x2c, 0x29, 0xdc, 0xa0, 0xe8, 0xd7, + 0xf1, 0x87, 0x27, 0xbb, 0x76, 0x64, 0x89, 0xfb, 0x50, 0x0c, 0x3d, 0x6b, 0x12, 0x1e, 0xfb, 0x2c, + 0xbf, 0x94, 0x1f, 0xd6, 0xe4, 0xdc, 0x91, 0x50, 0x23, 0xc6, 0xeb, 0xef, 0xc2, 0xaa, 0xfc, 0x06, + 0x0a, 0x66, 0x91, 0xed, 0x59, 0x5e, 0x64, 0xc6, 0xa2, 0x66, 0x91, 0x01, 0xed, 0x91, 0xfe, 0x37, + 0x72, 0xa0, 0xf5, 0x53, 0xd5, 0xa6, 0x0f, 0x2d, 0xe2, 0x4a, 0x6f, 0x02, 0x58, 0xc3, 0xa1, 0x3f, + 0xe5, 0x62, 0x78, 0x32, 0x96, 0x24, 0xa4, 0x3d, 0x4a, 0xf7, 0x75, 0x3e, 0xd3, 0xd7, 0x6f, 0x41, + 0x45, 0xe5, 0x4b, 0x31, 0x88, 0xb2, 0x84, 0xa9, 0xde, 0x0e, 0xa7, 0x19, 0x2e, 0xb1, 0x1a, 0x4e, + 0x39, 0xf7, 0x55, 0x58, 0x21, 0xb9, 0x34, 0x54, 0x23, 0xc8, 0x29, 0xfd, 0xef, 0xe4, 0xa0, 0xda, + 0xf6, 0x46, 0xf6, 0x59, 0x7f, 0x68, 0x79, 0xaa, 0x03, 0x9d, 0xd0, 0x74, 0x10, 0x66, 0x86, 0x43, + 0xcb, 0x93, 0xf2, 0x53, 0xd9, 0x09, 0x63, 0x3a, 0x6c, 0x03, 0x13, 0xd0, 0xa7, 0x96, 0xa8, 0xc4, + 0x12, 0x41, 0xe8, 0x63, 0xef, 0xc2, 0xda, 0x81, 0xed, 0xfa, 0xde, 0x91, 0x19, 0xf9, 0x26, 0xcb, + 0xc6, 0xdc, 0x96, 0x2a, 0x83, 0x07, 0xfe, 0x80, 0x64, 0xe4, 0x0d, 0x58, 0x9e, 0x58, 0x41, 0x14, + 0xd6, 0x0b, 0x77, 0xf2, 0xb8, 0xe4, 0x29, 0x81, 0xdd, 0xec, 0x84, 0xe6, 0xd4, 0x73, 0xbe, 0x9f, + 0x72, 0x33, 0x8a, 0x46, 0xd1, 0x09, 0xf7, 0x29, 0x2d, 0xee, 0x81, 0xc6, 0x5f, 0xa6, 0x62, 0xd3, + 0x73, 0xb2, 0x46, 0x70, 0x2a, 0x98, 0x18, 0xe3, 0x7f, 0x9d, 0x87, 0xe2, 0xf6, 0xd4, 0x1b, 0xe2, + 0x60, 0x88, 0xb7, 0xa1, 0x70, 0x38, 0xf5, 0x86, 0xd4, 0x96, 0x58, 0xda, 0x88, 0xd7, 0x94, 0x41, + 0x48, 0xe4, 0x56, 0x56, 0x70, 0x84, 0x5c, 0x6e, 0x8e, 0x5b, 0x21, 0x9c, 0x46, 0xee, 0xe8, 0x88, + 0x44, 0x5f, 0xe7, 0x88, 0x5a, 0x54, 0x31, 0x4a, 0xd6, 0xd1, 0x51, 0x93, 0x00, 0xa2, 0x01, 0x6b, + 0x09, 0x9a, 0xe5, 0xd3, 0x02, 0x31, 0xa6, 0xeb, 0x5c, 0x52, 0xe3, 0xe8, 0x28, 0xb0, 0x8f, 0xac, + 0xc8, 0x66, 0x7a, 0xe2, 0x4d, 0xd5, 0x38, 0x3b, 0xf1, 0x8d, 0x4f, 0x60, 0x23, 0x3c, 0xf7, 0x22, + 0xeb, 0xcc, 0xb4, 0xcf, 0x26, 0xae, 0x33, 0x74, 0x22, 0x73, 0x68, 0x85, 0x91, 0xec, 0x05, 0xc1, + 0xb8, 0x96, 0x44, 0x35, 0xad, 0x30, 0x12, 0x9f, 0x41, 0x25, 0xf0, 0xa7, 0x91, 0xe3, 0xd9, 0xe6, + 0xd0, 0x72, 0x59, 0xde, 0x2c, 0x3f, 0x5c, 0xe7, 0x2f, 0x1a, 0x8c, 0x69, 0x5a, 0xae, 0x6b, 0x94, + 0x83, 0x24, 0xa1, 0xff, 0x9b, 0x39, 0xee, 0x9b, 0x6d, 0xd7, 0x3a, 0x12, 0x45, 0x28, 0x74, 0x7b, + 0xdd, 0x96, 0x76, 0x49, 0x54, 0xa0, 0xd8, 0xee, 0x0e, 0x5a, 0x46, 0xb7, 0xd1, 0xd1, 0x72, 0xc4, + 0xc4, 0x06, 0x8d, 0xcd, 0x4e, 0x4b, 0x5b, 0x42, 0xcc, 0xf3, 0x5e, 0xa7, 0x31, 0x68, 0x77, 0x5a, + 0x5a, 0x81, 0x31, 0x46, 0xbb, 0x39, 0xd0, 0x8a, 0x42, 0x83, 0xca, 0x9e, 0xd1, 0xdb, 0xda, 0x6f, + 0xb6, 0xcc, 0xee, 0x7e, 0xa7, 0xa3, 0x69, 0xe2, 0x32, 0xac, 0xc5, 0x90, 0x1e, 0x03, 0xef, 0x60, + 0x96, 0xe7, 0x0d, 0xa3, 0x61, 0x3c, 0xd1, 0x7e, 0x2e, 0x8a, 0x90, 0x6f, 0x3c, 0x79, 0xa2, 0xfd, + 0x1a, 0xf9, 0x61, 0xe9, 0x45, 0xbb, 0x6b, 0x3e, 0x6f, 0x74, 0xf6, 0x5b, 0xda, 0xaf, 0x97, 0x54, + 0xba, 0x67, 0x6c, 0xb5, 0x0c, 0xed, 0xd7, 0x05, 0xb1, 0x0e, 0x95, 0x5f, 0xf6, 0xba, 0xad, 0xdd, + 0xc6, 0xde, 0x1e, 0x55, 0xe4, 0xd7, 0x45, 0xfd, 0x3f, 0x59, 0x86, 0x6b, 0x7b, 0x81, 0x3d, 0xb1, + 0x02, 0x7b, 0xd4, 0x9d, 0x8e, 0xed, 0xc0, 0x19, 0xe2, 0x52, 0x1b, 0x59, 0x91, 0x25, 0x6e, 0x40, + 0xf1, 0xd0, 0x72, 0xdd, 0x03, 0x6b, 0x78, 0x22, 0x67, 0x6d, 0x9c, 0x66, 0xad, 0x2a, 0xb0, 0xc6, + 0xa9, 0x7d, 0xac, 0x48, 0x00, 0xdc, 0xc9, 0xde, 0x83, 0x35, 0x45, 0xa8, 0xc4, 0x1a, 0x16, 0x0d, + 0x6a, 0x0a, 0x2c, 0x05, 0x9b, 0xcf, 0xe1, 0xda, 0x0c, 0xa1, 0xa9, 0xb6, 0x15, 0xd6, 0x14, 0x37, + 0xb2, 0x19, 0xba, 0xbc, 0xc9, 0x2c, 0xc8, 0xa6, 0xb6, 0xd4, 0xe5, 0x45, 0xd9, 0x9a, 0xbc, 0xc1, + 0x7e, 0x01, 0xd7, 0x26, 0x81, 0xff, 0xd2, 0x41, 0xed, 0x88, 0x44, 0xa8, 0x70, 0xea, 0xca, 0x19, + 0xb1, 0x42, 0xd5, 0xbb, 0x92, 0x42, 0x1b, 0x84, 0xa5, 0x49, 0xb1, 0x38, 0xdf, 0xc4, 0xb6, 0x03, + 0x62, 0xd1, 0x8b, 0xf2, 0xed, 0xd9, 0x76, 0x20, 0xb6, 0xe0, 0xf6, 0x05, 0xf9, 0x68, 0x3a, 0x63, + 0x2b, 0x8b, 0x54, 0xdd, 0x37, 0x16, 0xe6, 0xc7, 0x29, 0xdc, 0x1e, 0x89, 0x06, 0xbc, 0x79, 0x51, + 0x29, 0xac, 0x53, 0x97, 0xa8, 0x8c, 0x1b, 0x0b, 0xcb, 0x78, 0x41, 0x8a, 0xf6, 0x2b, 0x8a, 0x60, + 0x05, 0x1c, 0x5e, 0x51, 0x44, 0x9f, 0xb4, 0xf2, 0x9f, 0xc2, 0x46, 0x46, 0x8c, 0x53, 0xe3, 0x5a, + 0x9e, 0xdb, 0xd6, 0x45, 0x98, 0x12, 0xea, 0xe4, 0x38, 0x3f, 0x80, 0xcb, 0xce, 0x21, 0xea, 0x8b, + 0xe6, 0xd0, 0x1f, 0x8f, 0x51, 0x77, 0x25, 0xd1, 0x84, 0x95, 0xdd, 0x75, 0x46, 0x35, 0x09, 0xc3, + 0xc2, 0xcb, 0x67, 0x70, 0x75, 0x12, 0xf8, 0xc8, 0x4e, 0xec, 0x51, 0x36, 0x4b, 0x95, 0xb2, 0x6c, + 0xc4, 0xd8, 0x54, 0x2e, 0xfd, 0x5f, 0x5c, 0x81, 0x02, 0x56, 0x41, 0xe8, 0x89, 0x1c, 0x13, 0xd7, + 0x0d, 0x7b, 0x73, 0xb3, 0xf0, 0xb7, 0xfe, 0xde, 0xed, 0x4b, 0x2c, 0xc1, 0xbc, 0x05, 0x79, 0xd7, + 0x89, 0x68, 0xea, 0xc6, 0xbb, 0x9f, 0x94, 0x9c, 0x77, 0x2e, 0x19, 0x88, 0x13, 0xb7, 0x20, 0xc7, + 0xa2, 0x4c, 0xbc, 0xa1, 0x29, 0xd9, 0x79, 0xe7, 0x92, 0x91, 0x9b, 0x88, 0x9b, 0x90, 0x7b, 0x29, + 0xe5, 0x9a, 0x0a, 0xe3, 0x59, 0x7a, 0x46, 0xec, 0x4b, 0x71, 0x07, 0xf2, 0x43, 0x9f, 0x55, 0xd9, + 0x18, 0xcf, 0xb2, 0x21, 0x96, 0x3f, 0xf4, 0x5d, 0xf1, 0x36, 0xe4, 0x03, 0xeb, 0x54, 0xf2, 0x18, + 0xc9, 0x44, 0x63, 0xe1, 0x13, 0x89, 0x02, 0xeb, 0x14, 0x2b, 0x71, 0x48, 0xd3, 0x2c, 0xae, 0x84, + 0xe2, 0xc2, 0xf8, 0x99, 0x43, 0x71, 0x07, 0x72, 0xa7, 0x34, 0x8d, 0x62, 0xed, 0xed, 0x85, 0xe3, + 0x8d, 0xfc, 0xd3, 0xfe, 0xc4, 0x1e, 0x22, 0xc5, 0xa9, 0x78, 0x07, 0xf2, 0xe1, 0xf4, 0x80, 0xa6, + 0x49, 0xcc, 0xca, 0x52, 0x52, 0x1d, 0x7e, 0x28, 0x9c, 0x1e, 0x88, 0x77, 0xa1, 0x30, 0xf4, 0x83, + 0x40, 0xca, 0x03, 0x9a, 0xaa, 0xb0, 0x12, 0x68, 0x51, 0x9b, 0x45, 0x3c, 0x7e, 0x30, 0x92, 0xc3, + 0x2e, 0x89, 0x12, 0x89, 0x12, 0x3f, 0x18, 0x89, 0xbb, 0x52, 0x4c, 0xcd, 0xc8, 0x02, 0x4a, 0x88, + 0xc5, 0x72, 0x10, 0x8b, 0x83, 0x34, 0xb6, 0xce, 0x68, 0x40, 0x63, 0x22, 0x25, 0xbd, 0x62, 0x9d, + 0xc6, 0xd6, 0x99, 0xb8, 0x0b, 0xf9, 0x97, 0xf6, 0x90, 0xb4, 0xe6, 0xf8, 0x6b, 0x72, 0x90, 0x9e, + 0x53, 0xf3, 0x10, 0x4d, 0xbb, 0x91, 0xef, 0x8e, 0x48, 0x81, 0x8e, 0xc7, 0x72, 0xdb, 0x77, 0x47, + 0xcf, 0x69, 0x2c, 0x09, 0x29, 0x1e, 0x41, 0x69, 0x64, 0x4f, 0x6c, 0x6f, 0x64, 0x7b, 0x11, 0xa9, + 0x86, 0xe5, 0x87, 0x97, 0x99, 0x72, 0x4b, 0x81, 0xb1, 0x8a, 0xa8, 0x68, 0xc6, 0x74, 0xe2, 0x03, + 0x28, 0x84, 0xae, 0x1f, 0x91, 0xc6, 0x58, 0x7e, 0x78, 0x25, 0xe9, 0x13, 0x9b, 0x4d, 0x2d, 0x7d, + 0xd7, 0xa7, 0x06, 0x21, 0x11, 0xaa, 0x05, 0xd6, 0xf4, 0x0c, 0x57, 0xb5, 0xc6, 0x02, 0xbc, 0x35, + 0x3d, 0x6b, 0x8f, 0x50, 0x40, 0xf4, 0x46, 0x2f, 0x49, 0x31, 0xcf, 0x19, 0xf8, 0x53, 0xdc, 0x41, + 0x01, 0xd1, 0xb5, 0x87, 0x91, 0xf3, 0xd2, 0x89, 0xce, 0x49, 0xf5, 0xce, 0x19, 0x69, 0x90, 0xd8, + 0x01, 0x6d, 0x22, 0x99, 0xb2, 0xe9, 0x31, 0x57, 0x26, 0x45, 0xbb, 0xfc, 0xf0, 0x4d, 0x39, 0x11, + 0x17, 0xb3, 0x6c, 0x63, 0x6d, 0x92, 0x45, 0x6c, 0xae, 0x40, 0xc1, 0x3e, 0x9b, 0x04, 0x4f, 0x0b, + 0xc5, 0x0d, 0xad, 0xae, 0x3f, 0x85, 0xb5, 0x99, 0xda, 0xe3, 0x2e, 0x3c, 0x09, 0xfc, 0x23, 0x64, + 0xe5, 0x52, 0x0c, 0xab, 0x1a, 0x25, 0x09, 0x69, 0x8f, 0x44, 0x1d, 0x56, 0xfd, 0x60, 0xe4, 0x78, + 0xd2, 0xc2, 0x53, 0x35, 0x54, 0x52, 0xff, 0x8b, 0x4b, 0x50, 0xcd, 0x74, 0xdd, 0xeb, 0x8a, 0x7a, + 0x1b, 0xaa, 0xfe, 0x70, 0x38, 0x0d, 0x02, 0xdb, 0x1b, 0xc6, 0x9a, 0x43, 0xd5, 0xa8, 0x24, 0xc0, + 0x36, 0x69, 0x03, 0x61, 0x64, 0x1d, 0x11, 0x3e, 0xcf, 0x1f, 0xa4, 0x74, 0x7b, 0x24, 0x3e, 0x41, + 0x8d, 0x6a, 0x34, 0x1d, 0xda, 0x81, 0x14, 0x04, 0x2e, 0xd2, 0x50, 0x14, 0x99, 0xd0, 0x61, 0xc5, + 0xf1, 0x26, 0xd3, 0x08, 0xb7, 0x85, 0x59, 0x19, 0x44, 0x62, 0x50, 0xff, 0x77, 0x8f, 0x51, 0x8c, + 0x9b, 0x25, 0x40, 0xb0, 0xb8, 0x0f, 0x30, 0xf4, 0xc7, 0x13, 0x2b, 0x70, 0x42, 0xdf, 0x93, 0xcb, + 0x30, 0x4d, 0x94, 0xc2, 0xea, 0xff, 0x5c, 0x0e, 0x44, 0xaa, 0x77, 0xf7, 0xb8, 0xe1, 0xb8, 0x53, + 0x06, 0xbe, 0x1f, 0xd1, 0xc6, 0xa6, 0xc4, 0x5c, 0x04, 0xe0, 0x5e, 0x26, 0x3e, 0x85, 0x32, 0xd5, + 0x83, 0x36, 0x84, 0x19, 0x51, 0x29, 0xc5, 0xb1, 0x80, 0x88, 0x10, 0x10, 0x8a, 0x47, 0x50, 0xf1, + 0xa7, 0x51, 0x92, 0x27, 0x7f, 0x41, 0x9e, 0x32, 0x53, 0x51, 0x26, 0xfd, 0xff, 0xc8, 0x81, 0x96, + 0x1e, 0x79, 0xec, 0x52, 0x1c, 0x2f, 0xff, 0xd4, 0x43, 0x3d, 0x25, 0xa9, 0x5a, 0x89, 0x20, 0x54, + 0xb7, 0x8f, 0xa1, 0x70, 0xe2, 0x78, 0x3c, 0x4c, 0xb5, 0x87, 0x6f, 0xcc, 0x4f, 0x7e, 0x2c, 0xe4, + 0xc1, 0x33, 0xc7, 0x1b, 0x19, 0x44, 0x48, 0xc6, 0x92, 0x31, 0x8e, 0x9d, 0xb2, 0x4c, 0xf2, 0x00, + 0x56, 0x08, 0xa8, 0xac, 0x92, 0xc7, 0x50, 0xc0, 0x2c, 0xa2, 0x04, 0xcb, 0xed, 0xee, 0xde, 0xfe, + 0x40, 0xbb, 0x24, 0xaa, 0x50, 0x7a, 0xda, 0x6b, 0x77, 0xcd, 0xbd, 0x46, 0xdb, 0xd0, 0x72, 0x88, + 0x79, 0x62, 0xf4, 0xf6, 0xf7, 0xb4, 0x25, 0x94, 0x86, 0x5e, 0xb4, 0xbb, 0x5b, 0xbd, 0x17, 0x66, + 0xbf, 0x35, 0xd8, 0xdf, 0xd3, 0xf2, 0xa8, 0xf2, 0x49, 0x88, 0xd1, 0x7b, 0xa1, 0x15, 0x30, 0xdd, + 0xe8, 0xf7, 0xdb, 0x4f, 0xba, 0xbb, 0xad, 0xee, 0x40, 0x5b, 0xc6, 0xcc, 0x46, 0x6f, 0x7f, 0xd0, + 0xd2, 0x56, 0xf4, 0xff, 0x31, 0x97, 0x9d, 0xed, 0x13, 0x7b, 0x88, 0xd3, 0x59, 0x55, 0x8e, 0xe7, + 0xa7, 0x4a, 0xa2, 0x24, 0x4c, 0xfb, 0x9a, 0xec, 0xdb, 0x30, 0xb2, 0x27, 0x52, 0xae, 0xa9, 0x21, + 0xbc, 0x47, 0xe0, 0x7e, 0x64, 0x4f, 0x48, 0x4b, 0x8b, 0xec, 0x89, 0x49, 0x3d, 0xc5, 0xfd, 0x5f, + 0x35, 0x00, 0x41, 0x3d, 0x82, 0x88, 0xcf, 0xa0, 0x28, 0x67, 0x3d, 0x8b, 0xe2, 0xe5, 0x87, 0xf5, + 0xb9, 0xce, 0x93, 0xb3, 0xc3, 0x88, 0x29, 0xc5, 0x03, 0x58, 0xa1, 0x99, 0xae, 0x26, 0xeb, 0xd5, + 0xc5, 0x1d, 0x6e, 0x48, 0x2a, 0x7d, 0x07, 0x56, 0x25, 0x8f, 0x9b, 0xb3, 0xd6, 0x5f, 0x87, 0xa2, + 0x13, 0xa2, 0xe4, 0x1c, 0x46, 0xd2, 0x56, 0xb3, 0xea, 0x84, 0x4d, 0x4c, 0xa2, 0x0a, 0x85, 0x8c, + 0x42, 0x8a, 0xdb, 0xf4, 0x5b, 0xff, 0x77, 0x73, 0x00, 0x09, 0x57, 0x45, 0x86, 0xe5, 0xda, 0x9e, + 0xb2, 0x0b, 0xb9, 0xb6, 0x17, 0x67, 0x5a, 0x4a, 0x32, 0xcd, 0x5b, 0xc6, 0xf2, 0x0b, 0x2c, 0x63, + 0x73, 0xd6, 0xad, 0xc2, 0x6f, 0x60, 0xdd, 0x5a, 0x7e, 0x8d, 0x75, 0x4b, 0xbf, 0x8e, 0xac, 0x5d, + 0x1a, 0x37, 0x45, 0x05, 0x72, 0x96, 0x54, 0xe5, 0x73, 0x96, 0x7e, 0x0f, 0x20, 0x31, 0x5f, 0x66, + 0x71, 0x98, 0x52, 0x0a, 0x7e, 0xee, 0x40, 0xff, 0x29, 0x54, 0xa4, 0xc8, 0xe7, 0xbb, 0x5b, 0xf6, + 0xa1, 0xf8, 0x10, 0x20, 0x4e, 0x87, 0xd2, 0xe2, 0x92, 0xec, 0xe2, 0x5b, 0xf6, 0xa1, 0x91, 0xc2, + 0xeb, 0xff, 0xdb, 0x32, 0xd9, 0xae, 0xb6, 0xd8, 0x68, 0x24, 0xad, 0x43, 0xb9, 0x94, 0x75, 0x28, + 0xd6, 0x5d, 0x97, 0xb2, 0x16, 0xb5, 0x63, 0x67, 0x34, 0xb2, 0x3d, 0x65, 0x39, 0xe3, 0x14, 0x6e, + 0x7b, 0x96, 0x7b, 0x24, 0xb9, 0x9c, 0x50, 0x1f, 0x1d, 0x4f, 0x02, 0x3b, 0x0c, 0xd9, 0x06, 0x63, + 0xb9, 0x47, 0x4a, 0xca, 0x59, 0x7e, 0x95, 0x94, 0x73, 0x1d, 0x8a, 0xa8, 0xbe, 0x93, 0xe1, 0x9e, + 0x65, 0xdc, 0x55, 0x79, 0x68, 0x23, 0xde, 0x83, 0x55, 0x69, 0x72, 0x95, 0x7c, 0xad, 0xaa, 0xb6, + 0x43, 0x02, 0x1a, 0x0a, 0x4b, 0x47, 0x2b, 0xfe, 0x78, 0x8c, 0xfb, 0xa6, 0xb4, 0x39, 0xc8, 0xa4, + 0xf8, 0x00, 0x4a, 0xbe, 0x67, 0xb2, 0x5d, 0x56, 0xca, 0x17, 0x72, 0x23, 0xef, 0x79, 0xfb, 0x04, + 0x35, 0x8a, 0xbe, 0xfc, 0x85, 0x55, 0x71, 0xfd, 0x53, 0x73, 0x68, 0x05, 0x23, 0x92, 0x31, 0x8a, + 0xc6, 0xaa, 0xeb, 0x9f, 0x36, 0xad, 0x60, 0xc4, 0x36, 0x98, 0xef, 0xbd, 0xe9, 0x98, 0xe4, 0x8a, + 0xaa, 0x21, 0x53, 0xe2, 0x26, 0x94, 0x86, 0xee, 0x34, 0x8c, 0xec, 0x60, 0xf3, 0x5c, 0x0a, 0x8b, + 0x09, 0x00, 0xeb, 0x35, 0x09, 0x9c, 0xb1, 0x15, 0x9c, 0x4b, 0xa9, 0x50, 0x25, 0x49, 0x11, 0x3e, + 0x71, 0x46, 0x67, 0x6c, 0x6e, 0x37, 0x38, 0x81, 0xf4, 0xc7, 0x74, 0x18, 0x12, 0x92, 0xa4, 0x50, + 0x34, 0x54, 0x92, 0xc6, 0x81, 0x7e, 0xd2, 0xce, 0x5d, 0x32, 0x64, 0x2a, 0x63, 0x40, 0x5c, 0xbf, + 0xd0, 0x80, 0x28, 0x66, 0x6d, 0x38, 0x7e, 0xe0, 0x1c, 0x39, 0xd2, 0x02, 0x73, 0x99, 0x6d, 0x38, + 0x0c, 0x22, 0x82, 0x2f, 0xa1, 0x7a, 0x64, 0x7b, 0x76, 0x60, 0xb1, 0x6c, 0xcb, 0x06, 0xf2, 0xb2, + 0x1a, 0xe6, 0x27, 0x0a, 0x85, 0x52, 0x57, 0xe5, 0x28, 0x95, 0xc2, 0x5a, 0x4a, 0x2d, 0xfe, 0x0a, + 0xcf, 0x16, 0x4e, 0x89, 0x77, 0x61, 0x4d, 0x7e, 0x31, 0xae, 0xec, 0x55, 0x36, 0x0f, 0x30, 0x78, + 0x20, 0xab, 0xbc, 0x05, 0x42, 0xa9, 0x3c, 0xbe, 0x3b, 0x1d, 0x7b, 0x26, 0x71, 0xf7, 0x6b, 0xe9, + 0xad, 0x34, 0x9e, 0xd1, 0xd3, 0xb1, 0x47, 0x8c, 0x5d, 0x0b, 0x66, 0x20, 0xfa, 0xf7, 0xb0, 0x2a, + 0x67, 0x08, 0x2a, 0xf8, 0x28, 0x5b, 0x64, 0xe5, 0x6c, 0x56, 0xf0, 0x11, 0x4e, 0x1b, 0x3e, 0x57, + 0x8c, 0xd7, 0xbb, 0x9c, 0xfb, 0x15, 0x06, 0xb2, 0xed, 0x57, 0xbc, 0x05, 0x15, 0x52, 0x0c, 0x2c, + 0x79, 0xee, 0x96, 0x97, 0xf6, 0xa5, 0xa9, 0xeb, 0x36, 0x18, 0xa4, 0xf7, 0xa0, 0xa8, 0xe6, 0xd3, + 0x9f, 0xca, 0x37, 0xf5, 0x09, 0x54, 0xd2, 0xfd, 0xfc, 0xa7, 0xd3, 0x10, 0xb6, 0xb3, 0x84, 0x91, + 0x1f, 0xc4, 0xcc, 0xb0, 0xe8, 0x84, 0x7d, 0x4a, 0xeb, 0xbf, 0xbf, 0x04, 0x65, 0xb2, 0xf7, 0xf4, + 0xc8, 0x9a, 0x25, 0x3e, 0x04, 0x31, 0x0c, 0x6c, 0x2b, 0xb2, 0x4d, 0xfb, 0x2c, 0x0a, 0x2c, 0x69, + 0xd5, 0x61, 0x25, 0x5b, 0x63, 0x4c, 0x0b, 0x11, 0x6c, 0xd8, 0xb9, 0x0d, 0xe5, 0x89, 0x15, 0x84, + 0xca, 0xa2, 0xc8, 0x5f, 0x07, 0x06, 0x49, 0x7b, 0x9e, 0xe6, 0x91, 0xdc, 0x15, 0xf9, 0x27, 0xb6, + 0xc7, 0xb6, 0x54, 0xb6, 0x22, 0xd7, 0x08, 0x3e, 0x40, 0x70, 0xdf, 0xf9, 0x15, 0xea, 0x71, 0x80, + 0x2a, 0x9e, 0xec, 0x6c, 0xe6, 0x30, 0x37, 0xb9, 0xc1, 0xa9, 0xfa, 0x3d, 0x78, 0x1e, 0xd3, 0x18, + 0x29, 0x7a, 0xfd, 0x97, 0x00, 0x09, 0x46, 0xdc, 0x80, 0xab, 0xcf, 0xdb, 0xfd, 0xf6, 0x66, 0xbb, + 0xd3, 0x1e, 0x7c, 0x6b, 0xee, 0x77, 0xfb, 0x7b, 0xad, 0x66, 0x7b, 0xbb, 0xdd, 0xda, 0xd2, 0x2e, + 0x89, 0xab, 0x20, 0x52, 0x38, 0xfa, 0xd9, 0x69, 0x69, 0x39, 0x51, 0x87, 0x8d, 0x14, 0xbc, 0xdd, + 0x55, 0x98, 0x25, 0xfd, 0x7f, 0xc8, 0x41, 0x75, 0x8f, 0x17, 0xf0, 0x33, 0xfb, 0x7c, 0x8b, 0x0f, + 0x21, 0x86, 0x8a, 0xf9, 0x16, 0x0c, 0xfa, 0x2d, 0x6e, 0x41, 0x79, 0x72, 0x62, 0x9f, 0x9b, 0x19, + 0x03, 0x7c, 0x09, 0x41, 0x4d, 0x62, 0xb3, 0xef, 0xc3, 0x8a, 0x4f, 0x4d, 0x90, 0x8a, 0xdb, 0xfa, + 0x5c, 0xdb, 0x0c, 0x49, 0x20, 0x74, 0xa8, 0xc6, 0x45, 0xa5, 0x4d, 0x80, 0xb2, 0x30, 0xea, 0xd8, + 0x0d, 0x58, 0x46, 0x14, 0xef, 0xc9, 0x25, 0x83, 0x13, 0xe2, 0x13, 0xa8, 0xa2, 0xdc, 0x67, 0xaa, + 0xec, 0x52, 0x85, 0xcb, 0x6e, 0x0f, 0x65, 0x24, 0xd9, 0xe3, 0xb2, 0xf4, 0xff, 0x27, 0x0f, 0x45, + 0xaa, 0x83, 0xdc, 0x21, 0x9c, 0xd1, 0x99, 0xda, 0x21, 0x4a, 0xc6, 0xb2, 0x33, 0x42, 0x45, 0xe1, + 0x35, 0x56, 0xc0, 0xd8, 0xba, 0x97, 0x4f, 0x5b, 0xf7, 0x12, 0xa6, 0x50, 0xc8, 0x30, 0x85, 0x45, + 0x86, 0xbd, 0xe5, 0x45, 0x86, 0x3d, 0x9c, 0x5c, 0x4c, 0x63, 0x9f, 0x39, 0xb1, 0x25, 0x04, 0x08, + 0xd4, 0x42, 0x48, 0x9a, 0xff, 0xaf, 0x66, 0xf9, 0x3f, 0x4a, 0x53, 0x38, 0x1d, 0x5c, 0xb6, 0x46, + 0x17, 0x0d, 0x95, 0x4c, 0x0d, 0x43, 0xe9, 0x75, 0xc3, 0x10, 0x37, 0xdb, 0x72, 0x8f, 0xd8, 0x1a, + 0xad, 0x9a, 0xdd, 0x70, 0x8f, 0x7c, 0xf1, 0x29, 0x5c, 0x49, 0xd0, 0xb2, 0x35, 0x64, 0x0c, 0xa4, + 0xf3, 0x58, 0x43, 0xc4, 0x94, 0xd4, 0x22, 0x32, 0xfb, 0xdd, 0x87, 0xf5, 0x54, 0x16, 0xb2, 0x4a, + 0x85, 0xb4, 0x7d, 0x94, 0x8c, 0xb5, 0x98, 0x9c, 0x54, 0xf9, 0x50, 0xbc, 0x8f, 0xfd, 0x34, 0x74, + 0xa7, 0x23, 0x66, 0xc6, 0xd3, 0xb1, 0x17, 0xd6, 0xab, 0xd4, 0xc1, 0x6b, 0x0a, 0xce, 0xcc, 0x8f, + 0xec, 0x95, 0x38, 0xde, 0x87, 0x7e, 0x30, 0xb6, 0x22, 0xda, 0x42, 0xaa, 0x46, 0xe9, 0xc4, 0x3e, + 0xdf, 0x26, 0xc0, 0xd3, 0x42, 0xb1, 0xa6, 0xad, 0x19, 0xb5, 0x64, 0xb5, 0x98, 0xa1, 0x1d, 0xe9, + 0xbf, 0xb7, 0x0c, 0xd5, 0x6d, 0x3f, 0xb0, 0x9d, 0x23, 0x2f, 0x99, 0xd5, 0x73, 0x46, 0x6c, 0x35, + 0xd3, 0x97, 0x52, 0x33, 0xfd, 0x36, 0x94, 0x0f, 0x39, 0x23, 0xf2, 0x75, 0x9a, 0xce, 0x05, 0x03, + 0x24, 0x68, 0x70, 0xe0, 0x22, 0xe7, 0x54, 0x04, 0x94, 0xb9, 0x40, 0x99, 0x55, 0x26, 0x14, 0x4b, + 0xc4, 0xd7, 0xb4, 0x41, 0x8f, 0x6c, 0xd7, 0x8e, 0x78, 0xf8, 0x6b, 0x4a, 0x81, 0xcc, 0xd4, 0xe9, + 0x81, 0x61, 0x1f, 0x36, 0xc8, 0xa6, 0x80, 0xfb, 0xf5, 0x16, 0x91, 0xcb, 0xbc, 0x72, 0x73, 0x5f, + 0xf9, 0x81, 0x79, 0x25, 0x97, 0x7e, 0x08, 0x57, 0x02, 0xfb, 0xd0, 0x26, 0xa5, 0x6e, 0x64, 0xa6, + 0x66, 0x35, 0x4f, 0xa0, 0xcb, 0x09, 0xb2, 0x1d, 0xcf, 0xef, 0x5d, 0xd0, 0xe2, 0xba, 0x9a, 0xcc, + 0x59, 0x69, 0x56, 0xd5, 0x1e, 0xbe, 0xfd, 0xca, 0xcf, 0xf6, 0x88, 0xd4, 0xa8, 0xa9, 0x8a, 0x73, + 0x5a, 0x16, 0xc7, 0xd5, 0x57, 0xc5, 0x95, 0x7e, 0x54, 0x71, 0xdc, 0x16, 0x4e, 0xeb, 0x03, 0x28, + 0xc5, 0x24, 0xa2, 0x02, 0x45, 0xa3, 0x25, 0x4d, 0xb6, 0x97, 0x44, 0x19, 0x56, 0x9b, 0x8d, 0x7e, + 0xb3, 0xb1, 0x85, 0xfc, 0xad, 0x02, 0xc5, 0x7e, 0x6b, 0xc0, 0x66, 0xda, 0x25, 0xb1, 0x06, 0x65, + 0x4c, 0x6d, 0xb5, 0xb6, 0x1b, 0xfb, 0x9d, 0x81, 0x96, 0x47, 0x55, 0xa7, 0xdb, 0x33, 0x1b, 0xcd, + 0x41, 0xbb, 0xd7, 0xd5, 0x0a, 0xba, 0x0b, 0x6b, 0x33, 0x1f, 0x46, 0xa6, 0xca, 0x68, 0xb3, 0x67, + 0xb4, 0x9f, 0xb4, 0xbb, 0x66, 0xeb, 0x9b, 0xbd, 0x4e, 0xbb, 0xd9, 0xc6, 0x2f, 0x5d, 0x87, 0x2b, + 0x59, 0x9c, 0x2a, 0x38, 0x27, 0x74, 0xb8, 0x95, 0x45, 0x75, 0x5a, 0x4f, 0x1a, 0xcd, 0x6f, 0xcd, + 0xc6, 0xee, 0x66, 0xfb, 0xc9, 0x7e, 0x6f, 0xbf, 0xaf, 0x2d, 0xe9, 0x26, 0x14, 0x9b, 0xc7, 0xf6, + 0xf0, 0xe4, 0xa2, 0x59, 0x48, 0x67, 0x75, 0xf6, 0xf0, 0x44, 0x1a, 0xc5, 0x66, 0xce, 0xea, 0xec, + 0xe1, 0x09, 0x69, 0x8c, 0x72, 0x23, 0xfc, 0xde, 0x95, 0x87, 0x10, 0x25, 0xb9, 0x0b, 0x7e, 0xef, + 0xea, 0x2d, 0x28, 0xed, 0x59, 0x41, 0xe4, 0x50, 0x27, 0x3d, 0x86, 0x6a, 0x9c, 0xd8, 0xb2, 0x0f, + 0x95, 0x0c, 0x2d, 0x62, 0x4b, 0x5a, 0x8c, 0x32, 0xb2, 0x84, 0xfa, 0x87, 0x50, 0x49, 0x03, 0x50, + 0x45, 0x1f, 0xd9, 0x87, 0x0b, 0x76, 0x67, 0x04, 0xeb, 0xcf, 0xa1, 0xd2, 0x54, 0x32, 0xe1, 0x45, + 0x2d, 0x7b, 0x08, 0x35, 0x62, 0xd8, 0xc3, 0x03, 0xc5, 0xb1, 0x97, 0x16, 0x70, 0xec, 0x0a, 0xd2, + 0x34, 0x0f, 0x24, 0xcb, 0xfe, 0x1c, 0xca, 0x7b, 0x81, 0x3f, 0xb1, 0x83, 0x88, 0x8a, 0xd5, 0x20, + 0x7f, 0x62, 0x9f, 0xcb, 0x52, 0xf1, 0x67, 0x72, 0xc2, 0xba, 0x94, 0x3e, 0x61, 0x7d, 0x08, 0x45, + 0x95, 0xed, 0x07, 0xe7, 0xf9, 0x19, 0xee, 0x7c, 0x94, 0xc7, 0xb1, 0x43, 0xfc, 0xd8, 0x03, 0xb2, + 0xa4, 0x48, 0x80, 0xec, 0x38, 0x65, 0x82, 0x94, 0x85, 0x1b, 0x29, 0x0a, 0xfd, 0x4d, 0x58, 0x7d, + 0xee, 0xd8, 0xa7, 0xb2, 0xf9, 0x2f, 0x1d, 0xfb, 0x54, 0x35, 0x1f, 0x7f, 0xeb, 0x7f, 0xa9, 0x0c, + 0x45, 0x62, 0x8f, 0x5b, 0x17, 0x1f, 0x6a, 0xff, 0x18, 0xfd, 0xe4, 0x8e, 0x64, 0x57, 0x85, 0x05, + 0x5a, 0x11, 0x33, 0xaf, 0x37, 0x01, 0x52, 0xac, 0x9a, 0x37, 0x9e, 0x52, 0x14, 0x73, 0x68, 0x14, + 0xec, 0x49, 0xc8, 0xc1, 0x69, 0xc4, 0xe7, 0x4d, 0x09, 0x40, 0x3c, 0x60, 0xb1, 0x9b, 0x4e, 0x98, + 0x56, 0xd3, 0x96, 0x3a, 0x6a, 0x83, 0x32, 0x7f, 0x92, 0x2c, 0x8e, 0x89, 0xb4, 0x52, 0x5f, 0xcc, + 0x2a, 0xf5, 0xef, 0x41, 0x01, 0xf7, 0x68, 0x69, 0xae, 0xbc, 0xac, 0x7a, 0x30, 0x25, 0x64, 0x18, + 0x44, 0x20, 0xee, 0xc1, 0x2a, 0x71, 0x29, 0x1b, 0x37, 0x8a, 0x54, 0x6f, 0xab, 0x3d, 0xdb, 0x50, + 0x68, 0xf1, 0x3e, 0x2c, 0x1f, 0x9e, 0xd8, 0xe7, 0xbc, 0x4b, 0xc4, 0x65, 0x66, 0x98, 0x89, 0xc1, + 0x14, 0xe2, 0x2e, 0xd4, 0x02, 0xfb, 0xd0, 0xa4, 0x63, 0x6e, 0xe4, 0xe1, 0x61, 0xbd, 0x46, 0x2c, + 0xba, 0x12, 0xd8, 0x87, 0x4d, 0x04, 0x0e, 0x0e, 0xdc, 0x50, 0xbc, 0x0b, 0x2b, 0xb4, 0xb8, 0x50, + 0x2b, 0x49, 0x7d, 0x59, 0xad, 0x54, 0x43, 0x62, 0xc5, 0xa7, 0x00, 0x52, 0xf7, 0x31, 0x0f, 0xce, + 0x49, 0xc2, 0x8f, 0x17, 0x53, 0x7a, 0xfe, 0xa7, 0x35, 0xa4, 0xf7, 0x60, 0x19, 0x27, 0x49, 0x58, + 0xbf, 0x46, 0x25, 0xaf, 0x67, 0x67, 0x10, 0xd5, 0x94, 0xf0, 0xe2, 0x1e, 0x14, 0x71, 0xa2, 0xd0, + 0xaa, 0xae, 0xa7, 0x95, 0x41, 0x39, 0xab, 0x70, 0x63, 0xb7, 0x4f, 0xfb, 0xdf, 0xbb, 0xe2, 0x3e, + 0x14, 0x46, 0xb8, 0x98, 0xaf, 0xa7, 0x6d, 0x14, 0x6a, 0x6e, 0xa1, 0xee, 0x48, 0xfa, 0x29, 0xd1, + 0x88, 0x1d, 0xa8, 0xe1, 0x34, 0x7a, 0x48, 0xb2, 0x1a, 0x76, 0x5f, 0xfd, 0x06, 0xe5, 0x7a, 0x6b, + 0x26, 0x57, 0x57, 0x12, 0x51, 0x67, 0xb7, 0xbc, 0x28, 0x38, 0x37, 0xaa, 0x5e, 0x1a, 0x26, 0x6e, + 0x40, 0xd1, 0x09, 0x3b, 0xfe, 0xf0, 0x24, 0xf6, 0xc0, 0x89, 0xd3, 0xe2, 0x2b, 0xa8, 0xd2, 0xc4, + 0xc2, 0x24, 0x7e, 0x5c, 0xba, 0xdf, 0xa4, 0xa7, 0x8c, 0x42, 0x19, 0x59, 0x4a, 0xdc, 0x41, 0x9d, + 0xd0, 0x8c, 0xec, 0xf1, 0xc4, 0x0f, 0x50, 0x8d, 0x7c, 0x53, 0x1d, 0xcd, 0x0e, 0x14, 0x08, 0xe5, + 0xa8, 0xd8, 0xad, 0xd1, 0xf4, 0x0f, 0x0f, 0x43, 0x3b, 0x22, 0x77, 0x9b, 0x82, 0x51, 0x53, 0xde, + 0x8d, 0x3d, 0x82, 0x92, 0x1c, 0x13, 0x9a, 0xa3, 0x73, 0xcf, 0x1a, 0x3b, 0xc3, 0xfa, 0x6d, 0xd6, + 0x56, 0x9d, 0x70, 0x8b, 0x01, 0x69, 0x85, 0xf1, 0x4e, 0x46, 0x61, 0xbc, 0x0c, 0xcb, 0xa3, 0x03, + 0x5c, 0x8e, 0x6f, 0x51, 0xb1, 0x85, 0xd1, 0x41, 0x7b, 0x24, 0x3e, 0xa2, 0xe3, 0x35, 0x66, 0x81, + 0x75, 0x3d, 0x7d, 0x40, 0x10, 0x73, 0x46, 0x23, 0xa1, 0x10, 0x77, 0xa0, 0xbc, 0x6d, 0x5b, 0xd1, + 0x34, 0xb0, 0xb7, 0x5d, 0xeb, 0xa8, 0xfe, 0x36, 0x95, 0x94, 0x06, 0x61, 0xed, 0x5c, 0xff, 0xc8, + 0x19, 0x5a, 0xb4, 0xf2, 0xef, 0xb2, 0xd8, 0x2c, 0x21, 0xd2, 0x36, 0x4b, 0x6c, 0xdc, 0x92, 0xb2, + 0xf0, 0x3b, 0x69, 0x0d, 0xc7, 0x72, 0xd5, 0x39, 0x74, 0xd2, 0x17, 0xf6, 0xc4, 0x1f, 0x1e, 0xd7, + 0xdf, 0xa5, 0xf5, 0x56, 0x55, 0x5d, 0xd1, 0x42, 0xa0, 0x78, 0x0f, 0xd6, 0xa4, 0xed, 0xc0, 0x54, + 0x3e, 0x99, 0xef, 0x11, 0x5d, 0x4d, 0x82, 0x9b, 0xd2, 0x35, 0x53, 0x87, 0x2a, 0x17, 0x38, 0x32, + 0x87, 0xd6, 0xf0, 0xd8, 0xae, 0xdf, 0xe3, 0x8a, 0x53, 0x71, 0xa3, 0x26, 0x82, 0x66, 0xa4, 0xae, + 0xf7, 0x67, 0xa4, 0xae, 0xc5, 0x1e, 0x91, 0xf7, 0x17, 0x7b, 0x44, 0xde, 0x78, 0x42, 0xba, 0x2b, + 0x0d, 0xfd, 0xe7, 0x33, 0x1c, 0x36, 0xc3, 0x1f, 0x52, 0xac, 0x78, 0xe7, 0x52, 0x9a, 0xd1, 0x6e, + 0x2e, 0xd3, 0x56, 0x74, 0xe3, 0xe7, 0x20, 0xe6, 0x27, 0xed, 0xeb, 0xd8, 0xfd, 0xb2, 0x64, 0xf7, + 0x5f, 0x2f, 0x3d, 0xce, 0xe9, 0xff, 0x54, 0x0e, 0xaa, 0x19, 0x76, 0xb6, 0x70, 0xdf, 0x62, 0x99, + 0xdf, 0x1a, 0x4b, 0xcb, 0x1b, 0x27, 0x94, 0xa6, 0xe9, 0x78, 0x47, 0xae, 0x9d, 0xd2, 0x34, 0x29, + 0xfd, 0xb4, 0x50, 0x2c, 0x68, 0xcb, 0x4f, 0x0b, 0xc5, 0x65, 0x6d, 0xc5, 0xb8, 0x7c, 0x38, 0x75, + 0xdd, 0xc8, 0x3e, 0x8b, 0xd4, 0x29, 0x69, 0x60, 0x1f, 0x1a, 0x22, 0x06, 0xb2, 0x5c, 0x16, 0xd8, + 0x87, 0xfa, 0x7f, 0x91, 0x87, 0xca, 0x8e, 0x15, 0x1e, 0xef, 0x5a, 0x93, 0x7e, 0x64, 0x45, 0x21, + 0xae, 0x8c, 0x63, 0x2b, 0x3c, 0x1e, 0x5b, 0x13, 0x56, 0x26, 0x73, 0x7c, 0x46, 0x21, 0x61, 0xa4, + 0x49, 0xde, 0x80, 0x22, 0x26, 0x7b, 0xde, 0xde, 0x33, 0x69, 0x64, 0x8c, 0xd3, 0xc8, 0x91, 0xc3, + 0xe3, 0xe9, 0xe1, 0x61, 0x5c, 0x3f, 0x95, 0x14, 0x77, 0xa1, 0x2a, 0x7f, 0x92, 0xbe, 0x76, 0x26, + 0xcf, 0x79, 0xb3, 0x40, 0xf1, 0x08, 0xca, 0x12, 0x30, 0x50, 0xfb, 0x47, 0x2d, 0x3e, 0xba, 0x4a, + 0x10, 0x46, 0x9a, 0x4a, 0xfc, 0x02, 0xae, 0xa4, 0x92, 0xdb, 0x7e, 0xb0, 0x3b, 0x75, 0x23, 0xa7, + 0xd9, 0x95, 0xc2, 0xeb, 0x1b, 0x73, 0xd9, 0x13, 0x12, 0x63, 0x71, 0xce, 0x6c, 0x6d, 0x77, 0x1d, + 0x3e, 0x01, 0xc8, 0x1b, 0x59, 0xe0, 0x0c, 0x95, 0x75, 0x46, 0xbb, 0x50, 0x96, 0xca, 0x3a, 0x43, + 0x3e, 0x25, 0x01, 0xbb, 0x76, 0x74, 0xec, 0x8f, 0xa4, 0x34, 0x7a, 0x39, 0x53, 0x2d, 0x46, 0x19, + 0x59, 0x4a, 0xec, 0x4e, 0x6f, 0xea, 0xba, 0x43, 0x2f, 0x22, 0xfd, 0x28, 0x6f, 0xa8, 0x24, 0xee, + 0xd0, 0x81, 0xe5, 0x1d, 0xd9, 0x61, 0xbd, 0x7c, 0x27, 0x7f, 0x2f, 0x67, 0xc8, 0x94, 0xfe, 0x57, + 0x97, 0x60, 0x99, 0x47, 0xf2, 0x0d, 0x28, 0x1d, 0x90, 0xf7, 0x8e, 0x37, 0x1d, 0xab, 0xe3, 0x07, + 0x02, 0x74, 0xa7, 0x63, 0xd6, 0x3b, 0xa4, 0x91, 0x38, 0x67, 0xd0, 0x6f, 0x2c, 0xd2, 0x9f, 0x46, + 0xf8, 0xad, 0x3c, 0x41, 0x65, 0x0a, 0x2b, 0x11, 0xf8, 0xa7, 0x34, 0x1b, 0x0a, 0x84, 0x50, 0x49, + 0x72, 0xe4, 0xa1, 0xcd, 0x1e, 0x33, 0x2d, 0x13, 0xae, 0x48, 0x80, 0xa6, 0x17, 0xcd, 0x1e, 0x76, + 0xad, 0xcc, 0x1f, 0x76, 0xdd, 0x02, 0xd4, 0x6a, 0x86, 0x76, 0xcf, 0xb3, 0x9b, 0x5d, 0x79, 0xa2, + 0x9e, 0x82, 0xe0, 0xb2, 0x1a, 0xf9, 0x13, 0x79, 0x54, 0x8e, 0x3f, 0xc5, 0x17, 0xf1, 0xec, 0xa4, + 0x36, 0x4a, 0x1d, 0x53, 0x6e, 0x86, 0xe9, 0x79, 0x6c, 0x64, 0xe8, 0xb0, 0x24, 0xdc, 0xe1, 0x58, + 0xc7, 0xc4, 0x9f, 0x7a, 0x0b, 0xc0, 0xf0, 0x4f, 0x43, 0x9b, 0x0f, 0xb0, 0xae, 0x51, 0x13, 0x33, + 0x3e, 0x7b, 0xfe, 0xe9, 0x9e, 0x1f, 0xc6, 0x06, 0xa2, 0xa5, 0xc5, 0x06, 0x22, 0xfd, 0x63, 0x58, + 0x45, 0xf1, 0xc7, 0x8a, 0x2c, 0x71, 0x57, 0xda, 0xca, 0x59, 0x68, 0xd3, 0x94, 0xe7, 0x88, 0xfa, + 0x86, 0x34, 0xb9, 0x77, 0xd4, 0x77, 0x29, 0xcf, 0x5b, 0x29, 0x43, 0x47, 0xbc, 0xf5, 0xca, 0x02, + 0xa5, 0x40, 0x45, 0xa7, 0x48, 0xa7, 0x26, 0x39, 0x27, 0x29, 0x7f, 0x8b, 0xc0, 0x3f, 0x6d, 0x62, + 0x5a, 0xff, 0xbb, 0x39, 0x28, 0xf7, 0x82, 0x11, 0xee, 0xf9, 0x74, 0xca, 0xf1, 0x3a, 0x7b, 0x16, + 0x8a, 0x5f, 0x8a, 0x37, 0x2a, 0x43, 0x43, 0x0c, 0x10, 0x9f, 0x42, 0xe1, 0x10, 0x77, 0x91, 0x7c, + 0x5a, 0xe7, 0x4b, 0x15, 0xaf, 0x7e, 0xe3, 0xbe, 0x62, 0x10, 0xa9, 0xfe, 0x3b, 0xf1, 0xf7, 0x69, + 0xb3, 0x49, 0x3b, 0xbe, 0x5c, 0x22, 0xc7, 0xbb, 0x7e, 0x53, 0xcb, 0x89, 0x22, 0x14, 0xb6, 0x5a, + 0xfd, 0x26, 0xeb, 0x45, 0xa8, 0x21, 0xf5, 0xcd, 0xed, 0xb6, 0xd1, 0x1f, 0xf0, 0x31, 0x0e, 0x03, + 0x3a, 0x8d, 0xfe, 0x40, 0x2b, 0x0a, 0x80, 0x95, 0xfd, 0x6e, 0xfb, 0x17, 0xfb, 0x2d, 0x4d, 0xd3, + 0xff, 0x76, 0x0e, 0x20, 0x39, 0xd3, 0x16, 0x1f, 0x40, 0xf9, 0x94, 0x52, 0x66, 0xca, 0x05, 0x29, + 0x73, 0x26, 0xc7, 0x68, 0x12, 0x0d, 0x3f, 0x82, 0x4a, 0xbc, 0x4b, 0xa2, 0xd8, 0x34, 0xef, 0x8b, + 0x54, 0x8e, 0xf1, 0x9b, 0xe7, 0xe2, 0x43, 0x28, 0xfa, 0xd8, 0x0e, 0x24, 0xcd, 0xa7, 0x65, 0xa6, + 0x54, 0xf3, 0xe9, 0x04, 0x54, 0x89, 0x57, 0x87, 0x81, 0x32, 0x1c, 0xc5, 0xa4, 0xdb, 0x08, 0x6a, + 0xba, 0xd6, 0x34, 0xb4, 0x0d, 0xc6, 0xc7, 0xac, 0x7d, 0x39, 0x61, 0xed, 0xfa, 0x2f, 0xa1, 0xd6, + 0xb7, 0xc6, 0x13, 0xde, 0x00, 0xa8, 0x61, 0x02, 0x0a, 0x38, 0x27, 0xe4, 0xd4, 0xa3, 0xdf, 0xb8, + 0xe8, 0xf6, 0xec, 0x60, 0x68, 0x7b, 0x6a, 0x8d, 0xaa, 0x24, 0xb2, 0xdf, 0x7d, 0xdc, 0x02, 0x0c, + 0xff, 0x54, 0xed, 0x01, 0x2a, 0xad, 0xff, 0x6b, 0x39, 0x28, 0xa7, 0xaa, 0x21, 0x3e, 0x86, 0x02, + 0xc9, 0xe1, 0xb9, 0x34, 0x23, 0x4c, 0x11, 0xf0, 0x6f, 0x96, 0xdc, 0x90, 0x50, 0xbc, 0x0b, 0xcb, + 0x61, 0x64, 0x05, 0xca, 0x3d, 0x42, 0x4b, 0xe5, 0xd8, 0xf4, 0xa7, 0xde, 0xc8, 0x60, 0xb4, 0xd0, + 0x21, 0x6f, 0x7b, 0x23, 0x69, 0x6a, 0x9b, 0xa7, 0x42, 0xa4, 0x7e, 0x07, 0x4a, 0x71, 0xf1, 0x38, + 0x05, 0x8c, 0xde, 0x8b, 0xbe, 0x76, 0x89, 0x0e, 0xea, 0x1a, 0xdd, 0x27, 0x2d, 0x2d, 0xa7, 0xff, + 0x8d, 0x1c, 0x40, 0x92, 0x4b, 0x3c, 0xc8, 0xd4, 0xf6, 0xc6, 0x6c, 0xa9, 0x0f, 0xe8, 0x6f, 0xaa, + 0xb2, 0x37, 0xa1, 0x34, 0xf5, 0x08, 0x68, 0x8f, 0xe4, 0x4e, 0x94, 0x00, 0x50, 0x79, 0x54, 0xb7, + 0x10, 0x66, 0x94, 0xc7, 0x97, 0x96, 0xab, 0x7f, 0x0d, 0xa5, 0xb8, 0x38, 0x54, 0xce, 0xb7, 0x7b, + 0x9d, 0x4e, 0xef, 0x45, 0xbb, 0xfb, 0x84, 0x8f, 0x25, 0xf7, 0x8c, 0x56, 0xb3, 0xb5, 0x85, 0xc9, + 0x1c, 0xce, 0xd9, 0xe6, 0xbe, 0x61, 0xb4, 0xba, 0x03, 0x3a, 0x7a, 0x5c, 0xd2, 0xff, 0x42, 0x0e, + 0xaa, 0x3d, 0x77, 0xd4, 0xf4, 0xdd, 0xa6, 0x35, 0x41, 0x41, 0x4b, 0xfc, 0x0c, 0xd6, 0x0f, 0xa6, + 0x28, 0xec, 0x4f, 0x5c, 0x6b, 0x68, 0x1f, 0xfb, 0xee, 0xc8, 0x56, 0x8b, 0x30, 0xe3, 0x00, 0x22, + 0x4f, 0x68, 0x34, 0x22, 0xde, 0x4b, 0x68, 0xc5, 0xe7, 0x50, 0x99, 0x04, 0xfe, 0x81, 0xad, 0x8e, + 0xcb, 0x96, 0x2e, 0xcc, 0x5b, 0x26, 0x3a, 0x3e, 0x41, 0xd3, 0xff, 0xe3, 0x65, 0xa8, 0x6c, 0xd9, + 0xa3, 0xe9, 0xe4, 0xa9, 0xef, 0x78, 0xcd, 0xe8, 0x4c, 0x7c, 0x06, 0x15, 0xdf, 0x25, 0x83, 0x96, + 0x99, 0x72, 0x18, 0x5e, 0x54, 0x0e, 0xf8, 0xd4, 0x02, 0x72, 0x2f, 0xfe, 0x08, 0x2e, 0x4b, 0x7b, + 0x09, 0x5b, 0x57, 0xcf, 0x38, 0x33, 0xae, 0x99, 0x65, 0x43, 0x63, 0x14, 0x6f, 0xd0, 0x44, 0xfe, + 0x13, 0xd8, 0x48, 0x91, 0x23, 0x63, 0x61, 0xfa, 0xfc, 0xdc, 0x1a, 0x5b, 0x8f, 0xf3, 0xc6, 0xae, + 0xcc, 0x4f, 0x61, 0x43, 0xd5, 0x70, 0xc8, 0xbd, 0xc7, 0x99, 0x0b, 0x69, 0xad, 0x2a, 0xd3, 0xbb, + 0xb2, 0xc2, 0xeb, 0x7e, 0x1a, 0x48, 0x65, 0x7d, 0x0a, 0x57, 0x46, 0xd8, 0x7a, 0x93, 0x3b, 0xff, + 0xc4, 0xb6, 0x27, 0xa6, 0x9b, 0xf2, 0xf3, 0x23, 0xe4, 0x26, 0xe2, 0x9e, 0xd9, 0xf6, 0xa4, 0x63, + 0x85, 0x91, 0x78, 0x0c, 0xeb, 0xd6, 0xe1, 0x21, 0xfb, 0x17, 0xe1, 0x36, 0xb6, 0xd0, 0x8a, 0x6b, + 0xd8, 0x87, 0xc6, 0x9a, 0x22, 0xc3, 0xe5, 0xd8, 0xf4, 0x5d, 0xf1, 0x04, 0xae, 0x4f, 0x8e, 0xcf, + 0x43, 0x92, 0xa4, 0x87, 0xc7, 0xb8, 0xdb, 0xa6, 0x4a, 0x58, 0x5d, 0x50, 0xc2, 0x55, 0x45, 0xde, + 0x64, 0x6a, 0x55, 0xd0, 0x63, 0xb8, 0xae, 0xba, 0x0f, 0x15, 0xbc, 0x6c, 0x9f, 0x17, 0xa9, 0xcf, + 0xaf, 0xc8, 0x7e, 0x43, 0x7c, 0xaa, 0xe3, 0xef, 0x81, 0xc6, 0x8e, 0xab, 0x87, 0xe4, 0x5e, 0x8f, + 0x5f, 0x97, 0x17, 0x9b, 0x6a, 0x04, 0xdf, 0xa6, 0xc5, 0x87, 0xec, 0xe3, 0x1e, 0x68, 0xf6, 0xd8, + 0x89, 0x4c, 0x8b, 0x44, 0x4c, 0xa6, 0xe4, 0xb3, 0xb7, 0x1a, 0xc2, 0xa5, 0xdd, 0x0e, 0x29, 0xbf, + 0x00, 0x4d, 0x12, 0x1d, 0x92, 0x12, 0x80, 0xad, 0x29, 0x2f, 0x68, 0x4d, 0x8d, 0xa9, 0xb6, 0x91, + 0x08, 0x5b, 0xb1, 0x0b, 0x42, 0x19, 0x21, 0xc9, 0xb4, 0xc2, 0x9a, 0x2c, 0xeb, 0xd0, 0xd2, 0x51, + 0xb3, 0xb7, 0xf5, 0x6c, 0x3f, 0xd1, 0x8f, 0xa9, 0x31, 0x6a, 0x01, 0x1c, 0x66, 0xc1, 0xa1, 0xfe, + 0x1f, 0xae, 0x40, 0x89, 0xed, 0x6e, 0x38, 0x8d, 0xef, 0xc1, 0xaa, 0x7f, 0xf0, 0x1d, 0x4a, 0xa8, + 0x17, 0x79, 0x9a, 0xae, 0xf8, 0x07, 0xdf, 0x19, 0xf6, 0xa1, 0xf8, 0x40, 0x89, 0x20, 0x23, 0xfb, + 0x50, 0xae, 0x9a, 0x5a, 0x56, 0xcb, 0x94, 0x22, 0xc9, 0x96, 0x7d, 0x88, 0xd2, 0xa5, 0xe3, 0x85, + 0x76, 0x10, 0xb1, 0xdd, 0x74, 0xf5, 0xe2, 0xc5, 0xc1, 0x64, 0x64, 0x4a, 0x7d, 0x04, 0x65, 0x69, + 0x9b, 0xa4, 0x4c, 0xc5, 0x8b, 0x33, 0x31, 0x19, 0x65, 0xfa, 0x0a, 0x6a, 0xc9, 0xf6, 0x43, 0xf9, + 0x4a, 0x17, 0xe6, 0xab, 0xc6, 0x94, 0x94, 0xf5, 0x21, 0x5c, 0x0d, 0x4f, 0x9c, 0x89, 0x29, 0x6b, + 0xea, 0x7b, 0x74, 0x88, 0x6b, 0x4e, 0x4e, 0xe4, 0x00, 0x0a, 0xc4, 0xb6, 0x09, 0xd9, 0xf3, 0xba, + 0x53, 0xd7, 0xdd, 0x3b, 0x11, 0xef, 0xc3, 0xba, 0x24, 0x9f, 0xc4, 0xf3, 0x89, 0x46, 0x71, 0xd9, + 0xa8, 0x31, 0x62, 0x4f, 0xce, 0x23, 0xf1, 0x25, 0xd4, 0x79, 0x0e, 0xc9, 0x46, 0xf1, 0x34, 0xe7, + 0x19, 0xc2, 0x27, 0xad, 0x57, 0x08, 0xcf, 0x36, 0xd5, 0x06, 0x61, 0x69, 0xa2, 0x7c, 0x02, 0x1b, + 0xce, 0x91, 0xe7, 0x07, 0x2a, 0x8b, 0x9c, 0xfe, 0xf2, 0x08, 0x56, 0x30, 0xae, 0x91, 0x5a, 0x34, + 0xd8, 0x12, 0xb9, 0x3c, 0xcf, 0xcd, 0x88, 0x5c, 0xc5, 0x30, 0x07, 0xaa, 0xa1, 0xb5, 0xf4, 0xfa, + 0x3c, 0x67, 0x37, 0x32, 0xc3, 0x3f, 0x6d, 0x8f, 0x70, 0x49, 0x4b, 0x52, 0xb5, 0x46, 0xa2, 0x33, + 0x6a, 0xcd, 0x1a, 0xb5, 0x46, 0x30, 0x32, 0x9e, 0x29, 0xd8, 0xa2, 0x9f, 0x83, 0x98, 0x5b, 0xd2, + 0x61, 0x5d, 0xbb, 0xb0, 0xbf, 0xb5, 0x99, 0x95, 0x4d, 0x6b, 0x60, 0x6e, 0x45, 0xaf, 0x2f, 0x5a, + 0x03, 0xc3, 0xec, 0x4a, 0x6e, 0x41, 0x3d, 0xfb, 0xe5, 0x53, 0xdb, 0x39, 0x3a, 0xa6, 0xd9, 0x25, + 0xef, 0x55, 0x65, 0xf3, 0x5f, 0x49, 0x7f, 0xf9, 0x05, 0xd1, 0xbe, 0x96, 0xb3, 0x5c, 0xfe, 0xe1, + 0x9c, 0x45, 0xff, 0xd7, 0x73, 0x50, 0xe2, 0x99, 0x81, 0x8b, 0xe8, 0x2d, 0xc8, 0xbf, 0x62, 0x01, + 0x21, 0x4e, 0xdc, 0x87, 0x75, 0x6b, 0x34, 0x9a, 0x19, 0x50, 0xde, 0x49, 0xd7, 0xac, 0xd1, 0x28, + 0x33, 0x9a, 0xf7, 0x40, 0x73, 0x42, 0x53, 0x59, 0xa2, 0x12, 0x6f, 0xf4, 0xa2, 0x51, 0x73, 0x42, + 0x69, 0x88, 0xe2, 0x53, 0xcb, 0xcc, 0x9a, 0x2c, 0xbc, 0x7a, 0x4d, 0xea, 0x02, 0xc0, 0xb0, 0x69, + 0xdb, 0x6c, 0x46, 0x67, 0x4f, 0x0b, 0xc5, 0x9c, 0x06, 0xfa, 0x7f, 0x56, 0x86, 0x72, 0xc3, 0xb3, + 0xdc, 0xf3, 0x5f, 0xd9, 0xe4, 0x4a, 0x4f, 0x27, 0x45, 0x93, 0xa9, 0x9c, 0xa5, 0xec, 0xc7, 0x51, + 0x22, 0x08, 0xd5, 0xec, 0x36, 0x48, 0x97, 0xa7, 0xa4, 0xfe, 0x79, 0x03, 0x18, 0x44, 0x04, 0x71, + 0xfe, 0xf8, 0x7c, 0x54, 0xe5, 0x27, 0x85, 0x36, 0xc9, 0x1f, 0x2b, 0x39, 0x71, 0x7e, 0x22, 0x78, + 0x1b, 0xaa, 0x91, 0x33, 0xa6, 0xcb, 0x9a, 0xe1, 0x74, 0x6c, 0x8f, 0xf8, 0x9a, 0x22, 0xdf, 0x7c, + 0x6b, 0x4a, 0x18, 0x96, 0x32, 0xb6, 0xc7, 0x7e, 0x70, 0xce, 0xa5, 0xac, 0x70, 0x29, 0x0c, 0xa2, + 0x52, 0x3e, 0x04, 0x71, 0x6a, 0x39, 0x91, 0x99, 0x2d, 0x8a, 0x15, 0x4b, 0x0d, 0x31, 0x83, 0x74, + 0x71, 0x57, 0x61, 0x65, 0xe4, 0x84, 0x27, 0xed, 0x9e, 0x54, 0x2a, 0x65, 0x0a, 0xdb, 0x12, 0x0e, + 0x2d, 0x94, 0x69, 0x23, 0x9b, 0xb9, 0x7f, 0xde, 0x28, 0x21, 0x64, 0x13, 0x01, 0x28, 0x13, 0x79, + 0x76, 0x74, 0xea, 0x07, 0x98, 0x93, 0x75, 0xc6, 0x04, 0x80, 0xb2, 0x23, 0x92, 0xe2, 0x87, 0x88, + 0x3d, 0xe4, 0x8d, 0x38, 0x8d, 0xda, 0x18, 0xb3, 0x0a, 0xc2, 0x56, 0xb8, 0xfa, 0x09, 0x44, 0xdc, + 0x85, 0x1a, 0x55, 0x9f, 0x74, 0x4a, 0x6c, 0x03, 0xad, 0xfc, 0xbc, 0x51, 0x41, 0x28, 0x59, 0xd6, + 0x90, 0xea, 0x2b, 0xb8, 0x9e, 0x69, 0x9f, 0x69, 0x05, 0x81, 0x75, 0x6e, 0x8e, 0xad, 0xef, 0xfc, + 0x80, 0xac, 0xa0, 0x79, 0xe3, 0x6a, 0xba, 0xdb, 0x1a, 0x88, 0xde, 0x45, 0xec, 0x85, 0x59, 0x1d, + 0xcf, 0x0f, 0xc8, 0x44, 0xba, 0x30, 0x2b, 0x62, 0xc9, 0x9e, 0x47, 0x03, 0x4c, 0x0a, 0x6e, 0xc8, + 0x37, 0x26, 0x0d, 0xf6, 0xb0, 0xdb, 0x24, 0x10, 0xaa, 0x78, 0xe1, 0x23, 0xde, 0x63, 0xd7, 0xe5, + 0x3d, 0x9e, 0x47, 0xb4, 0xa9, 0x32, 0xe2, 0xd8, 0xb6, 0x46, 0xb4, 0x66, 0x09, 0xb1, 0x63, 0x5b, + 0x74, 0xdb, 0x2b, 0x7c, 0x64, 0x4e, 0xa6, 0x11, 0x5f, 0x75, 0x34, 0x96, 0xc3, 0x47, 0x7b, 0xd3, + 0x48, 0x82, 0x8f, 0xec, 0x88, 0xfc, 0x37, 0x08, 0xfc, 0x84, 0x6f, 0x1b, 0x87, 0x8f, 0xd4, 0x89, + 0xdb, 0x15, 0xd9, 0xb7, 0x8f, 0xe4, 0x91, 0x9a, 0x0e, 0xd5, 0x18, 0x69, 0x8e, 0xa7, 0x7c, 0xb7, + 0x31, 0x6f, 0x94, 0x15, 0xc1, 0xee, 0xd4, 0xc5, 0x81, 0x25, 0x5b, 0x98, 0x19, 0x60, 0x55, 0xae, + 0xf1, 0xd0, 0x11, 0xc4, 0xc0, 0xda, 0xbc, 0x01, 0x9c, 0x30, 0x8f, 0x1d, 0x76, 0x63, 0xcd, 0x1b, + 0x45, 0x02, 0xec, 0x38, 0x11, 0xae, 0x63, 0x46, 0xca, 0x19, 0x48, 0x45, 0x5c, 0x27, 0xa2, 0x35, + 0x42, 0xec, 0x12, 0x9c, 0x0a, 0x42, 0x21, 0x22, 0x4d, 0x8b, 0xe5, 0xdd, 0x20, 0xd2, 0x5a, 0x8a, + 0x14, 0x4b, 0x7d, 0x17, 0x38, 0xb3, 0x89, 0x53, 0x8f, 0xcb, 0x7c, 0x83, 0x0d, 0x1c, 0x04, 0xde, + 0x72, 0xc2, 0x13, 0x2a, 0xf1, 0x2e, 0xd4, 0x52, 0x74, 0x58, 0xde, 0x4d, 0x9e, 0x19, 0x31, 0x59, + 0xa6, 0x8e, 0x81, 0x3d, 0xf6, 0x23, 0xd9, 0xcc, 0x37, 0x53, 0x75, 0x34, 0x08, 0x9e, 0xad, 0xa3, + 0xa4, 0xc5, 0x32, 0x6f, 0xa5, 0xea, 0xc8, 0xa4, 0x58, 0xea, 0x5b, 0x50, 0x39, 0x0d, 0x9c, 0x28, + 0xb2, 0xa5, 0x90, 0x73, 0x9b, 0x3b, 0x56, 0xc2, 0x68, 0xf5, 0xbf, 0x05, 0x15, 0xee, 0x79, 0xc9, + 0xdf, 0xee, 0x30, 0x89, 0x84, 0x29, 0x06, 0x21, 0x7b, 0x63, 0xec, 0x78, 0x64, 0x8f, 0xcd, 0x1b, + 0x25, 0x86, 0xec, 0x3a, 0x5e, 0x1a, 0x6d, 0x9d, 0x91, 0x55, 0x36, 0x41, 0x5b, 0x67, 0xb4, 0x24, + 0x27, 0x8e, 0xeb, 0xf2, 0xc2, 0x7f, 0x5b, 0x2e, 0x49, 0x84, 0xd0, 0xba, 0x8f, 0xd1, 0xf4, 0xf5, + 0xbb, 0x29, 0x34, 0x7d, 0x1b, 0x27, 0x0e, 0xa1, 0xf1, 0xd3, 0xef, 0xc8, 0x89, 0x83, 0x00, 0xfc, + 0x72, 0x82, 0xb4, 0xce, 0xc8, 0xe6, 0x1a, 0x23, 0xad, 0x33, 0xc9, 0xb7, 0x68, 0xa7, 0xc0, 0xbc, + 0xef, 0xc5, 0x7c, 0x0b, 0x41, 0x98, 0x3b, 0x4d, 0x60, 0x9d, 0x91, 0x91, 0x35, 0x45, 0x60, 0x9d, + 0x91, 0x71, 0xc1, 0xb6, 0x46, 0x5c, 0xf1, 0xf7, 0xb9, 0x78, 0x04, 0x50, 0xbd, 0xef, 0x40, 0x25, + 0x7c, 0x64, 0x26, 0xf8, 0xfb, 0x9c, 0x3d, 0x7c, 0x64, 0x28, 0x8a, 0xbb, 0x50, 0x8b, 0xa7, 0x06, + 0xd3, 0x7c, 0xc0, 0x03, 0x3f, 0x92, 0x53, 0x83, 0x2e, 0xf3, 0xfd, 0x3a, 0x07, 0x37, 0xf8, 0x8c, + 0x93, 0xd8, 0xff, 0xae, 0x1d, 0x86, 0xd6, 0x91, 0xbd, 0xed, 0x07, 0xdb, 0xd3, 0x5f, 0xfd, 0xea, + 0x5c, 0xdc, 0x83, 0xb5, 0x3d, 0x2b, 0xb0, 0xbd, 0x28, 0xf6, 0x4c, 0x90, 0x96, 0xd0, 0x59, 0xb0, + 0x78, 0x0c, 0x1a, 0x83, 0xf8, 0x0e, 0x53, 0x53, 0x1d, 0x9c, 0xcf, 0x9e, 0x44, 0xcd, 0x51, 0xe9, + 0x7f, 0x37, 0x07, 0xa5, 0x2d, 0x27, 0x8c, 0x0c, 0xdc, 0x2e, 0xc5, 0x57, 0xa0, 0xb9, 0xfe, 0x29, + 0x2a, 0xfb, 0x24, 0x46, 0xa7, 0x74, 0x4e, 0xb9, 0x4b, 0x26, 0x8a, 0x66, 0x8d, 0x08, 0x13, 0x4d, + 0xf1, 0x2b, 0xd0, 0xa6, 0x93, 0x49, 0x36, 0xeb, 0xd2, 0x05, 0x59, 0x89, 0x30, 0xc9, 0xfa, 0x01, + 0x94, 0x53, 0x5f, 0x5d, 0xa0, 0x97, 0x42, 0xf2, 0x2d, 0x24, 0x4e, 0x7d, 0x67, 0xc1, 0x1d, 0x4a, + 0x48, 0x4a, 0xd7, 0xff, 0x8d, 0x25, 0xd0, 0xc8, 0x1a, 0x6d, 0x90, 0xf7, 0x1a, 0x39, 0x38, 0x64, + 0x2c, 0x1a, 0xb9, 0xd7, 0x5a, 0x34, 0xee, 0xc0, 0xb2, 0xeb, 0x8c, 0xe3, 0x6b, 0x11, 0x99, 0x13, + 0x60, 0x42, 0xe0, 0x58, 0xfb, 0x81, 0x73, 0x44, 0xb6, 0x97, 0xf4, 0xb5, 0x3a, 0x3a, 0x29, 0xd8, + 0x9e, 0x7a, 0x43, 0x1a, 0xa2, 0x07, 0x00, 0x23, 0x27, 0x8c, 0x4c, 0xb2, 0x46, 0xca, 0x6a, 0xcb, + 0x9e, 0x89, 0xfb, 0xdf, 0x28, 0x8d, 0xe2, 0xa1, 0xb8, 0x07, 0x5a, 0x4a, 0x4e, 0xf6, 0x62, 0x43, + 0xe2, 0xb2, 0x91, 0xc8, 0xcf, 0x4d, 0xaf, 0xe9, 0x45, 0x73, 0x94, 0x28, 0x13, 0xae, 0xcc, 0x51, + 0xa2, 0x3c, 0x78, 0x0f, 0x34, 0xff, 0xa5, 0x1d, 0x98, 0x87, 0x76, 0x34, 0x3c, 0x36, 0xb9, 0x59, + 0xab, 0x7c, 0x72, 0x83, 0xf0, 0x6d, 0x04, 0x77, 0x10, 0xaa, 0x9f, 0xc1, 0x65, 0xea, 0xb7, 0x1d, + 0x3a, 0xdd, 0xa4, 0x89, 0x26, 0xef, 0x40, 0x07, 0xbe, 0x1b, 0x1b, 0xe4, 0xf1, 0xb7, 0x78, 0x0f, + 0x50, 0xe3, 0xb0, 0x87, 0xaa, 0x87, 0x16, 0x2a, 0x24, 0xf6, 0x10, 0xfb, 0x69, 0x39, 0x91, 0x8d, + 0xe6, 0x05, 0x1f, 0x46, 0xea, 0xff, 0xf7, 0x0a, 0xac, 0xf1, 0x35, 0x40, 0xdb, 0x0a, 0x86, 0xc7, + 0x74, 0x19, 0xf0, 0x21, 0x54, 0xa4, 0xb5, 0x3e, 0x71, 0x0a, 0x5b, 0xf0, 0xa1, 0x32, 0x13, 0xb1, + 0xa8, 0xf5, 0x18, 0xb4, 0x74, 0x9e, 0x57, 0x68, 0x41, 0xb5, 0x54, 0x36, 0xd4, 0x85, 0xee, 0xc2, + 0x32, 0x1f, 0xcd, 0x65, 0xea, 0x19, 0x1f, 0x7b, 0x32, 0x52, 0xfc, 0x36, 0x54, 0xf9, 0xe8, 0xd7, + 0x94, 0xb7, 0x1e, 0x0b, 0x69, 0x05, 0x6f, 0x41, 0xe7, 0x19, 0x95, 0xe3, 0x24, 0x1d, 0x8a, 0x8f, + 0xa1, 0x4a, 0x2e, 0xfa, 0xe6, 0xc4, 0x3a, 0x77, 0x7d, 0x6b, 0x94, 0x75, 0x5a, 0xa5, 0xf9, 0x55, + 0x21, 0x82, 0x3d, 0xc6, 0x8b, 0x0f, 0x60, 0x1d, 0x67, 0x87, 0xe5, 0x0d, 0x6d, 0x9a, 0x6a, 0x64, + 0xa9, 0xe4, 0x83, 0x62, 0x4d, 0x21, 0xe2, 0x93, 0x93, 0x9f, 0x40, 0x69, 0xe4, 0x04, 0x36, 0x13, + 0xad, 0xfe, 0x10, 0xab, 0x65, 0x42, 0x2f, 0x1e, 0xe1, 0xee, 0xe6, 0x8d, 0x1c, 0xd2, 0x32, 0x78, + 0x96, 0x14, 0xe7, 0x2a, 0x57, 0x8b, 0x49, 0x68, 0xc6, 0x88, 0x2f, 0x88, 0xe3, 0x71, 0xf5, 0x78, + 0x8e, 0x97, 0x16, 0xcf, 0xf1, 0xaa, 0x22, 0xe3, 0x79, 0xfe, 0x01, 0x94, 0x27, 0x81, 0x6d, 0x1e, + 0x3a, 0x6e, 0x64, 0x07, 0xa8, 0x8a, 0xcf, 0x5a, 0x4a, 0x60, 0x12, 0xd8, 0xdb, 0x8c, 0x5d, 0xe8, + 0x9a, 0x54, 0x5e, 0xec, 0x9a, 0xf4, 0x08, 0xaa, 0x24, 0x0d, 0xc6, 0xd7, 0x70, 0xb5, 0x85, 0xd7, + 0x70, 0x2b, 0x48, 0xa4, 0x52, 0xe2, 0x11, 0x5c, 0x9d, 0xf8, 0x61, 0x24, 0x6b, 0x63, 0x26, 0x8b, + 0x85, 0x24, 0xa3, 0xa2, 0x71, 0x19, 0xb1, 0x5c, 0x99, 0x9e, 0x5a, 0x30, 0xe2, 0x0b, 0x20, 0x29, + 0xd3, 0x44, 0x49, 0x52, 0x2a, 0x37, 0xe9, 0x59, 0x90, 0xcc, 0xe3, 0x17, 0x7e, 0x70, 0xc2, 0x62, + 0x25, 0xfe, 0xa2, 0xeb, 0xb6, 0xee, 0x91, 0x6f, 0xb2, 0xd3, 0x57, 0x48, 0xb2, 0x54, 0xc5, 0x28, + 0x23, 0x8c, 0xfd, 0xc1, 0xb0, 0xbd, 0x40, 0x24, 0xf6, 0xd9, 0x24, 0x08, 0xeb, 0x1b, 0x73, 0x7d, + 0x53, 0x42, 0x2c, 0xfe, 0x0a, 0xe9, 0x24, 0x52, 0x91, 0x9a, 0xec, 0xa0, 0x77, 0x85, 0x7a, 0xa6, + 0xaa, 0x68, 0x90, 0x0d, 0x85, 0x4f, 0x0b, 0xc5, 0x8a, 0x56, 0x7d, 0x5a, 0x28, 0x56, 0xb5, 0x1a, + 0xfb, 0x67, 0x3d, 0x2d, 0x14, 0xd7, 0x34, 0x4d, 0xff, 0xeb, 0x1f, 0x41, 0x81, 0xee, 0x38, 0x7c, + 0x02, 0x25, 0xba, 0x70, 0x98, 0x62, 0xfe, 0xd2, 0xf6, 0x84, 0x68, 0xfa, 0x43, 0x5c, 0xbc, 0xe8, + 0xc9, 0x5f, 0x17, 0xdf, 0x7c, 0x7f, 0x8b, 0x6c, 0xa6, 0xe4, 0x9f, 0x87, 0xbd, 0x52, 0x56, 0xe1, + 0x1f, 0xac, 0x28, 0x34, 0x18, 0x83, 0x72, 0x37, 0x39, 0x03, 0x04, 0xb6, 0x47, 0x2b, 0x68, 0xd9, + 0x88, 0xd3, 0x64, 0xa9, 0xe6, 0x4b, 0x6d, 0x2c, 0x9d, 0x2e, 0x2f, 0xb0, 0x54, 0x33, 0x9e, 0xc4, + 0xd5, 0x4f, 0xa0, 0xf4, 0x9d, 0xef, 0x78, 0x5c, 0xf1, 0x95, 0xb9, 0x8a, 0x3f, 0xf5, 0x1d, 0x8f, + 0x2b, 0xfe, 0x9d, 0xfc, 0x25, 0xde, 0x86, 0x55, 0xdf, 0xe3, 0xb2, 0x57, 0xe7, 0x6f, 0xc3, 0xf8, + 0x5e, 0x87, 0x2f, 0x65, 0x55, 0x9d, 0xd0, 0x0c, 0x48, 0x7d, 0xc5, 0x9c, 0xd2, 0xaf, 0xaf, 0xec, + 0x84, 0x06, 0xc2, 0xb0, 0x58, 0x9c, 0xc4, 0x72, 0xca, 0x50, 0x61, 0xa5, 0xf9, 0x49, 0xcc, 0x68, + 0x2a, 0xf0, 0x1d, 0x28, 0x1e, 0x05, 0x3e, 0x29, 0xff, 0x0b, 0xa6, 0xfb, 0x2a, 0xe1, 0x36, 0xcf, + 0x51, 0xb5, 0xa2, 0x9f, 0x8e, 0x77, 0x64, 0xd2, 0xe1, 0x03, 0x4e, 0xf4, 0xa2, 0x51, 0x51, 0x40, + 0x3a, 0x56, 0x78, 0x07, 0x8a, 0xd6, 0xd1, 0x91, 0x29, 0xef, 0x96, 0xcd, 0x95, 0x65, 0x1d, 0x1d, + 0xd1, 0x27, 0x1f, 0x40, 0xf5, 0xd4, 0xf1, 0xcc, 0x70, 0x62, 0x0f, 0x99, 0xb6, 0x3a, 0xdf, 0x95, + 0xa7, 0x0e, 0xdd, 0x07, 0x21, 0xfa, 0xf4, 0x16, 0x59, 0xfb, 0xe1, 0x5b, 0xe4, 0xda, 0x45, 0x5b, + 0xa4, 0x0e, 0x2b, 0xd2, 0x51, 0x40, 0x9b, 0x23, 0x91, 0x18, 0xf1, 0x29, 0x94, 0x03, 0xcb, 0x3b, + 0x91, 0xcb, 0xa1, 0xfe, 0x6d, 0xda, 0x80, 0x6e, 0x58, 0xde, 0x89, 0xf4, 0x91, 0x84, 0x20, 0xfe, + 0x9d, 0x55, 0xa7, 0xd7, 0x5f, 0x63, 0xe2, 0x4a, 0x59, 0xce, 0xc4, 0xab, 0x2d, 0x67, 0x9f, 0x93, + 0x89, 0xca, 0xf6, 0x22, 0x53, 0x65, 0xb8, 0xbc, 0x38, 0x43, 0x85, 0xc9, 0x7a, 0x9c, 0x0d, 0x1b, + 0x40, 0x07, 0x58, 0x26, 0x9d, 0x76, 0x6d, 0x64, 0x1a, 0x10, 0x9f, 0x6c, 0x19, 0x10, 0x24, 0xa7, + 0x5c, 0x0d, 0x58, 0x4b, 0xae, 0xc1, 0x73, 0xec, 0x81, 0x2b, 0xe9, 0x73, 0xf7, 0xcc, 0xbd, 0x79, + 0x65, 0x14, 0x73, 0x32, 0x97, 0xe9, 0xdf, 0x86, 0x2a, 0xfb, 0x4b, 0x2b, 0x36, 0xc2, 0x8e, 0xee, + 0x15, 0x02, 0x2a, 0x3e, 0x82, 0xc2, 0x87, 0xb4, 0xd4, 0x45, 0x67, 0xa4, 0x41, 0x25, 0x8c, 0x99, + 0x4d, 0x73, 0xd1, 0x99, 0x51, 0x1a, 0xa9, 0x9f, 0xc8, 0x9a, 0x0e, 0x1c, 0x6f, 0x84, 0x53, 0x2f, + 0xb2, 0x8e, 0xc2, 0x7a, 0x9d, 0x56, 0x66, 0x59, 0xc2, 0x06, 0xd6, 0x51, 0x28, 0x3e, 0x83, 0x8a, + 0xc5, 0x86, 0x08, 0xae, 0xf7, 0xf5, 0xf4, 0x81, 0x4f, 0xca, 0x44, 0x61, 0x94, 0xad, 0x94, 0xbd, + 0xe2, 0x4b, 0x10, 0xca, 0x8f, 0x29, 0x65, 0x1e, 0xbf, 0x31, 0x37, 0x1b, 0xd7, 0xa4, 0x23, 0x53, + 0x6c, 0x1c, 0xbf, 0x0d, 0x72, 0x77, 0xe7, 0x6b, 0x48, 0x6f, 0x50, 0x85, 0x80, 0x41, 0x74, 0x05, + 0xe9, 0x4b, 0xa8, 0x66, 0x2d, 0x30, 0x37, 0x17, 0xb8, 0x03, 0xf1, 0x5e, 0x5c, 0x19, 0xa6, 0x6d, + 0x32, 0x6f, 0x73, 0x38, 0x07, 0xd2, 0x9e, 0x28, 0x23, 0xbb, 0xbc, 0x54, 0x3c, 0x3f, 0x6a, 0x2a, + 0x18, 0x76, 0xa0, 0xb2, 0x8f, 0x46, 0x67, 0xa4, 0x70, 0xc5, 0x1d, 0x18, 0x9b, 0x95, 0x8c, 0x92, + 0x13, 0x5b, 0x98, 0xb6, 0x40, 0x28, 0x57, 0x02, 0x14, 0x3c, 0xd9, 0xe3, 0x96, 0xf4, 0xab, 0xd8, + 0x43, 0x68, 0x56, 0x2e, 0x35, 0xd8, 0x3b, 0x39, 0x2d, 0xa9, 0x3e, 0x86, 0x1a, 0xee, 0x8d, 0xa9, + 0x2f, 0xeb, 0xe9, 0x46, 0xed, 0x05, 0x76, 0xf2, 0xf1, 0xca, 0x24, 0x95, 0x12, 0x3f, 0x83, 0xf5, + 0x54, 0xce, 0xe9, 0x09, 0x65, 0x7e, 0x9b, 0x32, 0x6f, 0xcc, 0x64, 0xde, 0x3f, 0xc1, 0xec, 0xb5, + 0x49, 0x26, 0x2d, 0x36, 0x60, 0xb9, 0x1d, 0xb6, 0xbc, 0x11, 0xe9, 0x5d, 0x45, 0x83, 0x13, 0xe2, + 0x11, 0x54, 0xd8, 0xc8, 0x41, 0xb6, 0xc6, 0xb0, 0xfe, 0x6e, 0xfa, 0x44, 0x97, 0x2c, 0x1d, 0x6c, + 0xb0, 0x2c, 0xbb, 0xf1, 0xef, 0x50, 0x7c, 0x01, 0xeb, 0x7c, 0xdc, 0x9e, 0x66, 0x91, 0xef, 0xcd, + 0x0f, 0x39, 0x11, 0x6d, 0x27, 0x7c, 0xd2, 0x80, 0xeb, 0xc1, 0xd4, 0x23, 0xc3, 0x87, 0xcc, 0xc9, + 0x07, 0x41, 0x94, 0xff, 0x1e, 0xe5, 0x97, 0x01, 0x85, 0x0c, 0x26, 0xe3, 0xbc, 0xc4, 0x9b, 0xae, + 0x06, 0x69, 0xd0, 0x1e, 0xe6, 0xbb, 0xa0, 0x4c, 0x3e, 0x20, 0xa1, 0x32, 0xdf, 0xff, 0x31, 0x65, + 0xd2, 0xe1, 0x09, 0x95, 0x29, 0xa0, 0x30, 0x9d, 0x3a, 0x23, 0xd2, 0x02, 0x2b, 0x06, 0xfd, 0x16, + 0xef, 0x40, 0x2d, 0xb0, 0x87, 0xd3, 0x20, 0x74, 0x5e, 0xda, 0x66, 0xe8, 0x78, 0x27, 0xa4, 0xff, + 0x15, 0x8d, 0x6a, 0x0c, 0xed, 0x3b, 0xde, 0x09, 0xb2, 0x0c, 0xfb, 0x2c, 0xb2, 0x03, 0x8f, 0xe3, + 0x60, 0x7c, 0x98, 0x66, 0x19, 0x2d, 0x42, 0xe0, 0x3a, 0x37, 0xc0, 0x8e, 0x7f, 0xcf, 0x8c, 0x6c, + 0xc8, 0x23, 0xfb, 0xe0, 0x07, 0x8d, 0x6c, 0x9f, 0x46, 0xf6, 0x5d, 0x28, 0x3a, 0x5e, 0x64, 0x07, + 0x2f, 0x2d, 0xb7, 0xfe, 0xf1, 0x1c, 0x37, 0x8e, 0x71, 0xe2, 0x2e, 0xac, 0x86, 0xae, 0x83, 0xeb, + 0xbd, 0xfe, 0xc9, 0x1c, 0x99, 0x42, 0x89, 0x7b, 0x50, 0x8a, 0xa3, 0x5c, 0xd5, 0x3f, 0x9d, 0xa3, + 0x4b, 0x90, 0xe2, 0x16, 0x14, 0x4e, 0x71, 0x42, 0x3d, 0x9c, 0x3f, 0x81, 0x47, 0x38, 0x6e, 0xdf, + 0x87, 0xa8, 0xcf, 0xd3, 0xf6, 0xfd, 0x68, 0x6e, 0xfb, 0xde, 0x76, 0x5c, 0x97, 0xb7, 0xef, 0x43, + 0xf9, 0x0b, 0x37, 0x3f, 0xca, 0x81, 0x2d, 0xf9, 0x6c, 0x7e, 0xf3, 0x43, 0xdc, 0x73, 0x8a, 0x07, + 0x56, 0x0e, 0xe9, 0x58, 0x99, 0x4f, 0xc7, 0x3f, 0x4f, 0xf7, 0x55, 0xf6, 0xbc, 0xd9, 0x80, 0x30, + 0x4e, 0x8b, 0x37, 0x41, 0x9e, 0x9a, 0x93, 0x42, 0xf5, 0x05, 0x5f, 0x05, 0x65, 0x08, 0xea, 0x52, + 0x9f, 0x40, 0x55, 0xf9, 0x43, 0x93, 0x00, 0x56, 0xff, 0x72, 0xae, 0x06, 0x59, 0x02, 0xb1, 0x05, + 0x95, 0x43, 0xd4, 0xeb, 0xc7, 0xac, 0xe6, 0xd7, 0x1f, 0x53, 0x45, 0xee, 0xa8, 0x8d, 0xf5, 0x22, + 0x33, 0x80, 0x91, 0xc9, 0x25, 0x1e, 0x80, 0x70, 0x0e, 0x79, 0x3c, 0xb7, 0x03, 0x7f, 0xcc, 0xaa, + 0x7c, 0xfd, 0x2b, 0x79, 0xd4, 0x30, 0x87, 0x21, 0x1f, 0x1b, 0xdb, 0x1b, 0x99, 0xe3, 0x50, 0x8a, + 0x09, 0x5f, 0x53, 0x3d, 0x25, 0xf3, 0x8a, 0xa3, 0xe1, 0xa9, 0x33, 0x54, 0xa4, 0xdd, 0x0d, 0x59, + 0x6a, 0xf8, 0x0a, 0x70, 0xba, 0xbe, 0x4c, 0xb2, 0xfe, 0xe4, 0x95, 0x59, 0x91, 0x56, 0x65, 0x7d, + 0x0c, 0x35, 0x3e, 0xe0, 0x20, 0x89, 0x0c, 0xa7, 0xe8, 0x4f, 0xd3, 0x9c, 0x2b, 0x7d, 0x32, 0x6b, + 0x54, 0x46, 0xe9, 0x73, 0xda, 0x2f, 0x61, 0x2d, 0x75, 0xbe, 0x41, 0x9f, 0xfd, 0xad, 0xf4, 0x67, + 0xe3, 0x03, 0x0e, 0xa3, 0x3a, 0x55, 0x3f, 0xe9, 0x93, 0x73, 0x02, 0xff, 0x6f, 0xff, 0x00, 0x81, + 0xff, 0x6d, 0x48, 0x56, 0xa4, 0x39, 0x8c, 0xec, 0xfa, 0xcf, 0x98, 0xf9, 0xc7, 0xc0, 0x66, 0x64, + 0x8b, 0x47, 0x00, 0xd6, 0x64, 0xe2, 0x9e, 0xf3, 0xd4, 0xfc, 0x39, 0x4d, 0xcd, 0x8d, 0xd4, 0xd4, + 0x6c, 0x20, 0x92, 0xe6, 0x66, 0xc9, 0x52, 0x3f, 0x51, 0x67, 0x25, 0x55, 0x62, 0x34, 0x76, 0xa9, + 0xfd, 0x8d, 0xf4, 0xda, 0xde, 0xf3, 0xc3, 0x68, 0x6b, 0xec, 0x62, 0x2b, 0x60, 0x12, 0xff, 0x16, + 0x1d, 0xb8, 0xec, 0x7b, 0xe6, 0x68, 0x3a, 0x71, 0x9d, 0x21, 0xf6, 0x00, 0x1f, 0x2c, 0xd6, 0x37, + 0xd3, 0x57, 0x92, 0xe8, 0x8b, 0x3d, 0x6f, 0x4b, 0x11, 0xc9, 0x03, 0xcb, 0x75, 0x7f, 0x16, 0x44, + 0x36, 0x28, 0x1a, 0x83, 0xf8, 0x36, 0x4f, 0x93, 0x45, 0x03, 0x82, 0xaa, 0xeb, 0x3c, 0x8f, 0x61, + 0x2d, 0xa1, 0xe2, 0xeb, 0xd3, 0x5b, 0x17, 0x5c, 0x9f, 0xae, 0xaa, 0x8c, 0x7c, 0xeb, 0x1a, 0xfb, + 0xce, 0x77, 0xdd, 0xe9, 0x44, 0xb2, 0xd2, 0x7a, 0x4b, 0xf6, 0x1d, 0x01, 0x99, 0x4b, 0xa6, 0xcc, + 0x74, 0xf6, 0xb8, 0xbe, 0x9d, 0x36, 0xd3, 0xd9, 0x63, 0xd1, 0x84, 0x3a, 0xb1, 0x62, 0xb9, 0xce, + 0x32, 0x6e, 0x29, 0xed, 0xb9, 0xe5, 0x74, 0x05, 0x69, 0xd9, 0xeb, 0x65, 0x2f, 0xe5, 0xa0, 0xf2, + 0x73, 0x78, 0x73, 0x71, 0x21, 0x2a, 0xfe, 0xc9, 0x53, 0x92, 0x15, 0xae, 0x2f, 0xc8, 0x2d, 0x83, + 0xa0, 0x7c, 0x0d, 0xd5, 0x23, 0x8b, 0x5a, 0xe1, 0x9a, 0x63, 0x7f, 0x64, 0xd7, 0x9f, 0xa5, 0x2f, + 0x00, 0x52, 0x87, 0x3f, 0xb1, 0xb0, 0x41, 0xee, 0xae, 0x3f, 0xb2, 0x8d, 0xf2, 0x51, 0x92, 0x10, + 0x8f, 0xa1, 0x9e, 0x4c, 0xa0, 0xa9, 0x87, 0xdf, 0x45, 0xfd, 0xd6, 0xf1, 0x86, 0x51, 0xbd, 0xc3, + 0x81, 0x2b, 0x63, 0xfc, 0x3e, 0xa2, 0xb7, 0x24, 0x56, 0x34, 0x41, 0xa3, 0x85, 0x2d, 0x77, 0xa0, + 0xd0, 0x19, 0xd9, 0xf5, 0xdd, 0x74, 0x34, 0x1f, 0x66, 0x7b, 0x48, 0x42, 0x7b, 0x4d, 0xdf, 0x19, + 0xd9, 0x46, 0xed, 0x30, 0x93, 0x16, 0xef, 0xc3, 0xba, 0xd2, 0x25, 0xcc, 0x63, 0x2b, 0x3c, 0x36, + 0x4f, 0xec, 0xf3, 0x7a, 0x97, 0x1a, 0x5c, 0x93, 0x8a, 0xc4, 0x8e, 0x15, 0x1e, 0x3f, 0xb3, 0xcf, + 0xc5, 0x7d, 0x58, 0x97, 0x5b, 0x9e, 0x13, 0x9a, 0x07, 0x56, 0x10, 0x38, 0x76, 0x50, 0xef, 0xf1, + 0x89, 0x16, 0x23, 0xda, 0xe1, 0x26, 0x83, 0xc5, 0x87, 0x20, 0xd2, 0x83, 0x21, 0x7d, 0xac, 0xf6, + 0x88, 0x07, 0x6a, 0x29, 0xef, 0x20, 0xf2, 0xb5, 0x12, 0x9f, 0x40, 0x2d, 0xee, 0x3f, 0xf6, 0x91, + 0xf9, 0xc5, 0xbc, 0x2d, 0x43, 0x76, 0x5a, 0x9f, 0x9c, 0x64, 0x3e, 0x84, 0x4a, 0x9c, 0xc3, 0xf6, + 0x46, 0x75, 0x63, 0xde, 0x8a, 0x27, 0xe9, 0x71, 0x67, 0xf8, 0x1c, 0xae, 0xf1, 0x14, 0xe5, 0x93, + 0x8c, 0x13, 0xfb, 0x3c, 0x0e, 0xde, 0xd4, 0xe7, 0xd8, 0x27, 0x84, 0x6e, 0x23, 0xf6, 0x99, 0x7d, + 0x1e, 0xc6, 0x9c, 0xef, 0x3a, 0x9d, 0xf4, 0x0f, 0xe5, 0x35, 0x61, 0xb6, 0x72, 0xcb, 0xb6, 0x0c, + 0x78, 0x6c, 0x90, 0xa0, 0x19, 0xe3, 0x0d, 0xe9, 0x3d, 0x26, 0x1a, 0xea, 0xba, 0x54, 0x48, 0xca, + 0x3b, 0xef, 0xce, 0xfb, 0xe9, 0x88, 0x17, 0x33, 0xaa, 0xbd, 0xbc, 0x45, 0x95, 0xb2, 0x59, 0x3d, + 0x81, 0x1b, 0xf1, 0xd1, 0xa5, 0xfd, 0xfd, 0xd4, 0xa2, 0xeb, 0x4f, 0x27, 0xf6, 0x39, 0xb3, 0xb4, + 0x17, 0x73, 0xb3, 0xfb, 0x9a, 0xa2, 0x6e, 0x49, 0xe2, 0x67, 0xf6, 0x39, 0xf1, 0xb5, 0xbb, 0x50, + 0xb3, 0x42, 0xff, 0x50, 0x6a, 0xa0, 0x43, 0xdf, 0xad, 0x3f, 0xa7, 0x71, 0xa8, 0x20, 0xd4, 0x50, + 0x27, 0xa5, 0x5d, 0xb8, 0x9c, 0x8c, 0x18, 0x6a, 0xfc, 0x81, 0x13, 0x1d, 0x8f, 0xeb, 0xbf, 0x4c, + 0x9b, 0x7e, 0x68, 0x42, 0xc5, 0x93, 0xbf, 0xa1, 0x88, 0x8c, 0x64, 0xac, 0x63, 0x98, 0x78, 0x0c, + 0xd7, 0x93, 0xf2, 0x22, 0x7f, 0x62, 0x7a, 0xe6, 0xa9, 0x13, 0x1d, 0x9b, 0xe4, 0x1b, 0xfc, 0x3b, + 0x32, 0xc4, 0x8f, 0x22, 0x18, 0xf8, 0x93, 0xee, 0x0b, 0x27, 0x3a, 0x1e, 0x38, 0x76, 0x28, 0x36, + 0xe1, 0x96, 0x35, 0xb2, 0x26, 0x11, 0x2e, 0x08, 0xcc, 0x18, 0x87, 0x25, 0xf2, 0x3d, 0xd3, 0x1e, + 0x4f, 0xa2, 0xf3, 0xfa, 0x9f, 0xa3, 0xec, 0x37, 0x14, 0xd5, 0xc0, 0x9f, 0x6c, 0x4b, 0x9a, 0x9e, + 0xd7, 0x42, 0x0a, 0xf1, 0x08, 0xae, 0xbe, 0xb4, 0x87, 0x91, 0x1f, 0x98, 0x6c, 0x23, 0x93, 0xa2, + 0xbf, 0x33, 0xaa, 0xff, 0x2e, 0xb5, 0xfd, 0x32, 0x63, 0x7f, 0x81, 0x48, 0x76, 0xf8, 0x69, 0x8f, + 0x50, 0x1b, 0x24, 0x8f, 0xfd, 0x89, 0x15, 0x1d, 0xd7, 0xff, 0xa1, 0xf4, 0xc5, 0x81, 0xe7, 0x8e, + 0x7d, 0x8a, 0x4a, 0x82, 0x41, 0x2e, 0xfd, 0x7b, 0x56, 0x74, 0x2c, 0x1e, 0x2a, 0xb6, 0x87, 0x43, + 0xc2, 0xe6, 0x15, 0x73, 0x7e, 0x03, 0x27, 0x92, 0x67, 0xf6, 0x39, 0x6d, 0xe0, 0xfa, 0x5f, 0x5c, + 0x81, 0xa2, 0x32, 0x7f, 0x88, 0x32, 0xac, 0xee, 0x77, 0x9f, 0x75, 0x7b, 0x2f, 0xba, 0x1c, 0x81, + 0xaf, 0xd1, 0xef, 0xb7, 0x8c, 0x81, 0x36, 0x12, 0x35, 0x00, 0x8a, 0x36, 0x65, 0xf6, 0x9b, 0x8d, + 0x2e, 0x47, 0xe4, 0xa3, 0x18, 0x57, 0x9c, 0x5e, 0x12, 0xeb, 0x50, 0xdd, 0xde, 0xef, 0xf2, 0xc5, + 0x24, 0x02, 0xe5, 0x11, 0xd4, 0xfa, 0x86, 0x9d, 0x03, 0x19, 0x54, 0x40, 0xd0, 0x6e, 0x63, 0xd0, + 0x32, 0xda, 0x0a, 0xb4, 0x2c, 0xae, 0xc0, 0x7a, 0x4c, 0xa5, 0x4a, 0xd0, 0x56, 0x11, 0xdc, 0xee, + 0x6e, 0xb5, 0xbe, 0x31, 0xfb, 0xad, 0x86, 0xd1, 0xdc, 0x61, 0xea, 0x22, 0xd6, 0x6f, 0xcf, 0xe8, + 0x3d, 0x6d, 0x35, 0x07, 0x1a, 0x90, 0xbf, 0xe1, 0x93, 0x27, 0x5a, 0x59, 0x54, 0xa0, 0xb8, 0xd5, + 0xee, 0x0f, 0xda, 0xdd, 0xe6, 0x40, 0xab, 0x60, 0xb5, 0xb7, 0xdb, 0x9d, 0x41, 0xcb, 0xd0, 0xaa, + 0xa2, 0x08, 0x85, 0xa7, 0xbd, 0x76, 0x57, 0xab, 0x51, 0xec, 0xad, 0xc6, 0xee, 0x5e, 0xa7, 0xa5, + 0xad, 0x21, 0xb4, 0xdf, 0x33, 0x06, 0x9a, 0x86, 0x50, 0x8e, 0x32, 0xa1, 0xad, 0x8b, 0x12, 0x2c, + 0xef, 0x77, 0xf1, 0xeb, 0x42, 0x54, 0xa1, 0x44, 0x3f, 0xcd, 0x46, 0xa7, 0xa3, 0x5d, 0x4e, 0x39, + 0x29, 0x6e, 0x20, 0x8a, 0x5c, 0x1e, 0xfb, 0x58, 0x87, 0x2b, 0xd8, 0xa2, 0x38, 0x49, 0xd4, 0x57, + 0xb1, 0x9c, 0xdd, 0x76, 0x77, 0xbf, 0xaf, 0x5d, 0x43, 0x62, 0xfa, 0x49, 0x98, 0x3a, 0x96, 0xd3, + 0xee, 0x52, 0x87, 0xde, 0xc2, 0xdf, 0x5b, 0xad, 0x4e, 0x6b, 0xd0, 0xd2, 0x6e, 0x63, 0xab, 0x3a, + 0xbd, 0xe6, 0x33, 0xb3, 0xb7, 0xa7, 0xbd, 0x85, 0x3d, 0xbb, 0x67, 0xb4, 0x4c, 0x49, 0xf8, 0xb6, + 0xd0, 0xa0, 0xb2, 0xbd, 0xff, 0xcb, 0x5f, 0x7e, 0x6b, 0xca, 0x46, 0xbd, 0x83, 0xdf, 0x4c, 0x28, + 0xcc, 0xfd, 0x67, 0xda, 0xbb, 0x33, 0xa0, 0xfe, 0x33, 0xed, 0x3d, 0xec, 0x14, 0xd5, 0xd7, 0xda, + 0x3d, 0x24, 0x30, 0x5a, 0xcd, 0x7d, 0xa3, 0xdf, 0x7e, 0xde, 0x32, 0x9b, 0x83, 0x96, 0xf6, 0x3e, + 0xf5, 0x42, 0xbb, 0xfb, 0x4c, 0xbb, 0x8f, 0xd5, 0xc4, 0x5f, 0xdc, 0xc9, 0x1f, 0x08, 0x01, 0xb5, + 0x84, 0x96, 0x60, 0x1f, 0x22, 0xc9, 0xa6, 0xd1, 0x6b, 0x6c, 0x35, 0x1b, 0xfd, 0x81, 0xf6, 0x11, + 0xb6, 0xb1, 0xbf, 0xd7, 0x69, 0x0f, 0xb4, 0x07, 0xd8, 0x90, 0x27, 0x8d, 0xc1, 0x4e, 0xcb, 0xd0, + 0x3e, 0x16, 0x6b, 0x50, 0x1e, 0xb4, 0x77, 0x5b, 0xa6, 0xec, 0xd3, 0x87, 0xf8, 0x8d, 0xed, 0x76, + 0xa7, 0xa3, 0x3d, 0x22, 0x27, 0xbb, 0x86, 0x31, 0x68, 0xd3, 0xf8, 0x7e, 0x86, 0x05, 0x34, 0xf6, + 0xf6, 0x3a, 0xdf, 0x6a, 0x9f, 0x63, 0x03, 0x77, 0xf7, 0x3b, 0x83, 0xb6, 0xb9, 0xbf, 0xb7, 0xd5, + 0x18, 0xb4, 0xb4, 0x2f, 0x68, 0x94, 0x7b, 0xfd, 0xc1, 0xd6, 0x6e, 0x47, 0xfb, 0x92, 0xca, 0xa4, + 0x99, 0xd6, 0xec, 0xf4, 0xba, 0x2d, 0xed, 0x31, 0xd2, 0x37, 0xb6, 0x1a, 0x7b, 0x03, 0xac, 0xdd, + 0xa0, 0xb7, 0xa7, 0x7d, 0x25, 0x36, 0x40, 0x7b, 0xde, 0x6a, 0x0e, 0x7a, 0x86, 0xf9, 0x8b, 0xfd, + 0x96, 0xf1, 0x2d, 0x41, 0xbf, 0x16, 0xd7, 0xe0, 0x72, 0x06, 0xda, 0xef, 0xed, 0x1b, 0xcd, 0x96, + 0xf6, 0x13, 0xbd, 0x50, 0x5c, 0xd1, 0x56, 0xf4, 0x42, 0xf1, 0x8e, 0x76, 0x47, 0x2f, 0x14, 0x75, + 0x4d, 0xbf, 0x5f, 0x66, 0x1c, 0x35, 0x56, 0xff, 0x2b, 0x39, 0x28, 0x2a, 0xb3, 0x1a, 0x47, 0x2f, + 0xe9, 0xb6, 0x0c, 0xed, 0x12, 0xb6, 0xa5, 0xd3, 0xda, 0x1e, 0x70, 0xe0, 0x12, 0xa3, 0xfd, 0x64, + 0x67, 0xa0, 0x2d, 0xe1, 0xcf, 0xde, 0x3e, 0x0e, 0x4b, 0x9e, 0xfa, 0xb3, 0xb5, 0xdb, 0xd6, 0x0a, + 0xf8, 0xab, 0xd1, 0x1d, 0xb4, 0xb5, 0x65, 0x9a, 0x75, 0xed, 0xee, 0x93, 0x4e, 0x4b, 0x5b, 0x41, + 0xe8, 0x6e, 0xc3, 0x78, 0xa6, 0xad, 0x72, 0xa1, 0x5b, 0xad, 0x6f, 0xb4, 0xa2, 0x58, 0x81, 0xa5, + 0xce, 0x43, 0xad, 0x84, 0xa0, 0xad, 0xd6, 0xd6, 0xfe, 0x9e, 0x06, 0x94, 0xbb, 0xdf, 0xdb, 0xd6, + 0xca, 0xd8, 0x67, 0xf8, 0xcb, 0xa4, 0xcf, 0x56, 0xf4, 0x7b, 0xb0, 0xda, 0x38, 0x3a, 0xa2, 0x0d, + 0x1a, 0xfb, 0x75, 0xbf, 0xd3, 0xe1, 0x45, 0xba, 0xd9, 0x1b, 0x0c, 0x7a, 0xbb, 0x5a, 0x0e, 0x17, + 0x04, 0x36, 0x7d, 0x49, 0x6f, 0x43, 0x51, 0x69, 0x16, 0xa9, 0x30, 0x75, 0x45, 0x28, 0xec, 0x19, + 0xad, 0xe7, 0xec, 0xa0, 0xdb, 0x6d, 0x7d, 0x83, 0xf5, 0xc7, 0x5f, 0x58, 0x50, 0x1e, 0x6b, 0xc0, + 0xf1, 0xe4, 0x28, 0x4e, 0x5d, 0xa7, 0xdd, 0x6d, 0x35, 0x0c, 0x6d, 0x59, 0x7f, 0x0c, 0xe5, 0x94, + 0x98, 0x80, 0xf3, 0xe8, 0x49, 0x63, 0x0f, 0xe7, 0x62, 0xc7, 0x94, 0xc5, 0x5e, 0x05, 0x11, 0x83, + 0x92, 0x21, 0xce, 0xe9, 0x9f, 0xc3, 0xfa, 0x9c, 0x44, 0x47, 0x15, 0x6f, 0xb4, 0x65, 0xc5, 0xdb, + 0x4f, 0xba, 0x3d, 0xa3, 0xc5, 0x21, 0xf3, 0xe4, 0xe0, 0x2f, 0xe9, 0x1f, 0x40, 0x29, 0x16, 0x3d, + 0x71, 0x31, 0x34, 0x8d, 0x5e, 0xbf, 0xcf, 0x73, 0xe5, 0x12, 0xa6, 0xa9, 0xbb, 0x39, 0x9d, 0xd3, + 0x1d, 0xa8, 0x65, 0x65, 0x09, 0x71, 0x07, 0x6e, 0xf2, 0x72, 0xd9, 0xdc, 0x6f, 0x77, 0xb6, 0xcc, + 0x7e, 0x7b, 0xab, 0x35, 0x73, 0x63, 0xfd, 0x06, 0x5c, 0x9d, 0xa3, 0xe0, 0x78, 0x7d, 0x39, 0x71, + 0x1d, 0xae, 0xcc, 0xe1, 0x68, 0x91, 0x2c, 0xe9, 0x7b, 0x20, 0xe6, 0x77, 0x19, 0x71, 0x13, 0xea, + 0x71, 0x9b, 0xcd, 0x46, 0xe7, 0x49, 0xcf, 0x68, 0x0f, 0x76, 0x76, 0x4d, 0x62, 0x2f, 0x97, 0x2e, + 0xc2, 0xee, 0x34, 0xfa, 0x3b, 0x5a, 0xee, 0x69, 0xa1, 0x78, 0x5b, 0xbb, 0xf3, 0xb4, 0x50, 0xbc, + 0xab, 0xbd, 0xf3, 0xb4, 0x50, 0x7c, 0xa2, 0xed, 0x3c, 0x2d, 0x14, 0x77, 0xb4, 0xb6, 0xde, 0x87, + 0x75, 0x25, 0xca, 0x53, 0x6c, 0x00, 0xb2, 0x31, 0x6d, 0xc0, 0x72, 0xc7, 0x7e, 0x69, 0xbb, 0xea, + 0x2a, 0x39, 0x25, 0x10, 0xda, 0x3b, 0xf8, 0xae, 0x1d, 0x07, 0xa8, 0xa5, 0x04, 0xea, 0xee, 0xdd, + 0x54, 0x8c, 0x5c, 0x0a, 0xeb, 0xf8, 0xcf, 0xe4, 0xa0, 0x18, 0x2b, 0x08, 0x77, 0x61, 0x69, 0xd0, + 0x97, 0x07, 0x4e, 0x1b, 0x0f, 0x92, 0xe0, 0xf0, 0x03, 0xf5, 0xcb, 0x58, 0x1a, 0xf4, 0xc5, 0x87, + 0xb0, 0xc2, 0x61, 0x3a, 0xe5, 0x11, 0xd3, 0x46, 0x56, 0xe9, 0x18, 0x10, 0xce, 0x90, 0x34, 0xe2, + 0x73, 0x28, 0xc5, 0xb5, 0x95, 0xa6, 0xf1, 0x6b, 0xd9, 0x0c, 0x31, 0xda, 0x48, 0x28, 0xf5, 0x0e, + 0xd4, 0xb2, 0x05, 0x8a, 0x5b, 0x00, 0x5c, 0x64, 0xea, 0x6c, 0x38, 0x05, 0x11, 0x37, 0x40, 0x45, + 0x0f, 0xdd, 0x92, 0x91, 0xa5, 0xe2, 0xb4, 0xfe, 0xaf, 0x2e, 0x03, 0x24, 0x26, 0x06, 0xec, 0x88, + 0xd8, 0xe0, 0xbf, 0x2c, 0xbd, 0x88, 0xdf, 0x80, 0x92, 0xeb, 0x5b, 0xa3, 0x74, 0x20, 0xf4, 0x22, + 0x02, 0x68, 0xbe, 0xa5, 0xa3, 0xe6, 0x94, 0x64, 0x00, 0x9c, 0xab, 0xb0, 0x22, 0x2f, 0x25, 0x71, + 0xdc, 0x00, 0x99, 0xa2, 0xc0, 0x38, 0xe4, 0x04, 0x37, 0x32, 0x5d, 0xc7, 0xb3, 0x39, 0x24, 0x61, + 0xc1, 0xa8, 0x48, 0x60, 0x07, 0x61, 0xe2, 0x36, 0x94, 0x6d, 0x6f, 0xe8, 0xfa, 0x28, 0xa7, 0x1d, + 0xf0, 0xad, 0x88, 0x8a, 0x01, 0x0a, 0xb4, 0x79, 0xce, 0xad, 0x0d, 0xc6, 0x8e, 0x67, 0x45, 0xd2, + 0x3b, 0x88, 0x5a, 0xab, 0x20, 0x58, 0xdd, 0xef, 0x42, 0x5f, 0xda, 0xff, 0x39, 0x2c, 0x4b, 0x11, + 0x01, 0x54, 0xdd, 0x37, 0x01, 0xec, 0x70, 0x68, 0x4d, 0xb8, 0xf0, 0x12, 0x47, 0xd6, 0x94, 0x90, + 0xcd, 0x73, 0xd1, 0x81, 0xda, 0xe0, 0x00, 0x35, 0x1b, 0x7f, 0xcb, 0x8a, 0xac, 0xa6, 0xef, 0x4a, + 0xcb, 0xfc, 0xdd, 0x59, 0x5b, 0xcc, 0x83, 0x2c, 0x19, 0x5f, 0xcd, 0x9b, 0xc9, 0x2b, 0x3e, 0x83, + 0x8a, 0x33, 0xb4, 0x0f, 0xec, 0xe0, 0x88, 0x25, 0xc7, 0x72, 0xe6, 0xc2, 0x3f, 0x63, 0x48, 0x6a, + 0x2c, 0x3b, 0x49, 0x02, 0x35, 0xc6, 0xb1, 0xef, 0x1d, 0xf9, 0xa3, 0x03, 0xce, 0x55, 0x49, 0x5b, + 0x19, 0x77, 0x11, 0xc3, 0x79, 0x24, 0x11, 0xe5, 0xf9, 0x2d, 0x58, 0xc3, 0x9e, 0x0f, 0xa3, 0xc0, + 0xb6, 0xc6, 0x9c, 0xad, 0x9a, 0x9e, 0x81, 0x58, 0xa3, 0x3e, 0x21, 0x29, 0x6f, 0x2d, 0x21, 0xa6, + 0xec, 0x9f, 0x25, 0xf7, 0xe5, 0x29, 0x6f, 0x2d, 0xe3, 0xb5, 0xcf, 0x18, 0xfe, 0xe8, 0x61, 0x92, + 0x10, 0x0f, 0x00, 0x4e, 0xac, 0xc3, 0x13, 0x8b, 0xf3, 0xac, 0xa5, 0xab, 0xf9, 0x0c, 0xe1, 0x94, + 0xa3, 0x74, 0xa2, 0x7e, 0xde, 0x68, 0xc0, 0xe5, 0x05, 0xbd, 0xf6, 0xa3, 0xee, 0x86, 0xfd, 0xb5, + 0x1c, 0xd4, 0xb2, 0x6d, 0x99, 0x89, 0x52, 0x5c, 0x8a, 0xa3, 0x14, 0x0b, 0x28, 0x4c, 0xfc, 0x40, + 0xdd, 0x08, 0xa1, 0xdf, 0xc9, 0x03, 0x0a, 0xf9, 0xf4, 0x03, 0x0a, 0x75, 0x58, 0x0d, 0x6c, 0xbe, + 0xde, 0xcd, 0x91, 0x22, 0x54, 0x12, 0x27, 0xec, 0x64, 0x1a, 0x1e, 0xdb, 0x23, 0xa5, 0xda, 0xf2, + 0x35, 0x85, 0x0a, 0x03, 0xa5, 0x6a, 0x7b, 0x0d, 0x56, 0xad, 0x89, 0x43, 0x1a, 0x97, 0x8c, 0x78, + 0x6b, 0x4d, 0x9c, 0x67, 0xf6, 0xb9, 0xfe, 0x2b, 0x28, 0xa7, 0xfa, 0x0e, 0x2b, 0x44, 0x61, 0x65, + 0xe4, 0xa1, 0x39, 0xc5, 0x05, 0xbb, 0x0a, 0x2b, 0x32, 0xc8, 0x2b, 0xdf, 0x35, 0x91, 0x29, 0xfc, + 0xb0, 0xba, 0x27, 0x48, 0x92, 0xaf, 0x72, 0x25, 0x90, 0x40, 0x12, 0x78, 0x71, 0x59, 0x63, 0x45, + 0x46, 0xfe, 0xa9, 0x27, 0x2b, 0x1e, 0xa7, 0xf5, 0x7f, 0x7f, 0x09, 0x4a, 0xf1, 0x20, 0x60, 0x0b, + 0x0f, 0x02, 0xff, 0xc4, 0x0e, 0x42, 0xf9, 0x75, 0x95, 0xa4, 0x1e, 0xf1, 0x27, 0xce, 0x50, 0xdd, + 0xba, 0xa6, 0x84, 0xb8, 0x99, 0xbe, 0x63, 0xc9, 0xd1, 0x52, 0x52, 0x57, 0x2a, 0x6f, 0x01, 0x58, + 0xd3, 0xc8, 0x1f, 0xfa, 0xe3, 0xb1, 0x13, 0xc9, 0x2f, 0xa7, 0x20, 0x58, 0x26, 0xe9, 0x9c, 0xb2, + 0xb7, 0x38, 0x91, 0x62, 0x0a, 0x2b, 0x19, 0xa6, 0x70, 0x13, 0x4a, 0xa1, 0x3d, 0xb1, 0x02, 0x2b, + 0xf2, 0x03, 0xb9, 0x9a, 0x13, 0x80, 0x0c, 0x7a, 0x17, 0x44, 0x2a, 0x22, 0x68, 0x9e, 0x82, 0xde, + 0x05, 0x51, 0x7b, 0x24, 0xee, 0xd0, 0x55, 0x27, 0x33, 0x46, 0xb3, 0x9f, 0x37, 0x1c, 0x5b, 0x61, + 0x5f, 0x52, 0x08, 0x28, 0x90, 0xcf, 0x0d, 0x7b, 0xf9, 0xd1, 0x6f, 0xf1, 0x1e, 0xd0, 0xd3, 0x1e, + 0xfe, 0x34, 0x32, 0x43, 0x7b, 0xe8, 0x7b, 0xa3, 0x50, 0xfa, 0xf9, 0xd5, 0x24, 0xb8, 0xcf, 0x50, + 0xfd, 0x3f, 0x5f, 0x82, 0x72, 0x6a, 0x8d, 0x92, 0x8b, 0x93, 0x35, 0xa1, 0x63, 0xb8, 0xf8, 0x82, + 0x78, 0x49, 0x42, 0x38, 0x44, 0xc9, 0xd0, 0x8a, 0x2c, 0xd7, 0x3f, 0x4a, 0x05, 0x5f, 0x91, 0x90, + 0xf6, 0x88, 0xbc, 0x0e, 0xad, 0xb1, 0xcd, 0x4f, 0x6d, 0xc8, 0xe8, 0x00, 0x31, 0x20, 0x99, 0x97, + 0x85, 0xf4, 0xbc, 0xd4, 0xd8, 0x3d, 0x95, 0x7b, 0x91, 0xbc, 0x51, 0x6f, 0x43, 0x59, 0x99, 0xb5, + 0xf0, 0x2b, 0xd2, 0x83, 0x52, 0x81, 0xda, 0x23, 0xf1, 0x2e, 0x24, 0x0f, 0x97, 0x98, 0x56, 0x68, + 0xfa, 0x87, 0xea, 0x5e, 0x5e, 0x0c, 0x6e, 0x84, 0xbd, 0xc3, 0xd8, 0xad, 0x89, 0xcc, 0x1c, 0x92, + 0x47, 0x22, 0x80, 0x24, 0x96, 0x07, 0x70, 0x39, 0x09, 0x31, 0x7a, 0xe8, 0xd8, 0xee, 0xc8, 0x74, + 0x46, 0xec, 0x9f, 0xbd, 0x6c, 0xac, 0xc7, 0xa8, 0x6d, 0xc4, 0xb4, 0x47, 0x64, 0x00, 0x92, 0x16, + 0x85, 0x91, 0x73, 0x64, 0x87, 0x91, 0xbc, 0x45, 0x56, 0x61, 0xe0, 0x16, 0xc1, 0xf4, 0xbf, 0xbf, + 0x02, 0xa5, 0x98, 0x79, 0xbd, 0xae, 0x33, 0xdf, 0x86, 0xea, 0xd0, 0xf7, 0x3c, 0xf6, 0x43, 0x48, + 0xfa, 0xb3, 0x92, 0x00, 0xe9, 0x22, 0xb0, 0x48, 0x11, 0xa5, 0x03, 0xeb, 0x15, 0x8c, 0xf5, 0x04, + 0x23, 0x6f, 0xb8, 0xe2, 0x6a, 0x41, 0xae, 0x77, 0x60, 0x85, 0xaa, 0x9b, 0xe3, 0x34, 0xce, 0xe8, + 0xa1, 0xef, 0xba, 0xd2, 0x4f, 0x42, 0x86, 0x25, 0x4f, 0x20, 0xe2, 0x21, 0x05, 0xa6, 0x27, 0x37, + 0x83, 0x95, 0x74, 0xd4, 0x3a, 0x6a, 0x10, 0x7b, 0x1a, 0xec, 0x72, 0xe5, 0x0d, 0x45, 0x28, 0x7e, + 0x06, 0x9a, 0xe4, 0x1d, 0x93, 0xc0, 0x1e, 0x91, 0x44, 0x27, 0x2f, 0x41, 0x6c, 0xa4, 0x32, 0xef, + 0x29, 0x9c, 0xb1, 0xc6, 0xd4, 0x31, 0x00, 0x67, 0x6a, 0x32, 0x0c, 0xa8, 0xcc, 0xb2, 0x6b, 0x7d, + 0xc9, 0xa8, 0xc5, 0x60, 0x54, 0x61, 0x43, 0xf1, 0x19, 0x5c, 0x0d, 0xec, 0xd0, 0x19, 0x4d, 0x2d, + 0xd7, 0xcc, 0x0e, 0x04, 0x07, 0x39, 0xdf, 0x50, 0xd8, 0xed, 0xd4, 0x80, 0x60, 0xf1, 0x63, 0xeb, + 0x8c, 0x4e, 0xa4, 0x5c, 0xd7, 0x76, 0x9d, 0x70, 0x2c, 0x63, 0xdd, 0xd6, 0xc6, 0xd6, 0xd9, 0x5e, + 0x02, 0xa5, 0x1b, 0x4f, 0x13, 0xd7, 0x99, 0x89, 0x6c, 0xca, 0x63, 0x89, 0x70, 0x83, 0xd1, 0x42, + 0x87, 0x2a, 0x16, 0x48, 0xc6, 0xd7, 0xd8, 0x59, 0x3e, 0x6f, 0x94, 0xc7, 0x16, 0x9d, 0x52, 0x92, + 0x2b, 0xdf, 0x5d, 0xa8, 0xc5, 0x34, 0xec, 0x9f, 0x2b, 0x5d, 0x64, 0x25, 0x11, 0xbb, 0xe8, 0x52, + 0xd5, 0x78, 0x76, 0xa8, 0x61, 0xad, 0xb1, 0x7b, 0x92, 0x04, 0xab, 0x31, 0xbd, 0x0e, 0x7c, 0xae, + 0x8b, 0x53, 0x64, 0x8d, 0x28, 0x56, 0x29, 0xcd, 0x2b, 0x61, 0x1a, 0xda, 0xca, 0x70, 0x40, 0x8c, + 0x97, 0x63, 0x8f, 0x56, 0x11, 0x4c, 0x0c, 0x94, 0x82, 0x2d, 0xde, 0x03, 0x8d, 0xe8, 0xd4, 0x31, + 0x50, 0xe8, 0x7b, 0x74, 0x84, 0x5c, 0x31, 0x6a, 0x08, 0x97, 0x87, 0x3c, 0xa1, 0xef, 0x89, 0x2f, + 0xa1, 0x4e, 0x94, 0x13, 0x67, 0x62, 0xa3, 0xf8, 0x62, 0x72, 0x34, 0x4e, 0xca, 0x21, 0xee, 0xe4, + 0xef, 0x55, 0x8c, 0x2b, 0x88, 0xdf, 0x93, 0x68, 0x0a, 0x49, 0x48, 0x19, 0xef, 0xc3, 0x7a, 0xaa, + 0x2a, 0x72, 0x68, 0x38, 0xfa, 0xd9, 0x5a, 0x5c, 0x19, 0x39, 0x2a, 0x9f, 0xc0, 0x86, 0xf4, 0x60, + 0x91, 0xe4, 0x3c, 0x9d, 0xe8, 0x14, 0xb9, 0x68, 0x08, 0x89, 0xa3, 0x1c, 0x3c, 0xef, 0xc4, 0x5b, + 0x50, 0x21, 0x73, 0x8a, 0x8c, 0x5d, 0x2c, 0x23, 0xa0, 0x95, 0x09, 0xc6, 0x41, 0xcb, 0xf4, 0xbf, + 0x94, 0x03, 0x31, 0x3f, 0x55, 0x2f, 0x0a, 0xb7, 0x43, 0x76, 0x13, 0x19, 0xeb, 0x02, 0x7f, 0x8b, + 0xf7, 0x61, 0x75, 0xec, 0xb3, 0x38, 0x95, 0xbf, 0x20, 0xa2, 0xde, 0xca, 0xd8, 0x27, 0xf1, 0xea, + 0x3d, 0x58, 0x1b, 0xfa, 0x9e, 0x1c, 0x34, 0xe6, 0x2e, 0xbc, 0xd6, 0x6a, 0x09, 0x18, 0x79, 0x8c, + 0xfe, 0xef, 0xe5, 0xa0, 0x96, 0x5d, 0x00, 0xe2, 0x5d, 0x7a, 0x1f, 0x21, 0xf3, 0xc2, 0x42, 0x96, + 0xa2, 0x37, 0xa1, 0x77, 0x13, 0x16, 0x55, 0xf1, 0x4d, 0x00, 0x12, 0x12, 0x78, 0x34, 0x64, 0xc0, + 0x74, 0x82, 0xd0, 0x08, 0xdc, 0x86, 0x32, 0x3f, 0x86, 0xc4, 0xf8, 0x02, 0x8d, 0x16, 0xe7, 0x08, + 0x89, 0xe0, 0x93, 0x94, 0xfb, 0x09, 0xbb, 0x97, 0x2c, 0x5e, 0xa4, 0x31, 0x95, 0xfe, 0x07, 0x39, + 0x80, 0x64, 0x0d, 0xe0, 0x4c, 0x3c, 0xb1, 0xcf, 0xd9, 0xe6, 0x24, 0xb7, 0xd8, 0x13, 0xfb, 0x7c, + 0x4f, 0xd6, 0x4d, 0xba, 0x35, 0x86, 0xf2, 0x4e, 0x69, 0xc5, 0x28, 0xb1, 0x27, 0x63, 0xc8, 0x41, + 0x9e, 0xa4, 0x23, 0x63, 0xaa, 0xea, 0xec, 0xbb, 0x18, 0x52, 0x9c, 0x8e, 0x35, 0xce, 0x4d, 0x43, + 0x1f, 0x3a, 0x2f, 0x55, 0x38, 0x2b, 0x76, 0xbc, 0x6c, 0x2b, 0x28, 0x12, 0x72, 0x39, 0x09, 0x21, + 0x5f, 0xf2, 0x62, 0x37, 0xcb, 0x98, 0x50, 0x77, 0x95, 0xc0, 0xdf, 0x88, 0x22, 0xda, 0x60, 0xe3, + 0x73, 0x81, 0x9c, 0x8a, 0x61, 0xc5, 0x47, 0x02, 0x6f, 0xd0, 0x5d, 0x58, 0x19, 0x9f, 0x42, 0xca, + 0xfd, 0x71, 0xdc, 0x89, 0x77, 0x71, 0xa4, 0x5d, 0xb5, 0x3d, 0xc4, 0x7e, 0x72, 0xcb, 0x46, 0x75, + 0xe8, 0xbb, 0xbc, 0x35, 0x20, 0x50, 0xff, 0x2f, 0x97, 0x01, 0x92, 0x13, 0xe1, 0xcc, 0x8a, 0xcd, + 0x65, 0x57, 0xec, 0x43, 0xb8, 0x2a, 0xa3, 0x14, 0xc6, 0x17, 0xbe, 0x1c, 0xcf, 0x3c, 0xb0, 0x94, + 0x08, 0x27, 0x24, 0x96, 0xaf, 0xe9, 0xb4, 0xbd, 0x4d, 0x2b, 0x12, 0x8f, 0x91, 0x47, 0x26, 0x79, + 0xa2, 0xf3, 0xc9, 0x85, 0x53, 0xb4, 0x9a, 0x64, 0x1f, 0x9c, 0x4f, 0xc4, 0x27, 0x14, 0x87, 0x29, + 0xb0, 0xc3, 0x63, 0x33, 0x0a, 0xd3, 0x1f, 0xe3, 0x5b, 0xf7, 0xeb, 0x12, 0x39, 0x08, 0xe3, 0x6f, + 0x7d, 0x02, 0x57, 0x24, 0x93, 0x98, 0xa9, 0x1e, 0xbb, 0x63, 0x4a, 0xab, 0x7a, 0xba, 0x76, 0x34, + 0xf2, 0x74, 0x4c, 0xae, 0x1e, 0xed, 0x2a, 0xe2, 0xc8, 0x63, 0x67, 0xc8, 0x47, 0x09, 0xe8, 0xac, + 0x5b, 0x4a, 0x2e, 0x9c, 0x10, 0x3a, 0x14, 0x70, 0x85, 0x10, 0x33, 0xae, 0x3d, 0xac, 0x3d, 0xa0, + 0x47, 0xc9, 0xe8, 0x41, 0x09, 0x7f, 0x64, 0x1b, 0x84, 0x13, 0x1f, 0xe1, 0x0e, 0x9d, 0x34, 0x5b, + 0xbd, 0xa6, 0x52, 0x96, 0x86, 0xf9, 0xb8, 0xa1, 0x06, 0xbf, 0xab, 0xf2, 0x01, 0x88, 0x54, 0xcd, + 0x15, 0x75, 0x85, 0xa8, 0xd7, 0xe2, 0x6a, 0x4b, 0xe2, 0xf7, 0x80, 0xaa, 0x98, 0x5c, 0x5d, 0x9a, + 0x39, 0x18, 0x46, 0xa4, 0xbc, 0xee, 0x74, 0x25, 0x69, 0x9d, 0x69, 0x45, 0x66, 0x74, 0x6c, 0x93, + 0x15, 0x9f, 0xef, 0x2e, 0xad, 0xc7, 0x0d, 0x6d, 0x44, 0x83, 0x63, 0xbb, 0x45, 0xbc, 0x36, 0x76, + 0xbd, 0x59, 0x7b, 0xb5, 0xeb, 0xcd, 0x17, 0x50, 0xcf, 0x1e, 0xe0, 0xa4, 0xba, 0x9b, 0xd9, 0xf8, + 0x46, 0xfa, 0x4e, 0x58, 0xdc, 0xe3, 0xf7, 0x61, 0x1d, 0x65, 0xc2, 0x4c, 0x5e, 0xe9, 0xb3, 0xb7, + 0x76, 0x6c, 0x85, 0xe9, 0x13, 0x1f, 0x76, 0x57, 0x33, 0x4f, 0x2d, 0x27, 0x22, 0x47, 0xa0, 0xa2, + 0xb1, 0xe2, 0xf9, 0x2f, 0x2c, 0x87, 0x7d, 0x4c, 0x4e, 0x9c, 0x09, 0xdd, 0xe3, 0xb0, 0x47, 0xc4, + 0xa9, 0x8b, 0x06, 0x20, 0x88, 0xe3, 0xaa, 0xe8, 0xff, 0xd8, 0x2a, 0xd4, 0xb2, 0xa7, 0xeb, 0x1c, + 0x09, 0x8e, 0x25, 0x84, 0x1c, 0xc9, 0x49, 0xb1, 0x1c, 0xf0, 0x06, 0x94, 0xf8, 0xca, 0x19, 0xb2, + 0x71, 0xf5, 0x1c, 0xc0, 0x89, 0x64, 0xde, 0xef, 0xc3, 0xea, 0xe4, 0xe4, 0x35, 0xac, 0x75, 0xc2, + 0x11, 0x59, 0xde, 0x87, 0xd5, 0xe9, 0x49, 0xf2, 0xd8, 0xc3, 0x42, 0xd2, 0xe9, 0x89, 0xf4, 0xc1, + 0xbe, 0x2e, 0xfd, 0x02, 0xe4, 0x7d, 0xb4, 0xf1, 0xd4, 0x8d, 0x1c, 0x93, 0xac, 0xd8, 0x92, 0x29, + 0x5c, 0x65, 0x82, 0x36, 0xe1, 0x29, 0xa6, 0x03, 0x9d, 0xc5, 0x62, 0xdb, 0x65, 0x1c, 0xa8, 0x58, + 0xda, 0x59, 0x36, 0x80, 0xe3, 0x3e, 0x51, 0x73, 0xde, 0x07, 0x4d, 0xbd, 0xc8, 0x16, 0x53, 0xad, + 0x12, 0xd5, 0x9a, 0x82, 0x2b, 0xd2, 0x77, 0xa0, 0x26, 0x6f, 0x0d, 0x29, 0x42, 0x0e, 0x54, 0x50, + 0x65, 0xa8, 0x22, 0xfb, 0x02, 0xae, 0xf9, 0xa3, 0x93, 0xa9, 0xba, 0x00, 0x67, 0x05, 0x07, 0x4e, + 0x14, 0x58, 0x71, 0x84, 0xbc, 0xa2, 0x71, 0x05, 0xd1, 0xcc, 0x3f, 0x1a, 0x09, 0x12, 0x8b, 0x97, + 0x59, 0x54, 0xf1, 0x40, 0xf5, 0xa8, 0x32, 0x54, 0x15, 0xff, 0x19, 0x5c, 0x8d, 0x43, 0xb3, 0xd8, + 0x63, 0xdb, 0x8b, 0xcc, 0xc0, 0x26, 0x8f, 0x35, 0xf9, 0x5e, 0xcb, 0x86, 0x8a, 0xd0, 0x42, 0x48, + 0x83, 0x71, 0xe2, 0x21, 0x5c, 0x99, 0xc9, 0x25, 0x47, 0x90, 0x57, 0xcd, 0xe5, 0x4c, 0x26, 0x39, + 0x98, 0x2d, 0xb8, 0x3d, 0x93, 0x27, 0x13, 0xcd, 0x14, 0x73, 0x57, 0x29, 0xf7, 0xcd, 0x4c, 0xee, + 0x74, 0xbc, 0x4d, 0x2c, 0xe6, 0x4b, 0xa8, 0xcf, 0x14, 0x83, 0x23, 0xc2, 0x2c, 0x96, 0xa3, 0xb6, + 0x5e, 0xc9, 0xe4, 0x7f, 0x66, 0x9f, 0x33, 0x4b, 0xfe, 0x19, 0xdc, 0x9c, 0xc9, 0x98, 0xe9, 0x7e, + 0x79, 0x41, 0xf0, 0x7a, 0x26, 0x73, 0x2f, 0x35, 0x14, 0x38, 0x55, 0xf1, 0x53, 0xec, 0x35, 0xaa, + 0x91, 0xac, 0x89, 0xbb, 0x1a, 0x39, 0x8c, 0x22, 0x5f, 0x40, 0x24, 0x1f, 0x0d, 0xaf, 0xcf, 0x1e, + 0x0d, 0x13, 0x21, 0x9f, 0x07, 0xbf, 0x0b, 0x6b, 0x8a, 0x90, 0x0f, 0xd9, 0x42, 0x12, 0x8f, 0x96, + 0x8d, 0xaa, 0x24, 0xa1, 0xb3, 0xb5, 0x50, 0xfc, 0x1c, 0x36, 0x90, 0x6e, 0xe4, 0x58, 0x47, 0x9e, + 0x1f, 0x46, 0xce, 0x50, 0x9e, 0xbf, 0x5c, 0x4e, 0x1f, 0xd9, 0x28, 0xc7, 0x2f, 0x43, 0x9c, 0xd8, + 0xe7, 0x5b, 0x31, 0x29, 0x1f, 0xc4, 0xfc, 0xe5, 0x65, 0xa8, 0xa4, 0x9d, 0x9f, 0x7e, 0xc8, 0x85, + 0xbe, 0x1f, 0x75, 0x1d, 0x56, 0xaa, 0x98, 0xd4, 0xab, 0xc8, 0x49, 0xf2, 0xb1, 0x8a, 0xd9, 0x98, + 0x46, 0x28, 0x4d, 0x91, 0xda, 0xe7, 0xbb, 0x2a, 0xfc, 0x11, 0xef, 0x1d, 0xb8, 0x6b, 0xca, 0xc8, + 0x47, 0x9f, 0xc8, 0xe8, 0x6a, 0x13, 0x75, 0xbc, 0xb4, 0xc8, 0xbd, 0x5b, 0x45, 0xc3, 0xa4, 0x40, + 0x1b, 0x0f, 0x61, 0x2d, 0x89, 0x65, 0xc5, 0x59, 0x56, 0xe6, 0xb2, 0x54, 0xe3, 0x40, 0x56, 0xf2, + 0x51, 0x87, 0xaa, 0x13, 0x9a, 0xbe, 0x3b, 0x52, 0x31, 0x09, 0x57, 0x95, 0x6b, 0x6a, 0xcf, 0x1d, + 0xc9, 0xb8, 0x83, 0x4c, 0xe3, 0xd9, 0xa7, 0x8a, 0x26, 0x76, 0x5f, 0xed, 0xda, 0xa7, 0x92, 0xe6, + 0x01, 0x5c, 0xc6, 0xe6, 0xca, 0x55, 0xc5, 0x81, 0x48, 0xfc, 0x40, 0xae, 0x42, 0x64, 0xac, 0xbc, + 0x08, 0xfb, 0x12, 0x91, 0xba, 0x8a, 0x1a, 0xf8, 0xa7, 0xa6, 0x37, 0x1d, 0x1f, 0xf0, 0x16, 0x23, + 0x15, 0x09, 0x79, 0x15, 0xd5, 0xf0, 0x4f, 0xbb, 0x84, 0xc2, 0xfe, 0xba, 0x0f, 0xeb, 0x6a, 0x9d, + 0x0f, 0xe9, 0x68, 0x50, 0xdd, 0xa6, 0x5e, 0x36, 0xd6, 0x18, 0xd1, 0x20, 0x38, 0xd2, 0xbe, 0x1f, + 0xd3, 0xf2, 0xa5, 0x58, 0xa2, 0xe5, 0xf5, 0x57, 0x8b, 0x92, 0x1b, 0xb1, 0x48, 0xda, 0x84, 0x5b, + 0x51, 0x60, 0x0d, 0x4f, 0xcc, 0x8b, 0x16, 0xa0, 0xbc, 0x84, 0xfb, 0x06, 0x51, 0x35, 0x16, 0x2e, + 0xbf, 0x1f, 0xb2, 0x7e, 0x6b, 0xaf, 0x5f, 0xbf, 0xfa, 0xef, 0x15, 0x60, 0x7d, 0xce, 0x6b, 0x0c, + 0x95, 0xf9, 0xe4, 0x85, 0x49, 0xfc, 0x89, 0x82, 0xfb, 0xd8, 0x8a, 0x86, 0xc7, 0xa8, 0x1f, 0x1e, + 0x3a, 0x67, 0xea, 0xe5, 0x50, 0x82, 0xed, 0x11, 0x08, 0xb9, 0x31, 0xcb, 0x74, 0xec, 0x57, 0xcb, + 0x02, 0x16, 0x8b, 0x8b, 0xec, 0x6d, 0xaf, 0xc2, 0x99, 0x14, 0x2e, 0x08, 0x67, 0x72, 0x03, 0x4a, + 0x9e, 0x4f, 0x57, 0xa4, 0x27, 0x27, 0x92, 0xf3, 0xaf, 0x7a, 0x7e, 0xd4, 0xf3, 0xf6, 0x4e, 0x90, + 0xc5, 0x4d, 0x43, 0xba, 0xe4, 0x76, 0x60, 0x07, 0xe1, 0xb1, 0x13, 0xfb, 0x6f, 0xb0, 0xa0, 0x72, + 0x79, 0x1a, 0xda, 0xbb, 0x31, 0x4e, 0xda, 0xba, 0x1a, 0x50, 0xa1, 0x99, 0xec, 0x0d, 0x7d, 0xf2, + 0x08, 0xe3, 0x2b, 0x05, 0xb7, 0x16, 0xb8, 0xca, 0x3d, 0xb3, 0xcf, 0x5b, 0x92, 0xca, 0xc0, 0x2d, + 0x45, 0x25, 0xc4, 0xfb, 0x14, 0x5e, 0xea, 0xc0, 0x4e, 0xec, 0xb3, 0x59, 0x46, 0x52, 0x22, 0x2c, + 0xed, 0x63, 0xcf, 0xe0, 0x3a, 0x6f, 0x46, 0xe3, 0x89, 0xef, 0xe1, 0x78, 0x24, 0x19, 0xc3, 0xac, + 0x73, 0x75, 0x6a, 0x13, 0xbc, 0x4a, 0x9b, 0x95, 0xcc, 0xb1, 0xa7, 0xca, 0x22, 0x1f, 0x7a, 0xf6, + 0xb0, 0xa0, 0x0e, 0x83, 0x79, 0x17, 0x35, 0xc2, 0xd2, 0x7a, 0x7a, 0x1f, 0xb4, 0x70, 0x68, 0xb9, + 0x56, 0x90, 0x52, 0xdd, 0x79, 0xb3, 0x58, 0x63, 0x78, 0xa2, 0xb4, 0xbc, 0x09, 0x30, 0x9e, 0x86, + 0x91, 0x49, 0x0e, 0x3f, 0x2a, 0x10, 0x37, 0x42, 0xe8, 0x44, 0x46, 0xbf, 0x09, 0x2b, 0xed, 0xd8, + 0x3b, 0x30, 0x8e, 0x37, 0x91, 0x97, 0x8f, 0xd2, 0xf9, 0x50, 0x62, 0xd7, 0x93, 0x5d, 0x6b, 0x22, + 0xee, 0x43, 0x7e, 0x6c, 0x4d, 0xe4, 0x4d, 0xa4, 0x38, 0x2a, 0xbe, 0xc4, 0x3e, 0xd8, 0xb5, 0x26, + 0x6c, 0x63, 0x46, 0xa2, 0x1b, 0x5f, 0x40, 0x51, 0x01, 0x7e, 0x94, 0xf9, 0xf4, 0xbf, 0x5d, 0x82, + 0xd2, 0x56, 0xda, 0xbb, 0x17, 0xf5, 0xf0, 0x28, 0x98, 0x7a, 0xd4, 0x44, 0xf9, 0xfc, 0xd6, 0xd0, + 0xf2, 0x06, 0x12, 0xa4, 0x18, 0xea, 0xd2, 0x2b, 0x18, 0xea, 0x4d, 0x00, 0xb9, 0x3c, 0x9d, 0x91, + 0xd2, 0x01, 0x8a, 0x01, 0x2e, 0xcc, 0xf6, 0xe8, 0x6c, 0xf1, 0xfd, 0xe9, 0xc2, 0x0f, 0xbf, 0x3f, + 0xbd, 0xbc, 0xf0, 0xfe, 0xf4, 0xbb, 0x89, 0xd8, 0x4f, 0x7b, 0xe3, 0xe8, 0x4c, 0x3e, 0xf5, 0xa3, + 0x84, 0x7c, 0xdc, 0x13, 0x47, 0x67, 0xe2, 0x6b, 0xa8, 0xa9, 0xd6, 0xc9, 0xf2, 0x20, 0x13, 0x34, + 0x51, 0xe2, 0xd8, 0x1d, 0xb8, 0x1a, 0xa5, 0x93, 0xd9, 0x8d, 0xa2, 0xfc, 0x9a, 0x3b, 0xda, 0xff, + 0x52, 0x0e, 0x84, 0x74, 0xe6, 0xda, 0x9e, 0xba, 0xee, 0xc0, 0x3e, 0xa3, 0xfd, 0xe8, 0x3e, 0xac, + 0x67, 0x2e, 0x1f, 0xa5, 0xb4, 0xac, 0xb5, 0xd4, 0x6d, 0x23, 0x15, 0xa8, 0x7a, 0x2e, 0x2c, 0xf1, + 0xd2, 0xc2, 0xb0, 0xc4, 0x8b, 0xc3, 0x1d, 0xdf, 0x86, 0x72, 0x3a, 0xa8, 0x2f, 0xab, 0xdd, 0x74, + 0x6d, 0x84, 0xe3, 0xf9, 0xea, 0xff, 0xfd, 0x12, 0x40, 0xe2, 0x70, 0xf6, 0xa7, 0x7d, 0xf9, 0x7d, + 0xc1, 0x90, 0xe4, 0x17, 0x0d, 0xc9, 0x3d, 0xd0, 0xd2, 0x74, 0xa9, 0xe8, 0xd2, 0xb5, 0x84, 0x50, + 0xa9, 0x9f, 0x4e, 0x98, 0x8e, 0xd0, 0x4b, 0xb1, 0xdc, 0xe4, 0x7d, 0x61, 0x46, 0xb2, 0x10, 0x2b, + 0x19, 0x56, 0xd1, 0x09, 0x59, 0x12, 0x20, 0xf9, 0x57, 0xe5, 0x24, 0x77, 0x15, 0x7f, 0x1a, 0xc5, + 0x37, 0x8b, 0x56, 0xa5, 0xfc, 0x2b, 0x4b, 0x7a, 0xc1, 0x68, 0x75, 0xb3, 0xe8, 0x73, 0x28, 0x1d, + 0x4e, 0x5d, 0xd7, 0x8c, 0xec, 0x33, 0x75, 0xdb, 0xa9, 0x9e, 0xf1, 0xd5, 0x4b, 0x0d, 0xaf, 0x51, + 0x3c, 0x94, 0x09, 0xfd, 0x9f, 0x2d, 0xc2, 0x32, 0x1b, 0xe5, 0xbf, 0x80, 0x52, 0x18, 0x8d, 0xa3, + 0xf4, 0xb5, 0x19, 0xe9, 0xc7, 0x45, 0x78, 0xba, 0xf5, 0x42, 0xdb, 0x06, 0x4b, 0x4d, 0x48, 0x4b, + 0xbc, 0x6e, 0x03, 0x96, 0xc3, 0xc8, 0x9e, 0x84, 0x32, 0xa6, 0x0c, 0x27, 0xc4, 0x1d, 0x58, 0xf6, + 0xfc, 0xd1, 0xec, 0x53, 0x26, 0x5d, 0xd4, 0x04, 0x19, 0x21, 0x74, 0x58, 0x89, 0x47, 0x7c, 0xee, + 0xea, 0x0a, 0x63, 0x28, 0x1e, 0x9d, 0x6d, 0x21, 0xf7, 0x55, 0xd1, 0xba, 0xe3, 0x34, 0x2a, 0x2e, + 0x74, 0x96, 0x67, 0x1d, 0xa9, 0x57, 0x10, 0x64, 0x52, 0xdc, 0x81, 0x32, 0xfe, 0x7c, 0x11, 0x38, + 0x91, 0xdd, 0x7f, 0xa4, 0x64, 0x8a, 0x14, 0x48, 0xdc, 0x02, 0x18, 0xd9, 0x91, 0x3d, 0x8c, 0xfa, + 0xdf, 0xbb, 0xca, 0x38, 0x99, 0x82, 0x88, 0xaf, 0x41, 0x1c, 0x58, 0xc3, 0x93, 0xa3, 0x80, 0xae, + 0x82, 0x7e, 0x3f, 0xb5, 0x03, 0x27, 0x66, 0xdc, 0xe5, 0x54, 0xa7, 0x18, 0xeb, 0x09, 0xd9, 0x2f, + 0x98, 0x4a, 0x5c, 0x85, 0x95, 0xb1, 0x75, 0xb6, 0xe5, 0x4f, 0xa4, 0xf5, 0x5e, 0xa6, 0xc4, 0x23, + 0xb8, 0x8a, 0x32, 0x4a, 0x3a, 0xb2, 0x8a, 0x74, 0x8f, 0x64, 0x0e, 0x8d, 0x12, 0x4c, 0x12, 0x52, + 0x45, 0x9e, 0xa1, 0x6f, 0xc2, 0x86, 0x32, 0xce, 0xab, 0x17, 0x8c, 0x86, 0x4e, 0x1c, 0xd0, 0x74, + 0x6e, 0xf2, 0x5f, 0x96, 0xc4, 0x5b, 0x29, 0x5a, 0xf1, 0x36, 0x54, 0xf1, 0xc3, 0x81, 0x1d, 0x4d, + 0x03, 0x0f, 0xf7, 0x3e, 0x96, 0x28, 0x50, 0x40, 0x34, 0x14, 0x8c, 0xfd, 0xbd, 0x65, 0x82, 0x6f, + 0x28, 0xb0, 0xc4, 0x50, 0x8d, 0xa1, 0x74, 0x49, 0xe1, 0x11, 0x5c, 0x65, 0x4f, 0xd2, 0xf0, 0x7b, + 0x57, 0xca, 0x59, 0x66, 0x72, 0x75, 0xa6, 0x68, 0x5c, 0x26, 0x6c, 0xff, 0x7b, 0x97, 0x45, 0x2d, + 0xde, 0xeb, 0x7b, 0x70, 0x75, 0xea, 0x05, 0x76, 0xe8, 0xbb, 0x2f, 0xe3, 0xc8, 0xd1, 0xc7, 0x0e, + 0x8a, 0xd7, 0x5a, 0xfa, 0xca, 0xe1, 0x7e, 0x4c, 0x23, 0x2f, 0x1f, 0x7a, 0x91, 0xb1, 0x31, 0x9d, + 0x07, 0x86, 0xe2, 0xb7, 0xe1, 0x26, 0x39, 0x4a, 0x8d, 0xe5, 0x13, 0x49, 0xb2, 0x6f, 0x42, 0x14, + 0x17, 0xa6, 0xa3, 0x43, 0xa9, 0x37, 0xd7, 0x91, 0x46, 0xbd, 0xa2, 0xc4, 0x3d, 0x12, 0xf6, 0xbc, + 0xfd, 0xd1, 0xa1, 0xf8, 0x29, 0xac, 0x51, 0xfe, 0x38, 0x64, 0x35, 0x0b, 0xfa, 0x31, 0x7b, 0x7d, + 0xee, 0xd8, 0xa7, 0x86, 0xc2, 0x19, 0xb5, 0x97, 0xe9, 0x64, 0x28, 0xbe, 0x84, 0xf2, 0x30, 0x79, + 0xc0, 0x45, 0x5e, 0xad, 0x59, 0xf0, 0x8e, 0xd4, 0xc4, 0x1e, 0x1a, 0x69, 0x4a, 0xd1, 0x85, 0x0d, + 0xf5, 0x10, 0x61, 0x66, 0x30, 0xf9, 0x5a, 0xdc, 0x1b, 0x99, 0x07, 0x09, 0xf7, 0x5c, 0xcb, 0x8b, + 0x47, 0xf1, 0xdc, 0xb8, 0x2c, 0x33, 0xa6, 0x07, 0x56, 0xff, 0x5d, 0xa8, 0x66, 0x16, 0xe5, 0x9c, + 0x4b, 0x57, 0xbf, 0xd5, 0x69, 0x35, 0x07, 0xec, 0x74, 0x21, 0x9d, 0x8c, 0x96, 0x52, 0xde, 0x48, + 0x85, 0x94, 0x33, 0x06, 0xbd, 0xb2, 0xb3, 0xdb, 0x32, 0x9e, 0xb4, 0xc8, 0x5f, 0x26, 0xaf, 0xe5, + 0xf5, 0x7f, 0x79, 0x09, 0xd6, 0x07, 0x81, 0xe5, 0x85, 0xf2, 0xc1, 0x73, 0x2f, 0x0a, 0x7c, 0x57, + 0x7c, 0x0d, 0xc5, 0x68, 0xe8, 0xa6, 0xb9, 0xc4, 0x6d, 0xb5, 0x27, 0xcd, 0x90, 0x3e, 0x18, 0x0c, + 0xd9, 0xe1, 0x7d, 0x35, 0xe2, 0x1f, 0xe2, 0x23, 0x58, 0x3e, 0xb0, 0x8f, 0x1c, 0x4f, 0x6e, 0xcb, + 0x57, 0x66, 0x33, 0x6e, 0x22, 0x72, 0xe7, 0x92, 0xc1, 0x54, 0xe2, 0x13, 0x58, 0x91, 0x47, 0x75, + 0xf9, 0xf4, 0xbd, 0x93, 0xf4, 0x87, 0x10, 0xbb, 0x73, 0xc9, 0x90, 0x74, 0xe2, 0x0b, 0x28, 0x06, + 0xbe, 0x7c, 0xdd, 0xb0, 0x90, 0xe6, 0x81, 0x49, 0x1e, 0x43, 0xe2, 0x77, 0x2e, 0x19, 0x31, 0xad, + 0xfe, 0x00, 0x56, 0x65, 0x65, 0xb1, 0x1b, 0x36, 0x5b, 0x4f, 0xda, 0xb2, 0x07, 0x9b, 0xbd, 0xdd, + 0xdd, 0xf6, 0x80, 0x63, 0x80, 0x1b, 0xbd, 0x4e, 0x67, 0xb3, 0xd1, 0x7c, 0xa6, 0x2d, 0x6d, 0x16, + 0x61, 0x85, 0xd7, 0xae, 0xfe, 0x8f, 0xe7, 0x60, 0x6d, 0xa6, 0x01, 0xe2, 0x31, 0x14, 0xc6, 0xea, + 0xf5, 0xa5, 0x9a, 0x3a, 0x81, 0x9f, 0x21, 0x4a, 0xa5, 0xd9, 0x3c, 0x86, 0x39, 0xf4, 0xaf, 0xa0, + 0x96, 0x85, 0xa7, 0x5c, 0x7a, 0xaa, 0x50, 0x32, 0x5a, 0x8d, 0x2d, 0xb3, 0xd7, 0xed, 0x7c, 0xcb, + 0x5e, 0x79, 0x94, 0x7c, 0x61, 0xb4, 0xc9, 0x97, 0xe6, 0x77, 0x40, 0x9b, 0xed, 0x18, 0xf1, 0x04, + 0xd6, 0x50, 0x04, 0x75, 0x6d, 0x76, 0x82, 0x4c, 0x86, 0xec, 0xd6, 0x82, 0x9e, 0x94, 0x64, 0x7c, + 0xc1, 0x7d, 0x98, 0x49, 0xeb, 0xbf, 0x0b, 0x62, 0xbe, 0x07, 0xff, 0xf4, 0x8a, 0xff, 0xbf, 0x72, + 0x50, 0xc0, 0x09, 0x2f, 0xde, 0x86, 0x65, 0x3e, 0x35, 0xce, 0xa5, 0xef, 0x5b, 0x12, 0xab, 0xc5, + 0x69, 0x41, 0x38, 0xf1, 0x01, 0xe4, 0xa3, 0xa1, 0x8a, 0xf6, 0x7d, 0xed, 0x82, 0xc9, 0xb7, 0x73, + 0xc9, 0x40, 0x2a, 0x71, 0x0f, 0xf2, 0xa3, 0x91, 0x0a, 0x15, 0x97, 0xf2, 0x29, 0xd8, 0xb2, 0x0f, + 0x1d, 0xcf, 0x91, 0x4f, 0xee, 0x21, 0x89, 0x78, 0x07, 0xf2, 0xa3, 0xa1, 0x9b, 0x8d, 0xfb, 0xc7, + 0xc7, 0xfd, 0x71, 0x81, 0xa3, 0xa1, 0x8b, 0xea, 0x68, 0x14, 0x9c, 0x9b, 0xc1, 0xd4, 0xa3, 0x48, + 0x29, 0xea, 0x75, 0xca, 0x32, 0x8a, 0xb8, 0x53, 0x0a, 0xb7, 0x12, 0xca, 0xb0, 0xc1, 0xf2, 0xd9, + 0x36, 0x65, 0x3e, 0x75, 0x42, 0xf9, 0xc0, 0xdb, 0xe6, 0x0a, 0x14, 0xb0, 0x74, 0xfd, 0x43, 0x7a, + 0x55, 0x68, 0x3a, 0xf6, 0x70, 0x2f, 0x94, 0x7a, 0xda, 0xfc, 0x33, 0xd0, 0x12, 0xa3, 0xff, 0xbd, + 0x3c, 0x94, 0x53, 0xf5, 0x11, 0x9f, 0x41, 0x71, 0x94, 0x5d, 0x88, 0xd7, 0xe7, 0x2a, 0xfd, 0x60, + 0x4b, 0x2d, 0xc1, 0x91, 0x9c, 0xde, 0x74, 0x9b, 0x22, 0x32, 0x5f, 0x5a, 0x81, 0xc3, 0xb7, 0xbe, + 0x97, 0xd2, 0xd7, 0x1a, 0xfa, 0x76, 0xf4, 0x5c, 0x61, 0x76, 0x2e, 0x19, 0x95, 0x30, 0x95, 0x26, + 0x93, 0x9f, 0x6c, 0x52, 0x3e, 0xf3, 0xbe, 0x30, 0x03, 0x77, 0x2e, 0x19, 0x0a, 0x8f, 0xa4, 0xf6, + 0x99, 0x3d, 0x9c, 0x46, 0xca, 0xe4, 0x57, 0x55, 0x0d, 0x22, 0x20, 0xbd, 0xed, 0xce, 0x3f, 0xc5, + 0x43, 0xdc, 0x8a, 0x2d, 0xd7, 0xf5, 0x49, 0x92, 0x5f, 0x4e, 0x9f, 0xd4, 0x6d, 0xc5, 0x70, 0x7e, + 0x4b, 0x5e, 0xa5, 0xc4, 0xbb, 0xb0, 0xec, 0x47, 0xc7, 0xb6, 0x32, 0x30, 0xa8, 0xf7, 0x89, 0x10, + 0xb4, 0xd5, 0xec, 0xe0, 0x4c, 0x21, 0xb4, 0xfe, 0xfb, 0x39, 0x58, 0x95, 0x3d, 0x20, 0xd6, 0xa1, + 0xda, 0x6f, 0x0d, 0xcc, 0xe7, 0x0d, 0xa3, 0xdd, 0xd8, 0xec, 0xb4, 0x64, 0xb8, 0xc2, 0x27, 0x46, + 0xa3, 0x2b, 0x19, 0xa4, 0xd1, 0x7a, 0xde, 0x7b, 0xd6, 0x62, 0x3f, 0xb9, 0xad, 0x56, 0xf7, 0x5b, + 0x2d, 0xcf, 0x2e, 0xa8, 0xad, 0xbd, 0x86, 0x81, 0xbc, 0xb2, 0x0c, 0xab, 0xad, 0x6f, 0x5a, 0xcd, + 0x7d, 0x62, 0x96, 0x35, 0x80, 0xad, 0x56, 0xa3, 0xd3, 0xe9, 0x35, 0x91, 0x79, 0xae, 0x08, 0x01, + 0xb5, 0xa6, 0xd1, 0x6a, 0x0c, 0x5a, 0x66, 0xa3, 0xd9, 0xec, 0xed, 0x77, 0x07, 0xda, 0x2a, 0x7e, + 0xb1, 0xd1, 0x19, 0xb4, 0x8c, 0x18, 0x44, 0x2f, 0xc1, 0x6e, 0x19, 0xbd, 0xbd, 0x18, 0x52, 0xda, + 0x2c, 0xc1, 0xea, 0x90, 0xc7, 0x4a, 0xff, 0x77, 0xd6, 0xd9, 0x45, 0x24, 0x99, 0x9a, 0xe2, 0x4b, + 0x28, 0x8e, 0x46, 0x99, 0x31, 0xbe, 0xb9, 0x68, 0x0a, 0x3f, 0xd8, 0x1a, 0xa9, 0x61, 0xe6, 0x1f, + 0xe2, 0x2d, 0xb5, 0x90, 0x96, 0xe6, 0x16, 0x92, 0x5a, 0x46, 0x3f, 0x83, 0x35, 0xf9, 0x5c, 0x4d, + 0x7c, 0xba, 0x9c, 0x59, 0x25, 0x4d, 0x42, 0x6e, 0x49, 0xdc, 0xce, 0x25, 0xa3, 0x36, 0xcc, 0x40, + 0xc4, 0x4f, 0xa1, 0x66, 0xf1, 0x99, 0x6d, 0xfa, 0x74, 0x3a, 0xde, 0x44, 0x1b, 0x74, 0x64, 0x9b, + 0x64, 0xaf, 0x5a, 0x69, 0x00, 0x4e, 0xc4, 0x51, 0xe0, 0x4f, 0x92, 0xcc, 0xcb, 0x99, 0xfb, 0x35, + 0x81, 0x3f, 0x49, 0xe5, 0xad, 0x8c, 0x52, 0x69, 0xf1, 0x05, 0x54, 0x64, 0xcd, 0x93, 0xf3, 0x89, + 0x78, 0xc9, 0x72, 0xb5, 0x49, 0xe7, 0xd8, 0xb9, 0x64, 0x94, 0x87, 0x49, 0x52, 0x3c, 0x42, 0x45, + 0x23, 0xd1, 0xd0, 0x56, 0xd3, 0x73, 0x8d, 0x6a, 0xab, 0x72, 0x81, 0x15, 0xa7, 0xc4, 0x27, 0x00, + 0x54, 0x4f, 0xce, 0x53, 0xcc, 0xdc, 0x3c, 0x0d, 0xfc, 0x89, 0xca, 0x52, 0x1a, 0xa9, 0x44, 0xaa, + 0x7a, 0x6c, 0xfa, 0x2c, 0xcd, 0x57, 0x8f, 0x65, 0x99, 0xb8, 0x7a, 0x6c, 0x05, 0x8d, 0xab, 0xc7, + 0xd9, 0x60, 0xae, 0x7a, 0x2a, 0x17, 0x57, 0x8f, 0x33, 0xa9, 0xea, 0x71, 0x9e, 0xf2, 0x6c, 0xf5, + 0x54, 0x16, 0xaa, 0x1e, 0xe7, 0xf8, 0xe9, 0x9c, 0x6a, 0x59, 0xb9, 0x50, 0xb5, 0xc4, 0x61, 0xcb, + 0x2a, 0x97, 0x3f, 0x85, 0x5a, 0x78, 0xec, 0x9f, 0xa6, 0x18, 0x48, 0x35, 0x9d, 0xbb, 0x7f, 0xec, + 0x9f, 0xa6, 0x39, 0x48, 0x35, 0x4c, 0x03, 0xb0, 0xb6, 0xdc, 0x44, 0x7a, 0xce, 0xa0, 0x96, 0xae, + 0x2d, 0xb5, 0x10, 0x05, 0x2f, 0xac, 0xad, 0xa5, 0x12, 0xd8, 0x29, 0xc9, 0x59, 0x4d, 0x28, 0x4f, + 0x5f, 0x32, 0xf7, 0x35, 0xe5, 0x97, 0x20, 0x3e, 0xb5, 0x09, 0x71, 0x6e, 0x4d, 0xbd, 0x74, 0x36, + 0x2d, 0x3d, 0xb7, 0xf6, 0xbd, 0x4c, 0xc6, 0x0a, 0x93, 0xca, 0xac, 0xc9, 0xaa, 0x08, 0xed, 0xef, + 0xa7, 0x28, 0xf0, 0xc9, 0x7b, 0xd9, 0x99, 0x55, 0xd1, 0x97, 0xb8, 0x64, 0x55, 0x28, 0x48, 0x3c, + 0xaf, 0xe3, 0xec, 0x62, 0x76, 0x5e, 0xa7, 0x32, 0xd3, 0xbc, 0x8e, 0xb3, 0xc6, 0x0b, 0x2a, 0xce, + 0x7b, 0x79, 0x6e, 0x41, 0xa5, 0x32, 0xf3, 0x82, 0x8a, 0x73, 0x3f, 0x02, 0x39, 0x9b, 0xb8, 0x73, + 0x33, 0xb7, 0xb7, 0xb9, 0xd6, 0xb2, 0x77, 0x61, 0x18, 0xa7, 0x70, 0xae, 0x06, 0x36, 0xaa, 0xb2, + 0x72, 0x2a, 0x5c, 0xc9, 0xbc, 0x8d, 0x4d, 0x98, 0x78, 0x29, 0x05, 0x49, 0x32, 0xf5, 0xb1, 0x89, + 0x13, 0x05, 0xf5, 0xd1, 0xfc, 0xc7, 0xf6, 0x9c, 0x28, 0x48, 0x3e, 0x86, 0x29, 0xf1, 0x11, 0xd0, + 0x34, 0xe4, 0x2c, 0x76, 0x9a, 0x75, 0x63, 0xb7, 0xc8, 0x0c, 0xc5, 0x91, 0xfc, 0x8d, 0x93, 0x45, + 0x7e, 0x63, 0x38, 0x1a, 0xd6, 0x0f, 0xd3, 0x93, 0x85, 0x3f, 0xd1, 0xdc, 0x6a, 0xe2, 0x64, 0x61, + 0xa2, 0xe6, 0x68, 0x28, 0xee, 0x03, 0xe5, 0x26, 0xfa, 0xa3, 0xcc, 0xfb, 0x77, 0x81, 0x3f, 0x61, + 0xea, 0x55, 0x24, 0x40, 0x5a, 0x6c, 0x81, 0xeb, 0x7b, 0xaa, 0xe1, 0xc7, 0x99, 0x16, 0x20, 0x22, + 0x66, 0x06, 0xc3, 0x38, 0xa5, 0xff, 0x93, 0x2b, 0xb0, 0x2a, 0x79, 0xad, 0xb8, 0x0c, 0x6b, 0x92, + 0xe5, 0x6f, 0x35, 0x06, 0x8d, 0xcd, 0x46, 0x1f, 0x85, 0x34, 0x01, 0x35, 0xe6, 0xf9, 0x31, 0x2c, + 0x87, 0xfb, 0x00, 0x31, 0xfd, 0x18, 0x44, 0x6f, 0x60, 0xca, 0xbc, 0xec, 0x8d, 0x9c, 0x17, 0x6b, + 0x50, 0xe6, 0x8c, 0x0c, 0xa0, 0xe8, 0xc9, 0x94, 0x8b, 0xd3, 0xcb, 0xa9, 0x2c, 0xec, 0x4f, 0xbe, + 0x92, 0x64, 0x61, 0xc0, 0x6a, 0x9c, 0x45, 0x39, 0x9c, 0x0b, 0xa8, 0x0d, 0x8c, 0xfd, 0x6e, 0x33, + 0xf9, 0x4e, 0x89, 0x22, 0xde, 0x72, 0x31, 0xcf, 0xdb, 0xad, 0x17, 0x1a, 0xd0, 0x63, 0x9b, 0x54, + 0x0a, 0xa5, 0xc9, 0x11, 0x9d, 0x0a, 0xa1, 0x64, 0x45, 0x5c, 0x83, 0xcb, 0xfd, 0x9d, 0xde, 0x0b, + 0x93, 0x33, 0xc5, 0x4d, 0xa8, 0x8a, 0x0d, 0xd0, 0x52, 0x08, 0x2e, 0xbe, 0x86, 0x9f, 0x24, 0xa8, + 0x22, 0xec, 0x6b, 0x6b, 0xf4, 0x60, 0x0e, 0xc2, 0x06, 0xbc, 0xef, 0x6a, 0xd8, 0x14, 0xce, 0xda, + 0xeb, 0xec, 0xef, 0x76, 0xfb, 0xda, 0x3a, 0x56, 0x82, 0x20, 0x5c, 0x73, 0x11, 0x17, 0x93, 0xec, + 0xd6, 0x97, 0x69, 0x03, 0x47, 0xd8, 0x8b, 0x86, 0xd1, 0x6d, 0x77, 0x9f, 0xf4, 0xb5, 0x8d, 0xb8, + 0xe4, 0x96, 0x61, 0xf4, 0x8c, 0xbe, 0x76, 0x25, 0x06, 0xf4, 0x07, 0x8d, 0xc1, 0x7e, 0x5f, 0xbb, + 0x1a, 0xd7, 0x72, 0xcf, 0xe8, 0x35, 0x5b, 0xfd, 0x7e, 0xa7, 0xdd, 0x1f, 0x68, 0xd7, 0xc4, 0x15, + 0x58, 0x4f, 0x6a, 0xa4, 0x88, 0xeb, 0xa9, 0x8a, 0x1a, 0x4f, 0x5a, 0x03, 0xed, 0x7a, 0x5c, 0x8d, + 0x66, 0xaf, 0xd3, 0x69, 0x90, 0xab, 0xfb, 0x0d, 0x24, 0xa2, 0x0b, 0x1c, 0xb2, 0x35, 0x6f, 0x60, + 0xbd, 0xf6, 0xbb, 0x69, 0xd0, 0xcd, 0xd4, 0xd4, 0xe8, 0xb7, 0x7e, 0xb1, 0xdf, 0xea, 0x36, 0x5b, + 0xda, 0x9b, 0xc9, 0xd4, 0x88, 0x61, 0xb7, 0xe2, 0xa9, 0x11, 0x83, 0x6e, 0xc7, 0xdf, 0x54, 0xa0, + 0xbe, 0x76, 0x27, 0xee, 0xb0, 0xfd, 0xbd, 0x27, 0x46, 0x63, 0xab, 0xa5, 0xe9, 0x08, 0x31, 0x5a, + 0xdd, 0xc6, 0xae, 0x1a, 0xd8, 0xb7, 0x53, 0x03, 0xbb, 0xd7, 0x1e, 0x18, 0xda, 0xdd, 0x78, 0x20, + 0x29, 0xf9, 0x8e, 0x78, 0x03, 0xae, 0xa5, 0xa7, 0x9c, 0xf9, 0xa2, 0x3d, 0xd8, 0x91, 0xf7, 0x2c, + 0xde, 0x65, 0xdf, 0x7b, 0x42, 0x36, 0xb7, 0x9a, 0x7c, 0xa1, 0x84, 0xf2, 0x62, 0xea, 0x9e, 0x5e, + 0x28, 0xbe, 0xa5, 0xbd, 0x75, 0x7f, 0x4d, 0x76, 0x45, 0xb7, 0x4b, 0x37, 0x2d, 0xfa, 0x9b, 0x15, + 0x94, 0xdc, 0x94, 0x08, 0xa2, 0x3f, 0x05, 0xd1, 0x9f, 0x1e, 0x84, 0xc3, 0xc0, 0xa1, 0x90, 0x0d, + 0x32, 0xc0, 0x85, 0x80, 0xc2, 0x61, 0xe0, 0x8f, 0x95, 0xa7, 0x0e, 0xfe, 0x16, 0x77, 0xa0, 0x3c, + 0x99, 0x1e, 0xd0, 0x55, 0x81, 0x24, 0x56, 0x79, 0x1a, 0xa4, 0xff, 0x2f, 0x39, 0xa8, 0x65, 0xc5, + 0x0f, 0x3a, 0x05, 0x3a, 0x34, 0x3d, 0x3f, 0xe2, 0x27, 0xcd, 0x42, 0x65, 0xf3, 0x75, 0x0e, 0xbb, + 0x7e, 0x44, 0x6f, 0x9a, 0x85, 0x19, 0x47, 0xb9, 0xa5, 0x19, 0x47, 0xb9, 0x36, 0x5c, 0x0e, 0x53, + 0xd5, 0x33, 0x33, 0x0f, 0xca, 0xd5, 0xe3, 0x47, 0x87, 0x67, 0xea, 0x6f, 0x88, 0x70, 0xbe, 0x4d, + 0x32, 0xe2, 0x7c, 0x21, 0x8e, 0x38, 0x2f, 0x1e, 0x42, 0x51, 0xfa, 0xb7, 0x86, 0x52, 0x8c, 0xb9, + 0x9a, 0x88, 0x69, 0xf8, 0x79, 0xf9, 0xba, 0x62, 0x68, 0xc4, 0x74, 0xfa, 0x9f, 0x87, 0x6a, 0x46, + 0x42, 0x22, 0xc3, 0xe0, 0x61, 0xb6, 0x75, 0x45, 0xe7, 0xf0, 0x07, 0x34, 0x2d, 0xfd, 0xf5, 0xfc, + 0x0f, 0xfc, 0xfa, 0x5f, 0xcb, 0x41, 0x25, 0x2d, 0x63, 0xfd, 0xe6, 0x5f, 0xbf, 0x0d, 0x65, 0xf5, + 0x5b, 0xbd, 0xef, 0x5c, 0x30, 0x40, 0x81, 0xc8, 0xdb, 0xb5, 0xcc, 0x07, 0x77, 0xdb, 0x27, 0xfd, + 0xb8, 0xdb, 0xd2, 0x20, 0x72, 0x62, 0x3c, 0xb6, 0x87, 0x27, 0xdb, 0xcf, 0x90, 0x40, 0x39, 0x31, + 0xc6, 0x10, 0xfd, 0x36, 0x94, 0xb6, 0x4f, 0xd4, 0x75, 0xdf, 0xf4, 0x03, 0x82, 0x25, 0x0e, 0xa4, + 0xaf, 0xff, 0x41, 0x0e, 0x6a, 0x89, 0xe9, 0x8c, 0xee, 0x50, 0xd4, 0x60, 0x69, 0x74, 0x20, 0xa7, + 0xdd, 0xd2, 0xe8, 0x20, 0x71, 0x54, 0x5d, 0x4a, 0x3b, 0xaa, 0xbe, 0x2d, 0x0b, 0xcb, 0xa7, 0x37, + 0x97, 0xf8, 0x5b, 0x32, 0x4c, 0xff, 0x23, 0xa8, 0xe0, 0x7f, 0xb2, 0x00, 0x05, 0xf6, 0x28, 0x1b, + 0xfa, 0x2c, 0x21, 0xce, 0x10, 0x91, 0x36, 0x29, 0x5d, 0x60, 0x2f, 0x78, 0x50, 0x88, 0x1e, 0xba, + 0xfa, 0x07, 0xcb, 0x50, 0x4e, 0x49, 0xac, 0x3f, 0x68, 0x9a, 0xdf, 0x84, 0x52, 0xf2, 0xbc, 0x8d, + 0x8c, 0x8d, 0x1e, 0x03, 0x32, 0x63, 0x95, 0x9f, 0x19, 0x2b, 0xf2, 0x17, 0xa7, 0x80, 0xac, 0x89, + 0xbf, 0x38, 0x25, 0xb3, 0x67, 0x06, 0xcb, 0xaf, 0x39, 0x5c, 0xfe, 0x14, 0x2a, 0x29, 0x83, 0xbf, + 0xf2, 0x2c, 0x9d, 0xa5, 0x2f, 0x27, 0xc6, 0xff, 0x50, 0x5c, 0x81, 0x95, 0xc3, 0x13, 0x73, 0x74, + 0xc0, 0x2e, 0x17, 0x25, 0x63, 0xf9, 0xf0, 0x64, 0xeb, 0x80, 0x5c, 0x4c, 0x0e, 0x63, 0x21, 0x8d, + 0xcd, 0xb0, 0xc5, 0x43, 0x25, 0x8a, 0xdd, 0x83, 0xd5, 0xc3, 0x93, 0x74, 0x84, 0xe5, 0xb9, 0x2e, + 0x5f, 0x39, 0x3c, 0xa1, 0x20, 0xbf, 0x1f, 0xc3, 0x86, 0x94, 0x14, 0xac, 0x50, 0x59, 0x25, 0x71, + 0x89, 0xf2, 0x73, 0x82, 0xeb, 0x8c, 0x6b, 0x84, 0x6c, 0x93, 0xc4, 0x19, 0xa7, 0x43, 0x25, 0x35, + 0x01, 0xd9, 0x9c, 0x5a, 0x32, 0x32, 0x30, 0xf1, 0x18, 0x2a, 0x87, 0x27, 0x3c, 0xa0, 0x03, 0x7f, + 0xd7, 0x96, 0x11, 0x87, 0x36, 0x66, 0x87, 0x92, 0x2e, 0xb9, 0x64, 0x28, 0xc5, 0x55, 0x58, 0x31, + 0xac, 0xd3, 0xfe, 0x2f, 0x3a, 0x24, 0xae, 0x96, 0x0c, 0x99, 0x12, 0x4d, 0xb8, 0x92, 0xb2, 0x83, + 0x1e, 0x9e, 0x98, 0x1c, 0x7d, 0x47, 0x99, 0x41, 0xe7, 0xad, 0xb9, 0x09, 0xf5, 0xf6, 0x09, 0x07, + 0x3e, 0x0c, 0xc5, 0x97, 0xb0, 0x76, 0x78, 0x42, 0xa7, 0x0f, 0xa6, 0x8c, 0x66, 0x23, 0x05, 0xd4, + 0xb5, 0xc4, 0xe1, 0x4a, 0x1e, 0x0b, 0x1d, 0x9e, 0x60, 0x2f, 0x6d, 0x32, 0x95, 0x68, 0xc2, 0x7a, + 0xbc, 0x50, 0x63, 0x7e, 0x21, 0x5e, 0xc9, 0x2f, 0xb4, 0xd1, 0x0c, 0x44, 0xb4, 0xe0, 0xf6, 0x30, + 0xb2, 0x42, 0x93, 0xb5, 0x77, 0x64, 0xa4, 0x93, 0xc0, 0x8f, 0xfc, 0xa1, 0xef, 0xc6, 0x0e, 0xaf, + 0x1c, 0x51, 0xf5, 0x26, 0x92, 0xb5, 0x14, 0xd5, 0x9e, 0x24, 0x92, 0xee, 0xaf, 0x1c, 0xb7, 0x4b, + 0xff, 0x8f, 0x72, 0x50, 0x4b, 0xf4, 0x2e, 0x64, 0x47, 0xe2, 0x3e, 0xbf, 0x7f, 0xcc, 0xba, 0x6e, + 0x7d, 0x56, 0x35, 0x43, 0x92, 0x07, 0x83, 0xf3, 0x09, 0xbf, 0x83, 0xbc, 0xe8, 0x75, 0xb3, 0x45, + 0x67, 0x51, 0xf9, 0x45, 0x67, 0x51, 0xfa, 0x13, 0xc8, 0x0f, 0xce, 0x27, 0x6c, 0xe3, 0x43, 0x31, + 0x84, 0xed, 0x01, 0x2c, 0x80, 0xd0, 0xf5, 0xba, 0x67, 0xad, 0x6f, 0xf9, 0x55, 0x8b, 0x3d, 0xa3, + 0xbd, 0xdb, 0x30, 0xbe, 0x35, 0x11, 0x40, 0x82, 0xda, 0x76, 0xcf, 0x68, 0xb5, 0x9f, 0x74, 0x09, + 0x50, 0x20, 0x0b, 0x60, 0x52, 0xc5, 0xc6, 0x68, 0xb4, 0x7d, 0x92, 0x7e, 0x18, 0x2a, 0x97, 0x79, + 0x18, 0x2a, 0x7e, 0x43, 0x2d, 0xfd, 0x1e, 0x68, 0x14, 0x1f, 0x90, 0x89, 0x98, 0x1f, 0xc5, 0xcc, + 0x4d, 0xbc, 0x07, 0x85, 0xc3, 0x13, 0xfb, 0x3c, 0xab, 0x5c, 0x67, 0x59, 0x09, 0x11, 0xe8, 0x7f, + 0x94, 0x03, 0x91, 0xa9, 0x08, 0xeb, 0x7b, 0xbf, 0x69, 0x5d, 0xbe, 0x84, 0xba, 0x7a, 0x82, 0x98, + 0xa8, 0x52, 0x87, 0x5f, 0xb2, 0x4b, 0xaf, 0xf8, 0x49, 0xcc, 0x8f, 0xe4, 0x01, 0x36, 0xf1, 0x31, + 0xf0, 0x53, 0x9f, 0x74, 0x3b, 0xac, 0x70, 0x81, 0x6e, 0x6e, 0x24, 0x34, 0xc9, 0xdb, 0x9e, 0xe9, + 0x37, 0x4b, 0xf9, 0xdc, 0x6c, 0x2d, 0x19, 0x35, 0xe2, 0x7e, 0xfa, 0x5f, 0xc9, 0xc1, 0xe5, 0xec, + 0x84, 0xf8, 0x93, 0xb5, 0x32, 0xfb, 0x40, 0x6b, 0x7e, 0xf6, 0x81, 0xd6, 0x45, 0xf3, 0xa9, 0xb0, + 0x70, 0x3e, 0xfd, 0x85, 0x1c, 0x6c, 0xa4, 0x7a, 0x3f, 0xd1, 0xd0, 0xff, 0x8c, 0x6a, 0x96, 0x7a, + 0xa7, 0xb5, 0x90, 0x79, 0xa7, 0x55, 0xff, 0x3b, 0x39, 0xb8, 0x3a, 0x53, 0x13, 0xc3, 0xfe, 0x33, + 0xad, 0x4b, 0xf6, 0x3d, 0x57, 0x3a, 0xbb, 0x53, 0x2f, 0x3f, 0x20, 0x2f, 0x10, 0xd9, 0x07, 0x5a, + 0xc9, 0xab, 0xe0, 0x4d, 0xf9, 0x40, 0x90, 0x19, 0x9e, 0x7b, 0x43, 0x39, 0xd8, 0x25, 0x82, 0xf4, + 0xcf, 0xbd, 0x21, 0x6e, 0xd7, 0x63, 0x3b, 0x38, 0x52, 0xc6, 0x53, 0x4e, 0xe8, 0xff, 0x56, 0x0e, + 0xae, 0xcf, 0xb4, 0xac, 0x31, 0x8d, 0x7c, 0xe9, 0x04, 0xf4, 0x67, 0xd4, 0xb8, 0xdb, 0x40, 0x6f, + 0x97, 0x29, 0xef, 0xa3, 0xd4, 0xad, 0x21, 0xf9, 0x5d, 0x0d, 0xf2, 0x23, 0xeb, 0x5c, 0x06, 0x0e, + 0xc7, 0x9f, 0xb8, 0x8c, 0x8f, 0xfd, 0x69, 0x20, 0xaf, 0xb9, 0xd0, 0x6f, 0xfd, 0x33, 0x58, 0x4f, + 0xaa, 0xde, 0x94, 0x8f, 0xed, 0xde, 0x86, 0xb2, 0x67, 0x9f, 0x9a, 0xea, 0x29, 0x5e, 0x79, 0x01, + 0xd2, 0xb3, 0x4f, 0x25, 0x81, 0xbe, 0x9d, 0xe6, 0x90, 0x54, 0x9d, 0xeb, 0x50, 0xf4, 0xdd, 0x51, + 0xc6, 0xed, 0xd9, 0x77, 0x47, 0x0a, 0x85, 0xa5, 0xa5, 0x5a, 0xb9, 0xea, 0xd9, 0xa7, 0x34, 0x3b, + 0x4f, 0x65, 0x39, 0x8d, 0x91, 0x72, 0xd6, 0x5b, 0xe4, 0x43, 0x7f, 0x1d, 0x8a, 0x93, 0x20, 0xd3, + 0x4d, 0xab, 0x93, 0x80, 0x3f, 0x7b, 0x57, 0x5e, 0xaf, 0xbc, 0xc8, 0xd9, 0x93, 0x2f, 0x5c, 0x6a, + 0x90, 0x9f, 0xf8, 0xa1, 0xf4, 0x26, 0xc3, 0x9f, 0xfa, 0xe7, 0x92, 0x39, 0x92, 0x06, 0xce, 0x5f, + 0xd6, 0x20, 0xef, 0x8c, 0xce, 0xe8, 0xc3, 0x55, 0x03, 0x7f, 0x92, 0x44, 0x6d, 0x7f, 0x2f, 0x6f, + 0x78, 0xe2, 0x4f, 0x7d, 0x13, 0xca, 0x46, 0xc6, 0xdc, 0x50, 0x49, 0x59, 0xee, 0xc2, 0xec, 0x43, + 0x4c, 0x49, 0x07, 0x19, 0xe5, 0xc4, 0x70, 0x17, 0xea, 0xa1, 0x64, 0x87, 0xcf, 0xad, 0x60, 0x78, + 0x6c, 0x05, 0x1d, 0xdb, 0x3b, 0x8a, 0x8e, 0xb1, 0xcb, 0xe5, 0x53, 0xe9, 0xa9, 0xe6, 0x03, 0x83, + 0xd4, 0x74, 0xc0, 0x5e, 0x74, 0x89, 0x5c, 0x7a, 0xa2, 0x94, 0x3c, 0xfb, 0x54, 0xe6, 0x7f, 0x13, + 0x00, 0xfb, 0x5f, 0xa2, 0xe5, 0x15, 0x33, 0xdf, 0x1d, 0x31, 0x5a, 0x5f, 0x97, 0xed, 0x95, 0x81, + 0xef, 0xb7, 0xec, 0x43, 0xdd, 0x95, 0x23, 0xcf, 0x0d, 0x92, 0x9d, 0xf0, 0x1b, 0x0d, 0xa3, 0x78, + 0x0b, 0x2a, 0xca, 0x36, 0x44, 0x6f, 0x7f, 0xf1, 0xe7, 0xcb, 0x0a, 0xd6, 0x9d, 0x8e, 0xf5, 0x7f, + 0xbb, 0x00, 0x95, 0x06, 0x3b, 0x46, 0x4f, 0xce, 0x7b, 0x93, 0x48, 0xfc, 0x2e, 0x5c, 0x21, 0xa7, + 0x60, 0x0e, 0x38, 0x42, 0xfe, 0xc8, 0xec, 0x4f, 0xcb, 0x9d, 0x78, 0x3f, 0xd5, 0x89, 0x32, 0xcb, + 0x83, 0xfe, 0x89, 0x33, 0xe1, 0x18, 0x24, 0xed, 0xd1, 0x19, 0xb9, 0xd7, 0xb2, 0x0b, 0x0f, 0xbd, + 0x4f, 0x91, 0x45, 0x50, 0xfc, 0x73, 0x2c, 0x7e, 0x72, 0x22, 0x8b, 0x95, 0xde, 0x60, 0x08, 0xdc, + 0x3b, 0x61, 0x9a, 0xc4, 0x77, 0x6e, 0x6e, 0x5b, 0x96, 0xbe, 0x73, 0xc9, 0xfc, 0xee, 0xc3, 0xba, + 0x7c, 0x23, 0x83, 0xde, 0xe6, 0x34, 0x87, 0xfe, 0xe4, 0x5c, 0x7a, 0x08, 0xbc, 0x77, 0x41, 0x55, + 0xdb, 0x4c, 0x8a, 0x20, 0xae, 0xe7, 0x5a, 0x98, 0x85, 0x8a, 0xe7, 0x20, 0xb0, 0x4b, 0x27, 0xee, + 0x14, 0xf7, 0x33, 0xf5, 0x2a, 0x28, 0xdf, 0x97, 0xb8, 0xb7, 0xa0, 0xd4, 0xae, 0x7d, 0xba, 0x47, + 0xb4, 0xb2, 0x10, 0x2e, 0x56, 0xf3, 0x66, 0xc0, 0x37, 0x5a, 0x70, 0xed, 0x82, 0xbe, 0x7a, 0x9d, + 0x77, 0x53, 0x31, 0xe5, 0xdd, 0x74, 0x63, 0x13, 0x36, 0x16, 0xb5, 0xe3, 0x47, 0x95, 0xd1, 0x84, + 0x2b, 0x0b, 0x6b, 0xfd, 0x63, 0x0a, 0xd1, 0xff, 0x42, 0x0d, 0x20, 0x59, 0x4e, 0x19, 0x5d, 0x22, + 0x37, 0xa3, 0x4b, 0xfc, 0x28, 0x77, 0xd4, 0xcf, 0xa0, 0x86, 0xe3, 0x98, 0x8a, 0x64, 0xbc, 0x38, + 0x84, 0x72, 0x05, 0xa9, 0x06, 0x49, 0xc0, 0xcb, 0x79, 0xb7, 0xaa, 0xc2, 0x42, 0xb7, 0xaa, 0x4f, + 0x61, 0x95, 0xcf, 0x63, 0xd5, 0xa0, 0x5e, 0x9b, 0x65, 0x0d, 0x0f, 0x64, 0x98, 0x29, 0x45, 0x27, + 0x5a, 0x50, 0x8b, 0xa3, 0xcc, 0xa4, 0x23, 0xae, 0xde, 0x9a, 0xcf, 0xa9, 0xc8, 0xf8, 0xb9, 0x51, + 0x2b, 0x9d, 0x4c, 0xa9, 0x1e, 0xd1, 0x58, 0x1e, 0x12, 0x90, 0xea, 0xb1, 0x9a, 0x56, 0x3d, 0x06, + 0x63, 0x3e, 0x1a, 0x40, 0xd5, 0xe3, 0x23, 0xb8, 0x2c, 0x5d, 0xdc, 0x31, 0x03, 0x79, 0x2f, 0x20, + 0x3d, 0x5f, 0x65, 0xd4, 0xe4, 0xa3, 0x0c, 0x63, 0x52, 0xcc, 0x91, 0xfc, 0x1b, 0xd8, 0xe0, 0x77, + 0x43, 0xcc, 0xe8, 0x80, 0x5e, 0xf0, 0x69, 0x8f, 0xcc, 0xb1, 0x35, 0x91, 0x1a, 0xd1, 0x7b, 0x73, + 0x95, 0xe5, 0x67, 0x43, 0x06, 0x07, 0x2e, 0x5d, 0x2e, 0x88, 0x9d, 0xef, 0xd6, 0x87, 0xb3, 0xf0, + 0x19, 0x1f, 0x18, 0x98, 0xf3, 0x81, 0x99, 0xd5, 0x91, 0xca, 0x0b, 0x74, 0xa4, 0x44, 0xd3, 0xa9, + 0x64, 0x34, 0x9d, 0x0f, 0x61, 0x55, 0x46, 0xee, 0x94, 0xc7, 0x03, 0x62, 0x7e, 0x91, 0x19, 0x8a, + 0x04, 0xbf, 0xa4, 0x3c, 0xb2, 0x28, 0xf0, 0x7b, 0x8d, 0xbf, 0x94, 0x86, 0x89, 0x4d, 0x69, 0x1b, + 0x8f, 0x2f, 0x42, 0xc8, 0xa3, 0x80, 0x1b, 0xa9, 0x82, 0x63, 0x9c, 0x34, 0xde, 0xcc, 0xe4, 0xb8, + 0xf1, 0x97, 0x57, 0x61, 0x45, 0xfa, 0xd5, 0xdc, 0x87, 0xc2, 0x28, 0x90, 0x97, 0xb6, 0x62, 0xa5, + 0x2e, 0x2b, 0x57, 0xee, 0x5c, 0x32, 0x88, 0x46, 0x3c, 0x80, 0x15, 0x6b, 0x84, 0xfa, 0x5a, 0xd6, + 0x6d, 0x61, 0x46, 0xe6, 0xdf, 0xb9, 0x64, 0x2c, 0x5b, 0x24, 0xfc, 0x7f, 0x09, 0x25, 0xa4, 0x4f, + 0x87, 0xe0, 0xae, 0x2f, 0xc8, 0xa2, 0x8e, 0x66, 0x8a, 0x96, 0x92, 0xd4, 0x7f, 0x2b, 0x7b, 0x00, + 0x54, 0x98, 0x6b, 0xe0, 0x8c, 0x68, 0x39, 0x73, 0x14, 0xf4, 0xdb, 0xc0, 0x27, 0x02, 0xb1, 0x38, + 0xb1, 0x9c, 0x3e, 0x21, 0x9f, 0x13, 0x3e, 0x76, 0x2e, 0x19, 0xbc, 0xa9, 0x2a, 0x61, 0xe4, 0x73, + 0x75, 0x38, 0x43, 0xec, 0x79, 0x65, 0x71, 0xcf, 0x20, 0x8f, 0x8e, 0x4f, 0x68, 0x88, 0x61, 0x63, + 0xb6, 0x51, 0xec, 0x67, 0xbc, 0x3a, 0x97, 0x2d, 0x16, 0x39, 0x28, 0x5b, 0x2c, 0x7f, 0x3c, 0x86, + 0x32, 0xdb, 0xea, 0x39, 0x5f, 0x71, 0xae, 0x6b, 0x13, 0x89, 0x81, 0x4e, 0x7f, 0x13, 0xf9, 0xa1, + 0xa9, 0xda, 0x19, 0xd8, 0xe9, 0x03, 0xb6, 0x9b, 0x0b, 0x3b, 0xca, 0x88, 0xcf, 0xda, 0xb8, 0xb1, + 0x06, 0xe7, 0x11, 0x1d, 0xd8, 0x90, 0x27, 0x51, 0x2c, 0x1d, 0xa8, 0x0d, 0x1d, 0xe6, 0xc6, 0x2b, + 0x23, 0x3e, 0xec, 0x5c, 0x32, 0x84, 0x35, 0x2f, 0x54, 0x34, 0x61, 0x5d, 0x55, 0x89, 0xb6, 0xfd, + 0x94, 0xeb, 0x65, 0xba, 0x49, 0x89, 0x50, 0xb0, 0x73, 0xc9, 0x58, 0xb3, 0xb2, 0x20, 0xd1, 0x86, + 0xcb, 0xaa, 0x10, 0x52, 0xef, 0x53, 0xf7, 0x36, 0xb2, 0xa3, 0x98, 0x16, 0x24, 0x76, 0x2e, 0x19, + 0xeb, 0xd6, 0x9c, 0x74, 0xb1, 0xab, 0xea, 0x93, 0x96, 0x5c, 0x79, 0x25, 0xde, 0x5e, 0xd8, 0x4d, + 0x89, 0x18, 0x1d, 0xd7, 0x2c, 0x25, 0x59, 0xff, 0x42, 0x75, 0x56, 0xd6, 0xcb, 0x5c, 0x1e, 0xe0, + 0xbd, 0x39, 0x57, 0x62, 0xda, 0xc9, 0x3c, 0xee, 0xb1, 0x0c, 0x34, 0xf1, 0xa0, 0xb9, 0x61, 0xc0, + 0xd5, 0xc5, 0x4c, 0x2b, 0xbd, 0x73, 0x15, 0x78, 0xe7, 0xd2, 0xd3, 0x3b, 0xd7, 0xec, 0xdb, 0x10, + 0xa9, 0x7d, 0xec, 0xe7, 0x50, 0xcd, 0x70, 0x6d, 0x51, 0x86, 0x55, 0xf5, 0xae, 0x3e, 0x05, 0xc7, + 0x69, 0xf6, 0xf6, 0xbe, 0xd5, 0x72, 0x08, 0x6e, 0x77, 0xfb, 0x83, 0x46, 0x77, 0xa0, 0x2d, 0x71, + 0x62, 0xaf, 0xd3, 0x68, 0xb6, 0xb4, 0xbc, 0xfe, 0x37, 0xf3, 0x50, 0x8a, 0xcf, 0x77, 0x7f, 0x73, + 0xeb, 0xe8, 0xe2, 0xb8, 0x0d, 0x33, 0x0a, 0x2f, 0x5f, 0x5b, 0x29, 0xa8, 0x30, 0xf0, 0x69, 0xb5, + 0x32, 0x9c, 0x0f, 0x0b, 0xbc, 0xfc, 0x03, 0xc3, 0x02, 0xa7, 0x2f, 0x2c, 0xae, 0x64, 0x2f, 0x2c, + 0xde, 0x06, 0x15, 0x0e, 0x03, 0x77, 0x15, 0x32, 0xc9, 0x15, 0xe8, 0x79, 0x56, 0x04, 0x0d, 0x0e, + 0x5c, 0xe4, 0xeb, 0x4e, 0xf8, 0xdc, 0xb1, 0x4f, 0xe5, 0x15, 0x0a, 0x99, 0xca, 0x6e, 0xfa, 0xf0, + 0x9a, 0x4d, 0xff, 0x87, 0x6c, 0x20, 0x0f, 0x61, 0xe3, 0xf0, 0x24, 0x7e, 0x37, 0x3d, 0x31, 0xb6, + 0x55, 0xa8, 0x4a, 0x0b, 0x71, 0xe2, 0x3d, 0x58, 0x89, 0xd4, 0xd1, 0x73, 0x7e, 0xc1, 0x69, 0xbc, + 0x21, 0xd1, 0xfa, 0x5f, 0xce, 0x01, 0x24, 0x27, 0x9f, 0x7f, 0xe2, 0x23, 0x84, 0x94, 0xf5, 0x34, + 0xff, 0x0a, 0xeb, 0xe9, 0xeb, 0x5e, 0xc5, 0xfa, 0x1e, 0x4a, 0xf1, 0x59, 0xf7, 0x6f, 0x3e, 0xb1, + 0x7e, 0xd4, 0x27, 0xff, 0x61, 0x75, 0x9c, 0x12, 0x1f, 0x16, 0xff, 0x49, 0xfb, 0x22, 0xf3, 0xf9, + 0xfc, 0x6b, 0x3e, 0x7f, 0xc6, 0x67, 0x0d, 0xf1, 0xc7, 0xff, 0x94, 0x57, 0x53, 0x7a, 0xa2, 0x17, + 0x32, 0x13, 0x5d, 0x9f, 0xca, 0x43, 0x96, 0x3f, 0xf9, 0xa7, 0x7f, 0x54, 0x83, 0xff, 0xf7, 0x9c, + 0xb2, 0xea, 0xc7, 0x4f, 0xdd, 0x5f, 0x28, 0x47, 0x2f, 0x3e, 0x98, 0xf8, 0x31, 0x9f, 0x7b, 0xa5, + 0xa5, 0xae, 0xf0, 0x2a, 0x4b, 0xdd, 0x7b, 0xea, 0xa1, 0x90, 0xe5, 0x8b, 0xac, 0x74, 0xf2, 0xad, + 0x90, 0xdb, 0x50, 0x4e, 0xdb, 0xe6, 0xd8, 0x28, 0xc3, 0x46, 0x15, 0x36, 0xcb, 0xe9, 0x52, 0x6f, + 0xe0, 0xf6, 0x6e, 0xa8, 0x72, 0x65, 0x00, 0x2b, 0x4a, 0xe8, 0x7f, 0x8e, 0x39, 0xea, 0x6f, 0xda, + 0x25, 0xaf, 0x36, 0xd3, 0xe8, 0xff, 0x6f, 0x0e, 0xaa, 0x19, 0xdf, 0x95, 0xdf, 0xe0, 0x13, 0x0b, + 0xf9, 0x72, 0xfe, 0xff, 0x47, 0x7c, 0x39, 0x73, 0xb3, 0xa0, 0x98, 0xbd, 0x59, 0x80, 0xec, 0xae, + 0x92, 0xd1, 0x8a, 0x16, 0xe9, 0x4f, 0xb9, 0x85, 0xfa, 0xd3, 0x2d, 0x00, 0x6b, 0x48, 0x57, 0x1e, + 0xdb, 0x5b, 0xec, 0xc8, 0x5f, 0x35, 0x52, 0x10, 0xf1, 0x15, 0x5c, 0x97, 0x46, 0x13, 0xee, 0x1f, + 0xff, 0xd0, 0x54, 0xd8, 0x91, 0x34, 0x42, 0x5c, 0x65, 0x02, 0x1a, 0xdd, 0xde, 0x61, 0x43, 0x61, + 0xf5, 0x36, 0x54, 0x33, 0x4e, 0x41, 0xb8, 0xb7, 0x1c, 0xb9, 0xfe, 0x81, 0xe5, 0xca, 0xba, 0xc8, + 0x94, 0xb8, 0x03, 0xcb, 0xa7, 0xc7, 0x76, 0x60, 0x2f, 0x78, 0xcf, 0x99, 0x11, 0xfa, 0x4f, 0xa1, + 0x92, 0x76, 0x50, 0x14, 0x1f, 0xc2, 0xb2, 0x13, 0xd9, 0x63, 0x65, 0x0e, 0xba, 0x3a, 0xef, 0xc3, + 0xd8, 0x8e, 0xec, 0xb1, 0xc1, 0x44, 0xfa, 0xef, 0xe7, 0x40, 0x9b, 0xc5, 0x51, 0x0c, 0xa6, 0xf3, + 0x30, 0xb2, 0xc7, 0xaa, 0x32, 0x9c, 0x4a, 0x55, 0x72, 0x29, 0x53, 0x49, 0x65, 0x35, 0xcb, 0xa7, + 0xac, 0x66, 0x77, 0x94, 0x50, 0x32, 0x7f, 0x97, 0x8d, 0x11, 0xe2, 0x5d, 0x28, 0x06, 0x36, 0x45, + 0x77, 0x5a, 0xf4, 0x4a, 0x4e, 0x8c, 0xd3, 0x7f, 0x2f, 0x07, 0xab, 0xd2, 0x9b, 0x72, 0xa1, 0x7d, + 0xee, 0x7d, 0x58, 0x0d, 0x87, 0xc7, 0xf6, 0xd8, 0x52, 0x8f, 0x63, 0xcd, 0x1d, 0x19, 0x29, 0xbc, + 0xb8, 0xc5, 0x3e, 0xa6, 0x59, 0x7b, 0xdd, 0x9e, 0x6b, 0x79, 0x06, 0xc1, 0x71, 0xaa, 0xb1, 0x9d, + 0x96, 0xef, 0xa4, 0xf1, 0xcb, 0x25, 0x40, 0x20, 0xba, 0x75, 0xa6, 0xff, 0x16, 0xac, 0x4a, 0x6f, + 0xcd, 0x85, 0x55, 0xb9, 0x05, 0x05, 0x2b, 0x38, 0x0a, 0x17, 0x0c, 0x16, 0xc1, 0xf5, 0x3b, 0x00, + 0x89, 0xfb, 0xe6, 0xa2, 0x12, 0xf4, 0xfb, 0x50, 0x54, 0x1e, 0x9b, 0x38, 0xff, 0x92, 0x4f, 0xcb, + 0x7b, 0xe8, 0xe9, 0xca, 0xb8, 0x50, 0xa5, 0x89, 0xda, 0xf1, 0x87, 0x27, 0x74, 0x64, 0xf0, 0x31, + 0xd0, 0x75, 0xfe, 0xc1, 0xdc, 0x13, 0x2f, 0x31, 0x19, 0xdf, 0x52, 0x51, 0x44, 0xe2, 0x3e, 0xc4, + 0xfc, 0xf2, 0x75, 0xd6, 0x0a, 0xbd, 0xa1, 0x02, 0x3f, 0xd0, 0x2c, 0x7b, 0x24, 0xad, 0xc7, 0x1d, + 0x7a, 0x7e, 0x30, 0x97, 0xbe, 0x27, 0x90, 0xa9, 0x93, 0x91, 0x22, 0xd3, 0x6b, 0x50, 0x49, 0xbb, + 0x99, 0xe9, 0x0d, 0x58, 0x57, 0x37, 0x11, 0xd4, 0xc3, 0x17, 0x3c, 0x7f, 0xf1, 0x47, 0x76, 0xfe, + 0xce, 0xd2, 0x19, 0x4c, 0xa4, 0xff, 0xcd, 0x02, 0x68, 0xb3, 0xb8, 0x57, 0x05, 0xc1, 0xb8, 0x0d, + 0x65, 0x7e, 0xb7, 0x2a, 0x6d, 0x49, 0x04, 0x06, 0xa5, 0xae, 0x29, 0xf1, 0x9b, 0x4e, 0xea, 0xb9, + 0x71, 0x27, 0xe4, 0x37, 0x9f, 0xc4, 0x35, 0x8e, 0x78, 0xe0, 0xfa, 0x43, 0x9a, 0xd6, 0x15, 0x0a, + 0x70, 0xd0, 0xf1, 0x87, 0x14, 0x5b, 0x43, 0x1a, 0x3c, 0xd8, 0xd9, 0xa1, 0x62, 0x14, 0xa5, 0x95, + 0x83, 0xce, 0x73, 0xe5, 0xe5, 0xa5, 0x28, 0x94, 0x01, 0xf0, 0x8a, 0x0c, 0x18, 0x84, 0xea, 0x25, + 0xfe, 0xa1, 0x17, 0xc9, 0xd0, 0x4e, 0x2b, 0x81, 0x7f, 0xda, 0xf4, 0x28, 0xb4, 0x06, 0xbd, 0x83, + 0x8b, 0x18, 0x19, 0x2a, 0x0b, 0xd3, 0x88, 0xa2, 0x78, 0x4a, 0x1c, 0xdd, 0x98, 0x5f, 0xa1, 0x2b, + 0xc9, 0xe7, 0x07, 0x25, 0x30, 0x7e, 0xe4, 0x93, 0xf7, 0xbf, 0x54, 0xd0, 0x2c, 0x60, 0x10, 0x11, + 0x5c, 0x87, 0xe2, 0xaf, 0x7c, 0xcf, 0x26, 0xc3, 0x49, 0x99, 0x6a, 0xb5, 0x8a, 0xe9, 0x5d, 0x6b, + 0x82, 0x1b, 0x81, 0x4b, 0xb1, 0x16, 0xf9, 0x7a, 0x2e, 0x27, 0xf4, 0xff, 0x26, 0x07, 0x1b, 0xb3, + 0x7d, 0x4d, 0xd3, 0xa8, 0x02, 0xc5, 0x66, 0xaf, 0x63, 0x76, 0x1b, 0xbb, 0x2d, 0xed, 0x92, 0x58, + 0x83, 0x72, 0x6f, 0xf3, 0x69, 0xab, 0x39, 0x60, 0x40, 0x8e, 0x22, 0xc6, 0xf6, 0xcd, 0x9d, 0xf6, + 0xd6, 0x56, 0xab, 0xcb, 0x1a, 0x45, 0x6f, 0xf3, 0xa9, 0xd9, 0xe9, 0x35, 0xb5, 0x3c, 0xe2, 0x94, + 0x03, 0x4e, 0x5f, 0x2b, 0x90, 0x7b, 0x0e, 0x5d, 0xc3, 0xc0, 0xe4, 0x32, 0xdf, 0x2f, 0x78, 0xd1, + 0x37, 0x9b, 0xdd, 0x81, 0xb6, 0x82, 0xa9, 0xee, 0x7e, 0xa7, 0x43, 0x29, 0x72, 0x24, 0x6e, 0xf6, + 0x76, 0xf7, 0x8c, 0x56, 0xbf, 0x6f, 0xf6, 0xdb, 0xbf, 0x6c, 0x69, 0x45, 0xfa, 0xb2, 0xd1, 0x7e, + 0xd2, 0xee, 0x32, 0xa0, 0x24, 0x56, 0x21, 0xbf, 0xdb, 0xee, 0x72, 0xa4, 0xdc, 0xdd, 0xc6, 0x37, + 0x5a, 0x19, 0x7f, 0xf4, 0xf7, 0x77, 0xb5, 0x8a, 0x28, 0xc1, 0x72, 0xa7, 0xf5, 0xbc, 0xd5, 0xd1, + 0xaa, 0xfa, 0xff, 0x94, 0x57, 0x12, 0x31, 0x79, 0xd8, 0xfd, 0x10, 0x29, 0x70, 0xd1, 0x29, 0x6b, + 0xdc, 0x69, 0xf9, 0x54, 0xa7, 0xd1, 0x73, 0x50, 0xcc, 0xf6, 0xd3, 0xe7, 0x64, 0x65, 0x09, 0xa3, + 0x29, 0xf7, 0x36, 0x54, 0xe3, 0x33, 0xe8, 0xd4, 0xeb, 0xf9, 0x15, 0x05, 0x5c, 0x70, 0x5c, 0xb3, + 0xb2, 0xe0, 0xb8, 0x66, 0xe2, 0x44, 0xa8, 0xb8, 0x23, 0xcf, 0xe5, 0x99, 0x54, 0x42, 0xc8, 0x73, + 0xe2, 0xb5, 0x6f, 0x00, 0x25, 0xcc, 0xa9, 0x27, 0x5f, 0xfd, 0x2a, 0x19, 0x45, 0x04, 0xec, 0x7b, + 0x1c, 0x20, 0x23, 0xed, 0xac, 0x52, 0x9a, 0x73, 0x56, 0x49, 0x6f, 0xce, 0x90, 0xdd, 0x9c, 0xdf, + 0x8c, 0xf7, 0x48, 0x44, 0x96, 0xe9, 0xac, 0xa2, 0x14, 0xef, 0x82, 0xe2, 0x43, 0x10, 0xc3, 0x69, + 0x40, 0x8f, 0xee, 0xa4, 0xc8, 0x2a, 0x44, 0xa6, 0x49, 0x4c, 0xbc, 0x2b, 0x52, 0xb8, 0xa1, 0x2c, + 0x35, 0xa9, 0xe7, 0x25, 0xa3, 0x96, 0x25, 0x15, 0x0f, 0xe0, 0xb2, 0x9c, 0xdb, 0x99, 0xbe, 0x95, + 0x91, 0x4a, 0x18, 0xd5, 0x48, 0x7a, 0x58, 0xff, 0x09, 0x14, 0x95, 0x33, 0xe5, 0xab, 0x85, 0xdd, + 0x05, 0xe3, 0xaa, 0xff, 0xf5, 0x25, 0x28, 0xc5, 0xae, 0x95, 0x3f, 0x68, 0x76, 0xbc, 0x81, 0x72, + 0x6a, 0x78, 0x92, 0x66, 0x31, 0x45, 0x04, 0xa8, 0x91, 0x92, 0x97, 0x48, 0xa7, 0x81, 0xa3, 0x24, + 0x36, 0x86, 0xec, 0x07, 0x0e, 0x45, 0xd6, 0x77, 0xbc, 0x54, 0x64, 0x90, 0x92, 0x51, 0x44, 0x00, + 0x2d, 0xb4, 0xeb, 0x40, 0xbf, 0x29, 0x27, 0x4f, 0x92, 0x55, 0x4c, 0x63, 0xbe, 0xab, 0xb1, 0xfe, + 0x27, 0xe3, 0xf1, 0x45, 0xb1, 0x60, 0x21, 0xbd, 0xba, 0xd8, 0xc7, 0x44, 0xa6, 0xf0, 0x3b, 0x14, + 0xc5, 0x8a, 0xea, 0x28, 0x67, 0x04, 0x02, 0x54, 0x1d, 0x53, 0xc3, 0x55, 0x9a, 0x1d, 0xd5, 0xd9, + 0x39, 0x0d, 0x73, 0x73, 0x5a, 0x8f, 0x60, 0x55, 0xba, 0x97, 0xbe, 0xba, 0xc3, 0x5f, 0xd9, 0x55, + 0x1a, 0xe4, 0x2d, 0x57, 0x85, 0x69, 0xc0, 0x9f, 0x33, 0x15, 0x2b, 0xcc, 0x54, 0x4c, 0xff, 0x57, + 0x96, 0x00, 0x12, 0x37, 0x55, 0xf1, 0xd1, 0x8c, 0x4b, 0x7c, 0x6e, 0x6e, 0xdb, 0x9f, 0xf1, 0x84, + 0x9f, 0x79, 0x6a, 0x62, 0xe9, 0x07, 0x3c, 0x35, 0xf1, 0x10, 0xaa, 0x61, 0x30, 0x7c, 0xad, 0x0d, + 0xbf, 0x1c, 0x06, 0xc3, 0xd8, 0x84, 0xff, 0x31, 0x60, 0x92, 0x9e, 0xa1, 0x4a, 0x14, 0xd5, 0x39, + 0xa9, 0xa5, 0x14, 0x06, 0xc3, 0xde, 0xc1, 0x77, 0x5b, 0x7c, 0x73, 0x77, 0x14, 0x46, 0xe6, 0x22, + 0x2e, 0xb1, 0x36, 0x0a, 0xa3, 0xad, 0x34, 0xa3, 0xb8, 0x0b, 0x35, 0xa4, 0x9d, 0x63, 0x16, 0x95, + 0x51, 0x98, 0x1c, 0x28, 0xe9, 0xff, 0x84, 0x3a, 0x98, 0x9f, 0x31, 0x0f, 0x8b, 0x2f, 0xa4, 0x22, + 0x9e, 0x12, 0x22, 0xea, 0x8b, 0xac, 0xc9, 0x7c, 0xb9, 0x3f, 0x26, 0x15, 0x8f, 0xa1, 0x1a, 0xe3, + 0xb6, 0xec, 0x43, 0x25, 0x03, 0xa9, 0x37, 0x8d, 0x52, 0x28, 0x23, 0x4b, 0xa8, 0x3f, 0x06, 0x48, + 0x1e, 0x02, 0xc3, 0x15, 0x18, 0x5f, 0x13, 0x2b, 0xf1, 0x05, 0x30, 0x9c, 0xc3, 0x1e, 0xc5, 0x0a, + 0x90, 0x4f, 0x5d, 0xcb, 0x94, 0xfe, 0x18, 0xae, 0x5d, 0x60, 0x5f, 0x53, 0xe7, 0x95, 0x32, 0x90, + 0x87, 0x8c, 0x48, 0xe8, 0xd9, 0xa7, 0x1c, 0xc8, 0x43, 0xf7, 0xe0, 0xf2, 0x82, 0xc7, 0xfa, 0xc5, + 0x1d, 0x72, 0x6a, 0xa3, 0xd3, 0xc0, 0xf8, 0x76, 0xff, 0x32, 0x9d, 0x83, 0xb6, 0x47, 0xfc, 0x1c, + 0xc9, 0xe7, 0xb0, 0x66, 0xbb, 0xce, 0x91, 0x73, 0xe0, 0x50, 0xe4, 0xff, 0xa1, 0xef, 0xce, 0x59, + 0xdd, 0xe8, 0xe1, 0xf4, 0x14, 0x51, 0xd3, 0x77, 0xf5, 0x7f, 0x3a, 0x27, 0x5f, 0xde, 0xcc, 0x3e, + 0x1b, 0xc8, 0x2f, 0x6f, 0xca, 0x27, 0xbe, 0x73, 0x06, 0xfd, 0xc6, 0xd6, 0xca, 0x57, 0x9d, 0xe5, + 0xb3, 0x7b, 0x9c, 0x12, 0x1f, 0xc3, 0x86, 0x8c, 0x9e, 0x4f, 0xa1, 0xf6, 0xcc, 0x89, 0x1d, 0x98, + 0x81, 0x7f, 0x4a, 0x13, 0x2e, 0x67, 0xac, 0x33, 0x8e, 0x22, 0xee, 0xed, 0xd9, 0x81, 0xe1, 0x9f, + 0x8a, 0x3a, 0x49, 0x2b, 0xf6, 0x30, 0x52, 0x67, 0xcf, 0x2a, 0xa9, 0xff, 0x0e, 0x5c, 0x5e, 0x70, + 0xaf, 0x54, 0xbc, 0xa3, 0xf4, 0xbf, 0x0b, 0x6e, 0x91, 0x2f, 0xd4, 0x39, 0x97, 0x66, 0x75, 0xce, + 0x2e, 0x54, 0x33, 0x57, 0x45, 0xb3, 0x11, 0xfc, 0x0b, 0xaf, 0x8e, 0xe0, 0x4f, 0x0f, 0xa2, 0x2f, + 0x3d, 0x2d, 0x14, 0x97, 0xb4, 0xfc, 0xd3, 0x42, 0x31, 0xaf, 0x15, 0xf4, 0xbf, 0x9a, 0x83, 0xa2, + 0x22, 0x9c, 0xdf, 0x2b, 0x73, 0x0b, 0xf6, 0xca, 0x37, 0xe4, 0x07, 0xd3, 0x4c, 0x05, 0x01, 0x84, + 0xbc, 0x0f, 0xc5, 0x78, 0x81, 0xe7, 0x17, 0x2e, 0xf0, 0x18, 0x2f, 0x3e, 0x80, 0xf5, 0x8c, 0x7f, + 0x6c, 0x6a, 0x07, 0xd7, 0xd2, 0x08, 0x6a, 0xf7, 0x1f, 0xe4, 0xa0, 0xac, 0x5e, 0xea, 0x34, 0x38, + 0xba, 0xa7, 0x7a, 0xd0, 0x33, 0x09, 0x8f, 0x06, 0x0a, 0xd4, 0x1e, 0xa1, 0x2a, 0x1e, 0xd8, 0x2f, + 0x9d, 0x50, 0xf9, 0xfb, 0x16, 0x8c, 0x38, 0x8d, 0x5f, 0x8e, 0xe3, 0x89, 0xce, 0x04, 0xc3, 0xd4, + 0x62, 0x84, 0x8a, 0x9b, 0x38, 0xcf, 0x15, 0x0b, 0x69, 0x76, 0x3d, 0xb3, 0xbf, 0x2f, 0xcf, 0xee, + 0xef, 0xfa, 0xbf, 0x90, 0x83, 0x7a, 0xff, 0x7b, 0x57, 0x5e, 0xb2, 0x6d, 0x8f, 0x27, 0x2e, 0x2d, + 0x22, 0xbe, 0x9f, 0xfb, 0x39, 0x5c, 0x4d, 0x1c, 0x9a, 0xcd, 0x43, 0xc7, 0x3b, 0xb2, 0x83, 0x49, + 0xe0, 0x48, 0xc7, 0x8c, 0x8a, 0x71, 0x25, 0xc1, 0x6e, 0x27, 0x48, 0xf1, 0x0c, 0xf4, 0xd0, 0x1e, + 0x5b, 0x5e, 0xe4, 0x0c, 0xcd, 0x54, 0x7e, 0xd6, 0xc4, 0xe2, 0x16, 0xf1, 0x0c, 0xbf, 0xad, 0x28, + 0x93, 0xcb, 0x5b, 0x7d, 0xa2, 0x93, 0x0d, 0xd4, 0xff, 0x83, 0x3c, 0xbc, 0xb1, 0x77, 0x1e, 0x1d, + 0xfb, 0xde, 0xe2, 0x3a, 0xd6, 0x61, 0xf5, 0xd8, 0xf2, 0x46, 0x6e, 0x1c, 0x35, 0x58, 0x25, 0xc5, + 0x0d, 0x58, 0xe1, 0xbd, 0x95, 0xe7, 0xc1, 0xe6, 0x52, 0x3d, 0x67, 0x48, 0x08, 0x6d, 0x63, 0x07, + 0x8e, 0x49, 0x37, 0xcd, 0xac, 0x61, 0x24, 0xf7, 0xe2, 0xb2, 0x75, 0xe0, 0x34, 0x25, 0x08, 0x25, + 0x12, 0x7a, 0xcf, 0xc2, 0x0e, 0xe2, 0x2a, 0x4b, 0x47, 0x27, 0x09, 0x56, 0x43, 0x80, 0x84, 0x41, + 0xe4, 0x1c, 0x5a, 0xc3, 0x48, 0x85, 0x84, 0x5c, 0x96, 0x84, 0x12, 0x2c, 0x23, 0x42, 0x7e, 0x04, + 0xc2, 0xf6, 0x5e, 0x3a, 0x81, 0xef, 0x51, 0x48, 0x1a, 0x49, 0xcb, 0x2c, 0x7a, 0x3d, 0x85, 0x91, + 0xe4, 0xb7, 0xa1, 0x1c, 0x8e, 0x4e, 0xe2, 0x8f, 0xcb, 0xf0, 0xd8, 0xe1, 0xe8, 0x44, 0x7d, 0xf8, + 0x6b, 0xb8, 0x7e, 0x71, 0xf7, 0x72, 0x80, 0xae, 0x6b, 0xa3, 0xc5, 0xdd, 0x1a, 0xf3, 0xda, 0x52, + 0x8a, 0xd7, 0xde, 0x86, 0x32, 0xa9, 0x1d, 0x13, 0xdf, 0x75, 0x86, 0xe7, 0x72, 0x6b, 0x07, 0x04, + 0xed, 0x11, 0xe4, 0x15, 0xf3, 0x81, 0x1d, 0x4b, 0x17, 0xcf, 0x07, 0xfd, 0x7f, 0x5d, 0x86, 0xb2, + 0x1c, 0xbc, 0x26, 0xee, 0xe4, 0x1c, 0x78, 0x8c, 0x7a, 0x39, 0xae, 0x2e, 0x47, 0xd3, 0x59, 0x53, + 0x70, 0x55, 0xcd, 0xcf, 0xa0, 0x12, 0x2f, 0xa4, 0x24, 0x7c, 0x89, 0x0a, 0x67, 0x9d, 0xac, 0x38, + 0x23, 0x5e, 0x6f, 0xb8, 0xfc, 0x6e, 0x40, 0xd1, 0xb5, 0xbc, 0xa3, 0xa9, 0x75, 0x14, 0xbb, 0xfc, + 0xaa, 0xb4, 0xf8, 0x14, 0x6a, 0x56, 0x70, 0x34, 0xa5, 0x11, 0x48, 0x54, 0xfd, 0x6c, 0xe0, 0x9a, + 0xaa, 0xa2, 0xe0, 0x78, 0x33, 0x9f, 0x42, 0x99, 0x2f, 0xfd, 0xb3, 0x64, 0xb6, 0x7c, 0x81, 0xc7, + 0x0f, 0x30, 0x11, 0x6d, 0x89, 0xb7, 0x00, 0x5e, 0xfa, 0xae, 0x15, 0xd1, 0x2e, 0x20, 0x87, 0x38, + 0x05, 0x99, 0xed, 0xea, 0xd5, 0xb9, 0xae, 0x7e, 0xc8, 0x3e, 0xf5, 0x7c, 0x0a, 0x28, 0x8f, 0xe0, + 0x2f, 0x5a, 0xa7, 0x3b, 0x97, 0xd8, 0xeb, 0xfe, 0x27, 0xb0, 0x32, 0xa1, 0x95, 0x22, 0x0f, 0x00, + 0xdf, 0x92, 0x1b, 0xf0, 0xc5, 0xab, 0x67, 0xe7, 0x92, 0x21, 0xb3, 0x88, 0x9f, 0xf2, 0xbd, 0x4b, + 0xfb, 0x2c, 0x92, 0x81, 0xd2, 0x6f, 0x65, 0xae, 0xdf, 0xe3, 0xc0, 0x3d, 0x68, 0x32, 0x01, 0x1d, + 0x46, 0xd1, 0x72, 0x52, 0x59, 0xc8, 0x89, 0xc8, 0x72, 0xdd, 0xd0, 0x89, 0x6c, 0xa5, 0x0c, 0x94, + 0x0c, 0x50, 0xa0, 0x36, 0x85, 0x72, 0x1f, 0x5b, 0xe7, 0xa6, 0x1d, 0x04, 0x7e, 0x20, 0x83, 0xeb, + 0x14, 0xc7, 0xd6, 0x79, 0x0b, 0xd3, 0xc8, 0xd9, 0x43, 0x7b, 0x38, 0x0d, 0x70, 0x5b, 0xa5, 0x59, + 0xc9, 0xa2, 0x7f, 0x45, 0x01, 0xe9, 0xe2, 0xf7, 0x4d, 0x28, 0xb9, 0xb6, 0x75, 0x32, 0x09, 0x7c, + 0xff, 0x50, 0x8a, 0xfb, 0x09, 0x40, 0x3c, 0x82, 0x2b, 0x09, 0xd3, 0x4c, 0xcf, 0x4c, 0xf6, 0x38, + 0xde, 0x88, 0x91, 0xa9, 0x89, 0x79, 0xe3, 0x6b, 0xa8, 0xa4, 0x9b, 0xf4, 0x3a, 0xcf, 0x90, 0x52, + 0xea, 0x44, 0x6d, 0x53, 0x83, 0x9a, 0x93, 0xe9, 0x4b, 0xfd, 0xef, 0xe7, 0xe1, 0xca, 0xc2, 0x60, + 0x05, 0x73, 0xb3, 0x38, 0xf7, 0xa3, 0x67, 0xf1, 0xd2, 0xcc, 0x2c, 0x5e, 0xb4, 0x84, 0xf2, 0x8b, + 0x97, 0xd0, 0xc5, 0x8b, 0xb6, 0xf0, 0x8a, 0x45, 0xfb, 0x67, 0xc6, 0xd5, 0xb2, 0x2b, 0x63, 0xf5, + 0x75, 0x2b, 0xa3, 0x38, 0xb7, 0x32, 0x32, 0x33, 0xa9, 0xf4, 0xba, 0x99, 0x04, 0xaf, 0x9b, 0x49, + 0xe5, 0x1f, 0x3c, 0x93, 0x2a, 0x17, 0xcf, 0x24, 0xfd, 0x8f, 0x72, 0xa0, 0xcd, 0x7a, 0x8b, 0xcf, + 0x6e, 0xbe, 0xb9, 0x39, 0xe5, 0xfa, 0x6d, 0xa8, 0x0e, 0x8f, 0x2d, 0x1c, 0x2c, 0xba, 0xe3, 0x18, + 0xc9, 0x61, 0xae, 0xc4, 0xc0, 0xbe, 0x4d, 0x51, 0xd5, 0x87, 0xbe, 0x2b, 0x63, 0x6b, 0x48, 0x9d, + 0x31, 0x06, 0x90, 0xd7, 0x6b, 0x6a, 0x77, 0x2a, 0x18, 0x2a, 0x49, 0x31, 0xa1, 0x14, 0x99, 0xda, + 0xfb, 0xab, 0x46, 0x39, 0x86, 0xa9, 0xb8, 0xdb, 0x8a, 0x24, 0x96, 0x47, 0x56, 0x88, 0x70, 0x3d, + 0xc6, 0x18, 0x12, 0x71, 0xff, 0x9f, 0xcf, 0xc1, 0x7a, 0x3f, 0x0a, 0x1c, 0xef, 0xa8, 0xe3, 0x44, + 0x76, 0x60, 0xb9, 0xdb, 0x7e, 0x30, 0xa6, 0x0b, 0x71, 0x03, 0xa3, 0xdd, 0x7d, 0x62, 0x76, 0xda, + 0x83, 0x96, 0xd1, 0x88, 0xdf, 0x46, 0x99, 0x47, 0x0c, 0x5a, 0xdf, 0x0c, 0xb4, 0x9c, 0xb8, 0x0b, + 0x77, 0x66, 0x10, 0x9b, 0xed, 0x6e, 0xc3, 0xf8, 0xd6, 0x6c, 0x77, 0x07, 0x46, 0x6f, 0x6b, 0xbf, + 0xd9, 0x32, 0xb4, 0x25, 0x71, 0x15, 0xc4, 0x0c, 0xd5, 0x4e, 0xeb, 0x1b, 0x2d, 0xbf, 0x00, 0xbe, + 0xd9, 0x1e, 0x68, 0x85, 0xfb, 0xbb, 0x70, 0xb9, 0x71, 0x74, 0x14, 0xd8, 0x47, 0xa8, 0xad, 0x53, + 0xec, 0x7d, 0x75, 0x2b, 0xb1, 0xf1, 0xe4, 0x89, 0xd9, 0xec, 0x75, 0xb7, 0xdb, 0x4f, 0x54, 0xd5, + 0xde, 0x82, 0x37, 0x53, 0xc0, 0x27, 0x46, 0x6f, 0x7f, 0x0f, 0x13, 0xcd, 0xc6, 0xc0, 0xec, 0x19, + 0x5b, 0x2d, 0x43, 0xcb, 0xdd, 0x7f, 0x0b, 0x79, 0x03, 0xdb, 0xd4, 0xe2, 0xa7, 0x64, 0x7c, 0xcf, + 0xd6, 0x2e, 0x89, 0x55, 0xc8, 0x77, 0x7e, 0xf5, 0x99, 0x96, 0xbb, 0x1f, 0x80, 0xc6, 0x61, 0x99, + 0xd9, 0xc9, 0x80, 0x82, 0x50, 0xdf, 0x82, 0x1b, 0x46, 0xab, 0xbf, 0xdf, 0x19, 0xc8, 0xcb, 0x7c, + 0xe6, 0xb3, 0x76, 0x77, 0xcb, 0x4c, 0x82, 0x90, 0xbc, 0x09, 0xd7, 0x17, 0xe0, 0xfb, 0x83, 0x9e, + 0xd1, 0xda, 0xd2, 0x72, 0xe2, 0x36, 0xbc, 0xb1, 0x00, 0xdd, 0xec, 0xed, 0xee, 0xed, 0x0f, 0x5a, + 0x5b, 0xda, 0xd2, 0x7d, 0x1d, 0xca, 0xfd, 0xe3, 0xe9, 0xe1, 0xa1, 0x6b, 0xab, 0x5a, 0xed, 0x58, + 0xe1, 0x31, 0xfb, 0xea, 0xd3, 0xf3, 0xeb, 0x5a, 0xee, 0xfe, 0xbb, 0x50, 0x95, 0x34, 0xbb, 0x76, + 0x74, 0xec, 0x8f, 0x04, 0xc0, 0x4a, 0xd7, 0x0f, 0xc6, 0x96, 0x2b, 0xe9, 0xec, 0x69, 0x88, 0x74, + 0x1f, 0xc3, 0x95, 0x54, 0x59, 0xdb, 0x7e, 0x40, 0xd1, 0x43, 0x9b, 0x5d, 0x8a, 0x94, 0x42, 0xcc, + 0x8d, 0x63, 0x7e, 0xec, 0x9c, 0x1f, 0x04, 0xce, 0x48, 0xcb, 0xdd, 0x7f, 0x0c, 0xa5, 0x4d, 0x7f, + 0xea, 0xf1, 0x73, 0x21, 0xf4, 0x4e, 0xd4, 0x66, 0x6f, 0xbf, 0xbb, 0x45, 0x2f, 0xcb, 0xd0, 0xdb, + 0x50, 0xcd, 0xce, 0x7e, 0xbf, 0xfd, 0x5c, 0x1a, 0xfe, 0x5a, 0xdf, 0xa8, 0xe4, 0xd2, 0xfd, 0xdf, + 0xcb, 0xa9, 0x50, 0xc5, 0xaa, 0xda, 0x9d, 0x5e, 0x63, 0x8b, 0x2d, 0x86, 0xf1, 0x13, 0x58, 0x83, + 0x4d, 0x2d, 0x87, 0x00, 0xd9, 0x03, 0xf2, 0x75, 0xad, 0x1a, 0x40, 0xbb, 0xd9, 0xda, 0x6c, 0x19, + 0x4f, 0x90, 0x20, 0x8f, 0xe9, 0xdd, 0x5e, 0xf7, 0x49, 0x6f, 0x6b, 0x13, 0xd3, 0xf4, 0xae, 0xd6, + 0x56, 0x63, 0xd0, 0xe8, 0x0f, 0x8c, 0x56, 0x63, 0x17, 0x41, 0x14, 0x8c, 0x40, 0x5d, 0x49, 0x18, + 0x6c, 0xb2, 0xf5, 0xf0, 0x59, 0x63, 0xfb, 0x59, 0x03, 0x53, 0xab, 0xf7, 0xff, 0xab, 0x25, 0xd0, + 0x66, 0xc3, 0x51, 0x8b, 0x37, 0xe0, 0x1a, 0x95, 0x6a, 0xee, 0x19, 0xad, 0xad, 0x76, 0x93, 0xaf, + 0x95, 0x3e, 0x6f, 0x74, 0xda, 0x5b, 0x3c, 0x93, 0x67, 0x91, 0x8d, 0xee, 0x16, 0x3f, 0x99, 0x33, + 0x8b, 0x68, 0xfd, 0x62, 0xbf, 0xd1, 0xd1, 0x96, 0x70, 0xa0, 0x67, 0x51, 0xdd, 0xde, 0x40, 0xa2, + 0xf3, 0xa2, 0x0e, 0x1b, 0xb3, 0xe8, 0x4e, 0xab, 0xdf, 0xd7, 0x0a, 0x38, 0x83, 0x16, 0x61, 0x64, + 0xce, 0xe5, 0x45, 0x35, 0x7d, 0x42, 0x66, 0x54, 0x43, 0x5b, 0xc1, 0x89, 0x7d, 0x01, 0x52, 0xe6, + 0x5f, 0xc5, 0xf5, 0x33, 0xdf, 0x52, 0xad, 0xb8, 0xb0, 0x07, 0xfa, 0x26, 0x3d, 0x90, 0x54, 0xc2, + 0x79, 0xb9, 0x08, 0xd9, 0x1b, 0x30, 0x01, 0xdc, 0xff, 0xdb, 0x39, 0xa8, 0x5f, 0x14, 0x35, 0x50, + 0xe8, 0x70, 0xcb, 0xd8, 0xef, 0xd2, 0xeb, 0x58, 0xfc, 0x90, 0x97, 0xf9, 0xac, 0xf5, 0xed, 0xcc, + 0xcb, 0x44, 0xb8, 0x30, 0xe6, 0x69, 0x8c, 0xc6, 0x0b, 0xf3, 0xf9, 0xa7, 0x5a, 0x4e, 0x7c, 0x00, + 0xef, 0x2d, 0x40, 0x6f, 0x77, 0x7a, 0x8d, 0x81, 0xf9, 0xcb, 0x96, 0xd1, 0x33, 0x9b, 0x9d, 0x5e, + 0xbf, 0xb5, 0x85, 0xc4, 0x4b, 0xe2, 0x0e, 0xdc, 0x5c, 0x40, 0xdc, 0xe7, 0xb7, 0xd7, 0x9e, 0x7f, + 0xaa, 0xe5, 0xc5, 0x3b, 0xf0, 0xd6, 0xc5, 0x14, 0xdb, 0xfb, 0x1d, 0x22, 0x2b, 0xdc, 0xff, 0x39, + 0xd4, 0x2f, 0x8a, 0xd9, 0x82, 0x0b, 0xa9, 0xb9, 0xd3, 0xa0, 0xb8, 0x38, 0x15, 0x28, 0x76, 0x7b, + 0x26, 0xa7, 0xc8, 0x87, 0xc6, 0x68, 0x75, 0x5a, 0x74, 0xb1, 0xf9, 0xfe, 0xaf, 0x73, 0xa9, 0x93, + 0x1a, 0x15, 0x77, 0x23, 0x06, 0x48, 0x8e, 0x92, 0x06, 0x19, 0xb6, 0x35, 0xd2, 0x72, 0x38, 0x4a, + 0x19, 0x50, 0xc7, 0x1f, 0x5a, 0xae, 0xb6, 0x44, 0x57, 0x98, 0x15, 0x9c, 0x82, 0x77, 0x69, 0x79, + 0xec, 0xba, 0x18, 0xd6, 0xf1, 0x4f, 0xf7, 0x02, 0xc7, 0xc7, 0xbd, 0x8e, 0xd1, 0x85, 0xfb, 0xff, + 0x88, 0x74, 0xfb, 0xce, 0xd8, 0x6f, 0xf0, 0x03, 0x8d, 0xd1, 0x28, 0x81, 0x91, 0xc9, 0x90, 0xe7, + 0x3a, 0xd9, 0x4b, 0x67, 0x10, 0x39, 0x9c, 0x1f, 0xea, 0x38, 0x79, 0x16, 0xb9, 0x84, 0x48, 0xc3, + 0x26, 0x41, 0x62, 0x0e, 0x99, 0xdf, 0x7c, 0xf6, 0xb7, 0xfe, 0xe8, 0x56, 0xee, 0x0f, 0xff, 0xe8, + 0x56, 0xee, 0x7f, 0xfe, 0xa3, 0x5b, 0x97, 0xfe, 0xd2, 0x1f, 0xdf, 0xca, 0xfd, 0xfe, 0x1f, 0xdf, + 0xca, 0xfd, 0xe1, 0x1f, 0xdf, 0xca, 0xfd, 0x77, 0x7f, 0x7c, 0x2b, 0xf7, 0xcb, 0x8f, 0x8e, 0x9c, + 0xe8, 0x78, 0x7a, 0xf0, 0x60, 0xe8, 0x8f, 0x3f, 0x1e, 0x5b, 0x51, 0xe0, 0x9c, 0xb1, 0x11, 0x57, + 0x25, 0x3c, 0xfb, 0xe3, 0xc9, 0xc9, 0xd1, 0xc7, 0x93, 0x83, 0x8f, 0x51, 0x5c, 0x3a, 0x58, 0xa1, + 0xfb, 0x55, 0x8f, 0xfe, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x45, 0x75, 0x8e, 0x28, 0x24, 0xc8, + 0x00, 0x00, } func (m *Type) Marshal() (dAtA []byte, err error) { @@ -34292,6 +34312,13 @@ func (m *RoutineCall) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.NamespaceFingerprint) > 0 { + i -= len(m.NamespaceFingerprint) + copy(dAtA[i:], m.NamespaceFingerprint) + i = encodeVarintPlan(dAtA, i, uint64(len(m.NamespaceFingerprint))) + i-- + dAtA[i] = 0x7a + } if m.Leakproof { i-- if m.Leakproof { @@ -34485,6 +34512,13 @@ func (m *RoutinePlanDependency) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.NamespaceFingerprint) > 0 { + i -= len(m.NamespaceFingerprint) + copy(dAtA[i:], m.NamespaceFingerprint) + i = encodeVarintPlan(dAtA, i, uint64(len(m.NamespaceFingerprint))) + i-- + dAtA[i] = 0x62 + } if m.Leakproof { i-- if m.Leakproof { @@ -41402,6 +41436,10 @@ func (m *RoutineCall) ProtoSize() (n int) { if m.Leakproof { n += 2 } + l = len(m.NamespaceFingerprint) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -41479,6 +41517,10 @@ func (m *RoutinePlanDependency) ProtoSize() (n int) { if m.Leakproof { n += 2 } + l = len(m.NamespaceFingerprint) + if l > 0 { + n += 1 + l + sovPlan(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -80888,6 +80930,38 @@ func (m *RoutineCall) Unmarshal(dAtA []byte) error { } } m.Leakproof = bool(v != 0) + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NamespaceFingerprint", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NamespaceFingerprint = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipPlan(dAtA[iNdEx:]) @@ -81258,6 +81332,38 @@ func (m *RoutinePlanDependency) Unmarshal(dAtA []byte) error { } } m.Leakproof = bool(v != 0) + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NamespaceFingerprint", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPlan + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthPlan + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthPlan + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NamespaceFingerprint = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipPlan(dAtA[iNdEx:]) diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index ae19eb8c94de0..1a5292a7c6033 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -34,11 +34,12 @@ type Udf struct { // FunctionID and Revision are resolved from the shared catalog. They are // part of the executable identity; the planner must never re-resolve a // Python routine by name or latest revision at execution time. - FunctionID int64 `json:"function_id,omitempty"` - AccountID uint64 `json:"account_id,omitempty"` - DatabaseID uint64 `json:"database_id,omitempty"` - Revision uint64 `json:"revision,omitempty"` - NamespaceVersion uint64 `json:"namespace_version,omitempty"` + FunctionID int64 `json:"function_id,omitempty"` + AccountID uint64 `json:"account_id,omitempty"` + DatabaseID uint64 `json:"database_id,omitempty"` + Revision uint64 `json:"revision,omitempty"` + NamespaceFingerprint string `json:"namespace_fingerprint,omitempty"` + NamespaceVersion uint64 `json:"namespace_version,omitempty"` // SQL revisions use the same immutable identity envelope as Python. These // fields are empty for legacy SQL rows, which intentionally remain on the // historical text-expansion path until they are explicitly replaced. @@ -335,7 +336,8 @@ func (u *Udf) GetRoutineCall() (*plan.RoutineCall, error) { } returnType := type2PlanType(body.ReturnType.Type()) return &plan.RoutineCall{ - ContractVersion: udf.PythonPlanContractVersion, + ContractVersion: udf.PythonPlanContractVersion, + NamespaceFingerprint: u.NamespaceFingerprint, FunctionRef: &plan.FunctionRef{ FunctionId: uint64(u.FunctionID), Revision: u.Revision, @@ -392,7 +394,8 @@ func (u *Udf) getSQLRoutineCall() (*plan.RoutineCall, error) { nullPolicy = udf.NullCallHandler } return &plan.RoutineCall{ - ContractVersion: udf.RoutinePlanContractVersion, + ContractVersion: udf.RoutinePlanContractVersion, + NamespaceFingerprint: u.NamespaceFingerprint, FunctionRef: &plan.FunctionRef{ FunctionId: uint64(u.FunctionID), Revision: u.Revision, diff --git a/pkg/sql/plan/routine_dependency.go b/pkg/sql/plan/routine_dependency.go index f80920cf8f2dd..31765cfcef242 100644 --- a/pkg/sql/plan/routine_dependency.go +++ b/pkg/sql/plan/routine_dependency.go @@ -60,6 +60,7 @@ func (builder *QueryBuilder) recordRoutinePlanDependency(call *planpb.RoutineCal DatabaseId: ref.DatabaseId, }, Language: call.Language, + NamespaceFingerprint: call.NamespaceFingerprint, ContractVersion: call.ContractVersion, DefinitionFingerprint: "", Volatility: call.Volatility, @@ -94,7 +95,8 @@ func routinePlanDependenciesEqual(left, right *planpb.RoutinePlanDependency) boo if left == nil || right == nil || left.FunctionRef == nil || right.FunctionRef == nil { return left == right } - return left.Language == right.Language && + return left.NamespaceFingerprint == right.NamespaceFingerprint && + left.Language == right.Language && left.ContractVersion == right.ContractVersion && left.DefinitionFingerprint == right.DefinitionFingerprint && left.ArtifactDigest == right.ArtifactDigest && diff --git a/pkg/udf/python/capability_lifecycle_test.go b/pkg/udf/python/capability_lifecycle_test.go new file mode 100644 index 0000000000000..04afe1e595458 --- /dev/null +++ b/pkg/udf/python/capability_lifecycle_test.go @@ -0,0 +1,198 @@ +// Copyright 2026 Matrix Origin +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. + +package python + +import ( + "context" + "encoding/json" + "errors" + "sync" + "testing" + "time" + + "github.com/apache/arrow-go/v18/arrow/flight/gen/flight" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/matrixorigin/matrixone/pkg/udf/protocol" + "google.golang.org/grpc" +) + +type blockedCapabilityClient struct { + flight.FlightServiceClient + started chan struct{} + release chan struct{} + once sync.Once +} + +func (c *blockedCapabilityClient) DoAction(ctx context.Context, _ *flight.Action, _ ...grpc.CallOption) (flight.FlightService_DoActionClient, error) { + c.once.Do(func() { close(c.started) }) + select { + case <-c.release: + if err := ctx.Err(); err != nil { + return nil, err + } + return nil, errors.New("released test capability probe") + case <-ctx.Done(): + return nil, ctx.Err() + } +} + +func TestCancelledReadinessDoesNotWaitForOtherProbe(t *testing.T) { + gateway, err := NewGateway(ClientConfig{Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:1", RequestTimeout: 30 * time.Second}) + if err != nil { + t.Fatal(err) + } + defer gateway.Close() + client := &blockedCapabilityClient{started: make(chan struct{}), release: make(chan struct{})} + gateway.flight = client + firstDone := make(chan error, 1) + go func() { firstDone <- gateway.CheckLanguageReady(context.Background(), udf.LanguagePython) }() + select { + case <-client.started: + case <-time.After(time.Second): + t.Fatal("first probe did not reach the Flight boundary") + } + ctx, cancel := context.WithCancel(context.Background()) + cancel() + secondStarted := make(chan struct{}) + secondDone := make(chan error, 1) + go func() { + close(secondStarted) + secondDone <- gateway.CheckLanguageReady(ctx, udf.LanguagePython) + }() + <-secondStarted + blocked := false + select { + case err := <-secondDone: + if !errors.Is(err, context.Canceled) { + t.Errorf("cancelled probe returned %v", err) + } + case <-time.After(200 * time.Millisecond): + blocked = true + } + close(client.release) + <-firstDone + if blocked { + if err := <-secondDone; !errors.Is(err, context.Canceled) { + t.Errorf("released cancelled probe returned %v", err) + } + t.Fatal("already-cancelled readiness blocked behind another request's capabilityMu/Flight probe; it returned only after the unrelated probe was released") + } +} + +func TestCapabilityInvalidationDoesNotWaitForProbe(t *testing.T) { + g, err := NewGateway(ClientConfig{Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:1", RequestTimeout: time.Second}) + if err != nil { + t.Fatal(err) + } + defer g.Close() + c := &blockedCapabilityClient{started: make(chan struct{}), release: make(chan struct{})} + done := make(chan error, 1) + go func() { done <- g.ensureCapabilities(context.Background(), c, true) }() + <-c.started + invalidated := make(chan struct{}) + go func() { g.invalidateCapabilities(); close(invalidated) }() + select { + case <-invalidated: + case <-time.After(time.Second): + close(c.release) + <-done + t.Fatal("invalidation blocked on RPC") + } + if err := <-done; err == nil { + t.Fatal("invalidated probe succeeded") + } + g.mu.Lock() + defer g.mu.Unlock() + if g.capabilityReady || g.workerLeaseEpoch != 0 || g.capabilityProbe != nil { + t.Fatal("probe retained state") + } +} + +func TestStaleCapabilityFailurePreservesNewGeneration(t *testing.T) { + g := &Gateway{capabilityGeneration: 2, capabilityReady: true, workerLeaseEpoch: 42} + g.invalidateCapabilities(1) + if !g.capabilityReady || g.workerLeaseEpoch != 42 { + t.Fatal("old failure invalidated new lease") + } + g.invalidateCapabilities(2) + if g.capabilityReady || g.workerLeaseEpoch != 0 { + t.Fatal("current failure retained lease") + } +} + +func currentTestCapabilities() capabilityResponse { + response := capabilityResponse{ + ProtocolVersion: protocol.Version, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + PlanContractVersion: udf.PythonPlanContractVersion, + TypeDescriptorContract: udf.PythonTypeDescriptorContract, + TimezoneDatabaseVersion: currentTimezoneDatabaseVersion(), + Modes: []string{ModeScalar, ModeVector}, + NullPolicies: []string{NullCallHandler, NullReturnNull}, + WindowBatches: 1, + MaxExecutionFrameBytes: 1 << 30, + MaxHandlerProcesses: DefaultWorkerMaxHandlerProcesses, + MaxAccountHandlerProcesses: DefaultWorkerMaxAccountHandlers, + MaxOwnerHandlerProcesses: DefaultWorkerMaxOwnerHandlers, + } + response.LeaseEpoch = 42 + return response +} + +type delayedCapabilityClient struct { + flight.FlightServiceClient + started chan struct{} + release chan struct{} + response capabilityResponse +} + +func (c *delayedCapabilityClient) DoAction(ctx context.Context, _ *flight.Action, _ ...grpc.CallOption) (flight.FlightService_DoActionClient, error) { + close(c.started) + <-c.release // Deliberately ignore cancellation: exercise the publication fence. + payload, err := json.Marshal(c.response) + return &finishAckActionStream{result: &flight.Result{Body: payload}}, err +} +func TestCapabilityLateResponseCannotRepublish(t *testing.T) { + for _, closeGateway := range []bool{false, true} { + t.Run(map[bool]string{false: "invalidate", true: "close"}[closeGateway], func(t *testing.T) { + g, err := NewGateway(ClientConfig{Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:1", RequestTimeout: time.Second}) + if err != nil { + t.Fatal(err) + } + defer g.Close() + c := &delayedCapabilityClient{started: make(chan struct{}), release: make(chan struct{}), response: currentTestCapabilities()} + done := make(chan error, 1) + go func() { done <- g.ensureCapabilities(context.Background(), c, true) }() + <-c.started + // Close/invalidation must return while a misbehaving transport is blocked. + if closeGateway { + if err := g.Close(); err != nil { + t.Fatal(err) + } + } else { + g.invalidateCapabilities() + } + g.mu.Lock() + occupied := g.capabilityProbe != nil + g.mu.Unlock() + if !occupied { + t.Error("cancelled physical probe released its slot too early") + } + close(c.release) + if err := <-done; err == nil { + t.Fatal("late success escaped generation fence") + } + g.mu.Lock() + defer g.mu.Unlock() + if g.capabilityReady || g.workerLeaseEpoch != 0 || g.capability != nil || g.capabilityProbe != nil { + t.Fatal("late response republished state") + } + }) + } +} diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index c619d59137d3e..ea79515ec6d47 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -59,23 +59,24 @@ var _ udf.RuntimeDefinitionValidator = (*Gateway)(nil) var _ udf.RuntimeStatusProvider = (*Gateway)(nil) type Gateway struct { - cfg ClientConfig - artifactResolver ArtifactResolver - allowInlineSource bool - conn *grpc.ClientConn - flight flight.FlightServiceClient - mu sync.Mutex - lifecycleCtx context.Context - lifecycleCancel context.CancelFunc - capabilityMu sync.Mutex - admissionMu sync.Mutex - capabilityReady bool - workerLeaseEpoch uint64 - capability *capabilityResponse - closed bool - active chan struct{} - ledger *protocol.TerminalLedger - ledgerTTL time.Duration + cfg ClientConfig + artifactResolver ArtifactResolver + allowInlineSource bool + conn *grpc.ClientConn + flight flight.FlightServiceClient + mu sync.Mutex + lifecycleCtx context.Context + lifecycleCancel context.CancelFunc + capabilityGeneration uint64 + capabilityProbe *capabilityProbe + admissionMu sync.Mutex + capabilityReady bool + workerLeaseEpoch uint64 + capability *capabilityResponse + closed bool + active chan struct{} + ledger *protocol.TerminalLedger + ledgerTTL time.Duration // admittedGroups and closedGroups are the Gateway's ownership fence for // the current one-member adapter. A group epoch may be admitted only once; // a terminal tombstone is reclaimable only after its exact group epoch has @@ -400,7 +401,8 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin // lease in its request. It must perform its own worker-instance handshake; // relying on a cached readiness result could validate against a replacement // worker with a different contract. - if err := g.ensureCapabilities(requestCtx, client, true); err != nil { + capability, err := g.ensureCapabilitySnapshot(requestCtx, client, true) + if err != nil { return err } payload, err := json.Marshal(definitionValidationPayload{ @@ -430,33 +432,33 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin } stream, err := client.DoAction(actionCtx, &flight.Action{Type: "ValidatePythonDefinition", Body: payload}) if err != nil { - g.invalidateCapabilities() + g.invalidateCapabilities(capability.generation) return fmt.Errorf("python udf: definition validation action: %w", err) } result, err := stream.Recv() if err != nil { - g.invalidateCapabilities() + g.invalidateCapabilities(capability.generation) return fmt.Errorf("python udf: definition validation response: %w", err) } if result == nil { - g.invalidateCapabilities() + g.invalidateCapabilities(capability.generation) return fmt.Errorf("python udf: empty definition validation response") } var response definitionValidationResponse decoder := json.NewDecoder(bytes.NewReader(result.Body)) decoder.DisallowUnknownFields() if err := decoder.Decode(&response); err != nil { - g.invalidateCapabilities() + g.invalidateCapabilities(capability.generation) return fmt.Errorf("python udf: decode definition validation response: %w", err) } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { - g.invalidateCapabilities() + g.invalidateCapabilities(capability.generation) return fmt.Errorf("python udf: definition validation response has trailing JSON") } if response.Status == "ERROR" { if _, err := stream.Recv(); err != io.EOF { - g.invalidateCapabilities() + g.invalidateCapabilities(capability.generation) if err == nil { return fmt.Errorf("python udf: definition validation returned multiple results") } @@ -469,11 +471,11 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin } if response.Status != statusOK || response.ArtifactDigest != definition.ArtifactDigest || response.DefinitionFingerprint != definition.DefinitionFingerprint { - g.invalidateCapabilities() + g.invalidateCapabilities(capability.generation) return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition validation returned an invalid result") } if _, err := stream.Recv(); err != io.EOF { - g.invalidateCapabilities() + g.invalidateCapabilities(capability.generation) if err == nil { return fmt.Errorf("python udf: definition validation returned multiple results") } @@ -524,10 +526,19 @@ func (g *Gateway) Close() error { // released, no caller can pass the admission check after Close returns. g.admissionMu.Lock() g.closed = true + g.capabilityGeneration++ + g.capabilityReady, g.workerLeaseEpoch, g.capability = false, 0, nil + var probeCancel context.CancelFunc + if g.capabilityProbe != nil { + probeCancel = g.capabilityProbe.cancel + } conn := g.conn g.conn = nil g.admissionMu.Unlock() g.mu.Unlock() + if probeCancel != nil { + probeCancel() + } if conn == nil { return nil } @@ -684,7 +695,8 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul if err != nil { return err } - if err := g.ensureCapabilities(streamCtx, client, false); err != nil { + capability, err := g.ensureCapabilitySnapshot(streamCtx, client, false) + if err != nil { return err } // The worker instance owns the lease epoch. Copy the invocation before @@ -692,9 +704,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul // another worker process. If the worker was restarted after the cached // handshake, the exchange fails with STALE_LEASE_EPOCH and the deferred // invalidation below forces a fresh handshake on the next call. - g.mu.Lock() - workerLeaseEpoch := g.workerLeaseEpoch - g.mu.Unlock() + workerLeaseEpoch := capability.response.LeaseEpoch if workerLeaseEpoch == 0 { return fmt.Errorf("python udf: capability handshake did not return a worker lease epoch") } @@ -704,7 +714,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul } defer func() { if err != nil { - g.invalidateCapabilities() + g.invalidateCapabilities(capability.generation) } }() openBody, err := json.Marshal(openPayload{ @@ -1232,97 +1242,139 @@ type capabilityResponse struct { // Gateway connection before OpenInvocation, and it caches only a successful // match. A worker with an unknown or different contract therefore cannot run // user code, while ordinary SQL remains independent of this client. +type capabilitySnapshot struct { + generation uint64 + response capabilityResponse +} + +type capabilityProbe struct { + generation uint64 + done chan struct{} + cancel context.CancelFunc + snapshot capabilitySnapshot + err error +} + func (g *Gateway) ensureCapabilities(ctx context.Context, client flight.FlightServiceClient, forceRefresh bool) error { - g.capabilityMu.Lock() - defer g.capabilityMu.Unlock() + _, err := g.ensureCapabilitySnapshot(ctx, client, forceRefresh) + return err +} + +// One caller owns the RPC. Joiners wait with their own deadline and cancellation; +// no network operation or wait holds mu. The owner alone retires the probe. +func (g *Gateway) ensureCapabilitySnapshot(ctx context.Context, client flight.FlightServiceClient, forceRefresh bool) (capabilitySnapshot, error) { + ctx, release := g.withLifecycleContext(ctx) + defer release() + ctx, cancel := context.WithTimeout(ctx, g.cfg.RequestTimeout) + defer cancel() + if err := ctx.Err(); err != nil { + return capabilitySnapshot{}, err + } g.mu.Lock() - if forceRefresh { - // Clear the old lease before probing. If the probe fails, callers must - // observe the worker as unavailable rather than retaining a stale - // success that could authorize a lease-less Flight Action. - g.capabilityReady = false - g.workerLeaseEpoch = 0 - g.capability = nil - } - ready := g.capabilityReady - closed := g.closed - g.mu.Unlock() - if closed { - return errGatewayClosed + if g.closed { + g.mu.Unlock() + return capabilitySnapshot{}, errGatewayClosed } - if ready { - g.mu.Lock() - leaseEpoch := g.workerLeaseEpoch + if !forceRefresh && g.capabilityReady && g.capability != nil && g.workerLeaseEpoch != 0 { + snapshot := capabilitySnapshot{g.capabilityGeneration, *g.capability} g.mu.Unlock() - if leaseEpoch != 0 { - return nil + return snapshot, ctx.Err() + } + if p := g.capabilityProbe; p != nil { + g.mu.Unlock() + select { + case <-ctx.Done(): + return capabilitySnapshot{}, ctx.Err() + case <-p.done: + if err := ctx.Err(); err != nil { + return capabilitySnapshot{}, err + } + return p.snapshot, p.err } - // A partially initialized Gateway must not treat readiness as a valid - // worker contract. Fall through and establish the complete capability - // record again. } + g.capabilityGeneration++ + g.capabilityReady, g.workerLeaseEpoch, g.capability = false, 0, nil + p := &capabilityProbe{generation: g.capabilityGeneration, done: make(chan struct{}), cancel: cancel} + g.capabilityProbe = p + g.mu.Unlock() + response, err := readCapabilities(ctx, client) + g.mu.Lock() + if g.closed { + err = errGatewayClosed + } else if p.generation != g.capabilityGeneration { + err = errors.New("python udf: capability probe invalidated") + } else if ctx.Err() != nil { + err = ctx.Err() + } + if err == nil { + // response is immutable after publication, including its decoded slices. + g.capabilityReady, g.workerLeaseEpoch, g.capability = true, response.LeaseEpoch, response + p.snapshot = capabilitySnapshot{p.generation, *response} + } + p.err = err + g.capabilityProbe = nil + close(p.done) + g.mu.Unlock() + return p.snapshot, p.err +} + +func readCapabilities(ctx context.Context, client flight.FlightServiceClient) (*capabilityResponse, error) { request, err := json.Marshal(capabilityRequest{ProtocolVersion: protocol.Version}) if err != nil { - return err + return nil, err } - actionCtx, cancel := context.WithTimeout(ctx, g.cfg.RequestTimeout) - defer cancel() - stream, err := client.DoAction(actionCtx, &flight.Action{Type: "GetPythonCapabilities", Body: request}) + stream, err := client.DoAction(ctx, &flight.Action{Type: "GetPythonCapabilities", Body: request}) if err != nil { - return fmt.Errorf("python udf: capability handshake: %w", err) + return nil, fmt.Errorf("python udf: capability handshake: %w", err) } result, err := stream.Recv() if err != nil { - return fmt.Errorf("python udf: capability handshake response: %w", err) + return nil, fmt.Errorf("python udf: capability handshake response: %w", err) } if result == nil { - return fmt.Errorf("python udf: empty capability handshake response") + return nil, fmt.Errorf("python udf: empty capability handshake response") } var response capabilityResponse decoder := json.NewDecoder(bytes.NewReader(result.Body)) decoder.DisallowUnknownFields() if err := decoder.Decode(&response); err != nil { - return fmt.Errorf("python udf: decode capability handshake: %w", err) + return nil, fmt.Errorf("python udf: decode capability handshake: %w", err) } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { - return fmt.Errorf("python udf: capability handshake has trailing JSON") + return nil, fmt.Errorf("python udf: capability handshake has trailing JSON") } if err := validateCapabilities(response); err != nil { - return err + return nil, err } if _, err := stream.Recv(); err != io.EOF { if err == nil { - return fmt.Errorf("python udf: capability handshake returned multiple results") + return nil, fmt.Errorf("python udf: capability handshake returned multiple results") } - return fmt.Errorf("python udf: capability handshake stream: %w", err) - } - g.mu.Lock() - if !g.closed { - g.capabilityReady = true - g.workerLeaseEpoch = response.LeaseEpoch - capability := response - capability.Modes = append([]string(nil), response.Modes...) - capability.NullPolicies = append([]string(nil), response.NullPolicies...) - g.capability = &capability + return nil, fmt.Errorf("python udf: capability handshake stream: %w", err) } - g.mu.Unlock() - return nil + return &response, nil } -// invalidateCapabilities is called after a post-handshake execution error. -// In particular, a restarted worker keeps the same endpoint but advertises a -// new instance lease epoch; clearing the cached record makes the next -// invocation perform the handshake again. This never retries the failed -// invocation or changes its terminal outcome. -func (g *Gateway) invalidateCapabilities() { - g.capabilityMu.Lock() - defer g.capabilityMu.Unlock() +// Invalidating an old execution must not evict a newer worker handshake. Keep a +// cancelled probe in its physical slot until its owner exits, bounding RPCs even +// if the transport is slow to acknowledge cancellation. +func (g *Gateway) invalidateCapabilities(expected ...uint64) { g.mu.Lock() - g.capabilityReady = false - g.workerLeaseEpoch = 0 - g.capability = nil + if len(expected) != 0 && expected[0] != g.capabilityGeneration { + g.mu.Unlock() + return + } + g.capabilityGeneration++ + g.capabilityReady, g.workerLeaseEpoch, g.capability = false, 0, nil + var cancel context.CancelFunc + if g.capabilityProbe != nil { + cancel = g.capabilityProbe.cancel + } g.mu.Unlock() + if cancel != nil { + cancel() + } } func validateCapabilities(response capabilityResponse) error { diff --git a/pkg/udf/runtime_status_wire_test.go b/pkg/udf/runtime_status_wire_test.go new file mode 100644 index 0000000000000..ef52beffbf94e --- /dev/null +++ b/pkg/udf/runtime_status_wire_test.go @@ -0,0 +1,39 @@ +// Copyright 2026 Matrix Origin +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +package udf + +import ( + "encoding/base64" + "encoding/json" + "github.com/matrixorigin/matrixone/pkg/pb/query" + "github.com/stretchr/testify/require" + "os" + "testing" +) + +// The identical fixture is consumed by Operator's independent wire decoder. +// This prevents successful status alone from concealing fault-enum drift. +func TestPythonStatusWireContract(t *testing.T) { + expected := map[string][]string{ + "": {RuntimeStatusReasonReady}, RuntimeStatusDisabled: {RuntimeStatusReasonRuntimeDisabled}, RuntimeStatusNotAllowed: {RuntimeStatusReasonUnisolatedNotAllowed}, + RuntimeStatusUnavailable: {RuntimeStatusReasonWorkerUnavailable, RuntimeStatusReasonStatusUnavailable}, RuntimeStatusContractMismatch: {RuntimeStatusReasonCapabilityMismatch}, RuntimeStatusTimeout: {RuntimeStatusReasonRequestTimeout}, RuntimeStatusClosed: {RuntimeStatusReasonRuntimeClosed}, RuntimeStatusInvalid: {RuntimeStatusReasonInvalidLanguage}, RuntimeStatusInternal: {RuntimeStatusReasonRuntimeError}, + } + raw, err := os.ReadFile("testdata/python_status_wire.json") + require.NoError(t, err) + var rows []struct{ Class, Reason, Wire string } + require.NoError(t, json.Unmarshal(raw, &rows)) + seen := map[string][]string{} + for _, row := range rows { + wire, err := base64.StdEncoding.DecodeString(row.Wire) + require.NoError(t, err) + var response query.Response + require.NoError(t, response.Unmarshal(wire)) + require.Equal(t, query.CmdMethod_GetPythonUdfStatus, response.CmdMethod) + require.Equal(t, row.Class, response.GetPythonUdfStatus.ErrorClass) + require.Equal(t, row.Reason, response.GetPythonUdfStatus.Reason) + require.Equal(t, row.Class == "", response.GetPythonUdfStatus.Ready) + seen[row.Class] = append(seen[row.Class], row.Reason) + } + require.Equal(t, expected, seen) +} diff --git a/pkg/udf/testdata/python_status_wire.json b/pkg/udf/testdata/python_status_wire.json new file mode 100644 index 0000000000000..6b35d431092a8 --- /dev/null +++ b/pkg/udf/testdata/python_status_wire.json @@ -0,0 +1,52 @@ +[ + { + "Class": "", + "Reason": "CapabilityHandshakeReady", + "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICMQoEY24tMRIGcHl0aG9uGAEgASgBOhhDYXBhYmlsaXR5SGFuZHNoYWtlUmVhZHmwASo=" + }, + { + "Class": "DISABLED", + "Reason": "RuntimeDisabled", + "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICLgoEY24tMRIGcHl0aG9uIAEyCERJU0FCTEVEOg9SdW50aW1lRGlzYWJsZWSwASo=" + }, + { + "Class": "NOT_ALLOWED", + "Reason": "UnisolatedExecutionNotAllowed", + "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICPwoEY24tMRIGcHl0aG9uGAEyC05PVF9BTExPV0VEOh1Vbmlzb2xhdGVkRXhlY3V0aW9uTm90QWxsb3dlZLABKg==" + }, + { + "Class": "UNAVAILABLE", + "Reason": "WorkerUnavailable", + "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICNQoEY24tMRIGcHl0aG9uGAEgATILVU5BVkFJTEFCTEU6EVdvcmtlclVuYXZhaWxhYmxlsAEq" + }, + { + "Class": "UNAVAILABLE", + "Reason": "RuntimeStatusUnavailable", + "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICPAoEY24tMRIGcHl0aG9uGAEgATILVU5BVkFJTEFCTEU6GFJ1bnRpbWVTdGF0dXNVbmF2YWlsYWJsZbABKg==" + }, + { + "Class": "CONTRACT_MISMATCH", + "Reason": "CapabilityContractMismatch", + "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICRAoEY24tMRIGcHl0aG9uGAEgATIRQ09OVFJBQ1RfTUlTTUFUQ0g6GkNhcGFiaWxpdHlDb250cmFjdE1pc21hdGNosAEq" + }, + { + "Class": "TIMEOUT", + "Reason": "CapabilityRequestTimeout", + "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICOAoEY24tMRIGcHl0aG9uGAEgATIHVElNRU9VVDoYQ2FwYWJpbGl0eVJlcXVlc3RUaW1lb3V0sAEq" + }, + { + "Class": "CLOSED", + "Reason": "RuntimeClosed", + "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICLAoEY24tMRIGcHl0aG9uGAEgATIGQ0xPU0VEOg1SdW50aW1lQ2xvc2VksAEq" + }, + { + "Class": "INVALID", + "Reason": "InvalidLanguage", + "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICLwoEY24tMRIGcHl0aG9uGAEgATIHSU5WQUxJRDoPSW52YWxpZExhbmd1YWdlsAEq" + }, + { + "Class": "INTERNAL", + "Reason": "RuntimeError", + "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICLQoEY24tMRIGcHl0aG9uGAEgATIISU5URVJOQUw6DFJ1bnRpbWVFcnJvcrABKg==" + } +] diff --git a/proto/plan.proto b/proto/plan.proto index 44b3b88f93f73..3d6e5e58d5a3d 100644 --- a/proto/plan.proto +++ b/proto/plan.proto @@ -2591,6 +2591,9 @@ message RoutineCall { bool may_error = 12; string security_mode = 13; bool leakproof = 14; + // State fingerprint of the complete overload namespace at binding snapshot. + // Separate from the selected immutable FunctionRef; missing means no reuse. + string namespace_fingerprint = 15; } // RoutinePlanDependency is the shared cache/prepared-plan validation envelope @@ -2609,6 +2612,7 @@ message RoutinePlanDependency { bool may_error = 9; string security_mode = 10; bool leakproof = 11; + string namespace_fingerprint = 12; } // A zero version represents a legacy database without a persisted default. diff --git a/test/distributed/cases/udf/overload_namespace.result b/test/distributed/cases/udf/overload_namespace.result new file mode 100644 index 0000000000000..ff683f260eaef --- /dev/null +++ b/test/distributed/cases/udf/overload_namespace.result @@ -0,0 +1,57 @@ +drop database if exists udf_sql_namespace_bvt; +create database udf_sql_namespace_bvt; +use udf_sql_namespace_bvt; +create table namespace_values(x smallint); +insert into namespace_values values (1),(2); +create function overload(x bigint) returns bigint language sql as '$1 + 100'; +select overload(x) as result from namespace_values order by x; +➤ result[-5,64,0] 𝄀 +101 𝄀 +102 +prepare namespace_plan from 'select overload(x) as result from namespace_values order by x'; +execute namespace_plan; +➤ result[-5,64,0] 𝄀 +101 𝄀 +102 +use udf_sql_namespace_bvt; +create function overload(x smallint) returns bigint language sql as '$1 + 200'; +execute namespace_plan; +➤ result[-5,64,0] 𝄀 +201 𝄀 +202 +select overload(x) as result from namespace_values order by x; +➤ result[-5,64,0] 𝄀 +201 𝄀 +202 +use udf_sql_namespace_bvt; +create or replace function overload(x smallint) returns bigint language sql as '$1 + 300'; +execute namespace_plan; +➤ result[-5,64,0] 𝄀 +301 𝄀 +302 +select overload(x) as result from namespace_values order by x; +➤ result[-5,64,0] 𝄀 +301 𝄀 +302 +use udf_sql_namespace_bvt; +drop function overload(smallint); +execute namespace_plan; +➤ result[-5,64,0] 𝄀 +101 𝄀 +102 +select overload(x) as result from namespace_values order by x; +➤ result[-5,64,0] 𝄀 +101 𝄀 +102 +use udf_sql_namespace_bvt; +create function overload(x smallint) returns bigint language sql as '$1 + 400'; +execute namespace_plan; +➤ result[-5,64,0] 𝄀 +401 𝄀 +402 +select overload(x) as result from namespace_values order by x; +➤ result[-5,64,0] 𝄀 +401 𝄀 +402 +deallocate prepare namespace_plan; +drop database udf_sql_namespace_bvt; diff --git a/test/distributed/cases/udf/overload_namespace.sql b/test/distributed/cases/udf/overload_namespace.sql new file mode 100644 index 0000000000000..fb6f89938b7b5 --- /dev/null +++ b/test/distributed/cases/udf/overload_namespace.sql @@ -0,0 +1,35 @@ +drop database if exists udf_sql_namespace_bvt; +create database udf_sql_namespace_bvt; +use udf_sql_namespace_bvt; +create table namespace_values(x smallint); +insert into namespace_values values (1),(2); +create function overload(x bigint) returns bigint language sql as '$1 + 100'; +select overload(x) as result from namespace_values order by x; +prepare namespace_plan from 'select overload(x) as result from namespace_values order by x'; +execute namespace_plan; +-- @session:id=1 +use udf_sql_namespace_bvt; +create function overload(x smallint) returns bigint language sql as '$1 + 200'; +-- @session +execute namespace_plan; +select overload(x) as result from namespace_values order by x; +-- @session:id=1 +use udf_sql_namespace_bvt; +create or replace function overload(x smallint) returns bigint language sql as '$1 + 300'; +-- @session +execute namespace_plan; +select overload(x) as result from namespace_values order by x; +-- @session:id=1 +use udf_sql_namespace_bvt; +drop function overload(smallint); +-- @session +execute namespace_plan; +select overload(x) as result from namespace_values order by x; +-- @session:id=1 +use udf_sql_namespace_bvt; +create function overload(x smallint) returns bigint language sql as '$1 + 400'; +-- @session +execute namespace_plan; +select overload(x) as result from namespace_values order by x; +deallocate prepare namespace_plan; +drop database udf_sql_namespace_bvt; diff --git a/test/distributed/cases/udf_python/overload_namespace.result b/test/distributed/cases/udf_python/overload_namespace.result new file mode 100644 index 0000000000000..22f90130768aa --- /dev/null +++ b/test/distributed/cases/udf_python/overload_namespace.result @@ -0,0 +1,57 @@ +drop database if exists udf_python_namespace_bvt; +create database udf_python_namespace_bvt; +use udf_python_namespace_bvt; +create table namespace_values(x smallint); +insert into namespace_values values (1),(2); +create function overload(x bigint) returns bigint language python as 'def overload(ctx,x): return x + 100' handler 'overload'; +select overload(x) as result from namespace_values order by x; +➤ result[-5,64,0] 𝄀 +101 𝄀 +102 +prepare namespace_plan from 'select overload(x) as result from namespace_values order by x'; +execute namespace_plan; +➤ result[-5,64,0] 𝄀 +101 𝄀 +102 +use udf_python_namespace_bvt; +create function overload(x smallint) returns bigint language python as 'def overload(ctx,x): return x + 200' handler 'overload'; +execute namespace_plan; +➤ result[-5,64,0] 𝄀 +201 𝄀 +202 +select overload(x) as result from namespace_values order by x; +➤ result[-5,64,0] 𝄀 +201 𝄀 +202 +use udf_python_namespace_bvt; +create or replace function overload(x smallint) returns bigint language python as 'def overload(ctx,x): return x + 300' handler 'overload'; +execute namespace_plan; +➤ result[-5,64,0] 𝄀 +301 𝄀 +302 +select overload(x) as result from namespace_values order by x; +➤ result[-5,64,0] 𝄀 +301 𝄀 +302 +use udf_python_namespace_bvt; +drop function overload(smallint); +execute namespace_plan; +➤ result[-5,64,0] 𝄀 +101 𝄀 +102 +select overload(x) as result from namespace_values order by x; +➤ result[-5,64,0] 𝄀 +101 𝄀 +102 +use udf_python_namespace_bvt; +create function overload(x smallint) returns bigint language python as 'def overload(ctx,x): return x + 400' handler 'overload'; +execute namespace_plan; +➤ result[-5,64,0] 𝄀 +401 𝄀 +402 +select overload(x) as result from namespace_values order by x; +➤ result[-5,64,0] 𝄀 +401 𝄀 +402 +deallocate prepare namespace_plan; +drop database udf_python_namespace_bvt; diff --git a/test/distributed/cases/udf_python/overload_namespace.sql b/test/distributed/cases/udf_python/overload_namespace.sql new file mode 100644 index 0000000000000..5a1634f84bd04 --- /dev/null +++ b/test/distributed/cases/udf_python/overload_namespace.sql @@ -0,0 +1,35 @@ +drop database if exists udf_python_namespace_bvt; +create database udf_python_namespace_bvt; +use udf_python_namespace_bvt; +create table namespace_values(x smallint); +insert into namespace_values values (1),(2); +create function overload(x bigint) returns bigint language python as 'def overload(ctx,x): return x + 100' handler 'overload'; +select overload(x) as result from namespace_values order by x; +prepare namespace_plan from 'select overload(x) as result from namespace_values order by x'; +execute namespace_plan; +-- @session:id=1 +use udf_python_namespace_bvt; +create function overload(x smallint) returns bigint language python as 'def overload(ctx,x): return x + 200' handler 'overload'; +-- @session +execute namespace_plan; +select overload(x) as result from namespace_values order by x; +-- @session:id=1 +use udf_python_namespace_bvt; +create or replace function overload(x smallint) returns bigint language python as 'def overload(ctx,x): return x + 300' handler 'overload'; +-- @session +execute namespace_plan; +select overload(x) as result from namespace_values order by x; +-- @session:id=1 +use udf_python_namespace_bvt; +drop function overload(smallint); +-- @session +execute namespace_plan; +select overload(x) as result from namespace_values order by x; +-- @session:id=1 +use udf_python_namespace_bvt; +create function overload(x smallint) returns bigint language python as 'def overload(ctx,x): return x + 400' handler 'overload'; +-- @session +execute namespace_plan; +select overload(x) as result from namespace_values order by x; +deallocate prepare namespace_plan; +drop database udf_python_namespace_bvt; From 05de7ffb6a466401ad96eaf9dba88a7255448207 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 20 Sep 2026 12:29:29 +0800 Subject: [PATCH 186/241] test(udf): supply NULL input for scalar control-flow assertion --- test/distributed/cases/udf_python/control_flow.result | 2 +- test/distributed/cases/udf_python/control_flow.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/distributed/cases/udf_python/control_flow.result b/test/distributed/cases/udf_python/control_flow.result index 10afe7303cdae..f850f15cf9194 100644 --- a/test/distributed/cases/udf_python/control_flow.result +++ b/test/distributed/cases/udf_python/control_flow.result @@ -18,7 +18,7 @@ from control_values order by id; 1 ¦ 𝄀 2 ¦ <中😀> 𝄀 3 ¦ -select id, python_bvt_add_one(value) as plus_one +select id, python_bvt_add_one(case when id = 3 then null else value end) as plus_one from control_values order by id; ➤ id[4,32,0] ¦ plus_one[4,32,0] 𝄀 1 ¦ 2 𝄀 diff --git a/test/distributed/cases/udf_python/control_flow.sql b/test/distributed/cases/udf_python/control_flow.sql index 5b133dbdc9d70..9e3652cae5c93 100644 --- a/test/distributed/cases/udf_python/control_flow.sql +++ b/test/distributed/cases/udf_python/control_flow.sql @@ -22,7 +22,7 @@ select id, python_bvt_mark_null(label) as marked from control_values order by id; -- A scalar handler must be invoked once per row and preserve a handler NULL. -select id, python_bvt_add_one(value) as plus_one +select id, python_bvt_add_one(case when id = 3 then null else value end) as plus_one from control_values order by id; -- A zero-argument scalar still produces one result per input row. From 5d008a577a19e227b6b624097f6297ce99c6636a Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 20 Sep 2026 14:42:40 +0800 Subject: [PATCH 187/241] fix(udf): preserve exact DROP and failed initialization ownership --- pkg/frontend/authenticate.go | 6 +- pkg/frontend/python_udf_catalog_test.go | 23 +++ pkg/frontend/snapshot_test.go | 8 +- pkg/udf/python/worker/Dockerfile | 9 + pkg/udf/python/worker/test_worker.py | 180 +++++++++++++++++- pkg/udf/python/worker/worker.py | 50 +++-- .../issue_27103_clone_external_table.result | 4 +- .../issue_27103_clone_external_table.sql | 4 +- test/distributed/cases/udf_python/README.md | 5 + .../udf_python/overload_namespace.result | 13 ++ .../cases/udf_python/overload_namespace.sql | 8 + .../cases/udf_python/snapshot_restore.result | 40 ++++ .../cases/udf_python/snapshot_restore.sql | 34 ++++ 13 files changed, 355 insertions(+), 29 deletions(-) create mode 100644 test/distributed/cases/udf_python/snapshot_restore.result create mode 100644 test/distributed/cases/udf_python/snapshot_restore.sql diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index a63110a0c428d..c0fbb80ead036 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -5086,7 +5086,11 @@ func doDropFunction(ctx context.Context, ses *Session, df *tree.DropFunction, rm // overloads would be indistinguishable and DROP could remove the // wrong immutable identity. A non-current body is left on the // logical path so an old demo can still be explicitly removed. - if !pythonDropSignatureMatches(df.Args, argstr) { + body, err := erArray[0].GetString(ctx, i, 2) + if err != nil { + return err + } + if !pythonDropSignatureMatches(df.Args, body) { continue } handleArgMatch := func() (rtnErr error) { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index c2cd6c78d87ee..44d12281c6beb 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -13,6 +13,7 @@ import ( "strings" "testing" + "github.com/golang/mock/gomock" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/config" @@ -26,6 +27,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/plan/function" "github.com/matrixorigin/matrixone/pkg/udf" pythonudf "github.com/matrixorigin/matrixone/pkg/udf/python" + "github.com/prashantv/gostub" "github.com/stretchr/testify/require" ) @@ -1140,4 +1142,25 @@ func TestPythonDropSignatureUsesExactDescriptor(t *testing.T) { require.True(t, pythonDropSignatureMatches(drop.Args, makeBody(decimal2))) require.False(t, pythonDropSignatureMatches(drop.Args, makeBody(decimal6))) + + // Exercise the catalog projection wiring, not only the descriptor helper. + ctrl := gomock.NewController(t) + ses := newSes(nil, ctrl) + ctx := ses.GetTxnHandler().GetTxnCtx() + bh := &backgroundExecTest{} + bh.init() + stub := gostub.StubFunc(&NewBackgroundExec, bh) + defer stub.Reset() + checkDB, err := getSqlForCheckDatabaseByAccount(ctx, "db") + require.NoError(t, err) + bh.sql2result[checkDB] = newMrsForCheckDatabase([][]interface{}{{int64(1)}}) + bh.sql2result[fmt.Sprintf(checkUdfArgs, "f", "db")] = newMrsForCheckUdfArgs([][]interface{}{ + {`[{"name":"value","type":"decimal"}]`, int64(101), makeBody(decimal2)}, + {`[{"name":"value","type":"decimal"}]`, int64(102), makeBody(decimal6)}, + }) + require.NoError(t, doDropFunction(ctx, ses, drop, nil)) + require.Contains(t, bh.executedSQLs, fmt.Sprintf(deleteUserDefinedFunctionFormat, 101)) + require.Contains(t, bh.executedSQLs, fmt.Sprintf(deleteUserDefinedFunctionRevisionsFormat, 101)) + require.NotContains(t, bh.executedSQLs, fmt.Sprintf(deleteUserDefinedFunctionFormat, 102)) + require.NotContains(t, bh.executedSQLs, fmt.Sprintf(deleteUserDefinedFunctionRevisionsFormat, 102)) } diff --git a/pkg/frontend/snapshot_test.go b/pkg/frontend/snapshot_test.go index 3eb50f00e7a9d..393ea5582171c 100644 --- a/pkg/frontend/snapshot_test.go +++ b/pkg/frontend/snapshot_test.go @@ -1859,7 +1859,7 @@ func TestRecreateUserDefinedFunctionCatalogPreservesCurrentSchema(t *testing.T) bh := &backgroundExecTest{} bh.init() ctx := defines.AttachAccountId(t.Context(), sourceAccount) - require.NoError(t, recreateTable(ctx, "", bh, snapshotName, currentUDFTable, sourceAccount, snapshotTS)) + require.NoError(t, recreateTable(ctx, "", bh, snapshotName, currentUDFTable, sourceAccount, snapshotTS, false)) require.Contains(t, bh.executedSQLs[len(bh.executedSQLs)-1], " select "+userDefinedFunctionCatalogSourceColumns+" from ") }) @@ -1957,7 +1957,7 @@ func TestRecreatePythonFunctionRevisionCatalogPreservesCurrentSchema(t *testing. bh.init() bh.sql2result[validationSQL] = &MysqlResultSet{} ctx := defines.AttachAccountId(t.Context(), sourceAccount) - require.NoError(t, recreateTable(ctx, "", bh, snapshotName, currentTable, sourceAccount, snapshotTS)) + require.NoError(t, recreateTable(ctx, "", bh, snapshotName, currentTable, sourceAccount, snapshotTS, false)) require.Equal(t, []string{ dropTableIfExistsSQL(moCatalog, currentTable.tblName), MoCatalogMoFunctionRevisionDDL, @@ -1970,7 +1970,7 @@ func TestRecreatePythonFunctionRevisionCatalogPreservesCurrentSchema(t *testing. bh := &backgroundExecTest{} bh.init() ctx := defines.AttachAccountId(t.Context(), sourceAccount) - require.NoError(t, recreateTable(ctx, "", bh, snapshotName, legacyTable, sourceAccount, snapshotTS)) + require.NoError(t, recreateTable(ctx, "", bh, snapshotName, legacyTable, sourceAccount, snapshotTS, false)) require.Equal(t, []string{ dropTableIfExistsSQL(moCatalog, legacyTable.tblName), MoCatalogMoFunctionRevisionDDL, @@ -1983,7 +1983,7 @@ func TestRecreatePythonFunctionRevisionCatalogPreservesCurrentSchema(t *testing. bh.init() bh.sql2result[validationSQL] = &MysqlResultSet{} ctx := defines.AttachAccountId(t.Context(), sourceAccount) - require.NoError(t, recreateTable(ctx, "", bh, snapshotName, currentTable, targetAccount, snapshotTS)) + require.NoError(t, recreateTable(ctx, "", bh, snapshotName, currentTable, targetAccount, snapshotTS, false)) require.Equal(t, []string{ dropTableIfExistsSQL(moCatalog, currentTable.tblName), MoCatalogMoFunctionRevisionDDL, diff --git a/pkg/udf/python/worker/Dockerfile b/pkg/udf/python/worker/Dockerfile index 4fbcaf7784120..31d3a145d283d 100644 --- a/pkg/udf/python/worker/Dockerfile +++ b/pkg/udf/python/worker/Dockerfile @@ -15,6 +15,12 @@ RUN apt-get update \ FROM python:3.12-slim-bookworm +RUN apt-get update \ + && apt-get install -y --no-install-recommends tini \ + && rm -rf /var/lib/apt/lists/* /usr/share/zoneinfo + +# Replace the complete database: Debian's posix symlinks cannot be overlaid +# safely with Ubuntu's directory layout, nor may stale zones be retained. COPY --from=matrixone-tzdata /usr/share/zoneinfo/ /usr/share/zoneinfo/ RUN useradd -m -s /bin/bash mo @@ -40,4 +46,7 @@ USER mo EXPOSE 50051 +# The worker waits for its direct children; init owns orphaned descendants +# after a handler leader exits. Keep that owner outside Python/Popen. +ENTRYPOINT [ "/usr/bin/tini", "--" ] CMD [ "python", "-u", "worker.py", "--address=grpc://0.0.0.0:50051" ] diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index a0bd3ec02fd6e..3c1a5616c3667 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -2,6 +2,7 @@ import datetime import decimal +import errno import io import importlib.util import json @@ -2137,13 +2138,172 @@ def test_handler_close_keeps_h_slot_while_process_cleanup_is_pending(self): if session._slot_acquired: slots.release() + def test_exchange_construction_failure_retains_cleanup_owner(self): + server = worker.RoutineFlightServer("grpc://127.0.0.1:0") + self.addCleanup(server.shutdown) + slots = server._handler_slots = threading.BoundedSemaphore(1) + quota = server._handler_quota = worker._HandlerQuota(1, 1) + allow_kill = threading.Event() + process = mock.Mock(pid=1234, stdin=mock.Mock()) + watchdog = mock.Mock() + construction_error = OSError(errno.EMFILE, "selector exhausted") + descriptor = {"type_id": worker.INT64, "offset_width": 32} + payload = complete_open_payload({ + "function_ref": {"account_id": 1, "database_id": 2, "function_id": 3, + "revision": 1, "namespace_version": 1}, + "source": "def f(ctx, x): return x + 1", "handler": "f", + "mode": worker.MODE_SCALAR, "null_policy": worker.NULL_CALL, + "abi_contract": worker.ABI_CONTRACT, + "adapter_version": worker.ADAPTER_VERSION, "sdk_version": worker.SDK_VERSION, + "args": [descriptor], "return": descriptor, + "max_batch_bytes": 1 << 20, "max_batch_rows": 8, + "handler_timeout_seconds": 10, + }) + fence = {"account_id": 1, "statement_id": "construction", + "group_id": "construction", "group_epoch": 1, + "invocation_id": "failed", "lease_epoch": 1} + batch = pa.RecordBatch.from_arrays( + [pa.array([7], type=pa.int64())], + schema=pa.schema([worker._field("arg_0", descriptor)]), + ) + controls, results = [], [] + + def exchange(): + key = worker._tuple_key(fence) + + def control(kind, **fields): + return worker._encode_control({"kind": kind, "tuple": fence, **fields}) + + chunks = iter([ + types.SimpleNamespace(data=batch, app_metadata=control("InputBatch", sequence=1)), + types.SimpleNamespace(data=None, app_metadata=control("EndInput", last_sequence=1)), + ]) + + def metadata(data): + value = worker._decode_control(data) + controls.append(value) + if value["kind"] == "Finish": + server._active[key].ack_finish(value["finish_id"]) + + def output(record, data): + results.append(record.column(0).to_pylist()) + server._active[key].ack_result(worker._decode_control(data)["sequence"]) + + server.do_exchange( + None, types.SimpleNamespace(command=control("OpenInvocation", payload=payload)), + types.SimpleNamespace(schema=batch.schema, read_chunk=lambda: next(chunks)), + types.SimpleNamespace(begin=lambda schema: None, + write_metadata=metadata, write_with_metadata=output), + ) + + def kill(child): + self.assertIs(child, process) + if not allow_kill.is_set(): + raise OSError("kill blocked") + + key = worker._tuple_key(fence) + owner = worker._handler_quota_owner(payload) + with mock.patch.object(worker.subprocess, "Popen", side_effect=[process, watchdog]), \ + mock.patch.object(worker.selectors, "DefaultSelector", side_effect=construction_error), \ + mock.patch.object(worker, "_kill_execution_process", side_effect=kill), \ + mock.patch.object(slots, "release", wraps=slots.release) as release_slot, \ + mock.patch.object(quota, "_release", wraps=quota._release) as release_quota: + try: + with self.assertRaises(OSError) as raised: + exchange() + self.assertIs(construction_error, raised.exception) + self.assertEqual("Error", controls[-1]["kind"]) + self.assertEqual([], results) + with server._pending_cleanup_condition: + self.assertEqual([key], list(server._pending_cleanups)) + session = server._pending_cleanups[key].handler_session + self.assertIs(process, session._process) + self.assertIn(key, server._active) + self.assertNotIn(key, server._terminal) + self.assertFalse(slots.acquire(blocking=False)) + self.assertEqual(({1: 1}, {(1, owner): 1}), quota.counts()) + release_slot.assert_not_called() + release_quota.assert_not_called() + with self.assertRaisesRegex(ValueError, "account handler budget is full"): + quota.acquire(1, owner) + + allow_kill.set() + with server._pending_cleanup_condition: + self.assertTrue(server._pending_cleanup_condition.wait_for( + lambda: not server._pending_cleanups, timeout=3 + ), "pending cleanup did not complete") + self.assertNotIn(key, server._active) + self.assertIn(key, server._terminal) + self.assertEqual(({}, {}), quota.counts()) + session.close() + release_slot.assert_called_once_with() + release_quota.assert_called_once_with(1, owner) + process.stdin.close.assert_called_once_with() + self.assertTrue(slots.acquire(blocking=False)) + slots.release() + finally: + allow_kill.set() + # Drain while the process doubles and kill hook remain installed, + # including after an early assertion failure. + with server._pending_cleanup_condition: + self.assertTrue(server._pending_cleanup_condition.wait_for( + lambda: not server._pending_cleanups, timeout=3 + ), "test cleanup did not drain") + + # A later actual exchange can acquire the returned budgets and execute. + fence.update(group_epoch=2, invocation_id="next") + exchange() + self.assertEqual([[8]], results) + self.assertEqual("Finish", controls[-1]["kind"]) + self.assertFalse(server._active) + self.assertEqual(({}, {}), quota.counts()) + self.assertTrue(slots.acquire(blocking=False)) + slots.release() + + def test_helper_construction_failure_transfers_cleanup_owner(self): + slots = threading.BoundedSemaphore(1) + process = mock.Mock(pid=1234, stdin=mock.Mock()) + error = OSError(errno.EMFILE, "selector exhausted") + with mock.patch.object(worker.subprocess, "Popen", return_value=process), \ + mock.patch.object(worker.selectors, "DefaultSelector", side_effect=error), \ + mock.patch.object(worker, "_kill_execution_process", side_effect=OSError("kill blocked")) as kill: + with self.assertRaises(worker._HandlerCleanupPending) as raised: + worker._run_handler_process(None, {}, 1, slots) + pending = raised.exception + try: + self.assertIs(error, pending.error) + self.assertIs(error, pending.__cause__) + self.assertIs(process, pending.session._process) + self.assertFalse(slots.acquire(blocking=False)) + self.assertEqual(2, kill.call_count) + finally: + kill.side_effect = None + pending.session.close() + pending.session.close() + self.assertTrue(slots.acquire(blocking=False)) + slots.release() + process.stdin.close.assert_called_once_with() + def test_handler_cleanup_does_not_mask_execution_error(self): session = mock.Mock() session.run.side_effect = ValueError("USER_CODE: handler failed") session.close.side_effect = RuntimeError("close failed") with mock.patch.object(worker, "_HandlerProcessSession", return_value=session): - with self.assertRaisesRegex(ValueError, "handler failed"): + with self.assertRaises(worker._HandlerCleanupPending) as raised: worker._run_handler_process(None, {}, 1) + self.assertIs(session.run.side_effect, raised.exception.error) + self.assertIs(session.run.side_effect, raised.exception.__cause__) + self.assertIs(session, raised.exception.session) + session.close.assert_called_once_with() + + def test_helper_success_with_failed_cleanup_transfers_owner(self): + session = mock.Mock() + session.close.side_effect = OSError("kill blocked") + with mock.patch.object(worker, "_HandlerProcessSession", return_value=session): + with self.assertRaises(worker._HandlerCleanupPending) as raised: + worker._run_handler_process(None, {}, 1) + self.assertIs(session.close.side_effect, raised.exception.error) + self.assertIs(session, raised.exception.session) session.close.assert_called_once_with() def test_real_flight_half_close_delivers_delayed_float_result_and_finish(self): @@ -3319,11 +3479,19 @@ def test_descendant_is_killed_after_handler_leader_exits(self): with self.assertRaisesRegex(ValueError, "handler process"): worker._run_handler_process(None, request, 2) observed = json.loads(witness.read_text()) - try: - survived = os.getpgid(observed["pid"]) == observed["pgid"] - except ProcessLookupError: - survived = False - self.assertFalse(survived) + # SIGKILL is synchronous as a request, but orphan adoption + # and init's waitpid are asynchronous. Require disappearance + # of the owned identity, including zombies, within a bound. + deadline = time.monotonic() + 2 + while True: + try: + survived = os.getpgid(observed["pid"]) == observed["pgid"] + except ProcessLookupError: + survived = False + if not survived or time.monotonic() >= deadline: + break + time.sleep(0.005) + self.assertFalse(survived, "init did not reap the owned descendant") finally: if witness.exists(): owned = json.loads(witness.read_text()) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index 0a081de3e83e8..fee826d826f65 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -2599,6 +2599,19 @@ def counts(self) -> tuple[Dict[int, int], Dict[tuple[int, str], int]]: return dict(self._account_counts), dict(self._owner_counts) +class _HandlerCleanupPending(Exception): + """Transfer a session whose cleanup failed, preserving the primary error. + + Callers must retain ``session`` until close succeeds. Exchanges hand it to + their bounded cleanup owner; standalone helper callers own the retry. + """ + + def __init__(self, error: BaseException, session): + super().__init__(str(error)) + self.error = error + self.session = session + + class _HandlerProcessSession: """One handler child reused only inside a bounded invocation burst.""" @@ -2704,7 +2717,7 @@ def __init__( os.set_blocking(stdin_fd, False) os.set_blocking(response_read_fd, False) self._selector.register(response_read_fd, selectors.EVENT_READ, "response") - except Exception: + except Exception as error: for fd in ( locals().get("response_write_fd", -1), locals().get("parent_watch_read_fd", -1), @@ -2715,13 +2728,12 @@ def __init__( os.close(fd) except OSError: pass - # Preserve the construction failure. Cleanup is best effort and - # must not hide the contract error that caused session creation - # to fail. try: self.close() except Exception: - pass + # __init__ never returns on this path, so the assignment in + # the caller cannot publish us. Transfer ownership explicitly. + raise _HandlerCleanupPending(error, self) from error raise @property @@ -2991,20 +3003,26 @@ def _run_handler_process( context, request: Dict[str, Any], timeout_seconds: float, execution_slots: Optional[threading.BoundedSemaphore] = None, ) -> bytes: + # Construction failures already transfer their pending session in + # _HandlerCleanupPending. This standalone helper has no server reaper; + # its caller must retain that exception and retry session.close(). session = _HandlerProcessSession(execution_slots) try: result = session.run(context, request, timeout_seconds) - except BaseException: + except BaseException as error: # Preserve the handler/transport failure as the primary diagnosis. # Cleanup is still mandatory, but a close failure must not replace a # deadline, user-code, or protocol error and hide the actual cause. try: session.close() except Exception: - logging.exception("Python UDF handler cleanup failed after an execution error") + raise _HandlerCleanupPending(error, session) from error raise else: - session.close() + try: + session.close() + except Exception as error: + raise _HandlerCleanupPending(error, session) from error return result @@ -3812,12 +3830,16 @@ def do_exchange(self, context, descriptor, reader, writer): # admission and all input validation still happen # before a handler slot is acquired. owner_id = _handler_quota_owner(payload) - handler_session = _HandlerProcessSession( - self._handler_slots, - handler_quota=self._handler_quota, - account_id=key[0], - owner_id=owner_id, - ) + try: + handler_session = _HandlerProcessSession( + self._handler_slots, + handler_quota=self._handler_quota, + account_id=key[0], + owner_id=owner_id, + ) + except _HandlerCleanupPending as pending: + handler_session = pending.session + raise pending.error from None execution_request = { "source": source, "handler": handler_name, diff --git a/test/distributed/cases/git4data/clone/issue_27103_clone_external_table.result b/test/distributed/cases/git4data/clone/issue_27103_clone_external_table.result index 4e69c42722791..14e7e9fbc2fe2 100644 --- a/test/distributed/cases/git4data/clone/issue_27103_clone_external_table.result +++ b/test/distributed/cases/git4data/clone/issue_27103_clone_external_table.result @@ -29,7 +29,7 @@ fields terminated by ','; create function issue_27103_live_src.f_control() returns int language sql as 'select count(*) from issue_27103_live_src.control_t'; create function issue_27103_live_src.py_add(x int) returns int language python as -'return x + 1' handler 'py_add'; +'def py_add(ctx, x): return x + 1' handler 'py_add'; create function issue_27103_live_src.f_external() returns int language sql as 'select count(*) from issue_27103_live_src.ext_t'; create function issue_27103_live_src.f_transitive() returns int language sql as @@ -112,7 +112,7 @@ fields terminated by ','; create function issue_27103_snapshot_src.f_control() returns int language sql as 'select count(*) from issue_27103_snapshot_src.control_t'; create function issue_27103_snapshot_src.py_add(x int) returns int language python as -'return x + 1' handler 'py_add'; +'def py_add(ctx, x): return x + 1' handler 'py_add'; create function issue_27103_snapshot_src.f_external() returns int language sql as 'select count(*) from issue_27103_snapshot_src.ext_t'; create function issue_27103_snapshot_src.f_transitive() returns int language sql as diff --git a/test/distributed/cases/git4data/clone/issue_27103_clone_external_table.sql b/test/distributed/cases/git4data/clone/issue_27103_clone_external_table.sql index d4645ada92d90..a6bdc887a6d96 100644 --- a/test/distributed/cases/git4data/clone/issue_27103_clone_external_table.sql +++ b/test/distributed/cases/git4data/clone/issue_27103_clone_external_table.sql @@ -31,7 +31,7 @@ fields terminated by ','; create function issue_27103_live_src.f_control() returns int language sql as 'select count(*) from issue_27103_live_src.control_t'; create function issue_27103_live_src.py_add(x int) returns int language python as -'return x + 1' handler 'py_add'; +'def py_add(ctx, x): return x + 1' handler 'py_add'; create function issue_27103_live_src.f_external() returns int language sql as 'select count(*) from issue_27103_live_src.ext_t'; create function issue_27103_live_src.f_transitive() returns int language sql as @@ -84,7 +84,7 @@ fields terminated by ','; create function issue_27103_snapshot_src.f_control() returns int language sql as 'select count(*) from issue_27103_snapshot_src.control_t'; create function issue_27103_snapshot_src.py_add(x int) returns int language python as -'return x + 1' handler 'py_add'; +'def py_add(ctx, x): return x + 1' handler 'py_add'; create function issue_27103_snapshot_src.f_external() returns int language sql as 'select count(*) from issue_27103_snapshot_src.ext_t'; create function issue_27103_snapshot_src.f_transitive() returns int language sql as diff --git a/test/distributed/cases/udf_python/README.md b/test/distributed/cases/udf_python/README.md index 087f65dd69de4..3241d9f991a15 100644 --- a/test/distributed/cases/udf_python/README.md +++ b/test/distributed/cases/udf_python/README.md @@ -49,6 +49,11 @@ The cases keep the data sets small and target contract boundaries: SELECT, and DELETE atomically without publishing partial changes. - `revision_lifecycle.sql` checks create, immutable-revision replacement, prepared-plan invalidation, drop, and recreate on the same SQL signature. +- `overload_namespace.sql` checks cross-session overload changes invalidate + prepared/cache plans and DROP distinguishes exact decimal scales. +- `snapshot_restore.sql` restores revision A into a different account after + replacing the source with revision B, checking exact catalog bytes, execution, + account-scoped artifact publication, a SQL UDF control and teardown. - `vector_mode.sql` checks Arrow VECTOR handlers, zero-argument batch shape, NULL policies, and handler validation during create and replace. - `arrow_compute_arithmetic.sql` checks `pyarrow.compute` arithmetic, diff --git a/test/distributed/cases/udf_python/overload_namespace.result b/test/distributed/cases/udf_python/overload_namespace.result index 22f90130768aa..c75e6546a3527 100644 --- a/test/distributed/cases/udf_python/overload_namespace.result +++ b/test/distributed/cases/udf_python/overload_namespace.result @@ -54,4 +54,17 @@ select overload(x) as result from namespace_values order by x; 401 𝄀 402 deallocate prepare namespace_plan; +create function exact_decimal(x decimal(18,2)) returns int language python as 'def exact_decimal(ctx,x): return 2' handler 'exact_decimal'; +create function exact_decimal(x decimal(18,6)) returns int language python as 'def exact_decimal(ctx,x): return 6' handler 'exact_decimal'; +drop function exact_decimal(decimal(18,2)); +select count(*) as remaining_heads from mo_catalog.mo_user_defined_function where db = 'udf_python_namespace_bvt' and name = 'exact_decimal'; +➤ remaining_heads[-5,64,0] 𝄀 +1 +select count(*) as remaining_revisions from mo_catalog.mo_function_revisions r join mo_catalog.mo_user_defined_function f on r.function_id = f.function_id where f.db = 'udf_python_namespace_bvt' and f.name = 'exact_decimal'; +➤ remaining_revisions[-5,64,0] 𝄀 +1 +select exact_decimal(cast(1.23 as decimal(18,6))) as surviving_overload; +➤ surviving_overload[4,32,0] 𝄀 +6 +drop function exact_decimal(decimal(18,6)); drop database udf_python_namespace_bvt; diff --git a/test/distributed/cases/udf_python/overload_namespace.sql b/test/distributed/cases/udf_python/overload_namespace.sql index 5a1634f84bd04..f9dd31556db9b 100644 --- a/test/distributed/cases/udf_python/overload_namespace.sql +++ b/test/distributed/cases/udf_python/overload_namespace.sql @@ -32,4 +32,12 @@ create function overload(x smallint) returns bigint language python as 'def over execute namespace_plan; select overload(x) as result from namespace_values order by x; deallocate prepare namespace_plan; +-- Exact input descriptors, including scale, select the identity removed by DROP. +create function exact_decimal(x decimal(18,2)) returns int language python as 'def exact_decimal(ctx,x): return 2' handler 'exact_decimal'; +create function exact_decimal(x decimal(18,6)) returns int language python as 'def exact_decimal(ctx,x): return 6' handler 'exact_decimal'; +drop function exact_decimal(decimal(18,2)); +select count(*) as remaining_heads from mo_catalog.mo_user_defined_function where db = 'udf_python_namespace_bvt' and name = 'exact_decimal'; +select count(*) as remaining_revisions from mo_catalog.mo_function_revisions r join mo_catalog.mo_user_defined_function f on r.function_id = f.function_id where f.db = 'udf_python_namespace_bvt' and f.name = 'exact_decimal'; +select exact_decimal(cast(1.23 as decimal(18,6))) as surviving_overload; +drop function exact_decimal(decimal(18,6)); drop database udf_python_namespace_bvt; diff --git a/test/distributed/cases/udf_python/snapshot_restore.result b/test/distributed/cases/udf_python/snapshot_restore.result new file mode 100644 index 0000000000000..15b3d027484e5 --- /dev/null +++ b/test/distributed/cases/udf_python/snapshot_restore.result @@ -0,0 +1,40 @@ +drop snapshot if exists python_udf_revision_snapshot; +drop account if exists python_udf_restore_target; +drop account if exists python_udf_restore_source; +create account python_udf_restore_source admin_name = 'udf_admin' identified by '111'; +create account python_udf_restore_target admin_name = 'udf_admin' identified by '111'; +create database udf_restore; +use udf_restore; +create function restored_python(x int) returns int language python as 'def restored_python(ctx,x): return x + 10' handler 'restored_python'; +create function restored_sql(x int) returns int language sql as '$1 + 20'; +create table expected_revisions as select f.name, f.function_id, f.active_revision, r.body from mo_catalog.mo_user_defined_function f join mo_catalog.mo_function_revisions r on f.function_id = r.function_id and f.active_revision = r.revision where f.db = 'udf_restore'; +select restored_python(1) as python_value, restored_sql(1) as sql_value; +➤ python_value[4,32,0] ¦ sql_value[-5,64,0] 𝄀 +11 ¦ 21 +create snapshot python_udf_revision_snapshot for account python_udf_restore_source; +use udf_restore; +create or replace function restored_python(x int) returns int language python as 'def restored_python(ctx,x): return x + 100' handler 'restored_python'; +select restored_python(1) as source_value; +➤ source_value[4,32,0] 𝄀 +101 +restore account python_udf_restore_source{snapshot="python_udf_revision_snapshot"} to account python_udf_restore_target; +use udf_restore; +select restored_python(1) as python_value, restored_sql(1) as sql_value; +➤ python_value[4,32,0] ¦ sql_value[-5,64,0] 𝄀 +11 ¦ 21 +select count(*) as exact_restored_revisions from expected_revisions e join mo_catalog.mo_user_defined_function f on e.function_id = f.function_id and e.name = f.name and e.active_revision = f.active_revision join mo_catalog.mo_function_revisions r on f.function_id = r.function_id and f.active_revision = r.revision where f.db = 'udf_restore' and e.body = r.body; +➤ exact_restored_revisions[-5,64,0] 𝄀 +2 +use udf_restore; +select restored_python(1) as source_unchanged; +➤ source_unchanged[4,32,0] 𝄀 +101 +drop snapshot python_udf_revision_snapshot; +drop account python_udf_restore_target; +drop account python_udf_restore_source; +select count(*) as leftover_accounts from mo_catalog.mo_account where account_name in ('python_udf_restore_source','python_udf_restore_target'); +➤ leftover_accounts[-5,64,0] 𝄀 +0 +select count(*) as leftover_snapshots from mo_catalog.mo_snapshots where sname = 'python_udf_revision_snapshot'; +➤ leftover_snapshots[-5,64,0] 𝄀 +0 diff --git a/test/distributed/cases/udf_python/snapshot_restore.sql b/test/distributed/cases/udf_python/snapshot_restore.sql new file mode 100644 index 0000000000000..b123d80b68ab3 --- /dev/null +++ b/test/distributed/cases/udf_python/snapshot_restore.sql @@ -0,0 +1,34 @@ +-- Restore into a different account must republish the account-scoped artifact. +drop snapshot if exists python_udf_revision_snapshot; +drop account if exists python_udf_restore_target; +drop account if exists python_udf_restore_source; +create account python_udf_restore_source admin_name = 'udf_admin' identified by '111'; +create account python_udf_restore_target admin_name = 'udf_admin' identified by '111'; +-- @session:id=1&user=python_udf_restore_source:udf_admin&password=111 +create database udf_restore; +use udf_restore; +create function restored_python(x int) returns int language python as 'def restored_python(ctx,x): return x + 10' handler 'restored_python'; +create function restored_sql(x int) returns int language sql as '$1 + 20'; +create table expected_revisions as select f.name, f.function_id, f.active_revision, r.body from mo_catalog.mo_user_defined_function f join mo_catalog.mo_function_revisions r on f.function_id = r.function_id and f.active_revision = r.revision where f.db = 'udf_restore'; +select restored_python(1) as python_value, restored_sql(1) as sql_value; +-- @session +create snapshot python_udf_revision_snapshot for account python_udf_restore_source; +-- @session:id=1&user=python_udf_restore_source:udf_admin&password=111 +use udf_restore; +create or replace function restored_python(x int) returns int language python as 'def restored_python(ctx,x): return x + 100' handler 'restored_python'; +select restored_python(1) as source_value; +-- @session +restore account python_udf_restore_source{snapshot="python_udf_revision_snapshot"} to account python_udf_restore_target; +-- @session:id=2&user=python_udf_restore_target:udf_admin&password=111 +use udf_restore; +select restored_python(1) as python_value, restored_sql(1) as sql_value; +select count(*) as exact_restored_revisions from expected_revisions e join mo_catalog.mo_user_defined_function f on e.function_id = f.function_id and e.name = f.name and e.active_revision = f.active_revision join mo_catalog.mo_function_revisions r on f.function_id = r.function_id and f.active_revision = r.revision where f.db = 'udf_restore' and e.body = r.body; +-- @session:id=1&user=python_udf_restore_source:udf_admin&password=111 +use udf_restore; +select restored_python(1) as source_unchanged; +-- @session +drop snapshot python_udf_revision_snapshot; +drop account python_udf_restore_target; +drop account python_udf_restore_source; +select count(*) as leftover_accounts from mo_catalog.mo_account where account_name in ('python_udf_restore_source','python_udf_restore_target'); +select count(*) as leftover_snapshots from mo_catalog.mo_snapshots where sname = 'python_udf_revision_snapshot'; From 9535e3f81ddb229c977fb0a23e0d43bbb9b39c4a Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 20 Sep 2026 14:45:16 +0800 Subject: [PATCH 188/241] docs(udf): document execution and rollout scope for review --- docs/design/python_udf.md | 97 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 docs/design/python_udf.md diff --git a/docs/design/python_udf.md b/docs/design/python_udf.md new file mode 100644 index 0000000000000..dde191f159839 --- /dev/null +++ b/docs/design/python_udf.md @@ -0,0 +1,97 @@ +# Python UDF implementation and rollout scope + +This describes the implemented, owner-authorized external Python adapter and its +PR acceptance boundary. It does not approve a production tenant-isolation model. +The shared Function Catalog design owns identity, revision and security semantics; +SQL and Python designs own their language contracts. This summary does not replace +those contracts. + +## Execution and identity + +CREATE/REPLACE validates Python syntax and the handler contract before publishing +a definition. The shared Catalog stores immutable typed revisions and complete +argument/return descriptors. Artifacts are digest-addressed, account-scoped and +published through FileService; worker execution receives the verified artifact +from CN. The worker needs no object-storage credentials or query-time package +installation. Old demo definitions are inert: explicitly recreate them using the +current DDL and SDK. Unknown definition, plan, Arrow, SDK or wire contracts fail +before user execution; no legacy fallback or automatic adapter is provided. + +Planning resolves an exact FunctionRef and RoutineCall. Prepared/cache reuse +validates the selected revision and the complete overload namespace state; see +[routine namespace validation](routine_namespace_validation.md). Execution never +resolves a mutable latest revision. Clone and restore preserve supported catalog +contracts and republish Python artifacts for the destination account. + +CN keeps native MO vectors. The expression framework dispatches typed Python calls +to ExternalRoutineEval; the parent evaluator owns argument evaluation, casts, +CASE/selection and NULL guards. The physical stage compacts selected rows, +admits bounded asynchronous work and scatters verified results, preserving empty +input, NULLs, zero arguments, nested calls and default VOLATILE semantics. + +The Gateway is a CN library, not a separately deployed service. It connects to +Arrow Flight served by the Python worker. No second Flight daemon is required. +A worker creates bounded handler subprocesses; each handler/module can be reused +only within the invocation's bounded burst. It does not pool user heaps across +invocations. SCALAR handlers receive `(ctx, scalar...)`; VECTOR handlers receive +`(ctx, arrays...)` and use `ctx.num_rows` for output shape. Arrow field/schema +metadata comes from the trusted adapter, not handler-supplied identity. + +## Completion and resources + +K bounds active Gateway invocations, H bounds handler execution slots, and W=1 +bounds stream batch progress. Admission, group/member state, terminal records and +per-account/per-owner quotas have independent owners and budgets. Protocol steps +include EndInput, InputConsumed, result ACK and Finish/FinishAck. Started work is +never transparently replayed. Cancellation and capability refresh waiters progress +independently; generation fences reject stale completions. + +Process cleanup must cover both termination and reaping. Handler sessions own +pipes, child/watchdog processes and H/quota until cleanup succeeds; partial +initialization transfers a failed session to the same bounded pending-cleanup +owner. Linux containers run `/usr/bin/tini -- python -u worker.py`; init adopts +orphaned descendants after their handler leader exits. An Operator command override +must retain this init process. Native Supervisor launches rely on the host's init +(or an explicit subreaper in a container test harness). + +## Enablement and deployment boundary + +Generic launch keeps Python disabled. The explicit worker-enabled launch and +ordinary BVT entry point enable the unisolated adapter. See +[Python BVT and local launch](../../test/distributed/cases/udf_python/README.md). +Compose configures a separate worker endpoint for each CN. The `PYTHON_UDF` +mo-service role wraps a Go Supervisor; the standalone worker image runs Python +under init. These are different launch forms for the same Flight service. + +Gateway and worker must match the current capability contract, including tzdata. +The worker image replaces its entire zoneinfo tree from the MO runtime base; +upgrading tzdata also changes the environment digest of definitions. Check existing +definitions before enabling an incompatible environment and explicitly rebuild +where required. Matching software version strings alone are not this check. + +`enabled` and `allow-unisolated` are explicit gates. This implementation does not +provide sandbox isolation or authenticated/TLS Flight transport. Same-Pod Operator +configuration binds the worker to loopback and controls Pod composition; it does +not add broad CN ingress grants. External worker exposure needs a separately +approved security/deployment design. Worker availability is a Python execution +condition, not evidence of production tenant isolation. + +## Verification and remaining scope + +The regression suite covers scalar/vector Arrow computation, types and malformed +values, guarded SQL positions and DML atomicity, revision/overload invalidation, +exact-descriptor DROP and cross-account snapshot restore. Runtime tests cover +ACK/Finish, cancellation, quotas, initialization/cleanup failure, worker death, +stale events and real Flight consumers. Operator status wire fixtures pin the +producer/consumer error contract. + +Linux PR validation uses the repository CGo wrapper, two CNs with distinct +Supervisor/worker endpoints, ordinary SQL/Python BVT, current worker image and +process-tree fault injection. Record the exact revision, selected tests, image +and terminal result with each run; unit or CNI echo tests are not complete +Operator rollout evidence. + +Sandbox, production deployment approval, imported dependency environments and +W>1/cumulative ACK enablement remain separate work. W=1 measurements do not prove +that a wider window has no benefit. This PR is related to issue #28132 and does +not close that issue's broader isolated-runtime acceptance criteria. From 420444663dbac15a454cafd33596de497740dbca Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 20 Sep 2026 15:41:43 +0800 Subject: [PATCH 189/241] fix(ci): add missing license headers for Python UDF files --- pkg/cnservice/python_runtime.go | 9 +++++++++ pkg/cnservice/python_runtime_test.go | 9 +++++++++ pkg/frontend/python_udf_catalog_test.go | 9 +++++++++ pkg/frontend/routine_namespace.go | 9 +++++++++ pkg/frontend/routine_namespace_test.go | 11 +++++++++++ pkg/frontend/routine_plan_validation.go | 9 +++++++++ pkg/sql/colexec/external_routine_eval.go | 9 +++++++++ pkg/sql/colexec/external_routine_eval_test.go | 9 +++++++++ pkg/sql/plan/function/python_udf.go | 6 ++++++ pkg/sql/plan/function/udf.go | 6 ++++++ pkg/sql/plan/routine_dependency.go | 9 +++++++++ pkg/udf/python/arrow_test.go | 9 +++++++++ pkg/udf/python/artifact.go | 9 +++++++++ pkg/udf/python/artifact_test.go | 9 +++++++++ pkg/udf/python/capability_lifecycle_test.go | 9 +++++++++ pkg/udf/python/config.go | 6 ++++++ pkg/udf/python/config_test.go | 9 +++++++++ pkg/udf/python/definition.go | 9 +++++++++ pkg/udf/python/definition_test.go | 9 +++++++++ pkg/udf/python/gateway.go | 6 ++++++ pkg/udf/python/gateway_admission_test.go | 9 +++++++++ pkg/udf/python/gateway_benchmark_test.go | 9 +++++++++ pkg/udf/python/gateway_integration_test.go | 9 +++++++++ pkg/udf/python/gateway_test.go | 9 +++++++++ pkg/udf/python/supervisor.go | 8 ++++++++ pkg/udf/python/supervisor_process_other.go | 14 ++++++++++++++ pkg/udf/python/supervisor_process_unix.go | 14 ++++++++++++++ pkg/udf/python/supervisor_test.go | 9 +++++++++ pkg/udf/python_contract.go | 9 +++++++++ pkg/udf/python_contract_test.go | 9 +++++++++ pkg/udf/runtime_status_wire_test.go | 11 +++++++++++ pkg/udf/runtime_test.go | 9 +++++++++ pkg/udf/timezone.go | 9 +++++++++ 33 files changed, 298 insertions(+) diff --git a/pkg/cnservice/python_runtime.go b/pkg/cnservice/python_runtime.go index d168e583b3e05..38a391abef7d3 100644 --- a/pkg/cnservice/python_runtime.go +++ b/pkg/cnservice/python_runtime.go @@ -2,6 +2,15 @@ // // 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 cnservice diff --git a/pkg/cnservice/python_runtime_test.go b/pkg/cnservice/python_runtime_test.go index 1da63a1bd3de6..e3eff6af6fed6 100644 --- a/pkg/cnservice/python_runtime_test.go +++ b/pkg/cnservice/python_runtime_test.go @@ -2,6 +2,15 @@ // // 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 cnservice diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 44d12281c6beb..a454781694c31 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -2,6 +2,15 @@ // // 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 frontend diff --git a/pkg/frontend/routine_namespace.go b/pkg/frontend/routine_namespace.go index 89e494ba8b40f..7f5e635cb4d74 100644 --- a/pkg/frontend/routine_namespace.go +++ b/pkg/frontend/routine_namespace.go @@ -2,6 +2,15 @@ // // 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 frontend diff --git a/pkg/frontend/routine_namespace_test.go b/pkg/frontend/routine_namespace_test.go index e8531c811613a..6b6478a36a89a 100644 --- a/pkg/frontend/routine_namespace_test.go +++ b/pkg/frontend/routine_namespace_test.go @@ -1,6 +1,17 @@ // Copyright 2026 Matrix Origin +// // 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 frontend import ( diff --git a/pkg/frontend/routine_plan_validation.go b/pkg/frontend/routine_plan_validation.go index 99ae6506cff28..d3722613112be 100644 --- a/pkg/frontend/routine_plan_validation.go +++ b/pkg/frontend/routine_plan_validation.go @@ -2,6 +2,15 @@ // // 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 frontend diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index d3bf16cfb8c34..0a7bc02b476df 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -2,6 +2,15 @@ // // 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 colexec diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index 39ac13d31f227..a7a09181ed299 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -2,6 +2,15 @@ // // 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 colexec diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index ddd7764d6a63f..576fa6dc27615 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -5,6 +5,12 @@ // 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 function diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index 1a5292a7c6033..a60c78cc0250d 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -5,6 +5,12 @@ // 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 function diff --git a/pkg/sql/plan/routine_dependency.go b/pkg/sql/plan/routine_dependency.go index 31765cfcef242..a1d34f8950311 100644 --- a/pkg/sql/plan/routine_dependency.go +++ b/pkg/sql/plan/routine_dependency.go @@ -2,6 +2,15 @@ // // 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 plan diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index fecb17e389558..f0f72f768ab7e 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python/artifact.go b/pkg/udf/python/artifact.go index 72912c2173bf0..ad374605bdebb 100644 --- a/pkg/udf/python/artifact.go +++ b/pkg/udf/python/artifact.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python/artifact_test.go b/pkg/udf/python/artifact_test.go index 5f56eebd3d568..4e1be71b90a12 100644 --- a/pkg/udf/python/artifact_test.go +++ b/pkg/udf/python/artifact_test.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python/capability_lifecycle_test.go b/pkg/udf/python/capability_lifecycle_test.go index 04afe1e595458..36ca4d7eaf8ec 100644 --- a/pkg/udf/python/capability_lifecycle_test.go +++ b/pkg/udf/python/capability_lifecycle_test.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python/config.go b/pkg/udf/python/config.go index d1e1372d457d8..021e4f5cc90c8 100644 --- a/pkg/udf/python/config.go +++ b/pkg/udf/python/config.go @@ -5,6 +5,12 @@ // 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 python diff --git a/pkg/udf/python/config_test.go b/pkg/udf/python/config_test.go index 88be8ee0ca663..4873cc8fb5198 100644 --- a/pkg/udf/python/config_test.go +++ b/pkg/udf/python/config_test.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python/definition.go b/pkg/udf/python/definition.go index 4b118b3b83d9c..2f172098158e8 100644 --- a/pkg/udf/python/definition.go +++ b/pkg/udf/python/definition.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python/definition_test.go b/pkg/udf/python/definition_test.go index 9a0209935afe0..9dbeace96877d 100644 --- a/pkg/udf/python/definition_test.go +++ b/pkg/udf/python/definition_test.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index ea79515ec6d47..27fb6033a6e68 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -5,6 +5,12 @@ // 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 python diff --git a/pkg/udf/python/gateway_admission_test.go b/pkg/udf/python/gateway_admission_test.go index c29eb711f1423..fd4d96e5e63d5 100644 --- a/pkg/udf/python/gateway_admission_test.go +++ b/pkg/udf/python/gateway_admission_test.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python/gateway_benchmark_test.go b/pkg/udf/python/gateway_benchmark_test.go index 3ce304fe2ef19..ba245079f8fb3 100644 --- a/pkg/udf/python/gateway_benchmark_test.go +++ b/pkg/udf/python/gateway_benchmark_test.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python/gateway_integration_test.go b/pkg/udf/python/gateway_integration_test.go index 0d26ddb95ca88..5517b648cda28 100644 --- a/pkg/udf/python/gateway_integration_test.go +++ b/pkg/udf/python/gateway_integration_test.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index 3a9c2cb07e823..a98d16686c512 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python/supervisor.go b/pkg/udf/python/supervisor.go index b16df8411e752..af3de0793fa10 100644 --- a/pkg/udf/python/supervisor.go +++ b/pkg/udf/python/supervisor.go @@ -3,6 +3,14 @@ // 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 python diff --git a/pkg/udf/python/supervisor_process_other.go b/pkg/udf/python/supervisor_process_other.go index 6ec19f6431cc9..bd72579d202c6 100644 --- a/pkg/udf/python/supervisor_process_other.go +++ b/pkg/udf/python/supervisor_process_other.go @@ -1,3 +1,17 @@ +// Copyright 2026 Matrix Origin +// +// 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. + //go:build !(aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris) package python diff --git a/pkg/udf/python/supervisor_process_unix.go b/pkg/udf/python/supervisor_process_unix.go index 20bbb1f545436..c0930ebcd7026 100644 --- a/pkg/udf/python/supervisor_process_unix.go +++ b/pkg/udf/python/supervisor_process_unix.go @@ -1,3 +1,17 @@ +// Copyright 2026 Matrix Origin +// +// 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. + //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris package python diff --git a/pkg/udf/python/supervisor_test.go b/pkg/udf/python/supervisor_test.go index 9105ffb7adb6e..21fe77e45d69e 100644 --- a/pkg/udf/python/supervisor_test.go +++ b/pkg/udf/python/supervisor_test.go @@ -2,6 +2,15 @@ // // 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 python diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index c9a12dd2eaa61..60bfd4d12f679 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -2,6 +2,15 @@ // // 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 udf diff --git a/pkg/udf/python_contract_test.go b/pkg/udf/python_contract_test.go index 1f9edd7070603..543e489773c52 100644 --- a/pkg/udf/python_contract_test.go +++ b/pkg/udf/python_contract_test.go @@ -2,6 +2,15 @@ // // 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 udf diff --git a/pkg/udf/runtime_status_wire_test.go b/pkg/udf/runtime_status_wire_test.go index ef52beffbf94e..3bce3cd16d052 100644 --- a/pkg/udf/runtime_status_wire_test.go +++ b/pkg/udf/runtime_status_wire_test.go @@ -1,6 +1,17 @@ // Copyright 2026 Matrix Origin +// // 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 udf import ( diff --git a/pkg/udf/runtime_test.go b/pkg/udf/runtime_test.go index 3faa79a6dfe99..4ee0bd5e7e4c0 100644 --- a/pkg/udf/runtime_test.go +++ b/pkg/udf/runtime_test.go @@ -2,6 +2,15 @@ // // 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 udf diff --git a/pkg/udf/timezone.go b/pkg/udf/timezone.go index f4816995f043d..2995f5ca79759 100644 --- a/pkg/udf/timezone.go +++ b/pkg/udf/timezone.go @@ -2,6 +2,15 @@ // // 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 udf From 8a6511592310d58b725e96abc9f983dcbc06f36d Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 20 Sep 2026 19:01:16 +0800 Subject: [PATCH 190/241] fix(udf): satisfy static checks and import ownership --- pkg/cnservice/python_runtime.go | 12 +- pkg/frontend/authenticate.go | 3 +- pkg/frontend/compiler_context.go | 47 ++-- pkg/frontend/routine_namespace.go | 11 +- pkg/frontend/routine_plan_validation.go | 44 +-- pkg/frontend/snapshot_catalog_restore.go | 79 +++--- pkg/iceberg/api/import_boundary_test.go | 134 ++++++++-- pkg/sql/colexec/external_routine_eval.go | 111 ++++---- pkg/sql/plan/function/python_udf.go | 29 +- pkg/sql/plan/function/udf.go | 89 ++++--- pkg/sql/plan/routine_dependency.go | 11 +- pkg/udf/protocol/protocol.go | 147 +++++----- pkg/udf/python/arrow.go | 188 +++++++------ pkg/udf/python/artifact.go | 46 ++-- pkg/udf/python/definition.go | 11 +- pkg/udf/python/gateway.go | 326 +++++++++++------------ pkg/udf/python/supervisor.go | 7 +- pkg/udf/runtime.go | 34 +-- pkg/udf/timezone.go | 4 +- pkg/util/errutil/errors.go | 26 ++ pkg/util/errutil/errors_test.go | 7 + 21 files changed, 742 insertions(+), 624 deletions(-) diff --git a/pkg/cnservice/python_runtime.go b/pkg/cnservice/python_runtime.go index 38a391abef7d3..6487d4a863a67 100644 --- a/pkg/cnservice/python_runtime.go +++ b/pkg/cnservice/python_runtime.go @@ -16,8 +16,8 @@ package cnservice import ( "context" - "fmt" - + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "go.uber.org/zap" "github.com/matrixorigin/matrixone/pkg/common/mpool" @@ -73,9 +73,9 @@ func (r *unavailablePythonRuntime) Language() string { return udf.LanguagePython func (r *unavailablePythonRuntime) unavailableError() error { if r == nil || r.cause == nil { - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime initialization failed") + return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime initialization failed") } - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime initialization failed: %w", r.cause) + return errutil.Wrapf(r.cause, "RESOURCE_UNAVAILABLE: Python UDF runtime initialization failed") } func (r *unavailablePythonRuntime) Execute(context.Context, *udf.Invocation, vector.FunctionResultWrapper, *mpool.MPool) error { @@ -84,7 +84,7 @@ func (r *unavailablePythonRuntime) Execute(context.Context, *udf.Invocation, vec func (r *unavailablePythonRuntime) CheckLanguageReady(ctx context.Context, language string) error { if language != udf.LanguagePython { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported readiness language %q", language) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported readiness language %q", language) } if ctx != nil { select { @@ -98,7 +98,7 @@ func (r *unavailablePythonRuntime) CheckLanguageReady(ctx context.Context, langu func (r *unavailablePythonRuntime) ValidateDefinition(ctx context.Context, definition *udf.RoutineDefinition) error { if definition == nil || definition.Language != udf.LanguagePython { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: invalid Python definition") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: invalid Python definition") } return r.CheckLanguageReady(ctx, udf.LanguagePython) } diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index c0fbb80ead036..0399f5442c78e 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -20,6 +20,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "io" "math" "math/bits" @@ -12673,7 +12674,7 @@ func readPythonRevisionBody(ctx context.Context, bh BackgroundExec, functionID i "select body from mo_catalog.mo_function_revisions where function_id = %d and revision = %d and namespace_version = %d;", functionID, revision, namespace, )); err != nil { - return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python revision %d is unavailable: %w", revision, err) + return "", errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python revision %d is unavailable", revision) } rows, err := getResultSet(ctx, bh) if err != nil { diff --git a/pkg/frontend/compiler_context.go b/pkg/frontend/compiler_context.go index 40b65f2a8eda5..9d8d0bda5a4cb 100644 --- a/pkg/frontend/compiler_context.go +++ b/pkg/frontend/compiler_context.go @@ -20,6 +20,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "slices" "strconv" "strings" @@ -943,7 +944,7 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex return nil, err } if len(erArray) > 1 || (len(erArray) == 1 && erArray[0] == nil) { - return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: UDF %s lookup returned %d result sets, expected one or an empty candidate result", name, len(erArray)) + return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: UDF %s lookup returned %d result sets, expected one or an empty candidate result", name, len(erArray)) } if execResultArrayHasData(erArray) { @@ -1112,7 +1113,7 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex if strings.EqualFold(matchedList[0].Udf.Language, string(tree.PYTHON)) { matchedList[0].Udf.ArgsType = function.PythonUdfArgTypeCast(fromList, matchedList[0].Udf.GetArgsType()) if len(matchedList[0].Udf.ArgsType) != len(fromList) { - return nil, fmt.Errorf("python udf: argument descriptor count changed during resolution") + return nil, moerr.NewInternalErrorNoCtxf("python udf: argument descriptor count changed during resolution") } } else { matchedList[0].Udf.ArgsType = function.UdfArgTypeCast(fromList, matchedList[0].TypeList) @@ -1125,7 +1126,7 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex accountID = routineCatalogAccountID(accountID, tcc.GetSnapshot()) databaseID, databaseErr := routineCatalogDatabaseID(queryCtx, bh, matchedList[0].Udf.Db, accountID, tcc.GetSnapshot()) if databaseErr != nil { - return nil, fmt.Errorf("python routine database identity: %w", databaseErr) + return nil, errutil.Wrapf(databaseErr, "python routine database identity") } matchedList[0].Udf.AccountID = uint64(accountID) matchedList[0].Udf.DatabaseID = databaseID @@ -1135,7 +1136,7 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex } matchedList[0].Udf.NamespaceFingerprint = namespaces[uint64(matchedList[0].Udf.FunctionID)] if namespaceErr == nil && matchedList[0].Udf.NamespaceFingerprint == "" { - return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: missing routine namespace") + return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: missing routine namespace") } } @@ -1182,7 +1183,7 @@ func udfCatalogLookup( // catalog corruption from the planner/cache validator. func exactlyOneCatalogResultSet(ctx context.Context, rows []ExecResult, label string) (ExecResult, error) { if len(rows) != 1 || rows[0] == nil { - return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: %s returned %d result sets, expected exactly one", label, len(rows)) + return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: %s returned %d result sets, expected exactly one", label, len(rows)) } return rows[0], nil } @@ -1210,7 +1211,7 @@ func exactlyOneCatalogRow(ctx context.Context, rows []ExecResult, label string) } rowCount := result.GetRowCount() if rowCount != 1 { - return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: %s returned %d rows, expected exactly one", label, rowCount) + return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: %s returned %d rows, expected exactly one", label, rowCount) } return result, nil } @@ -1281,7 +1282,7 @@ func readSQLRevision( if isMissingCatalogObjectError(err) { return sqlRevisionCatalogRow{}, false, nil } - return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision head is unavailable: %w", functionID, err) + return sqlRevisionCatalogRow{}, false, errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision head is unavailable", functionID) } rows, err := getResultSet(ctx, bh) if err != nil { @@ -1307,7 +1308,7 @@ func readSQLRevision( return sqlRevisionCatalogRow{}, false, nil } if activeRevision <= 0 || namespaceVersion <= 0 { - return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d has an invalid revision head", functionID) + return sqlRevisionCatalogRow{}, false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d has an invalid revision head", functionID) } bh.ClearExecResultSet() @@ -1318,9 +1319,9 @@ func readSQLRevision( revisionTable, functionID, activeRevision, namespaceVersion, )); err != nil { if isMissingCatalogObjectError(err) { - return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision table is unavailable: %w", functionID, err) + return sqlRevisionCatalogRow{}, false, errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision table is unavailable", functionID) } - return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision is unavailable: %w", functionID, err) + return sqlRevisionCatalogRow{}, false, errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision is unavailable", functionID) } rows, err = getResultSet(ctx, bh) if err != nil { @@ -1381,15 +1382,15 @@ func readSQLRevision( volatility != "VOLATILE" || nullPolicy != udf.NullCallHandler || !strings.EqualFold(securityType, "DEFINER") || !strings.EqualFold(baseSecurityType, securityType) { - return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision contract is not supported", functionID) + return sqlRevisionCatalogRow{}, false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision contract is not supported", functionID) } logicalArgTypes, err := userDefinedFunctionArgumentTypesFromJSON(args) if err != nil || logicalArgTypes != argTypes { - return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision argument metadata is invalid", functionID) + return sqlRevisionCatalogRow{}, false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision argument metadata is invalid", functionID) } expectedFingerprint, err := function.SQLRoutineFingerprint(body, argTypes, retType) if err != nil || fingerprint == "" || fingerprint != expectedFingerprint { - return sqlRevisionCatalogRow{}, false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision fingerprint mismatch", functionID) + return sqlRevisionCatalogRow{}, false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision fingerprint mismatch", functionID) } return sqlRevisionCatalogRow{ Args: args, ArgTypes: argTypes, Body: body, Language: language, RetType: retType, @@ -1403,7 +1404,7 @@ func readPythonRevision(ctx context.Context, bh BackgroundExec, functionID int64 bh.ClearExecResultSet() query := pythonRevisionCatalogSQL(snapshot, functionID) if err := bh.Exec(ctx, query); err != nil { - return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python catalog revision is unavailable: %w", err) + return pythonRevisionCatalogRow{}, errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python catalog revision is unavailable") } rows, err := getResultSet(ctx, bh) if err != nil { @@ -1426,7 +1427,7 @@ func readPythonRevision(ctx context.Context, bh BackgroundExec, functionID int64 return pythonRevisionCatalogRow{}, err } if activeRevision <= 0 || namespaceVersion <= 0 || revision != activeRevision { - return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d has an invalid revision head", functionID) + return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d has an invalid revision head", functionID) } getString := func(column uint64) (string, error) { return row.GetString(ctx, 0, column) } canonicalInput, err := getString(3) @@ -1510,32 +1511,32 @@ func readPythonRevision(ctx context.Context, bh BackgroundExec, functionID int64 return pythonRevisionCatalogRow{}, err } if language != string(tree.PYTHON) || definitionSchema != udf.PythonDefinitionSchemaVersion || abi != udf.PythonABIContract || adapter != udf.PythonAdapterVersion || sdk != udf.PythonSDKVersion || volatility != "VOLATILE" || !strings.EqualFold(securityType, "INVOKER") || !strings.EqualFold(baseSecurityType, securityType) { - return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision contract is not supported", functionID) + return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision contract is not supported", functionID) } bodyDefinition, err := function.DecodePythonRoutineBody(body) if err != nil { - return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision body is invalid: %w", functionID, err) + return pythonRevisionCatalogRow{}, errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python function %d revision body is invalid", functionID) } if bodyDefinition.ABIContract != abi || bodyDefinition.AdapterVersion != adapter || bodyDefinition.SDKVersion != sdk || bodyDefinition.NullPolicy != nullPolicy || bodyDefinition.ArtifactDigest != artifact || bodyDefinition.EnvironmentDigest != environment { - return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision metadata does not match its definition", functionID) + return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision metadata does not match its definition", functionID) } actualFingerprint, err := function.PythonRoutineFingerprint(body) if err != nil { - return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision fingerprint cannot be computed: %w", functionID, err) + return pythonRevisionCatalogRow{}, errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python function %d revision fingerprint cannot be computed", functionID) } if fingerprint == "" || fingerprint != actualFingerprint { - return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision fingerprint mismatch", functionID) + return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision fingerprint mismatch", functionID) } expectedInput, expectedReturn, expectedSignature, err := function.PythonSignatureMetadata(bodyDefinition.ArgTypes, bodyDefinition.ReturnType) if err != nil { - return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d signature cannot be computed: %w", functionID, err) + return pythonRevisionCatalogRow{}, errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python function %d signature cannot be computed", functionID) } if signatureKeySchemaVersion != udf.PythonSignatureKeySchemaVersion || canonicalInput != expectedInput || returnDescriptor != expectedReturn || signatureFingerprint != expectedSignature { - return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d identity descriptor metadata mismatch", functionID) + return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d identity descriptor metadata mismatch", functionID) } if argTypes != expectedInput { - return pythonRevisionCatalogRow{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision argument descriptor mismatch", functionID) + return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision argument descriptor mismatch", functionID) } return pythonRevisionCatalogRow{ Args: args, ArgTypes: argTypes, Body: body, Language: language, RetType: retType, diff --git a/pkg/frontend/routine_namespace.go b/pkg/frontend/routine_namespace.go index 7f5e635cb4d74..1c9e6d4856986 100644 --- a/pkg/frontend/routine_namespace.go +++ b/pkg/frontend/routine_namespace.go @@ -19,8 +19,9 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - "errors" "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "sort" "strconv" "strings" @@ -28,7 +29,7 @@ import ( planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" ) -var errRoutineNamespaceBudget = errors.New("routine namespace cache budget exceeded") +var errRoutineNamespaceBudget = moerr.NewInternalErrorNoCtx("routine namespace cache budget exceeded") const maxRoutineNamespaceRows = 65536 const maxRoutineNamespaceBytes = 64 << 20 @@ -80,7 +81,7 @@ func routineNamespacesSQL(ids []uint64, snapshot *planpb.Snapshot) string { func decodeRoutineNamespaces(ctx context.Context, rows ExecResult) (map[uint64]string, error) { if rows.GetRowCount() > maxRoutineNamespaceRows { - return nil, fmt.Errorf("%w: namespace rows exceed %d", errRoutineNamespaceBudget, maxRoutineNamespaceRows) + return nil, errutil.WrapfCauseFirst(errRoutineNamespaceBudget, "namespace rows exceed %d", maxRoutineNamespaceRows) } groups := make(map[uint64]map[uint64]string) remaining := maxRoutineNamespaceBytes @@ -100,7 +101,7 @@ func decodeRoutineNamespaces(ctx context.Context, rows ExecResult) (map[uint64]s return nil, err } if len(value) > remaining { - return nil, fmt.Errorf("%w: namespace bytes exceed %d", errRoutineNamespaceBudget, maxRoutineNamespaceBytes) + return nil, errutil.WrapfCauseFirst(errRoutineNamespaceBudget, "namespace bytes exceed %d", maxRoutineNamespaceBytes) } remaining -= len(value) fields[col] = value @@ -120,7 +121,7 @@ func decodeRoutineNamespaces(ctx context.Context, rows ExecResult) (map[uint64]s groups[numbers[0]] = make(map[uint64]string) } if _, duplicate := groups[numbers[0]][numbers[1]]; duplicate { - return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: duplicate routine namespace member") + return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: duplicate routine namespace member") } groups[numbers[0]][numbers[1]] = hex.EncodeToString(digest[:]) } diff --git a/pkg/frontend/routine_plan_validation.go b/pkg/frontend/routine_plan_validation.go index d3722613112be..98dcfa9429b97 100644 --- a/pkg/frontend/routine_plan_validation.go +++ b/pkg/frontend/routine_plan_validation.go @@ -18,6 +18,8 @@ import ( "context" "errors" "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "sort" "strconv" "strings" @@ -114,7 +116,7 @@ func routinePlanDependencies(p *planpb.Plan) ([]*planpb.RoutinePlanDependency, e if frame.next == 0 { frameDependencies := frame.query.GetRoutineDependencies() if len(dependencies)+len(frameDependencies) > maxRoutinePlanDependencies { - return nil, fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) + return nil, moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) } for _, dependency := range frameDependencies { dependencySize := 1 @@ -122,7 +124,7 @@ func routinePlanDependencies(p *planpb.Plan) ([]*planpb.RoutinePlanDependency, e dependencySize = dependency.ProtoSize() } if dependencySize > maxRoutinePlanDependencyBytes-dependencyBytes { - return nil, fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine dependency bytes exceed %d", maxRoutinePlanDependencyBytes) + return nil, moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine dependency bytes exceed %d", maxRoutinePlanDependencyBytes) } dependencyBytes += dependencySize } @@ -141,10 +143,10 @@ func routinePlanDependencies(p *planpb.Plan) ([]*planpb.RoutinePlanDependency, e continue } if frame.depth+1 > maxRoutinePlanQueryDepth { - return nil, fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine dependency query nesting exceeds %d", maxRoutinePlanQueryDepth) + return nil, moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine dependency query nesting exceeds %d", maxRoutinePlanQueryDepth) } if _, exists := active[background]; exists { - return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency query graph contains a cycle") + return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine dependency query graph contains a cycle") } // Shared background queries contribute their immutable dependencies // once. Re-expanding a DAG as a tree can turn a small plan into @@ -171,10 +173,10 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan return false, nil } if len(dependencies) > maxRoutinePlanDependencies { - return false, fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) + return false, moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) } if ses == nil { - return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation has no session") + return false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation has no session") } var snapshot *planpb.Snapshot if tcc := ses.GetTxnCompileCtx(); tcc != nil { @@ -220,7 +222,7 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan defer bh.Close() if !useCallerTxn { if err = bh.Exec(ctx, "begin;"); err != nil { - return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation could not start: %w", err) + return false, errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: routine dependency validation could not start") } defer func() { err = finishTxn(ctx, bh, err) }() } @@ -235,7 +237,7 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan } } if err = bh.Exec(ctx, query); err != nil { - return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation failed: %w", err) + return false, errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: routine dependency validation failed") } rows, err := getResultSet(ctx, bh) if err != nil { @@ -348,13 +350,13 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan return false, getErr } if !strings.EqualFold(revisionSecurityType, baseSecurityType) { - return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine %d has inconsistent revision and identity security contracts", id) + return false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine %d has inconsistent revision and identity security contracts", id) } if language == udf.LanguagePython && !strings.EqualFold(revisionSecurityType, "INVOKER") { - return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine catalog security type is not INVOKER") + return false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python routine catalog security type is not INVOKER") } if language == udf.LanguageSQL && !strings.EqualFold(revisionSecurityType, "DEFINER") { - return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL routine catalog security type is not DEFINER") + return false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL routine catalog security type is not DEFINER") } identityValid := routinePlanCatalogIdentityValidForLanguage( language, @@ -364,7 +366,7 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan revisionSDK, revisionNullPolicy, ) if _, duplicate := states[id]; duplicate { - return false, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine catalog returned duplicate state for function %d", id) + return false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine catalog returned duplicate state for function %d", id) } states[id] = routinePlanCatalogState{ activeRevision: activeRevision, namespaceVersion: namespaceVersion, @@ -490,37 +492,37 @@ func routineRevisionReturnTypeMatches(rettype string, oid types.T) bool { func validateRoutinePlanDependencyShape(dependency *planpb.RoutinePlanDependency, accountID uint32) error { if dependency == nil || dependency.FunctionRef == nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency has no FunctionRef") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency has no FunctionRef") } ref := dependency.FunctionRef if ref.FunctionId == 0 || ref.Revision == 0 || ref.NamespaceVersion == 0 || ref.AccountId != uint64(accountID) || ref.DatabaseId == 0 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency has an invalid catalog identity") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency has an invalid catalog identity") } if dependency.ContractVersion != udf.RoutinePlanContractVersion || !udf.IsSHA256Digest(dependency.DefinitionFingerprint) || !udf.IsSHA256Digest(dependency.NamespaceFingerprint) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency contract is incomplete") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency contract is incomplete") } if dependency.Volatility == "" || dependency.NullPolicy == "" || !dependency.MayError || dependency.Leakproof { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency semantic contract is incomplete") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency semantic contract is incomplete") } switch dependency.Language { case udf.LanguagePython: if dependency.SecurityMode != "INVOKER" { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine plan dependency must use INVOKER security") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python routine plan dependency must use INVOKER security") } if !udf.IsSHA256Digest(dependency.ArtifactDigest) || !udf.IsSHA256Digest(dependency.EnvironmentDigest) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine plan dependency integrity is incomplete") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python routine plan dependency integrity is incomplete") } case udf.LanguageSQL: if dependency.SecurityMode == "" { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL routine plan dependency has no security mode") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL routine plan dependency has no security mode") } if dependency.ArtifactDigest != "" || dependency.EnvironmentDigest != "" { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL routine plan dependency has external integrity fields") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL routine plan dependency has external integrity fields") } default: - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency language %q is unsupported", dependency.Language) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency language %q is unsupported", dependency.Language) } return nil } diff --git a/pkg/frontend/snapshot_catalog_restore.go b/pkg/frontend/snapshot_catalog_restore.go index d2d90f8f74f34..c42bd89df6434 100644 --- a/pkg/frontend/snapshot_catalog_restore.go +++ b/pkg/frontend/snapshot_catalog_restore.go @@ -18,6 +18,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "strconv" "strings" @@ -187,27 +188,27 @@ func validateRestoredFunctionRevisionCatalog( ) rows, err := getStringColsList(targetCtx, bh, query, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision catalog cannot be validated: %w", err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: restored Python revision catalog cannot be validated") } for rowIndex, row := range rows { if len(row) != 20 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision row %d has %d columns", rowIndex, len(row)) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision row %d has %d columns", rowIndex, len(row)) } functionID, err := strconv.ParseUint(row[0], 10, 64) if err != nil || functionID == 0 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision row %d has an invalid function identity", rowIndex) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision row %d has an invalid function identity", rowIndex) } revision, err := strconv.ParseUint(row[1], 10, 64) if err != nil || revision == 0 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has an invalid revision", functionID) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has an invalid revision", functionID) } namespace, err := strconv.ParseUint(row[2], 10, 64) if err != nil || namespace == 0 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has an invalid namespace version", functionID) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has an invalid namespace version", functionID) } definitionSchema, err := strconv.Atoi(row[9]) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored function %d revision %d has an invalid definition schema", functionID, revision) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored function %d revision %d has an invalid definition schema", functionID, revision) } if row[8] == udf.LanguageSQL { if err := validateRestoredSQLFunctionRevision(functionID, revision, row, definitionSchema); err != nil { @@ -222,12 +223,12 @@ func validateRestoredFunctionRevisionCatalog( row[14] != udf.PythonSDKVersion || !strings.EqualFold(row[16], "VOLATILE") || !strings.EqualFold(row[19], "INVOKER") { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored function %d revision %d has an unsupported execution contract", functionID, revision) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored function %d revision %d has an unsupported execution contract", functionID, revision) } body, err := function.DecodePythonRoutineBody(row[7]) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d body is invalid: %w", functionID, revision, err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d body is invalid", functionID, revision) } if body.DefinitionSchemaVersion != definitionSchema || body.ABIContract != row[10] || @@ -236,11 +237,11 @@ func validateRestoredFunctionRevisionCatalog( body.EnvironmentDigest != row[13] || body.SDKVersion != row[14] || body.NullPolicy != row[15] { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d metadata does not match its definition", functionID, revision) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d metadata does not match its definition", functionID, revision) } fingerprint, err := function.PythonRoutineFingerprint(row[7]) if err != nil || row[17] == "" || row[17] != fingerprint { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d fingerprint mismatch", functionID, revision) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d fingerprint mismatch", functionID, revision) } // `args` retains the shared logical names while `arg_types` in the // current Python revision is the exact descriptor identity used for @@ -248,11 +249,11 @@ func validateRestoredFunctionRevisionCatalog( // comparing arg_types with the logical OID list would reject every // current Python revision after restore. if _, err := userDefinedFunctionArgumentTypesFromJSON(row[4]); err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d arguments are invalid: %w", functionID, revision, err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d arguments are invalid", functionID, revision) } var args []*function.Arg if err := json.Unmarshal([]byte(row[4]), &args); err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d arguments are invalid: %w", functionID, revision, err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d arguments are invalid", functionID, revision) } routine := &function.Udf{ Language: udf.LanguagePython, @@ -262,14 +263,14 @@ func validateRestoredFunctionRevisionCatalog( PythonReturnType: body.ReturnType, } if err := routine.ValidatePythonTypeContract(); err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d type contract mismatch: %w", functionID, revision, err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d type contract mismatch", functionID, revision) } if err := routine.ValidatePythonCatalogSignature(); err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d catalog signature mismatch: %w", functionID, revision, err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d catalog signature mismatch", functionID, revision) } expectedInput, _, _, err := function.PythonSignatureMetadata(body.ArgTypes, body.ReturnType) if err != nil || row[5] != expectedInput { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d argument descriptor mismatch", functionID, revision) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d argument descriptor mismatch", functionID, revision) } } return nil @@ -280,15 +281,15 @@ func validateRestoredSQLFunctionRevision(functionID, revision uint64, row []stri row[10] != "" || row[11] != "" || row[12] != "" || row[13] != "" || row[14] != "" || row[15] != udf.NullCallHandler || !strings.EqualFold(row[16], "VOLATILE") || !strings.EqualFold(row[19], "DEFINER") { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d has an unsupported execution contract", functionID, revision) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d has an unsupported execution contract", functionID, revision) } logicalArgTypes, err := userDefinedFunctionArgumentTypesFromJSON(row[4]) if err != nil || logicalArgTypes != row[5] { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d argument metadata is invalid", functionID, revision) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d argument metadata is invalid", functionID, revision) } fingerprint, err := function.SQLRoutineFingerprint(row[7], row[5], row[6]) if err != nil || row[17] == "" || row[17] != fingerprint { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d fingerprint mismatch", functionID, revision) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d fingerprint mismatch", functionID, revision) } return nil } @@ -317,23 +318,23 @@ func validateRestoredFunctionCatalogHeads( order by f.function_id;` rows, err := getStringColsList(targetCtx, bh, query, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog heads cannot be validated: %w", err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: restored routine catalog heads cannot be validated") } for rowIndex, row := range rows { if len(row) != 16 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog head row %d has %d columns", rowIndex, len(row)) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog head row %d has %d columns", rowIndex, len(row)) } functionID, err := strconv.ParseUint(row[0], 10, 64) if err != nil || functionID == 0 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog head row %d has an invalid function identity", rowIndex) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog head row %d has an invalid function identity", rowIndex) } activeRevision, err := strconv.ParseUint(row[1], 10, 64) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored routine function %d has an invalid active revision: %v", functionID, err) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored routine function %d has an invalid active revision: %v", functionID, err) } namespaceVersion, err := strconv.ParseUint(row[2], 10, 64) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored routine function %d has an invalid namespace version: %v", functionID, err) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored routine function %d has an invalid namespace version: %v", functionID, err) } language := strings.ToLower(row[12]) if (language == udf.LanguageSQL || language == udf.LanguagePython) && activeRevision == 0 && namespaceVersion == 0 { @@ -345,52 +346,52 @@ func validateRestoredFunctionCatalogHeads( continue } if activeRevision == 0 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d has no active immutable revision", language, functionID) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d has no active immutable revision", language, functionID) } if namespaceVersion == 0 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d has an invalid namespace version", language, functionID) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d has an invalid namespace version", language, functionID) } revision, err := strconv.ParseUint(row[3], 10, 64) if err != nil || revision != activeRevision { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d active revision does not exist", language, functionID) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d active revision does not exist", language, functionID) } revisionNamespace, err := strconv.ParseUint(row[4], 10, 64) if err != nil || revisionNamespace != namespaceVersion { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d head namespace does not match its revision", language, functionID) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d head namespace does not match its revision", language, functionID) } if language == udf.LanguageSQL { if row[10] == "" || row[11] == "" { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d has incomplete active revision", functionID) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d has incomplete active revision", functionID) } if !strings.EqualFold(row[14], "DEFINER") || !strings.EqualFold(row[15], "DEFINER") { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d has inconsistent security contract", functionID) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d has inconsistent security contract", functionID) } expectedFingerprint, fingerprintErr := function.SQLRoutineFingerprint(row[11], row[9], row[10]) if fingerprintErr != nil || row[13] == "" || row[13] != expectedFingerprint { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d head fingerprint does not match its active revision", functionID) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d head fingerprint does not match its active revision", functionID) } continue } if language != udf.LanguagePython { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored function %d has unsupported language %q", functionID, row[12]) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored function %d has unsupported language %q", functionID, row[12]) } if row[5] == "" || row[6] == "" || row[7] == "" || row[8] == "" || row[9] == "" || row[10] == "" || row[11] == "" || row[13] == "" || !strings.EqualFold(row[14], "INVOKER") || !strings.EqualFold(row[15], "INVOKER") || !strings.EqualFold(row[14], row[15]) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has incomplete head identity", functionID) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has incomplete head identity", functionID) } body, err := function.DecodePythonRoutineBody(row[11]) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d head body is invalid: %w", functionID, err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: restored Python function %d head body is invalid", functionID) } input, output, signature, err := function.PythonSignatureMetadata(body.ArgTypes, body.ReturnType) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d head signature is invalid: %w", functionID, err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: restored Python function %d head signature is invalid", functionID) } bodyFingerprint, fingerprintErr := function.PythonRoutineFingerprint(row[11]) if fingerprintErr != nil || row[13] != bodyFingerprint || row[5] != input || row[6] != output || row[7] != strconv.Itoa(udf.PythonSignatureKeySchemaVersion) || row[8] != signature || row[9] != input { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d head identity does not match its active revision", functionID) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d head identity does not match its active revision", functionID) } } return nil @@ -515,12 +516,12 @@ func publishRestoredPythonArtifacts( 0, 1, 2, ) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python artifacts cannot be inspected: %w", err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: restored Python artifacts cannot be inspected") } needStore := false for rowIndex, row := range rows { if len(row) != 3 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored revision row %d has %d artifact columns", rowIndex, len(row)) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored revision row %d has %d artifact columns", rowIndex, len(row)) } if row[0] == udf.LanguagePython { needStore = true @@ -544,10 +545,10 @@ func publishRestoredPythonArtifacts( } body, decodeErr := function.DecodePythonRoutineBody(row[2]) if decodeErr != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python artifact row %d is invalid: %w", rowIndex, decodeErr) + return errutil.Wrapf(decodeErr, "UNSUPPORTED_ROUTINE_VERSION: restored Python artifact row %d is invalid", rowIndex) } if body.ArtifactDigest != row[1] { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: restored Python artifact row %d digest does not match its revision", rowIndex) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python artifact row %d digest does not match its revision", rowIndex) } if _, publishErr := store.Publish(ctx, uint64(targetAccount), body.Handler, body.Source); publishErr != nil { return publishErr diff --git a/pkg/iceberg/api/import_boundary_test.go b/pkg/iceberg/api/import_boundary_test.go index d628a98ecfcb1..1b4faad0e293c 100644 --- a/pkg/iceberg/api/import_boundary_test.go +++ b/pkg/iceberg/api/import_boundary_test.go @@ -23,13 +23,42 @@ import ( "testing" ) -func TestIcebergAdapterImportBoundary(t *testing.T) { +type importBoundaryPolicy struct { + name string + importPrefixes []string + allowedDirectories []string + allowedFiles []string +} + +var importBoundaryPolicies = []importBoundaryPolicy{ + { + name: "Iceberg", + importPrefixes: []string{"github.com/apache/iceberg-go"}, + allowedDirectories: []string{ + "pkg/iceberg/adapter/iceberggo", + }, + }, + { + name: "Arrow", + importPrefixes: []string{ + "github.com/apache/arrow-go", + "github.com/apache/arrow/go", + }, + allowedDirectories: []string{ + "pkg/iceberg/adapter/iceberggo", + "pkg/container/arrowbridge", + "pkg/sql/colexec/external/arrowio", + "pkg/udf/python", + }, + allowedFiles: []string{ + "pkg/sql/colexec/external/reader_arrow.go", + "pkg/sql/compile/compile.go", + }, + }, +} + +func TestIcebergAndArrowImportBoundaries(t *testing.T) { root := findRepoRoot(t) - forbidden := []string{ - "github.com/apache/iceberg-go", - "github.com/apache/arrow-go", - "github.com/apache/arrow/go", - } err := filepath.WalkDir(root, func(path string, d os.DirEntry, walkErr error) error { if walkErr != nil { return walkErr @@ -52,20 +81,18 @@ func TestIcebergAdapterImportBoundary(t *testing.T) { if parseErr != nil { return parseErr } - slashPath := filepath.ToSlash(path) - // Arrow has two approved MatrixOne-owned boundaries: the Iceberg - // adapter and the static-file ingestion bridge. Everywhere else remains - // forbidden so an implementation detail cannot leak into SQL layers. - arrowAllowed := strings.Contains(slashPath, "/pkg/iceberg/adapter/iceberggo/") || - strings.Contains(slashPath, "/pkg/container/arrowbridge/") || - strings.Contains(slashPath, "/pkg/sql/colexec/external/arrowio/") || - strings.HasSuffix(slashPath, "/pkg/sql/colexec/external/reader_arrow.go") || - strings.HasSuffix(slashPath, "/pkg/sql/compile/compile.go") + relativePath, relErr := filepath.Rel(root, path) + if relErr != nil { + return relErr + } + slashPath := filepath.ToSlash(relativePath) for _, imp := range file.Imports { importPath := strings.Trim(imp.Path.Value, `"`) - for _, prefix := range forbidden { - if strings.HasPrefix(importPath, prefix) && !arrowAllowed { - t.Fatalf("forbidden Iceberg/Arrow import outside adapter: %s imports %s", slashPath, importPath) + for _, policy := range importBoundaryPolicies { + if importMatchesPrefix(importPath, policy.importPrefixes) && + !policy.allows(slashPath) { + t.Fatalf("forbidden %s import outside an approved owner: %s imports %s", + policy.name, slashPath, importPath) } } } @@ -76,6 +103,77 @@ func TestIcebergAdapterImportBoundary(t *testing.T) { } } +func (p importBoundaryPolicy) allows(relativePath string) bool { + for _, directory := range p.allowedDirectories { + if relativePath == directory || strings.HasPrefix(relativePath, directory+"/") { + return true + } + } + for _, file := range p.allowedFiles { + if relativePath == file { + return true + } + } + return false +} + +func importMatchesPrefix(importPath string, prefixes []string) bool { + for _, prefix := range prefixes { + if importPath == prefix || strings.HasPrefix(importPath, prefix+"/") { + return true + } + } + return false +} + +func TestImportBoundaryPolicies(t *testing.T) { + tests := []struct { + name string + policy importBoundaryPolicy + relativePath string + importPath string + allowed bool + }{ + { + name: "UDF owns Arrow but not Iceberg", + policy: importBoundaryPolicies[1], + relativePath: "pkg/udf/python/gateway.go", + importPath: "github.com/apache/arrow-go/v18/arrow/flight/gen/flight", + allowed: true, + }, + { + name: "UDF cannot own Iceberg", + policy: importBoundaryPolicies[0], + relativePath: "pkg/udf/python/gateway.go", + importPath: "github.com/apache/iceberg-go/io", + allowed: false, + }, + { + name: "Iceberg adapter owns Iceberg", + policy: importBoundaryPolicies[0], + relativePath: "pkg/iceberg/adapter/iceberggo/io.go", + importPath: "github.com/apache/iceberg-go/io", + allowed: true, + }, + { + name: "sibling package is not an Arrow owner", + policy: importBoundaryPolicies[1], + relativePath: "pkg/udf/pythonish/gateway.go", + importPath: "github.com/apache/arrow-go/v18/arrow", + allowed: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + matches := importMatchesPrefix(tt.importPath, tt.policy.importPrefixes) + if matches && tt.policy.allows(tt.relativePath) != tt.allowed { + t.Fatalf("policy allowed=%v for %s importing %s, want %v", + tt.policy.allows(tt.relativePath), tt.relativePath, tt.importPath, tt.allowed) + } + }) + } +} + func TestIcebergPackagesUseMOErrorAndCauseAwareTimeouts(t *testing.T) { root := findRepoRoot(t) bareFmtErrorf := "fmt." + "Errorf(" diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index 0a7bc02b476df..993da7c51cdc9 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -16,7 +16,8 @@ package colexec import ( "encoding/json" - "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "os" "sort" "strconv" @@ -72,13 +73,13 @@ func newExternalRoutineEval( allocation *vector.AllocationAccountSelection, ) (*ExternalRoutineEval, error) { if proc == nil || proc.Base == nil { - return nil, fmt.Errorf("python udf: evaluator has no process") + return nil, moerr.NewInternalErrorNoCtxf("python udf: evaluator has no process") } if err := validateRoutineCall(call); err != nil { return nil, err } if len(call.ArgumentTypes) != len(parameters) { - return nil, fmt.Errorf("python udf: typed routine has %d argument descriptors but %d bound arguments", len(call.ArgumentTypes), len(parameters)) + return nil, moerr.NewInternalErrorNoCtxf("python udf: typed routine has %d argument descriptors but %d bound arguments", len(call.ArgumentTypes), len(parameters)) } resultType := planTypeToSQL(call.ReturnType) result, err := vector.NewFunctionResultWrapperWithAllocation(resultType, proc.Mp(), allocation) @@ -99,69 +100,69 @@ func newExternalRoutineEval( func validateRoutineCall(call *planpb.RoutineCall) error { if call == nil || call.FunctionRef == nil || call.FunctionRef.FunctionId == 0 || call.FunctionRef.DatabaseId == 0 || call.FunctionRef.Revision == 0 || call.FunctionRef.NamespaceVersion == 0 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no exact FunctionRef") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no exact FunctionRef") } if call.ReturnType.Id == int32(types.T_any) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no return descriptor") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no return descriptor") } if call.ContractVersion != udf.PythonPlanContractVersion || call.Language != udf.LanguagePython { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported typed routine call contract") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported typed routine call contract") } if call.Volatility != "VOLATILE" { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine must be VOLATILE") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python routine must be VOLATILE") } if call.MayError != true || call.SecurityMode != "INVOKER" || call.Leakproof { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python routine semantic contract is not supported") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python routine semantic contract is not supported") } if call.CallsiteId == "" || len(call.CallsiteId) > 256 || strings.ContainsAny(call.CallsiteId, "\r\n") { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no valid callsite id") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no valid callsite id") } if len(call.Context) != 0 { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed routine call contains execution context") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed routine call contains execution context") } python := call.GetPython() if python == nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no Python implementation") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no Python implementation") } if python.Source != "" { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python plan contains source; rebind from the current artifact contract") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python plan contains source; rebind from the current artifact contract") } if python.Handler == "" || python.AbiContract != udf.PythonABIContract || python.AdapterVersion != udf.PythonAdapterVersion || python.SdkVersion != udf.PythonSDKVersion || python.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation contract is not supported") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation contract is not supported") } if python.Mode != "SCALAR" && python.Mode != "VECTOR" { - return fmt.Errorf("python udf: unsupported typed call mode %q", python.Mode) + return moerr.NewInternalErrorNoCtxf("python udf: unsupported typed call mode %q", python.Mode) } if python.NullPolicy != udf.NullCallHandler && python.NullPolicy != udf.NullReturnNull { - return fmt.Errorf("python udf: unsupported typed NULL policy %q", python.NullPolicy) + return moerr.NewInternalErrorNoCtxf("python udf: unsupported typed NULL policy %q", python.NullPolicy) } if call.NullPolicy != python.NullPolicy { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed call NULL policy does not match its implementation") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed call NULL policy does not match its implementation") } if !udf.IsSHA256Digest(python.ArtifactDigest) || !udf.IsSHA256Digest(python.EnvironmentDigest) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid artifact/environment digest") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid artifact/environment digest") } if !udf.IsSHA256Digest(python.DefinitionFingerprint) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid definition fingerprint") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid definition fingerprint") } arguments := make([]pythonudf.TypeDescriptor, len(call.ArgumentTypes)) for i, argumentType := range call.ArgumentTypes { if argumentType == nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is nil", i) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is nil", i) } descriptor, err := function.NewPythonTypeDescriptor(planTypeToSQL(*argumentType)) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is unsupported: %w", i, err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is unsupported", i) } arguments[i] = descriptor } result, err := function.NewPythonTypeDescriptor(planTypeToSQL(call.ReturnType)) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python return descriptor is unsupported: %w", err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: typed Python return descriptor is unsupported") } fingerprint, err := pythonudf.DefinitionFingerprint( int(python.DefinitionSchemaVersion), python.Handler, python.Mode, python.NullPolicy, @@ -169,10 +170,10 @@ func validateRoutineCall(call *planpb.RoutineCall) error { python.EnvironmentDigest, python.SdkVersion, arguments, result, ) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: invalid typed Python definition: %w", err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: invalid typed Python definition") } if fingerprint != python.DefinitionFingerprint { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python definition fingerprint mismatch") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python definition fingerprint mismatch") } return nil @@ -184,12 +185,12 @@ func (e *ExternalRoutineEval) Eval(proc *process.Process, batches []*batch.Batch func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch, selectList []bool, transfer bool) (output *vector.Vector, evalErr error) { if e == nil || proc == nil || proc.Base == nil { - return nil, fmt.Errorf("python udf: evaluator has no process") + return nil, moerr.NewInternalErrorNoCtxf("python udf: evaluator has no process") } e.executionMu.Lock() defer e.executionMu.Unlock() if e.freed { - return nil, fmt.Errorf("python udf: evaluator is freed") + return nil, moerr.NewInternalErrorNoCtxf("python udf: evaluator is freed") } // Transfer under executionMu, before a concurrent Eval/Free can reuse the // backing. The wrapper retains its allocation policy for the next result. @@ -207,7 +208,7 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch return nil, err } if uint64(accountID) != e.call.FunctionRef.AccountId { - return nil, fmt.Errorf("python udf: FunctionRef account does not match the execution account") + return nil, moerr.NewInternalErrorNoCtxf("python udf: FunctionRef account does not match the execution account") } python := e.call.GetPython() rowCount, err := externalRoutineRowCount(python.Mode, batches) @@ -218,11 +219,7 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch // early before this check would let a stale selection mask cross the // physical boundary and hide a relation-position bug in the caller. if selectList != nil && len(selectList) != rowCount { - return nil, fmt.Errorf( - "external routine selection has %d rows, expected %d", - len(selectList), - rowCount, - ) + return nil, moerr.NewInternalErrorNoCtxf("external routine selection has %d rows, expected %d", len(selectList), rowCount) } if rowCount == 0 { if err := e.result.PreExtendAndReset(0); err != nil { @@ -341,20 +338,16 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch Tuple: tuple, } if proc.Base.UdfService == nil { - return nil, fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime is not enabled") + return nil, moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime is not enabled") } if err := proc.Base.UdfService.Execute(proc.Ctx, invocation, selectedResult, proc.Mp()); err != nil { return nil, err } if selectedResult.ResultLength() != len(e.selectedRows) { - return nil, fmt.Errorf( - "python udf: runtime produced %d result rows, expected %d", - selectedResult.ResultLength(), - len(e.selectedRows), - ) + return nil, moerr.NewInternalErrorNoCtxf("python udf: runtime produced %d result rows, expected %d", selectedResult.ResultLength(), len(e.selectedRows)) } if selectedResult.GetResultVector() == nil { - return nil, fmt.Errorf("python udf: runtime returned no result vector") + return nil, moerr.NewInternalErrorNoCtxf("python udf: runtime returned no result vector") } if len(e.selectedRows) == rowCount { return e.result.GetResultVector(), nil @@ -371,14 +364,14 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch // that two calls belong to the same statement. func (e *ExternalRoutineEval) attachInvocationGroup(context map[string]string, queryID string) error { if context == nil { - return fmt.Errorf("python udf: invocation context is unavailable") + return moerr.NewInternalErrorNoCtxf("python udf: invocation context is unavailable") } e.groupMu.Lock() defer e.groupMu.Unlock() if queryID == "" { group, err := uuid.NewV7() if err != nil { - return fmt.Errorf("python udf: create execution group fence: %w", err) + return errutil.Wrapf(err, "python udf: create execution group fence") } context["group_id"] = "python/" + group.String() context["group_epoch"] = "1" @@ -387,14 +380,14 @@ func (e *ExternalRoutineEval) attachInvocationGroup(context map[string]string, q if e.groupID == "" || e.groupStatementID != queryID { group, err := uuid.NewV7() if err != nil { - return fmt.Errorf("python udf: create execution group fence: %w", err) + return errutil.Wrapf(err, "python udf: create execution group fence") } e.groupStatementID = queryID e.groupID = queryID + "/python/" + group.String() e.groupEpoch = 0 } if e.groupEpoch == ^uint64(0) { - return fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF execution group epoch overflow") + return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF execution group epoch overflow") } e.groupEpoch++ context["group_id"] = e.groupID @@ -416,7 +409,7 @@ func (e *ExternalRoutineEval) compactParameters(proc *process.Process, rowCount e.selectedParameters = e.selectedParameters[:0] for i, input := range e.parameterResults { if input == nil { - return nil, fmt.Errorf("external routine parameter %d is nil", i) + return nil, moerr.NewInternalErrorNoCtxf("external routine parameter %d is nil", i) } if input.IsConst() || len(e.selectedRows) == rowCount { e.selectedParameters = append(e.selectedParameters, input) @@ -439,22 +432,22 @@ func (e *ExternalRoutineEval) compactParameters(proc *process.Process, rowCount func validateExternalRoutineInputs(inputs []*vector.Vector, call *planpb.RoutineCall, rowCount int) error { if len(inputs) != len(call.ArgumentTypes) { - return fmt.Errorf("python udf: evaluated input count %d does not match routine argument count %d", len(inputs), len(call.ArgumentTypes)) + return moerr.NewInternalErrorNoCtxf("python udf: evaluated input count %d does not match routine argument count %d", len(inputs), len(call.ArgumentTypes)) } for index, input := range inputs { if input == nil || input.GetType() == nil { - return fmt.Errorf("python udf: evaluated input vector %d has no type", index) + return moerr.NewInternalErrorNoCtxf("python udf: evaluated input vector %d has no type", index) } if input.Length() == 0 || (!input.IsConst() && input.Length() < rowCount) { - return fmt.Errorf("python udf: evaluated input vector %d has %d rows, expected at least %d", index, input.Length(), rowCount) + return moerr.NewInternalErrorNoCtxf("python udf: evaluated input vector %d has %d rows, expected at least %d", index, input.Length(), rowCount) } expected, err := function.NewPythonTypeDescriptor(planTypeToSQL(*call.ArgumentTypes[index])) if err != nil { - return fmt.Errorf("python udf: invalid argument descriptor %d: %w", index, err) + return errutil.Wrapf(err, "python udf: invalid argument descriptor %d", index) } actual, err := function.NewPythonTypeDescriptor(*input.GetType()) if err != nil { - return fmt.Errorf("python udf: evaluated input vector %d has unsupported type: %w", index, err) + return errutil.Wrapf(err, "python udf: evaluated input vector %d has unsupported type", index) } expectedFingerprint, err := expected.Fingerprint() if err != nil { @@ -465,7 +458,7 @@ func validateExternalRoutineInputs(inputs []*vector.Vector, call *planpb.Routine return err } if expectedFingerprint != actualFingerprint { - return fmt.Errorf("python udf: evaluated input vector %d type %s does not match the frozen descriptor", index, input.GetType().DescString()) + return moerr.NewInternalErrorNoCtxf("python udf: evaluated input vector %d type %s does not match the frozen descriptor", index, input.GetType().DescString()) } } return nil @@ -595,20 +588,20 @@ func externalRoutineRowCount(mode string, batches []*batch.Batch) (int, error) { rowCount := -1 for index, input := range batches { if input == nil { - return 0, fmt.Errorf("external routine input batch %d is nil", index) + return 0, moerr.NewInternalErrorNoCtxf("external routine input batch %d is nil", index) } if rowCount < 0 { rowCount = input.RowCount() continue } if input.RowCount() != rowCount { - return 0, fmt.Errorf("python udf: external routine input batch %d has %d rows, expected %d for the logical row domain", index, input.RowCount(), rowCount) + return 0, moerr.NewInternalErrorNoCtxf("python udf: external routine input batch %d has %d rows, expected %d for the logical row domain", index, input.RowCount(), rowCount) } } return rowCount, nil } if mode == "VECTOR" { - return 0, fmt.Errorf("python udf: zero-argument VECTOR requires an input batch with num_rows") + return 0, moerr.NewInternalErrorNoCtxf("python udf: zero-argument VECTOR requires an input batch with num_rows") } return 1, nil } @@ -619,7 +612,7 @@ func externalRoutineRowCount(mode string, batches []*batch.Batch) (int, error) { // prepared plan can outlive both. func buildRoutineContext(proc *process.Process) (map[string]string, error) { if proc == nil || proc.Base == nil { - return nil, fmt.Errorf("python udf: process is unavailable for statement context") + return nil, moerr.NewInternalErrorNoCtxf("python udf: process is unavailable for statement context") } context := make(map[string]string) // The current query id is stable for the statement and changes for every @@ -637,7 +630,7 @@ func buildRoutineContext(proc *process.Process) (map[string]string, error) { // the lifetime of that process; a real frontend statement always uses // its query start above. if proc.Base.UnixTime == 0 { - return nil, fmt.Errorf("python udf: statement timestamp is unavailable") + return nil, moerr.NewInternalErrorNoCtxf("python udf: statement timestamp is unavailable") } queryStart = time.Unix(0, proc.Base.UnixTime) } @@ -645,12 +638,12 @@ func buildRoutineContext(proc *process.Process) (map[string]string, error) { location := proc.GetSessionInfo().TimeZone if location == nil { - return nil, fmt.Errorf("python udf: session timezone is unavailable") + return nil, moerr.NewInternalErrorNoCtxf("python udf: session timezone is unavailable") } zoneName := location.String() var timezoneErr error if zoneName == "" || zoneName == "SYSTEM" { - return nil, fmt.Errorf("python udf: session timezone is not a stable IANA identity") + return nil, moerr.NewInternalErrorNoCtxf("python udf: session timezone is not a stable IANA identity") } if zoneName == "Local" { zoneName, location, timezoneErr = resolveSystemTimezone() @@ -661,7 +654,7 @@ func buildRoutineContext(proc *process.Process) (map[string]string, error) { if zoneName == "FixedZone" { _, offset := queryStart.In(location).Zone() if offset%60 != 0 { - return nil, fmt.Errorf("python udf: fixed session timezone offset must be a whole number of minutes") + return nil, moerr.NewInternalErrorNoCtxf("python udf: fixed session timezone offset must be a whole number of minutes") } context["session_timezone_kind"] = "FIXED_OFFSET" context["session_timezone_offset_minutes"] = formatTimezoneOffsetMinutes(offset / 60) @@ -681,7 +674,7 @@ func buildRoutineContext(proc *process.Process) (map[string]string, error) { mode := sessionSQLMode(proc) encodedMode, err := json.Marshal(mode) if err != nil { - return nil, fmt.Errorf("python udf: encode sql_mode context: %w", err) + return nil, errutil.Wrapf(err, "python udf: encode sql_mode context") } context["sql_mode"] = string(encodedMode) info := proc.GetSessionInfo() @@ -727,7 +720,7 @@ func resolveSystemTimezone() (string, *time.Location, error) { return candidate, location, nil } } - return "", nil, fmt.Errorf("python udf: SYSTEM timezone has no stable IANA identity") + return "", nil, moerr.NewInternalErrorNoCtxf("python udf: SYSTEM timezone has no stable IANA identity") } func formatTimezoneOffsetMinutes(offset int) string { diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index 576fa6dc27615..af8f2fa811e6c 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -15,7 +15,8 @@ package function import ( - "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "strconv" "github.com/google/uuid" @@ -175,42 +176,42 @@ func pythonUdfRetType(parameters []types.Type) types.Type { // historical overload id. Long-term execution enters through the typed // RoutineCall field and ExternalRoutineEval. func rejectPythonJSONPlan(_ []*vector.Vector, _ vector.FunctionResultWrapper, _ *process.Process, _ int, _ *FunctionSelectList) error { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python JSON plan execution is not supported; reprepare the statement") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python JSON plan execution is not supported; reprepare the statement") } func validatePythonRoutineDescriptor(descriptor *vector.Vector) error { if descriptor == nil { - return fmt.Errorf("python udf: missing routine descriptor") + return moerr.NewInternalErrorNoCtxf("python udf: missing routine descriptor") } if !descriptor.IsConst() { - return fmt.Errorf("python udf: routine descriptor must be constant") + return moerr.NewInternalErrorNoCtxf("python udf: routine descriptor must be constant") } if descriptor.Length() == 0 { - return fmt.Errorf("python udf: routine descriptor is empty") + return moerr.NewInternalErrorNoCtxf("python udf: routine descriptor is empty") } return nil } func validatePythonInputVectors(inputs []*vector.Vector, args []types.Type, length int) error { if len(inputs) != len(args) { - return fmt.Errorf("python udf: input column count %d does not match routine argument count %d", len(inputs), len(args)) + return moerr.NewInternalErrorNoCtxf("python udf: input column count %d does not match routine argument count %d", len(inputs), len(args)) } for index, input := range inputs { if input == nil { - return fmt.Errorf("python udf: input vector %d is nil", index) + return moerr.NewInternalErrorNoCtxf("python udf: input vector %d is nil", index) } if input.Length() == 0 { - return fmt.Errorf("python udf: input vector %d is empty", index) + return moerr.NewInternalErrorNoCtxf("python udf: input vector %d is empty", index) } if !input.IsConst() && input.Length() < length { - return fmt.Errorf("python udf: input vector %d is shorter than invocation length", index) + return moerr.NewInternalErrorNoCtxf("python udf: input vector %d is shorter than invocation length", index) } if input.GetType() == nil || !pythonTypesEqual(*input.GetType(), args[index]) { actual := "" if input.GetType() != nil { actual = input.GetType().String() } - return fmt.Errorf("python udf: input vector %d type %s does not match %s", index, actual, args[index].String()) + return moerr.NewInternalErrorNoCtxf("python udf: input vector %d type %s does not match %s", index, actual, args[index].String()) } } return nil @@ -233,13 +234,13 @@ func invocationTuple(context map[string]string, queryID string, accountID uint32 if statementID == "" { id, err := uuid.NewV7() if err != nil { - return protocol.FencingTuple{}, fmt.Errorf("python udf: create statement fence: %w", err) + return protocol.FencingTuple{}, errutil.Wrapf(err, "python udf: create statement fence") } statementID = id.String() } invocationID, err := uuid.NewV7() if err != nil { - return protocol.FencingTuple{}, fmt.Errorf("python udf: create invocation fence: %w", err) + return protocol.FencingTuple{}, errutil.Wrapf(err, "python udf: create invocation fence") } groupID := context["group_id"] if groupID == "" { @@ -249,7 +250,7 @@ func invocationTuple(context map[string]string, queryID string, accountID uint32 // explicit epoch when it is introduced. groupID = statementID + "/python/" + invocationID.String() } else if context["group_epoch"] == "" { - return protocol.FencingTuple{}, fmt.Errorf("python udf: explicit group_id requires group_epoch") + return protocol.FencingTuple{}, moerr.NewInternalErrorNoCtxf("python udf: explicit group_id requires group_epoch") } groupEpoch, err := positiveContextUint(context, "group_epoch", 1) if err != nil { @@ -283,7 +284,7 @@ func positiveContextUint(context map[string]string, key string, fallback uint64) } parsed, err := strconv.ParseUint(value, 10, 64) if err != nil || parsed == 0 { - return 0, fmt.Errorf("python udf: invalid %s %q", key, value) + return 0, moerr.NewInternalErrorNoCtxf("python udf: invalid %s %q", key, value) } return parsed, nil } diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index a60c78cc0250d..e102ce3b9cabd 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -18,7 +18,8 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "io" "reflect" "strings" @@ -100,29 +101,29 @@ func PythonSignatureMetadata( returnType *PythonTypeDescriptor, ) (canonicalInput, canonicalReturn, fingerprint string, err error) { if returnType == nil { - return "", "", "", fmt.Errorf("python routine is missing return descriptor") + return "", "", "", moerr.NewInternalErrorNoCtxf("python routine is missing return descriptor") } if args == nil { args = []PythonTypeDescriptor{} } for index, descriptor := range args { if err := validatePythonTypeDescriptor(descriptor); err != nil { - return "", "", "", fmt.Errorf("python routine argument descriptor %d: %w", index, err) + return "", "", "", errutil.Wrapf(err, "python routine argument descriptor %d", index) } } if err := validatePythonTypeDescriptor(*returnType); err != nil { - return "", "", "", fmt.Errorf("python routine return descriptor: %w", err) + return "", "", "", errutil.Wrapf(err, "python routine return descriptor") } inputBytes, err := json.Marshal(args) if err != nil { - return "", "", "", fmt.Errorf("marshal Python input descriptor: %w", err) + return "", "", "", errutil.Wrapf(err, "marshal Python input descriptor") } returnBytes, err := json.Marshal(returnType) if err != nil { - return "", "", "", fmt.Errorf("marshal Python return descriptor: %w", err) + return "", "", "", errutil.Wrapf(err, "marshal Python return descriptor") } if len(inputBytes) > types.MaxStringSize || len(returnBytes) > types.MaxStringSize { - return "", "", "", fmt.Errorf("python signature descriptor exceeds the %d-byte catalog limit", types.MaxStringSize) + return "", "", "", moerr.NewInternalErrorNoCtxf("python signature descriptor exceeds the %d-byte catalog limit", types.MaxStringSize) } keyBytes, err := json.Marshal(struct { SchemaVersion int `json:"schema_version"` @@ -134,7 +135,7 @@ func PythonSignatureMetadata( Return: *returnType, }) if err != nil { - return "", "", "", fmt.Errorf("marshal Python signature key: %w", err) + return "", "", "", errutil.Wrapf(err, "marshal Python signature key") } digest := sha256.New() digest.Write([]byte("matrixone-python-udf-signature\x00")) @@ -156,7 +157,7 @@ func DecodePythonRoutineBody(raw string) (PythonRoutineBody, error) { var extra json.RawMessage if err := decoder.Decode(&extra); err != io.EOF { if err == nil { - return PythonRoutineBody{}, fmt.Errorf("python routine body contains multiple JSON values") + return PythonRoutineBody{}, moerr.NewInternalErrorNoCtxf("python routine body contains multiple JSON values") } return PythonRoutineBody{}, err } @@ -199,7 +200,7 @@ func PythonRoutineBodyFingerprint(body PythonRoutineBody) (string, error) { // independently hashing source text. func SQLRoutineFingerprint(body, argTypes, returnType string) (string, error) { if body == "" || returnType == "" { - return "", fmt.Errorf("SQL routine definition is incomplete") + return "", moerr.NewInternalErrorNoCtxf("SQL routine definition is incomplete") } encoded, err := json.Marshal(struct { SchemaVersion int `json:"schema_version"` @@ -213,7 +214,7 @@ func SQLRoutineFingerprint(body, argTypes, returnType string) (string, error) { ReturnType: returnType, }) if err != nil { - return "", fmt.Errorf("marshal SQL routine definition: %w", err) + return "", errutil.Wrapf(err, "marshal SQL routine definition") } digest := sha256.New() digest.Write([]byte("matrixone-sql-udf-definition\x00")) @@ -227,7 +228,7 @@ func SQLRoutineFingerprint(body, argTypes, returnType string) (string, error) { // catalog contract instead of decoding and dispatching this payload. func DecodeUdfWithContext(raw []byte) (UdfWithContext, error) { _ = raw - return UdfWithContext{}, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python JSON plan is not executable; rebind the statement from the current typed catalog contract") + return UdfWithContext{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python JSON plan is not executable; rebind the statement from the current typed catalog contract") } // Validate checks fields that are independent of the catalog argument list. @@ -235,55 +236,55 @@ func DecodeUdfWithContext(raw []byte) (UdfWithContext, error) { // legacy catalog args column has been decoded. func (body PythonRoutineBody) Validate() error { if body.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: python definition schema %d is not supported", body.DefinitionSchemaVersion) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: python definition schema %d is not supported", body.DefinitionSchemaVersion) } if body.Handler == "" || body.Source == "" { - return fmt.Errorf("python routine handler and source are required") + return moerr.NewInternalErrorNoCtxf("python routine handler and source are required") } if !utf8.ValidString(body.Source) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python source is not valid UTF-8") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python source is not valid UTF-8") } if int64(len([]byte(body.Source))) > pythonudf.DefaultMaxArtifactBytes { - return fmt.Errorf("RESOURCE_EXHAUSTED: Python source exceeds %d bytes", pythonudf.DefaultMaxArtifactBytes) + return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python source exceeds %d bytes", pythonudf.DefaultMaxArtifactBytes) } if strings.Contains(body.Handler, ":") { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog") } if body.Mode != "SCALAR" && body.Mode != "VECTOR" { - return fmt.Errorf("python routine has unsupported mode %q", body.Mode) + return moerr.NewInternalErrorNoCtxf("python routine has unsupported mode %q", body.Mode) } if body.NullPolicy != udf.NullCallHandler && body.NullPolicy != udf.NullReturnNull { - return fmt.Errorf("python routine has unsupported NULL policy %q", body.NullPolicy) + return moerr.NewInternalErrorNoCtxf("python routine has unsupported NULL policy %q", body.NullPolicy) } if body.ABIContract != udf.PythonABIContract || body.AdapterVersion != udf.PythonAdapterVersion { - return fmt.Errorf("python routine has unsupported ABI contract %q/%q", body.ABIContract, body.AdapterVersion) + return moerr.NewInternalErrorNoCtxf("python routine has unsupported ABI contract %q/%q", body.ABIContract, body.AdapterVersion) } if body.SDKVersion != udf.PythonSDKVersion { - return fmt.Errorf("python routine has unsupported SDK %q", body.SDKVersion) + return moerr.NewInternalErrorNoCtxf("python routine has unsupported SDK %q", body.SDKVersion) } if !udf.IsSHA256Digest(body.ArtifactDigest) || body.EnvironmentDigest == "" { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition has no immutable artifact/environment digest; use DROP and CREATE") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition has no immutable artifact/environment digest; use DROP and CREATE") } if body.ArtifactDigest != udf.PythonInlineArtifactDigest(body.Handler, body.Source) { - return fmt.Errorf("python routine artifact digest does not match its source") + return moerr.NewInternalErrorNoCtxf("python routine artifact digest does not match its source") } environmentDigest, err := udf.PythonEnvironmentDigest() if err != nil { - return fmt.Errorf("python routine environment digest is unavailable: %w", err) + return errutil.Wrapf(err, "python routine environment digest is unavailable") } if body.EnvironmentDigest != environmentDigest { - return fmt.Errorf("python routine environment digest does not match the current contract") + return moerr.NewInternalErrorNoCtxf("python routine environment digest does not match the current contract") } if body.ReturnType == nil { - return fmt.Errorf("python routine is missing return descriptor") + return moerr.NewInternalErrorNoCtxf("python routine is missing return descriptor") } for i, descriptor := range body.ArgTypes { if err := validatePythonTypeDescriptor(descriptor); err != nil { - return fmt.Errorf("python routine argument descriptor %d: %w", i, err) + return errutil.Wrapf(err, "python routine argument descriptor %d", i) } } if err := validatePythonTypeDescriptor(*body.ReturnType); err != nil { - return fmt.Errorf("python routine return descriptor: %w", err) + return errutil.Wrapf(err, "python routine return descriptor") } return nil } @@ -309,16 +310,16 @@ type Arg struct { // process at execution time. func (u *Udf) GetRoutineCall() (*plan.RoutineCall, error) { if u == nil { - return nil, fmt.Errorf("routine call requires a non-nil routine") + return nil, moerr.NewInternalErrorNoCtxf("routine call requires a non-nil routine") } if u.Language == udf.LanguageSQL { return u.getSQLRoutineCall() } if u.Language != udf.LanguagePython { - return nil, fmt.Errorf("routine call has unsupported language %q", u.Language) + return nil, moerr.NewInternalErrorNoCtxf("routine call has unsupported language %q", u.Language) } if u.FunctionID <= 0 || u.DatabaseID == 0 || u.Revision == 0 || u.NamespaceVersion == 0 { - return nil, fmt.Errorf("python routine has no stable catalog identity or revision") + return nil, moerr.NewInternalErrorNoCtxf("python routine has no stable catalog identity or revision") } body, err := DecodePythonRoutineBody(u.Body) if err != nil { @@ -380,10 +381,10 @@ func (u *Udf) GetRoutineCall() (*plan.RoutineCall, error) { // plan dependency so replace/drop cannot silently reuse the old definition. func (u *Udf) getSQLRoutineCall() (*plan.RoutineCall, error) { if u.FunctionID <= 0 || u.DatabaseID == 0 || u.Revision == 0 || u.NamespaceVersion == 0 { - return nil, fmt.Errorf("SQL routine has no stable catalog identity or revision") + return nil, moerr.NewInternalErrorNoCtxf("SQL routine has no stable catalog identity or revision") } if u.SemanticDefinitionSchemaVersion != udf.SQLDefinitionSchemaVersion || !udf.IsSHA256Digest(u.DefinitionFingerprint) { - return nil, fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: SQL routine has no supported semantic definition") + return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL routine has no supported semantic definition") } argTypes := u.GetArgsType() arguments := make([]*plan.Type, len(argTypes)) @@ -470,7 +471,7 @@ func (u *Udf) LoadPythonTypeContract() error { return nil } if u.Language != udf.LanguagePython { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) } u.PythonArgTypes = nil u.PythonReturnType = nil @@ -493,17 +494,17 @@ func (u *Udf) ValidatePythonTypeContract() error { return nil } if u.Language != udf.LanguagePython { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) } if u.PythonReturnType == nil { - return fmt.Errorf("python routine is missing return descriptor") + return moerr.NewInternalErrorNoCtxf("python routine is missing return descriptor") } if len(u.PythonArgTypes) != len(u.Args) { - return fmt.Errorf("python routine has %d descriptors for %d arguments", len(u.PythonArgTypes), len(u.Args)) + return moerr.NewInternalErrorNoCtxf("python routine has %d descriptors for %d arguments", len(u.PythonArgTypes), len(u.Args)) } for i, descriptor := range u.PythonArgTypes { if err := validatePythonTypeDescriptor(descriptor); err != nil { - return fmt.Errorf("python routine argument descriptor %d: %w", i, err) + return errutil.Wrapf(err, "python routine argument descriptor %d", i) } } return validatePythonTypeDescriptor(*u.PythonReturnType) @@ -520,10 +521,10 @@ func (u *Udf) ValidatePythonCatalogSignature() error { return nil } if u.Language != udf.LanguagePython { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) } if len(u.Args) != len(u.PythonArgTypes) || u.PythonReturnType == nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python catalog signature is incomplete") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python catalog signature is incomplete") } for index, argument := range u.Args { if argument == nil || !pythonCatalogTypeNameMatches(argument.Type, u.PythonArgTypes[index].Type().Oid) { @@ -531,11 +532,11 @@ func (u *Udf) ValidatePythonCatalogSignature() error { if argument != nil { name = argument.Type } - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python catalog argument %d type %q does not match its descriptor", index+1, name) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python catalog argument %d type %q does not match its descriptor", index+1, name) } } if !pythonCatalogTypeNameMatches(u.RetType, u.PythonReturnType.Type().Oid) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python catalog return type %q does not match its descriptor", u.RetType) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python catalog return type %q does not match its descriptor", u.RetType) } return nil } @@ -564,10 +565,10 @@ func validatePythonTypeDescriptor(descriptor PythonTypeDescriptor) error { return err } if !reflect.DeepEqual(canonical, descriptor) { - return fmt.Errorf("descriptor is not canonical for %s", typ.String()) + return moerr.NewInternalErrorNoCtxf("descriptor is not canonical for %s", typ.String()) } if _, err := descriptor.Fingerprint(); err != nil { - return fmt.Errorf("descriptor has no valid Arrow physical type: %w", err) + return errutil.Wrapf(err, "descriptor has no valid Arrow physical type") } return nil } diff --git a/pkg/sql/plan/routine_dependency.go b/pkg/sql/plan/routine_dependency.go index a1d34f8950311..aadb7307d7ee0 100644 --- a/pkg/sql/plan/routine_dependency.go +++ b/pkg/sql/plan/routine_dependency.go @@ -16,6 +16,7 @@ package plan import ( "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "strings" planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" @@ -36,16 +37,16 @@ func (builder *QueryBuilder) assignRoutineCallsite(call *planpb.RoutineCall) err return nil } if call.Language != udf.LanguageSQL && call.Language != udf.LanguagePython { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine call language %q is not canonical", call.Language) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine call language %q is not canonical", call.Language) } if call.CallsiteId != "" { if len(call.CallsiteId) > 256 || strings.ContainsAny(call.CallsiteId, "\r\n") { - return fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine callsite id is too large or invalid") + return moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine callsite id is too large or invalid") } return nil } if builder.nextRoutineCallID == ^uint64(0) { - return fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine callsite id exhausted") + return moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine callsite id exhausted") } builder.nextRoutineCallID++ call.CallsiteId = fmt.Sprintf("%s/%d", strings.ToLower(call.Language), builder.nextRoutineCallID) @@ -57,7 +58,7 @@ func (builder *QueryBuilder) recordRoutinePlanDependency(call *planpb.RoutineCal return nil } if call.Language != udf.LanguageSQL && call.Language != udf.LanguagePython { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: routine call language %q is not canonical", call.Language) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine call language %q is not canonical", call.Language) } ref := call.FunctionRef dependency := &planpb.RoutinePlanDependency{ @@ -94,7 +95,7 @@ func (builder *QueryBuilder) recordRoutinePlanDependency(call *planpb.RoutineCal } } if len(builder.qry.RoutineDependencies) >= maxRoutinePlanDependencies { - return fmt.Errorf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) + return moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) } builder.qry.RoutineDependencies = append(builder.qry.RoutineDependencies, dependency) return nil diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 2ada4e2800423..405a9bd590604 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -23,7 +23,8 @@ import ( "encoding/hex" "encoding/json" "errors" - "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "io" "sync" "time" @@ -51,12 +52,12 @@ const ( ) var ( - ErrProtocol = errors.New("python udf protocol violation") - ErrSequence = errors.New("python udf sequence violation") - ErrGroupClosed = errors.New("python udf execution group is closed") - ErrDuplicate = errors.New("python udf identity is already present") - ErrLedgerFull = errors.New("python udf terminal ledger is full") - ErrUnknownIdentity = errors.New("python udf identity is unknown") + ErrProtocol = moerr.NewInternalErrorNoCtx("python udf protocol violation") + ErrSequence = moerr.NewInternalErrorNoCtx("python udf sequence violation") + ErrGroupClosed = moerr.NewInternalErrorNoCtx("python udf execution group is closed") + ErrDuplicate = moerr.NewInternalErrorNoCtx("python udf identity is already present") + ErrLedgerFull = moerr.NewInternalErrorNoCtx("python udf terminal ledger is full") + ErrUnknownIdentity = moerr.NewInternalErrorNoCtx("python udf identity is unknown") ) // FencingTuple is carried by every invocation control and data-plane @@ -77,13 +78,13 @@ func (t FencingTuple) Validate() error { // never be zero or empty. if t.StatementID == "" || t.GroupID == "" || t.GroupEpoch == 0 || t.InvocationID == "" || t.LeaseEpoch == 0 { - return fmt.Errorf("%w: incomplete fencing tuple", ErrProtocol) + return errutil.WrapfCauseFirst(ErrProtocol, "incomplete fencing tuple") } if !utf8.ValidString(t.StatementID) || !utf8.ValidString(t.GroupID) || !utf8.ValidString(t.InvocationID) { - return fmt.Errorf("%w: fencing tuple contains invalid UTF-8", ErrProtocol) + return errutil.WrapfCauseFirst(ErrProtocol, "fencing tuple contains invalid UTF-8") } if len(t.StatementID) > MaxFenceComponentBytes || len(t.GroupID) > MaxFenceComponentBytes || len(t.InvocationID) > MaxFenceComponentBytes { - return fmt.Errorf("%w: fencing tuple component is too large", ErrProtocol) + return errutil.WrapfCauseFirst(ErrProtocol, "fencing tuple component is too large") } return nil } @@ -133,7 +134,7 @@ var controlBaseFields = map[string]struct{}{ func validateControlFields(control Control, wire map[string]json.RawMessage) error { rule, ok := controlFieldRules[control.Kind] if !ok { - return fmt.Errorf("%w: unsupported control kind %q", ErrProtocol, control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "unsupported control kind %q", control.Kind) } if wire != nil { for field := range wire { @@ -141,106 +142,106 @@ func validateControlFields(control Control, wire map[string]json.RawMessage) err continue } if _, allowed := rule.allowed[field]; !allowed { - return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, field, control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "field %q is not valid for control kind %q", field, control.Kind) } } for field := range rule.required { if _, present := wire[field]; !present { - return fmt.Errorf("%w: control kind %q is missing field %q", ErrProtocol, control.Kind, field) + return errutil.WrapfCauseFirst(ErrProtocol, "control kind %q is missing field %q", control.Kind, field) } } } if control.Sequence != 0 { if _, allowed := rule.allowed["sequence"]; !allowed { - return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "sequence", control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "field %q is not valid for control kind %q", "sequence", control.Kind) } } if control.LastSequence != 0 { if _, allowed := rule.allowed["last_sequence"]; !allowed { - return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "last_sequence", control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "field %q is not valid for control kind %q", "last_sequence", control.Kind) } } if control.AckSequence != 0 { if _, allowed := rule.allowed["ack_sequence"]; !allowed { - return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "ack_sequence", control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "field %q is not valid for control kind %q", "ack_sequence", control.Kind) } } if control.ReleasedBytes != 0 { if _, allowed := rule.allowed["released_bytes"]; !allowed { - return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "released_bytes", control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "field %q is not valid for control kind %q", "released_bytes", control.Kind) } } if control.ReleasedBatches != 0 { if _, allowed := rule.allowed["released_batches"]; !allowed { - return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "released_batches", control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "field %q is not valid for control kind %q", "released_batches", control.Kind) } } if control.LastResultSequence != 0 { if _, allowed := rule.allowed["last_result_sequence"]; !allowed { - return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "last_result_sequence", control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "field %q is not valid for control kind %q", "last_result_sequence", control.Kind) } } if control.FinishID != "" { if _, allowed := rule.allowed["finish_id"]; !allowed { - return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "finish_id", control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "field %q is not valid for control kind %q", "finish_id", control.Kind) } } if control.Status != "" { if _, allowed := rule.allowed["status"]; !allowed { - return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "status", control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "field %q is not valid for control kind %q", "status", control.Kind) } } if control.Reason != "" { if _, allowed := rule.allowed["reason"]; !allowed { - return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "reason", control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "field %q is not valid for control kind %q", "reason", control.Kind) } } if len(control.Payload) != 0 { if _, allowed := rule.allowed["payload"]; !allowed { - return fmt.Errorf("%w: field %q is not valid for control kind %q", ErrProtocol, "payload", control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "field %q is not valid for control kind %q", "payload", control.Kind) } } switch control.Kind { case "OpenInvocation": if len(control.Payload) == 0 && wire == nil { - return fmt.Errorf("%w: control kind %q is missing field %q", ErrProtocol, control.Kind, "payload") + return errutil.WrapfCauseFirst(ErrProtocol, "control kind %q is missing field %q", control.Kind, "payload") } if len(control.Payload) != 0 { var payload map[string]json.RawMessage if err := json.Unmarshal(control.Payload, &payload); err != nil || payload == nil { - return fmt.Errorf("%w: control kind %q payload must be a JSON object", ErrProtocol, control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "control kind %q payload must be a JSON object", control.Kind) } if err := rejectDuplicateJSONKeys(control.Payload); err != nil { - return fmt.Errorf("%w: invalid control payload: %v", ErrProtocol, err) + return errutil.WrapfCauseFirst(ErrProtocol, "invalid control payload: %v", err) } } case "InputBatch", "ResultBatch": if control.Sequence == 0 { - return fmt.Errorf("%w: control kind %q requires a positive sequence", ErrProtocol, control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "control kind %q requires a positive sequence", control.Kind) } case "InputConsumed": if control.Sequence == 0 || control.ReleasedBytes <= 0 || control.ReleasedBatches == 0 { - return fmt.Errorf("%w: control kind %q requires sequence and positive released bytes/batches", ErrProtocol, control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "control kind %q requires sequence and positive released bytes/batches", control.Kind) } case "AcknowledgeResults": if control.AckSequence == 0 { - return fmt.Errorf("%w: control kind %q requires a positive ack_sequence", ErrProtocol, control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "control kind %q requires a positive ack_sequence", control.Kind) } case "Finish": if control.FinishID == "" || control.Status == "" { - return fmt.Errorf("%w: control kind %q requires finish_id and status", ErrProtocol, control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "control kind %q requires finish_id and status", control.Kind) } case "AcknowledgeFinish": if control.FinishID == "" { - return fmt.Errorf("%w: control kind %q requires finish_id", ErrProtocol, control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "control kind %q requires finish_id", control.Kind) } case "Ack": if control.Status == "" || ((control.AckSequence == 0) == (control.FinishID == "")) { - return fmt.Errorf("%w: Ack requires status and exactly one acknowledgement identity", ErrProtocol) + return errutil.WrapfCauseFirst(ErrProtocol, "Ack requires status and exactly one acknowledgement identity") } case "Error": if control.Status == "" || control.Reason == "" { - return fmt.Errorf("%w: control kind %q requires status and reason", ErrProtocol, control.Kind) + return errutil.WrapfCauseFirst(ErrProtocol, "control kind %q requires status and reason", control.Kind) } } return nil @@ -298,7 +299,7 @@ func MarshalControl(control Control) ([]byte, error) { control.Version = Version } if control.Version != Version || control.Kind == "" { - return nil, fmt.Errorf("%w: unsupported control version or empty kind", ErrProtocol) + return nil, errutil.WrapfCauseFirst(ErrProtocol, "unsupported control version or empty kind") } if err := control.Tuple.Validate(); err != nil { return nil, err @@ -308,50 +309,50 @@ func MarshalControl(control Control) ([]byte, error) { } encoded, err := json.Marshal(control) if err != nil { - return nil, fmt.Errorf("%w: encode control: %v", ErrProtocol, err) + return nil, errutil.WrapfCauseFirst(ErrProtocol, "encode control: %v", err) } if len(encoded) > MaxControlBytes { - return nil, fmt.Errorf("%w: control is %d bytes, limit is %d", ErrProtocol, len(encoded), MaxControlBytes) + return nil, errutil.WrapfCauseFirst(ErrProtocol, "control is %d bytes, limit is %d", len(encoded), MaxControlBytes) } return encoded, nil } func UnmarshalControl(data []byte) (Control, error) { if len(data) == 0 || len(data) > MaxControlBytes { - return Control{}, fmt.Errorf("%w: control size %d is outside the allowed range", ErrProtocol, len(data)) + return Control{}, errutil.WrapfCauseFirst(ErrProtocol, "control size %d is outside the allowed range", len(data)) } // encoding/json replaces invalid UTF-8 in JSON strings with U+FFFD. A // fencing tuple is an identity, so accepting that replacement would make a // malformed wire tuple refer to a different invocation than the sender // intended. Reject the bytes before any JSON decoder can normalize them. if !utf8.Valid(data) { - return Control{}, fmt.Errorf("%w: control contains invalid UTF-8", ErrProtocol) + return Control{}, errutil.WrapfCauseFirst(ErrProtocol, "control contains invalid UTF-8") } if err := rejectDuplicateJSONKeys(data); err != nil { - return Control{}, fmt.Errorf("%w: %v", ErrProtocol, err) + return Control{}, errutil.WrapfCauseFirst(ErrProtocol, "%v", err) } var control Control decoder := json.NewDecoder(bytes.NewReader(data)) decoder.DisallowUnknownFields() if err := decoder.Decode(&control); err != nil { - return Control{}, fmt.Errorf("%w: decode control: %v", ErrProtocol, err) + return Control{}, errutil.WrapfCauseFirst(ErrProtocol, "decode control: %v", err) } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { - return Control{}, fmt.Errorf("%w: control contains trailing JSON", ErrProtocol) + return Control{}, errutil.WrapfCauseFirst(ErrProtocol, "control contains trailing JSON") } - return Control{}, fmt.Errorf("%w: decode trailing control data: %v", ErrProtocol, err) + return Control{}, errutil.WrapfCauseFirst(ErrProtocol, "decode trailing control data: %v", err) } if control.Version != Version || control.Kind == "" { - return Control{}, fmt.Errorf("%w: unsupported control version %d", ErrProtocol, control.Version) + return Control{}, errutil.WrapfCauseFirst(ErrProtocol, "unsupported control version %d", control.Version) } if err := control.Tuple.Validate(); err != nil { return Control{}, err } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { - return Control{}, fmt.Errorf("%w: control must be an object: %v", ErrProtocol, err) + return Control{}, errutil.WrapfCauseFirst(ErrProtocol, "control must be an object: %v", err) } if err := validateControlFields(control, fields); err != nil { return Control{}, err @@ -367,9 +368,9 @@ func rejectDuplicateJSONKeys(data []byte) error { var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { - return errors.New("control contains trailing JSON") + return moerr.NewInternalErrorNoCtx("control contains trailing JSON") } - return fmt.Errorf("decode trailing control data: %v", err) + return moerr.NewInternalErrorNoCtxf("decode trailing control data: %v", err) } return nil } @@ -381,14 +382,14 @@ func walkJSONValue(decoder *json.Decoder) error { func walkJSONValueAtDepth(decoder *json.Decoder, depth int) error { token, err := decoder.Token() if err != nil { - return fmt.Errorf("decode control JSON: %v", err) + return moerr.NewInternalErrorNoCtxf("decode control JSON: %v", err) } delim, ok := token.(json.Delim) if !ok { return nil } if depth >= MaxJSONNesting { - return fmt.Errorf("control JSON nesting exceeds %d levels", MaxJSONNesting) + return moerr.NewInternalErrorNoCtxf("control JSON nesting exceeds %d levels", MaxJSONNesting) } switch delim { case '{': @@ -396,14 +397,14 @@ func walkJSONValueAtDepth(decoder *json.Decoder, depth int) error { for decoder.More() { keyToken, err := decoder.Token() if err != nil { - return fmt.Errorf("decode control object key: %v", err) + return moerr.NewInternalErrorNoCtxf("decode control object key: %v", err) } key, ok := keyToken.(string) if !ok { - return errors.New("control object key is not a string") + return moerr.NewInternalErrorNoCtx("control object key is not a string") } if _, exists := seen[key]; exists { - return fmt.Errorf("duplicate control JSON field %q", key) + return moerr.NewInternalErrorNoCtxf("duplicate control JSON field %q", key) } seen[key] = struct{}{} if err := walkJSONValueAtDepth(decoder, depth+1); err != nil { @@ -421,7 +422,7 @@ func walkJSONValueAtDepth(decoder *json.Decoder, depth int) error { _, err = decoder.Token() return err default: - return fmt.Errorf("unexpected control JSON delimiter %q", delim) + return moerr.NewInternalErrorNoCtxf("unexpected control JSON delimiter %q", delim) } } @@ -442,10 +443,10 @@ func (s *Sequence) AcceptInput(sequence uint64) error { s.mu.Lock() defer s.mu.Unlock() if s.inputEnded { - return fmt.Errorf("%w: input arrived after EndInput", ErrSequence) + return errutil.WrapfCauseFirst(ErrSequence, "input arrived after EndInput") } if sequence != s.nextInput+1 { - return fmt.Errorf("%w: input sequence %d, expected %d", ErrSequence, sequence, s.nextInput+1) + return errutil.WrapfCauseFirst(ErrSequence, "input sequence %d, expected %d", sequence, s.nextInput+1) } s.nextInput = sequence s.lastInput = sequence @@ -459,10 +460,10 @@ func (s *Sequence) EndInput(lastSequence uint64) error { if s.lastInput == lastSequence { return nil } - return fmt.Errorf("%w: EndInput changed from %d to %d", ErrSequence, s.lastInput, lastSequence) + return errutil.WrapfCauseFirst(ErrSequence, "EndInput changed from %d to %d", s.lastInput, lastSequence) } if lastSequence != s.lastInput { - return fmt.Errorf("%w: EndInput last sequence %d, observed %d", ErrSequence, lastSequence, s.lastInput) + return errutil.WrapfCauseFirst(ErrSequence, "EndInput last sequence %d, observed %d", lastSequence, s.lastInput) } s.inputEnded = true return nil @@ -472,7 +473,7 @@ func (s *Sequence) AcceptResult(sequence uint64) error { s.mu.Lock() defer s.mu.Unlock() if sequence != s.nextResult+1 || sequence > s.lastInput { - return fmt.Errorf("%w: result sequence %d, expected %d and at most input %d", ErrSequence, sequence, s.nextResult+1, s.lastInput) + return errutil.WrapfCauseFirst(ErrSequence, "result sequence %d, expected %d and at most input %d", sequence, s.nextResult+1, s.lastInput) } s.nextResult = sequence s.lastResult = sequence @@ -483,7 +484,7 @@ func (s *Sequence) AcknowledgeResults(sequence uint64) error { s.mu.Lock() defer s.mu.Unlock() if sequence == 0 || sequence < s.ackedResult || sequence > s.lastResult { - return fmt.Errorf("%w: result ACK %d outside [%d,%d]", ErrSequence, sequence, s.ackedResult, s.lastResult) + return errutil.WrapfCauseFirst(ErrSequence, "result ACK %d outside [%d,%d]", sequence, s.ackedResult, s.lastResult) } s.ackedResult = sequence return nil @@ -512,7 +513,7 @@ type OutputSnapshot struct { func FreezeOutput(source []byte, maxBytes int64) (*OutputSnapshot, error) { if maxBytes <= 0 || int64(len(source)) > maxBytes { - return nil, fmt.Errorf("%w: output snapshot size %d exceeds limit %d", ErrProtocol, len(source), maxBytes) + return nil, errutil.WrapfCauseFirst(ErrProtocol, "output snapshot size %d exceeds limit %d", len(source), maxBytes) } backing := make([]byte, len(source)) copy(backing, source) @@ -535,17 +536,17 @@ func (s *OutputSnapshot) Digest() string { func (s *OutputSnapshot) Validate(expectedLength int, expectedDigest string) error { if s == nil || s.backing == nil { - return fmt.Errorf("%w: missing output snapshot", ErrProtocol) + return errutil.WrapfCauseFirst(ErrProtocol, "missing output snapshot") } if expectedLength >= 0 && len(s.backing) != expectedLength { - return fmt.Errorf("%w: output snapshot length %d, expected %d", ErrProtocol, len(s.backing), expectedLength) + return errutil.WrapfCauseFirst(ErrProtocol, "output snapshot length %d, expected %d", len(s.backing), expectedLength) } currentDigest := sha256.Sum256(s.backing) if currentDigest != s.digest { - return fmt.Errorf("%w: output snapshot backing changed", ErrProtocol) + return errutil.WrapfCauseFirst(ErrProtocol, "output snapshot backing changed") } if expectedDigest != "" && !equalFoldHex(expectedDigest, hex.EncodeToString(currentDigest[:])) { - return fmt.Errorf("%w: output snapshot digest changed", ErrProtocol) + return errutil.WrapfCauseFirst(ErrProtocol, "output snapshot digest changed") } return nil } @@ -639,7 +640,7 @@ type ExecutionGroup struct { func NewExecutionGroup(id string, epoch uint64, maxMembers int, release func() error) (*ExecutionGroup, error) { if id == "" || epoch == 0 || maxMembers <= 0 || release == nil { - return nil, fmt.Errorf("%w: invalid execution group", ErrProtocol) + return nil, errutil.WrapfCauseFirst(ErrProtocol, "invalid execution group") } return &ExecutionGroup{ id: id, epoch: epoch, maxMembers: maxMembers, @@ -652,7 +653,7 @@ func NewExecutionGroup(id string, epoch uint64, maxMembers int, release func() e // token must be committed or aborted exactly once by the Open owner. func (g *ExecutionGroup) BeginOpen(memberID string) (*OpenToken, error) { if memberID == "" { - return nil, fmt.Errorf("%w: empty member id", ErrProtocol) + return nil, errutil.WrapfCauseFirst(ErrProtocol, "empty member id") } g.mu.Lock() defer g.mu.Unlock() @@ -666,7 +667,7 @@ func (g *ExecutionGroup) BeginOpen(memberID string) (*OpenToken, error) { return nil, ErrDuplicate } if g.registered+g.inFlight >= g.maxMembers { - return nil, fmt.Errorf("%w: member limit %d reached", ErrLedgerFull, g.maxMembers) + return nil, errutil.WrapfCauseFirst(ErrLedgerFull, "member limit %d reached", g.maxMembers) } g.pending[memberID] = struct{}{} g.inFlight++ @@ -736,7 +737,7 @@ func (t *OpenToken) begin(state openTokenState) error { t.mu.Lock() defer t.mu.Unlock() if t.state != openTokenPending { - return fmt.Errorf("%w: open token was already finalized", ErrProtocol) + return errutil.WrapfCauseFirst(ErrProtocol, "open token was already finalized") } t.state = state return nil @@ -744,12 +745,12 @@ func (t *OpenToken) begin(state openTokenState) error { func (g *ExecutionGroup) Close(reason CloseReason) error { if reason == "" { - return fmt.Errorf("%w: close reason is empty", ErrProtocol) + return errutil.WrapfCauseFirst(ErrProtocol, "close reason is empty") } g.mu.Lock() if g.closing && g.reason != reason { g.mu.Unlock() - return fmt.Errorf("%w: close reason changed from %q to %q", ErrProtocol, g.reason, reason) + return errutil.WrapfCauseFirst(ErrProtocol, "close reason changed from %q to %q", g.reason, reason) } if g.released { g.mu.Unlock() @@ -821,7 +822,7 @@ func (g *ExecutionGroup) releaseIfReady() error { err := func() (err error) { defer func() { if recovered := recover(); recovered != nil { - err = fmt.Errorf("%w: group release panicked: %v", ErrProtocol, recovered) + err = errutil.WrapfCauseFirst(ErrProtocol, "group release panicked: %v", recovered) } }() return g.release() @@ -916,14 +917,14 @@ type LedgerCredit struct { func NewTerminalLedger(maxEntries int, maxBytes int64) (*TerminalLedger, error) { if maxEntries <= 0 || maxBytes <= 0 { - return nil, fmt.Errorf("%w: invalid terminal ledger limit", ErrProtocol) + return nil, errutil.WrapfCauseFirst(ErrProtocol, "invalid terminal ledger limit") } return &TerminalLedger{maxEntries: maxEntries, maxBytes: maxBytes, entries: make(map[string]ledgerEntry)}, nil } func (l *TerminalLedger) Reserve(groupID string, groupEpoch uint64, entries int, bytes int64) (*LedgerCredit, error) { if groupID == "" || groupEpoch == 0 || entries <= 0 || bytes <= 0 { - return nil, fmt.Errorf("%w: invalid terminal ledger reservation", ErrProtocol) + return nil, errutil.WrapfCauseFirst(ErrProtocol, "invalid terminal ledger reservation") } l.mu.Lock() defer l.mu.Unlock() @@ -937,7 +938,7 @@ func (l *TerminalLedger) Reserve(groupID string, groupEpoch uint64, entries int, func (c *LedgerCredit) Add(key string, bytes int64, expiry time.Time) error { if c == nil || c.ledger == nil || key == "" || bytes <= 0 || expiry.IsZero() { - return fmt.Errorf("%w: invalid terminal ledger entry", ErrProtocol) + return errutil.WrapfCauseFirst(ErrProtocol, "invalid terminal ledger entry") } c.ledger.mu.Lock() defer c.ledger.mu.Unlock() diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index b3217761c53f7..11f254a6ad7c6 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -21,8 +21,9 @@ import ( "encoding/binary" "encoding/hex" "encoding/json" - "errors" "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "io" "math" "reflect" @@ -104,11 +105,11 @@ func NewTypeDescriptor(typ types.Type) (TypeDescriptor, error) { types.T_binary, types.T_varbinary, types.T_blob, types.T_array_float32, types.T_array_float64: default: - return TypeDescriptor{}, fmt.Errorf("python udf does not support MatrixOne type %s", typ.String()) + return TypeDescriptor{}, moerr.NewInternalErrorNoCtxf("python udf does not support MatrixOne type %s", typ.String()) } if typ.Oid == types.T_array_float32 || typ.Oid == types.T_array_float64 { if typ.Width <= 0 { - return TypeDescriptor{}, fmt.Errorf("python udf requires a positive vector dimension for %s", typ.String()) + return TypeDescriptor{}, moerr.NewInternalErrorNoCtxf("python udf requires a positive vector dimension for %s", typ.String()) } d.OffsetWidth = 0 } @@ -156,29 +157,29 @@ func (d TypeDescriptor) Fingerprint() (string, error) { func (d TypeDescriptor) Validate() error { oid := types.T(d.TypeID) if d.Width < 0 { - return fmt.Errorf("TYPE_CONTRACT: descriptor width must be non-negative") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: descriptor width must be non-negative") } if d.Scale < 0 { - return fmt.Errorf("TYPE_CONTRACT: descriptor scale must be non-negative") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: descriptor scale must be non-negative") } expectedOffsetWidth := int32(32) if oid == types.T_uuid || oid == types.T_array_float32 || oid == types.T_array_float64 { expectedOffsetWidth = 0 } if d.OffsetWidth != expectedOffsetWidth { - return fmt.Errorf("TYPE_CONTRACT: descriptor offset_width must be %d for %s", expectedOffsetWidth, oid.String()) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: descriptor offset_width must be %d for %s", expectedOffsetWidth, oid.String()) } if d.JSONEncoding != "" && (oid != types.T_json || d.JSONEncoding != "canonical_text") { - return fmt.Errorf("TYPE_CONTRACT: unsupported JSON encoding") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: unsupported JSON encoding") } if oid == types.T_json && d.JSONEncoding != "canonical_text" { - return fmt.Errorf("TYPE_CONTRACT: JSON descriptor must use canonical_text encoding") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: JSON descriptor must use canonical_text encoding") } if d.TemporalEncoding != "" && (oid != types.T_date && oid != types.T_datetime && oid != types.T_timestamp || d.TemporalEncoding != "sql_zero_struct") { - return fmt.Errorf("TYPE_CONTRACT: unsupported temporal encoding") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: unsupported temporal encoding") } if (oid == types.T_date || oid == types.T_datetime || oid == types.T_timestamp) && d.TemporalEncoding != "sql_zero_struct" { - return fmt.Errorf("TYPE_CONTRACT: temporal descriptor must use sql_zero_struct encoding") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: temporal descriptor must use sql_zero_struct encoding") } switch oid { @@ -186,7 +187,7 @@ func (d TypeDescriptor) Validate() error { types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, types.T_float32, types.T_float64, types.T_json: if d.Width != 0 || d.Scale != 0 || d.Charset != types.CharsetLegacy { - return fmt.Errorf("TYPE_CONTRACT: descriptor carries unused fields for %s", oid.String()) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: descriptor carries unused fields for %s", oid.String()) } case types.T_decimal64, types.T_decimal128: maxPrecision := int32(38) @@ -194,45 +195,45 @@ func (d TypeDescriptor) Validate() error { maxPrecision = 18 } if d.Width < 1 || d.Width > maxPrecision { - return fmt.Errorf("TYPE_CONTRACT: decimal precision %d is outside %s range", d.Width, oid.String()) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: decimal precision %d is outside %s range", d.Width, oid.String()) } if d.Scale > d.Width { - return fmt.Errorf("TYPE_CONTRACT: decimal scale %d exceeds precision %d", d.Scale, d.Width) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: decimal scale %d exceeds precision %d", d.Scale, d.Width) } if d.Charset != types.CharsetLegacy { - return fmt.Errorf("TYPE_CONTRACT: decimal descriptor carries a charset") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: decimal descriptor carries a charset") } case types.T_date: if d.Width != 0 || d.Scale != 0 || d.Charset != types.CharsetLegacy { - return fmt.Errorf("TYPE_CONTRACT: DATE descriptor has unused or invalid fields") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATE descriptor has unused or invalid fields") } case types.T_time, types.T_datetime, types.T_timestamp: if d.Width != 0 || d.Scale > 6 || d.Charset != types.CharsetLegacy { - return fmt.Errorf("TYPE_CONTRACT: temporal scale or charset is outside the supported range") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: temporal scale or charset is outside the supported range") } case types.T_char, types.T_varchar, types.T_text: if d.Scale != 0 { - return fmt.Errorf("TYPE_CONTRACT: text descriptor carries an unused scale") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: text descriptor carries an unused scale") } switch d.Charset { case types.CharsetLegacy, types.CharsetUTF8MB4Bin, types.CharsetUTF8: default: - return fmt.Errorf("TYPE_CONTRACT: unsupported text charset %d", d.Charset) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: unsupported text charset %d", d.Charset) } case types.T_binary, types.T_varbinary, types.T_blob: if d.Scale != 0 || d.Charset != types.CharsetBinary { - return fmt.Errorf("TYPE_CONTRACT: binary descriptor must use the binary charset") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: binary descriptor must use the binary charset") } case types.T_uuid: if d.Width != 0 || d.Scale != 0 || d.Charset != types.CharsetLegacy { - return fmt.Errorf("TYPE_CONTRACT: UUID descriptor carries unused fields") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: UUID descriptor carries unused fields") } case types.T_array_float32, types.T_array_float64: if d.Width < 1 || d.Width > types.MaxArrayDimension || d.Scale != 0 || d.Charset != types.CharsetLegacy { - return fmt.Errorf("TYPE_CONTRACT: vector dimension or metadata is outside the supported range") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: vector dimension or metadata is outside the supported range") } default: - return fmt.Errorf("TYPE_CONTRACT: unsupported MatrixOne type id %d", d.TypeID) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: unsupported MatrixOne type id %d", d.TypeID) } return nil } @@ -270,7 +271,7 @@ func (d TypeDescriptor) arrowType() (arrow.DataType, error) { } } if precision < 1 || precision > decimal128.MaxPrecision { - return nil, fmt.Errorf("decimal precision %d is outside Arrow's supported range", precision) + return nil, moerr.NewInternalErrorNoCtxf("decimal precision %d is outside Arrow's supported range", precision) } return &arrow.Decimal128Type{Precision: precision, Scale: d.Scale}, nil case types.T_char, types.T_varchar, types.T_text, types.T_json: @@ -289,12 +290,12 @@ func (d TypeDescriptor) arrowType() (arrow.DataType, error) { return &arrow.DurationType{Unit: arrow.Microsecond}, nil case types.T_array_float32: if d.Width <= 0 { - return nil, fmt.Errorf("invalid vecf32 dimension %d", d.Width) + return nil, moerr.NewInternalErrorNoCtxf("invalid vecf32 dimension %d", d.Width) } return arrow.FixedSizeListOf(d.Width, arrow.PrimitiveTypes.Float32), nil case types.T_array_float64: if d.Width <= 0 { - return nil, fmt.Errorf("invalid vecf64 dimension %d", d.Width) + return nil, moerr.NewInternalErrorNoCtxf("invalid vecf64 dimension %d", d.Width) } return arrow.FixedSizeListOf(d.Width, arrow.PrimitiveTypes.Float64), nil case types.T_date: @@ -304,7 +305,7 @@ func (d TypeDescriptor) arrowType() (arrow.DataType, error) { case types.T_timestamp: return sqlTemporalType(&arrow.TimestampType{Unit: arrow.Microsecond, TimeZone: "UTC"}), nil default: - return nil, fmt.Errorf("unsupported MatrixOne type id %d", d.TypeID) + return nil, moerr.NewInternalErrorNoCtxf("unsupported MatrixOne type id %d", d.TypeID) } } func sqlTemporalType(value arrow.DataType) *arrow.StructType { @@ -331,10 +332,10 @@ func (d TypeDescriptor) ValidateField(field arrow.Field) error { return err } if field.Type == nil || !sameArrowType(field.Type, want.Type) || field.Nullable != want.Nullable { - return fmt.Errorf("TYPE_CONTRACT: Arrow type %s does not match %s", field.Type, want.Type) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: Arrow type %s does not match %s", field.Type, want.Type) } if !field.Metadata.Equal(want.Metadata) { - return fmt.Errorf("TYPE_CONTRACT: Arrow logical metadata does not match the frozen descriptor") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: Arrow logical metadata does not match the frozen descriptor") } return nil } @@ -361,22 +362,22 @@ type encodedRecordBatch struct { Rows int64 } -var errArrowBatchTooLarge = errors.New("Arrow record batch exceeds the configured limit") +var errArrowBatchTooLarge = moerr.NewInternalErrorNoCtx("Arrow record batch exceeds the configured limit") func EncodeRecordBatch(record arrow.RecordBatch, maxBytes int64) ([]ArrowFrame, error) { if record == nil || record.Schema() == nil || maxBytes <= 0 { - return nil, fmt.Errorf("invalid Arrow record batch") + return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow record batch") } collector := &flightFrameCollector{maxBytes: maxBytes} writer := flight.NewRecordWriter(collector, ipc.WithSchema(record.Schema()), ipc.WithAllocator(memory.NewGoAllocator())) if err := writer.Write(record); err != nil { - return nil, fmt.Errorf("encode Arrow record batch: %w", err) + return nil, errutil.Wrapf(err, "encode Arrow record batch") } if err := writer.Close(); err != nil { - return nil, fmt.Errorf("close Arrow record batch: %w", err) + return nil, errutil.Wrapf(err, "close Arrow record batch") } if len(collector.frames) < 2 { - return nil, fmt.Errorf("Arrow stream did not contain schema and record batch") + return nil, moerr.NewInternalErrorNoCtxf("Arrow stream did not contain schema and record batch") } return collector.frames, nil } @@ -402,16 +403,16 @@ func (c *flightFrameCollector) reset(maxBytes, retainedBytes int64) { func (c *flightFrameCollector) Send(data *flight.FlightData) error { if data == nil || len(data.DataHeader) == 0 { - return fmt.Errorf("invalid Arrow Flight frame") + return moerr.NewInternalErrorNoCtxf("invalid Arrow Flight frame") } if data.FlightDescriptor != nil || len(data.AppMetadata) != 0 { - return fmt.Errorf("unexpected metadata on Arrow payload frame") + return moerr.NewInternalErrorNoCtxf("unexpected metadata on Arrow payload frame") } header := append([]byte(nil), data.DataHeader...) body := append([]byte(nil), data.DataBody...) c.total += int64(len(header) + len(body)) if c.total > c.maxBytes { - return fmt.Errorf("%w: stream is %d bytes, limit is %d", errArrowBatchTooLarge, c.total, c.maxBytes) + return errutil.WrapfCauseFirst(errArrowBatchTooLarge, "stream is %d bytes, limit is %d", c.total, c.maxBytes) } c.frames = append(c.frames, ArrowFrame{Header: header, Body: body}) return nil @@ -434,10 +435,10 @@ type inputBatchWireEncoder struct { func (e *inputBatchWireEncoder) encode(record arrow.RecordBatch, maxBytes int64) ([]ArrowFrame, error) { if e == nil || e.closed || record == nil || maxBytes <= 0 { - return nil, fmt.Errorf("invalid Arrow record batch encoder") + return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow record batch encoder") } if e.schema == nil || !record.Schema().Equal(e.schema) { - return nil, fmt.Errorf("Arrow record batch schema does not match the invocation schema") + return nil, moerr.NewInternalErrorNoCtxf("Arrow record batch schema does not match the invocation schema") } if e.writer == nil { e.collector = &flightFrameCollector{} @@ -451,17 +452,17 @@ func (e *inputBatchWireEncoder) encode(record arrow.RecordBatch, maxBytes int64) e.collector.reset(maxBytes, e.schemaBytes) if err := e.writer.Write(record); err != nil { e.captureSchema() - return nil, fmt.Errorf("encode Arrow record batch: %w", err) + return nil, errutil.Wrapf(err, "encode Arrow record batch") } e.captureSchema() if writerHadSchema { if len(e.collector.frames) != 1 { - return nil, fmt.Errorf("Arrow writer did not emit one record frame") + return nil, moerr.NewInternalErrorNoCtxf("Arrow writer did not emit one record frame") } return []ArrowFrame{e.schemaFrame, e.collector.frames[0]}, nil } if len(e.collector.frames) != 2 || !e.schemaReady { - return nil, fmt.Errorf("Arrow stream did not contain schema and record batch") + return nil, moerr.NewInternalErrorNoCtxf("Arrow stream did not contain schema and record batch") } return append([]ArrowFrame(nil), e.collector.frames...), nil } @@ -488,7 +489,7 @@ func (e *inputBatchWireEncoder) close() error { return nil } if err := e.writer.Close(); err != nil { - return fmt.Errorf("close Arrow record batch encoder: %w", err) + return errutil.Wrapf(err, "close Arrow record batch encoder") } // Commit the closed state only after the writer has released its resources. // A failed close remains retryable for the owning invocation cleanup path. @@ -525,7 +526,7 @@ type inputBatchEncoder struct { func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBatchEncoder, error) { if len(inputs) != len(args) { - return nil, fmt.Errorf("invalid Python UDF input shape") + return nil, moerr.NewInternalErrorNoCtxf("invalid Python UDF input shape") } fields := make([]arrow.Field, len(args)) descriptors := make([]TypeDescriptor, len(args)) @@ -545,19 +546,14 @@ func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBat fixedWidth = false } if inputs[i] == nil { - return nil, fmt.Errorf("input column %d is missing", i) + return nil, moerr.NewInternalErrorNoCtxf("input column %d is missing", i) } actualType := inputs[i].GetType() if actualType == nil { - return nil, fmt.Errorf("input column %d has no type", i) + return nil, moerr.NewInternalErrorNoCtxf("input column %d has no type", i) } if !actualType.Eq(typ) { - return nil, fmt.Errorf( - "input column %d type %s does not match the frozen argument type %s", - i, - actualType.DescString(), - typ.DescString(), - ) + return nil, moerr.NewInternalErrorNoCtxf("input column %d type %s does not match the frozen argument type %s", i, actualType.DescString(), typ.DescString()) } if inputs[i].Length() > 0 && isVarlenaInputType(typ.Oid) { varlenaParameters[i] = vector.GenerateFunctionStrParameter(inputs[i]) @@ -576,7 +572,7 @@ func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBat func (e *inputBatchEncoder) encode(record arrow.RecordBatch, maxBytes int64) ([]ArrowFrame, error) { if e == nil { - return nil, fmt.Errorf("invalid Python UDF input encoder") + return nil, moerr.NewInternalErrorNoCtxf("invalid Python UDF input encoder") } if e.wire == nil { e.wire = &inputBatchWireEncoder{schema: e.schema} @@ -593,11 +589,11 @@ func (e *inputBatchEncoder) close() error { func (e *inputBatchEncoder) build(start, length int) (arrow.RecordBatch, *arrow.Schema, error) { if e == nil || start < 0 || length <= 0 { - return nil, nil, fmt.Errorf("invalid Python UDF input shape") + return nil, nil, moerr.NewInternalErrorNoCtxf("invalid Python UDF input shape") } for i, input := range e.inputs { if input.Length() == 0 || (!input.IsConst() && input.Length() < start+length) { - return nil, nil, fmt.Errorf("input column %d is shorter than batch range", i) + return nil, nil, moerr.NewInternalErrorNoCtxf("input column %d is shorter than batch range", i) } } if len(e.args) == 0 { @@ -610,7 +606,7 @@ func (e *inputBatchEncoder) build(start, length int) (arrow.RecordBatch, *arrow. builder.Field(column), e.inputs[column], typ, start, length, ) if err != nil { - return nil, nil, fmt.Errorf("input column %d: %w", column, err) + return nil, nil, errutil.Wrapf(err, "input column %d", column) } if bulk { continue @@ -620,7 +616,7 @@ func (e *inputBatchEncoder) build(start, length int) (arrow.RecordBatch, *arrow. builder.Field(column), e.inputs[column], typ, start, row, e.varlenaParameters[column], ); err != nil { - return nil, nil, fmt.Errorf("input column %d row %d: %w", column, row, err) + return nil, nil, errutil.Wrapf(err, "input column %d row %d", column, row) } } } @@ -653,7 +649,7 @@ func appendBulkFixedInputValue( return valid } if builder == nil || v == nil { - return false, fmt.Errorf("input column is missing") + return false, moerr.NewInternalErrorNoCtxf("input column is missing") } switch typ.Oid { @@ -739,7 +735,7 @@ func bulkFixedInputWindow[T any](v *vector.Vector, start, length int) ([]T, erro values := vector.MustFixedColNoTypeCheck[T](v) if v.IsConst() { if len(values) == 0 { - return nil, fmt.Errorf("constant input column has no value") + return nil, moerr.NewInternalErrorNoCtxf("constant input column has no value") } expanded := make([]T, length) for row := range expanded { @@ -748,7 +744,7 @@ func bulkFixedInputWindow[T any](v *vector.Vector, start, length int) ([]T, erro return expanded, nil } if start < 0 || length <= 0 || start > len(values) || length > len(values)-start { - return nil, fmt.Errorf("input column is shorter than batch range") + return nil, moerr.NewInternalErrorNoCtxf("input column is shorter than batch range") } return values[start : start+length], nil } @@ -877,7 +873,7 @@ func appendInputValue( index := sourceRow(v, start, row) null := v.IsNull(uint64(index)) if !null && isVarlenaInputType(typ.Oid) && varlenaParameter == nil { - return fmt.Errorf("missing cached varlena input parameter") + return moerr.NewInternalErrorNoCtxf("missing cached varlena input parameter") } if typ.Oid == types.T_date || typ.Oid == types.T_datetime || typ.Oid == types.T_timestamp { return appendTemporalInput(builder.(*array.StructBuilder), v, typ, index, null) @@ -1032,7 +1028,7 @@ func appendInputValue( b.ValueBuilder().(*array.Float64Builder).AppendValues(vector.GetArrayAt[float64](v, index), nil) } default: - return fmt.Errorf("unsupported input type %s", typ.String()) + return moerr.NewInternalErrorNoCtxf("unsupported input type %s", typ.String()) } return nil } @@ -1046,7 +1042,7 @@ func canonicalJSONInput(value []byte) ([]byte, error) { text := []byte(types.DecodeJson(value).String()) canonical, err := canonicalJSONTextBytes(text) if err != nil { - return nil, fmt.Errorf("TYPE_CONTRACT: invalid JSON input: %w", err) + return nil, errutil.Wrapf(err, "TYPE_CONTRACT: invalid JSON input") } return canonical, nil } @@ -1105,7 +1101,7 @@ func appendTemporalInput(builder *array.StructBuilder, v *vector.Vector, typ typ builder.FieldBuilder(0).(*array.BooleanBuilder).Append(zero) builder.FieldBuilder(1).(*array.TimestampBuilder).Append(arrow.Timestamp(raw)) default: - return fmt.Errorf("unsupported temporal type %s", typ.String()) + return moerr.NewInternalErrorNoCtxf("unsupported temporal type %s", typ.String()) } return nil } @@ -1118,24 +1114,24 @@ func decimal64ToArrow(value types.Decimal64) decimal128.Num { func DecodeRecordBatch(schemaFrame, batchFrame ArrowFrame, maxBytes int64) (arrow.RecordBatch, error) { if len(schemaFrame.Header) == 0 || len(batchFrame.Header) == 0 || maxBytes <= 0 { - return nil, fmt.Errorf("invalid Arrow output frames") + return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow output frames") } if len(schemaFrame.Body) != 0 { - return nil, fmt.Errorf("invalid Arrow schema frame body") + return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow schema frame body") } schemaInfo, err := arrowipc.InspectMessage(context.Background(), schemaFrame.Header, arrowipc.ValidationOptions{MaxMetadataBytes: arrowipc.DefaultMaxMetadataBytes, MaxBodyBytes: 0, BodyEnvelopeBytes: 0, MaxDecodedRecordBytes: 1}) if err != nil { return nil, err } if schemaInfo.HeaderType != arrowipc.MessageHeaderSchema { - return nil, fmt.Errorf("invalid Arrow schema frame header %d", schemaInfo.HeaderType) + return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow schema frame header %d", schemaInfo.HeaderType) } batchInfo, err := arrowipc.InspectMessage(context.Background(), batchFrame.Header, arrowipc.ValidationOptions{MaxMetadataBytes: arrowipc.DefaultMaxMetadataBytes, MaxBodyBytes: maxBytes, BodyEnvelopeBytes: int64(len(batchFrame.Body)), Body: batchFrame.Body, ValidateBody: true, MaxDecodedRecordBytes: maxBytes}) if err != nil { return nil, err } if batchInfo.HeaderType != arrowipc.MessageHeaderRecordBatch { - return nil, fmt.Errorf("invalid Arrow record frame header %d", batchInfo.HeaderType) + return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow record frame header %d", batchInfo.HeaderType) } // The snapshot is already the immutable validation/publication backing. // Feed that backing directly to Arrow's stream reader instead of assembling @@ -1145,15 +1141,15 @@ func DecodeRecordBatch(schemaFrame, batchFrame ArrowFrame, maxBytes int64) (arro stream := newIPCStreamReader(schemaFrame, batchFrame) reader, err := ipc.NewReader(stream, ipc.WithAllocator(memory.NewGoAllocator())) if err != nil { - return nil, fmt.Errorf("decode Arrow output: %w", err) + return nil, errutil.Wrapf(err, "decode Arrow output") } defer reader.Release() if !reader.Next() { - return nil, fmt.Errorf("decode Arrow output: %v", reader.Err()) + return nil, moerr.NewInternalErrorNoCtxf("decode Arrow output: %v", reader.Err()) } record := reader.RecordBatch() if record == nil { - return nil, fmt.Errorf("decode Arrow output: missing record batch") + return nil, moerr.NewInternalErrorNoCtxf("decode Arrow output: missing record batch") } record.Retain() return record, nil @@ -1244,10 +1240,10 @@ func (r *ipcStreamReader) Read(dst []byte) (int, error) { func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vector.FunctionResultWrapper, mp *mpool.MPool) error { if input == nil { - return fmt.Errorf("TYPE_CONTRACT: missing Arrow result") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: missing Arrow result") } if result == nil { - return fmt.Errorf("python udf: missing result wrapper") + return moerr.NewInternalErrorNoCtxf("python udf: missing result wrapper") } // AppendArrowResult is also the public adapter boundary used by runtimes // other than the Flight Gateway. Do not let an invalid manually-built @@ -1266,7 +1262,7 @@ func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vect return nil } if mp == nil { - return fmt.Errorf("python udf: missing memory pool for Arrow result") + return moerr.NewInternalErrorNoCtxf("python udf: missing memory pool for Arrow result") } result.GetResultVector().SetTypeScale(descriptor.Scale) typ := types.T(descriptor.TypeID) @@ -1352,7 +1348,7 @@ func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vect return err } default: - return fmt.Errorf("unsupported output type %s", typ.String()) + return moerr.NewInternalErrorNoCtxf("unsupported output type %s", typ.String()) } } return nil @@ -1384,7 +1380,7 @@ func appendJSONArrowResult(input *array.String, result vector.FunctionResultWrap } encoded, err := bytejson.ParseJsonByteFromString(input.Value(i)) if err != nil { - return fmt.Errorf("TYPE_CONTRACT: invalid JSON result: %w", err) + return errutil.Wrapf(err, "TYPE_CONTRACT: invalid JSON result") } if err = output.AppendBytes(encoded, false); err != nil { return err @@ -1453,7 +1449,7 @@ func appendFloat32ArrayResult(input *array.FixedSizeList, row int, null bool, re items := make([]float32, end-start) for i := start; i < end; i++ { if values.IsNull(int(i)) { - return fmt.Errorf("TYPE_CONTRACT: vector child at row %d is null", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: vector child at row %d is null", row) } items[i-start] = values.Value(int(i)) } @@ -1469,7 +1465,7 @@ func appendFloat64ArrayResult(input *array.FixedSizeList, row int, null bool, re items := make([]float64, end-start) for i := start; i < end; i++ { if values.IsNull(int(i)) { - return fmt.Errorf("TYPE_CONTRACT: vector child at row %d is null", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: vector child at row %d is null", row) } items[i-start] = values.Value(int(i)) } @@ -1481,14 +1477,14 @@ func validateArrayType(descriptor TypeDescriptor, input arrow.Array) error { return err } if !sameArrowType(input.DataType(), want) { - return fmt.Errorf("TYPE_CONTRACT: output Arrow type %s does not match %s", input.DataType(), want) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: output Arrow type %s does not match %s", input.DataType(), want) } return nil } func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) error { if input == nil { - return fmt.Errorf("TYPE_CONTRACT: missing Arrow result") + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: missing Arrow result") } for row := 0; row < input.Len(); row++ { if input.IsNull(row) { @@ -1497,25 +1493,25 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro switch types.T(descriptor.TypeID) { case types.T_char, types.T_varchar, types.T_text: if descriptor.Width > 0 && int32(utf8.RuneCountInString(input.(*array.String).Value(row))) > descriptor.Width { - return fmt.Errorf("TYPE_CONTRACT: string row %d exceeds width %d", row, descriptor.Width) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: string row %d exceeds width %d", row, descriptor.Width) } case types.T_json: value := input.(*array.String).Value(row) canonical, err := canonicalJSONText(value) if err != nil { - return fmt.Errorf("TYPE_CONTRACT: JSON row %d is not valid canonical text: %w", row, err) + return errutil.Wrapf(err, "TYPE_CONTRACT: JSON row %d is not valid canonical text", row) } if canonical != value { - return fmt.Errorf("TYPE_CONTRACT: JSON row %d is not canonical text", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: JSON row %d is not canonical text", row) } case types.T_binary, types.T_varbinary, types.T_blob: if descriptor.Width > 0 && int32(len(input.(*array.Binary).Value(row))) > descriptor.Width { - return fmt.Errorf("TYPE_CONTRACT: binary row %d exceeds width %d", row, descriptor.Width) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: binary row %d exceeds width %d", row, descriptor.Width) } case types.T_time: value := types.Time(input.(*array.Duration).Value(row)) if !types.IsMySQLTime(value) || !hasExactMicrosecondScale(int64(value), descriptor.Scale) { - return fmt.Errorf("TYPE_CONTRACT: TIME row %d is outside the declared SQL domain", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: TIME row %d is outside the declared SQL domain", row) } case types.T_decimal64, types.T_decimal128: precision := descriptor.Width @@ -1526,7 +1522,7 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro } } if !input.(*array.Decimal128).Value(row).FitsInPrecision(precision) { - return fmt.Errorf("TYPE_CONTRACT: decimal row %d exceeds precision %d", row, precision) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: decimal row %d exceeds precision %d", row, precision) } case types.T_array_float32: list := input.(*array.FixedSizeList) @@ -1534,7 +1530,7 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro start, end := list.ValueOffsets(row) for child := start; child < end; child++ { if values.IsNull(int(child)) { - return fmt.Errorf("TYPE_CONTRACT: vector child at row %d is null", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: vector child at row %d is null", row) } } case types.T_array_float64: @@ -1543,54 +1539,54 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro start, end := list.ValueOffsets(row) for child := start; child < end; child++ { if values.IsNull(int(child)) { - return fmt.Errorf("TYPE_CONTRACT: vector child at row %d is null", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: vector child at row %d is null", row) } } case types.T_date, types.T_datetime, types.T_timestamp: structValue := input.(*array.Struct) zeroField, valueField := structValue.Field(0), structValue.Field(1) if zeroField.IsNull(row) || valueField.IsNull(row) { - return fmt.Errorf("TYPE_CONTRACT: temporal row %d has a null child", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: temporal row %d has a null child", row) } zero := zeroField.(*array.Boolean).Value(row) switch types.T(descriptor.TypeID) { case types.T_date: value := valueField.(*array.Date32).Value(row) if zero && value != 0 { - return fmt.Errorf("TYPE_CONTRACT: DATE zero row %d has a non-zero placeholder", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATE zero row %d has a non-zero placeholder", row) } if !zero { date := types.DaysFromUnixEpochToDate(int32(value)) year, month, day, _ := date.Calendar(true) if !types.ValidDate(year, month, day) { - return fmt.Errorf("TYPE_CONTRACT: DATE row %d is outside the SQL domain", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATE row %d is outside the SQL domain", row) } } case types.T_datetime: value := valueField.(*array.Timestamp).Value(row) if zero && value != 0 { - return fmt.Errorf("TYPE_CONTRACT: DATETIME zero row %d has a non-zero placeholder", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATETIME zero row %d has a non-zero placeholder", row) } if !zero { absolute, ok := addUnixEpoch(int64(value)) if !ok || !hasExactMicrosecondScale(absolute, descriptor.Scale) { - return fmt.Errorf("TYPE_CONTRACT: DATETIME row %d is outside the declared SQL domain", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATETIME row %d is outside the declared SQL domain", row) } datetime := types.Datetime(absolute) year, month, day, _ := datetime.ToDate().Calendar(true) if !types.ValidDatetime(year, month, day) { - return fmt.Errorf("TYPE_CONTRACT: DATETIME row %d is outside the SQL domain", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATETIME row %d is outside the SQL domain", row) } } case types.T_timestamp: value := valueField.(*array.Timestamp).Value(row) if zero && value != 0 { - return fmt.Errorf("TYPE_CONTRACT: TIMESTAMP zero row %d has a non-zero placeholder", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: TIMESTAMP zero row %d has a non-zero placeholder", row) } if !zero { absolute, ok := addUnixEpoch(int64(value)) if !ok || absolute < int64(types.TimestampMinValue) || absolute > int64(types.TimestampMaxValue) || !hasExactMicrosecondScale(absolute, descriptor.Scale) { - return fmt.Errorf("TYPE_CONTRACT: TIMESTAMP row %d is outside the declared SQL domain", row) + return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: TIMESTAMP row %d is outside the declared SQL domain", row) } } } @@ -1620,7 +1616,7 @@ func hasExactMicrosecondScale(value int64, scale int32) bool { func decimalFromArray(value decimal128.Num, narrow bool) (any, error) { high, low := uint64(value.HighBits()), value.LowBits() if narrow && !decimal128FitsDecimal64(high, low) { - return nil, fmt.Errorf("TYPE_CONTRACT: Decimal128 result does not fit Decimal64") + return nil, moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: Decimal128 result does not fit Decimal64") } if narrow { return types.Decimal64(low), nil diff --git a/pkg/udf/python/artifact.go b/pkg/udf/python/artifact.go index ad374605bdebb..c0175ae01d147 100644 --- a/pkg/udf/python/artifact.go +++ b/pkg/udf/python/artifact.go @@ -17,6 +17,7 @@ package python import ( "context" "fmt" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "strings" "unicode/utf8" @@ -68,20 +69,17 @@ var _ ArtifactStore = (*FileArtifactStore)(nil) func NewFileArtifactStore(fs fileservice.FileService, maxSize int64) (*FileArtifactStore, error) { if fs == nil { - return nil, fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact store has no FileService") + return nil, moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact store has no FileService") } shared, err := fileservice.Get[fileservice.FileService](fs, defines.SharedFileServiceName) if err != nil { - return nil, fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact store has no shared FileService: %w", err) + return nil, errutil.Wrapf(err, "RESOURCE_UNAVAILABLE: Python artifact store has no shared FileService") } if maxSize <= 0 { maxSize = DefaultMaxArtifactBytes } if maxSize > DefaultMaxArtifactBytes { - return nil, fmt.Errorf( - "UNSUPPORTED_ROUTINE_VERSION: Python artifact limit %d exceeds the current contract limit %d", - maxSize, DefaultMaxArtifactBytes, - ) + return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact limit %d exceeds the current contract limit %d", maxSize, DefaultMaxArtifactBytes) } return &FileArtifactStore{fs: shared, maxSize: maxSize}, nil } @@ -111,17 +109,17 @@ func (s *FileArtifactStore) Publish(ctx context.Context, accountID uint64, handl return digest, nil } if !moerr.IsMoErrCode(err, moerr.ErrFileAlreadyExists) { - return "", fmt.Errorf("python artifact publish %s: %w", digest, err) + return "", errutil.Wrapf(err, "python artifact publish %s", digest) } // A concurrent or retrying publisher is successful only after reading and // validating the existing object. This closes the write-once collision // boundary instead of treating path existence as proof of content identity. existing, resolveErr := s.Resolve(ctx, accountID, handler, digest) if resolveErr != nil { - return "", fmt.Errorf("python artifact publish %s found an invalid existing object: %w", digest, resolveErr) + return "", errutil.Wrapf(resolveErr, "python artifact publish %s found an invalid existing object", digest) } if existing != source { - return "", fmt.Errorf("python artifact publish %s encountered a digest collision", digest) + return "", moerr.NewInternalErrorNoCtxf("python artifact publish %s encountered a digest collision", digest) } return digest, nil } @@ -134,18 +132,18 @@ func (s *FileArtifactStore) Resolve(ctx context.Context, accountID uint64, handl ctx = context.Background() } if strings.TrimSpace(handler) == "" { - return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact has no handler") + return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact has no handler") } if !udf.IsSHA256Digest(digest) { - return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest is invalid") + return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest is invalid") } path := artifactPath(accountID, digest) entry, err := s.fs.StatFile(ctx, path) if err != nil { - return "", fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact %s is unavailable: %w", digest, err) + return "", errutil.Wrapf(err, "RESOURCE_UNAVAILABLE: Python artifact %s is unavailable", digest) } if entry == nil || entry.IsDir || entry.Size <= 0 || entry.Size > s.maxSize { - return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s has invalid size", digest) + return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s has invalid size", digest) } data := make([]byte, entry.Size) readVector := &fileservice.IOVector{ @@ -153,46 +151,46 @@ func (s *FileArtifactStore) Resolve(ctx context.Context, accountID uint64, handl Entries: []fileservice.IOEntry{{Offset: 0, Size: entry.Size, Data: data}}, } if err := s.fs.Read(ctx, readVector); err != nil { - return "", fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact %s cannot be read: %w", digest, err) + return "", errutil.Wrapf(err, "RESOURCE_UNAVAILABLE: Python artifact %s cannot be read", digest) } if len(readVector.Entries) != 1 || int64(len(readVector.Entries[0].Data)) != entry.Size { - return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s changed size while reading", digest) + return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s changed size while reading", digest) } source := string(readVector.Entries[0].Data) if !utf8.ValidString(source) { - return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s is not valid UTF-8", digest) + return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s is not valid UTF-8", digest) } if udf.PythonInlineArtifactDigest(handler, source) != digest { - return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s content digest mismatch", digest) + return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s content digest mismatch", digest) } return source, nil } func validateArtifactInput(accountID uint64, handler, source string, maxSize int64) (string, error) { if maxSize <= 0 { - return "", fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact store has an invalid size limit") + return "", moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact store has an invalid size limit") } if strings.TrimSpace(handler) == "" { - return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact has no handler") + return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact has no handler") } if source == "" { - return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is empty") + return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is empty") } if !utf8.ValidString(source) { - return "", fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is not valid UTF-8") + return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is not valid UTF-8") } if int64(len([]byte(source))) > maxSize { - return "", fmt.Errorf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", maxSize) + return "", moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", maxSize) } return udf.PythonInlineArtifactDigest(handler, source), nil } func (s *FileArtifactStore) validate() error { if s == nil || s.fs == nil { - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact store has no FileService") + return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact store has no FileService") } if s.maxSize <= 0 { - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact store has an invalid size limit") + return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact store has an invalid size limit") } return nil } diff --git a/pkg/udf/python/definition.go b/pkg/udf/python/definition.go index 2f172098158e8..3a2db3e2bbc65 100644 --- a/pkg/udf/python/definition.go +++ b/pkg/udf/python/definition.go @@ -18,7 +18,8 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" ) // definitionFingerprintBody is the canonical executable contract. Source is @@ -55,15 +56,15 @@ func DefinitionFingerprint( mode == "" || nullPolicy == "" || abiContract == "" || adapterVersion == "" || sdkVersion == "" || artifactDigest == "" || environmentDigest == "" { - return "", fmt.Errorf("python definition fingerprint has incomplete metadata") + return "", moerr.NewInternalErrorNoCtxf("python definition fingerprint has incomplete metadata") } for index, descriptor := range args { if err := descriptor.Validate(); err != nil { - return "", fmt.Errorf("argument descriptor %d: %w", index, err) + return "", errutil.Wrapf(err, "argument descriptor %d", index) } } if err := returnType.Validate(); err != nil { - return "", fmt.Errorf("return descriptor: %w", err) + return "", errutil.Wrapf(err, "return descriptor") } body := definitionFingerprintBody{ DefinitionSchemaVersion: definitionSchemaVersion, @@ -80,7 +81,7 @@ func DefinitionFingerprint( } canonical, err := json.Marshal(body) if err != nil { - return "", fmt.Errorf("marshal definition fingerprint: %w", err) + return "", errutil.Wrapf(err, "marshal definition fingerprint") } digest := sha256.Sum256(canonical) return hex.EncodeToString(digest[:]), nil diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index 27fb6033a6e68..fddb53d318c23 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -21,7 +21,8 @@ import ( "encoding/hex" "encoding/json" "errors" - "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "io" "strconv" "strings" @@ -59,7 +60,7 @@ const ( statusOK = "OK" ) -var errGatewayClosed = errors.New("python udf gateway is closed") +var errGatewayClosed = moerr.NewInternalErrorNoCtx("python udf gateway is closed") var _ udf.RuntimeDefinitionValidator = (*Gateway)(nil) var _ udf.RuntimeStatusProvider = (*Gateway)(nil) @@ -110,7 +111,7 @@ func NewGateway(cfg ClientConfig) (*Gateway, error) { // rejected at this boundary. func NewGatewayWithArtifactStore(cfg ClientConfig, resolver ArtifactResolver) (*Gateway, error) { if resolver == nil { - return nil, fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") + return nil, moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") } return newGateway(cfg, resolver, false) } @@ -174,13 +175,13 @@ func (g *Gateway) CheckLanguageReady(ctx context.Context, language string) error ctx = context.Background() } if language != udf.LanguagePython { - return fmt.Errorf("python udf: unsupported readiness language %q", language) + return moerr.NewInternalErrorNoCtxf("python udf: unsupported readiness language %q", language) } if !g.cfg.Enabled { - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") + return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") } if !g.cfg.AllowUnisolated { - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") + return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") } requestCtx, release := g.withLifecycleContext(ctx) defer release() @@ -303,10 +304,10 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin return errGatewayClosed } if !g.cfg.Enabled { - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") + return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") } if !g.cfg.AllowUnisolated { - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") + return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") } requestCtx, release := g.withLifecycleContext(ctx) defer release() @@ -316,49 +317,49 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin defer cancel() } if definition == nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: nil Python routine definition") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: nil Python routine definition") } if definition.Language != udf.LanguagePython { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported UDF language %q", definition.Language) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported UDF language %q", definition.Language) } if strings.TrimSpace(definition.Handler) == "" { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python handler is required") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python handler is required") } if strings.Contains(definition.Handler, ":") { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires the immutable artifact catalog") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires the immutable artifact catalog") } if definition.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion || definition.ABIContract != udf.PythonABIContract || definition.AdapterVersion != udf.PythonAdapterVersion || definition.SDKVersion != udf.PythonSDKVersion { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition contract is not supported") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition contract is not supported") } if definition.Mode != ModeScalar && definition.Mode != ModeVector { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python mode %q", definition.Mode) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python mode %q", definition.Mode) } if definition.NullPolicy != NullCallHandler && definition.NullPolicy != NullReturnNull { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python NULL policy %q", definition.NullPolicy) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python NULL policy %q", definition.NullPolicy) } if !udf.IsSHA256Digest(definition.ArtifactDigest) || !udf.IsSHA256Digest(definition.EnvironmentDigest) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition digest is invalid") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition digest is invalid") } currentEnvironment, err := udf.PythonEnvironmentDigest() if err != nil || currentEnvironment != definition.EnvironmentDigest { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the current contract") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the current contract") } if !udf.IsSHA256Digest(definition.DefinitionFingerprint) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint is invalid") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint is invalid") } args := make([]TypeDescriptor, len(definition.Args)) for index, typ := range definition.Args { args[index], err = NewTypeDescriptor(typ) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python argument descriptor %d: %w", index, err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python argument descriptor %d", index) } } returnDescriptor, err := NewTypeDescriptor(definition.ReturnType) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python return descriptor: %w", err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python return descriptor") } expectedFingerprint, err := DefinitionFingerprint( definition.DefinitionSchemaVersion, @@ -368,10 +369,10 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin args, returnDescriptor, ) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint cannot be computed: %w", err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint cannot be computed") } if definition.DefinitionFingerprint != expectedFingerprint { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition") } source := definition.Source @@ -383,20 +384,20 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin return resolveErr } if source != "" && source != resolved { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source does not match the immutable artifact") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source does not match the immutable artifact") } source = resolved } else if !g.allowInlineSource { - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") + return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") } if source == "" || !utf8.ValidString(source) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is empty or not valid UTF-8") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is empty or not valid UTF-8") } if int64(len([]byte(source))) > DefaultMaxArtifactBytes { - return fmt.Errorf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", DefaultMaxArtifactBytes) + return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", DefaultMaxArtifactBytes) } if udf.PythonInlineArtifactDigest(definition.Handler, source) != definition.ArtifactDigest { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") } client, err := g.flightClient() @@ -428,7 +429,7 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin Return: returnDescriptor, }) if err != nil { - return fmt.Errorf("python udf: encode definition validation: %w", err) + return errutil.Wrapf(err, "python udf: encode definition validation") } actionCtx := requestCtx var actionCancel context.CancelFunc @@ -439,53 +440,53 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin stream, err := client.DoAction(actionCtx, &flight.Action{Type: "ValidatePythonDefinition", Body: payload}) if err != nil { g.invalidateCapabilities(capability.generation) - return fmt.Errorf("python udf: definition validation action: %w", err) + return errutil.Wrapf(err, "python udf: definition validation action") } result, err := stream.Recv() if err != nil { g.invalidateCapabilities(capability.generation) - return fmt.Errorf("python udf: definition validation response: %w", err) + return errutil.Wrapf(err, "python udf: definition validation response") } if result == nil { g.invalidateCapabilities(capability.generation) - return fmt.Errorf("python udf: empty definition validation response") + return moerr.NewInternalErrorNoCtxf("python udf: empty definition validation response") } var response definitionValidationResponse decoder := json.NewDecoder(bytes.NewReader(result.Body)) decoder.DisallowUnknownFields() if err := decoder.Decode(&response); err != nil { g.invalidateCapabilities(capability.generation) - return fmt.Errorf("python udf: decode definition validation response: %w", err) + return errutil.Wrapf(err, "python udf: decode definition validation response") } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { g.invalidateCapabilities(capability.generation) - return fmt.Errorf("python udf: definition validation response has trailing JSON") + return moerr.NewInternalErrorNoCtxf("python udf: definition validation response has trailing JSON") } if response.Status == "ERROR" { if _, err := stream.Recv(); err != io.EOF { g.invalidateCapabilities(capability.generation) if err == nil { - return fmt.Errorf("python udf: definition validation returned multiple results") + return moerr.NewInternalErrorNoCtxf("python udf: definition validation returned multiple results") } - return fmt.Errorf("python udf: definition validation stream: %w", err) + return errutil.Wrapf(err, "python udf: definition validation stream") } if response.Reason == "" { - return fmt.Errorf("USER_CODE: Python definition validation failed") + return moerr.NewInternalErrorNoCtxf("USER_CODE: Python definition validation failed") } - return errors.New(response.Reason) + return moerr.NewInternalErrorNoCtx(response.Reason) } if response.Status != statusOK || response.ArtifactDigest != definition.ArtifactDigest || response.DefinitionFingerprint != definition.DefinitionFingerprint { g.invalidateCapabilities(capability.generation) - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition validation returned an invalid result") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition validation returned an invalid result") } if _, err := stream.Recv(); err != io.EOF { g.invalidateCapabilities(capability.generation) if err == nil { - return fmt.Errorf("python udf: definition validation returned multiple results") + return moerr.NewInternalErrorNoCtxf("python udf: definition validation returned multiple results") } - return fmt.Errorf("python udf: definition validation stream: %w", err) + return errutil.Wrapf(err, "python udf: definition validation stream") } return nil } @@ -615,22 +616,22 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return errGatewayClosed } if !g.cfg.Enabled { - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") + return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") } if !g.cfg.AllowUnisolated { - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") + return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") } requestCtx, release := g.withLifecycleContext(ctx) defer release() streamCtx, cancel := context.WithTimeout(requestCtx, g.cfg.RequestTimeout) defer cancel() if invocation == nil || result == nil || mp == nil { - return fmt.Errorf("python udf: nil invocation, result, or memory pool") + return moerr.NewInternalErrorNoCtxf("python udf: nil invocation, result, or memory pool") } execution := *invocation if g.artifactResolver != nil { if execution.Source != "" { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: typed Python invocation contains source; use its immutable artifact digest") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python invocation contains source; use its immutable artifact digest") } // Validate the identity, semantic contract, descriptors, and resource // shape before resolving an account-scoped artifact. Resolution is a @@ -650,7 +651,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return err } } else if !g.allowInlineSource && execution.Source == "" { - return fmt.Errorf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") + return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") } if err := validateInvocation(&execution); err != nil { return err @@ -712,7 +713,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul // invalidation below forces a fresh handshake on the next call. workerLeaseEpoch := capability.response.LeaseEpoch if workerLeaseEpoch == 0 { - return fmt.Errorf("python udf: capability handshake did not return a worker lease epoch") + return moerr.NewInternalErrorNoCtxf("python udf: capability handshake did not return a worker lease epoch") } execution.Tuple.LeaseEpoch = workerLeaseEpoch if err := validateInvocation(&execution); err != nil { @@ -739,7 +740,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul HandlerTimeoutSeconds: g.cfg.RequestTimeout.Seconds(), }) if err != nil { - return fmt.Errorf("python udf: encode open payload: %w", err) + return errutil.Wrapf(err, "python udf: encode open payload") } open, err := protocol.MarshalControl(protocol.Control{Kind: "OpenInvocation", Tuple: execution.Tuple, Payload: openBody}) if err != nil { @@ -765,7 +766,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul stream, err := client.DoExchange(streamCtx) if err != nil { - return fmt.Errorf("python udf: open Arrow Flight exchange: %w", err) + return errutil.Wrapf(err, "python udf: open Arrow Flight exchange") } // Flight carries the invocation command in the descriptor. The descriptor // is delivered to the server separately from the Arrow IPC reader; putting @@ -797,7 +798,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return err } if len(batch.Frames) != 2 { - return fmt.Errorf("python udf: input batch contains %d Arrow frames", len(batch.Frames)) + return moerr.NewInternalErrorNoCtxf("python udf: input batch contains %d Arrow frames", len(batch.Frames)) } if batchIndex == 0 { inputSchema = append([]byte(nil), batch.Frames[0].Header...) @@ -805,7 +806,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return err } } else if !bytes.Equal(inputSchema, batch.Frames[0].Header) { - return fmt.Errorf("python udf: input batches do not share one Arrow schema") + return moerr.NewInternalErrorNoCtxf("python udf: input batches do not share one Arrow schema") } sequenceNumber := batchIndex + 1 if err := sequence.AcceptInput(sequenceNumber); err != nil { @@ -851,7 +852,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul } } if !inputEnded || lastSequence != batchIndex { - return fmt.Errorf("python udf: input stream did not reach EndInput") + return moerr.NewInternalErrorNoCtxf("python udf: input stream did not reach EndInput") } // Close the local Arrow writer before accepting the worker's terminal // Finish. If finalizing the local input owner fails, the admission cleanup @@ -886,7 +887,7 @@ type invocationAdmission struct { func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmission, error) { if invocation == nil { - return nil, fmt.Errorf("python udf: cannot admit a nil invocation") + return nil, moerr.NewInternalErrorNoCtxf("python udf: cannot admit a nil invocation") } if err := invocation.Tuple.Validate(); err != nil { return nil, err @@ -923,7 +924,7 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss if ledger == nil || active == nil { g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() - return nil, fmt.Errorf("python udf: admission state is not initialized") + return nil, moerr.NewInternalErrorNoCtxf("python udf: admission state is not initialized") } // Expire is intentionally limited to tombstones by TerminalLedger. An // active invocation can leave this path only through finish/abandon. @@ -936,7 +937,7 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss if err != nil { g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() - return nil, fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF terminal ledger: %w", err) + return nil, errutil.Wrapf(err, "RESOURCE_EXHAUSTED: Python UDF terminal ledger") } if err := credit.Add(key, entryBytes, time.Now().Add(ttl)); err != nil { credit.ReleaseUnused() @@ -954,7 +955,7 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss credit.ReleaseUnused() g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() - return nil, fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF active invocation slots are full") + return nil, moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF active invocation slots are full") } var releaseOnce sync.Once @@ -1055,10 +1056,10 @@ func (g *Gateway) ensureAdmissionState() error { func (g *Gateway) claimGroupLocked(groupID string, groupEpoch uint64) error { if closedEpoch, ok := g.closedGroups[groupID]; ok && groupEpoch <= closedEpoch { - return fmt.Errorf("%w: execution group %q epoch %d is already closed", protocol.ErrDuplicate, groupID, groupEpoch) + return errutil.WrapfCauseFirst(protocol.ErrDuplicate, "execution group %q epoch %d is already closed", groupID, groupEpoch) } if admittedEpoch, ok := g.admittedGroups[groupID]; ok { - return fmt.Errorf("%w: execution group %q epoch %d is already admitted", protocol.ErrDuplicate, groupID, admittedEpoch) + return errutil.WrapfCauseFirst(protocol.ErrDuplicate, "execution group %q epoch %d is already admitted", groupID, admittedEpoch) } if _, exists := g.closedGroups[groupID]; !exists { // Reserve the future tombstone while the group is active. Checking only @@ -1067,7 +1068,7 @@ func (g *Gateway) claimGroupLocked(groupID string, groupEpoch uint64) error { // drain together. if len(g.closedGroups)+len(g.admittedGroups) >= g.closedGroupLimit || g.closedGroupBytes+g.reservedGroupBytes+int64(len(groupID)+8) > g.closedGroupByteLimit { - return fmt.Errorf("%w: Python UDF closed-group fence is full", protocol.ErrLedgerFull) + return errutil.WrapfCauseFirst(protocol.ErrLedgerFull, "Python UDF closed-group fence is full") } g.reservedGroupBytes += int64(len(groupID) + 8) } @@ -1120,7 +1121,7 @@ func scopedGroupKey(accountID uint64, groupID string) string { func invocationLedgerKey(tuple protocol.FencingTuple) (string, error) { wire, err := json.Marshal(tuple) if err != nil { - return "", fmt.Errorf("python udf: encode invocation identity: %w", err) + return "", errutil.Wrapf(err, "python udf: encode invocation identity") } digest := sha256.Sum256(wire) return hex.EncodeToString(digest[:]), nil @@ -1308,7 +1309,7 @@ func (g *Gateway) ensureCapabilitySnapshot(ctx context.Context, client flight.Fl if g.closed { err = errGatewayClosed } else if p.generation != g.capabilityGeneration { - err = errors.New("python udf: capability probe invalidated") + err = moerr.NewInternalErrorNoCtx("python udf: capability probe invalidated") } else if ctx.Err() != nil { err = ctx.Err() } @@ -1331,33 +1332,33 @@ func readCapabilities(ctx context.Context, client flight.FlightServiceClient) (* } stream, err := client.DoAction(ctx, &flight.Action{Type: "GetPythonCapabilities", Body: request}) if err != nil { - return nil, fmt.Errorf("python udf: capability handshake: %w", err) + return nil, errutil.Wrapf(err, "python udf: capability handshake") } result, err := stream.Recv() if err != nil { - return nil, fmt.Errorf("python udf: capability handshake response: %w", err) + return nil, errutil.Wrapf(err, "python udf: capability handshake response") } if result == nil { - return nil, fmt.Errorf("python udf: empty capability handshake response") + return nil, moerr.NewInternalErrorNoCtxf("python udf: empty capability handshake response") } var response capabilityResponse decoder := json.NewDecoder(bytes.NewReader(result.Body)) decoder.DisallowUnknownFields() if err := decoder.Decode(&response); err != nil { - return nil, fmt.Errorf("python udf: decode capability handshake: %w", err) + return nil, errutil.Wrapf(err, "python udf: decode capability handshake") } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { - return nil, fmt.Errorf("python udf: capability handshake has trailing JSON") + return nil, moerr.NewInternalErrorNoCtxf("python udf: capability handshake has trailing JSON") } if err := validateCapabilities(response); err != nil { return nil, err } if _, err := stream.Recv(); err != io.EOF { if err == nil { - return nil, fmt.Errorf("python udf: capability handshake returned multiple results") + return nil, moerr.NewInternalErrorNoCtxf("python udf: capability handshake returned multiple results") } - return nil, fmt.Errorf("python udf: capability handshake stream: %w", err) + return nil, errutil.Wrapf(err, "python udf: capability handshake stream") } return &response, nil } @@ -1398,11 +1399,11 @@ func validateCapabilities(response capabilityResponse) error { response.MaxAccountHandlerProcesses != DefaultWorkerMaxAccountHandlers || response.MaxOwnerHandlerProcesses != DefaultWorkerMaxOwnerHandlers || response.LeaseEpoch == 0 { - return fmt.Errorf("python udf: worker capability contract does not match the current contract") + return moerr.NewInternalErrorNoCtxf("python udf: worker capability contract does not match the current contract") } if !sameStrings(response.Modes, []string{ModeScalar, ModeVector}) || !sameStrings(response.NullPolicies, []string{NullCallHandler, NullReturnNull}) { - return fmt.Errorf("python udf: worker capability set does not match the current contract") + return moerr.NewInternalErrorNoCtxf("python udf: worker capability set does not match the current contract") } return nil } @@ -1437,10 +1438,10 @@ func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaini func encodeInputBatchWithEncoder(encoder *inputBatchEncoder, start, remaining, maxBytes, maxRows int64) (encodedRecordBatch, error) { if start < 0 || remaining <= 0 { - return encodedRecordBatch{}, fmt.Errorf("invalid Python UDF input batch range") + return encodedRecordBatch{}, moerr.NewInternalErrorNoCtxf("invalid Python UDF input batch range") } if maxRows <= 0 { - return encodedRecordBatch{}, fmt.Errorf("invalid Python UDF max batch rows") + return encodedRecordBatch{}, moerr.NewInternalErrorNoCtxf("invalid Python UDF max batch rows") } if remaining > maxRows { remaining = maxRows @@ -1451,7 +1452,7 @@ func encodeInputBatchWithEncoder(encoder *inputBatchEncoder, start, remaining, m // slice keeps the same backing buffers, and every candidate is still encoded // and checked against maxBytes before publication. if encoder == nil { - return encodedRecordBatch{}, fmt.Errorf("invalid Python UDF input encoder") + return encodedRecordBatch{}, moerr.NewInternalErrorNoCtxf("invalid Python UDF input encoder") } if encoder.fixedWidth { record, _, err := encoder.build(int(start), int(remaining)) @@ -1537,7 +1538,7 @@ func chooseInputBatchWithFullCandidate(remaining, maxBytes int64, tryEncode func high = middle - 1 } if best == 0 { - return encodedRecordBatch{}, fmt.Errorf("%w: one Arrow row exceeds %d bytes", errArrowBatchTooLarge, maxBytes) + return encodedRecordBatch{}, errutil.WrapfCauseFirst(errArrowBatchTooLarge, "one Arrow row exceeds %d bytes", maxBytes) } return encodedRecordBatch{Frames: bestFrames, Rows: best}, nil } @@ -1561,17 +1562,17 @@ func (g *Gateway) receiveResultBatch( data, err := stream.Recv() if err != nil { if err == io.EOF { - return 0, fmt.Errorf("python udf: exchange ended before result sequence %d", sequenceNumber) + return 0, moerr.NewInternalErrorNoCtxf("python udf: exchange ended before result sequence %d", sequenceNumber) } - return 0, fmt.Errorf("python udf: receive result: %w", err) + return 0, errutil.Wrapf(err, "python udf: receive result") } if data == nil || (len(data.AppMetadata) == 0 && len(data.DataHeader) == 0) { - return 0, fmt.Errorf("python udf: empty Flight result") + return 0, moerr.NewInternalErrorNoCtxf("python udf: empty Flight result") } if len(data.DataHeader) > 0 { if *schemaFrame == nil { if len(data.DataBody) != 0 { - return 0, fmt.Errorf("python udf: result schema contains a body") + return 0, moerr.NewInternalErrorNoCtxf("python udf: result schema contains a body") } *schemaFrame = &ArrowFrame{Header: append([]byte(nil), data.DataHeader...)} if len(data.AppMetadata) != 0 { @@ -1583,17 +1584,17 @@ func (g *Gateway) receiveResultBatch( continue } if !*schemaReady { - return 0, fmt.Errorf("python udf: result schema metadata was not received") + return 0, moerr.NewInternalErrorNoCtxf("python udf: result schema metadata was not received") } control, err := protocol.UnmarshalControl(data.AppMetadata) if err != nil { return 0, err } if control.Tuple != tuple || control.Kind != "ResultBatch" || control.Sequence != sequenceNumber { - return 0, fmt.Errorf("python udf: unexpected result sequence %d", control.Sequence) + return 0, moerr.NewInternalErrorNoCtxf("python udf: unexpected result sequence %d", control.Sequence) } if !inputConsumed { - return 0, fmt.Errorf("python udf: result sequence %d arrived before InputConsumed", sequenceNumber) + return 0, moerr.NewInternalErrorNoCtxf("python udf: result sequence %d arrived before InputConsumed", sequenceNumber) } if err := sequence.AcceptResult(control.Sequence); err != nil { return 0, err @@ -1612,16 +1613,16 @@ func (g *Gateway) receiveResultBatch( // validation/publication boundary. decoded, err := DecodeRecordBatch(**schemaFrame, ArrowFrame{Header: headerSnapshot.TrustedBytes(), Body: bodySnapshot.TrustedBytes()}, g.cfg.MaxBatchBytes) if err != nil { - return 0, fmt.Errorf("python udf: decode result: %w", err) + return 0, errutil.Wrapf(err, "python udf: decode result") } decodedRows := decoded.NumRows() if decoded.NumCols() != 1 || decodedRows <= 0 || decodedRows != expectedRows { decoded.Release() - return 0, fmt.Errorf("python udf: result batch row count %d, expected %d", decodedRows, expectedRows) + return 0, moerr.NewInternalErrorNoCtxf("python udf: result batch row count %d, expected %d", decodedRows, expectedRows) } if decoded.Schema().Field(0).Name != "result" { decoded.Release() - return 0, fmt.Errorf("python udf: result field has unexpected name %q", decoded.Schema().Field(0).Name) + return 0, moerr.NewInternalErrorNoCtxf("python udf: result field has unexpected name %q", decoded.Schema().Field(0).Name) } if err := returnDescriptor.ValidateField(decoded.Schema().Field(0)); err != nil { decoded.Release() @@ -1633,7 +1634,7 @@ func (g *Gateway) receiveResultBatch( } if limit := g.cfg.MaxInvocationResultBytes; limit > 0 && result.GetResultVector() != nil && int64(result.GetResultVector().Size()) > limit { decoded.Release() - return 0, fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF invocation result exceeds %d bytes", limit) + return 0, moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF invocation result exceeds %d bytes", limit) } decoded.Release() if err := g.action(ctx, client, "AcknowledgeResults", protocol.Control{Kind: "AcknowledgeResults", Tuple: tuple, AckSequence: control.Sequence}); err != nil { @@ -1645,40 +1646,40 @@ func (g *Gateway) receiveResultBatch( return int(expectedRows), nil } if len(data.DataBody) != 0 { - return 0, fmt.Errorf("python udf: control frame contains an Arrow body") + return 0, moerr.NewInternalErrorNoCtxf("python udf: control frame contains an Arrow body") } control, err := protocol.UnmarshalControl(data.AppMetadata) if err != nil { return 0, err } if control.Tuple != tuple { - return 0, fmt.Errorf("python udf: result tuple changed") + return 0, moerr.NewInternalErrorNoCtxf("python udf: result tuple changed") } switch control.Kind { case "ResultSchema": if *schemaFrame == nil || *schemaReady { - return 0, fmt.Errorf("python udf: invalid result schema metadata") + return 0, moerr.NewInternalErrorNoCtxf("python udf: invalid result schema metadata") } *schemaReady = true continue case "InputConsumed": if control.Sequence != sequenceNumber { - return 0, fmt.Errorf("python udf: input sequence %d was consumed while waiting for result %d", control.Sequence, sequenceNumber) + return 0, moerr.NewInternalErrorNoCtxf("python udf: input sequence %d was consumed while waiting for result %d", control.Sequence, sequenceNumber) } if control.ReleasedBatches != 1 || control.ReleasedBytes <= 0 || control.ReleasedBytes > g.cfg.MaxBatchBytes { - return 0, fmt.Errorf("python udf: input sequence %d released invalid bytes/batches (%d/%d)", sequenceNumber, control.ReleasedBytes, control.ReleasedBatches) + return 0, moerr.NewInternalErrorNoCtxf("python udf: input sequence %d released invalid bytes/batches (%d/%d)", sequenceNumber, control.ReleasedBytes, control.ReleasedBatches) } if inputConsumed { - return 0, fmt.Errorf("python udf: input sequence %d was consumed more than once", sequenceNumber) + return 0, moerr.NewInternalErrorNoCtxf("python udf: input sequence %d was consumed more than once", sequenceNumber) } inputConsumed = true continue case "Error": - return 0, fmt.Errorf("python udf: worker error: %s", control.Reason) + return 0, moerr.NewInternalErrorNoCtxf("python udf: worker error: %s", control.Reason) case "Finish": - return 0, fmt.Errorf("python udf: Finish arrived before result sequence %d", sequenceNumber) + return 0, moerr.NewInternalErrorNoCtxf("python udf: Finish arrived before result sequence %d", sequenceNumber) default: - return 0, fmt.Errorf("python udf: unexpected control %q", control.Kind) + return 0, moerr.NewInternalErrorNoCtxf("python udf: unexpected control %q", control.Kind) } } } @@ -1689,12 +1690,12 @@ func (g *Gateway) receiveResultBatch( // header could bypass the body-only limit used by the old result path. func freezeResultFrames(header, body []byte, maxBytes int64) (*protocol.OutputSnapshot, *protocol.OutputSnapshot, error) { if maxBytes <= 0 { - return nil, nil, fmt.Errorf("invalid Python UDF result batch limit") + return nil, nil, moerr.NewInternalErrorNoCtxf("invalid Python UDF result batch limit") } headerBytes := int64(len(header)) bodyBytes := int64(len(body)) if headerBytes > maxBytes || bodyBytes > maxBytes-headerBytes { - return nil, nil, fmt.Errorf("RESOURCE_EXHAUSTED: Arrow result batch exceeds %d bytes", maxBytes) + return nil, nil, moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Arrow result batch exceeds %d bytes", maxBytes) } headerSnapshot, err := protocol.FreezeOutput(header, maxBytes) if err != nil { @@ -1722,10 +1723,10 @@ type executionBudget struct { func validateInvocationBudget(budget executionBudget) error { if budget.rows < 0 { - return fmt.Errorf("python udf: invocation row count is negative") + return moerr.NewInternalErrorNoCtxf("python udf: invocation row count is negative") } if budget.maxRows > 0 && budget.rows > budget.maxRows { - return fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF invocation has %d rows, limit is %d", budget.rows, budget.maxRows) + return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF invocation has %d rows, limit is %d", budget.rows, budget.maxRows) } if budget.maxResultBytes <= 0 || budget.rows == 0 { return nil @@ -1736,11 +1737,11 @@ func validateInvocationBudget(budget executionBudget) error { // each validated append because their area size depends on user values. validityBytes := (budget.rows-1)/8 + 1 if validityBytes >= budget.maxResultBytes { - return fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF invocation result reservation exceeds %d bytes", budget.maxResultBytes) + return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF invocation result reservation exceeds %d bytes", budget.maxResultBytes) } perRow := int64(budget.returnType.TypeSize()) if perRow > 0 && budget.rows > (budget.maxResultBytes-validityBytes)/perRow { - return fmt.Errorf("RESOURCE_EXHAUSTED: Python UDF invocation result reservation exceeds %d bytes", budget.maxResultBytes) + return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF invocation result reservation exceeds %d bytes", budget.maxResultBytes) } return nil } @@ -1748,7 +1749,7 @@ func validateInvocationBudget(budget executionBudget) error { func validateResultSchemaMetadata(metadata []byte, tuple protocol.FencingTuple) error { control, err := protocol.UnmarshalControl(metadata) if err != nil || control.Tuple != tuple || control.Kind != "ResultSchema" { - return fmt.Errorf("python udf: invalid result schema metadata") + return moerr.NewInternalErrorNoCtxf("python udf: invalid result schema metadata") } return nil } @@ -1765,33 +1766,33 @@ func (g *Gateway) receiveFinish( data, err := stream.Recv() if err != nil { if err == io.EOF { - return fmt.Errorf("python udf: exchange ended before Finish") + return moerr.NewInternalErrorNoCtxf("python udf: exchange ended before Finish") } - return fmt.Errorf("python udf: receive Finish: %w", err) + return errutil.Wrapf(err, "python udf: receive Finish") } if data == nil || len(data.DataHeader) > 0 || len(data.DataBody) > 0 { - return fmt.Errorf("python udf: unexpected Arrow data while finishing") + return moerr.NewInternalErrorNoCtxf("python udf: unexpected Arrow data while finishing") } control, err := protocol.UnmarshalControl(data.AppMetadata) if err != nil { return err } if control.Tuple != tuple { - return fmt.Errorf("python udf: Finish tuple changed") + return moerr.NewInternalErrorNoCtxf("python udf: Finish tuple changed") } switch control.Kind { case "InputConsumed", "ResultSchema": - return fmt.Errorf("python udf: %s arrived after result stream was drained", control.Kind) + return moerr.NewInternalErrorNoCtxf("python udf: %s arrived after result stream was drained", control.Kind) case "Error": - return fmt.Errorf("python udf: worker error: %s", control.Reason) + return moerr.NewInternalErrorNoCtxf("python udf: worker error: %s", control.Reason) case "Finish": lastInput, lastResult, acked, inputEnded := sequence.State() if control.Status != statusOK || control.FinishID == "" || rows != expectedRows || !inputEnded || control.LastSequence != lastInput || lastResult != lastInput || acked != lastInput || !sequence.ReadyToFinish() { - return fmt.Errorf("python udf: invalid Finish status=%q rows=%d", control.Status, rows) + return moerr.NewInternalErrorNoCtxf("python udf: invalid Finish status=%q rows=%d", control.Status, rows) } if control.LastResultSequence != lastResult { - return fmt.Errorf("python udf: invalid Finish result sequence %d, expected %d", control.LastResultSequence, lastResult) + return moerr.NewInternalErrorNoCtxf("python udf: invalid Finish result sequence %d, expected %d", control.LastResultSequence, lastResult) } if err := g.acknowledgeFinish(ctx, client, "AcknowledgeFinish", protocol.Control{Kind: "AcknowledgeFinish", Tuple: tuple, FinishID: control.FinishID}); err != nil { return err @@ -1804,7 +1805,7 @@ func (g *Gateway) receiveFinish( // has returned and its cleanup owner has completed. return g.waitExchangeEOF(ctx, stream) default: - return fmt.Errorf("python udf: unexpected control %q", control.Kind) + return moerr.NewInternalErrorNoCtxf("python udf: unexpected control %q", control.Kind) } } } @@ -1816,10 +1817,10 @@ func (g *Gateway) waitExchangeEOF(ctx context.Context, stream flight.FlightServi return nil } if err != nil { - return fmt.Errorf("python udf: wait for exchange completion: %w", err) + return errutil.Wrapf(err, "python udf: wait for exchange completion") } if data == nil || len(data.DataHeader) != 0 || len(data.DataBody) != 0 || len(data.AppMetadata) != 0 { - return fmt.Errorf("python udf: exchange returned data after Finish ACK") + return moerr.NewInternalErrorNoCtxf("python udf: exchange returned data after Finish ACK") } } } @@ -1830,19 +1831,19 @@ func (g *Gateway) waitExchangeEOF(ctx context.Context, stream flight.FlightServi // between an accepted terminal result and a locally unconfirmed Finish. func (g *Gateway) acknowledgeFinish(ctx context.Context, client flight.FlightServiceClient, kind string, finish protocol.Control) error { if client == nil { - return fmt.Errorf("FINISH_UNCONFIRMED: finish ACK client is unavailable") + return moerr.NewInternalErrorNoCtxf("FINISH_UNCONFIRMED: finish ACK client is unavailable") } firstErr := g.action(ctx, client, kind, finish) if firstErr == nil { return nil } if ctx != nil && ctx.Err() != nil { - return fmt.Errorf("FINISH_UNCONFIRMED: finish ACK budget expired: %w", firstErr) + return errutil.Wrapf(firstErr, "FINISH_UNCONFIRMED: finish ACK budget expired") } if retryErr := g.action(ctx, client, kind, finish); retryErr == nil { return nil } else { - return fmt.Errorf("FINISH_UNCONFIRMED: finish ACK was not confirmed after idempotent retry: %v; retry: %w", firstErr, retryErr) + return errutil.Wrapf(retryErr, "FINISH_UNCONFIRMED: finish ACK was not confirmed after idempotent retry: %v; retry", firstErr) } } @@ -1851,7 +1852,7 @@ func validateInvocation(invocation *udf.Invocation) error { return err } if invocation.Source == "" { - return fmt.Errorf("python udf: handler and source are required") + return moerr.NewInternalErrorNoCtxf("python udf: handler and source are required") } // ArtifactResolver is an execution boundary, so the Gateway must enforce // the same immutable source contract even when a custom resolver does not @@ -1859,13 +1860,13 @@ func validateInvocation(invocation *udf.Invocation) error { // otherwise an oversized or invalid source can consume a large temporary // allocation and only fail at the Flight control-size boundary. if !utf8.ValidString(invocation.Source) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is not valid UTF-8") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is not valid UTF-8") } if int64(len([]byte(invocation.Source))) > DefaultMaxArtifactBytes { - return fmt.Errorf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", DefaultMaxArtifactBytes) + return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", DefaultMaxArtifactBytes) } if invocation.ArtifactDigest != udf.PythonInlineArtifactDigest(invocation.Handler, invocation.Source) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") } return nil } @@ -1877,80 +1878,80 @@ func validateInvocation(invocation *udf.Invocation) error { // be valid. func validateInvocationHeader(invocation *udf.Invocation) error { if invocation == nil { - return fmt.Errorf("python udf: nil invocation") + return moerr.NewInternalErrorNoCtxf("python udf: nil invocation") } if invocation.Language != udf.LanguagePython { - return fmt.Errorf("python udf: unsupported language %q", invocation.Language) + return moerr.NewInternalErrorNoCtxf("python udf: unsupported language %q", invocation.Language) } if invocation.Handler == "" { - return fmt.Errorf("python udf: handler is required") + return moerr.NewInternalErrorNoCtxf("python udf: handler is required") } if strings.Contains(invocation.Handler, ":") { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog") } if invocation.Length < 0 || len(invocation.Args) != len(invocation.Inputs) { - return fmt.Errorf("python udf: invalid input shape") + return moerr.NewInternalErrorNoCtxf("python udf: invalid input shape") } if invocation.Mode != ModeScalar && invocation.Mode != ModeVector { - return fmt.Errorf("python udf: unsupported mode %q", invocation.Mode) + return moerr.NewInternalErrorNoCtxf("python udf: unsupported mode %q", invocation.Mode) } if invocation.CallsiteID == "" || len(invocation.CallsiteID) > 256 || strings.ContainsAny(invocation.CallsiteID, "\r\n") { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no valid callsite id") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no valid callsite id") } if !invocation.MayError || invocation.SecurityMode != "INVOKER" || invocation.Leakproof { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invocation semantic contract is not supported") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invocation semantic contract is not supported") } if invocation.StatementContext == nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no statement context") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no statement context") } if err := invocation.StatementContext.Validate(); err != nil { return err } if invocation.SecurityFrame == nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no security frame") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no security frame") } if err := invocation.SecurityFrame.Validate(); err != nil { return err } if invocation.SecurityFrame.Mode != invocation.SecurityMode { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invocation security mode does not match its frame") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invocation security mode does not match its frame") } if invocation.NullPolicy != NullCallHandler && invocation.NullPolicy != NullReturnNull { - return fmt.Errorf("python udf: unsupported NULL policy %q", invocation.NullPolicy) + return moerr.NewInternalErrorNoCtxf("python udf: unsupported NULL policy %q", invocation.NullPolicy) } if invocation.ABIContract != udf.PythonABIContract || invocation.AdapterVersion != udf.PythonAdapterVersion { - return fmt.Errorf("python udf: unsupported Python ABI contract %q/%q", invocation.ABIContract, invocation.AdapterVersion) + return moerr.NewInternalErrorNoCtxf("python udf: unsupported Python ABI contract %q/%q", invocation.ABIContract, invocation.AdapterVersion) } if invocation.SDKVersion != udf.PythonSDKVersion { - return fmt.Errorf("python udf: unsupported Python SDK %q", invocation.SDKVersion) + return moerr.NewInternalErrorNoCtxf("python udf: unsupported Python SDK %q", invocation.SDKVersion) } if invocation.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python definition schema %d", invocation.DefinitionSchemaVersion) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python definition schema %d", invocation.DefinitionSchemaVersion) } if !udf.IsSHA256Digest(invocation.ArtifactDigest) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") } environmentDigest, err := udf.PythonEnvironmentDigest() if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest is unavailable: %w", err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python environment digest is unavailable") } if invocation.EnvironmentDigest != environmentDigest { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the current worker contract") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the current worker contract") } if !udf.IsSHA256Digest(invocation.DefinitionFingerprint) { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint is invalid") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint is invalid") } args := make([]TypeDescriptor, len(invocation.Args)) for index, typ := range invocation.Args { descriptor, err := NewTypeDescriptor(typ) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python argument descriptor %d: %w", index, err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python argument descriptor %d", index) } args[index] = descriptor } returnDescriptor, err := NewTypeDescriptor(invocation.ReturnType) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python return descriptor: %w", err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python return descriptor") } if err := validateInvocationInputs(invocation, args); err != nil { return err @@ -1963,23 +1964,23 @@ func validateInvocationHeader(invocation *udf.Invocation) error { args, returnDescriptor, ) if err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint cannot be computed: %w", err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint cannot be computed") } if invocation.DefinitionFingerprint != expectedFingerprint { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition") } if err := invocation.FunctionRef.Validate(); err != nil { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: %w", err) + return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION") } if invocation.FunctionRef.AccountID != invocation.Tuple.AccountID { - return fmt.Errorf("python udf: FunctionRef account does not match the fencing tuple") + return moerr.NewInternalErrorNoCtxf("python udf: FunctionRef account does not match the fencing tuple") } return invocation.Tuple.Validate() } func validateInvocationInputs(invocation *udf.Invocation, args []TypeDescriptor) error { if invocation == nil || len(invocation.Inputs) != len(args) { - return fmt.Errorf("python udf: invalid input shape") + return moerr.NewInternalErrorNoCtxf("python udf: invalid input shape") } // An empty physical selection has no input backing to inspect. Nil inputs // are valid in this case, but a vector supplied by a caller still has to @@ -1991,33 +1992,20 @@ func validateInvocationInputs(invocation *udf.Invocation, args []TypeDescriptor) continue } if input.GetType() == nil || !input.GetType().Eq(invocation.Args[index]) { - return fmt.Errorf( - "python udf: input column %d type does not match the frozen argument type", - index, - ) + return moerr.NewInternalErrorNoCtxf("python udf: input column %d type does not match the frozen argument type", index) } } return nil } for index, input := range invocation.Inputs { if input == nil || input.GetType() == nil || input.Length() == 0 { - return fmt.Errorf("python udf: input column %d has no backing vector", index) + return moerr.NewInternalErrorNoCtxf("python udf: input column %d has no backing vector", index) } if !input.GetType().Eq(invocation.Args[index]) { - return fmt.Errorf( - "python udf: input column %d type %s does not match the frozen argument type %s", - index, - input.GetType().DescString(), - invocation.Args[index].DescString(), - ) + return moerr.NewInternalErrorNoCtxf("python udf: input column %d type %s does not match the frozen argument type %s", index, input.GetType().DescString(), invocation.Args[index].DescString()) } if !input.IsConst() && input.Length() < invocation.Length { - return fmt.Errorf( - "python udf: input column %d has %d rows, expected at least %d", - index, - input.Length(), - invocation.Length, - ) + return moerr.NewInternalErrorNoCtxf("python udf: input column %d has %d rows, expected at least %d", index, input.Length(), invocation.Length) } } return nil @@ -2032,14 +2020,14 @@ func (g *Gateway) action(ctx context.Context, client flight.FlightServiceClient, defer cancel() stream, err := client.DoAction(actionCtx, &flight.Action{Type: kind, Body: body}) if err != nil { - return fmt.Errorf("python udf: %s: %w", kind, err) + return errutil.Wrapf(err, "python udf: %s", kind) } result, err := stream.Recv() if err != nil { return err } if result == nil { - return fmt.Errorf("python udf: empty %s response", kind) + return moerr.NewInternalErrorNoCtxf("python udf: empty %s response", kind) } ack, err := protocol.UnmarshalControl(result.Body) if err != nil { @@ -2049,11 +2037,11 @@ func (g *Gateway) action(ctx context.Context, client flight.FlightServiceClient, return err } if ack.Status != statusOK { - return fmt.Errorf("python udf: %s rejected: %s", kind, ack.Reason) + return moerr.NewInternalErrorNoCtxf("python udf: %s rejected: %s", kind, ack.Reason) } if _, err := stream.Recv(); err != io.EOF { if err == nil { - return fmt.Errorf("python udf: %s returned multiple results", kind) + return moerr.NewInternalErrorNoCtxf("python udf: %s returned multiple results", kind) } return err } @@ -2062,19 +2050,19 @@ func (g *Gateway) action(ctx context.Context, client flight.FlightServiceClient, func validateActionAck(kind string, request, ack protocol.Control) error { if ack.Tuple != request.Tuple || ack.Kind != "Ack" { - return fmt.Errorf("python udf: %s returned an invalid ACK", kind) + return moerr.NewInternalErrorNoCtxf("python udf: %s returned an invalid ACK", kind) } switch kind { case "AcknowledgeResults": if ack.AckSequence != request.AckSequence { - return fmt.Errorf("python udf: %s ACK sequence %d, expected %d", kind, ack.AckSequence, request.AckSequence) + return moerr.NewInternalErrorNoCtxf("python udf: %s ACK sequence %d, expected %d", kind, ack.AckSequence, request.AckSequence) } case "AcknowledgeFinish": if ack.FinishID != request.FinishID { - return fmt.Errorf("python udf: %s ACK finish ID does not match the request", kind) + return moerr.NewInternalErrorNoCtxf("python udf: %s ACK finish ID does not match the request", kind) } default: - return fmt.Errorf("python udf: unsupported action %q", kind) + return moerr.NewInternalErrorNoCtxf("python udf: unsupported action %q", kind) } return nil } diff --git a/pkg/udf/python/supervisor.go b/pkg/udf/python/supervisor.go index af3de0793fa10..ed09bc63dc2b9 100644 --- a/pkg/udf/python/supervisor.go +++ b/pkg/udf/python/supervisor.go @@ -16,7 +16,8 @@ package python import ( "errors" - "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "os" "os/exec" "path/filepath" @@ -25,7 +26,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/logutil" ) -var errSupervisorClosing = errors.New("python udf worker is shutting down") +var errSupervisorClosing = moerr.NewInternalErrorNoCtx("python udf worker is shutting down") type Supervisor struct { cfg Config @@ -144,7 +145,7 @@ func (s *Supervisor) Close() error { var closeErr error if cmd != nil { if err := killSupervisorProcess(cmd); err != nil && !errors.Is(err, os.ErrProcessDone) { - closeErr = fmt.Errorf("stop Python UDF worker: %w", err) + closeErr = errutil.Wrapf(err, "stop Python UDF worker") } } if done != nil { diff --git a/pkg/udf/runtime.go b/pkg/udf/runtime.go index 72b3881f83bcc..16bed1eaef382 100644 --- a/pkg/udf/runtime.go +++ b/pkg/udf/runtime.go @@ -22,7 +22,7 @@ import ( "context" "encoding/json" "errors" - "fmt" + "github.com/matrixorigin/matrixone/pkg/util/errutil" "sort" "strconv" "strings" @@ -91,41 +91,41 @@ type StatementContext struct { func (c StatementContext) Validate() error { if c.ContractVersion != StatementContextContractVersion { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported statement context contract %d", c.ContractVersion) + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported statement context contract %d", c.ContractVersion) } if c.StatementTimestampUTC < minStatementTimestampUTC || c.StatementTimestampUTC > maxStatementTimestampUTC { - return fmt.Errorf("python udf: statement timestamp is outside the Python datetime range") + return moerr.NewInternalErrorNoCtxf("python udf: statement timestamp is outside the Python datetime range") } if c.CurrentUser == "" || c.ConnectionCollation == "" { - return fmt.Errorf("python udf: statement context has no authenticated user or collation") + return moerr.NewInternalErrorNoCtxf("python udf: statement context has no authenticated user or collation") } if c.TimezoneKind == "IANA" { if c.TimezoneName == "" || c.TimezoneDatabaseVersion == "" || c.TimezoneOffsetMinutes != 0 { - return fmt.Errorf("python udf: IANA statement timezone is incomplete") + return moerr.NewInternalErrorNoCtxf("python udf: IANA statement timezone is incomplete") } if _, err := time.LoadLocation(c.TimezoneName); err != nil { - return fmt.Errorf("python udf: IANA statement timezone is not present in the local tzdb: %w", err) + return errutil.Wrapf(err, "python udf: IANA statement timezone is not present in the local tzdb") } } else if c.TimezoneKind == "FIXED_OFFSET" { if c.TimezoneName != "" || c.TimezoneDatabaseVersion != "" || c.TimezoneOffsetMinutes < -839 || c.TimezoneOffsetMinutes > 840 { - return fmt.Errorf("python udf: fixed statement timezone is invalid") + return moerr.NewInternalErrorNoCtxf("python udf: fixed statement timezone is invalid") } } else { - return fmt.Errorf("python udf: unsupported statement timezone kind %q", c.TimezoneKind) + return moerr.NewInternalErrorNoCtxf("python udf: unsupported statement timezone kind %q", c.TimezoneKind) } mode := append([]string(nil), c.SQLMode...) sort.Strings(mode) for i := range mode { if mode[i] == "" || (i > 0 && mode[i] == mode[i-1]) { - return fmt.Errorf("python udf: statement sql_mode is not canonical") + return moerr.NewInternalErrorNoCtxf("python udf: statement sql_mode is not canonical") } } if len(mode) != len(c.SQLMode) { - return fmt.Errorf("python udf: statement sql_mode is not canonical") + return moerr.NewInternalErrorNoCtxf("python udf: statement sql_mode is not canonical") } for i := range mode { if mode[i] != c.SQLMode[i] { - return fmt.Errorf("python udf: statement sql_mode is not sorted") + return moerr.NewInternalErrorNoCtxf("python udf: statement sql_mode is not sorted") } } return nil @@ -157,12 +157,12 @@ func StatementContextFromMap(values map[string]string) (*StatementContext, error } timestamp, err := strconv.ParseInt(values["statement_timestamp_utc"], 10, 64) if err != nil { - return nil, fmt.Errorf("python udf: invalid statement timestamp: %w", err) + return nil, errutil.Wrapf(err, "python udf: invalid statement timestamp") } mode := make([]string, 0) if raw := values["sql_mode"]; raw != "" { if err := json.Unmarshal([]byte(raw), &mode); err != nil { - return nil, fmt.Errorf("python udf: invalid statement sql_mode: %w", err) + return nil, errutil.Wrapf(err, "python udf: invalid statement sql_mode") } // The wire contract is a JSON array, including when it is empty. A // JSON null decodes successfully into a nil Go slice, but would be @@ -170,7 +170,7 @@ func StatementContextFromMap(values map[string]string) (*StatementContext, error // Reject it at the trusted CN adapter instead of carrying a malformed // snapshot into the Flight request. if mode == nil { - return nil, fmt.Errorf("python udf: invalid statement sql_mode: expected a JSON array") + return nil, moerr.NewInternalErrorNoCtxf("python udf: invalid statement sql_mode: expected a JSON array") } } context := &StatementContext{ @@ -188,7 +188,7 @@ func StatementContextFromMap(values map[string]string) (*StatementContext, error if raw := values["session_timezone_offset_minutes"]; raw != "" { offset, parseErr := strconv.ParseInt(raw, 10, 32) if parseErr != nil { - return nil, fmt.Errorf("python udf: invalid fixed timezone offset: %w", parseErr) + return nil, errutil.Wrapf(parseErr, "python udf: invalid fixed timezone offset") } context.TimezoneOffsetMinutes = int32(offset) } @@ -213,10 +213,10 @@ type SecurityFrame struct { func (f SecurityFrame) Validate() error { if f.ContractVersion != SecurityFrameContractVersion || f.Mode != "INVOKER" { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python security frame") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python security frame") } if f.InvokerUserID != f.EffectiveUserID || f.InvokerRoleID != f.EffectiveRoleID { - return fmt.Errorf("UNSUPPORTED_ROUTINE_VERSION: Python invoker security frame changed effective principal") + return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invoker security frame changed effective principal") } return nil } diff --git a/pkg/udf/timezone.go b/pkg/udf/timezone.go index 2995f5ca79759..cafda4adef42f 100644 --- a/pkg/udf/timezone.go +++ b/pkg/udf/timezone.go @@ -16,7 +16,7 @@ package udf import ( "bufio" - "fmt" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "os" "strings" ) @@ -52,5 +52,5 @@ func TimezoneDatabaseVersion() (string, error) { } } } - return "", fmt.Errorf("python udf: IANA timezone database version is unavailable") + return "", moerr.NewInternalErrorNoCtxf("python udf: IANA timezone database version is unavailable") } diff --git a/pkg/util/errutil/errors.go b/pkg/util/errutil/errors.go index 5805b6918fe13..5106c0d03ecec 100644 --- a/pkg/util/errutil/errors.go +++ b/pkg/util/errutil/errors.go @@ -17,6 +17,7 @@ package errutil import ( "context" "errors" + "fmt" "sync/atomic" pkgErr "github.com/pkg/errors" @@ -42,6 +43,31 @@ func Wrapf(err error, format string, args ...any) error { return pkgErr.Wrapf(err, format, args...) } +type causeFirstError struct { + cause error + message string +} + +func (e *causeFirstError) Error() string { + if e.message == "" { + return e.cause.Error() + } + return e.cause.Error() + ": " + e.message +} + +func (e *causeFirstError) Unwrap() error { + return e.cause +} + +// WrapfCauseFirst preserves cause-first wrapped-error message order while +// retaining errors.Is/errors.As identity. +func WrapfCauseFirst(err error, format string, args ...any) error { + if err == nil { + return nil + } + return &causeFirstError{cause: err, message: fmt.Sprintf(format, args...)} +} + // WalkDeep does a depth-first traversal of all errors. // The visitor function can return true to end the traversal early, otherwise false. func WalkDeep(err error, visitor func(err error) bool) bool { diff --git a/pkg/util/errutil/errors_test.go b/pkg/util/errutil/errors_test.go index a36f6cb3a2f6a..21613cc7b182a 100644 --- a/pkg/util/errutil/errors_test.go +++ b/pkg/util/errutil/errors_test.go @@ -181,6 +181,13 @@ func TestWrapf(t *testing.T) { } } +func TestWrapfCauseFirst(t *testing.T) { + cause := context.Canceled + err := WrapfCauseFirst(cause, "detail %d", 7) + require.Equal(t, "context canceled: detail 7", err.Error()) + require.ErrorIs(t, err, cause) +} + func Test_noopReportError(t *testing.T) { type args struct { in0 context.Context From aa18ff1bd470797603f55b43ae3f864cab9b58dc Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 20 Sep 2026 19:46:14 +0800 Subject: [PATCH 191/241] fix(ci): align Python UDF runtime dependencies --- etc/launch-tae-compose/compose.yaml | 3 + optools/images/Dockerfile.prebuilt | 7 +++ optools/run_ut.sh | 61 +++++++++++++++++++ .../cases/dml/select/sp_table.result | 1 + .../cases/dml/show/database_statistics.result | 4 +- test/distributed/cases/dml/show/show.result | 1 + .../cases/metadata/information_schema.result | 1 + .../zz_accesscontrol/create_account.result | 1 + 8 files changed, 77 insertions(+), 2 deletions(-) diff --git a/etc/launch-tae-compose/compose.yaml b/etc/launch-tae-compose/compose.yaml index ea14e1051f7d5..6cea8d40485b2 100644 --- a/etc/launch-tae-compose/compose.yaml +++ b/etc/launch-tae-compose/compose.yaml @@ -30,6 +30,9 @@ x-mo-common: &mo-common x-python-udf-worker: &python-udf-worker image: matrixorigin/mo-python-udf-worker:latest + # The image is built by python-udf-worker-image in this Compose project. + # Do not race that local build with an unauthenticated registry pull. + pull_policy: never restart: on-failure profiles: - launch diff --git a/optools/images/Dockerfile.prebuilt b/optools/images/Dockerfile.prebuilt index f7d706d8e086c..ba424262a2458 100644 --- a/optools/images/Dockerfile.prebuilt +++ b/optools/images/Dockerfile.prebuilt @@ -13,6 +13,13 @@ ARG RUNTIME_IMAGE=matrixorigin/ubuntu:22.04 FROM ${RUNTIME_IMAGE} +# Keep the prebuilt runtime image's timezone database in sync with the +# Python UDF worker image. The Go and Python capability contracts compare the +# tzdata release, so omitting it makes the CN advertise an empty version. +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata \ + && rm -rf /var/lib/apt/lists/* + COPY --chmod=0755 mo-service /mo-service COPY etc /etc COPY lib/*.so /usr/local/lib/ diff --git a/optools/run_ut.sh b/optools/run_ut.sh index f9749d4a8a483..b43528a4d0a94 100755 --- a/optools/run_ut.sh +++ b/optools/run_ut.sh @@ -160,6 +160,58 @@ CGO_CFLAGS="-I${BUILD_WKSP}/cgo -I${THIRDPARTIES_INSTALL_DIR}/include" CGO_LDFLAGS="-Wl,-rpath,${THIRDPARTIES_INSTALL_DIR}/lib:${BUILD_WKSP}/cgo -L${THIRDPARTIES_INSTALL_DIR}/lib -L${BUILD_WKSP}/cgo -lmo -lusearch_c -lm" LD_LIBRARY_PATH="${THIRDPARTIES_INSTALL_DIR}/lib:${BUILD_WKSP}/cgo" +PYTHON_UDF_DEPS_DIR="" + +function cleanup_python_udf_dependencies(){ + if [[ -n "${PYTHON_UDF_DEPS_DIR}" ]]; then + rm -rf -- "${PYTHON_UDF_DEPS_DIR}" + PYTHON_UDF_DEPS_DIR="" + fi +} + +# UT starts the real Python UDF worker from the host's python3 executable. +# Keep the fallback dependency installation outside the worktree and clean it +# up even when the run exits through one of the script's signal handlers. +trap cleanup_python_udf_dependencies EXIT + +function prepare_python_udf_dependencies(){ + local python3_bin + python3_bin=$(command -v python3 || true) + if [[ -z "${python3_bin}" ]]; then + logger "ERR" "python3 is required for Python UDF UTs" + return 1 + fi + + if "${python3_bin}" -c 'import pyarrow' >/dev/null 2>&1; then + logger "INF" "Python UDF UT dependencies are already available" + return 0 + fi + + if ! "${python3_bin}" -m pip --version >/dev/null 2>&1; then + logger "ERR" "python3 cannot import pyarrow and its pip module is unavailable" + return 1 + fi + + PYTHON_UDF_DEPS_DIR=$(mktemp -d "${TMPDIR:-/tmp}/matrixone-ut-python.XXXXXX") || { + logger "ERR" "failed to create the temporary Python UDF dependency directory" + return 1 + } + if ! "${python3_bin}" -m pip install \ + --isolated --disable-pip-version-check --no-input --no-cache-dir \ + --only-binary=:all: --target "${PYTHON_UDF_DEPS_DIR}" \ + -r "${BUILD_WKSP}/pkg/udf/python/worker/requirements.txt"; then + logger "ERR" "failed to install Python UDF UT dependencies" + return 1 + fi + + export PYTHONPATH="${PYTHON_UDF_DEPS_DIR}${PYTHONPATH:+:${PYTHONPATH}}" + if ! "${python3_bin}" -c 'import pyarrow' >/dev/null 2>&1; then + logger "ERR" "Python UDF dependency bootstrap completed but pyarrow is still unavailable" + return 1 + fi + logger "INF" "Python UDF UT dependencies installed in ${PYTHON_UDF_DEPS_DIR}" +} + if [[ -n "${MO_CL_CUDA:-}" ]] ; then if [[ ${MO_CL_CUDA} == "1" ]] ; then . "${BUILD_WKSP}/cgo/mo-gpu-env" || exit 1 @@ -2752,6 +2804,15 @@ function run_tests(){ fi mark_ut_stage "routing" "validate shard and package partition" finish 0 + mark_ut_stage "prepare" "prepare Python UDF dependencies" start + prepare_python_udf_dependencies + local python_udf_dependency_status=$? + mark_ut_stage "prepare" "prepare Python UDF dependencies" finish "${python_udf_dependency_status}" + if (( python_udf_dependency_status != 0 )); then + UT_TEST_STATUS=1 + return 0 + fi + mark_ut_stage "prepare" "clean go test cache" start logger "INF" "Clean go test cache" local testcache_status=0 diff --git a/test/distributed/cases/dml/select/sp_table.result b/test/distributed/cases/dml/select/sp_table.result index a2f5658739bff..f88cda16115e4 100644 --- a/test/distributed/cases/dml/select/sp_table.result +++ b/test/distributed/cases/dml/select/sp_table.result @@ -20,6 +20,7 @@ mo_database_defaults r mo_feature_limit r mo_feature_registry r mo_foreign_keys r +mo_function_revisions r mo_iceberg_catalogs r mo_iceberg_maintenance_jobs r mo_iceberg_orphan_files r diff --git a/test/distributed/cases/dml/show/database_statistics.result b/test/distributed/cases/dml/show/database_statistics.result index 75a36f6ce6cc3..b7fb6d1808e84 100644 --- a/test/distributed/cases/dml/show/database_statistics.result +++ b/test/distributed/cases/dml/show/database_statistics.result @@ -93,7 +93,7 @@ show column_number from mo_role_privs; 10 show column_number from mo_user_defined_function; ➤ Number of columns in mo_user_defined_function[-5,64,0] 𝄀 -19 +25 show column_number from mo_tables; ➤ Number of columns in mo_tables[-5,64,0] 𝄀 19 @@ -430,7 +430,7 @@ show column_number from mo_role_privs; 10 show column_number from mo_user_defined_function; ➤ Number of columns in mo_user_defined_function[-5,64,0] 𝄀 -19 +25 show column_number from mo_tables; ➤ Number of columns in mo_tables[-5,64,0] 𝄀 19 diff --git a/test/distributed/cases/dml/show/show.result b/test/distributed/cases/dml/show/show.result index 5eac71c91c350..ddf75f6041857 100644 --- a/test/distributed/cases/dml/show/show.result +++ b/test/distributed/cases/dml/show/show.result @@ -273,6 +273,7 @@ mo_database_defaults 𝄀 mo_feature_limit 𝄀 mo_feature_registry 𝄀 mo_foreign_keys 𝄀 +mo_function_revisions 𝄀 mo_iceberg_catalogs 𝄀 mo_iceberg_maintenance_jobs 𝄀 mo_iceberg_orphan_files 𝄀 diff --git a/test/distributed/cases/metadata/information_schema.result b/test/distributed/cases/metadata/information_schema.result index 13b2259e23d0d..921baae3872ab 100644 --- a/test/distributed/cases/metadata/information_schema.result +++ b/test/distributed/cases/metadata/information_schema.result @@ -39,6 +39,7 @@ def mo_catalog mo_database_defaults BASE TABLE Tae def mo_catalog mo_feature_limit BASE TABLE Tae def mo_catalog mo_feature_registry BASE TABLE Tae def mo_catalog mo_foreign_keys BASE TABLE Tae +def mo_catalog mo_function_revisions BASE TABLE Tae def mo_catalog mo_iceberg_catalogs BASE TABLE Tae def mo_catalog mo_iceberg_maintenance_jobs BASE TABLE Tae def mo_catalog mo_iceberg_orphan_files BASE TABLE Tae diff --git a/test/distributed/cases/zz_accesscontrol/create_account.result b/test/distributed/cases/zz_accesscontrol/create_account.result index ed41c82811128..d8ca674fdb6df 100644 --- a/test/distributed/cases/zz_accesscontrol/create_account.result +++ b/test/distributed/cases/zz_accesscontrol/create_account.result @@ -170,6 +170,7 @@ mo_configurations mo_database mo_database_defaults mo_foreign_keys +mo_function_revisions mo_iceberg_catalogs mo_iceberg_maintenance_jobs mo_iceberg_orphan_files From 98e414d0fe33ab1f8831c438a36a400ec0de5766 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 20 Sep 2026 19:54:27 +0800 Subject: [PATCH 192/241] fix(udf): integrate concurrent CI contract repair --- .golangci.yml | 21 +- etc/launch-with-python-udf-worker/cn.toml | 13 + optools/images/Dockerfile.ci | 7 + optools/images/Dockerfile.prebuilt | 6 +- pkg/cnservice/python_runtime.go | 9 +- pkg/frontend/authenticate.go | 6 +- pkg/frontend/compiler_context.go | 34 +-- pkg/frontend/routine_error_contract_test.go | 41 +++ pkg/frontend/routine_namespace.go | 9 +- pkg/frontend/routine_plan_validation.go | 45 +-- pkg/frontend/snapshot_catalog_restore.go | 60 ++-- pkg/iceberg/api/import_boundary_test.go | 27 +- pkg/sql/colexec/external_routine_eval.go | 91 ++++--- pkg/sql/plan/function/python_udf.go | 36 +-- pkg/sql/plan/function/udf.go | 69 ++--- pkg/sql/plan/routine_dependency.go | 13 +- pkg/udf/protocol/protocol.go | 37 ++- pkg/udf/python/arrow.go | 163 +++++------ pkg/udf/python/artifact.go | 36 +-- pkg/udf/python/definition.go | 5 +- pkg/udf/python/gateway.go | 257 +++++++++--------- pkg/udf/python/gateway_integration_test.go | 17 +- pkg/udf/python/supervisor.go | 7 +- pkg/udf/runtime.go | 28 +- pkg/udf/timezone.go | 5 +- pkg/udf/udferr/errors.go | 33 +++ pkg/udf/udferr/errors_test.go | 35 +++ pkg/util/errutil/errors_test.go | 15 +- .../clone_sys_db_table_to_new_db_table.result | 2 + .../cases/mo_cloud/mo_cloud.result | 1 + .../cluster/restore_cluster_table.result | 14 +- .../cluster/restore_cluster_table.sql | 6 +- ...ster_level_snapshot_restore_cluster.result | 14 +- ...cluster_level_snapshot_restore_cluster.sql | 6 +- ...shot_restore_system_table_to_nonsys.result | 32 +-- ...napshot_restore_system_table_to_nonsys.sql | 12 +- ...restore_system_table_to_sys_account.result | 32 +-- ...ot_restore_system_table_to_sys_account.sql | 10 +- ...tore_system_table_to_nonsys_account.result | 32 +-- ...restore_system_table_to_nonsys_account.sql | 10 +- ...e_system_table_to_newnonsys_account.result | 32 +-- ...tore_system_table_to_newnonsys_account.sql | 10 +- ...tore_system_table_to_nonsys_account.result | 32 +-- ...restore_system_table_to_nonsys_account.sql | 12 +- ...restore_system_table_to_sys_account.result | 32 +-- ...ys_restore_system_table_to_sys_account.sql | 10 +- .../privilege/create_user_default_role.result | 1 + test/distributed/cases/udf_python/README.md | 16 +- 48 files changed, 825 insertions(+), 616 deletions(-) create mode 100644 pkg/frontend/routine_error_contract_test.go create mode 100644 pkg/udf/udferr/errors.go create mode 100644 pkg/udf/udferr/errors_test.go diff --git a/.golangci.yml b/.golangci.yml index 1d38a9fb11978..b8778e6ab54d9 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -35,20 +35,27 @@ linters: - $all - '!$test' - '!pkg/iceberg/adapter/iceberggo/**/*.go' - # Arrow IPC is isolated to the ingestion bridge and its external - # scan reader. Keep the dependency out of all other production - # packages, including the Iceberg-facing layers. + deny: + - pkg: github.com/apache/iceberg-go + desc: Iceberg dependency must stay behind pkg/iceberg/adapter/iceberggo + arrow-boundary: + list-mode: lax + files: + - $all + - '!$test' + - '!pkg/iceberg/adapter/iceberggo/**/*.go' + # Arrow belongs to the ingestion and external UDF boundaries. + # These owners do not also receive permission to import Iceberg. - '!**/pkg/container/arrowbridge/*.go' - '!**/pkg/sql/colexec/external/arrowio/*.go' - '!**/pkg/sql/colexec/external/reader_arrow.go' - '!**/pkg/sql/compile/compile.go' + - '!**/pkg/udf/python/*.go' deny: - - pkg: github.com/apache/iceberg-go - desc: Iceberg dependency must stay behind pkg/iceberg/adapter/iceberggo - pkg: github.com/apache/arrow-go - desc: Arrow dependency must not leak outside the Iceberg adapter + desc: Arrow dependency must stay behind an approved Arrow owner - pkg: github.com/apache/arrow/go - desc: Arrow dependency must not leak outside the Iceberg adapter + desc: Arrow dependency must stay behind an approved Arrow owner govet: disable: - fieldalignment diff --git a/etc/launch-with-python-udf-worker/cn.toml b/etc/launch-with-python-udf-worker/cn.toml index 76ae8790bf7b5..5cd29947a566a 100644 --- a/etc/launch-with-python-udf-worker/cn.toml +++ b/etc/launch-with-python-udf-worker/cn.toml @@ -1,6 +1,19 @@ service-type = "CN" data-dir = "./mo-data" +# Opt into the checksum-free DISK-V2 backend. The cluster-wide default remains +# DISK (CRC-framed) for backward compatibility with existing data dirs; this +# config explicitly selects DISK-V2 for a fresh deployment. +[[fileservice]] +name = "LOCAL" +backend = "DISK-V2" +data-dir = "./mo-data/local2" + +[[fileservice]] +name = "SHARED" +backend = "DISK-V2" +data-dir = "./mo-data/shared2" + [log] level = "info" diff --git a/optools/images/Dockerfile.ci b/optools/images/Dockerfile.ci index ea62c6f7c425b..148b39cfb372a 100644 --- a/optools/images/Dockerfile.ci +++ b/optools/images/Dockerfile.ci @@ -72,6 +72,13 @@ COPY --from=builder /go/pkg/mod /go/pkg/mod FROM ${RUNTIME_IMAGE} +# Python UDF admission compares the system IANA database with the worker. +# Keep every runtime assembly path aligned with optools/images/Dockerfile +# and pkg/udf/python/worker/Dockerfile, including shared-build artifacts. +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata \ + && rm -rf /var/lib/apt/lists/* + COPY --from=builder /go/src/github.com/matrixorigin/matrixone/mo-service /mo-service COPY --from=builder /go/src/github.com/matrixorigin/matrixone/etc /etc COPY --from=builder /go/src/github.com/matrixorigin/matrixone/thirdparties/install/lib/*.so /usr/local/lib diff --git a/optools/images/Dockerfile.prebuilt b/optools/images/Dockerfile.prebuilt index ba424262a2458..dd876f57243e9 100644 --- a/optools/images/Dockerfile.prebuilt +++ b/optools/images/Dockerfile.prebuilt @@ -13,9 +13,9 @@ ARG RUNTIME_IMAGE=matrixorigin/ubuntu:22.04 FROM ${RUNTIME_IMAGE} -# Keep the prebuilt runtime image's timezone database in sync with the -# Python UDF worker image. The Go and Python capability contracts compare the -# tzdata release, so omitting it makes the CN advertise an empty version. +# Python UDF admission compares the system IANA database with the worker. +# Keep every runtime assembly path aligned with optools/images/Dockerfile +# and pkg/udf/python/worker/Dockerfile, including shared-build artifacts. RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends tzdata \ && rm -rf /var/lib/apt/lists/* diff --git a/pkg/cnservice/python_runtime.go b/pkg/cnservice/python_runtime.go index 6487d4a863a67..9adc8ccd83c35 100644 --- a/pkg/cnservice/python_runtime.go +++ b/pkg/cnservice/python_runtime.go @@ -16,7 +16,8 @@ package cnservice import ( "context" - "github.com/matrixorigin/matrixone/pkg/common/moerr" + + "github.com/matrixorigin/matrixone/pkg/udf/udferr" "github.com/matrixorigin/matrixone/pkg/util/errutil" "go.uber.org/zap" @@ -73,7 +74,7 @@ func (r *unavailablePythonRuntime) Language() string { return udf.LanguagePython func (r *unavailablePythonRuntime) unavailableError() error { if r == nil || r.cause == nil { - return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime initialization failed") + return udferr.Newf("RESOURCE_UNAVAILABLE: Python UDF runtime initialization failed") } return errutil.Wrapf(r.cause, "RESOURCE_UNAVAILABLE: Python UDF runtime initialization failed") } @@ -84,7 +85,7 @@ func (r *unavailablePythonRuntime) Execute(context.Context, *udf.Invocation, vec func (r *unavailablePythonRuntime) CheckLanguageReady(ctx context.Context, language string) error { if language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported readiness language %q", language) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: unsupported readiness language %q", language) } if ctx != nil { select { @@ -98,7 +99,7 @@ func (r *unavailablePythonRuntime) CheckLanguageReady(ctx context.Context, langu func (r *unavailablePythonRuntime) ValidateDefinition(ctx context.Context, definition *udf.RoutineDefinition) error { if definition == nil || definition.Language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: invalid Python definition") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: invalid Python definition") } return r.CheckLanguageReady(ctx, udf.LanguagePython) } diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index 0399f5442c78e..e598743bfa217 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -32,6 +32,8 @@ import ( "sync/atomic" "time" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/tidwall/btree" "golang.org/x/sync/errgroup" @@ -12868,10 +12870,6 @@ func activateFunctionRevision(ctx context.Context, bh BackgroundExec, functionID )) } -func activatePythonRevision(ctx context.Context, bh BackgroundExec, functionID int64, revision, namespace uint64) error { - return activateFunctionRevision(ctx, bh, functionID, revision, namespace) -} - // storedProcedureDefinition is the procedure metadata kept outside mo_tables. // Callers control the transaction that persists it. type storedProcedureDefinition struct { diff --git a/pkg/frontend/compiler_context.go b/pkg/frontend/compiler_context.go index 9d8d0bda5a4cb..82fa672334591 100644 --- a/pkg/frontend/compiler_context.go +++ b/pkg/frontend/compiler_context.go @@ -20,13 +20,15 @@ import ( "encoding/json" "errors" "fmt" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "slices" "strconv" "strings" "sync" "time" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "go.uber.org/zap" "github.com/matrixorigin/matrixone/pkg/catalog" @@ -944,7 +946,7 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex return nil, err } if len(erArray) > 1 || (len(erArray) == 1 && erArray[0] == nil) { - return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: UDF %s lookup returned %d result sets, expected one or an empty candidate result", name, len(erArray)) + return nil, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: UDF %s lookup returned %d result sets, expected one or an empty candidate result", name, len(erArray)) } if execResultArrayHasData(erArray) { @@ -1113,7 +1115,7 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex if strings.EqualFold(matchedList[0].Udf.Language, string(tree.PYTHON)) { matchedList[0].Udf.ArgsType = function.PythonUdfArgTypeCast(fromList, matchedList[0].Udf.GetArgsType()) if len(matchedList[0].Udf.ArgsType) != len(fromList) { - return nil, moerr.NewInternalErrorNoCtxf("python udf: argument descriptor count changed during resolution") + return nil, udferr.Newf("python udf: argument descriptor count changed during resolution") } } else { matchedList[0].Udf.ArgsType = function.UdfArgTypeCast(fromList, matchedList[0].TypeList) @@ -1136,7 +1138,7 @@ func (tcc *TxnCompilerContext) resolveUdfInDatabase(name string, args []*plan.Ex } matchedList[0].Udf.NamespaceFingerprint = namespaces[uint64(matchedList[0].Udf.FunctionID)] if namespaceErr == nil && matchedList[0].Udf.NamespaceFingerprint == "" { - return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: missing routine namespace") + return nil, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: missing routine namespace") } } @@ -1183,7 +1185,7 @@ func udfCatalogLookup( // catalog corruption from the planner/cache validator. func exactlyOneCatalogResultSet(ctx context.Context, rows []ExecResult, label string) (ExecResult, error) { if len(rows) != 1 || rows[0] == nil { - return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: %s returned %d result sets, expected exactly one", label, len(rows)) + return nil, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: %s returned %d result sets, expected exactly one", label, len(rows)) } return rows[0], nil } @@ -1211,7 +1213,7 @@ func exactlyOneCatalogRow(ctx context.Context, rows []ExecResult, label string) } rowCount := result.GetRowCount() if rowCount != 1 { - return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: %s returned %d rows, expected exactly one", label, rowCount) + return nil, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: %s returned %d rows, expected exactly one", label, rowCount) } return result, nil } @@ -1308,7 +1310,7 @@ func readSQLRevision( return sqlRevisionCatalogRow{}, false, nil } if activeRevision <= 0 || namespaceVersion <= 0 { - return sqlRevisionCatalogRow{}, false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d has an invalid revision head", functionID) + return sqlRevisionCatalogRow{}, false, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d has an invalid revision head", functionID) } bh.ClearExecResultSet() @@ -1382,15 +1384,15 @@ func readSQLRevision( volatility != "VOLATILE" || nullPolicy != udf.NullCallHandler || !strings.EqualFold(securityType, "DEFINER") || !strings.EqualFold(baseSecurityType, securityType) { - return sqlRevisionCatalogRow{}, false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision contract is not supported", functionID) + return sqlRevisionCatalogRow{}, false, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision contract is not supported", functionID) } logicalArgTypes, err := userDefinedFunctionArgumentTypesFromJSON(args) if err != nil || logicalArgTypes != argTypes { - return sqlRevisionCatalogRow{}, false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision argument metadata is invalid", functionID) + return sqlRevisionCatalogRow{}, false, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision argument metadata is invalid", functionID) } expectedFingerprint, err := function.SQLRoutineFingerprint(body, argTypes, retType) if err != nil || fingerprint == "" || fingerprint != expectedFingerprint { - return sqlRevisionCatalogRow{}, false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision fingerprint mismatch", functionID) + return sqlRevisionCatalogRow{}, false, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: SQL function %d revision fingerprint mismatch", functionID) } return sqlRevisionCatalogRow{ Args: args, ArgTypes: argTypes, Body: body, Language: language, RetType: retType, @@ -1427,7 +1429,7 @@ func readPythonRevision(ctx context.Context, bh BackgroundExec, functionID int64 return pythonRevisionCatalogRow{}, err } if activeRevision <= 0 || namespaceVersion <= 0 || revision != activeRevision { - return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d has an invalid revision head", functionID) + return pythonRevisionCatalogRow{}, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python function %d has an invalid revision head", functionID) } getString := func(column uint64) (string, error) { return row.GetString(ctx, 0, column) } canonicalInput, err := getString(3) @@ -1511,21 +1513,21 @@ func readPythonRevision(ctx context.Context, bh BackgroundExec, functionID int64 return pythonRevisionCatalogRow{}, err } if language != string(tree.PYTHON) || definitionSchema != udf.PythonDefinitionSchemaVersion || abi != udf.PythonABIContract || adapter != udf.PythonAdapterVersion || sdk != udf.PythonSDKVersion || volatility != "VOLATILE" || !strings.EqualFold(securityType, "INVOKER") || !strings.EqualFold(baseSecurityType, securityType) { - return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision contract is not supported", functionID) + return pythonRevisionCatalogRow{}, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision contract is not supported", functionID) } bodyDefinition, err := function.DecodePythonRoutineBody(body) if err != nil { return pythonRevisionCatalogRow{}, errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python function %d revision body is invalid", functionID) } if bodyDefinition.ABIContract != abi || bodyDefinition.AdapterVersion != adapter || bodyDefinition.SDKVersion != sdk || bodyDefinition.NullPolicy != nullPolicy || bodyDefinition.ArtifactDigest != artifact || bodyDefinition.EnvironmentDigest != environment { - return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision metadata does not match its definition", functionID) + return pythonRevisionCatalogRow{}, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision metadata does not match its definition", functionID) } actualFingerprint, err := function.PythonRoutineFingerprint(body) if err != nil { return pythonRevisionCatalogRow{}, errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python function %d revision fingerprint cannot be computed", functionID) } if fingerprint == "" || fingerprint != actualFingerprint { - return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision fingerprint mismatch", functionID) + return pythonRevisionCatalogRow{}, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision fingerprint mismatch", functionID) } expectedInput, expectedReturn, expectedSignature, err := function.PythonSignatureMetadata(bodyDefinition.ArgTypes, bodyDefinition.ReturnType) if err != nil { @@ -1533,10 +1535,10 @@ func readPythonRevision(ctx context.Context, bh BackgroundExec, functionID int64 } if signatureKeySchemaVersion != udf.PythonSignatureKeySchemaVersion || canonicalInput != expectedInput || returnDescriptor != expectedReturn || signatureFingerprint != expectedSignature { - return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d identity descriptor metadata mismatch", functionID) + return pythonRevisionCatalogRow{}, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python function %d identity descriptor metadata mismatch", functionID) } if argTypes != expectedInput { - return pythonRevisionCatalogRow{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision argument descriptor mismatch", functionID) + return pythonRevisionCatalogRow{}, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python function %d revision argument descriptor mismatch", functionID) } return pythonRevisionCatalogRow{ Args: args, ArgTypes: argTypes, Body: body, Language: language, RetType: retType, diff --git a/pkg/frontend/routine_error_contract_test.go b/pkg/frontend/routine_error_contract_test.go new file mode 100644 index 0000000000000..50d7f732c5246 --- /dev/null +++ b/pkg/frontend/routine_error_contract_test.go @@ -0,0 +1,41 @@ +// Copyright 2026 Matrix Origin +// +// 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 frontend + +import ( + "testing" + + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/stretchr/testify/require" +) + +func TestRoutineDiagnosticSQLContract(t *testing.T) { + cause := udferr.New("TYPE_CONTRACT: result length mismatch") + for _, err := range []error{cause, errutil.Wrapf(cause, "python udf: worker error")} { + code, state, message := RewriteError(err, "") + require.Equal(t, uint16(moerr.ER_INTERNAL_ERROR), code) + require.Equal(t, "HY000", state) + require.Equal(t, err.Error(), message) + } + + // Existing MO-classified errors retain their own SQL mapping. + classified := moerr.NewInternalErrorNoCtx("classified") + code, state, message := RewriteError(classified, "") + require.Equal(t, classified.ErrorCode(), code) + require.Equal(t, classified.SqlState(), state) + require.Equal(t, "internal error: classified", message) +} diff --git a/pkg/frontend/routine_namespace.go b/pkg/frontend/routine_namespace.go index 1c9e6d4856986..6d89b74bc617c 100644 --- a/pkg/frontend/routine_namespace.go +++ b/pkg/frontend/routine_namespace.go @@ -20,16 +20,17 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/matrixorigin/matrixone/pkg/common/moerr" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "sort" "strconv" "strings" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" ) -var errRoutineNamespaceBudget = moerr.NewInternalErrorNoCtx("routine namespace cache budget exceeded") +var errRoutineNamespaceBudget = udferr.New("routine namespace cache budget exceeded") const maxRoutineNamespaceRows = 65536 const maxRoutineNamespaceBytes = 64 << 20 @@ -121,7 +122,7 @@ func decodeRoutineNamespaces(ctx context.Context, rows ExecResult) (map[uint64]s groups[numbers[0]] = make(map[uint64]string) } if _, duplicate := groups[numbers[0]][numbers[1]]; duplicate { - return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: duplicate routine namespace member") + return nil, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: duplicate routine namespace member") } groups[numbers[0]][numbers[1]] = hex.EncodeToString(digest[:]) } diff --git a/pkg/frontend/routine_plan_validation.go b/pkg/frontend/routine_plan_validation.go index 98dcfa9429b97..7329e417a6a29 100644 --- a/pkg/frontend/routine_plan_validation.go +++ b/pkg/frontend/routine_plan_validation.go @@ -18,12 +18,13 @@ import ( "context" "errors" "fmt" - "github.com/matrixorigin/matrixone/pkg/common/moerr" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "sort" "strconv" "strings" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/defines" planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" @@ -116,7 +117,7 @@ func routinePlanDependencies(p *planpb.Plan) ([]*planpb.RoutinePlanDependency, e if frame.next == 0 { frameDependencies := frame.query.GetRoutineDependencies() if len(dependencies)+len(frameDependencies) > maxRoutinePlanDependencies { - return nil, moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) + return nil, udferr.Newf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) } for _, dependency := range frameDependencies { dependencySize := 1 @@ -124,7 +125,7 @@ func routinePlanDependencies(p *planpb.Plan) ([]*planpb.RoutinePlanDependency, e dependencySize = dependency.ProtoSize() } if dependencySize > maxRoutinePlanDependencyBytes-dependencyBytes { - return nil, moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine dependency bytes exceed %d", maxRoutinePlanDependencyBytes) + return nil, udferr.Newf("PROGRAM_LIMIT_EXCEEDED: routine dependency bytes exceed %d", maxRoutinePlanDependencyBytes) } dependencyBytes += dependencySize } @@ -143,10 +144,10 @@ func routinePlanDependencies(p *planpb.Plan) ([]*planpb.RoutinePlanDependency, e continue } if frame.depth+1 > maxRoutinePlanQueryDepth { - return nil, moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine dependency query nesting exceeds %d", maxRoutinePlanQueryDepth) + return nil, udferr.Newf("PROGRAM_LIMIT_EXCEEDED: routine dependency query nesting exceeds %d", maxRoutinePlanQueryDepth) } if _, exists := active[background]; exists { - return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine dependency query graph contains a cycle") + return nil, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: routine dependency query graph contains a cycle") } // Shared background queries contribute their immutable dependencies // once. Re-expanding a DAG as a tree can turn a small plan into @@ -173,10 +174,10 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan return false, nil } if len(dependencies) > maxRoutinePlanDependencies { - return false, moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) + return false, udferr.Newf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) } if ses == nil { - return false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation has no session") + return false, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: routine dependency validation has no session") } var snapshot *planpb.Snapshot if tcc := ses.GetTxnCompileCtx(); tcc != nil { @@ -350,13 +351,13 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan return false, getErr } if !strings.EqualFold(revisionSecurityType, baseSecurityType) { - return false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine %d has inconsistent revision and identity security contracts", id) + return false, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: routine %d has inconsistent revision and identity security contracts", id) } if language == udf.LanguagePython && !strings.EqualFold(revisionSecurityType, "INVOKER") { - return false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python routine catalog security type is not INVOKER") + return false, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python routine catalog security type is not INVOKER") } if language == udf.LanguageSQL && !strings.EqualFold(revisionSecurityType, "DEFINER") { - return false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL routine catalog security type is not DEFINER") + return false, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: SQL routine catalog security type is not DEFINER") } identityValid := routinePlanCatalogIdentityValidForLanguage( language, @@ -366,7 +367,7 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan revisionSDK, revisionNullPolicy, ) if _, duplicate := states[id]; duplicate { - return false, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine catalog returned duplicate state for function %d", id) + return false, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: routine catalog returned duplicate state for function %d", id) } states[id] = routinePlanCatalogState{ activeRevision: activeRevision, namespaceVersion: namespaceVersion, @@ -492,37 +493,37 @@ func routineRevisionReturnTypeMatches(rettype string, oid types.T) bool { func validateRoutinePlanDependencyShape(dependency *planpb.RoutinePlanDependency, accountID uint32) error { if dependency == nil || dependency.FunctionRef == nil { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency has no FunctionRef") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency has no FunctionRef") } ref := dependency.FunctionRef if ref.FunctionId == 0 || ref.Revision == 0 || ref.NamespaceVersion == 0 || ref.AccountId != uint64(accountID) || ref.DatabaseId == 0 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency has an invalid catalog identity") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency has an invalid catalog identity") } if dependency.ContractVersion != udf.RoutinePlanContractVersion || !udf.IsSHA256Digest(dependency.DefinitionFingerprint) || !udf.IsSHA256Digest(dependency.NamespaceFingerprint) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency contract is incomplete") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency contract is incomplete") } if dependency.Volatility == "" || dependency.NullPolicy == "" || !dependency.MayError || dependency.Leakproof { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency semantic contract is incomplete") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency semantic contract is incomplete") } switch dependency.Language { case udf.LanguagePython: if dependency.SecurityMode != "INVOKER" { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python routine plan dependency must use INVOKER security") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python routine plan dependency must use INVOKER security") } if !udf.IsSHA256Digest(dependency.ArtifactDigest) || !udf.IsSHA256Digest(dependency.EnvironmentDigest) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python routine plan dependency integrity is incomplete") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python routine plan dependency integrity is incomplete") } case udf.LanguageSQL: if dependency.SecurityMode == "" { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL routine plan dependency has no security mode") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: SQL routine plan dependency has no security mode") } if dependency.ArtifactDigest != "" || dependency.EnvironmentDigest != "" { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL routine plan dependency has external integrity fields") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: SQL routine plan dependency has external integrity fields") } default: - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency language %q is unsupported", dependency.Language) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: routine plan dependency language %q is unsupported", dependency.Language) } return nil } @@ -556,7 +557,7 @@ func routinePlanDependenciesChanged( !strings.EqualFold(state.securityType, dependency.SecurityMode) || (dependency.Language == udf.LanguagePython && expectedSecurityMode != "INVOKER") || (dependency.Language == udf.LanguageSQL && expectedSecurityMode == "") || - dependency.MayError != true || dependency.Leakproof || + !dependency.MayError || dependency.Leakproof || state.language != dependency.Language || state.fingerprint != dependency.DefinitionFingerprint || state.artifactDigest != dependency.ArtifactDigest || diff --git a/pkg/frontend/snapshot_catalog_restore.go b/pkg/frontend/snapshot_catalog_restore.go index c42bd89df6434..d8368bca6e449 100644 --- a/pkg/frontend/snapshot_catalog_restore.go +++ b/pkg/frontend/snapshot_catalog_restore.go @@ -18,10 +18,12 @@ import ( "context" "encoding/json" "fmt" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "strconv" "strings" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/matrixorigin/matrixone/pkg/catalog" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/pubsub" @@ -192,23 +194,23 @@ func validateRestoredFunctionRevisionCatalog( } for rowIndex, row := range rows { if len(row) != 20 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision row %d has %d columns", rowIndex, len(row)) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision row %d has %d columns", rowIndex, len(row)) } functionID, err := strconv.ParseUint(row[0], 10, 64) if err != nil || functionID == 0 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision row %d has an invalid function identity", rowIndex) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored Python revision row %d has an invalid function identity", rowIndex) } revision, err := strconv.ParseUint(row[1], 10, 64) if err != nil || revision == 0 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has an invalid revision", functionID) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has an invalid revision", functionID) } namespace, err := strconv.ParseUint(row[2], 10, 64) if err != nil || namespace == 0 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has an invalid namespace version", functionID) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has an invalid namespace version", functionID) } definitionSchema, err := strconv.Atoi(row[9]) if err != nil { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored function %d revision %d has an invalid definition schema", functionID, revision) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored function %d revision %d has an invalid definition schema", functionID, revision) } if row[8] == udf.LanguageSQL { if err := validateRestoredSQLFunctionRevision(functionID, revision, row, definitionSchema); err != nil { @@ -223,7 +225,7 @@ func validateRestoredFunctionRevisionCatalog( row[14] != udf.PythonSDKVersion || !strings.EqualFold(row[16], "VOLATILE") || !strings.EqualFold(row[19], "INVOKER") { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored function %d revision %d has an unsupported execution contract", functionID, revision) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored function %d revision %d has an unsupported execution contract", functionID, revision) } body, err := function.DecodePythonRoutineBody(row[7]) @@ -237,11 +239,11 @@ func validateRestoredFunctionRevisionCatalog( body.EnvironmentDigest != row[13] || body.SDKVersion != row[14] || body.NullPolicy != row[15] { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d metadata does not match its definition", functionID, revision) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d metadata does not match its definition", functionID, revision) } fingerprint, err := function.PythonRoutineFingerprint(row[7]) if err != nil || row[17] == "" || row[17] != fingerprint { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d fingerprint mismatch", functionID, revision) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d fingerprint mismatch", functionID, revision) } // `args` retains the shared logical names while `arg_types` in the // current Python revision is the exact descriptor identity used for @@ -270,7 +272,7 @@ func validateRestoredFunctionRevisionCatalog( } expectedInput, _, _, err := function.PythonSignatureMetadata(body.ArgTypes, body.ReturnType) if err != nil || row[5] != expectedInput { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d argument descriptor mismatch", functionID, revision) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d revision %d argument descriptor mismatch", functionID, revision) } } return nil @@ -281,15 +283,15 @@ func validateRestoredSQLFunctionRevision(functionID, revision uint64, row []stri row[10] != "" || row[11] != "" || row[12] != "" || row[13] != "" || row[14] != "" || row[15] != udf.NullCallHandler || !strings.EqualFold(row[16], "VOLATILE") || !strings.EqualFold(row[19], "DEFINER") { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d has an unsupported execution contract", functionID, revision) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d has an unsupported execution contract", functionID, revision) } logicalArgTypes, err := userDefinedFunctionArgumentTypesFromJSON(row[4]) if err != nil || logicalArgTypes != row[5] { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d argument metadata is invalid", functionID, revision) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d argument metadata is invalid", functionID, revision) } fingerprint, err := function.SQLRoutineFingerprint(row[7], row[5], row[6]) if err != nil || row[17] == "" || row[17] != fingerprint { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d fingerprint mismatch", functionID, revision) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d revision %d fingerprint mismatch", functionID, revision) } return nil } @@ -322,19 +324,19 @@ func validateRestoredFunctionCatalogHeads( } for rowIndex, row := range rows { if len(row) != 16 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog head row %d has %d columns", rowIndex, len(row)) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog head row %d has %d columns", rowIndex, len(row)) } functionID, err := strconv.ParseUint(row[0], 10, 64) if err != nil || functionID == 0 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog head row %d has an invalid function identity", rowIndex) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored routine catalog head row %d has an invalid function identity", rowIndex) } activeRevision, err := strconv.ParseUint(row[1], 10, 64) if err != nil { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored routine function %d has an invalid active revision: %v", functionID, err) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored routine function %d has an invalid active revision: %v", functionID, err) } namespaceVersion, err := strconv.ParseUint(row[2], 10, 64) if err != nil { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored routine function %d has an invalid namespace version: %v", functionID, err) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored routine function %d has an invalid namespace version: %v", functionID, err) } language := strings.ToLower(row[12]) if (language == udf.LanguageSQL || language == udf.LanguagePython) && activeRevision == 0 && namespaceVersion == 0 { @@ -346,39 +348,39 @@ func validateRestoredFunctionCatalogHeads( continue } if activeRevision == 0 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d has no active immutable revision", language, functionID) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d has no active immutable revision", language, functionID) } if namespaceVersion == 0 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d has an invalid namespace version", language, functionID) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d has an invalid namespace version", language, functionID) } revision, err := strconv.ParseUint(row[3], 10, 64) if err != nil || revision != activeRevision { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d active revision does not exist", language, functionID) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d active revision does not exist", language, functionID) } revisionNamespace, err := strconv.ParseUint(row[4], 10, 64) if err != nil || revisionNamespace != namespaceVersion { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d head namespace does not match its revision", language, functionID) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored %s function %d head namespace does not match its revision", language, functionID) } if language == udf.LanguageSQL { if row[10] == "" || row[11] == "" { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d has incomplete active revision", functionID) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d has incomplete active revision", functionID) } if !strings.EqualFold(row[14], "DEFINER") || !strings.EqualFold(row[15], "DEFINER") { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d has inconsistent security contract", functionID) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d has inconsistent security contract", functionID) } expectedFingerprint, fingerprintErr := function.SQLRoutineFingerprint(row[11], row[9], row[10]) if fingerprintErr != nil || row[13] == "" || row[13] != expectedFingerprint { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d head fingerprint does not match its active revision", functionID) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored SQL function %d head fingerprint does not match its active revision", functionID) } continue } if language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored function %d has unsupported language %q", functionID, row[12]) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored function %d has unsupported language %q", functionID, row[12]) } if row[5] == "" || row[6] == "" || row[7] == "" || row[8] == "" || row[9] == "" || row[10] == "" || row[11] == "" || row[13] == "" || !strings.EqualFold(row[14], "INVOKER") || !strings.EqualFold(row[15], "INVOKER") || !strings.EqualFold(row[14], row[15]) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has incomplete head identity", functionID) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d has incomplete head identity", functionID) } body, err := function.DecodePythonRoutineBody(row[11]) if err != nil { @@ -391,7 +393,7 @@ func validateRestoredFunctionCatalogHeads( bodyFingerprint, fingerprintErr := function.PythonRoutineFingerprint(row[11]) if fingerprintErr != nil || row[13] != bodyFingerprint || row[5] != input || row[6] != output || row[7] != strconv.Itoa(udf.PythonSignatureKeySchemaVersion) || row[8] != signature || row[9] != input { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d head identity does not match its active revision", functionID) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored Python function %d head identity does not match its active revision", functionID) } } return nil @@ -521,7 +523,7 @@ func publishRestoredPythonArtifacts( needStore := false for rowIndex, row := range rows { if len(row) != 3 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored revision row %d has %d artifact columns", rowIndex, len(row)) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored revision row %d has %d artifact columns", rowIndex, len(row)) } if row[0] == udf.LanguagePython { needStore = true @@ -548,7 +550,7 @@ func publishRestoredPythonArtifacts( return errutil.Wrapf(decodeErr, "UNSUPPORTED_ROUTINE_VERSION: restored Python artifact row %d is invalid", rowIndex) } if body.ArtifactDigest != row[1] { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: restored Python artifact row %d digest does not match its revision", rowIndex) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: restored Python artifact row %d digest does not match its revision", rowIndex) } if _, publishErr := store.Publish(ctx, uint64(targetAccount), body.Handler, body.Source); publishErr != nil { return publishErr diff --git a/pkg/iceberg/api/import_boundary_test.go b/pkg/iceberg/api/import_boundary_test.go index 1b4faad0e293c..fde304fd1db79 100644 --- a/pkg/iceberg/api/import_boundary_test.go +++ b/pkg/iceberg/api/import_boundary_test.go @@ -166,7 +166,10 @@ func TestImportBoundaryPolicies(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { matches := importMatchesPrefix(tt.importPath, tt.policy.importPrefixes) - if matches && tt.policy.allows(tt.relativePath) != tt.allowed { + if !matches { + t.Fatal("expected policy to match the protected module") + } + if tt.policy.allows(tt.relativePath) != tt.allowed { t.Fatalf("policy allowed=%v for %s importing %s, want %v", tt.policy.allows(tt.relativePath), tt.relativePath, tt.importPath, tt.allowed) } @@ -224,3 +227,25 @@ func findRepoRoot(t *testing.T) string { dir = parent } } + +func TestImportBoundaryModuleNames(t *testing.T) { + for _, tc := range []struct { + path string + want bool + }{ + {"github.com/apache/arrow-go/v18/arrow", true}, + {"github.com/apache/arrow/go/v12/arrow", true}, + {"github.com/apache/arrow-gopher/arrow", false}, + {"github.com/apache/arrow/golang", false}, + {"example.com/arrow", false}, + } { + if got := importMatchesPrefix(tc.path, importBoundaryPolicies[1].importPrefixes); got != tc.want { + t.Errorf("%s: got %v, want %v", tc.path, got, tc.want) + } + } + for _, path := range []string{"pkg/container/arrowbridge/reader.go", "pkg/sql/plan/binder.go"} { + if importBoundaryPolicies[0].allows(path) { + t.Errorf("Iceberg unexpectedly allowed in %s", path) + } + } +} diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index 993da7c51cdc9..242dd13eb38d7 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -16,8 +16,6 @@ package colexec import ( "encoding/json" - "github.com/matrixorigin/matrixone/pkg/common/moerr" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "os" "sort" "strconv" @@ -25,6 +23,9 @@ import ( "sync" "time" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/google/uuid" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/batch" @@ -73,13 +74,13 @@ func newExternalRoutineEval( allocation *vector.AllocationAccountSelection, ) (*ExternalRoutineEval, error) { if proc == nil || proc.Base == nil { - return nil, moerr.NewInternalErrorNoCtxf("python udf: evaluator has no process") + return nil, udferr.Newf("python udf: evaluator has no process") } if err := validateRoutineCall(call); err != nil { return nil, err } if len(call.ArgumentTypes) != len(parameters) { - return nil, moerr.NewInternalErrorNoCtxf("python udf: typed routine has %d argument descriptors but %d bound arguments", len(call.ArgumentTypes), len(parameters)) + return nil, udferr.Newf("python udf: typed routine has %d argument descriptors but %d bound arguments", len(call.ArgumentTypes), len(parameters)) } resultType := planTypeToSQL(call.ReturnType) result, err := vector.NewFunctionResultWrapperWithAllocation(resultType, proc.Mp(), allocation) @@ -100,59 +101,59 @@ func newExternalRoutineEval( func validateRoutineCall(call *planpb.RoutineCall) error { if call == nil || call.FunctionRef == nil || call.FunctionRef.FunctionId == 0 || call.FunctionRef.DatabaseId == 0 || call.FunctionRef.Revision == 0 || call.FunctionRef.NamespaceVersion == 0 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no exact FunctionRef") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no exact FunctionRef") } if call.ReturnType.Id == int32(types.T_any) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no return descriptor") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no return descriptor") } if call.ContractVersion != udf.PythonPlanContractVersion || call.Language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported typed routine call contract") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: unsupported typed routine call contract") } if call.Volatility != "VOLATILE" { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python routine must be VOLATILE") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python routine must be VOLATILE") } - if call.MayError != true || call.SecurityMode != "INVOKER" || call.Leakproof { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python routine semantic contract is not supported") + if !call.MayError || call.SecurityMode != "INVOKER" || call.Leakproof { + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python routine semantic contract is not supported") } if call.CallsiteId == "" || len(call.CallsiteId) > 256 || strings.ContainsAny(call.CallsiteId, "\r\n") { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no valid callsite id") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no valid callsite id") } if len(call.Context) != 0 { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed routine call contains execution context") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed routine call contains execution context") } python := call.GetPython() if python == nil { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no Python implementation") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed routine call has no Python implementation") } if python.Source != "" { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python plan contains source; rebind from the current artifact contract") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed Python plan contains source; rebind from the current artifact contract") } if python.Handler == "" || python.AbiContract != udf.PythonABIContract || python.AdapterVersion != udf.PythonAdapterVersion || python.SdkVersion != udf.PythonSDKVersion || python.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation contract is not supported") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation contract is not supported") } if python.Mode != "SCALAR" && python.Mode != "VECTOR" { - return moerr.NewInternalErrorNoCtxf("python udf: unsupported typed call mode %q", python.Mode) + return udferr.Newf("python udf: unsupported typed call mode %q", python.Mode) } if python.NullPolicy != udf.NullCallHandler && python.NullPolicy != udf.NullReturnNull { - return moerr.NewInternalErrorNoCtxf("python udf: unsupported typed NULL policy %q", python.NullPolicy) + return udferr.Newf("python udf: unsupported typed NULL policy %q", python.NullPolicy) } if call.NullPolicy != python.NullPolicy { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed call NULL policy does not match its implementation") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed call NULL policy does not match its implementation") } if !udf.IsSHA256Digest(python.ArtifactDigest) || !udf.IsSHA256Digest(python.EnvironmentDigest) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid artifact/environment digest") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid artifact/environment digest") } if !udf.IsSHA256Digest(python.DefinitionFingerprint) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid definition fingerprint") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed Python implementation has invalid definition fingerprint") } arguments := make([]pythonudf.TypeDescriptor, len(call.ArgumentTypes)) for i, argumentType := range call.ArgumentTypes { if argumentType == nil { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is nil", i) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed Python argument %d is nil", i) } descriptor, err := function.NewPythonTypeDescriptor(planTypeToSQL(*argumentType)) if err != nil { @@ -173,7 +174,7 @@ func validateRoutineCall(call *planpb.RoutineCall) error { return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: invalid typed Python definition") } if fingerprint != python.DefinitionFingerprint { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python definition fingerprint mismatch") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed Python definition fingerprint mismatch") } return nil @@ -185,12 +186,12 @@ func (e *ExternalRoutineEval) Eval(proc *process.Process, batches []*batch.Batch func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch, selectList []bool, transfer bool) (output *vector.Vector, evalErr error) { if e == nil || proc == nil || proc.Base == nil { - return nil, moerr.NewInternalErrorNoCtxf("python udf: evaluator has no process") + return nil, udferr.Newf("python udf: evaluator has no process") } e.executionMu.Lock() defer e.executionMu.Unlock() if e.freed { - return nil, moerr.NewInternalErrorNoCtxf("python udf: evaluator is freed") + return nil, udferr.Newf("python udf: evaluator is freed") } // Transfer under executionMu, before a concurrent Eval/Free can reuse the // backing. The wrapper retains its allocation policy for the next result. @@ -208,7 +209,7 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch return nil, err } if uint64(accountID) != e.call.FunctionRef.AccountId { - return nil, moerr.NewInternalErrorNoCtxf("python udf: FunctionRef account does not match the execution account") + return nil, udferr.Newf("python udf: FunctionRef account does not match the execution account") } python := e.call.GetPython() rowCount, err := externalRoutineRowCount(python.Mode, batches) @@ -219,7 +220,7 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch // early before this check would let a stale selection mask cross the // physical boundary and hide a relation-position bug in the caller. if selectList != nil && len(selectList) != rowCount { - return nil, moerr.NewInternalErrorNoCtxf("external routine selection has %d rows, expected %d", len(selectList), rowCount) + return nil, udferr.Newf("external routine selection has %d rows, expected %d", len(selectList), rowCount) } if rowCount == 0 { if err := e.result.PreExtendAndReset(0); err != nil { @@ -338,16 +339,16 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch Tuple: tuple, } if proc.Base.UdfService == nil { - return nil, moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime is not enabled") + return nil, udferr.Newf("RESOURCE_UNAVAILABLE: Python UDF runtime is not enabled") } if err := proc.Base.UdfService.Execute(proc.Ctx, invocation, selectedResult, proc.Mp()); err != nil { return nil, err } if selectedResult.ResultLength() != len(e.selectedRows) { - return nil, moerr.NewInternalErrorNoCtxf("python udf: runtime produced %d result rows, expected %d", selectedResult.ResultLength(), len(e.selectedRows)) + return nil, udferr.Newf("python udf: runtime produced %d result rows, expected %d", selectedResult.ResultLength(), len(e.selectedRows)) } if selectedResult.GetResultVector() == nil { - return nil, moerr.NewInternalErrorNoCtxf("python udf: runtime returned no result vector") + return nil, udferr.Newf("python udf: runtime returned no result vector") } if len(e.selectedRows) == rowCount { return e.result.GetResultVector(), nil @@ -364,7 +365,7 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch // that two calls belong to the same statement. func (e *ExternalRoutineEval) attachInvocationGroup(context map[string]string, queryID string) error { if context == nil { - return moerr.NewInternalErrorNoCtxf("python udf: invocation context is unavailable") + return udferr.Newf("python udf: invocation context is unavailable") } e.groupMu.Lock() defer e.groupMu.Unlock() @@ -387,7 +388,7 @@ func (e *ExternalRoutineEval) attachInvocationGroup(context map[string]string, q e.groupEpoch = 0 } if e.groupEpoch == ^uint64(0) { - return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF execution group epoch overflow") + return udferr.Newf("RESOURCE_EXHAUSTED: Python UDF execution group epoch overflow") } e.groupEpoch++ context["group_id"] = e.groupID @@ -409,7 +410,7 @@ func (e *ExternalRoutineEval) compactParameters(proc *process.Process, rowCount e.selectedParameters = e.selectedParameters[:0] for i, input := range e.parameterResults { if input == nil { - return nil, moerr.NewInternalErrorNoCtxf("external routine parameter %d is nil", i) + return nil, udferr.Newf("external routine parameter %d is nil", i) } if input.IsConst() || len(e.selectedRows) == rowCount { e.selectedParameters = append(e.selectedParameters, input) @@ -432,14 +433,14 @@ func (e *ExternalRoutineEval) compactParameters(proc *process.Process, rowCount func validateExternalRoutineInputs(inputs []*vector.Vector, call *planpb.RoutineCall, rowCount int) error { if len(inputs) != len(call.ArgumentTypes) { - return moerr.NewInternalErrorNoCtxf("python udf: evaluated input count %d does not match routine argument count %d", len(inputs), len(call.ArgumentTypes)) + return udferr.Newf("python udf: evaluated input count %d does not match routine argument count %d", len(inputs), len(call.ArgumentTypes)) } for index, input := range inputs { if input == nil || input.GetType() == nil { - return moerr.NewInternalErrorNoCtxf("python udf: evaluated input vector %d has no type", index) + return udferr.Newf("python udf: evaluated input vector %d has no type", index) } if input.Length() == 0 || (!input.IsConst() && input.Length() < rowCount) { - return moerr.NewInternalErrorNoCtxf("python udf: evaluated input vector %d has %d rows, expected at least %d", index, input.Length(), rowCount) + return udferr.Newf("python udf: evaluated input vector %d has %d rows, expected at least %d", index, input.Length(), rowCount) } expected, err := function.NewPythonTypeDescriptor(planTypeToSQL(*call.ArgumentTypes[index])) if err != nil { @@ -458,7 +459,7 @@ func validateExternalRoutineInputs(inputs []*vector.Vector, call *planpb.Routine return err } if expectedFingerprint != actualFingerprint { - return moerr.NewInternalErrorNoCtxf("python udf: evaluated input vector %d type %s does not match the frozen descriptor", index, input.GetType().DescString()) + return udferr.Newf("python udf: evaluated input vector %d type %s does not match the frozen descriptor", index, input.GetType().DescString()) } } return nil @@ -588,20 +589,20 @@ func externalRoutineRowCount(mode string, batches []*batch.Batch) (int, error) { rowCount := -1 for index, input := range batches { if input == nil { - return 0, moerr.NewInternalErrorNoCtxf("external routine input batch %d is nil", index) + return 0, udferr.Newf("external routine input batch %d is nil", index) } if rowCount < 0 { rowCount = input.RowCount() continue } if input.RowCount() != rowCount { - return 0, moerr.NewInternalErrorNoCtxf("python udf: external routine input batch %d has %d rows, expected %d for the logical row domain", index, input.RowCount(), rowCount) + return 0, udferr.Newf("python udf: external routine input batch %d has %d rows, expected %d for the logical row domain", index, input.RowCount(), rowCount) } } return rowCount, nil } if mode == "VECTOR" { - return 0, moerr.NewInternalErrorNoCtxf("python udf: zero-argument VECTOR requires an input batch with num_rows") + return 0, udferr.Newf("python udf: zero-argument VECTOR requires an input batch with num_rows") } return 1, nil } @@ -612,7 +613,7 @@ func externalRoutineRowCount(mode string, batches []*batch.Batch) (int, error) { // prepared plan can outlive both. func buildRoutineContext(proc *process.Process) (map[string]string, error) { if proc == nil || proc.Base == nil { - return nil, moerr.NewInternalErrorNoCtxf("python udf: process is unavailable for statement context") + return nil, udferr.Newf("python udf: process is unavailable for statement context") } context := make(map[string]string) // The current query id is stable for the statement and changes for every @@ -630,7 +631,7 @@ func buildRoutineContext(proc *process.Process) (map[string]string, error) { // the lifetime of that process; a real frontend statement always uses // its query start above. if proc.Base.UnixTime == 0 { - return nil, moerr.NewInternalErrorNoCtxf("python udf: statement timestamp is unavailable") + return nil, udferr.Newf("python udf: statement timestamp is unavailable") } queryStart = time.Unix(0, proc.Base.UnixTime) } @@ -638,12 +639,12 @@ func buildRoutineContext(proc *process.Process) (map[string]string, error) { location := proc.GetSessionInfo().TimeZone if location == nil { - return nil, moerr.NewInternalErrorNoCtxf("python udf: session timezone is unavailable") + return nil, udferr.Newf("python udf: session timezone is unavailable") } zoneName := location.String() var timezoneErr error if zoneName == "" || zoneName == "SYSTEM" { - return nil, moerr.NewInternalErrorNoCtxf("python udf: session timezone is not a stable IANA identity") + return nil, udferr.Newf("python udf: session timezone is not a stable IANA identity") } if zoneName == "Local" { zoneName, location, timezoneErr = resolveSystemTimezone() @@ -654,7 +655,7 @@ func buildRoutineContext(proc *process.Process) (map[string]string, error) { if zoneName == "FixedZone" { _, offset := queryStart.In(location).Zone() if offset%60 != 0 { - return nil, moerr.NewInternalErrorNoCtxf("python udf: fixed session timezone offset must be a whole number of minutes") + return nil, udferr.Newf("python udf: fixed session timezone offset must be a whole number of minutes") } context["session_timezone_kind"] = "FIXED_OFFSET" context["session_timezone_offset_minutes"] = formatTimezoneOffsetMinutes(offset / 60) @@ -720,7 +721,7 @@ func resolveSystemTimezone() (string, *time.Location, error) { return candidate, location, nil } } - return "", nil, moerr.NewInternalErrorNoCtxf("python udf: SYSTEM timezone has no stable IANA identity") + return "", nil, udferr.Newf("python udf: SYSTEM timezone has no stable IANA identity") } func formatTimezoneOffsetMinutes(offset int) string { diff --git a/pkg/sql/plan/function/python_udf.go b/pkg/sql/plan/function/python_udf.go index af8f2fa811e6c..66d956168a843 100644 --- a/pkg/sql/plan/function/python_udf.go +++ b/pkg/sql/plan/function/python_udf.go @@ -15,10 +15,11 @@ package function import ( - "github.com/matrixorigin/matrixone/pkg/common/moerr" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "strconv" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/google/uuid" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -176,56 +177,47 @@ func pythonUdfRetType(parameters []types.Type) types.Type { // historical overload id. Long-term execution enters through the typed // RoutineCall field and ExternalRoutineEval. func rejectPythonJSONPlan(_ []*vector.Vector, _ vector.FunctionResultWrapper, _ *process.Process, _ int, _ *FunctionSelectList) error { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python JSON plan execution is not supported; reprepare the statement") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python JSON plan execution is not supported; reprepare the statement") } func validatePythonRoutineDescriptor(descriptor *vector.Vector) error { if descriptor == nil { - return moerr.NewInternalErrorNoCtxf("python udf: missing routine descriptor") + return udferr.Newf("python udf: missing routine descriptor") } if !descriptor.IsConst() { - return moerr.NewInternalErrorNoCtxf("python udf: routine descriptor must be constant") + return udferr.Newf("python udf: routine descriptor must be constant") } if descriptor.Length() == 0 { - return moerr.NewInternalErrorNoCtxf("python udf: routine descriptor is empty") + return udferr.Newf("python udf: routine descriptor is empty") } return nil } func validatePythonInputVectors(inputs []*vector.Vector, args []types.Type, length int) error { if len(inputs) != len(args) { - return moerr.NewInternalErrorNoCtxf("python udf: input column count %d does not match routine argument count %d", len(inputs), len(args)) + return udferr.Newf("python udf: input column count %d does not match routine argument count %d", len(inputs), len(args)) } for index, input := range inputs { if input == nil { - return moerr.NewInternalErrorNoCtxf("python udf: input vector %d is nil", index) + return udferr.Newf("python udf: input vector %d is nil", index) } if input.Length() == 0 { - return moerr.NewInternalErrorNoCtxf("python udf: input vector %d is empty", index) + return udferr.Newf("python udf: input vector %d is empty", index) } if !input.IsConst() && input.Length() < length { - return moerr.NewInternalErrorNoCtxf("python udf: input vector %d is shorter than invocation length", index) + return udferr.Newf("python udf: input vector %d is shorter than invocation length", index) } if input.GetType() == nil || !pythonTypesEqual(*input.GetType(), args[index]) { actual := "" if input.GetType() != nil { actual = input.GetType().String() } - return moerr.NewInternalErrorNoCtxf("python udf: input vector %d type %s does not match %s", index, actual, args[index].String()) + return udferr.Newf("python udf: input vector %d type %s does not match %s", index, actual, args[index].String()) } } return nil } -func hasNullInput(inputs []*vector.Vector, row int) bool { - for _, input := range inputs { - if input == nil || input.IsNull(uint64(row)) { - return true - } - } - return false -} - func invocationTuple(context map[string]string, queryID string, accountID uint32) (protocol.FencingTuple, error) { statementID := context["statement_id"] if statementID == "" { @@ -250,7 +242,7 @@ func invocationTuple(context map[string]string, queryID string, accountID uint32 // explicit epoch when it is introduced. groupID = statementID + "/python/" + invocationID.String() } else if context["group_epoch"] == "" { - return protocol.FencingTuple{}, moerr.NewInternalErrorNoCtxf("python udf: explicit group_id requires group_epoch") + return protocol.FencingTuple{}, udferr.Newf("python udf: explicit group_id requires group_epoch") } groupEpoch, err := positiveContextUint(context, "group_epoch", 1) if err != nil { @@ -284,7 +276,7 @@ func positiveContextUint(context map[string]string, key string, fallback uint64) } parsed, err := strconv.ParseUint(value, 10, 64) if err != nil || parsed == 0 { - return 0, moerr.NewInternalErrorNoCtxf("python udf: invalid %s %q", key, value) + return 0, udferr.Newf("python udf: invalid %s %q", key, value) } return parsed, nil } diff --git a/pkg/sql/plan/function/udf.go b/pkg/sql/plan/function/udf.go index e102ce3b9cabd..121a09831321c 100644 --- a/pkg/sql/plan/function/udf.go +++ b/pkg/sql/plan/function/udf.go @@ -18,13 +18,14 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - "github.com/matrixorigin/matrixone/pkg/common/moerr" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "io" "reflect" "strings" "unicode/utf8" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/udf" @@ -101,7 +102,7 @@ func PythonSignatureMetadata( returnType *PythonTypeDescriptor, ) (canonicalInput, canonicalReturn, fingerprint string, err error) { if returnType == nil { - return "", "", "", moerr.NewInternalErrorNoCtxf("python routine is missing return descriptor") + return "", "", "", udferr.Newf("python routine is missing return descriptor") } if args == nil { args = []PythonTypeDescriptor{} @@ -123,7 +124,7 @@ func PythonSignatureMetadata( return "", "", "", errutil.Wrapf(err, "marshal Python return descriptor") } if len(inputBytes) > types.MaxStringSize || len(returnBytes) > types.MaxStringSize { - return "", "", "", moerr.NewInternalErrorNoCtxf("python signature descriptor exceeds the %d-byte catalog limit", types.MaxStringSize) + return "", "", "", udferr.Newf("python signature descriptor exceeds the %d-byte catalog limit", types.MaxStringSize) } keyBytes, err := json.Marshal(struct { SchemaVersion int `json:"schema_version"` @@ -157,7 +158,7 @@ func DecodePythonRoutineBody(raw string) (PythonRoutineBody, error) { var extra json.RawMessage if err := decoder.Decode(&extra); err != io.EOF { if err == nil { - return PythonRoutineBody{}, moerr.NewInternalErrorNoCtxf("python routine body contains multiple JSON values") + return PythonRoutineBody{}, udferr.Newf("python routine body contains multiple JSON values") } return PythonRoutineBody{}, err } @@ -200,7 +201,7 @@ func PythonRoutineBodyFingerprint(body PythonRoutineBody) (string, error) { // independently hashing source text. func SQLRoutineFingerprint(body, argTypes, returnType string) (string, error) { if body == "" || returnType == "" { - return "", moerr.NewInternalErrorNoCtxf("SQL routine definition is incomplete") + return "", udferr.Newf("SQL routine definition is incomplete") } encoded, err := json.Marshal(struct { SchemaVersion int `json:"schema_version"` @@ -228,7 +229,7 @@ func SQLRoutineFingerprint(body, argTypes, returnType string) (string, error) { // catalog contract instead of decoding and dispatching this payload. func DecodeUdfWithContext(raw []byte) (UdfWithContext, error) { _ = raw - return UdfWithContext{}, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python JSON plan is not executable; rebind the statement from the current typed catalog contract") + return UdfWithContext{}, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python JSON plan is not executable; rebind the statement from the current typed catalog contract") } // Validate checks fields that are independent of the catalog argument list. @@ -236,47 +237,47 @@ func DecodeUdfWithContext(raw []byte) (UdfWithContext, error) { // legacy catalog args column has been decoded. func (body PythonRoutineBody) Validate() error { if body.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: python definition schema %d is not supported", body.DefinitionSchemaVersion) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: python definition schema %d is not supported", body.DefinitionSchemaVersion) } if body.Handler == "" || body.Source == "" { - return moerr.NewInternalErrorNoCtxf("python routine handler and source are required") + return udferr.Newf("python routine handler and source are required") } if !utf8.ValidString(body.Source) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python source is not valid UTF-8") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python source is not valid UTF-8") } if int64(len([]byte(body.Source))) > pythonudf.DefaultMaxArtifactBytes { - return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python source exceeds %d bytes", pythonudf.DefaultMaxArtifactBytes) + return udferr.Newf("RESOURCE_EXHAUSTED: Python source exceeds %d bytes", pythonudf.DefaultMaxArtifactBytes) } if strings.Contains(body.Handler, ":") { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog") } if body.Mode != "SCALAR" && body.Mode != "VECTOR" { - return moerr.NewInternalErrorNoCtxf("python routine has unsupported mode %q", body.Mode) + return udferr.Newf("python routine has unsupported mode %q", body.Mode) } if body.NullPolicy != udf.NullCallHandler && body.NullPolicy != udf.NullReturnNull { - return moerr.NewInternalErrorNoCtxf("python routine has unsupported NULL policy %q", body.NullPolicy) + return udferr.Newf("python routine has unsupported NULL policy %q", body.NullPolicy) } if body.ABIContract != udf.PythonABIContract || body.AdapterVersion != udf.PythonAdapterVersion { - return moerr.NewInternalErrorNoCtxf("python routine has unsupported ABI contract %q/%q", body.ABIContract, body.AdapterVersion) + return udferr.Newf("python routine has unsupported ABI contract %q/%q", body.ABIContract, body.AdapterVersion) } if body.SDKVersion != udf.PythonSDKVersion { - return moerr.NewInternalErrorNoCtxf("python routine has unsupported SDK %q", body.SDKVersion) + return udferr.Newf("python routine has unsupported SDK %q", body.SDKVersion) } if !udf.IsSHA256Digest(body.ArtifactDigest) || body.EnvironmentDigest == "" { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition has no immutable artifact/environment digest; use DROP and CREATE") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python definition has no immutable artifact/environment digest; use DROP and CREATE") } if body.ArtifactDigest != udf.PythonInlineArtifactDigest(body.Handler, body.Source) { - return moerr.NewInternalErrorNoCtxf("python routine artifact digest does not match its source") + return udferr.Newf("python routine artifact digest does not match its source") } environmentDigest, err := udf.PythonEnvironmentDigest() if err != nil { return errutil.Wrapf(err, "python routine environment digest is unavailable") } if body.EnvironmentDigest != environmentDigest { - return moerr.NewInternalErrorNoCtxf("python routine environment digest does not match the current contract") + return udferr.Newf("python routine environment digest does not match the current contract") } if body.ReturnType == nil { - return moerr.NewInternalErrorNoCtxf("python routine is missing return descriptor") + return udferr.Newf("python routine is missing return descriptor") } for i, descriptor := range body.ArgTypes { if err := validatePythonTypeDescriptor(descriptor); err != nil { @@ -310,16 +311,16 @@ type Arg struct { // process at execution time. func (u *Udf) GetRoutineCall() (*plan.RoutineCall, error) { if u == nil { - return nil, moerr.NewInternalErrorNoCtxf("routine call requires a non-nil routine") + return nil, udferr.Newf("routine call requires a non-nil routine") } if u.Language == udf.LanguageSQL { return u.getSQLRoutineCall() } if u.Language != udf.LanguagePython { - return nil, moerr.NewInternalErrorNoCtxf("routine call has unsupported language %q", u.Language) + return nil, udferr.Newf("routine call has unsupported language %q", u.Language) } if u.FunctionID <= 0 || u.DatabaseID == 0 || u.Revision == 0 || u.NamespaceVersion == 0 { - return nil, moerr.NewInternalErrorNoCtxf("python routine has no stable catalog identity or revision") + return nil, udferr.Newf("python routine has no stable catalog identity or revision") } body, err := DecodePythonRoutineBody(u.Body) if err != nil { @@ -381,10 +382,10 @@ func (u *Udf) GetRoutineCall() (*plan.RoutineCall, error) { // plan dependency so replace/drop cannot silently reuse the old definition. func (u *Udf) getSQLRoutineCall() (*plan.RoutineCall, error) { if u.FunctionID <= 0 || u.DatabaseID == 0 || u.Revision == 0 || u.NamespaceVersion == 0 { - return nil, moerr.NewInternalErrorNoCtxf("SQL routine has no stable catalog identity or revision") + return nil, udferr.Newf("SQL routine has no stable catalog identity or revision") } if u.SemanticDefinitionSchemaVersion != udf.SQLDefinitionSchemaVersion || !udf.IsSHA256Digest(u.DefinitionFingerprint) { - return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: SQL routine has no supported semantic definition") + return nil, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: SQL routine has no supported semantic definition") } argTypes := u.GetArgsType() arguments := make([]*plan.Type, len(argTypes)) @@ -471,7 +472,7 @@ func (u *Udf) LoadPythonTypeContract() error { return nil } if u.Language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) } u.PythonArgTypes = nil u.PythonReturnType = nil @@ -494,13 +495,13 @@ func (u *Udf) ValidatePythonTypeContract() error { return nil } if u.Language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) } if u.PythonReturnType == nil { - return moerr.NewInternalErrorNoCtxf("python routine is missing return descriptor") + return udferr.Newf("python routine is missing return descriptor") } if len(u.PythonArgTypes) != len(u.Args) { - return moerr.NewInternalErrorNoCtxf("python routine has %d descriptors for %d arguments", len(u.PythonArgTypes), len(u.Args)) + return udferr.Newf("python routine has %d descriptors for %d arguments", len(u.PythonArgTypes), len(u.Args)) } for i, descriptor := range u.PythonArgTypes { if err := validatePythonTypeDescriptor(descriptor); err != nil { @@ -521,10 +522,10 @@ func (u *Udf) ValidatePythonCatalogSignature() error { return nil } if u.Language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: unsupported routine language %q", u.Language) } if len(u.Args) != len(u.PythonArgTypes) || u.PythonReturnType == nil { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python catalog signature is incomplete") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python catalog signature is incomplete") } for index, argument := range u.Args { if argument == nil || !pythonCatalogTypeNameMatches(argument.Type, u.PythonArgTypes[index].Type().Oid) { @@ -532,11 +533,11 @@ func (u *Udf) ValidatePythonCatalogSignature() error { if argument != nil { name = argument.Type } - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python catalog argument %d type %q does not match its descriptor", index+1, name) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python catalog argument %d type %q does not match its descriptor", index+1, name) } } if !pythonCatalogTypeNameMatches(u.RetType, u.PythonReturnType.Type().Oid) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python catalog return type %q does not match its descriptor", u.RetType) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python catalog return type %q does not match its descriptor", u.RetType) } return nil } @@ -565,7 +566,7 @@ func validatePythonTypeDescriptor(descriptor PythonTypeDescriptor) error { return err } if !reflect.DeepEqual(canonical, descriptor) { - return moerr.NewInternalErrorNoCtxf("descriptor is not canonical for %s", typ.String()) + return udferr.Newf("descriptor is not canonical for %s", typ.String()) } if _, err := descriptor.Fingerprint(); err != nil { return errutil.Wrapf(err, "descriptor has no valid Arrow physical type") diff --git a/pkg/sql/plan/routine_dependency.go b/pkg/sql/plan/routine_dependency.go index aadb7307d7ee0..f589ad616ddc9 100644 --- a/pkg/sql/plan/routine_dependency.go +++ b/pkg/sql/plan/routine_dependency.go @@ -16,9 +16,10 @@ package plan import ( "fmt" - "github.com/matrixorigin/matrixone/pkg/common/moerr" "strings" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + planpb "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/udf" ) @@ -37,16 +38,16 @@ func (builder *QueryBuilder) assignRoutineCallsite(call *planpb.RoutineCall) err return nil } if call.Language != udf.LanguageSQL && call.Language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine call language %q is not canonical", call.Language) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: routine call language %q is not canonical", call.Language) } if call.CallsiteId != "" { if len(call.CallsiteId) > 256 || strings.ContainsAny(call.CallsiteId, "\r\n") { - return moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine callsite id is too large or invalid") + return udferr.Newf("PROGRAM_LIMIT_EXCEEDED: routine callsite id is too large or invalid") } return nil } if builder.nextRoutineCallID == ^uint64(0) { - return moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine callsite id exhausted") + return udferr.Newf("PROGRAM_LIMIT_EXCEEDED: routine callsite id exhausted") } builder.nextRoutineCallID++ call.CallsiteId = fmt.Sprintf("%s/%d", strings.ToLower(call.Language), builder.nextRoutineCallID) @@ -58,7 +59,7 @@ func (builder *QueryBuilder) recordRoutinePlanDependency(call *planpb.RoutineCal return nil } if call.Language != udf.LanguageSQL && call.Language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: routine call language %q is not canonical", call.Language) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: routine call language %q is not canonical", call.Language) } ref := call.FunctionRef dependency := &planpb.RoutinePlanDependency{ @@ -95,7 +96,7 @@ func (builder *QueryBuilder) recordRoutinePlanDependency(call *planpb.RoutineCal } } if len(builder.qry.RoutineDependencies) >= maxRoutinePlanDependencies { - return moerr.NewInternalErrorNoCtxf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) + return udferr.Newf("PROGRAM_LIMIT_EXCEEDED: routine dependency count exceeds %d", maxRoutinePlanDependencies) } builder.qry.RoutineDependencies = append(builder.qry.RoutineDependencies, dependency) return nil diff --git a/pkg/udf/protocol/protocol.go b/pkg/udf/protocol/protocol.go index 405a9bd590604..4b4418a441b4f 100644 --- a/pkg/udf/protocol/protocol.go +++ b/pkg/udf/protocol/protocol.go @@ -23,12 +23,13 @@ import ( "encoding/hex" "encoding/json" "errors" - "github.com/matrixorigin/matrixone/pkg/common/moerr" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "io" "sync" "time" "unicode/utf8" + + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" ) const ( @@ -52,12 +53,12 @@ const ( ) var ( - ErrProtocol = moerr.NewInternalErrorNoCtx("python udf protocol violation") - ErrSequence = moerr.NewInternalErrorNoCtx("python udf sequence violation") - ErrGroupClosed = moerr.NewInternalErrorNoCtx("python udf execution group is closed") - ErrDuplicate = moerr.NewInternalErrorNoCtx("python udf identity is already present") - ErrLedgerFull = moerr.NewInternalErrorNoCtx("python udf terminal ledger is full") - ErrUnknownIdentity = moerr.NewInternalErrorNoCtx("python udf identity is unknown") + ErrProtocol = udferr.New("python udf protocol violation") + ErrSequence = udferr.New("python udf sequence violation") + ErrGroupClosed = udferr.New("python udf execution group is closed") + ErrDuplicate = udferr.New("python udf identity is already present") + ErrLedgerFull = udferr.New("python udf terminal ledger is full") + ErrUnknownIdentity = udferr.New("python udf identity is unknown") ) // FencingTuple is carried by every invocation control and data-plane @@ -368,9 +369,9 @@ func rejectDuplicateJSONKeys(data []byte) error { var trailing any if err := decoder.Decode(&trailing); err != io.EOF { if err == nil { - return moerr.NewInternalErrorNoCtx("control contains trailing JSON") + return udferr.New("control contains trailing JSON") } - return moerr.NewInternalErrorNoCtxf("decode trailing control data: %v", err) + return udferr.Newf("decode trailing control data: %v", err) } return nil } @@ -382,14 +383,14 @@ func walkJSONValue(decoder *json.Decoder) error { func walkJSONValueAtDepth(decoder *json.Decoder, depth int) error { token, err := decoder.Token() if err != nil { - return moerr.NewInternalErrorNoCtxf("decode control JSON: %v", err) + return udferr.Newf("decode control JSON: %v", err) } delim, ok := token.(json.Delim) if !ok { return nil } if depth >= MaxJSONNesting { - return moerr.NewInternalErrorNoCtxf("control JSON nesting exceeds %d levels", MaxJSONNesting) + return udferr.Newf("control JSON nesting exceeds %d levels", MaxJSONNesting) } switch delim { case '{': @@ -397,14 +398,14 @@ func walkJSONValueAtDepth(decoder *json.Decoder, depth int) error { for decoder.More() { keyToken, err := decoder.Token() if err != nil { - return moerr.NewInternalErrorNoCtxf("decode control object key: %v", err) + return udferr.Newf("decode control object key: %v", err) } key, ok := keyToken.(string) if !ok { - return moerr.NewInternalErrorNoCtx("control object key is not a string") + return udferr.New("control object key is not a string") } if _, exists := seen[key]; exists { - return moerr.NewInternalErrorNoCtxf("duplicate control JSON field %q", key) + return udferr.Newf("duplicate control JSON field %q", key) } seen[key] = struct{}{} if err := walkJSONValueAtDepth(decoder, depth+1); err != nil { @@ -422,7 +423,7 @@ func walkJSONValueAtDepth(decoder *json.Decoder, depth int) error { _, err = decoder.Token() return err default: - return moerr.NewInternalErrorNoCtxf("unexpected control JSON delimiter %q", delim) + return udferr.Newf("unexpected control JSON delimiter %q", delim) } } @@ -788,10 +789,6 @@ func (g *ExecutionGroup) MemberTerminal(memberID string) error { return nil } -func (g *ExecutionGroup) canReleaseLocked() bool { - return g.shouldReleaseLocked() && !g.releaseBusy -} - func (g *ExecutionGroup) shouldReleaseLocked() bool { return g.closing && len(g.members) == 0 && g.inFlight == 0 && !g.released } diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index 11f254a6ad7c6..a129311757350 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -22,13 +22,14 @@ import ( "encoding/hex" "encoding/json" "fmt" - "github.com/matrixorigin/matrixone/pkg/common/moerr" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "io" "math" "reflect" "unicode/utf8" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/apache/arrow-go/v18/arrow" "github.com/apache/arrow-go/v18/arrow/array" "github.com/apache/arrow-go/v18/arrow/decimal128" @@ -105,11 +106,11 @@ func NewTypeDescriptor(typ types.Type) (TypeDescriptor, error) { types.T_binary, types.T_varbinary, types.T_blob, types.T_array_float32, types.T_array_float64: default: - return TypeDescriptor{}, moerr.NewInternalErrorNoCtxf("python udf does not support MatrixOne type %s", typ.String()) + return TypeDescriptor{}, udferr.Newf("python udf does not support MatrixOne type %s", typ.String()) } if typ.Oid == types.T_array_float32 || typ.Oid == types.T_array_float64 { if typ.Width <= 0 { - return TypeDescriptor{}, moerr.NewInternalErrorNoCtxf("python udf requires a positive vector dimension for %s", typ.String()) + return TypeDescriptor{}, udferr.Newf("python udf requires a positive vector dimension for %s", typ.String()) } d.OffsetWidth = 0 } @@ -157,29 +158,29 @@ func (d TypeDescriptor) Fingerprint() (string, error) { func (d TypeDescriptor) Validate() error { oid := types.T(d.TypeID) if d.Width < 0 { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: descriptor width must be non-negative") + return udferr.Newf("TYPE_CONTRACT: descriptor width must be non-negative") } if d.Scale < 0 { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: descriptor scale must be non-negative") + return udferr.Newf("TYPE_CONTRACT: descriptor scale must be non-negative") } expectedOffsetWidth := int32(32) if oid == types.T_uuid || oid == types.T_array_float32 || oid == types.T_array_float64 { expectedOffsetWidth = 0 } if d.OffsetWidth != expectedOffsetWidth { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: descriptor offset_width must be %d for %s", expectedOffsetWidth, oid.String()) + return udferr.Newf("TYPE_CONTRACT: descriptor offset_width must be %d for %s", expectedOffsetWidth, oid.String()) } if d.JSONEncoding != "" && (oid != types.T_json || d.JSONEncoding != "canonical_text") { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: unsupported JSON encoding") + return udferr.Newf("TYPE_CONTRACT: unsupported JSON encoding") } if oid == types.T_json && d.JSONEncoding != "canonical_text" { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: JSON descriptor must use canonical_text encoding") + return udferr.Newf("TYPE_CONTRACT: JSON descriptor must use canonical_text encoding") } if d.TemporalEncoding != "" && (oid != types.T_date && oid != types.T_datetime && oid != types.T_timestamp || d.TemporalEncoding != "sql_zero_struct") { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: unsupported temporal encoding") + return udferr.Newf("TYPE_CONTRACT: unsupported temporal encoding") } if (oid == types.T_date || oid == types.T_datetime || oid == types.T_timestamp) && d.TemporalEncoding != "sql_zero_struct" { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: temporal descriptor must use sql_zero_struct encoding") + return udferr.Newf("TYPE_CONTRACT: temporal descriptor must use sql_zero_struct encoding") } switch oid { @@ -187,7 +188,7 @@ func (d TypeDescriptor) Validate() error { types.T_uint8, types.T_uint16, types.T_uint32, types.T_uint64, types.T_float32, types.T_float64, types.T_json: if d.Width != 0 || d.Scale != 0 || d.Charset != types.CharsetLegacy { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: descriptor carries unused fields for %s", oid.String()) + return udferr.Newf("TYPE_CONTRACT: descriptor carries unused fields for %s", oid.String()) } case types.T_decimal64, types.T_decimal128: maxPrecision := int32(38) @@ -195,45 +196,45 @@ func (d TypeDescriptor) Validate() error { maxPrecision = 18 } if d.Width < 1 || d.Width > maxPrecision { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: decimal precision %d is outside %s range", d.Width, oid.String()) + return udferr.Newf("TYPE_CONTRACT: decimal precision %d is outside %s range", d.Width, oid.String()) } if d.Scale > d.Width { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: decimal scale %d exceeds precision %d", d.Scale, d.Width) + return udferr.Newf("TYPE_CONTRACT: decimal scale %d exceeds precision %d", d.Scale, d.Width) } if d.Charset != types.CharsetLegacy { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: decimal descriptor carries a charset") + return udferr.Newf("TYPE_CONTRACT: decimal descriptor carries a charset") } case types.T_date: if d.Width != 0 || d.Scale != 0 || d.Charset != types.CharsetLegacy { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATE descriptor has unused or invalid fields") + return udferr.Newf("TYPE_CONTRACT: DATE descriptor has unused or invalid fields") } case types.T_time, types.T_datetime, types.T_timestamp: if d.Width != 0 || d.Scale > 6 || d.Charset != types.CharsetLegacy { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: temporal scale or charset is outside the supported range") + return udferr.Newf("TYPE_CONTRACT: temporal scale or charset is outside the supported range") } case types.T_char, types.T_varchar, types.T_text: if d.Scale != 0 { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: text descriptor carries an unused scale") + return udferr.Newf("TYPE_CONTRACT: text descriptor carries an unused scale") } switch d.Charset { case types.CharsetLegacy, types.CharsetUTF8MB4Bin, types.CharsetUTF8: default: - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: unsupported text charset %d", d.Charset) + return udferr.Newf("TYPE_CONTRACT: unsupported text charset %d", d.Charset) } case types.T_binary, types.T_varbinary, types.T_blob: if d.Scale != 0 || d.Charset != types.CharsetBinary { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: binary descriptor must use the binary charset") + return udferr.Newf("TYPE_CONTRACT: binary descriptor must use the binary charset") } case types.T_uuid: if d.Width != 0 || d.Scale != 0 || d.Charset != types.CharsetLegacy { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: UUID descriptor carries unused fields") + return udferr.Newf("TYPE_CONTRACT: UUID descriptor carries unused fields") } case types.T_array_float32, types.T_array_float64: if d.Width < 1 || d.Width > types.MaxArrayDimension || d.Scale != 0 || d.Charset != types.CharsetLegacy { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: vector dimension or metadata is outside the supported range") + return udferr.Newf("TYPE_CONTRACT: vector dimension or metadata is outside the supported range") } default: - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: unsupported MatrixOne type id %d", d.TypeID) + return udferr.Newf("TYPE_CONTRACT: unsupported MatrixOne type id %d", d.TypeID) } return nil } @@ -271,7 +272,7 @@ func (d TypeDescriptor) arrowType() (arrow.DataType, error) { } } if precision < 1 || precision > decimal128.MaxPrecision { - return nil, moerr.NewInternalErrorNoCtxf("decimal precision %d is outside Arrow's supported range", precision) + return nil, udferr.Newf("decimal precision %d is outside Arrow's supported range", precision) } return &arrow.Decimal128Type{Precision: precision, Scale: d.Scale}, nil case types.T_char, types.T_varchar, types.T_text, types.T_json: @@ -290,12 +291,12 @@ func (d TypeDescriptor) arrowType() (arrow.DataType, error) { return &arrow.DurationType{Unit: arrow.Microsecond}, nil case types.T_array_float32: if d.Width <= 0 { - return nil, moerr.NewInternalErrorNoCtxf("invalid vecf32 dimension %d", d.Width) + return nil, udferr.Newf("invalid vecf32 dimension %d", d.Width) } return arrow.FixedSizeListOf(d.Width, arrow.PrimitiveTypes.Float32), nil case types.T_array_float64: if d.Width <= 0 { - return nil, moerr.NewInternalErrorNoCtxf("invalid vecf64 dimension %d", d.Width) + return nil, udferr.Newf("invalid vecf64 dimension %d", d.Width) } return arrow.FixedSizeListOf(d.Width, arrow.PrimitiveTypes.Float64), nil case types.T_date: @@ -305,7 +306,7 @@ func (d TypeDescriptor) arrowType() (arrow.DataType, error) { case types.T_timestamp: return sqlTemporalType(&arrow.TimestampType{Unit: arrow.Microsecond, TimeZone: "UTC"}), nil default: - return nil, moerr.NewInternalErrorNoCtxf("unsupported MatrixOne type id %d", d.TypeID) + return nil, udferr.Newf("unsupported MatrixOne type id %d", d.TypeID) } } func sqlTemporalType(value arrow.DataType) *arrow.StructType { @@ -332,10 +333,10 @@ func (d TypeDescriptor) ValidateField(field arrow.Field) error { return err } if field.Type == nil || !sameArrowType(field.Type, want.Type) || field.Nullable != want.Nullable { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: Arrow type %s does not match %s", field.Type, want.Type) + return udferr.Newf("TYPE_CONTRACT: Arrow type %s does not match %s", field.Type, want.Type) } if !field.Metadata.Equal(want.Metadata) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: Arrow logical metadata does not match the frozen descriptor") + return udferr.Newf("TYPE_CONTRACT: Arrow logical metadata does not match the frozen descriptor") } return nil } @@ -362,11 +363,11 @@ type encodedRecordBatch struct { Rows int64 } -var errArrowBatchTooLarge = moerr.NewInternalErrorNoCtx("Arrow record batch exceeds the configured limit") +var errArrowBatchTooLarge = udferr.New("Arrow record batch exceeds the configured limit") func EncodeRecordBatch(record arrow.RecordBatch, maxBytes int64) ([]ArrowFrame, error) { if record == nil || record.Schema() == nil || maxBytes <= 0 { - return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow record batch") + return nil, udferr.Newf("invalid Arrow record batch") } collector := &flightFrameCollector{maxBytes: maxBytes} writer := flight.NewRecordWriter(collector, ipc.WithSchema(record.Schema()), ipc.WithAllocator(memory.NewGoAllocator())) @@ -377,7 +378,7 @@ func EncodeRecordBatch(record arrow.RecordBatch, maxBytes int64) ([]ArrowFrame, return nil, errutil.Wrapf(err, "close Arrow record batch") } if len(collector.frames) < 2 { - return nil, moerr.NewInternalErrorNoCtxf("Arrow stream did not contain schema and record batch") + return nil, udferr.Newf("Arrow stream did not contain schema and record batch") } return collector.frames, nil } @@ -403,10 +404,10 @@ func (c *flightFrameCollector) reset(maxBytes, retainedBytes int64) { func (c *flightFrameCollector) Send(data *flight.FlightData) error { if data == nil || len(data.DataHeader) == 0 { - return moerr.NewInternalErrorNoCtxf("invalid Arrow Flight frame") + return udferr.Newf("invalid Arrow Flight frame") } if data.FlightDescriptor != nil || len(data.AppMetadata) != 0 { - return moerr.NewInternalErrorNoCtxf("unexpected metadata on Arrow payload frame") + return udferr.Newf("unexpected metadata on Arrow payload frame") } header := append([]byte(nil), data.DataHeader...) body := append([]byte(nil), data.DataBody...) @@ -435,10 +436,10 @@ type inputBatchWireEncoder struct { func (e *inputBatchWireEncoder) encode(record arrow.RecordBatch, maxBytes int64) ([]ArrowFrame, error) { if e == nil || e.closed || record == nil || maxBytes <= 0 { - return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow record batch encoder") + return nil, udferr.Newf("invalid Arrow record batch encoder") } if e.schema == nil || !record.Schema().Equal(e.schema) { - return nil, moerr.NewInternalErrorNoCtxf("Arrow record batch schema does not match the invocation schema") + return nil, udferr.Newf("Arrow record batch schema does not match the invocation schema") } if e.writer == nil { e.collector = &flightFrameCollector{} @@ -457,12 +458,12 @@ func (e *inputBatchWireEncoder) encode(record arrow.RecordBatch, maxBytes int64) e.captureSchema() if writerHadSchema { if len(e.collector.frames) != 1 { - return nil, moerr.NewInternalErrorNoCtxf("Arrow writer did not emit one record frame") + return nil, udferr.Newf("Arrow writer did not emit one record frame") } return []ArrowFrame{e.schemaFrame, e.collector.frames[0]}, nil } if len(e.collector.frames) != 2 || !e.schemaReady { - return nil, moerr.NewInternalErrorNoCtxf("Arrow stream did not contain schema and record batch") + return nil, udferr.Newf("Arrow stream did not contain schema and record batch") } return append([]ArrowFrame(nil), e.collector.frames...), nil } @@ -526,7 +527,7 @@ type inputBatchEncoder struct { func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBatchEncoder, error) { if len(inputs) != len(args) { - return nil, moerr.NewInternalErrorNoCtxf("invalid Python UDF input shape") + return nil, udferr.Newf("invalid Python UDF input shape") } fields := make([]arrow.Field, len(args)) descriptors := make([]TypeDescriptor, len(args)) @@ -546,14 +547,14 @@ func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBat fixedWidth = false } if inputs[i] == nil { - return nil, moerr.NewInternalErrorNoCtxf("input column %d is missing", i) + return nil, udferr.Newf("input column %d is missing", i) } actualType := inputs[i].GetType() if actualType == nil { - return nil, moerr.NewInternalErrorNoCtxf("input column %d has no type", i) + return nil, udferr.Newf("input column %d has no type", i) } if !actualType.Eq(typ) { - return nil, moerr.NewInternalErrorNoCtxf("input column %d type %s does not match the frozen argument type %s", i, actualType.DescString(), typ.DescString()) + return nil, udferr.Newf("input column %d type %s does not match the frozen argument type %s", i, actualType.DescString(), typ.DescString()) } if inputs[i].Length() > 0 && isVarlenaInputType(typ.Oid) { varlenaParameters[i] = vector.GenerateFunctionStrParameter(inputs[i]) @@ -572,7 +573,7 @@ func newInputBatchEncoder(inputs []*vector.Vector, args []types.Type) (*inputBat func (e *inputBatchEncoder) encode(record arrow.RecordBatch, maxBytes int64) ([]ArrowFrame, error) { if e == nil { - return nil, moerr.NewInternalErrorNoCtxf("invalid Python UDF input encoder") + return nil, udferr.Newf("invalid Python UDF input encoder") } if e.wire == nil { e.wire = &inputBatchWireEncoder{schema: e.schema} @@ -589,11 +590,11 @@ func (e *inputBatchEncoder) close() error { func (e *inputBatchEncoder) build(start, length int) (arrow.RecordBatch, *arrow.Schema, error) { if e == nil || start < 0 || length <= 0 { - return nil, nil, moerr.NewInternalErrorNoCtxf("invalid Python UDF input shape") + return nil, nil, udferr.Newf("invalid Python UDF input shape") } for i, input := range e.inputs { if input.Length() == 0 || (!input.IsConst() && input.Length() < start+length) { - return nil, nil, moerr.NewInternalErrorNoCtxf("input column %d is shorter than batch range", i) + return nil, nil, udferr.Newf("input column %d is shorter than batch range", i) } } if len(e.args) == 0 { @@ -649,7 +650,7 @@ func appendBulkFixedInputValue( return valid } if builder == nil || v == nil { - return false, moerr.NewInternalErrorNoCtxf("input column is missing") + return false, udferr.Newf("input column is missing") } switch typ.Oid { @@ -735,7 +736,7 @@ func bulkFixedInputWindow[T any](v *vector.Vector, start, length int) ([]T, erro values := vector.MustFixedColNoTypeCheck[T](v) if v.IsConst() { if len(values) == 0 { - return nil, moerr.NewInternalErrorNoCtxf("constant input column has no value") + return nil, udferr.Newf("constant input column has no value") } expanded := make([]T, length) for row := range expanded { @@ -744,7 +745,7 @@ func bulkFixedInputWindow[T any](v *vector.Vector, start, length int) ([]T, erro return expanded, nil } if start < 0 || length <= 0 || start > len(values) || length > len(values)-start { - return nil, moerr.NewInternalErrorNoCtxf("input column is shorter than batch range") + return nil, udferr.Newf("input column is shorter than batch range") } return values[start : start+length], nil } @@ -873,7 +874,7 @@ func appendInputValue( index := sourceRow(v, start, row) null := v.IsNull(uint64(index)) if !null && isVarlenaInputType(typ.Oid) && varlenaParameter == nil { - return moerr.NewInternalErrorNoCtxf("missing cached varlena input parameter") + return udferr.Newf("missing cached varlena input parameter") } if typ.Oid == types.T_date || typ.Oid == types.T_datetime || typ.Oid == types.T_timestamp { return appendTemporalInput(builder.(*array.StructBuilder), v, typ, index, null) @@ -1028,7 +1029,7 @@ func appendInputValue( b.ValueBuilder().(*array.Float64Builder).AppendValues(vector.GetArrayAt[float64](v, index), nil) } default: - return moerr.NewInternalErrorNoCtxf("unsupported input type %s", typ.String()) + return udferr.Newf("unsupported input type %s", typ.String()) } return nil } @@ -1101,7 +1102,7 @@ func appendTemporalInput(builder *array.StructBuilder, v *vector.Vector, typ typ builder.FieldBuilder(0).(*array.BooleanBuilder).Append(zero) builder.FieldBuilder(1).(*array.TimestampBuilder).Append(arrow.Timestamp(raw)) default: - return moerr.NewInternalErrorNoCtxf("unsupported temporal type %s", typ.String()) + return udferr.Newf("unsupported temporal type %s", typ.String()) } return nil } @@ -1114,24 +1115,24 @@ func decimal64ToArrow(value types.Decimal64) decimal128.Num { func DecodeRecordBatch(schemaFrame, batchFrame ArrowFrame, maxBytes int64) (arrow.RecordBatch, error) { if len(schemaFrame.Header) == 0 || len(batchFrame.Header) == 0 || maxBytes <= 0 { - return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow output frames") + return nil, udferr.Newf("invalid Arrow output frames") } if len(schemaFrame.Body) != 0 { - return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow schema frame body") + return nil, udferr.Newf("invalid Arrow schema frame body") } schemaInfo, err := arrowipc.InspectMessage(context.Background(), schemaFrame.Header, arrowipc.ValidationOptions{MaxMetadataBytes: arrowipc.DefaultMaxMetadataBytes, MaxBodyBytes: 0, BodyEnvelopeBytes: 0, MaxDecodedRecordBytes: 1}) if err != nil { return nil, err } if schemaInfo.HeaderType != arrowipc.MessageHeaderSchema { - return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow schema frame header %d", schemaInfo.HeaderType) + return nil, udferr.Newf("invalid Arrow schema frame header %d", schemaInfo.HeaderType) } batchInfo, err := arrowipc.InspectMessage(context.Background(), batchFrame.Header, arrowipc.ValidationOptions{MaxMetadataBytes: arrowipc.DefaultMaxMetadataBytes, MaxBodyBytes: maxBytes, BodyEnvelopeBytes: int64(len(batchFrame.Body)), Body: batchFrame.Body, ValidateBody: true, MaxDecodedRecordBytes: maxBytes}) if err != nil { return nil, err } if batchInfo.HeaderType != arrowipc.MessageHeaderRecordBatch { - return nil, moerr.NewInternalErrorNoCtxf("invalid Arrow record frame header %d", batchInfo.HeaderType) + return nil, udferr.Newf("invalid Arrow record frame header %d", batchInfo.HeaderType) } // The snapshot is already the immutable validation/publication backing. // Feed that backing directly to Arrow's stream reader instead of assembling @@ -1145,11 +1146,11 @@ func DecodeRecordBatch(schemaFrame, batchFrame ArrowFrame, maxBytes int64) (arro } defer reader.Release() if !reader.Next() { - return nil, moerr.NewInternalErrorNoCtxf("decode Arrow output: %v", reader.Err()) + return nil, udferr.Newf("decode Arrow output: %v", reader.Err()) } record := reader.RecordBatch() if record == nil { - return nil, moerr.NewInternalErrorNoCtxf("decode Arrow output: missing record batch") + return nil, udferr.Newf("decode Arrow output: missing record batch") } record.Retain() return record, nil @@ -1240,10 +1241,10 @@ func (r *ipcStreamReader) Read(dst []byte) (int, error) { func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vector.FunctionResultWrapper, mp *mpool.MPool) error { if input == nil { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: missing Arrow result") + return udferr.Newf("TYPE_CONTRACT: missing Arrow result") } if result == nil { - return moerr.NewInternalErrorNoCtxf("python udf: missing result wrapper") + return udferr.Newf("python udf: missing result wrapper") } // AppendArrowResult is also the public adapter boundary used by runtimes // other than the Flight Gateway. Do not let an invalid manually-built @@ -1262,7 +1263,7 @@ func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vect return nil } if mp == nil { - return moerr.NewInternalErrorNoCtxf("python udf: missing memory pool for Arrow result") + return udferr.Newf("python udf: missing memory pool for Arrow result") } result.GetResultVector().SetTypeScale(descriptor.Scale) typ := types.T(descriptor.TypeID) @@ -1348,7 +1349,7 @@ func AppendArrowResult(descriptor TypeDescriptor, input arrow.Array, result vect return err } default: - return moerr.NewInternalErrorNoCtxf("unsupported output type %s", typ.String()) + return udferr.Newf("unsupported output type %s", typ.String()) } } return nil @@ -1449,7 +1450,7 @@ func appendFloat32ArrayResult(input *array.FixedSizeList, row int, null bool, re items := make([]float32, end-start) for i := start; i < end; i++ { if values.IsNull(int(i)) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: vector child at row %d is null", row) + return udferr.Newf("TYPE_CONTRACT: vector child at row %d is null", row) } items[i-start] = values.Value(int(i)) } @@ -1465,7 +1466,7 @@ func appendFloat64ArrayResult(input *array.FixedSizeList, row int, null bool, re items := make([]float64, end-start) for i := start; i < end; i++ { if values.IsNull(int(i)) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: vector child at row %d is null", row) + return udferr.Newf("TYPE_CONTRACT: vector child at row %d is null", row) } items[i-start] = values.Value(int(i)) } @@ -1477,14 +1478,14 @@ func validateArrayType(descriptor TypeDescriptor, input arrow.Array) error { return err } if !sameArrowType(input.DataType(), want) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: output Arrow type %s does not match %s", input.DataType(), want) + return udferr.Newf("TYPE_CONTRACT: output Arrow type %s does not match %s", input.DataType(), want) } return nil } func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) error { if input == nil { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: missing Arrow result") + return udferr.Newf("TYPE_CONTRACT: missing Arrow result") } for row := 0; row < input.Len(); row++ { if input.IsNull(row) { @@ -1493,7 +1494,7 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro switch types.T(descriptor.TypeID) { case types.T_char, types.T_varchar, types.T_text: if descriptor.Width > 0 && int32(utf8.RuneCountInString(input.(*array.String).Value(row))) > descriptor.Width { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: string row %d exceeds width %d", row, descriptor.Width) + return udferr.Newf("TYPE_CONTRACT: string row %d exceeds width %d", row, descriptor.Width) } case types.T_json: value := input.(*array.String).Value(row) @@ -1502,16 +1503,16 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro return errutil.Wrapf(err, "TYPE_CONTRACT: JSON row %d is not valid canonical text", row) } if canonical != value { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: JSON row %d is not canonical text", row) + return udferr.Newf("TYPE_CONTRACT: JSON row %d is not canonical text", row) } case types.T_binary, types.T_varbinary, types.T_blob: if descriptor.Width > 0 && int32(len(input.(*array.Binary).Value(row))) > descriptor.Width { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: binary row %d exceeds width %d", row, descriptor.Width) + return udferr.Newf("TYPE_CONTRACT: binary row %d exceeds width %d", row, descriptor.Width) } case types.T_time: value := types.Time(input.(*array.Duration).Value(row)) if !types.IsMySQLTime(value) || !hasExactMicrosecondScale(int64(value), descriptor.Scale) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: TIME row %d is outside the declared SQL domain", row) + return udferr.Newf("TYPE_CONTRACT: TIME row %d is outside the declared SQL domain", row) } case types.T_decimal64, types.T_decimal128: precision := descriptor.Width @@ -1522,7 +1523,7 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro } } if !input.(*array.Decimal128).Value(row).FitsInPrecision(precision) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: decimal row %d exceeds precision %d", row, precision) + return udferr.Newf("TYPE_CONTRACT: decimal row %d exceeds precision %d", row, precision) } case types.T_array_float32: list := input.(*array.FixedSizeList) @@ -1530,7 +1531,7 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro start, end := list.ValueOffsets(row) for child := start; child < end; child++ { if values.IsNull(int(child)) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: vector child at row %d is null", row) + return udferr.Newf("TYPE_CONTRACT: vector child at row %d is null", row) } } case types.T_array_float64: @@ -1539,54 +1540,54 @@ func validateArrowValueDomain(descriptor TypeDescriptor, input arrow.Array) erro start, end := list.ValueOffsets(row) for child := start; child < end; child++ { if values.IsNull(int(child)) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: vector child at row %d is null", row) + return udferr.Newf("TYPE_CONTRACT: vector child at row %d is null", row) } } case types.T_date, types.T_datetime, types.T_timestamp: structValue := input.(*array.Struct) zeroField, valueField := structValue.Field(0), structValue.Field(1) if zeroField.IsNull(row) || valueField.IsNull(row) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: temporal row %d has a null child", row) + return udferr.Newf("TYPE_CONTRACT: temporal row %d has a null child", row) } zero := zeroField.(*array.Boolean).Value(row) switch types.T(descriptor.TypeID) { case types.T_date: value := valueField.(*array.Date32).Value(row) if zero && value != 0 { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATE zero row %d has a non-zero placeholder", row) + return udferr.Newf("TYPE_CONTRACT: DATE zero row %d has a non-zero placeholder", row) } if !zero { date := types.DaysFromUnixEpochToDate(int32(value)) year, month, day, _ := date.Calendar(true) if !types.ValidDate(year, month, day) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATE row %d is outside the SQL domain", row) + return udferr.Newf("TYPE_CONTRACT: DATE row %d is outside the SQL domain", row) } } case types.T_datetime: value := valueField.(*array.Timestamp).Value(row) if zero && value != 0 { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATETIME zero row %d has a non-zero placeholder", row) + return udferr.Newf("TYPE_CONTRACT: DATETIME zero row %d has a non-zero placeholder", row) } if !zero { absolute, ok := addUnixEpoch(int64(value)) if !ok || !hasExactMicrosecondScale(absolute, descriptor.Scale) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATETIME row %d is outside the declared SQL domain", row) + return udferr.Newf("TYPE_CONTRACT: DATETIME row %d is outside the declared SQL domain", row) } datetime := types.Datetime(absolute) year, month, day, _ := datetime.ToDate().Calendar(true) if !types.ValidDatetime(year, month, day) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: DATETIME row %d is outside the SQL domain", row) + return udferr.Newf("TYPE_CONTRACT: DATETIME row %d is outside the SQL domain", row) } } case types.T_timestamp: value := valueField.(*array.Timestamp).Value(row) if zero && value != 0 { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: TIMESTAMP zero row %d has a non-zero placeholder", row) + return udferr.Newf("TYPE_CONTRACT: TIMESTAMP zero row %d has a non-zero placeholder", row) } if !zero { absolute, ok := addUnixEpoch(int64(value)) if !ok || absolute < int64(types.TimestampMinValue) || absolute > int64(types.TimestampMaxValue) || !hasExactMicrosecondScale(absolute, descriptor.Scale) { - return moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: TIMESTAMP row %d is outside the declared SQL domain", row) + return udferr.Newf("TYPE_CONTRACT: TIMESTAMP row %d is outside the declared SQL domain", row) } } } @@ -1616,7 +1617,7 @@ func hasExactMicrosecondScale(value int64, scale int32) bool { func decimalFromArray(value decimal128.Num, narrow bool) (any, error) { high, low := uint64(value.HighBits()), value.LowBits() if narrow && !decimal128FitsDecimal64(high, low) { - return nil, moerr.NewInternalErrorNoCtxf("TYPE_CONTRACT: Decimal128 result does not fit Decimal64") + return nil, udferr.Newf("TYPE_CONTRACT: Decimal128 result does not fit Decimal64") } if narrow { return types.Decimal64(low), nil diff --git a/pkg/udf/python/artifact.go b/pkg/udf/python/artifact.go index c0175ae01d147..2c40c9a95edb1 100644 --- a/pkg/udf/python/artifact.go +++ b/pkg/udf/python/artifact.go @@ -17,10 +17,12 @@ package python import ( "context" "fmt" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "strings" "unicode/utf8" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/defines" "github.com/matrixorigin/matrixone/pkg/fileservice" @@ -69,7 +71,7 @@ var _ ArtifactStore = (*FileArtifactStore)(nil) func NewFileArtifactStore(fs fileservice.FileService, maxSize int64) (*FileArtifactStore, error) { if fs == nil { - return nil, moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact store has no FileService") + return nil, udferr.Newf("RESOURCE_UNAVAILABLE: Python artifact store has no FileService") } shared, err := fileservice.Get[fileservice.FileService](fs, defines.SharedFileServiceName) if err != nil { @@ -79,7 +81,7 @@ func NewFileArtifactStore(fs fileservice.FileService, maxSize int64) (*FileArtif maxSize = DefaultMaxArtifactBytes } if maxSize > DefaultMaxArtifactBytes { - return nil, moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact limit %d exceeds the current contract limit %d", maxSize, DefaultMaxArtifactBytes) + return nil, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact limit %d exceeds the current contract limit %d", maxSize, DefaultMaxArtifactBytes) } return &FileArtifactStore{fs: shared, maxSize: maxSize}, nil } @@ -119,7 +121,7 @@ func (s *FileArtifactStore) Publish(ctx context.Context, accountID uint64, handl return "", errutil.Wrapf(resolveErr, "python artifact publish %s found an invalid existing object", digest) } if existing != source { - return "", moerr.NewInternalErrorNoCtxf("python artifact publish %s encountered a digest collision", digest) + return "", udferr.Newf("python artifact publish %s encountered a digest collision", digest) } return digest, nil } @@ -132,10 +134,10 @@ func (s *FileArtifactStore) Resolve(ctx context.Context, accountID uint64, handl ctx = context.Background() } if strings.TrimSpace(handler) == "" { - return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact has no handler") + return "", udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact has no handler") } if !udf.IsSHA256Digest(digest) { - return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest is invalid") + return "", udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest is invalid") } path := artifactPath(accountID, digest) entry, err := s.fs.StatFile(ctx, path) @@ -143,7 +145,7 @@ func (s *FileArtifactStore) Resolve(ctx context.Context, accountID uint64, handl return "", errutil.Wrapf(err, "RESOURCE_UNAVAILABLE: Python artifact %s is unavailable", digest) } if entry == nil || entry.IsDir || entry.Size <= 0 || entry.Size > s.maxSize { - return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s has invalid size", digest) + return "", udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s has invalid size", digest) } data := make([]byte, entry.Size) readVector := &fileservice.IOVector{ @@ -154,43 +156,43 @@ func (s *FileArtifactStore) Resolve(ctx context.Context, accountID uint64, handl return "", errutil.Wrapf(err, "RESOURCE_UNAVAILABLE: Python artifact %s cannot be read", digest) } if len(readVector.Entries) != 1 || int64(len(readVector.Entries[0].Data)) != entry.Size { - return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s changed size while reading", digest) + return "", udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s changed size while reading", digest) } source := string(readVector.Entries[0].Data) if !utf8.ValidString(source) { - return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s is not valid UTF-8", digest) + return "", udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s is not valid UTF-8", digest) } if udf.PythonInlineArtifactDigest(handler, source) != digest { - return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s content digest mismatch", digest) + return "", udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact %s content digest mismatch", digest) } return source, nil } func validateArtifactInput(accountID uint64, handler, source string, maxSize int64) (string, error) { if maxSize <= 0 { - return "", moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact store has an invalid size limit") + return "", udferr.Newf("RESOURCE_UNAVAILABLE: Python artifact store has an invalid size limit") } if strings.TrimSpace(handler) == "" { - return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact has no handler") + return "", udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact has no handler") } if source == "" { - return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is empty") + return "", udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is empty") } if !utf8.ValidString(source) { - return "", moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is not valid UTF-8") + return "", udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is not valid UTF-8") } if int64(len([]byte(source))) > maxSize { - return "", moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", maxSize) + return "", udferr.Newf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", maxSize) } return udf.PythonInlineArtifactDigest(handler, source), nil } func (s *FileArtifactStore) validate() error { if s == nil || s.fs == nil { - return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact store has no FileService") + return udferr.Newf("RESOURCE_UNAVAILABLE: Python artifact store has no FileService") } if s.maxSize <= 0 { - return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact store has an invalid size limit") + return udferr.Newf("RESOURCE_UNAVAILABLE: Python artifact store has an invalid size limit") } return nil } diff --git a/pkg/udf/python/definition.go b/pkg/udf/python/definition.go index 3a2db3e2bbc65..a2617025e597e 100644 --- a/pkg/udf/python/definition.go +++ b/pkg/udf/python/definition.go @@ -18,7 +18,8 @@ import ( "crypto/sha256" "encoding/hex" "encoding/json" - "github.com/matrixorigin/matrixone/pkg/common/moerr" + + "github.com/matrixorigin/matrixone/pkg/udf/udferr" "github.com/matrixorigin/matrixone/pkg/util/errutil" ) @@ -56,7 +57,7 @@ func DefinitionFingerprint( mode == "" || nullPolicy == "" || abiContract == "" || adapterVersion == "" || sdkVersion == "" || artifactDigest == "" || environmentDigest == "" { - return "", moerr.NewInternalErrorNoCtxf("python definition fingerprint has incomplete metadata") + return "", udferr.Newf("python definition fingerprint has incomplete metadata") } for index, descriptor := range args { if err := descriptor.Validate(); err != nil { diff --git a/pkg/udf/python/gateway.go b/pkg/udf/python/gateway.go index fddb53d318c23..861885bc9dc7e 100644 --- a/pkg/udf/python/gateway.go +++ b/pkg/udf/python/gateway.go @@ -21,8 +21,6 @@ import ( "encoding/hex" "encoding/json" "errors" - "github.com/matrixorigin/matrixone/pkg/common/moerr" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "io" "strconv" "strings" @@ -30,6 +28,9 @@ import ( "time" "unicode/utf8" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/apache/arrow-go/v18/arrow/flight/gen/flight" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -60,7 +61,7 @@ const ( statusOK = "OK" ) -var errGatewayClosed = moerr.NewInternalErrorNoCtx("python udf gateway is closed") +var errGatewayClosed = udferr.New("python udf gateway is closed") var _ udf.RuntimeDefinitionValidator = (*Gateway)(nil) var _ udf.RuntimeStatusProvider = (*Gateway)(nil) @@ -111,7 +112,7 @@ func NewGateway(cfg ClientConfig) (*Gateway, error) { // rejected at this boundary. func NewGatewayWithArtifactStore(cfg ClientConfig, resolver ArtifactResolver) (*Gateway, error) { if resolver == nil { - return nil, moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") + return nil, udferr.Newf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") } return newGateway(cfg, resolver, false) } @@ -175,13 +176,13 @@ func (g *Gateway) CheckLanguageReady(ctx context.Context, language string) error ctx = context.Background() } if language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("python udf: unsupported readiness language %q", language) + return udferr.Newf("python udf: unsupported readiness language %q", language) } if !g.cfg.Enabled { - return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") + return udferr.Newf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") } if !g.cfg.AllowUnisolated { - return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") + return udferr.Newf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") } requestCtx, release := g.withLifecycleContext(ctx) defer release() @@ -304,10 +305,10 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin return errGatewayClosed } if !g.cfg.Enabled { - return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") + return udferr.Newf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") } if !g.cfg.AllowUnisolated { - return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") + return udferr.Newf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") } requestCtx, release := g.withLifecycleContext(ctx) defer release() @@ -317,38 +318,38 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin defer cancel() } if definition == nil { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: nil Python routine definition") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: nil Python routine definition") } if definition.Language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported UDF language %q", definition.Language) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: unsupported UDF language %q", definition.Language) } if strings.TrimSpace(definition.Handler) == "" { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python handler is required") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python handler is required") } if strings.Contains(definition.Handler, ":") { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires the immutable artifact catalog") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires the immutable artifact catalog") } if definition.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion || definition.ABIContract != udf.PythonABIContract || definition.AdapterVersion != udf.PythonAdapterVersion || definition.SDKVersion != udf.PythonSDKVersion { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition contract is not supported") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python definition contract is not supported") } if definition.Mode != ModeScalar && definition.Mode != ModeVector { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python mode %q", definition.Mode) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python mode %q", definition.Mode) } if definition.NullPolicy != NullCallHandler && definition.NullPolicy != NullReturnNull { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python NULL policy %q", definition.NullPolicy) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python NULL policy %q", definition.NullPolicy) } if !udf.IsSHA256Digest(definition.ArtifactDigest) || !udf.IsSHA256Digest(definition.EnvironmentDigest) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition digest is invalid") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python definition digest is invalid") } currentEnvironment, err := udf.PythonEnvironmentDigest() if err != nil || currentEnvironment != definition.EnvironmentDigest { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the current contract") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the current contract") } if !udf.IsSHA256Digest(definition.DefinitionFingerprint) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint is invalid") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint is invalid") } args := make([]TypeDescriptor, len(definition.Args)) for index, typ := range definition.Args { @@ -372,7 +373,7 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint cannot be computed") } if definition.DefinitionFingerprint != expectedFingerprint { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition") } source := definition.Source @@ -384,20 +385,20 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin return resolveErr } if source != "" && source != resolved { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source does not match the immutable artifact") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source does not match the immutable artifact") } source = resolved } else if !g.allowInlineSource { - return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") + return udferr.Newf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") } if source == "" || !utf8.ValidString(source) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is empty or not valid UTF-8") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is empty or not valid UTF-8") } if int64(len([]byte(source))) > DefaultMaxArtifactBytes { - return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", DefaultMaxArtifactBytes) + return udferr.Newf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", DefaultMaxArtifactBytes) } if udf.PythonInlineArtifactDigest(definition.Handler, source) != definition.ArtifactDigest { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") } client, err := g.flightClient() @@ -449,7 +450,7 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin } if result == nil { g.invalidateCapabilities(capability.generation) - return moerr.NewInternalErrorNoCtxf("python udf: empty definition validation response") + return udferr.Newf("python udf: empty definition validation response") } var response definitionValidationResponse decoder := json.NewDecoder(bytes.NewReader(result.Body)) @@ -461,30 +462,30 @@ func (g *Gateway) ValidateDefinition(ctx context.Context, definition *udf.Routin var trailing any if err := decoder.Decode(&trailing); err != io.EOF { g.invalidateCapabilities(capability.generation) - return moerr.NewInternalErrorNoCtxf("python udf: definition validation response has trailing JSON") + return udferr.Newf("python udf: definition validation response has trailing JSON") } if response.Status == "ERROR" { if _, err := stream.Recv(); err != io.EOF { g.invalidateCapabilities(capability.generation) if err == nil { - return moerr.NewInternalErrorNoCtxf("python udf: definition validation returned multiple results") + return udferr.Newf("python udf: definition validation returned multiple results") } return errutil.Wrapf(err, "python udf: definition validation stream") } if response.Reason == "" { - return moerr.NewInternalErrorNoCtxf("USER_CODE: Python definition validation failed") + return udferr.Newf("USER_CODE: Python definition validation failed") } - return moerr.NewInternalErrorNoCtx(response.Reason) + return udferr.New(response.Reason) } if response.Status != statusOK || response.ArtifactDigest != definition.ArtifactDigest || response.DefinitionFingerprint != definition.DefinitionFingerprint { g.invalidateCapabilities(capability.generation) - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition validation returned an invalid result") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python definition validation returned an invalid result") } if _, err := stream.Recv(); err != io.EOF { g.invalidateCapabilities(capability.generation) if err == nil { - return moerr.NewInternalErrorNoCtxf("python udf: definition validation returned multiple results") + return udferr.Newf("python udf: definition validation returned multiple results") } return errutil.Wrapf(err, "python udf: definition validation stream") } @@ -616,22 +617,22 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return errGatewayClosed } if !g.cfg.Enabled { - return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") + return udferr.Newf("RESOURCE_UNAVAILABLE: Python UDF runtime is disabled") } if !g.cfg.AllowUnisolated { - return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") + return udferr.Newf("RESOURCE_UNAVAILABLE: Python UDF runtime requires explicit unisolated opt-in") } requestCtx, release := g.withLifecycleContext(ctx) defer release() streamCtx, cancel := context.WithTimeout(requestCtx, g.cfg.RequestTimeout) defer cancel() if invocation == nil || result == nil || mp == nil { - return moerr.NewInternalErrorNoCtxf("python udf: nil invocation, result, or memory pool") + return udferr.Newf("python udf: nil invocation, result, or memory pool") } execution := *invocation if g.artifactResolver != nil { if execution.Source != "" { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: typed Python invocation contains source; use its immutable artifact digest") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: typed Python invocation contains source; use its immutable artifact digest") } // Validate the identity, semantic contract, descriptors, and resource // shape before resolving an account-scoped artifact. Resolution is a @@ -651,7 +652,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return err } } else if !g.allowInlineSource && execution.Source == "" { - return moerr.NewInternalErrorNoCtxf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") + return udferr.Newf("RESOURCE_UNAVAILABLE: Python artifact resolver is not configured") } if err := validateInvocation(&execution); err != nil { return err @@ -713,7 +714,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul // invalidation below forces a fresh handshake on the next call. workerLeaseEpoch := capability.response.LeaseEpoch if workerLeaseEpoch == 0 { - return moerr.NewInternalErrorNoCtxf("python udf: capability handshake did not return a worker lease epoch") + return udferr.Newf("python udf: capability handshake did not return a worker lease epoch") } execution.Tuple.LeaseEpoch = workerLeaseEpoch if err := validateInvocation(&execution); err != nil { @@ -798,7 +799,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return err } if len(batch.Frames) != 2 { - return moerr.NewInternalErrorNoCtxf("python udf: input batch contains %d Arrow frames", len(batch.Frames)) + return udferr.Newf("python udf: input batch contains %d Arrow frames", len(batch.Frames)) } if batchIndex == 0 { inputSchema = append([]byte(nil), batch.Frames[0].Header...) @@ -806,7 +807,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul return err } } else if !bytes.Equal(inputSchema, batch.Frames[0].Header) { - return moerr.NewInternalErrorNoCtxf("python udf: input batches do not share one Arrow schema") + return udferr.Newf("python udf: input batches do not share one Arrow schema") } sequenceNumber := batchIndex + 1 if err := sequence.AcceptInput(sequenceNumber); err != nil { @@ -852,7 +853,7 @@ func (g *Gateway) Execute(ctx context.Context, invocation *udf.Invocation, resul } } if !inputEnded || lastSequence != batchIndex { - return moerr.NewInternalErrorNoCtxf("python udf: input stream did not reach EndInput") + return udferr.Newf("python udf: input stream did not reach EndInput") } // Close the local Arrow writer before accepting the worker's terminal // Finish. If finalizing the local input owner fails, the admission cleanup @@ -887,7 +888,7 @@ type invocationAdmission struct { func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmission, error) { if invocation == nil { - return nil, moerr.NewInternalErrorNoCtxf("python udf: cannot admit a nil invocation") + return nil, udferr.Newf("python udf: cannot admit a nil invocation") } if err := invocation.Tuple.Validate(); err != nil { return nil, err @@ -924,7 +925,7 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss if ledger == nil || active == nil { g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() - return nil, moerr.NewInternalErrorNoCtxf("python udf: admission state is not initialized") + return nil, udferr.Newf("python udf: admission state is not initialized") } // Expire is intentionally limited to tombstones by TerminalLedger. An // active invocation can leave this path only through finish/abandon. @@ -955,7 +956,7 @@ func (g *Gateway) admitInvocation(invocation *udf.Invocation) (*invocationAdmiss credit.ReleaseUnused() g.releaseGroupClaim(groupKey, invocation.Tuple.GroupEpoch) g.mu.Unlock() - return nil, moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF active invocation slots are full") + return nil, udferr.Newf("RESOURCE_EXHAUSTED: Python UDF active invocation slots are full") } var releaseOnce sync.Once @@ -1309,7 +1310,7 @@ func (g *Gateway) ensureCapabilitySnapshot(ctx context.Context, client flight.Fl if g.closed { err = errGatewayClosed } else if p.generation != g.capabilityGeneration { - err = moerr.NewInternalErrorNoCtx("python udf: capability probe invalidated") + err = udferr.New("python udf: capability probe invalidated") } else if ctx.Err() != nil { err = ctx.Err() } @@ -1339,7 +1340,7 @@ func readCapabilities(ctx context.Context, client flight.FlightServiceClient) (* return nil, errutil.Wrapf(err, "python udf: capability handshake response") } if result == nil { - return nil, moerr.NewInternalErrorNoCtxf("python udf: empty capability handshake response") + return nil, udferr.Newf("python udf: empty capability handshake response") } var response capabilityResponse decoder := json.NewDecoder(bytes.NewReader(result.Body)) @@ -1349,14 +1350,14 @@ func readCapabilities(ctx context.Context, client flight.FlightServiceClient) (* } var trailing any if err := decoder.Decode(&trailing); err != io.EOF { - return nil, moerr.NewInternalErrorNoCtxf("python udf: capability handshake has trailing JSON") + return nil, udferr.Newf("python udf: capability handshake has trailing JSON") } if err := validateCapabilities(response); err != nil { return nil, err } if _, err := stream.Recv(); err != io.EOF { if err == nil { - return nil, moerr.NewInternalErrorNoCtxf("python udf: capability handshake returned multiple results") + return nil, udferr.Newf("python udf: capability handshake returned multiple results") } return nil, errutil.Wrapf(err, "python udf: capability handshake stream") } @@ -1399,11 +1400,11 @@ func validateCapabilities(response capabilityResponse) error { response.MaxAccountHandlerProcesses != DefaultWorkerMaxAccountHandlers || response.MaxOwnerHandlerProcesses != DefaultWorkerMaxOwnerHandlers || response.LeaseEpoch == 0 { - return moerr.NewInternalErrorNoCtxf("python udf: worker capability contract does not match the current contract") + return udferr.Newf("python udf: worker capability contract does not match the current contract") } if !sameStrings(response.Modes, []string{ModeScalar, ModeVector}) || !sameStrings(response.NullPolicies, []string{NullCallHandler, NullReturnNull}) { - return moerr.NewInternalErrorNoCtxf("python udf: worker capability set does not match the current contract") + return udferr.Newf("python udf: worker capability set does not match the current contract") } return nil } @@ -1428,20 +1429,12 @@ func sameStrings(actual, expected []string) bool { return true } -func encodeInputBatch(inputs []*vector.Vector, args []types.Type, start, remaining, maxBytes, maxRows int64) (encodedRecordBatch, error) { - encoder, err := newInputBatchEncoder(inputs, args) - if err != nil { - return encodedRecordBatch{}, err - } - return encodeInputBatchWithEncoder(encoder, start, remaining, maxBytes, maxRows) -} - func encodeInputBatchWithEncoder(encoder *inputBatchEncoder, start, remaining, maxBytes, maxRows int64) (encodedRecordBatch, error) { if start < 0 || remaining <= 0 { - return encodedRecordBatch{}, moerr.NewInternalErrorNoCtxf("invalid Python UDF input batch range") + return encodedRecordBatch{}, udferr.Newf("invalid Python UDF input batch range") } if maxRows <= 0 { - return encodedRecordBatch{}, moerr.NewInternalErrorNoCtxf("invalid Python UDF max batch rows") + return encodedRecordBatch{}, udferr.Newf("invalid Python UDF max batch rows") } if remaining > maxRows { remaining = maxRows @@ -1452,7 +1445,7 @@ func encodeInputBatchWithEncoder(encoder *inputBatchEncoder, start, remaining, m // slice keeps the same backing buffers, and every candidate is still encoded // and checked against maxBytes before publication. if encoder == nil { - return encodedRecordBatch{}, moerr.NewInternalErrorNoCtxf("invalid Python UDF input encoder") + return encodedRecordBatch{}, udferr.Newf("invalid Python UDF input encoder") } if encoder.fixedWidth { record, _, err := encoder.build(int(start), int(remaining)) @@ -1562,17 +1555,17 @@ func (g *Gateway) receiveResultBatch( data, err := stream.Recv() if err != nil { if err == io.EOF { - return 0, moerr.NewInternalErrorNoCtxf("python udf: exchange ended before result sequence %d", sequenceNumber) + return 0, udferr.Newf("python udf: exchange ended before result sequence %d", sequenceNumber) } return 0, errutil.Wrapf(err, "python udf: receive result") } if data == nil || (len(data.AppMetadata) == 0 && len(data.DataHeader) == 0) { - return 0, moerr.NewInternalErrorNoCtxf("python udf: empty Flight result") + return 0, udferr.Newf("python udf: empty Flight result") } if len(data.DataHeader) > 0 { if *schemaFrame == nil { if len(data.DataBody) != 0 { - return 0, moerr.NewInternalErrorNoCtxf("python udf: result schema contains a body") + return 0, udferr.Newf("python udf: result schema contains a body") } *schemaFrame = &ArrowFrame{Header: append([]byte(nil), data.DataHeader...)} if len(data.AppMetadata) != 0 { @@ -1584,17 +1577,17 @@ func (g *Gateway) receiveResultBatch( continue } if !*schemaReady { - return 0, moerr.NewInternalErrorNoCtxf("python udf: result schema metadata was not received") + return 0, udferr.Newf("python udf: result schema metadata was not received") } control, err := protocol.UnmarshalControl(data.AppMetadata) if err != nil { return 0, err } if control.Tuple != tuple || control.Kind != "ResultBatch" || control.Sequence != sequenceNumber { - return 0, moerr.NewInternalErrorNoCtxf("python udf: unexpected result sequence %d", control.Sequence) + return 0, udferr.Newf("python udf: unexpected result sequence %d", control.Sequence) } if !inputConsumed { - return 0, moerr.NewInternalErrorNoCtxf("python udf: result sequence %d arrived before InputConsumed", sequenceNumber) + return 0, udferr.Newf("python udf: result sequence %d arrived before InputConsumed", sequenceNumber) } if err := sequence.AcceptResult(control.Sequence); err != nil { return 0, err @@ -1618,11 +1611,11 @@ func (g *Gateway) receiveResultBatch( decodedRows := decoded.NumRows() if decoded.NumCols() != 1 || decodedRows <= 0 || decodedRows != expectedRows { decoded.Release() - return 0, moerr.NewInternalErrorNoCtxf("python udf: result batch row count %d, expected %d", decodedRows, expectedRows) + return 0, udferr.Newf("python udf: result batch row count %d, expected %d", decodedRows, expectedRows) } if decoded.Schema().Field(0).Name != "result" { decoded.Release() - return 0, moerr.NewInternalErrorNoCtxf("python udf: result field has unexpected name %q", decoded.Schema().Field(0).Name) + return 0, udferr.Newf("python udf: result field has unexpected name %q", decoded.Schema().Field(0).Name) } if err := returnDescriptor.ValidateField(decoded.Schema().Field(0)); err != nil { decoded.Release() @@ -1634,7 +1627,7 @@ func (g *Gateway) receiveResultBatch( } if limit := g.cfg.MaxInvocationResultBytes; limit > 0 && result.GetResultVector() != nil && int64(result.GetResultVector().Size()) > limit { decoded.Release() - return 0, moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF invocation result exceeds %d bytes", limit) + return 0, udferr.Newf("RESOURCE_EXHAUSTED: Python UDF invocation result exceeds %d bytes", limit) } decoded.Release() if err := g.action(ctx, client, "AcknowledgeResults", protocol.Control{Kind: "AcknowledgeResults", Tuple: tuple, AckSequence: control.Sequence}); err != nil { @@ -1646,40 +1639,40 @@ func (g *Gateway) receiveResultBatch( return int(expectedRows), nil } if len(data.DataBody) != 0 { - return 0, moerr.NewInternalErrorNoCtxf("python udf: control frame contains an Arrow body") + return 0, udferr.Newf("python udf: control frame contains an Arrow body") } control, err := protocol.UnmarshalControl(data.AppMetadata) if err != nil { return 0, err } if control.Tuple != tuple { - return 0, moerr.NewInternalErrorNoCtxf("python udf: result tuple changed") + return 0, udferr.Newf("python udf: result tuple changed") } switch control.Kind { case "ResultSchema": if *schemaFrame == nil || *schemaReady { - return 0, moerr.NewInternalErrorNoCtxf("python udf: invalid result schema metadata") + return 0, udferr.Newf("python udf: invalid result schema metadata") } *schemaReady = true continue case "InputConsumed": if control.Sequence != sequenceNumber { - return 0, moerr.NewInternalErrorNoCtxf("python udf: input sequence %d was consumed while waiting for result %d", control.Sequence, sequenceNumber) + return 0, udferr.Newf("python udf: input sequence %d was consumed while waiting for result %d", control.Sequence, sequenceNumber) } if control.ReleasedBatches != 1 || control.ReleasedBytes <= 0 || control.ReleasedBytes > g.cfg.MaxBatchBytes { - return 0, moerr.NewInternalErrorNoCtxf("python udf: input sequence %d released invalid bytes/batches (%d/%d)", sequenceNumber, control.ReleasedBytes, control.ReleasedBatches) + return 0, udferr.Newf("python udf: input sequence %d released invalid bytes/batches (%d/%d)", sequenceNumber, control.ReleasedBytes, control.ReleasedBatches) } if inputConsumed { - return 0, moerr.NewInternalErrorNoCtxf("python udf: input sequence %d was consumed more than once", sequenceNumber) + return 0, udferr.Newf("python udf: input sequence %d was consumed more than once", sequenceNumber) } inputConsumed = true continue case "Error": - return 0, moerr.NewInternalErrorNoCtxf("python udf: worker error: %s", control.Reason) + return 0, udferr.Newf("python udf: worker error: %s", control.Reason) case "Finish": - return 0, moerr.NewInternalErrorNoCtxf("python udf: Finish arrived before result sequence %d", sequenceNumber) + return 0, udferr.Newf("python udf: Finish arrived before result sequence %d", sequenceNumber) default: - return 0, moerr.NewInternalErrorNoCtxf("python udf: unexpected control %q", control.Kind) + return 0, udferr.Newf("python udf: unexpected control %q", control.Kind) } } } @@ -1690,12 +1683,12 @@ func (g *Gateway) receiveResultBatch( // header could bypass the body-only limit used by the old result path. func freezeResultFrames(header, body []byte, maxBytes int64) (*protocol.OutputSnapshot, *protocol.OutputSnapshot, error) { if maxBytes <= 0 { - return nil, nil, moerr.NewInternalErrorNoCtxf("invalid Python UDF result batch limit") + return nil, nil, udferr.Newf("invalid Python UDF result batch limit") } headerBytes := int64(len(header)) bodyBytes := int64(len(body)) if headerBytes > maxBytes || bodyBytes > maxBytes-headerBytes { - return nil, nil, moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Arrow result batch exceeds %d bytes", maxBytes) + return nil, nil, udferr.Newf("RESOURCE_EXHAUSTED: Arrow result batch exceeds %d bytes", maxBytes) } headerSnapshot, err := protocol.FreezeOutput(header, maxBytes) if err != nil { @@ -1723,10 +1716,10 @@ type executionBudget struct { func validateInvocationBudget(budget executionBudget) error { if budget.rows < 0 { - return moerr.NewInternalErrorNoCtxf("python udf: invocation row count is negative") + return udferr.Newf("python udf: invocation row count is negative") } if budget.maxRows > 0 && budget.rows > budget.maxRows { - return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF invocation has %d rows, limit is %d", budget.rows, budget.maxRows) + return udferr.Newf("RESOURCE_EXHAUSTED: Python UDF invocation has %d rows, limit is %d", budget.rows, budget.maxRows) } if budget.maxResultBytes <= 0 || budget.rows == 0 { return nil @@ -1737,11 +1730,11 @@ func validateInvocationBudget(budget executionBudget) error { // each validated append because their area size depends on user values. validityBytes := (budget.rows-1)/8 + 1 if validityBytes >= budget.maxResultBytes { - return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF invocation result reservation exceeds %d bytes", budget.maxResultBytes) + return udferr.Newf("RESOURCE_EXHAUSTED: Python UDF invocation result reservation exceeds %d bytes", budget.maxResultBytes) } perRow := int64(budget.returnType.TypeSize()) if perRow > 0 && budget.rows > (budget.maxResultBytes-validityBytes)/perRow { - return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python UDF invocation result reservation exceeds %d bytes", budget.maxResultBytes) + return udferr.Newf("RESOURCE_EXHAUSTED: Python UDF invocation result reservation exceeds %d bytes", budget.maxResultBytes) } return nil } @@ -1749,7 +1742,7 @@ func validateInvocationBudget(budget executionBudget) error { func validateResultSchemaMetadata(metadata []byte, tuple protocol.FencingTuple) error { control, err := protocol.UnmarshalControl(metadata) if err != nil || control.Tuple != tuple || control.Kind != "ResultSchema" { - return moerr.NewInternalErrorNoCtxf("python udf: invalid result schema metadata") + return udferr.Newf("python udf: invalid result schema metadata") } return nil } @@ -1766,33 +1759,33 @@ func (g *Gateway) receiveFinish( data, err := stream.Recv() if err != nil { if err == io.EOF { - return moerr.NewInternalErrorNoCtxf("python udf: exchange ended before Finish") + return udferr.Newf("python udf: exchange ended before Finish") } return errutil.Wrapf(err, "python udf: receive Finish") } if data == nil || len(data.DataHeader) > 0 || len(data.DataBody) > 0 { - return moerr.NewInternalErrorNoCtxf("python udf: unexpected Arrow data while finishing") + return udferr.Newf("python udf: unexpected Arrow data while finishing") } control, err := protocol.UnmarshalControl(data.AppMetadata) if err != nil { return err } if control.Tuple != tuple { - return moerr.NewInternalErrorNoCtxf("python udf: Finish tuple changed") + return udferr.Newf("python udf: Finish tuple changed") } switch control.Kind { case "InputConsumed", "ResultSchema": - return moerr.NewInternalErrorNoCtxf("python udf: %s arrived after result stream was drained", control.Kind) + return udferr.Newf("python udf: %s arrived after result stream was drained", control.Kind) case "Error": - return moerr.NewInternalErrorNoCtxf("python udf: worker error: %s", control.Reason) + return udferr.Newf("python udf: worker error: %s", control.Reason) case "Finish": lastInput, lastResult, acked, inputEnded := sequence.State() if control.Status != statusOK || control.FinishID == "" || rows != expectedRows || !inputEnded || control.LastSequence != lastInput || lastResult != lastInput || acked != lastInput || !sequence.ReadyToFinish() { - return moerr.NewInternalErrorNoCtxf("python udf: invalid Finish status=%q rows=%d", control.Status, rows) + return udferr.Newf("python udf: invalid Finish status=%q rows=%d", control.Status, rows) } if control.LastResultSequence != lastResult { - return moerr.NewInternalErrorNoCtxf("python udf: invalid Finish result sequence %d, expected %d", control.LastResultSequence, lastResult) + return udferr.Newf("python udf: invalid Finish result sequence %d, expected %d", control.LastResultSequence, lastResult) } if err := g.acknowledgeFinish(ctx, client, "AcknowledgeFinish", protocol.Control{Kind: "AcknowledgeFinish", Tuple: tuple, FinishID: control.FinishID}); err != nil { return err @@ -1805,7 +1798,7 @@ func (g *Gateway) receiveFinish( // has returned and its cleanup owner has completed. return g.waitExchangeEOF(ctx, stream) default: - return moerr.NewInternalErrorNoCtxf("python udf: unexpected control %q", control.Kind) + return udferr.Newf("python udf: unexpected control %q", control.Kind) } } } @@ -1820,7 +1813,7 @@ func (g *Gateway) waitExchangeEOF(ctx context.Context, stream flight.FlightServi return errutil.Wrapf(err, "python udf: wait for exchange completion") } if data == nil || len(data.DataHeader) != 0 || len(data.DataBody) != 0 || len(data.AppMetadata) != 0 { - return moerr.NewInternalErrorNoCtxf("python udf: exchange returned data after Finish ACK") + return udferr.Newf("python udf: exchange returned data after Finish ACK") } } } @@ -1831,7 +1824,7 @@ func (g *Gateway) waitExchangeEOF(ctx context.Context, stream flight.FlightServi // between an accepted terminal result and a locally unconfirmed Finish. func (g *Gateway) acknowledgeFinish(ctx context.Context, client flight.FlightServiceClient, kind string, finish protocol.Control) error { if client == nil { - return moerr.NewInternalErrorNoCtxf("FINISH_UNCONFIRMED: finish ACK client is unavailable") + return udferr.Newf("FINISH_UNCONFIRMED: finish ACK client is unavailable") } firstErr := g.action(ctx, client, kind, finish) if firstErr == nil { @@ -1852,7 +1845,7 @@ func validateInvocation(invocation *udf.Invocation) error { return err } if invocation.Source == "" { - return moerr.NewInternalErrorNoCtxf("python udf: handler and source are required") + return udferr.Newf("python udf: handler and source are required") } // ArtifactResolver is an execution boundary, so the Gateway must enforce // the same immutable source contract even when a custom resolver does not @@ -1860,13 +1853,13 @@ func validateInvocation(invocation *udf.Invocation) error { // otherwise an oversized or invalid source can consume a large temporary // allocation and only fail at the Flight control-size boundary. if !utf8.ValidString(invocation.Source) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is not valid UTF-8") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact source is not valid UTF-8") } if int64(len([]byte(invocation.Source))) > DefaultMaxArtifactBytes { - return moerr.NewInternalErrorNoCtxf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", DefaultMaxArtifactBytes) + return udferr.Newf("RESOURCE_EXHAUSTED: Python artifact exceeds %d bytes", DefaultMaxArtifactBytes) } if invocation.ArtifactDigest != udf.PythonInlineArtifactDigest(invocation.Handler, invocation.Source) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") } return nil } @@ -1878,68 +1871,68 @@ func validateInvocation(invocation *udf.Invocation) error { // be valid. func validateInvocationHeader(invocation *udf.Invocation) error { if invocation == nil { - return moerr.NewInternalErrorNoCtxf("python udf: nil invocation") + return udferr.Newf("python udf: nil invocation") } if invocation.Language != udf.LanguagePython { - return moerr.NewInternalErrorNoCtxf("python udf: unsupported language %q", invocation.Language) + return udferr.Newf("python udf: unsupported language %q", invocation.Language) } if invocation.Handler == "" { - return moerr.NewInternalErrorNoCtxf("python udf: handler is required") + return udferr.Newf("python udf: handler is required") } if strings.Contains(invocation.Handler, ":") { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python external handler import requires an immutable artifact catalog") } if invocation.Length < 0 || len(invocation.Args) != len(invocation.Inputs) { - return moerr.NewInternalErrorNoCtxf("python udf: invalid input shape") + return udferr.Newf("python udf: invalid input shape") } if invocation.Mode != ModeScalar && invocation.Mode != ModeVector { - return moerr.NewInternalErrorNoCtxf("python udf: unsupported mode %q", invocation.Mode) + return udferr.Newf("python udf: unsupported mode %q", invocation.Mode) } if invocation.CallsiteID == "" || len(invocation.CallsiteID) > 256 || strings.ContainsAny(invocation.CallsiteID, "\r\n") { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no valid callsite id") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no valid callsite id") } if !invocation.MayError || invocation.SecurityMode != "INVOKER" || invocation.Leakproof { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invocation semantic contract is not supported") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python invocation semantic contract is not supported") } if invocation.StatementContext == nil { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no statement context") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no statement context") } if err := invocation.StatementContext.Validate(); err != nil { return err } if invocation.SecurityFrame == nil { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no security frame") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python invocation has no security frame") } if err := invocation.SecurityFrame.Validate(); err != nil { return err } if invocation.SecurityFrame.Mode != invocation.SecurityMode { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invocation security mode does not match its frame") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python invocation security mode does not match its frame") } if invocation.NullPolicy != NullCallHandler && invocation.NullPolicy != NullReturnNull { - return moerr.NewInternalErrorNoCtxf("python udf: unsupported NULL policy %q", invocation.NullPolicy) + return udferr.Newf("python udf: unsupported NULL policy %q", invocation.NullPolicy) } if invocation.ABIContract != udf.PythonABIContract || invocation.AdapterVersion != udf.PythonAdapterVersion { - return moerr.NewInternalErrorNoCtxf("python udf: unsupported Python ABI contract %q/%q", invocation.ABIContract, invocation.AdapterVersion) + return udferr.Newf("python udf: unsupported Python ABI contract %q/%q", invocation.ABIContract, invocation.AdapterVersion) } if invocation.SDKVersion != udf.PythonSDKVersion { - return moerr.NewInternalErrorNoCtxf("python udf: unsupported Python SDK %q", invocation.SDKVersion) + return udferr.Newf("python udf: unsupported Python SDK %q", invocation.SDKVersion) } if invocation.DefinitionSchemaVersion != udf.PythonDefinitionSchemaVersion { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python definition schema %d", invocation.DefinitionSchemaVersion) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python definition schema %d", invocation.DefinitionSchemaVersion) } if !udf.IsSHA256Digest(invocation.ArtifactDigest) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python artifact digest does not match the immutable source") } environmentDigest, err := udf.PythonEnvironmentDigest() if err != nil { return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python environment digest is unavailable") } if invocation.EnvironmentDigest != environmentDigest { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the current worker contract") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python environment digest does not match the current worker contract") } if !udf.IsSHA256Digest(invocation.DefinitionFingerprint) { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint is invalid") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint is invalid") } args := make([]TypeDescriptor, len(invocation.Args)) for index, typ := range invocation.Args { @@ -1967,20 +1960,20 @@ func validateInvocationHeader(invocation *udf.Invocation) error { return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint cannot be computed") } if invocation.DefinitionFingerprint != expectedFingerprint { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python definition fingerprint does not match the typed definition") } if err := invocation.FunctionRef.Validate(); err != nil { return errutil.Wrapf(err, "UNSUPPORTED_ROUTINE_VERSION") } if invocation.FunctionRef.AccountID != invocation.Tuple.AccountID { - return moerr.NewInternalErrorNoCtxf("python udf: FunctionRef account does not match the fencing tuple") + return udferr.Newf("python udf: FunctionRef account does not match the fencing tuple") } return invocation.Tuple.Validate() } func validateInvocationInputs(invocation *udf.Invocation, args []TypeDescriptor) error { if invocation == nil || len(invocation.Inputs) != len(args) { - return moerr.NewInternalErrorNoCtxf("python udf: invalid input shape") + return udferr.Newf("python udf: invalid input shape") } // An empty physical selection has no input backing to inspect. Nil inputs // are valid in this case, but a vector supplied by a caller still has to @@ -1992,20 +1985,20 @@ func validateInvocationInputs(invocation *udf.Invocation, args []TypeDescriptor) continue } if input.GetType() == nil || !input.GetType().Eq(invocation.Args[index]) { - return moerr.NewInternalErrorNoCtxf("python udf: input column %d type does not match the frozen argument type", index) + return udferr.Newf("python udf: input column %d type does not match the frozen argument type", index) } } return nil } for index, input := range invocation.Inputs { if input == nil || input.GetType() == nil || input.Length() == 0 { - return moerr.NewInternalErrorNoCtxf("python udf: input column %d has no backing vector", index) + return udferr.Newf("python udf: input column %d has no backing vector", index) } if !input.GetType().Eq(invocation.Args[index]) { - return moerr.NewInternalErrorNoCtxf("python udf: input column %d type %s does not match the frozen argument type %s", index, input.GetType().DescString(), invocation.Args[index].DescString()) + return udferr.Newf("python udf: input column %d type %s does not match the frozen argument type %s", index, input.GetType().DescString(), invocation.Args[index].DescString()) } if !input.IsConst() && input.Length() < invocation.Length { - return moerr.NewInternalErrorNoCtxf("python udf: input column %d has %d rows, expected at least %d", index, input.Length(), invocation.Length) + return udferr.Newf("python udf: input column %d has %d rows, expected at least %d", index, input.Length(), invocation.Length) } } return nil @@ -2027,7 +2020,7 @@ func (g *Gateway) action(ctx context.Context, client flight.FlightServiceClient, return err } if result == nil { - return moerr.NewInternalErrorNoCtxf("python udf: empty %s response", kind) + return udferr.Newf("python udf: empty %s response", kind) } ack, err := protocol.UnmarshalControl(result.Body) if err != nil { @@ -2037,11 +2030,11 @@ func (g *Gateway) action(ctx context.Context, client flight.FlightServiceClient, return err } if ack.Status != statusOK { - return moerr.NewInternalErrorNoCtxf("python udf: %s rejected: %s", kind, ack.Reason) + return udferr.Newf("python udf: %s rejected: %s", kind, ack.Reason) } if _, err := stream.Recv(); err != io.EOF { if err == nil { - return moerr.NewInternalErrorNoCtxf("python udf: %s returned multiple results", kind) + return udferr.Newf("python udf: %s returned multiple results", kind) } return err } @@ -2050,19 +2043,19 @@ func (g *Gateway) action(ctx context.Context, client flight.FlightServiceClient, func validateActionAck(kind string, request, ack protocol.Control) error { if ack.Tuple != request.Tuple || ack.Kind != "Ack" { - return moerr.NewInternalErrorNoCtxf("python udf: %s returned an invalid ACK", kind) + return udferr.Newf("python udf: %s returned an invalid ACK", kind) } switch kind { case "AcknowledgeResults": if ack.AckSequence != request.AckSequence { - return moerr.NewInternalErrorNoCtxf("python udf: %s ACK sequence %d, expected %d", kind, ack.AckSequence, request.AckSequence) + return udferr.Newf("python udf: %s ACK sequence %d, expected %d", kind, ack.AckSequence, request.AckSequence) } case "AcknowledgeFinish": if ack.FinishID != request.FinishID { - return moerr.NewInternalErrorNoCtxf("python udf: %s ACK finish ID does not match the request", kind) + return udferr.Newf("python udf: %s ACK finish ID does not match the request", kind) } default: - return moerr.NewInternalErrorNoCtxf("python udf: unsupported action %q", kind) + return udferr.Newf("python udf: unsupported action %q", kind) } return nil } diff --git a/pkg/udf/python/gateway_integration_test.go b/pkg/udf/python/gateway_integration_test.go index 5517b648cda28..14661b2f88706 100644 --- a/pkg/udf/python/gateway_integration_test.go +++ b/pkg/udf/python/gateway_integration_test.go @@ -743,6 +743,8 @@ func startRealWorker(t testing.TB, python, workerPath string, port int) *exec.Cm cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} } require.NoError(t, cmd.Start()) + // Own cleanup before readiness can fail; Fatal also runs test cleanups. + t.Cleanup(func() { stopRealWorker(cmd) }) waitForWorkerPort(t, port) return cmd } @@ -756,7 +758,7 @@ func stopRealWorker(cmd *exec.Cmd) { } else { _ = cmd.Process.Kill() } - _, _ = cmd.Process.Wait() + _ = cmd.Wait() } func integrationInput(t testing.TB, values []int64) (*vector.Vector, *mpool.MPool) { @@ -868,3 +870,16 @@ func routineDefinitionForIntegration(invocation *udf.Invocation) *udf.RoutineDef DefinitionFingerprint: invocation.DefinitionFingerprint, } } + +func TestRealWorkerStopRecordsCompletion(t *testing.T) { + python, err := exec.LookPath("python3") + require.NoError(t, err) + cmd := startRealWorker(t, python, realWorkerPath(t), freeTCPPort(t)) + stopRealWorker(cmd) + // Process.Wait alone does not publish this state on Cmd, so delayed cleanup + // could send a second signal to a process group whose ID has been reused. + require.NotNil(t, cmd.ProcessState) + completed := cmd.ProcessState + stopRealWorker(cmd) + require.Same(t, completed, cmd.ProcessState) +} diff --git a/pkg/udf/python/supervisor.go b/pkg/udf/python/supervisor.go index ed09bc63dc2b9..b8b143c7610f3 100644 --- a/pkg/udf/python/supervisor.go +++ b/pkg/udf/python/supervisor.go @@ -16,17 +16,18 @@ package python import ( "errors" - "github.com/matrixorigin/matrixone/pkg/common/moerr" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "os" "os/exec" "path/filepath" "sync" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/matrixorigin/matrixone/pkg/logutil" ) -var errSupervisorClosing = moerr.NewInternalErrorNoCtx("python udf worker is shutting down") +var errSupervisorClosing = udferr.New("python udf worker is shutting down") type Supervisor struct { cfg Config diff --git a/pkg/udf/runtime.go b/pkg/udf/runtime.go index 16bed1eaef382..a9edc4a024492 100644 --- a/pkg/udf/runtime.go +++ b/pkg/udf/runtime.go @@ -22,13 +22,15 @@ import ( "context" "encoding/json" "errors" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "sort" "strconv" "strings" "sync" "time" + "github.com/matrixorigin/matrixone/pkg/udf/udferr" + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -91,41 +93,41 @@ type StatementContext struct { func (c StatementContext) Validate() error { if c.ContractVersion != StatementContextContractVersion { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported statement context contract %d", c.ContractVersion) + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: unsupported statement context contract %d", c.ContractVersion) } if c.StatementTimestampUTC < minStatementTimestampUTC || c.StatementTimestampUTC > maxStatementTimestampUTC { - return moerr.NewInternalErrorNoCtxf("python udf: statement timestamp is outside the Python datetime range") + return udferr.Newf("python udf: statement timestamp is outside the Python datetime range") } if c.CurrentUser == "" || c.ConnectionCollation == "" { - return moerr.NewInternalErrorNoCtxf("python udf: statement context has no authenticated user or collation") + return udferr.Newf("python udf: statement context has no authenticated user or collation") } if c.TimezoneKind == "IANA" { if c.TimezoneName == "" || c.TimezoneDatabaseVersion == "" || c.TimezoneOffsetMinutes != 0 { - return moerr.NewInternalErrorNoCtxf("python udf: IANA statement timezone is incomplete") + return udferr.Newf("python udf: IANA statement timezone is incomplete") } if _, err := time.LoadLocation(c.TimezoneName); err != nil { return errutil.Wrapf(err, "python udf: IANA statement timezone is not present in the local tzdb") } } else if c.TimezoneKind == "FIXED_OFFSET" { if c.TimezoneName != "" || c.TimezoneDatabaseVersion != "" || c.TimezoneOffsetMinutes < -839 || c.TimezoneOffsetMinutes > 840 { - return moerr.NewInternalErrorNoCtxf("python udf: fixed statement timezone is invalid") + return udferr.Newf("python udf: fixed statement timezone is invalid") } } else { - return moerr.NewInternalErrorNoCtxf("python udf: unsupported statement timezone kind %q", c.TimezoneKind) + return udferr.Newf("python udf: unsupported statement timezone kind %q", c.TimezoneKind) } mode := append([]string(nil), c.SQLMode...) sort.Strings(mode) for i := range mode { if mode[i] == "" || (i > 0 && mode[i] == mode[i-1]) { - return moerr.NewInternalErrorNoCtxf("python udf: statement sql_mode is not canonical") + return udferr.Newf("python udf: statement sql_mode is not canonical") } } if len(mode) != len(c.SQLMode) { - return moerr.NewInternalErrorNoCtxf("python udf: statement sql_mode is not canonical") + return udferr.Newf("python udf: statement sql_mode is not canonical") } for i := range mode { if mode[i] != c.SQLMode[i] { - return moerr.NewInternalErrorNoCtxf("python udf: statement sql_mode is not sorted") + return udferr.Newf("python udf: statement sql_mode is not sorted") } } return nil @@ -170,7 +172,7 @@ func StatementContextFromMap(values map[string]string) (*StatementContext, error // Reject it at the trusted CN adapter instead of carrying a malformed // snapshot into the Flight request. if mode == nil { - return nil, moerr.NewInternalErrorNoCtxf("python udf: invalid statement sql_mode: expected a JSON array") + return nil, udferr.Newf("python udf: invalid statement sql_mode: expected a JSON array") } } context := &StatementContext{ @@ -213,10 +215,10 @@ type SecurityFrame struct { func (f SecurityFrame) Validate() error { if f.ContractVersion != SecurityFrameContractVersion || f.Mode != "INVOKER" { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python security frame") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: unsupported Python security frame") } if f.InvokerUserID != f.EffectiveUserID || f.InvokerRoleID != f.EffectiveRoleID { - return moerr.NewInternalErrorNoCtxf("UNSUPPORTED_ROUTINE_VERSION: Python invoker security frame changed effective principal") + return udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python invoker security frame changed effective principal") } return nil } diff --git a/pkg/udf/timezone.go b/pkg/udf/timezone.go index cafda4adef42f..9053fb472087c 100644 --- a/pkg/udf/timezone.go +++ b/pkg/udf/timezone.go @@ -16,9 +16,10 @@ package udf import ( "bufio" - "github.com/matrixorigin/matrixone/pkg/common/moerr" "os" "strings" + + "github.com/matrixorigin/matrixone/pkg/udf/udferr" ) // TimezoneDatabaseVersion returns the version of the system IANA tz database @@ -52,5 +53,5 @@ func TimezoneDatabaseVersion() (string, error) { } } } - return "", moerr.NewInternalErrorNoCtxf("python udf: IANA timezone database version is unavailable") + return "", udferr.Newf("python udf: IANA timezone database version is unavailable") } diff --git a/pkg/udf/udferr/errors.go b/pkg/udf/udferr/errors.go new file mode 100644 index 0000000000000..24f123728691f --- /dev/null +++ b/pkg/udf/udferr/errors.go @@ -0,0 +1,33 @@ +// Copyright 2026 Matrix Origin +// +// 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 udferr defines diagnostic errors for the routine catalog and external +// execution contract. These errors retain the domain's message verbatim; they +// are not MO SQL error classifications. Callers that own a specific SQL error +// must continue to construct that moerr at the SQL boundary. +package udferr + +import "fmt" + +// Error is a routine-contract diagnostic. Each construction has distinct +// identity so equal text does not accidentally alias independent sentinels. +type Error struct{ message string } + +func (e *Error) Error() string { return e.message } + +func New(message string) error { return &Error{message: message} } + +// Newf formats a leaf diagnostic. Use errutil wrapping for an existing cause; +// this function deliberately does not interpret wrapping verbs. +func Newf(format string, args ...any) error { return New(fmt.Sprintf(format, args...)) } diff --git a/pkg/udf/udferr/errors_test.go b/pkg/udf/udferr/errors_test.go new file mode 100644 index 0000000000000..4a22db7f56d26 --- /dev/null +++ b/pkg/udf/udferr/errors_test.go @@ -0,0 +1,35 @@ +// Copyright 2026 Matrix Origin +// +// 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 udferr + +import ( + "errors" + "testing" + + "github.com/matrixorigin/matrixone/pkg/util/errutil" + "github.com/stretchr/testify/require" +) + +func TestDiagnosticIdentity(t *testing.T) { + first, second := New("TYPE_CONTRACT: invalid result"), New("TYPE_CONTRACT: invalid result") + wrapped := errutil.Wrapf(first, "gateway") + require.ErrorIs(t, wrapped, first) + require.NotErrorIs(t, wrapped, second) + var diagnostic *Error + require.True(t, errors.As(wrapped, &diagnostic)) + require.Equal(t, first, diagnostic) + require.EqualError(t, wrapped, "gateway: TYPE_CONTRACT: invalid result") + require.EqualError(t, Newf("invalid dimension %d", 3), "invalid dimension 3") +} diff --git a/pkg/util/errutil/errors_test.go b/pkg/util/errutil/errors_test.go index 21613cc7b182a..6e8f5b3485598 100644 --- a/pkg/util/errutil/errors_test.go +++ b/pkg/util/errutil/errors_test.go @@ -16,10 +16,13 @@ package errutil import ( "context" - "github.com/stretchr/testify/require" + "errors" + "os" "reflect" "sync/atomic" "testing" + + "github.com/stretchr/testify/require" ) func mockReportError(_ context.Context, err error, depth int) {} @@ -186,6 +189,16 @@ func TestWrapfCauseFirst(t *testing.T) { err := WrapfCauseFirst(cause, "detail %d", 7) require.Equal(t, "context canceled: detail 7", err.Error()) require.ErrorIs(t, err, cause) + require.Nil(t, WrapfCauseFirst(nil, "ignored")) + require.EqualError(t, WrapfCauseFirst(cause, ""), cause.Error()) + first, second := errors.New("same"), errors.New("same") + require.NotErrorIs(t, WrapfCauseFirst(first, "detail"), second) + typed := &os.PathError{Op: "read", Path: "artifact", Err: first} + nested := Wrap(WrapfCauseFirst(typed, "detail"), "gateway") + var target *os.PathError + require.ErrorAs(t, nested, &target) + require.Same(t, typed, target) + require.ErrorIs(t, nested, first) } func Test_noopReportError(t *testing.T) { diff --git a/test/distributed/cases/git4data/clone/clone_sys_db_table_to_new_db_table.result b/test/distributed/cases/git4data/clone/clone_sys_db_table_to_new_db_table.result index f40ec66cb0cde..ac3fd5a7b3307 100644 --- a/test/distributed/cases/git4data/clone/clone_sys_db_table_to_new_db_table.result +++ b/test/distributed/cases/git4data/clone/clone_sys_db_table_to_new_db_table.result @@ -145,6 +145,7 @@ mo_database_defaults mo_feature_limit mo_feature_registry mo_foreign_keys +mo_function_revisions mo_iceberg_catalogs mo_iceberg_maintenance_jobs mo_iceberg_orphan_files @@ -216,6 +217,7 @@ mo_database_defaults mo_feature_limit mo_feature_registry mo_foreign_keys +mo_function_revisions mo_iceberg_catalogs mo_iceberg_maintenance_jobs mo_iceberg_orphan_files diff --git a/test/distributed/cases/mo_cloud/mo_cloud.result b/test/distributed/cases/mo_cloud/mo_cloud.result index 4de1d00cd829a..0cfd9c3eae8f3 100644 --- a/test/distributed/cases/mo_cloud/mo_cloud.result +++ b/test/distributed/cases/mo_cloud/mo_cloud.result @@ -811,6 +811,7 @@ mo_catalog ¦ mo_configurations ¦ v ¦ accountadmin 𝄀 mo_catalog ¦ mo_database ¦ r ¦ - 𝄀 mo_catalog ¦ mo_database_defaults ¦ r ¦ accountadmin 𝄀 mo_catalog ¦ mo_foreign_keys ¦ r ¦ accountadmin 𝄀 +mo_catalog ¦ mo_function_revisions ¦ r ¦ accountadmin 𝄀 mo_catalog ¦ mo_iceberg_catalogs ¦ r ¦ accountadmin 𝄀 mo_catalog ¦ mo_iceberg_maintenance_jobs ¦ r ¦ accountadmin 𝄀 mo_catalog ¦ mo_iceberg_orphan_files ¦ r ¦ accountadmin 𝄀 diff --git a/test/distributed/cases/snapshot/cluster/restore_cluster_table.result b/test/distributed/cases/snapshot/cluster/restore_cluster_table.result index 27711a9aa3f3f..4ba4140d6cef2 100644 --- a/test/distributed/cases/snapshot/cluster/restore_cluster_table.result +++ b/test/distributed/cases/snapshot/cluster/restore_cluster_table.result @@ -231,8 +231,8 @@ create function `addAB`(x int, y int) returns int language sql as '$1 + $2'; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-11-24 15:27:40 2025-11-24 15:27:40 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-11-24 15:27:40 2025-11-24 15:27:40 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop stage if exists my_ext_stage; create stage my_ext_stage URL='s3://load/files/'; drop stage if exists my_ext_stage1; @@ -422,6 +422,7 @@ mo_database_defaults mo_feature_limit mo_feature_registry mo_foreign_keys +mo_function_revisions mo_iceberg_catalogs mo_iceberg_maintenance_jobs mo_iceberg_orphan_files @@ -485,8 +486,8 @@ create function `add`(x int, y int) returns int language sql as '$1 + $2'; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -2 add 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-11-24 15:27:40 2025-11-24 15:27:40 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +2 1 1 add 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-11-24 15:27:40 2025-11-24 15:27:40 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop database test01; use test02; select * from v01; @@ -554,6 +555,7 @@ mo_database_defaults mo_feature_limit mo_feature_registry mo_foreign_keys +mo_function_revisions mo_iceberg_catalogs mo_iceberg_maintenance_jobs mo_iceberg_orphan_files @@ -614,8 +616,8 @@ stage_id stage_name url stage_credentials stage_status created_ti 1 my_ext_stage s3://load/files/ in_use 2025-11-24 15:27:40 2 my_ext_stage1 s3://load/files/ AWS_KEY_ID=1a2b3c,AWS_SECRET_KEY=4x5y6z in_use 2025-11-24 15:27:40 select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-11-24 15:27:40 2025-11-24 15:27:40 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-11-24 15:27:40 2025-11-24 15:27:40 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG select * from test01.sales; id sale_date amount 1 2018-12-25 100.00 diff --git a/test/distributed/cases/snapshot/cluster/restore_cluster_table.sql b/test/distributed/cases/snapshot/cluster/restore_cluster_table.sql index bf28a6b2db10d..a34e41ca34850 100644 --- a/test/distributed/cases/snapshot/cluster/restore_cluster_table.sql +++ b/test/distributed/cases/snapshot/cluster/restore_cluster_table.sql @@ -230,7 +230,7 @@ use udf_db2; create function `addAB`(x int, y int) returns int language sql as '$1 + $2'; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop stage if exists my_ext_stage; @@ -376,7 +376,7 @@ use udf_db2; create function `add`(x int, y int) returns int language sql as '$1 + $2'; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session @@ -427,7 +427,7 @@ select * from mo_catalog.mo_stored_procedure; -- @session:id=2&user=acc02:test_account&password=111 -- @ignore:0,5 select * from mo_catalog.mo_stages; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session diff --git a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_cluster.result b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_cluster.result index f74eb980517e6..1dc53677abfec 100644 --- a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_cluster.result +++ b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_cluster.result @@ -266,8 +266,8 @@ create function `addAB`(x int, y int) returns int language sql as '$1 + $2'; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-11-24 15:26:50 2025-11-24 15:26:50 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-11-24 15:26:50 2025-11-24 15:26:50 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop stage if exists my_ext_stage; create stage my_ext_stage URL='s3://load/files/'; drop stage if exists my_ext_stage1; @@ -459,6 +459,7 @@ mo_database_defaults mo_feature_limit mo_feature_registry mo_foreign_keys +mo_function_revisions mo_iceberg_catalogs mo_iceberg_maintenance_jobs mo_iceberg_orphan_files @@ -523,8 +524,8 @@ create function `add`(x int, y int) returns int language sql as '$1 + $2'; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -2 add 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-11-24 15:26:50 2025-11-24 15:26:50 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +2 1 1 add 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-11-24 15:26:50 2025-11-24 15:26:50 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop database test01; use test02; select * from v01; @@ -607,6 +608,7 @@ mo_database_defaults mo_feature_limit mo_feature_registry mo_foreign_keys +mo_function_revisions mo_iceberg_catalogs mo_iceberg_maintenance_jobs mo_iceberg_orphan_files @@ -675,8 +677,8 @@ stage_id stage_name url stage_credentials stage_status created_ti 1 my_ext_stage s3://load/files/ in_use 2025-11-24 15:26:50 2 my_ext_stage1 s3://load/files/ AWS_KEY_ID=1a2b3c,AWS_SECRET_KEY=4x5y6z in_use 2025-11-24 15:26:50 select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-11-24 15:26:50 2025-11-24 15:26:50 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-11-24 15:26:50 2025-11-24 15:26:50 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG use test02; select * from v01; id sale_date amount diff --git a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_cluster.sql b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_cluster.sql index ef6a3bf23b556..c7a25d1d7ea4c 100644 --- a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_cluster.sql +++ b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_cluster.sql @@ -245,7 +245,7 @@ use udf_db2; create function `addAB`(x int, y int) returns int language sql as '$1 + $2'; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop stage if exists my_ext_stage; @@ -398,7 +398,7 @@ use udf_db2; create function `add`(x int, y int) returns int language sql as '$1 + $2'; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session @@ -454,7 +454,7 @@ select * from mo_catalog.mo_stored_procedure; -- @session:id=2&user=acc02:test_account&password=111 -- @ignore:0,5 select * from mo_catalog.mo_stages; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session diff --git a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_nonsys.result b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_nonsys.result index 9400c311f646e..9d09f869d7b46 100644 --- a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_nonsys.result +++ b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_nonsys.result @@ -54,23 +54,23 @@ udf_dsp03 2025-07-19 05:49:43.416853 cluster udf_dsp02 2025-07-19 05:49:43.394563 cluster udf_dsp01 2025-07-19 05:49:43.382694 cluster select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -3 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +3 1 1 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account acc01{snapshot="udf_dsp03"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -3 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +3 1 1 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG restore account acc01{snapshot="udf_dsp02"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop database udf_db; drop snapshot udf_dsp01; drop snapshot udf_dsp02; @@ -82,17 +82,17 @@ create function `addab`(x int, y int) returns int language sql as '$1 + $2'; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -10001 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +10001 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop snapshot if exists udf_sp04; create snapshot udf_sp04 for cluster; drop database udf_db2; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode restore account acc01{snapshot="udf_sp04"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -10001 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +10001 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-07-19 05:49:43 2025-07-19 05:49:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop database udf_db2; drop snapshot udf_sp04; drop database if exists procedure_test; diff --git a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_nonsys.sql b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_nonsys.sql index dc3faa13dd891..b786725664269 100644 --- a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_nonsys.sql +++ b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_nonsys.sql @@ -52,7 +52,7 @@ create snapshot udf_dsp03 for cluster; show snapshots; -- @session:id=1&user=acc01:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); @@ -61,14 +61,14 @@ drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account acc01{snapshot="udf_dsp03"}; -- @session:id=1&user=acc01:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session restore account acc01{snapshot="udf_dsp02"}; -- @session:id=1&user=acc01:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session @@ -90,7 +90,7 @@ use udf_db2; create function `addab`(x int, y int) returns int language sql as '$1 + $2'; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session @@ -99,14 +99,14 @@ create snapshot udf_sp04 for cluster; -- @session:id=1&user=acc01:test_account&password=111 drop database udf_db2; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session restore account acc01{snapshot="udf_sp04"}; -- @session:id=1&user=acc01:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop database udf_db2; -- @session diff --git a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_sys_account.result b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_sys_account.result index b45565cde0830..c6f28e62c6c28 100644 --- a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_sys_account.result +++ b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_sys_account.result @@ -52,18 +52,18 @@ udf_dsp03 2025-07-19 05:49:49.217379 cluster udf_dsp02 2025-07-19 05:49:49.192607 cluster udf_dsp01 2025-07-19 05:49:49.180259 cluster select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1250000 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -1250001 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -1250002 subab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1250000 1 1 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +1250001 1 1 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +1250002 1 1 subab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account sys{snapshot="udf_dsp03"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1250000 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -1250001 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -1250002 subab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1250000 1 1 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +1250001 1 1 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +1250002 1 1 subab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG show snapshots; SNAPSHOT_NAME TIMESTAMP SNAPSHOT_LEVEL ACCOUNT_NAME DATABASE_NAME TABLE_NAME udf_dsp03 2025-07-19 05:49:49.217379 cluster @@ -71,9 +71,9 @@ udf_dsp02 2025-07-19 05:49:49.192607 cluster udf_dsp01 2025-07-19 05:49:49.180259 cluster restore account sys{snapshot="udf_dsp02"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1250000 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -1250001 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1250000 1 1 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +1250001 1 1 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG show snapshots; SNAPSHOT_NAME TIMESTAMP SNAPSHOT_LEVEL ACCOUNT_NAME DATABASE_NAME TABLE_NAME udf_dsp03 2025-07-19 05:49:49.217379 cluster @@ -90,17 +90,17 @@ create function `addab`(x int, y int) returns int language sql as '$1 + $2'; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1260000 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1260000 1 1 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop snapshot if exists udf_sp04; create snapshot udf_sp04 for cluster; drop database udf_db2; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode restore account sys{snapshot="udf_sp04"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1260000 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1260000 1 1 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 dump 2025-07-19 05:49:49 2025-07-19 05:49:49 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop database udf_db2; drop snapshot udf_sp04; drop database if exists procedure_test; diff --git a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_sys_account.sql b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_sys_account.sql index 102958a93ed79..09e35f428202a 100644 --- a/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_sys_account.sql +++ b/test/distributed/cases/snapshot/cluster_level_snapshot_restore_system_table_to_sys_account.sql @@ -43,20 +43,20 @@ create snapshot udf_dsp03 for cluster; -- @ignore:0,1 show snapshots; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account sys{snapshot="udf_dsp03"}; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @ignore:0,1 show snapshots; restore account sys{snapshot="udf_dsp02"}; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @ignore:0,1 show snapshots; @@ -76,7 +76,7 @@ use udf_db2; create function `addab`(x int, y int) returns int language sql as '$1 + $2'; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop snapshot if exists udf_sp04; @@ -86,7 +86,7 @@ drop database udf_db2; select * from mo_catalog.mo_user_defined_function; restore account sys{snapshot="udf_sp04"}; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop database udf_db2; drop snapshot udf_sp04; diff --git a/test/distributed/cases/snapshot/nonsys_restore_system_table_to_nonsys_account.result b/test/distributed/cases/snapshot/nonsys_restore_system_table_to_nonsys_account.result index 90421a7e5c04e..09aa8d9cee4e1 100644 --- a/test/distributed/cases/snapshot/nonsys_restore_system_table_to_nonsys_account.result +++ b/test/distributed/cases/snapshot/nonsys_restore_system_table_to_nonsys_account.result @@ -54,18 +54,18 @@ udf_dsp03 2025-07-19 05:50:25.393332 account acc01 udf_dsp02 2025-07-19 05:50:25.371637 account acc01 udf_dsp01 2025-07-19 05:50:25.354111 account acc01 select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -3 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +3 1 1 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account acc01{snapshot="udf_dsp03"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -3 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +3 1 1 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG show snapshots; SNAPSHOT_NAME TIMESTAMP SNAPSHOT_LEVEL ACCOUNT_NAME DATABASE_NAME TABLE_NAME udf_dsp03 2025-07-19 05:50:25.393332 account acc01 @@ -73,9 +73,9 @@ udf_dsp02 2025-07-19 05:50:25.371637 account acc01 udf_dsp01 2025-07-19 05:50:25.354111 account acc01 restore account acc01{snapshot="udf_dsp02"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG show snapshots; SNAPSHOT_NAME TIMESTAMP SNAPSHOT_LEVEL ACCOUNT_NAME DATABASE_NAME TABLE_NAME udf_dsp03 2025-07-19 05:50:25.393332 account acc01 @@ -92,17 +92,17 @@ create function `addAB`(x int, y int) returns int language sql as '$1 + $2'; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -10001 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +10001 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop snapshot if exists udf_sp04; create snapshot udf_sp04 for account acc01; drop database udf_db2; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode restore account acc01{snapshot="udf_sp04"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -10001 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +10001 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-07-19 05:50:25 2025-07-19 05:50:25 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop database udf_db2; drop snapshot udf_sp04; drop database if exists procedure_test; diff --git a/test/distributed/cases/snapshot/nonsys_restore_system_table_to_nonsys_account.sql b/test/distributed/cases/snapshot/nonsys_restore_system_table_to_nonsys_account.sql index 8e04ccaf9653c..307ea3c26803c 100644 --- a/test/distributed/cases/snapshot/nonsys_restore_system_table_to_nonsys_account.sql +++ b/test/distributed/cases/snapshot/nonsys_restore_system_table_to_nonsys_account.sql @@ -46,20 +46,20 @@ create snapshot udf_dsp03 for account acc01; -- @ignore:1 show snapshots; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account acc01{snapshot="udf_dsp03"}; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @ignore:1 show snapshots; restore account acc01{snapshot="udf_dsp02"}; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @ignore:1 show snapshots; @@ -79,7 +79,7 @@ use udf_db2; create function `addAB`(x int, y int) returns int language sql as '$1 + $2'; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop snapshot if exists udf_sp04; @@ -89,7 +89,7 @@ drop database udf_db2; select * from mo_catalog.mo_user_defined_function; restore account acc01{snapshot="udf_sp04"}; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop database udf_db2; drop snapshot udf_sp04; diff --git a/test/distributed/cases/snapshot/sys_restore_system_table_to_newnonsys_account.result b/test/distributed/cases/snapshot/sys_restore_system_table_to_newnonsys_account.result index 938b13d74d6a0..9a03d829a5cbe 100644 --- a/test/distributed/cases/snapshot/sys_restore_system_table_to_newnonsys_account.result +++ b/test/distributed/cases/snapshot/sys_restore_system_table_to_newnonsys_account.result @@ -56,23 +56,23 @@ udf_dsp03 2025-07-19 05:52:33.805599 account acc01 udf_dsp02 2025-07-19 05:52:33.782182 account acc01 udf_dsp01 2025-07-19 05:52:33.77066 account acc01 select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -3 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +3 1 1 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account acc01{snapshot="udf_dsp03"} to account acc02; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -3 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +3 1 1 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG restore account acc01{snapshot="udf_dsp02"} to account acc02; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:33 2025-07-19 05:52:33 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop database udf_db; drop snapshot udf_dsp01; drop snapshot udf_dsp02; @@ -86,17 +86,17 @@ create function `addAB`(x int, y int) returns int language sql as '$1 + $2'; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -4 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-07-19 05:52:34 2025-07-19 05:52:34 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +4 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-07-19 05:52:34 2025-07-19 05:52:34 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop snapshot if exists udf_sp04; create snapshot udf_sp04 for account acc01; drop database udf_db2; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode restore account acc01{snapshot="udf_sp04"} to account acc02; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -4 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-07-19 05:52:34 2025-07-19 05:52:34 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +4 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-07-19 05:52:34 2025-07-19 05:52:34 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop database udf_db2; drop snapshot udf_sp04; drop database if exists procedure_test; diff --git a/test/distributed/cases/snapshot/sys_restore_system_table_to_newnonsys_account.sql b/test/distributed/cases/snapshot/sys_restore_system_table_to_newnonsys_account.sql index 6a92ed8abd7a9..3f0f65d37a318 100644 --- a/test/distributed/cases/snapshot/sys_restore_system_table_to_newnonsys_account.sql +++ b/test/distributed/cases/snapshot/sys_restore_system_table_to_newnonsys_account.sql @@ -54,7 +54,7 @@ create snapshot udf_dsp03 for account acc01; show snapshots; -- @session:id=1&user=acc01:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); @@ -63,13 +63,13 @@ drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account acc01{snapshot="udf_dsp03"} to account acc02; -- @session:id=2&user=acc02:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session restore account acc01{snapshot="udf_dsp02"} to account acc02; -- @session:id=2&user=acc02:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop database udf_db; -- @session @@ -94,7 +94,7 @@ use udf_db2; create function `addAB`(x int, y int) returns int language sql as '$1 + $2'; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session @@ -109,7 +109,7 @@ select * from mo_catalog.mo_user_defined_function; restore account acc01{snapshot="udf_sp04"} to account acc02; -- @session:id=2&user=acc02:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop database udf_db2; -- @session diff --git a/test/distributed/cases/snapshot/sys_restore_system_table_to_nonsys_account.result b/test/distributed/cases/snapshot/sys_restore_system_table_to_nonsys_account.result index 8109f9316452a..542ab75a09ff4 100644 --- a/test/distributed/cases/snapshot/sys_restore_system_table_to_nonsys_account.result +++ b/test/distributed/cases/snapshot/sys_restore_system_table_to_nonsys_account.result @@ -54,23 +54,23 @@ udf_dsp03 2025-07-19 05:52:41.738562 account acc01 udf_dsp02 2025-07-19 05:52:41.609162 account acc01 udf_dsp01 2025-07-19 05:52:41.560453 account acc01 select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -3 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +3 1 1 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account acc01{snapshot="udf_dsp03"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -3 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +3 1 1 subab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG restore account acc01{snapshot="udf_dsp02"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -2 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +2 1 1 concatenate 2 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db test_account 2025-07-19 05:52:41 2025-07-19 05:52:41 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop database udf_db; drop snapshot udf_dsp01; drop snapshot udf_dsp02; @@ -82,17 +82,17 @@ create function `addab`(x int, y int) returns int language sql as '$1 + $2'; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -10001 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-07-19 05:52:43 2025-07-19 05:52:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +10001 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-07-19 05:52:43 2025-07-19 05:52:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop snapshot if exists udf_sp04; create snapshot udf_sp04 for account acc01; drop database udf_db2; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode restore account acc01{snapshot="udf_sp04"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -10001 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 test_account 2025-07-19 05:52:43 2025-07-19 05:52:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +10001 1 1 addab 2 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 test_account 2025-07-19 05:52:43 2025-07-19 05:52:43 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop database udf_db2; drop snapshot udf_sp04; drop database if exists procedure_test; diff --git a/test/distributed/cases/snapshot/sys_restore_system_table_to_nonsys_account.sql b/test/distributed/cases/snapshot/sys_restore_system_table_to_nonsys_account.sql index 8d7e630fe7468..7d085efd06d6b 100644 --- a/test/distributed/cases/snapshot/sys_restore_system_table_to_nonsys_account.sql +++ b/test/distributed/cases/snapshot/sys_restore_system_table_to_nonsys_account.sql @@ -52,7 +52,7 @@ create snapshot udf_dsp03 for account acc01; show snapshots; -- @session:id=1&user=acc01:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); @@ -61,14 +61,14 @@ drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account acc01{snapshot="udf_dsp03"}; -- @session:id=1&user=acc01:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session restore account acc01{snapshot="udf_dsp02"}; -- @session:id=1&user=acc01:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session @@ -90,7 +90,7 @@ use udf_db2; create function `addab`(x int, y int) returns int language sql as '$1 + $2'; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session @@ -99,14 +99,14 @@ create snapshot udf_sp04 for account acc01; -- @session:id=1&user=acc01:test_account&password=111 drop database udf_db2; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @session restore account acc01{snapshot="udf_sp04"}; -- @session:id=1&user=acc01:test_account&password=111 --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop database udf_db2; -- @session diff --git a/test/distributed/cases/snapshot/sys_restore_system_table_to_sys_account.result b/test/distributed/cases/snapshot/sys_restore_system_table_to_sys_account.result index ff0f04f4581d5..361e8f6a17e88 100644 --- a/test/distributed/cases/snapshot/sys_restore_system_table_to_sys_account.result +++ b/test/distributed/cases/snapshot/sys_restore_system_table_to_sys_account.result @@ -52,18 +52,18 @@ udf_dsp03 2025-07-19 05:52:48.557367 account sys udf_dsp02 2025-07-19 05:52:48.529274 account sys udf_dsp01 2025-07-19 05:52:48.516842 account sys select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1890000 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -1890001 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -1890002 subab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1890000 1 1 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +1890001 1 1 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +1890002 1 1 subab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account sys{snapshot="udf_dsp03"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1890000 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -1890001 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -1890002 subab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 - $2 sql udf_db2 dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1890000 1 1 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +1890001 1 1 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +1890002 1 1 subab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 - $2 sql udf_db2 dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG show snapshots; SNAPSHOT_NAME TIMESTAMP SNAPSHOT_LEVEL ACCOUNT_NAME DATABASE_NAME TABLE_NAME udf_dsp03 2025-07-19 05:52:48.557367 account sys @@ -71,9 +71,9 @@ udf_dsp02 2025-07-19 05:52:48.529274 account sys udf_dsp01 2025-07-19 05:52:48.516842 account sys restore account sys{snapshot="udf_dsp02"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1890000 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG -1890001 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] varchar $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1890000 1 1 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +1890001 1 1 concatenate 0 [{"name": "str1", "type": "varchar"}, {"name": "str2", "type": "varchar"}] ["varchar", "varchar"] 0 varchar $1 + $2 sql udf_db dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG show snapshots; SNAPSHOT_NAME TIMESTAMP SNAPSHOT_LEVEL ACCOUNT_NAME DATABASE_NAME TABLE_NAME udf_dsp03 2025-07-19 05:52:48.557367 account sys @@ -90,17 +90,17 @@ create function `addab`(x int, y int) returns int language sql as '$1 + $2'; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1900000 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1900000 1 1 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop snapshot if exists udf_sp04; create snapshot udf_sp04 for account; drop database udf_db2; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode restore account sys{snapshot="udf_sp04"}; select * from mo_catalog.mo_user_defined_function; -function_id name owner args arg_types rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode -1900000 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] int $1 + $2 sql udf_db2 dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG +function_id active_revision namespace_version name owner args arg_types canonical_input_descriptor return_descriptor signature_key_schema_version signature_fingerprint rettype body language db definer modified_time created_time type security_type comment character_set_client collation_connection database_collation sql_mode +1900000 1 1 addab 0 [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}] ["int", "int"] 0 int $1 + $2 sql udf_db2 dump 2025-07-19 05:52:48 2025-07-19 05:52:48 FUNCTION DEFINER utf8mb4 utf8mb4_0900_ai_ci utf8mb4_0900_ai_ci ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATE,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ENABLE_BOOL_SUMAVG drop database udf_db2; drop snapshot udf_sp04; drop database if exists procedure_test; diff --git a/test/distributed/cases/snapshot/sys_restore_system_table_to_sys_account.sql b/test/distributed/cases/snapshot/sys_restore_system_table_to_sys_account.sql index 78587e4498806..e9eacb3058ba3 100644 --- a/test/distributed/cases/snapshot/sys_restore_system_table_to_sys_account.sql +++ b/test/distributed/cases/snapshot/sys_restore_system_table_to_sys_account.sql @@ -43,20 +43,20 @@ create snapshot udf_dsp03 for account; -- @ignore:0,1 show snapshots; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop function subab(x int,y int); drop function udf_db.concatenate(str1 varchar(255), str2 varchar(255)); restore account sys{snapshot="udf_dsp03"}; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @ignore:0,1 show snapshots; restore account sys{snapshot="udf_dsp02"}; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; -- @ignore:0,1 show snapshots; @@ -76,7 +76,7 @@ use udf_db2; create function `addab`(x int, y int) returns int language sql as '$1 + $2'; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop snapshot if exists udf_sp04; @@ -86,7 +86,7 @@ drop database udf_db2; select * from mo_catalog.mo_user_defined_function; restore account sys{snapshot="udf_sp04"}; --- @ignore:0,10,11 +-- @ignore:0,16,17 select * from mo_catalog.mo_user_defined_function; drop database udf_db2; drop snapshot udf_sp04; diff --git a/test/distributed/cases/tenant/privilege/create_user_default_role.result b/test/distributed/cases/tenant/privilege/create_user_default_role.result index ff608cc79276f..c0f590edc49c3 100644 --- a/test/distributed/cases/tenant/privilege/create_user_default_role.result +++ b/test/distributed/cases/tenant/privilege/create_user_default_role.result @@ -38,6 +38,7 @@ mo_database_defaults mo_feature_limit mo_feature_registry mo_foreign_keys +mo_function_revisions mo_iceberg_catalogs mo_iceberg_maintenance_jobs mo_iceberg_orphan_files diff --git a/test/distributed/cases/udf_python/README.md b/test/distributed/cases/udf_python/README.md index 3241d9f991a15..3a342a0113043 100644 --- a/test/distributed/cases/udf_python/README.md +++ b/test/distributed/cases/udf_python/README.md @@ -10,12 +10,26 @@ worker-enabled manifest for this ordinary BVT entry point; starting `etc/launch/launch.toml` directly leaves Python disabled. ```bash -python3 -m pip install -r pkg/udf/python/worker/requirements.txt +python3.12 -m venv /path/to/python-udf-test-venv +source /path/to/python-udf-test-venv/bin/activate +python3 -m pip install --only-binary=:all: -r pkg/udf/python/worker/requirements.txt ./optools/run_bvt.sh . launch cd /path/to/mo-tester ./run.sh -n -g -o -p /path/to/matrixone/test/distributed/cases ``` +The Go UDF package tests also start real Flight workers. Keep the same venv on +`PATH` when running them: installing PyArrow into another interpreter will not +satisfy `exec.LookPath("python3")`. The shared CI UT and coverage setup uses +Python 3.12 and the checked-out requirements file; this is a test environment +choice, not an exact-minor production compatibility rule. + +For fresh local data, the worker-enabled CN and its TN both use the same +`DISK-V2` FileService directories. Do not mix that configuration with an +existing `DISK` data directory. Container BVT also requires CN and worker +images with the same IANA database; both full-build and prebuilt runtime image +recipes install tzdata before the strict capability handshake. + To create or refresh a result file after reviewing the expected output, keep the normal worker-enabled launch running and use `mo-tester`'s `genrs` mode: From 80a2384879ef33e664d34e66deafb6758032c9cf Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 20 Sep 2026 20:06:50 +0800 Subject: [PATCH 193/241] fix(udf): remove duplicate frontend import --- pkg/frontend/authenticate.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index e598743bfa217..e9eeec15b8d01 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -20,7 +20,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/matrixorigin/matrixone/pkg/util/errutil" "io" "math" "math/bits" From f9cc07372ef88ce4ee3d484df1c37977800be351 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 20 Sep 2026 22:43:02 +0800 Subject: [PATCH 194/241] fix(udf): preserve Python UDF test dependencies --- cmd/mo-service/main.go | 2 +- optools/run_ut.sh | 22 +++++++++++++------- pkg/udf/python/worker/test_worker.py | 31 ++++++++++++++++++++++++++++ pkg/udf/python/worker/worker.py | 5 ++++- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/cmd/mo-service/main.go b/cmd/mo-service/main.go index c6bb1423f32ce..8f6a3605c527f 100644 --- a/cmd/mo-service/main.go +++ b/cmd/mo-service/main.go @@ -785,7 +785,7 @@ func startPythonUdfWorker(cfg *Config, stopper *stopper.Stopper) error { if workerErr == nil { workerErr = errors.New("process exited without an error") } - closeErr = fmt.Errorf("Python UDF worker exited unexpectedly: %w", workerErr) + closeErr = fmt.Errorf("python UDF worker exited unexpectedly: %w", workerErr) serviceLifecycle.notifyFatal(closeErr) } } diff --git a/optools/run_ut.sh b/optools/run_ut.sh index b43528a4d0a94..49083fd8bb4fd 100755 --- a/optools/run_ut.sh +++ b/optools/run_ut.sh @@ -2804,13 +2804,21 @@ function run_tests(){ fi mark_ut_stage "routing" "validate shard and package partition" finish 0 - mark_ut_stage "prepare" "prepare Python UDF dependencies" start - prepare_python_udf_dependencies - local python_udf_dependency_status=$? - mark_ut_stage "prepare" "prepare Python UDF dependencies" finish "${python_udf_dependency_status}" - if (( python_udf_dependency_status != 0 )); then - UT_TEST_STATUS=1 - return 0 + # The Python UDF package belongs to the light stage. Split shards execute + # only their selected stage groups; preparing a repository-relative + # requirements file in a synthetic heavy-plan harness is both unnecessary + # and invalid because that harness intentionally contains no pkg tree. + if should_run_ut_stage light; then + mark_ut_stage "prepare" "prepare Python UDF dependencies" start + prepare_python_udf_dependencies + local python_udf_dependency_status=$? + mark_ut_stage "prepare" "prepare Python UDF dependencies" finish "${python_udf_dependency_status}" + if (( python_udf_dependency_status != 0 )); then + UT_TEST_STATUS=1 + return 0 + fi + else + logger "INF" "Skip Python UDF dependency preparation for UT_SHARD=${UT_SHARD}" fi mark_ut_stage "prepare" "clean go test cache" start diff --git a/pkg/udf/python/worker/test_worker.py b/pkg/udf/python/worker/test_worker.py index 3c1a5616c3667..3df7f07549055 100644 --- a/pkg/udf/python/worker/test_worker.py +++ b/pkg/udf/python/worker/test_worker.py @@ -2896,6 +2896,37 @@ def test_handler_does_not_inherit_parent_environment(self): ) self.assertEqual([False], result.column(0).to_pylist()) + def test_handler_preserves_runtime_pythonpath(self): + descriptor = {"type_id": worker.BOOL, "offset_width": 32} + batch = pa.RecordBatch.from_arrays( + [pa.array([True], type=pa.bool_())], ["arg_0"] + ) + request = { + "source": ( + "import os\n" + "def f(ctx, x):\n" + " return os.environ.get('PYTHONPATH', '').startswith('matrixone-test-pythonpath')" + ), + "handler": "f", + "mode": worker.MODE_SCALAR, + "null_policy": worker.NULL_CALL, + "sdk_version": worker.SDK_VERSION, + "context": None, + "args": [descriptor], + "return": descriptor, + "max_batch_bytes": 1 << 20, + "input": worker._serialize_record_batch(batch), + } + inherited = os.environ.get("PYTHONPATH", "") + runtime_path = "matrixone-test-pythonpath" + if inherited: + runtime_path += os.pathsep + inherited + with mock.patch.dict(os.environ, {"PYTHONPATH": runtime_path}, clear=False): + result = worker._deserialize_record_batch( + worker._run_handler_process(None, request, 3) + ) + self.assertEqual([True], result.column(0).to_pylist()) + def test_handler_cannot_forge_completion_on_stdout(self): descriptor = {"type_id": worker.INT64, "offset_width": 32} batch = pa.RecordBatch.from_arrays([pa.array([77], type=pa.int64())], ["arg_0"]) diff --git a/pkg/udf/python/worker/worker.py b/pkg/udf/python/worker/worker.py index fee826d826f65..f73ea706dc18d 100644 --- a/pkg/udf/python/worker/worker.py +++ b/pkg/udf/python/worker/worker.py @@ -240,7 +240,10 @@ class _NoFlightServerBase: _HANDLER_REQUEST_BATCH = "batch" _HANDLER_RESPONSE_FD_ENV = "MATRIXONE_HANDLER_RESPONSE_FD" _HANDLER_PARENT_WATCH_FD_ENV = "MATRIXONE_HANDLER_PARENT_WATCH_FD" -_HANDLER_ENV_ALLOWLIST = frozenset({"PATH"}) +# UT may install the checked-out worker requirements into a temporary target +# and expose it through PYTHONPATH. Preserve only that runtime path in handler +# children; the rest of the parent environment remains excluded. +_HANDLER_ENV_ALLOWLIST = frozenset({"PATH", "PYTHONPATH"}) _MICROS_PER_SECOND = 1_000_000 _MAX_TIME_MICROS = (838 * 60 * 60 + 59 * 60 + 59) * _MICROS_PER_SECOND _MIN_TIMESTAMP = _datetime.datetime(1970, 1, 1, 0, 0, 1, tzinfo=_datetime.timezone.utc) From d08d1e8654d7594019027d9d464b1574b8f9183b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 21 Sep 2026 08:54:13 +0800 Subject: [PATCH 195/241] test(optools): isolate Python dependency probe in scheduler harness --- optools/ut_schedule_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/optools/ut_schedule_test.go b/optools/ut_schedule_test.go index 6571651bebc22..d4785aba53d6d 100644 --- a/optools/ut_schedule_test.go +++ b/optools/ut_schedule_test.go @@ -118,6 +118,27 @@ func scheduleHarnessWithMockTransform(t *testing.T, script, mock string, transfo if err := os.WriteFile(filepath.Join(dir, "go"), []byte(mock), 0755); err != nil { t.Fatal(err) } + // The scheduler fixture has no repository package tree, so it cannot run + // the real dependency bootstrap. Simulate only the already-prepared + // pyarrow probe and pass every other Python invocation to the host + // interpreter so the existing report/heartbeat helpers keep their coverage. + python3, err := exec.LookPath("python3") + if err != nil { + python3 = "" + } + pythonStub := `#!/bin/bash +if [[ "$#" == 2 && "$1" == -c && "$2" == "import pyarrow" ]]; then + exit 0 +fi +if [[ -n "${MATRIXONE_TEST_REAL_PYTHON3:-}" ]]; then + exec "${MATRIXONE_TEST_REAL_PYTHON3}" "$@" +fi +echo "python3 is unavailable in the scheduler harness" >&2 +exit 127 +` + if err := os.WriteFile(filepath.Join(dir, "python3"), []byte(pythonStub), 0755); err != nil { + t.Fatal(err) + } ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) defer cancel() cmd := exec.CommandContext(ctx, "bash", "-c", script) @@ -135,6 +156,9 @@ func scheduleHarnessWithMockTransform(t *testing.T, script, mock string, transfo cmd.Env = append(cmd.Env, value) } cmd.Env = append(cmd.Env, "PATH="+dir+string(os.PathListSeparator)+os.Getenv("PATH"), "UT_WORKDIR="+root, "CASE_DIR="+root, "UT_LINK_PARALLEL=0", "GOFLAGS=") + if python3 != "" { + cmd.Env = append(cmd.Env, "MATRIXONE_TEST_REAL_PYTHON3="+python3) + } cmd.Env = append(cmd.Env, variables...) out, err, diagnostic := runScheduleHarnessCommand(ctx, cmd, root) if diagnostic != "" { From e3b92036a8aff104af90c7ee6b808dc326f851bc Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 23 Sep 2026 18:38:18 +0800 Subject: [PATCH 196/241] test(udf): cover CI contracts and failure paths --- optools/ut_holder_test.go | 40 +- pkg/cnservice/python_runtime_test.go | 81 ++ pkg/frontend/clone_database_source_test.go | 92 +++ pkg/frontend/compiler_context_test.go | 107 +++ pkg/frontend/python_udf_catalog_test.go | 290 +++++++ pkg/frontend/routine_plan_validation_test.go | 146 ++++ pkg/sql/colexec/external_routine_eval_test.go | 264 +++++- pkg/udf/python/arrow_test.go | 20 +- pkg/udf/python/config_test.go | 40 + pkg/udf/python/gateway_test.go | 776 ++++++++++++++++++ pkg/udf/runtime_test.go | 66 ++ 11 files changed, 1919 insertions(+), 3 deletions(-) diff --git a/optools/ut_holder_test.go b/optools/ut_holder_test.go index f6a77fa6ca871..fc2f5fc235d4e 100644 --- a/optools/ut_holder_test.go +++ b/optools/ut_holder_test.go @@ -40,7 +40,9 @@ func TestUTAdmissionHolderEvidence(t *testing.T) { if err := os.WriteFile(path, []byte(strings.Join(tt.events, "\n")), 0600); err != nil { t.Fatal(err) } - out, err := exec.Command("python3", "summarize_ut_setup.py", path).CombinedOutput() + cmd := exec.Command("python3", "summarize_ut_setup.py", path) + cmd.Env = pythonStdlibEnvironment() + out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("summary: %v\n%s", err, out) } @@ -54,3 +56,39 @@ func TestUTAdmissionHolderEvidence(t *testing.T) { }) } } + +func TestPythonStdlibEnvironmentDropsNativeAndImportOverrides(t *testing.T) { + t.Setenv("LD_LIBRARY_PATH", "/matrixone/cgo") + t.Setenv("PYTHONPATH", "/matrixone/python") + t.Setenv("PYTHONHOME", "/matrixone/python-home") + t.Setenv("PYTHONUSERBASE", "/matrixone/user-site") + + env := pythonStdlibEnvironment() + if !strings.Contains(strings.Join(env, "\n"), "PATH=") { + t.Fatal("sanitized Python environment lost PATH") + } + for _, entry := range env { + for _, forbidden := range []string{"LD_LIBRARY_PATH=", "PYTHONPATH=", "PYTHONHOME=", "PYTHONUSERBASE="} { + if strings.HasPrefix(entry, forbidden) { + t.Fatalf("Python stdlib helper inherited %q", entry) + } + } + } +} + +// pythonStdlibEnvironment keeps the configured interpreter discoverable while +// preventing MatrixOne's native-library and Python import paths from changing +// a standard-library-only report parser's runtime. +func pythonStdlibEnvironment() []string { + env := make([]string, 0, len(os.Environ())) + for _, entry := range os.Environ() { + key, _, _ := strings.Cut(entry, "=") + switch key { + case "LD_LIBRARY_PATH", "PYTHONHOME", "PYTHONPATH", "PYTHONUSERBASE", "PYTHONSTARTUP", "PYTHONINSPECT": + continue + default: + env = append(env, entry) + } + } + return env +} diff --git a/pkg/cnservice/python_runtime_test.go b/pkg/cnservice/python_runtime_test.go index e3eff6af6fed6..1052bdffd7396 100644 --- a/pkg/cnservice/python_runtime_test.go +++ b/pkg/cnservice/python_runtime_test.go @@ -18,6 +18,8 @@ import ( "context" "testing" + "github.com/matrixorigin/matrixone/pkg/pb/metadata" + "github.com/matrixorigin/matrixone/pkg/pb/query" "github.com/matrixorigin/matrixone/pkg/udf" "github.com/matrixorigin/matrixone/pkg/udf/python" "github.com/stretchr/testify/require" @@ -51,3 +53,82 @@ func TestBuildCNRuntimeDisabledDoesNotCreatePythonRuntime(t *testing.T) { require.True(t, ok) require.ErrorContains(t, readiness.CheckLanguageReady(context.Background(), udf.LanguagePython), "not enabled") } + +func TestUnavailablePythonRuntimeRejectsOperationsWithoutAWorker(t *testing.T) { + runtime := &unavailablePythonRuntime{} + require.Equal(t, udf.LanguagePython, runtime.Language()) + require.ErrorContains(t, runtime.Execute( + context.Background(), nil, nil, nil, + ), "Python UDF runtime initialization failed") + require.ErrorContains(t, runtime.CheckLanguageReady(context.Background(), "sql"), "unsupported readiness language") + require.ErrorContains(t, runtime.CheckLanguageReady(context.Background(), udf.LanguagePython), "RESOURCE_UNAVAILABLE") + + canceled, cancel := context.WithCancel(context.Background()) + cancel() + require.ErrorIs(t, runtime.CheckLanguageReady(canceled, udf.LanguagePython), context.Canceled) + require.ErrorContains(t, runtime.ValidateDefinition(context.Background(), nil), "invalid Python definition") + require.ErrorContains(t, runtime.ValidateDefinition(context.Background(), &udf.RoutineDefinition{Language: "sql"}), "invalid Python definition") + require.Equal(t, udf.RuntimeStatusUnavailable, + runtime.StatusSnapshot(context.Background(), "sql").ErrorClass) +} + +type pythonStatusRuntime struct { + udf.Runtime + snapshot udf.RuntimeStatusSnapshot +} + +func (r *pythonStatusRuntime) StatusSnapshot(context.Context, string) udf.RuntimeStatusSnapshot { + return r.snapshot +} + +type pythonRuntimeWithoutStatus struct{ udf.Runtime } + +func TestGetPythonUdfStatusReturnsCNLocalBoundedRuntimeState(t *testing.T) { + status := udf.RuntimeStatusSnapshot{ + Language: udf.LanguagePython, + Enabled: true, + AllowUnisolated: true, + Ready: true, + ProtocolVersion: 1, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + DefinitionSchemaVersion: 1, + PlanContractVersion: 1, + TypeDescriptorContract: "arrow-sql-v1", + TimezoneDatabaseVersion: "2026c", + WindowBatches: 1, + MaxExecutionFrameBytes: 1 << 30, + MaxHandlerProcesses: 8, + MaxAccountHandlerProcesses: 8, + MaxOwnerHandlerProcesses: 4, + LeaseEpoch: 42, + Modes: []string{"SCALAR", "VECTOR"}, + NullPolicies: []string{"CALLED_ON_NULL_INPUT", "RETURNS_NULL_ON_NULL_INPUT"}, + } + s := &service{ + metadata: metadata.CNStore{UUID: "cn-local"}, + udfService: &pythonStatusRuntime{Runtime: &unavailablePythonRuntime{}, snapshot: status}, + } + response := &query.Response{} + require.NoError(t, s.handleGetPythonUdfStatus(context.Background(), nil, response, nil)) + got := response.GetPythonUdfStatus + require.Equal(t, "cn-local", got.CNUUID) + require.Equal(t, udf.LanguagePython, got.Language) + require.True(t, got.Enabled) + require.True(t, got.AllowUnisolated) + require.True(t, got.Ready) + require.Equal(t, int32(1), got.ProtocolVersion) + require.Equal(t, udf.PythonABIContract, got.ABIContract) + require.Equal(t, uint64(42), got.LeaseEpoch) + require.Equal(t, []string{"SCALAR", "VECTOR"}, got.Modes) + require.Equal(t, []string{"CALLED_ON_NULL_INPUT", "RETURNS_NULL_ON_NULL_INPUT"}, got.NullPolicies) + + // The query service has a stable fail-closed status if an older/custom + // Runtime implementation does not provide the bounded status contract. + s.udfService = pythonRuntimeWithoutStatus{} + response = &query.Response{} + require.NoError(t, s.handleGetPythonUdfStatus(context.Background(), nil, response, nil)) + require.Equal(t, udf.RuntimeStatusUnavailable, response.GetPythonUdfStatus.ErrorClass) + require.Equal(t, udf.RuntimeStatusReasonStatusUnavailable, response.GetPythonUdfStatus.Reason) +} diff --git a/pkg/frontend/clone_database_source_test.go b/pkg/frontend/clone_database_source_test.go index ccc37082884bb..a20f82bfada7a 100644 --- a/pkg/frontend/clone_database_source_test.go +++ b/pkg/frontend/clone_database_source_test.go @@ -24,7 +24,11 @@ import ( "github.com/golang/mock/gomock" "github.com/matrixorigin/matrixone/pkg/catalog" "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/fileservice" + "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + pythonudf "github.com/matrixorigin/matrixone/pkg/udf/python" "github.com/stretchr/testify/require" mock_frontend "github.com/matrixorigin/matrixone/pkg/frontend/test" @@ -417,6 +421,94 @@ func TestRestoreCloneDatabaseUserDefinedFunctions(t *testing.T) { require.Len(t, failing.executedSQLs, 1) } +func TestValidateCloneUserDefinedFunctionsRejectsInertOrMalformedPython(t *testing.T) { + validPython := pythonCatalogTestBody(t, types.T_int64) + for _, tc := range []struct { + name string + definition userDefinedFunctionDefinition + wantError string + }{ + { + name: "current Python definition is cloneable", + definition: userDefinedFunctionDefinition{name: "f", lang: "python", body: validPython}, + }, + { + name: "old Python demo is rejected", + definition: userDefinedFunctionDefinition{name: "legacy", lang: "python", body: `{"handler":"f","source":"old"}`}, + wantError: "unsupported python function legacy", + }, + { + name: "malformed body is rejected", + definition: userDefinedFunctionDefinition{name: "broken", lang: "python", body: "{"}, + wantError: "malformed python function broken", + }, + { + name: "imported non SQL function is rejected", + definition: userDefinedFunctionDefinition{name: "imported", lang: "python", body: `{"import":true}`}, + wantError: "imported python function imported", + }, + { + name: "SQL definition keeps existing clone behavior", + definition: userDefinedFunctionDefinition{name: "sql_f", lang: "sql", body: "select 1"}, + }, + } { + t.Run(tc.name, func(t *testing.T) { + err := validateCloneUserDefinedFunctions([]userDefinedFunctionDefinition{tc.definition}) + if tc.wantError == "" { + require.NoError(t, err) + } else { + require.ErrorContains(t, err, tc.wantError) + } + }) + } +} + +func TestRestoreCloneDatabasePythonRoutineRepublishesTargetArtifact(t *testing.T) { + ctx := context.Background() + const accountID = uint32(27) + tenant := &TenantInfo{User: "root1", TenantID: accountID, DefaultRoleID: accountAdminRoleID} + body := pythonCatalogTestBody(t, types.T_int64) + decoded, err := function.DecodePythonRoutineBody(body) + require.NoError(t, err) + inputDescriptor, _, _, err := function.PythonSignatureMetadata(decoded.ArgTypes, decoded.ReturnType) + require.NoError(t, err) + definition := userDefinedFunctionDefinition{ + name: "cloned_python", + args: `[{"name":"value","type":"bigint"}]`, + argTypes: `["bigint"]`, + retType: "bigint", + body: body, + lang: "python", + dbName: "source_db", + canonicalInputDescriptor: inputDescriptor, + } + findSQL := `select function_id from mo_catalog.mo_user_defined_function where name = "cloned_python" and db = "target_db" and canonical_input_descriptor = "` + escapeSQLStringForDoubleQuotes(inputDescriptor) + `" and language = 'python' order by function_id desc limit 1;` + background := &backgroundExecTest{} + background.init() + background.sql2result[findSQL] = singleInt64Result("function_id", 97) + fs, err := fileservice.NewMemoryFS(defines.SharedFileServiceName, fileservice.DisabledCacheConfig, nil) + require.NoError(t, err) + + require.NoError(t, restoreCloneDatabaseUserDefinedFunctions( + ctx, background, tenant, []userDefinedFunctionDefinition{definition}, "target_db", fs, + )) + require.Contains(t, background.executedSQLs[0], `"cloned_python"`) + require.Contains(t, background.executedSQLs[0], `"target_db"`) + store, err := pythonudf.NewFileArtifactStore(fs, pythonudf.DefaultMaxArtifactBytes) + require.NoError(t, err) + resolved, err := store.Resolve(ctx, uint64(accountID), decoded.Handler, decoded.ArtifactDigest) + require.NoError(t, err) + require.Equal(t, decoded.Source, resolved) + + withoutStore := &backgroundExecTest{} + withoutStore.init() + err = restoreCloneDatabaseUserDefinedFunctions( + ctx, withoutStore, tenant, []userDefinedFunctionDefinition{definition}, "target_db", + ) + require.ErrorContains(t, err, "artifact store is required") + require.Empty(t, withoutStore.executedSQLs, "a routine must not be persisted before its artifact store is available") +} + func TestRestoreCloneDatabaseStoredProcedures(t *testing.T) { ctx := context.Background() tenant := &TenantInfo{User: "root1", DefaultRoleID: accountAdminRoleID} diff --git a/pkg/frontend/compiler_context_test.go b/pkg/frontend/compiler_context_test.go index 859ed2592a56c..4fae7d8c12d48 100644 --- a/pkg/frontend/compiler_context_test.go +++ b/pkg/frontend/compiler_context_test.go @@ -36,6 +36,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/plan/function" "github.com/matrixorigin/matrixone/pkg/testutil" "github.com/matrixorigin/matrixone/pkg/txn/client" + "github.com/matrixorigin/matrixone/pkg/udf" "github.com/matrixorigin/matrixone/pkg/vm/engine" "github.com/stretchr/testify/require" ) @@ -89,6 +90,112 @@ func TestSubscriptionMetasFromSubInfos(t *testing.T) { }, metas) } +func TestResolveUdfBindsExactPythonRevisionAndNamespace(t *testing.T) { + ctx := defines.AttachAccountId(context.Background(), 0) + ses := &Session{feSessionImpl: feSessionImpl{}} + ses.SetAccountId(0) + background := &backgroundExecTestWithHistory{} + background.init() + previousNewBackgroundExec := NewBackgroundExec + NewBackgroundExec = func(context.Context, FeSession, ...*BackgroundExecOption) BackgroundExec { + return background + } + t.Cleanup(func() { NewBackgroundExec = previousNewBackgroundExec }) + + body := pythonCatalogTestBody(t, types.T_int64) + decoded, err := function.DecodePythonRoutineBody(body) + require.NoError(t, err) + logicalArgs := `[{"name":"value","type":"bigint"}]` + compiler := &TxnCompilerContext{execCtx: &ExecCtx{reqCtx: ctx, ses: ses}} + compiler.SetDatabase("app") + _, candidateSQL := udfCatalogLookup(ctx, nil, "f", "app") + background.sql2result[candidateSQL] = resolveUdfCatalogResult( + []string{"function_id", "args", "body", "language", "rettype", "db", "modified_time", "sql_mode"}, + []interface{}{int64(44), logicalArgs, body, "python", "bigint", "app", "2026-09-20 00:00:00", ""}, + ) + + inputDescriptor, returnDescriptor, signatureFingerprint, err := function.PythonSignatureMetadata(decoded.ArgTypes, decoded.ReturnType) + require.NoError(t, err) + definitionFingerprint, err := function.PythonRoutineFingerprint(body) + require.NoError(t, err) + background.sql2result[pythonRevisionCatalogSQL(nil, 44)] = resolveUdfCatalogResult( + []string{ + "active_revision", "namespace_version", "revision", "canonical_input_descriptor", "return_descriptor", + "signature_key_schema_version", "signature_fingerprint", "args", "arg_types", "body", "language", + "rettype", "definition_schema_version", "abi_contract", "adapter_version", "sdk_version", "null_policy", + "volatility", "definition_fingerprint", "artifact_digest", "environment_digest", "revision_security_type", "head_security_type", + }, + []interface{}{ + int64(1), int64(1), int64(1), inputDescriptor, returnDescriptor, int64(udf.PythonSignatureKeySchemaVersion), + signatureFingerprint, logicalArgs, inputDescriptor, body, "python", "bigint", int64(udf.PythonDefinitionSchemaVersion), + udf.PythonABIContract, udf.PythonAdapterVersion, udf.PythonSDKVersion, udf.NullCallHandler, "VOLATILE", + definitionFingerprint, decoded.ArtifactDigest, decoded.EnvironmentDigest, "INVOKER", "INVOKER", + }, + ) + background.sql2result["select dat_id from mo_catalog.mo_database where datname = 'app' and account_id = 0;"] = singleInt64Result("dat_id", 88) + namespaceSQL := routineNamespacesSQL([]uint64{44}, nil) + background.sql2result[namespaceSQL] = namespaceRows(namespaceMember(44, "candidate-state")) + + argumentType := types.T_int64.ToType() + resolved, err := compiler.ResolveUdf("f", []*pbplan.Expr{{Typ: plan2.MakePlan2Type(&argumentType)}}) + require.NoError(t, err) + require.Equal(t, int64(44), resolved.FunctionID) + require.Equal(t, uint64(1), resolved.Revision) + require.Equal(t, uint64(1), resolved.NamespaceVersion) + require.Equal(t, uint64(88), resolved.DatabaseID) + require.NotEmpty(t, resolved.NamespaceFingerprint) + require.Equal(t, []types.Type{types.T_int64.ToType()}, resolved.ArgsType) + require.Contains(t, background.executedSqls, candidateSQL) + require.Contains(t, background.executedSqls, pythonRevisionCatalogSQL(nil, 44)) + require.Contains(t, background.executedSqls, namespaceSQL) +} + +func TestResolveUdfKeepsLegacySQLRoutineReadableWithoutRevisionCatalog(t *testing.T) { + ctx := defines.AttachAccountId(context.Background(), 0) + ses := &Session{feSessionImpl: feSessionImpl{}} + ses.SetAccountId(0) + background := &backgroundExecTestWithHistory{} + background.init() + previousNewBackgroundExec := NewBackgroundExec + NewBackgroundExec = func(context.Context, FeSession, ...*BackgroundExecOption) BackgroundExec { + return background + } + t.Cleanup(func() { NewBackgroundExec = previousNewBackgroundExec }) + + compiler := &TxnCompilerContext{execCtx: &ExecCtx{reqCtx: ctx, ses: ses}} + compiler.SetDatabase("app") + _, candidateSQL := udfCatalogLookup(ctx, nil, "legacy_f", "app") + background.sql2result[candidateSQL] = resolveUdfCatalogResult( + []string{"function_id", "args", "body", "language", "rettype", "db", "modified_time", "sql_mode"}, + []interface{}{int64(52), `[{"name":"value","type":"bigint"}]`, "select value + 1", "sql", "bigint", "app", "2026-09-20 00:00:00", ""}, + ) + background.sql2err["select active_revision, namespace_version, security_type from mo_catalog.mo_user_defined_function where function_id = 52;"] = errors.New("no such table: mo_function_revisions") + argumentType := types.T_int64.ToType() + resolved, err := compiler.ResolveUdf("legacy_f", []*pbplan.Expr{{Typ: plan2.MakePlan2Type(&argumentType)}}) + require.NoError(t, err) + require.Equal(t, int64(52), resolved.FunctionID) + require.Equal(t, "sql", resolved.Language) + require.Zero(t, resolved.Revision, "a legacy SQL definition stays on its existing body while the shared revision table is absent") + require.Equal(t, []types.Type{types.T_int64.ToType()}, resolved.ArgsType) + require.Contains(t, background.executedSqls, "select active_revision, namespace_version, security_type from mo_catalog.mo_user_defined_function where function_id = 52;") +} + +func resolveUdfCatalogResult(columns []string, row []interface{}) *MysqlResultSet { + result := &MysqlResultSet{} + for index, name := range columns { + column := &MysqlColumn{} + column.SetName(name) + if _, ok := row[index].(int64); ok { + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + } else { + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + } + result.AddColumn(column) + } + result.AddRow(row) + return result +} + func TestSubscriptionMetadataEnumerationObservesCancellation(t *testing.T) { wantErr := errors.New("stop subscription metadata enumeration") ctx, cancel := context.WithCancelCause(context.Background()) diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index a454781694c31..849e7bdc85ec0 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -17,6 +17,7 @@ package frontend import ( "context" "encoding/json" + "errors" "fmt" "strconv" "strings" @@ -100,6 +101,123 @@ func TestValidatePythonUdfDefinitionAtCreateUsesTypedWorkerGate(t *testing.T) { require.Equal(t, types.T_int64.ToType(), runtime.definition.ReturnType) } +func TestInitPythonFunctionValidatesArtifactBeforeCatalogReadiness(t *testing.T) { + const service = "python-create-catalog-gate-test" + InitServerLevelVars(service) + previousPU := getPuIfPresent(service) + t.Cleanup(func() { setPu(service, previousPU) }) + + fs, err := fileservice.NewMemoryFS(defines.SharedFileServiceName, fileservice.DisabledCacheConfig, nil) + require.NoError(t, err) + runtime := &definitionValidationRuntime{} + pu := config.NewParameterUnit(&config.FrontendParameters{}, nil, nil, nil) + pu.FileService = fs + pu.UdfService = runtime + setPu(service, pu) + + ctx := defines.AttachAccountId(context.Background(), 27) + statement, err := parsers.ParseOne(ctx, dialect.MYSQL, + "create function app.py_echo(value bigint) returns bigint language python as 'def py_echo(ctx, value): return value' handler 'py_echo' mode scalar called on null input", 1) + require.NoError(t, err) + defer statement.Free() + createFunction, ok := statement.(*tree.CreateFunction) + require.True(t, ok) + + background := &backgroundExecTestWithHistory{} + background.init() + background.sql2result[pythonUdfCatalogIdentitySchemaCheck] = emptyCatalogProbeResult(6) + missingRevisionCatalog := errors.New("revision catalog has not been upgraded") + background.sql2err[functionRevisionCatalogSchemaCheck] = missingRevisionCatalog + previousNewBackgroundExec := NewBackgroundExec + NewBackgroundExec = func(context.Context, FeSession, ...*BackgroundExecOption) BackgroundExec { + return background + } + t.Cleanup(func() { NewBackgroundExec = previousNewBackgroundExec }) + + tenant := &TenantInfo{User: "root", TenantID: 27, DefaultRoleID: accountAdminRoleID} + session := &Session{feSessionImpl: feSessionImpl{service: service, tenant: tenant}} + err = InitFunction(session, &ExecCtx{reqCtx: ctx}, tenant, createFunction) + require.ErrorContains(t, err, "Python UDF catalog contract is not ready") + require.ErrorContains(t, err, missingRevisionCatalog.Error()) + require.NotNil(t, runtime.definition, "CREATE must validate the source with the current worker before opening the catalog transaction") + require.Equal(t, uint64(27), runtime.definition.AccountID) + require.Equal(t, "py_echo", runtime.definition.Handler) + require.Equal(t, "def py_echo(ctx, value): return value", runtime.definition.Source) + require.Equal(t, "SCALAR", runtime.definition.Mode) + require.Equal(t, udf.NullCallHandler, runtime.definition.NullPolicy) + + store, err := pythonudf.NewFileArtifactStore(fs, pythonudf.DefaultMaxArtifactBytes) + require.NoError(t, err) + resolved, err := store.Resolve(ctx, 27, runtime.definition.Handler, runtime.definition.ArtifactDigest) + require.NoError(t, err) + require.Equal(t, runtime.definition.Source, resolved) + for _, query := range background.executedSqls { + require.NotContains(t, query, "insert into mo_catalog.mo_user_defined_function") + require.NotContains(t, query, "insert into mo_catalog.mo_function_revisions") + } +} + +func TestInitPythonFunctionChecksExactOverloadBeforePublishing(t *testing.T) { + const service = "python-create-overload-check-test" + InitServerLevelVars(service) + previousPU := getPuIfPresent(service) + t.Cleanup(func() { setPu(service, previousPU) }) + + fs, err := fileservice.NewMemoryFS(defines.SharedFileServiceName, fileservice.DisabledCacheConfig, nil) + require.NoError(t, err) + runtime := &definitionValidationRuntime{} + pu := config.NewParameterUnit(&config.FrontendParameters{}, nil, nil, nil) + pu.FileService = fs + pu.UdfService = runtime + setPu(service, pu) + + ctx := defines.AttachAccountId(context.Background(), 27) + statement, err := parsers.ParseOne(ctx, dialect.MYSQL, + "create function app.py_echo(value bigint) returns bigint language python as 'def py_echo(ctx, value): return value' handler 'py_echo'", 1) + require.NoError(t, err) + defer statement.Free() + createFunction := statement.(*tree.CreateFunction) + + background := &backgroundExecTestWithHistory{} + background.init() + background.sql2result[pythonUdfCatalogIdentitySchemaCheck] = emptyCatalogProbeResult(6) + background.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) + databaseSQL, err := getSqlForCheckDatabaseByAccount(ctx, "app") + require.NoError(t, err) + databaseSQL = strings.TrimSuffix(databaseSQL, ";") + " for update;" + background.sql2result[databaseSQL] = singleInt64Result("dat_id", 8) + decoded, err := function.DecodePythonRoutineBody(pythonCatalogTestBody(t, types.T_int64)) + require.NoError(t, err) + canonicalInput, _, _, err := function.PythonSignatureMetadata(decoded.ArgTypes, decoded.ReturnType) + require.NoError(t, err) + checkCandidatesSQL := fmt.Sprintf(checkPythonUdfExistence, "py_echo", "app") + background.sql2result[checkCandidatesSQL] = resolveUdfCatalogResult( + []string{"function_id", "args", "language", "arg_types", "canonical_input_descriptor"}, + []interface{}{int64(55), `[{"name":"value","type":"bigint"}]`, "python", `["bigint"]`, + canonicalInput}, + ) + previousNewBackgroundExec := NewBackgroundExec + NewBackgroundExec = func(context.Context, FeSession, ...*BackgroundExecOption) BackgroundExec { + return background + } + t.Cleanup(func() { NewBackgroundExec = previousNewBackgroundExec }) + + tenant := &TenantInfo{User: "root", TenantID: 27, DefaultRoleID: accountAdminRoleID} + session := &Session{feSessionImpl: feSessionImpl{service: service, tenant: tenant}} + err = InitFunction(session, &ExecCtx{reqCtx: ctx}, tenant, createFunction) + require.ErrorContains(t, err, "already exists") + require.NotNil(t, runtime.definition, "the submitted source must be validated before the locked exact-signature check") + require.Equal(t, uint64(27), runtime.definition.AccountID) + require.Equal(t, "py_echo", runtime.definition.Handler) + require.Contains(t, background.executedSqls, databaseSQL) + require.Contains(t, background.executedSqls, checkCandidatesSQL) + require.Contains(t, background.executedSqls, "rollback;") + for _, query := range background.executedSqls { + require.NotContains(t, query, "insert into mo_catalog.mo_user_defined_function") + require.NotContains(t, query, "insert into mo_catalog.mo_function_revisions") + } +} + func TestPersistPythonReplaceRejectsLegacyHeadBeforeWriting(t *testing.T) { ctx := context.Background() functionID := int64(41) @@ -686,6 +804,114 @@ func TestReadSQLRevisionBindsActiveHeadAndRejectsTampering(t *testing.T) { _, found, err = readSQLRevision(context.Background(), bh, functionID, nil) require.ErrorContains(t, err, "fingerprint mismatch") require.False(t, found) + + for _, tc := range []struct { + name string + mutateBase func(*MysqlResultSet) + mutateVersion func(*MysqlResultSet) + wantError string + wantFound bool + }{ + { + name: "legacy head before shared revision upgrade", + mutateBase: func(result *MysqlResultSet) { + result.Data[0][0], result.Data[0][1] = int64(0), int64(0) + }, + }, + { + name: "partial revision head", + mutateBase: func(result *MysqlResultSet) { + result.Data[0][0] = int64(0) + }, + wantError: "invalid revision head", + }, + { + name: "missing active revision row", + mutateVersion: func(result *MysqlResultSet) { + result.Data = nil + }, + wantError: "expected exactly one", + }, + { + name: "revision id differs from head", + mutateVersion: func(result *MysqlResultSet) { + result.Data[0][0] = int64(2) + }, + wantError: "revision contract is not supported", + }, + { + name: "wrong implementation language", + mutateVersion: func(result *MysqlResultSet) { + result.Data[0][5] = "python" + }, + wantError: "revision contract is not supported", + }, + { + name: "wrong definition schema", + mutateVersion: func(result *MysqlResultSet) { + result.Data[0][6] = int64(udf.SQLDefinitionSchemaVersion + 100) + }, + wantError: "revision contract is not supported", + }, + { + name: "non volatile revision", + mutateVersion: func(result *MysqlResultSet) { + result.Data[0][8] = "IMMUTABLE" + }, + wantError: "revision contract is not supported", + }, + { + name: "wrong null policy", + mutateVersion: func(result *MysqlResultSet) { + result.Data[0][9] = "STRICT" + }, + wantError: "revision contract is not supported", + }, + { + name: "security contract differs from head", + mutateVersion: func(result *MysqlResultSet) { + result.Data[0][10] = "INVOKER" + }, + wantError: "revision contract is not supported", + }, + { + name: "malformed logical argument metadata", + mutateVersion: func(result *MysqlResultSet) { + result.Data[0][1] = "{" + }, + wantError: "argument metadata is invalid", + }, + { + name: "logical argument metadata disagrees", + mutateVersion: func(result *MysqlResultSet) { + result.Data[0][2] = `["int"]` + }, + wantError: "argument metadata is invalid", + }, + } { + t.Run(tc.name, func(t *testing.T) { + background := &backgroundExecTest{} + background.init() + base := newBase() + if tc.mutateBase != nil { + tc.mutateBase(base) + } + background.sql2result[baseSQL] = base + version := newRevision(body, fingerprint) + if tc.mutateVersion != nil { + tc.mutateVersion(version) + } + background.sql2result[revisionSQL] = version + _, found, err := readSQLRevision(context.Background(), background, functionID, nil) + if tc.wantError != "" { + require.ErrorContains(t, err, tc.wantError) + require.False(t, found) + return + } + require.NoError(t, err) + require.Equal(t, tc.wantFound, found) + }) + } } func TestEnsurePythonUdfCatalogReadyRequiresCurrentSchema(t *testing.T) { @@ -780,6 +1006,70 @@ func TestValidateRestoredPythonRevisionCatalogChecksCurrentContract(t *testing.T ) } +func TestValidateRestoredPythonRevisionCatalogRejectsMalformedContracts(t *testing.T) { + body := pythonCatalogTestBody(t, types.T_int64) + decoded, err := function.DecodePythonRoutineBody(body) + require.NoError(t, err) + inputDescriptor, _, _, err := function.PythonSignatureMetadata(decoded.ArgTypes, decoded.ReturnType) + require.NoError(t, err) + fingerprint, err := function.PythonRoutineFingerprint(body) + require.NoError(t, err) + baseRow := []string{ + "44", "1", "1", "f", `[{"name":"value","type":"bigint"}]`, inputDescriptor, "bigint", body, + udf.LanguagePython, strconv.Itoa(udf.PythonDefinitionSchemaVersion), udf.PythonABIContract, + udf.PythonAdapterVersion, decoded.ArtifactDigest, decoded.EnvironmentDigest, udf.PythonSDKVersion, + decoded.NullPolicy, "VOLATILE", fingerprint, "2026-09-11 00:00:00", "INVOKER", + } + query := fmt.Sprintf( + "select %s from %s order by function_id, revision;", + functionRevisionCatalogColumns, + qualifiedTableName(moCatalog, "mo_function_revisions"), + ) + newResult := func(row []string) *MysqlResultSet { + result := &MysqlResultSet{} + for index := range row { + column := &MysqlColumn{} + column.SetName(fmt.Sprintf("column_%d", index)) + column.SetColumnType(defines.MYSQL_TYPE_VAR_STRING) + result.AddColumn(column) + } + values := make([]interface{}, len(row)) + for index := range row { + values[index] = row[index] + } + result.AddRow(values) + return result + } + for _, tc := range []struct { + name string + index int + value string + want string + }{ + {name: "function identity", index: 0, value: "not-an-id", want: "invalid function identity"}, + {name: "zero revision", index: 1, value: "0", want: "invalid revision"}, + {name: "zero namespace", index: 2, value: "0", want: "invalid namespace version"}, + {name: "definition schema", index: 9, value: "future", want: "invalid definition schema"}, + {name: "unsupported ABI", index: 10, value: "future-abi", want: "unsupported execution contract"}, + {name: "body encoding", index: 7, value: "{", want: "body is invalid"}, + {name: "artifact digest binding", index: 12, value: strings.Repeat("a", 64), want: "metadata does not match"}, + {name: "argument JSON", index: 4, value: "{", want: "arguments are invalid"}, + {name: "argument descriptor", index: 5, value: "stale-descriptor", want: "argument descriptor mismatch"}, + {name: "volatility", index: 16, value: "IMMUTABLE", want: "unsupported execution contract"}, + {name: "security mode", index: 19, value: "DEFINER", want: "unsupported execution contract"}, + } { + t.Run(tc.name, func(t *testing.T) { + row := append([]string(nil), baseRow...) + row[tc.index] = tc.value + background := &backgroundExecTest{} + background.init() + background.sql2result[query] = newResult(row) + err := validateRestoredFunctionRevisionCatalog(context.Background(), background, context.Background()) + require.ErrorContains(t, err, tc.want) + }) + } +} + func TestValidateRestoredSharedRevisionCatalogAcceptsSQLAndRejectsTampering(t *testing.T) { args := `[ {"name":"value","type":"bigint"} ]` argTypes, err := userDefinedFunctionArgumentTypesFromJSON(args) diff --git a/pkg/frontend/routine_plan_validation_test.go b/pkg/frontend/routine_plan_validation_test.go index 22369c04d2597..41d26bbfa2234 100644 --- a/pkg/frontend/routine_plan_validation_test.go +++ b/pkg/frontend/routine_plan_validation_test.go @@ -17,6 +17,7 @@ package frontend import ( "context" "encoding/json" + "errors" "strings" "testing" @@ -28,6 +29,68 @@ import ( "github.com/stretchr/testify/require" ) +type routinePlanValidationExec struct { + BackgroundExec + resultSets []interface{} + catalogResultSets []interface{} + namespaceResultSets []interface{} + failOn string + statements []string +} + +func (e *routinePlanValidationExec) Close() {} + +func (e *routinePlanValidationExec) Exec(_ context.Context, statement string) error { + e.statements = append(e.statements, statement) + if e.failOn != "" && strings.Contains(statement, e.failOn) { + return errors.New("injected routine catalog read failure") + } + if strings.Contains(statement, "select f.function_id") { + e.resultSets = e.catalogResultSets + } else if strings.Contains(statement, "select selected.function_id") { + e.resultSets = e.namespaceResultSets + } + return nil +} + +func (e *routinePlanValidationExec) GetExecResultSet() []interface{} { + return e.resultSets +} + +func (e *routinePlanValidationExec) ClearExecResultSet() { + e.resultSets = nil +} + +type routinePlanValidationSession struct { + FeSession + exec BackgroundExec +} + +func (s *routinePlanValidationSession) GetAccountId() uint32 { return 9 } + +func (s *routinePlanValidationSession) GetTxnCompileCtx() *TxnCompilerContext { return nil } + +func (s *routinePlanValidationSession) GetBackgroundExec(context.Context, ...*BackgroundExecOption) BackgroundExec { + return s.exec +} + +func routinePlanCatalogResultSet(values []interface{}) *MysqlResultSet { + result := &MysqlResultSet{} + for range values { + result.AddColumn(&MysqlColumn{}) + } + result.AddRow(values) + return result +} + +func emptyRoutineNamespaceResultSet() *MysqlResultSet { + result := &MysqlResultSet{} + for range 16 { + result.AddColumn(&MysqlColumn{}) + } + return result +} + func testRoutinePlanDependency() *planpb.RoutinePlanDependency { return &planpb.RoutinePlanDependency{ FunctionRef: &planpb.FunctionRef{ @@ -246,6 +309,89 @@ func TestCachedRoutinePlanWithDependencyRequiresCatalogSession(t *testing.T) { require.False(t, cachedRoutinePlanDependenciesCurrent(nil, withRoutine)) } +func TestValidateRoutinePlanDependenciesUsesCatalogTransactionAndFailsClosed(t *testing.T) { + ctx := context.Background() + plainPlan := &planpb.Plan{Plan: &planpb.Plan_Query{Query: &planpb.Query{}}} + changed, err := validateRoutinePlanDependencies(ctx, nil, plainPlan) + require.NoError(t, err) + require.False(t, changed) + + dependency := testRoutinePlanDependency() + plan := &planpb.Plan{Plan: &planpb.Plan_Query{Query: &planpb.Query{ + RoutineDependencies: []*planpb.RoutinePlanDependency{dependency}, + }}} + _, err = validateRoutinePlanDependencies(ctx, nil, plan) + require.ErrorContains(t, err, "has no session") + + incomplete := testRoutinePlanDependency() + incomplete.NamespaceFingerprint = "" + incompletePlan := &planpb.Plan{Plan: &planpb.Plan_Query{Query: &planpb.Query{ + RoutineDependencies: []*planpb.RoutinePlanDependency{incomplete}, + }}} + changed, err = validateRoutinePlanDependencies(ctx, &routinePlanValidationSession{}, incompletePlan) + require.NoError(t, err) + require.True(t, changed, "an incomplete namespace fence must invalidate without a catalog read") + + exec := &routinePlanValidationExec{} + session := &routinePlanValidationSession{exec: exec} + changed, err = validateRoutinePlanDependencies(ctx, session, plan) + require.NoError(t, err) + require.True(t, changed, "a missing active catalog revision invalidates the prepared plan") + require.Len(t, exec.statements, 3) + require.Equal(t, "begin;", exec.statements[0]) + require.Contains(t, exec.statements[1], "where f.function_id in (41)") + require.Equal(t, "commit;", exec.statements[2]) + + // A present but damaged immutable revision is fully decoded and invalidates + // the cached plan; namespace state is still read in the same transaction. + row := []interface{}{ + uint64(41), uint64(7), uint64(12), uint64(8), uint64(7), + "python", "VOLATILE", strings.Repeat("a", 64), strings.Repeat("b", 64), + strings.Repeat("c", 64), "[]", "{}", int64(udf.PythonSignatureKeySchemaVersion), + strings.Repeat("d", 64), "damaged body", "[]", "bigint", + int64(udf.PythonDefinitionSchemaVersion), udf.PythonABIContract, + udf.PythonAdapterVersion, udf.PythonSDKVersion, udf.NullCallHandler, + "INVOKER", "INVOKER", + } + fullExec := &routinePlanValidationExec{ + catalogResultSets: []interface{}{routinePlanCatalogResultSet(row)}, + namespaceResultSets: []interface{}{emptyRoutineNamespaceResultSet()}, + } + changed, err = validateRoutinePlanDependencies(ctx, + &routinePlanValidationSession{exec: fullExec}, plan) + require.NoError(t, err) + require.True(t, changed) + require.Len(t, fullExec.statements, 4) + require.Contains(t, fullExec.statements[2], "select selected.function_id") + require.Equal(t, "commit;", fullExec.statements[3]) + + for _, tc := range []struct { + name string + catalogResultSets []interface{} + failOn string + want string + rollback bool + }{ + {name: "transaction begin error", failOn: "begin;", want: "could not start"}, + {name: "catalog query error", failOn: "mo_user_defined_function", want: "validation failed", rollback: true}, + {name: "malformed result set", catalogResultSets: []interface{}{struct{}{}}, want: "not the type of result set", rollback: true}, + } { + t.Run(tc.name, func(t *testing.T) { + failingExec := &routinePlanValidationExec{catalogResultSets: tc.catalogResultSets, failOn: tc.failOn} + changed, err := validateRoutinePlanDependencies(ctx, + &routinePlanValidationSession{exec: failingExec}, plan) + require.False(t, changed) + require.ErrorContains(t, err, tc.want) + lastStatement := failingExec.statements[len(failingExec.statements)-1] + if tc.rollback { + require.Equal(t, "rollback;", lastStatement) + } else { + require.Equal(t, "begin;", lastStatement) + } + }) + } +} + func TestExactlyOneCatalogResultSetRequiresOneCompleteResultSet(t *testing.T) { ctx := context.Background() _, err := exactlyOneCatalogResultSet(ctx, nil, "routine dependency catalog") diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index a7a09181ed299..d905cb55113ac 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -17,6 +17,8 @@ package colexec import ( "context" "encoding/json" + "errors" + "strconv" "testing" "time" @@ -36,13 +38,14 @@ import ( type externalRoutineTestExecutor struct { vector *vector.Vector evalSeen *int + err error } func (e *externalRoutineTestExecutor) Eval(_ *process.Process, _ []*batch.Batch, _ []bool) (*vector.Vector, error) { if e.evalSeen != nil { *e.evalSeen++ } - return e.vector, nil + return e.vector, e.err } func (e *externalRoutineTestExecutor) EvalWithoutResultReusing(proc *process.Process, batches []*batch.Batch, selectList []bool) (*vector.Vector, error) { @@ -61,12 +64,20 @@ type externalRoutineCaptureRuntime struct { type externalRoutineEmptySuccessRuntime struct{} +type externalRoutineErrorRuntime struct{ err error } + func (r *externalRoutineEmptySuccessRuntime) Language() string { return udf.LanguagePython } func (r *externalRoutineEmptySuccessRuntime) Execute(_ context.Context, _ *udf.Invocation, _ vector.FunctionResultWrapper, _ *mpool.MPool) error { return nil } +func (r *externalRoutineErrorRuntime) Language() string { return udf.LanguagePython } + +func (r *externalRoutineErrorRuntime) Execute(_ context.Context, _ *udf.Invocation, _ vector.FunctionResultWrapper, _ *mpool.MPool) error { + return r.err +} + func (r *externalRoutineCaptureRuntime) Language() string { return udf.LanguagePython } func (r *externalRoutineCaptureRuntime) Execute(_ context.Context, invocation *udf.Invocation, result vector.FunctionResultWrapper, mp *mpool.MPool) error { @@ -254,6 +265,39 @@ func TestExternalRoutineEvalRequiresRowDomainForZeroArgumentVector(t *testing.T) require.ErrorContains(t, err, "input batch 0 is nil") } +func TestExternalRoutineRowCountValidatesAllJoinDomains(t *testing.T) { + first := batch.NewWithSize(0) + first.SetRowCount(3) + second := batch.NewWithSize(0) + second.SetRowCount(3) + short := batch.NewWithSize(0) + short.SetRowCount(2) + for _, tc := range []struct { + name string + mode string + batches []*batch.Batch + want int + err string + }{ + {name: "aligned join row domains", mode: "SCALAR", batches: []*batch.Batch{first, second}, want: 3}, + {name: "scalar without explicit batch has one row", mode: "SCALAR", want: 1}, + {name: "empty vector batch carries zero rows", mode: "VECTOR", batches: []*batch.Batch{{}}, err: ""}, + {name: "nil later relation", mode: "SCALAR", batches: []*batch.Batch{first, nil}, err: "input batch 1 is nil"}, + {name: "unequal join cardinality", mode: "SCALAR", batches: []*batch.Batch{first, short}, err: "has 2 rows, expected 3"}, + } { + t.Run(tc.name, func(t *testing.T) { + rows, err := externalRoutineRowCount(tc.mode, tc.batches) + if tc.err != "" { + require.Zero(t, rows) + require.ErrorContains(t, err, tc.err) + return + } + require.NoError(t, err) + require.Equal(t, tc.want, rows) + }) + } +} + func TestExternalRoutineEvalAcceptsAlignedJoinBatches(t *testing.T) { first := batch.NewWithSize(0) first.SetRowCount(1) @@ -405,6 +449,100 @@ func TestBuildRoutineContextRejectsSubMinuteFixedTimezone(t *testing.T) { require.ErrorContains(t, err, "whole number of minutes") } +func TestBuildRoutineContextRejectsMissingStatementInputs(t *testing.T) { + if _, err := buildRoutineContext(nil); err == nil { + t.Fatal("nil process must not produce an invocation context") + } + if _, err := buildRoutineContext(&process.Process{}); err == nil { + t.Fatal("process without Base must not produce an invocation context") + } + proc := testutil.NewProcess(t) + defer proc.Free() + proc.Base.StmtProfile = &process.StmtProfile{} + proc.GetSessionInfo().TimeZone = time.UTC + proc.Base.UnixTime = 0 + _, err := buildRoutineContext(proc) + require.ErrorContains(t, err, "statement timestamp is unavailable") + + proc.Base.UnixTime = time.Now().UnixNano() + proc.GetSessionInfo().TimeZone = nil + _, err = buildRoutineContext(proc) + require.ErrorContains(t, err, "session timezone is unavailable") +} + +func TestResolveSystemTimezoneUsesExplicitStableZone(t *testing.T) { + t.Setenv("TZ", "posix/UTC") + name, location, err := resolveSystemTimezone() + require.NoError(t, err) + require.Equal(t, "UTC", name) + require.Equal(t, "UTC", location.String()) +} + +func TestBuildRoutineContextUsesStableStatementAndSessionSnapshot(t *testing.T) { + for _, tc := range []struct { + name string + sessionMode string + resolve func() (interface{}, error) + wantMode string + }{ + { + name: "resolved SQL mode overrides session fallback", + sessionMode: "ANSI", + resolve: func() (interface{}, error) { return "strict_trans_tables, ansi,STRICT_TRANS_TABLES", nil }, + wantMode: `["ANSI","STRICT_TRANS_TABLES"]`, + }, + { + name: "resolver error keeps session SQL mode", + sessionMode: "ansi, strict_trans_tables", + resolve: func() (interface{}, error) { return nil, errors.New("variable unavailable") }, + wantMode: `["ANSI","STRICT_TRANS_TABLES"]`, + }, + { + name: "non-string resolution keeps session SQL mode", + sessionMode: "ANSI", + resolve: func() (interface{}, error) { return int64(1), nil }, + wantMode: `["ANSI"]`, + }, + { + name: "empty sentinel becomes empty mode list", + sessionMode: process.EmptySqlModeSentinel, + wantMode: `[]`, + }, + } { + t.Run(tc.name, func(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + proc.SetQueryId("") + proc.GetSessionInfo().TimeZone = time.UTC + proc.GetSessionInfo().User = "root" + proc.GetSessionInfo().Database = "" + proc.GetSessionInfo().Role = "" + proc.GetSessionInfo().SqlMode = tc.sessionMode + proc.Base.StmtProfile = &process.StmtProfile{} + proc.Base.UnixTime = time.Date(2026, 9, 23, 1, 2, 3, 4000, time.UTC).UnixNano() + if tc.resolve != nil { + proc.SetResolveVariableFunc(func(name string, system, global bool) (interface{}, error) { + require.Equal(t, "sql_mode", name) + require.True(t, system) + require.False(t, global) + return tc.resolve() + }) + } + + values, err := buildRoutineContext(proc) + require.NoError(t, err) + require.NotContains(t, values, "statement_id") + require.Equal(t, strconv.FormatInt(time.Unix(0, proc.Base.UnixTime).UTC().UnixMicro(), 10), values["statement_timestamp_utc"]) + require.Equal(t, "IANA", values["session_timezone_kind"]) + require.Equal(t, "UTC", values["session_timezone_name"]) + require.NotEmpty(t, values["session_timezone_tzdb_version"]) + require.Equal(t, tc.wantMode, values["sql_mode"]) + require.NotContains(t, values, "current_database") + require.NotContains(t, values, "current_role") + }) + } +} + func testExternalRoutineCall(t *testing.T, mode, nullPolicy string) *planpb.RoutineCall { t.Helper() descriptor, err := function.NewPythonTypeDescriptor(types.T_int64.ToType()) @@ -481,6 +619,48 @@ func TestExternalRoutineEvalRejectsSuccessfulRuntimeWithoutResultRows(t *testing require.ErrorContains(t, err, "runtime produced 0 result rows, expected 1") } +func TestExternalRoutineEvalPropagatesParameterAndRuntimeFailures(t *testing.T) { + for _, tc := range []struct { + name string + parameterFailure bool + runtimeFailure bool + want string + }{ + {name: "parameter evaluation fails", parameterFailure: true, want: "parameter expression failed"}, + {name: "runtime is disabled", want: "runtime is not enabled"}, + {name: "runtime execution fails", runtimeFailure: true, want: "handler process was cancelled"}, + } { + t.Run(tc.name, func(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + proc.SetQueryId("error-path-query") + proc.GetSessionInfo().TimeZone = time.UTC + proc.GetSessionInfo().User = "root" + proc.Base.StmtProfile = &process.StmtProfile{} + proc.GetStmtProfile().SetQueryStart(time.Date(2026, 9, 23, 0, 0, 0, 0, time.UTC)) + input := vector.NewVec(types.T_int64.ToType()) + defer input.Free(proc.Mp()) + require.NoError(t, vector.AppendFixed(input, int64(10), false, proc.Mp())) + parameter := &externalRoutineTestExecutor{vector: input} + if tc.parameterFailure { + parameter.err = errors.New(tc.want) + } else if tc.runtimeFailure { + proc.Base.UdfService = &externalRoutineErrorRuntime{err: errors.New(tc.want)} + } + evaluator, err := newExternalRoutineEval( + proc, testExternalRoutineCall(t, python.ModeScalar, udf.NullCallHandler), + []ExpressionExecutor{parameter}, nil, + ) + require.NoError(t, err) + defer evaluator.Free() + bat := batch.NewWithSize(0) + bat.SetRowCount(1) + _, err = evaluator.Eval(proc, []*batch.Batch{bat}, []bool{true}) + require.ErrorContains(t, err, tc.want) + }) + } +} + func TestExternalRoutineTransfersResultOwnership(t *testing.T) { for _, mode := range []string{"SCALAR", "VECTOR"} { t.Run(mode, func(t *testing.T) { @@ -536,6 +716,88 @@ func TestExternalRoutineRejectsDamagedDefinitionBeforeArguments(t *testing.T) { } } +func TestValidateRoutineCallRejectsIncompleteTypedContracts(t *testing.T) { + for _, tc := range []struct { + name string + mutate func(*planpb.RoutineCall) + want string + }{ + {name: "missing FunctionRef", mutate: func(call *planpb.RoutineCall) { call.FunctionRef = nil }, want: "no exact FunctionRef"}, + {name: "zero function identity", mutate: func(call *planpb.RoutineCall) { call.FunctionRef.FunctionId = 0 }, want: "no exact FunctionRef"}, + {name: "missing return descriptor", mutate: func(call *planpb.RoutineCall) { call.ReturnType.Id = int32(types.T_any) }, want: "no return descriptor"}, + {name: "unsupported contract version", mutate: func(call *planpb.RoutineCall) { call.ContractVersion++ }, want: "unsupported typed routine call contract"}, + {name: "non-volatile function", mutate: func(call *planpb.RoutineCall) { call.Volatility = "IMMUTABLE" }, want: "must be VOLATILE"}, + {name: "function cannot error", mutate: func(call *planpb.RoutineCall) { call.MayError = false }, want: "semantic contract is not supported"}, + {name: "unsupported security contract", mutate: func(call *planpb.RoutineCall) { call.SecurityMode = "DEFINER" }, want: "semantic contract is not supported"}, + {name: "leakproof function", mutate: func(call *planpb.RoutineCall) { call.Leakproof = true }, want: "semantic contract is not supported"}, + {name: "invalid callsite newline", mutate: func(call *planpb.RoutineCall) { call.CallsiteId = "python/test\nother" }, want: "valid callsite id"}, + {name: "execution context in plan", mutate: func(call *planpb.RoutineCall) { call.Context = map[string]string{"statement_id": "stale"} }, want: "contains execution context"}, + {name: "missing Python implementation", mutate: func(call *planpb.RoutineCall) { call.Implementation = nil }, want: "no Python implementation"}, + {name: "source in plan", mutate: func(call *planpb.RoutineCall) { call.GetPython().Source = "def add(ctx, value): return value" }, want: "plan contains source"}, + {name: "unsupported SDK contract", mutate: func(call *planpb.RoutineCall) { call.GetPython().SdkVersion = "future" }, want: "implementation contract is not supported"}, + {name: "unsupported mode", mutate: func(call *planpb.RoutineCall) { call.GetPython().Mode = "BATCH" }, want: "unsupported typed call mode"}, + {name: "unsupported NULL policy", mutate: func(call *planpb.RoutineCall) { call.GetPython().NullPolicy = "DEFAULT" }, want: "unsupported typed NULL policy"}, + {name: "NULL policy mismatch", mutate: func(call *planpb.RoutineCall) { call.NullPolicy = udf.NullReturnNull }, want: "NULL policy does not match"}, + {name: "malformed artifact digest", mutate: func(call *planpb.RoutineCall) { call.GetPython().ArtifactDigest = "not-a-digest" }, want: "invalid artifact/environment digest"}, + {name: "malformed definition fingerprint", mutate: func(call *planpb.RoutineCall) { call.GetPython().DefinitionFingerprint = "not-a-digest" }, want: "invalid definition fingerprint"}, + {name: "nil argument descriptor", mutate: func(call *planpb.RoutineCall) { call.ArgumentTypes[0] = nil }, want: "argument 0 is nil"}, + {name: "unsupported argument type", mutate: func(call *planpb.RoutineCall) { call.ArgumentTypes[0].Id = int32(types.T_any) }, want: "argument 0 is unsupported"}, + } { + t.Run(tc.name, func(t *testing.T) { + call := testExternalRoutineCall(t, python.ModeScalar, udf.NullCallHandler) + tc.mutate(call) + require.ErrorContains(t, validateRoutineCall(call), tc.want) + }) + } +} + +func TestValidateExternalRoutineInputsChecksRowAndTypeContracts(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + int64Rows := vector.NewVec(types.T_int64.ToType()) + defer int64Rows.Free(proc.Mp()) + require.NoError(t, vector.AppendFixed(int64Rows, int64(1), false, proc.Mp())) + require.NoError(t, vector.AppendFixed(int64Rows, int64(2), false, proc.Mp())) + shortRows := vector.NewVec(types.T_int64.ToType()) + defer shortRows.Free(proc.Mp()) + require.NoError(t, vector.AppendFixed(shortRows, int64(1), false, proc.Mp())) + int32Rows := vector.NewVec(types.T_int32.ToType()) + defer int32Rows.Free(proc.Mp()) + require.NoError(t, vector.AppendFixed(int32Rows, int32(1), false, proc.Mp())) + require.NoError(t, vector.AppendFixed(int32Rows, int32(2), false, proc.Mp())) + emptyRows := vector.NewVec(types.T_int64.ToType()) + defer emptyRows.Free(proc.Mp()) + + for _, tc := range []struct { + name string + inputs []*vector.Vector + rows int + mutate func(*planpb.RoutineCall) + wantErr string + }{ + {name: "valid aligned input", inputs: []*vector.Vector{int64Rows}, rows: 2}, + {name: "argument count mismatch", inputs: nil, rows: 2, wantErr: "evaluated input count 0"}, + {name: "missing input vector", inputs: []*vector.Vector{nil}, rows: 1, wantErr: "has no type"}, + {name: "empty input vector", inputs: []*vector.Vector{emptyRows}, rows: 1, wantErr: "has 0 rows"}, + {name: "short non-constant input", inputs: []*vector.Vector{shortRows}, rows: 2, wantErr: "expected at least 2"}, + {name: "physical SQL type mismatch", inputs: []*vector.Vector{int32Rows}, rows: 2, wantErr: "does not match the frozen descriptor"}, + {name: "unsupported frozen descriptor", inputs: []*vector.Vector{int64Rows}, rows: 2, mutate: func(call *planpb.RoutineCall) { call.ArgumentTypes[0].Id = int32(types.T_enum) }, wantErr: "invalid argument descriptor 0"}, + } { + t.Run(tc.name, func(t *testing.T) { + call := testExternalRoutineCall(t, python.ModeScalar, udf.NullCallHandler) + if tc.mutate != nil { + tc.mutate(call) + } + err := validateExternalRoutineInputs(tc.inputs, call, tc.rows) + if tc.wantErr == "" { + require.NoError(t, err) + return + } + require.ErrorContains(t, err, tc.wantErr) + }) + } +} + func TestExternalRoutineSkipsArgumentsForEmptySelection(t *testing.T) { for _, mode := range []string{"SCALAR", "VECTOR"} { t.Run(mode, func(t *testing.T) { diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index f0f72f768ab7e..515206c9564fe 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -906,7 +906,7 @@ func TestBuildInputRecordCoversEverySupportedType(t *testing.T) { return vector.AppendFixed(v, types.Datetime(0), true, mp) }}, {"timestamp", types.New(types.T_timestamp, 0, 6), func(v *vector.Vector) error { - if err := vector.AppendFixed(v, types.Timestamp(types.GetUnixEpochSecs()+1), false, mp); err != nil { + if err := vector.AppendFixed(v, types.Timestamp(types.TimestampMinValue), false, mp); err != nil { return err } return vector.AppendFixed(v, types.Timestamp(0), true, mp) @@ -988,6 +988,24 @@ func TestBuildInputRecordCoversEverySupportedType(t *testing.T) { require.Equal(t, int64(2), record.NumRows()) require.False(t, record.Column(0).IsNull(0)) require.True(t, record.Column(0).IsNull(1)) + + // Exercise the reverse boundary with the same SQL values. Re-encoding + // the returned MO vector must reproduce the Arrow values and validity + // bitmap for every supported SQL descriptor. + returned := vector.NewFunctionResultWrapper(tc.typ, mp) + defer returned.Free() + require.NoError(t, returned.PreExtendAndReset(2)) + require.NoError(t, AppendArrowResult(descriptor, record.Column(0), returned, mp)) + require.Equal(t, 2, returned.GetResultVector().Length()) + require.False(t, returned.GetResultVector().IsNull(0)) + require.True(t, returned.GetResultVector().IsNull(1)) + + returnedRecord, _, err := BuildInputRecord( + []*vector.Vector{returned.GetResultVector()}, []types.Type{tc.typ}, 2, + ) + require.NoError(t, err) + defer returnedRecord.Release() + require.True(t, array.Equal(record.Column(0), returnedRecord.Column(0)), tc.name) }) } } diff --git a/pkg/udf/python/config_test.go b/pkg/udf/python/config_test.go index 4873cc8fb5198..dad3c7473e9b4 100644 --- a/pkg/udf/python/config_test.go +++ b/pkg/udf/python/config_test.go @@ -68,3 +68,43 @@ func TestClientConfigMatchesWorkerHandlerTimeoutContract(t *testing.T) { config.RequestTimeout = maxHandlerTimeout + time.Nanosecond require.ErrorContains(t, config.Validate(), "request timeout") } + +func TestClientConfigRejectsEveryOutOfRangeBudget(t *testing.T) { + for _, tc := range []struct { + name string + mutate func(*ClientConfig) + want string + }{ + {name: "missing worker address", mutate: func(c *ClientConfig) { c.ServerAddress = "" }, want: "missing python udf address"}, + {name: "negative input bytes", mutate: func(c *ClientConfig) { c.MaxBatchBytes = -1 }, want: "max batch bytes"}, + {name: "input bytes exceed wire bound", mutate: func(c *ClientConfig) { c.MaxBatchBytes = 1<<30 + 1 }, want: "max batch bytes"}, + {name: "negative input rows", mutate: func(c *ClientConfig) { c.MaxBatchRows = -1 }, want: "max batch rows"}, + {name: "input rows exceed bound", mutate: func(c *ClientConfig) { c.MaxBatchRows = 1<<30 + 1 }, want: "max batch rows"}, + {name: "invocation rows exceed bound", mutate: func(c *ClientConfig) { c.MaxInvocationRows = 1<<32 + 1 }, want: "max invocation rows"}, + {name: "result bytes exceed bound", mutate: func(c *ClientConfig) { c.MaxInvocationResultBytes = 1<<40 + 1 }, want: "max invocation result bytes"}, + {name: "active slots exceed bound", mutate: func(c *ClientConfig) { c.MaxActiveInvocations = 1<<20 + 1 }, want: "max active invocations"}, + {name: "negative request timeout", mutate: func(c *ClientConfig) { c.RequestTimeout = -time.Nanosecond }, want: "request timeout"}, + {name: "terminal entries exceed bound", mutate: func(c *ClientConfig) { c.MaxTerminalEntries = 1<<30 + 1 }, want: "max terminal entries"}, + {name: "negative terminal bytes", mutate: func(c *ClientConfig) { c.MaxTerminalBytes = -1 }, want: "max terminal bytes"}, + {name: "terminal bytes exceed bound", mutate: func(c *ClientConfig) { c.MaxTerminalBytes = 1<<40 + 1 }, want: "max terminal bytes"}, + {name: "negative tombstone lifetime", mutate: func(c *ClientConfig) { c.TerminalRecordTTL = -time.Nanosecond }, want: "terminal record ttl"}, + } { + t.Run(tc.name, func(t *testing.T) { + config := &ClientConfig{ + Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:50051", + } + tc.mutate(config) + require.ErrorContains(t, config.Validate(), tc.want) + }) + } +} + +func TestWorkerConfigRequiresAddressAndPath(t *testing.T) { + config := &Config{Path: "/opt/matrixone/pkg/udf/python/worker/worker.py"} + require.ErrorContains(t, config.Validate(), "missing python udf address") + config.Address = "127.0.0.1:50051" + config.Path = "" + require.ErrorContains(t, config.Validate(), "missing python udf path") + config.Path = "/opt/matrixone/pkg/udf/python/worker/worker.py" + require.NoError(t, config.Validate()) +} diff --git a/pkg/udf/python/gateway_test.go b/pkg/udf/python/gateway_test.go index a98d16686c512..cd2961e876bce 100644 --- a/pkg/udf/python/gateway_test.go +++ b/pkg/udf/python/gateway_test.go @@ -16,6 +16,7 @@ package python import ( "context" + "encoding/json" "errors" "io" "strings" @@ -23,7 +24,10 @@ import ( "testing" "time" + "github.com/apache/arrow-go/v18/arrow" + "github.com/apache/arrow-go/v18/arrow/array" "github.com/apache/arrow-go/v18/arrow/flight/gen/flight" + "github.com/apache/arrow-go/v18/arrow/memory" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -39,6 +43,29 @@ type gatewayResultStream struct { index int } +type scriptedGatewayResultStream struct { + grpc.ClientStream + results []*flight.FlightData + errors []error + index int +} + +func (s *scriptedGatewayResultStream) Recv() (*flight.FlightData, error) { + index := s.index + s.index++ + if index < len(s.results) { + return s.results[index], nil + } + if index < len(s.errors) { + return nil, s.errors[index] + } + return nil, io.EOF +} + +func (s *scriptedGatewayResultStream) Send(*flight.FlightData) error { + return nil +} + type gatedGatewayResultStream struct { grpc.ClientStream results []*flight.FlightData @@ -72,6 +99,74 @@ type finishAckFlightClient struct { actions []*flight.Action } +type resultAckFlightClient struct { + flight.FlightServiceClient + response []byte + err error +} + +func (c *resultAckFlightClient) DoAction(context.Context, *flight.Action, ...grpc.CallOption) (flight.FlightService_DoActionClient, error) { + return &finishAckActionStream{result: &flight.Result{Body: c.response}, err: c.err}, nil +} + +type capabilityActionClient struct { + flight.FlightServiceClient + response []byte + err error +} + +func (c *capabilityActionClient) DoAction( + _ context.Context, + action *flight.Action, + _ ...grpc.CallOption, +) (flight.FlightService_DoActionClient, error) { + if c.err != nil { + return nil, c.err + } + if action.Type != "GetPythonCapabilities" { + return nil, errors.New("unexpected capability action") + } + return &finishAckActionStream{result: &flight.Result{Body: c.response}}, nil +} + +type scriptedCapabilityActionStream struct { + grpc.ClientStream + results []*flight.Result + errors []error + index int +} + +func (s *scriptedCapabilityActionStream) Recv() (*flight.Result, error) { + index := s.index + s.index++ + if index < len(s.results) { + return s.results[index], nil + } + if index < len(s.errors) { + return nil, s.errors[index] + } + return nil, io.EOF +} + +type scriptedCapabilityFlightClient struct { + flight.FlightServiceClient + actionErr error + stream *scriptedCapabilityActionStream + actions []*flight.Action +} + +func (c *scriptedCapabilityFlightClient) DoAction( + _ context.Context, + action *flight.Action, + _ ...grpc.CallOption, +) (flight.FlightService_DoActionClient, error) { + c.actions = append(c.actions, action) + if c.actionErr != nil { + return nil, c.actionErr + } + return c.stream, nil +} + type recordingArtifactResolver struct { source string calls int @@ -305,6 +400,367 @@ func validInvocation() *udf.Invocation { } } +func TestValidateInvocationHeaderRejectsUnfrozenContracts(t *testing.T) { + require.NoError(t, validateInvocationHeader(validInvocation())) + + cases := []struct { + name string + mutate func(*udf.Invocation) + }{ + {"nil invocation", nil}, + {"language", func(i *udf.Invocation) { i.Language = "PYTHON" }}, + {"empty handler", func(i *udf.Invocation) { i.Handler = "" }}, + {"external handler", func(i *udf.Invocation) { i.Handler = "package:handler" }}, + {"negative length", func(i *udf.Invocation) { i.Length = -1 }}, + {"argument input count", func(i *udf.Invocation) { i.Inputs = nil }}, + {"unsupported mode", func(i *udf.Invocation) { i.Mode = "BATCH" }}, + {"empty callsite", func(i *udf.Invocation) { i.CallsiteID = "" }}, + {"oversized callsite", func(i *udf.Invocation) { i.CallsiteID = strings.Repeat("x", 257) }}, + {"control character callsite", func(i *udf.Invocation) { i.CallsiteID = "bad\nsite" }}, + {"must be allowed to error", func(i *udf.Invocation) { i.MayError = false }}, + {"unsupported security mode", func(i *udf.Invocation) { i.SecurityMode = "DEFINER" }}, + {"leakproof", func(i *udf.Invocation) { i.Leakproof = true }}, + {"missing statement context", func(i *udf.Invocation) { i.StatementContext = nil }}, + {"invalid statement context", func(i *udf.Invocation) { i.StatementContext.TimezoneKind = "UNKNOWN" }}, + {"missing security frame", func(i *udf.Invocation) { i.SecurityFrame = nil }}, + {"changed security principal", func(i *udf.Invocation) { i.SecurityFrame.EffectiveUserID = 8 }}, + {"security mode mismatch", func(i *udf.Invocation) { i.SecurityFrame.Mode = "DEFINER" }}, + {"unsupported null policy", func(i *udf.Invocation) { i.NullPolicy = "STRICT" }}, + {"unsupported ABI", func(i *udf.Invocation) { i.ABIContract = "PYTHON_NATIVE" }}, + {"unsupported adapter", func(i *udf.Invocation) { i.AdapterVersion = "future" }}, + {"unsupported SDK", func(i *udf.Invocation) { i.SDKVersion = "future" }}, + {"unsupported schema", func(i *udf.Invocation) { i.DefinitionSchemaVersion++ }}, + {"malformed artifact digest", func(i *udf.Invocation) { i.ArtifactDigest = "bad" }}, + {"environment digest mismatch", func(i *udf.Invocation) { i.EnvironmentDigest = strings.Repeat("d", 64) }}, + {"malformed definition fingerprint", func(i *udf.Invocation) { i.DefinitionFingerprint = "bad" }}, + {"unsupported argument type", func(i *udf.Invocation) { i.Args[0] = types.T_any.ToType() }}, + {"unsupported return type", func(i *udf.Invocation) { i.ReturnType = types.T_any.ToType() }}, + {"invalid function identity", func(i *udf.Invocation) { i.FunctionRef.FunctionID = 0 }}, + {"fencing account mismatch", func(i *udf.Invocation) { i.Tuple.AccountID++ }}, + {"invalid fencing tuple", func(i *udf.Invocation) { i.Tuple.StatementID = "" }}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + invocation := validInvocation() + if tc.mutate == nil { + require.Error(t, validateInvocationHeader(nil)) + return + } + tc.mutate(invocation) + require.Error(t, validateInvocationHeader(invocation)) + }) + } +} + +func TestGatewayStatusSnapshotReportsAdmissionAndWorkerContract(t *testing.T) { + response, err := json.Marshal(currentTestCapabilities()) + require.NoError(t, err) + for _, tc := range []struct { + name string + language string + config ClientConfig + client *capabilityActionClient + closeGateway bool + directConfig bool + wantReady bool + wantClass string + wantReason string + wantProtocol int32 + wantLease uint64 + }{ + { + name: "unsupported language", + language: "sql", + wantClass: udf.RuntimeStatusInvalid, + wantReason: udf.RuntimeStatusReasonInvalidLanguage, + }, + { + name: "disabled", + language: udf.LanguagePython, + wantClass: udf.RuntimeStatusDisabled, + wantReason: udf.RuntimeStatusReasonRuntimeDisabled, + }, + { + name: "unisolated execution not admitted", + language: udf.LanguagePython, + config: ClientConfig{ + Enabled: true, + }, + directConfig: true, + wantClass: udf.RuntimeStatusNotAllowed, + wantReason: udf.RuntimeStatusReasonUnisolatedNotAllowed, + }, + { + name: "worker transport failure", + language: udf.LanguagePython, + config: ClientConfig{ + Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:1", RequestTimeout: time.Second, + }, + client: &capabilityActionClient{err: errors.New("connection refused")}, + wantClass: udf.RuntimeStatusUnavailable, + wantReason: udf.RuntimeStatusReasonWorkerUnavailable, + }, + { + name: "capability contract mismatch", + language: udf.LanguagePython, + config: ClientConfig{ + Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:1", RequestTimeout: time.Second, + }, + client: func() *capabilityActionClient { + mismatch := currentTestCapabilities() + mismatch.ProtocolVersion++ + body, marshalErr := json.Marshal(mismatch) + require.NoError(t, marshalErr) + return &capabilityActionClient{response: body} + }(), + wantClass: udf.RuntimeStatusContractMismatch, + wantReason: udf.RuntimeStatusReasonCapabilityMismatch, + }, + { + name: "ready worker", + language: udf.LanguagePython, + config: ClientConfig{ + Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:1", RequestTimeout: time.Second, + }, + client: &capabilityActionClient{response: response}, + wantReady: true, + wantClass: "", + wantReason: udf.RuntimeStatusReasonReady, + wantProtocol: int32(protocol.Version), + wantLease: 42, + }, + { + name: "closed gateway", + language: udf.LanguagePython, + config: ClientConfig{Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:1"}, + closeGateway: true, + wantClass: udf.RuntimeStatusClosed, + wantReason: udf.RuntimeStatusReasonRuntimeClosed, + }, + } { + t.Run(tc.name, func(t *testing.T) { + cfg := tc.config + if cfg.ServerAddress == "" && cfg.Enabled { + cfg.ServerAddress = "127.0.0.1:1" + } + if cfg.Enabled && cfg.AllowUnisolated && cfg.RequestTimeout == 0 { + cfg.RequestTimeout = time.Second + } + var gateway *Gateway + var err error + if tc.directConfig { + // NewGateway correctly rejects this production configuration. A + // direct value exercises the status fail-closed branch itself. + gateway = &Gateway{cfg: cfg} + } else { + gateway, err = NewGateway(cfg) + require.NoError(t, err) + } + if tc.client != nil { + gateway.flight = tc.client + } + if tc.closeGateway { + require.NoError(t, gateway.Close()) + } else { + defer gateway.Close() + } + + snapshot := gateway.StatusSnapshot(nil, tc.language) + require.Equal(t, tc.language, snapshot.Language) + require.Equal(t, tc.wantReady, snapshot.Ready) + require.Equal(t, tc.wantClass, snapshot.ErrorClass) + require.Equal(t, tc.wantReason, snapshot.Reason) + if tc.wantReady { + require.Equal(t, tc.wantProtocol, snapshot.ProtocolVersion) + require.Equal(t, tc.wantLease, snapshot.LeaseEpoch) + require.Equal(t, []string{ModeScalar, ModeVector}, snapshot.Modes) + require.Equal(t, []string{NullCallHandler, NullReturnNull}, snapshot.NullPolicies) + require.Equal(t, udf.PythonABIContract, snapshot.ABIContract) + } + }) + } +} + +func TestReadCapabilitiesRequiresOneStrictCurrentResponse(t *testing.T) { + validBody, err := json.Marshal(currentTestCapabilities()) + require.NoError(t, err) + unknownFieldBody := append(append([]byte(nil), validBody[:len(validBody)-1]...), []byte(`,"future_contract":true}`)...) + + for _, tc := range []struct { + name string + actionErr error + stream *scriptedCapabilityActionStream + wantError string + wantResult bool + }{ + { + name: "one current response followed by EOF", + stream: &scriptedCapabilityActionStream{ + results: []*flight.Result{{Body: validBody}}, + }, + wantResult: true, + }, + { + name: "action RPC failure", + actionErr: errors.New("injected action failure"), + wantError: "capability handshake", + }, + { + name: "first response transport failure", + stream: &scriptedCapabilityActionStream{ + errors: []error{errors.New("injected response failure")}, + }, + wantError: "capability handshake response", + }, + { + name: "empty response", + stream: &scriptedCapabilityActionStream{results: []*flight.Result{nil}}, + wantError: "empty capability handshake response", + }, + { + name: "malformed JSON", + stream: &scriptedCapabilityActionStream{ + results: []*flight.Result{{Body: []byte("{")}}, + }, + wantError: "decode capability handshake", + }, + { + name: "unknown contract field", + stream: &scriptedCapabilityActionStream{ + results: []*flight.Result{{Body: unknownFieldBody}}, + }, + wantError: "decode capability handshake", + }, + { + name: "trailing JSON value", + stream: &scriptedCapabilityActionStream{ + results: []*flight.Result{{Body: append(append([]byte(nil), validBody...), []byte(" {}")...)}}, + }, + wantError: "trailing JSON", + }, + { + name: "unsupported current contract", + stream: func() *scriptedCapabilityActionStream { + mismatch := currentTestCapabilities() + mismatch.ProtocolVersion++ + body, marshalErr := json.Marshal(mismatch) + require.NoError(t, marshalErr) + return &scriptedCapabilityActionStream{results: []*flight.Result{{Body: body}}} + }(), + wantError: "contract does not match", + }, + { + name: "multiple responses", + stream: &scriptedCapabilityActionStream{ + results: []*flight.Result{{Body: validBody}, {Body: validBody}}, + }, + wantError: "multiple results", + }, + { + name: "stream failure after response", + stream: &scriptedCapabilityActionStream{ + results: []*flight.Result{{Body: validBody}}, + errors: []error{nil, errors.New("injected trailing stream failure")}, + }, + wantError: "capability handshake stream", + }, + } { + t.Run(tc.name, func(t *testing.T) { + client := &scriptedCapabilityFlightClient{actionErr: tc.actionErr, stream: tc.stream} + got, err := readCapabilities(context.Background(), client) + if tc.wantError != "" { + require.ErrorContains(t, err, tc.wantError) + require.Nil(t, got) + } else { + require.NoError(t, err) + require.Equal(t, tc.wantResult, got != nil) + require.Equal(t, protocol.Version, got.ProtocolVersion) + } + require.Len(t, client.actions, 1) + require.Equal(t, "GetPythonCapabilities", client.actions[0].Type) + var request capabilityRequest + require.NoError(t, json.Unmarshal(client.actions[0].Body, &request)) + require.Equal(t, protocol.Version, request.ProtocolVersion) + }) + } +} + +func TestValidateDefinitionRejectsMalformedCurrentContractsBeforeRPC(t *testing.T) { + valid := func() *udf.RoutineDefinition { + invocation := validInvocation() + return &udf.RoutineDefinition{ + Language: invocation.Language, + AccountID: invocation.FunctionRef.AccountID, + Handler: invocation.Handler, + Source: invocation.Source, + Args: append([]types.Type(nil), invocation.Args...), + ReturnType: invocation.ReturnType, + Mode: invocation.Mode, + NullPolicy: invocation.NullPolicy, + ABIContract: invocation.ABIContract, + AdapterVersion: invocation.AdapterVersion, + SDKVersion: invocation.SDKVersion, + DefinitionSchemaVersion: invocation.DefinitionSchemaVersion, + ArtifactDigest: invocation.ArtifactDigest, + EnvironmentDigest: invocation.EnvironmentDigest, + DefinitionFingerprint: invocation.DefinitionFingerprint, + } + } + for _, tc := range []struct { + name string + mutate func(*udf.RoutineDefinition) + }{ + {"unsupported language", func(d *udf.RoutineDefinition) { d.Language = "sql" }}, + {"empty handler", func(d *udf.RoutineDefinition) { d.Handler = " " }}, + {"external handler", func(d *udf.RoutineDefinition) { d.Handler = "module:handler" }}, + {"unsupported schema", func(d *udf.RoutineDefinition) { d.DefinitionSchemaVersion++ }}, + {"unsupported ABI", func(d *udf.RoutineDefinition) { d.ABIContract = "future" }}, + {"unsupported adapter", func(d *udf.RoutineDefinition) { d.AdapterVersion = "future" }}, + {"unsupported SDK", func(d *udf.RoutineDefinition) { d.SDKVersion = "future" }}, + {"unsupported mode", func(d *udf.RoutineDefinition) { d.Mode = "BATCH" }}, + {"unsupported NULL policy", func(d *udf.RoutineDefinition) { d.NullPolicy = "STRICT" }}, + {"invalid artifact digest", func(d *udf.RoutineDefinition) { d.ArtifactDigest = "invalid" }}, + {"invalid environment digest", func(d *udf.RoutineDefinition) { d.EnvironmentDigest = "invalid" }}, + {"environment digest mismatch", func(d *udf.RoutineDefinition) { d.EnvironmentDigest = strings.Repeat("a", 64) }}, + {"invalid fingerprint", func(d *udf.RoutineDefinition) { d.DefinitionFingerprint = "invalid" }}, + {"unsupported argument descriptor", func(d *udf.RoutineDefinition) { d.Args[0] = types.T_any.ToType() }}, + {"unsupported return descriptor", func(d *udf.RoutineDefinition) { d.ReturnType = types.T_any.ToType() }}, + {"fingerprint does not bind definition", func(d *udf.RoutineDefinition) { d.Mode = ModeVector }}, + } { + t.Run(tc.name, func(t *testing.T) { + gateway, err := NewGateway(ClientConfig{ + Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:1", RequestTimeout: time.Second, + }) + require.NoError(t, err) + defer gateway.Close() + definition := valid() + tc.mutate(definition) + err = gateway.ValidateDefinition(context.Background(), definition) + require.Error(t, err) + require.Contains(t, err.Error(), "UNSUPPORTED_ROUTINE_VERSION") + gateway.mu.Lock() + defer gateway.mu.Unlock() + require.Nil(t, gateway.conn, "invalid definitions must be rejected before opening a Flight connection") + }) + } + t.Run("nil definition", func(t *testing.T) { + gateway, err := NewGateway(ClientConfig{Enabled: true, AllowUnisolated: true, ServerAddress: "127.0.0.1:1"}) + require.NoError(t, err) + defer gateway.Close() + require.ErrorContains(t, gateway.ValidateDefinition(context.Background(), nil), "nil Python routine definition") + }) + t.Run("disabled runtime", func(t *testing.T) { + gateway, err := NewGateway(ClientConfig{}) + require.NoError(t, err) + defer gateway.Close() + require.ErrorContains(t, gateway.ValidateDefinition(context.Background(), valid()), "runtime is disabled") + }) + t.Run("unisolated opt in is required", func(t *testing.T) { + gateway := &Gateway{cfg: ClientConfig{Enabled: true, ServerAddress: "127.0.0.1:1"}} + require.ErrorContains(t, gateway.ValidateDefinition(context.Background(), valid()), "explicit unisolated opt-in") + }) +} + func TestValidateInvocationInputsChecksZeroRowVectorTypes(t *testing.T) { mp := mpool.MustNewZeroNoFixed() input := vector.NewVec(types.T_int32.ToType()) @@ -653,6 +1109,278 @@ func TestGatewayRejectsArrowBodyOnControlFrame(t *testing.T) { require.ErrorContains(t, err, "unexpected Arrow data") } +func TestReceiveResultBatchRejectsMalformedProtocolProgress(t *testing.T) { + tuple := validInvocation().Tuple + resultBatch := func(controlTuple protocol.FencingTuple) *flight.FlightData { + return &flight.FlightData{ + DataHeader: []byte("record"), + AppMetadata: func() []byte { + encoded, err := protocol.MarshalControl(protocol.Control{ + Kind: "ResultBatch", Tuple: controlTuple, Sequence: 1, + }) + require.NoError(t, err) + return encoded + }(), + } + } + inputConsumed := func(sequence uint64, releasedBytes int64, releasedBatches uint64) *flight.FlightData { + return gatewayControl(t, "InputConsumed", tuple, func(control *protocol.Control) { + control.Sequence = sequence + control.ReleasedBytes = releasedBytes + control.ReleasedBatches = releasedBatches + }) + } + for _, tc := range []struct { + name string + results []*flight.FlightData + recvErrors []error + initialSchema bool + schemaReady bool + want string + }{ + {name: "EOF before result", want: "ended before result sequence"}, + {name: "receive failure", recvErrors: []error{errors.New("injected receive failure")}, want: "receive result"}, + {name: "nil FlightData", results: []*flight.FlightData{nil}, want: "empty Flight result"}, + {name: "empty FlightData", results: []*flight.FlightData{{}}, want: "empty Flight result"}, + { + name: "control frame with Arrow body", + results: []*flight.FlightData{func() *flight.FlightData { + data := inputConsumed(1, 1, 1) + data.DataBody = []byte("unexpected") + return data + }()}, + want: "control frame contains an Arrow body", + }, + {name: "invalid control metadata", results: []*flight.FlightData{{AppMetadata: []byte("not-json")}}, want: "invalid character"}, + { + name: "changed tuple", + results: []*flight.FlightData{gatewayControl(t, "InputConsumed", protocol.FencingTuple{ + AccountID: tuple.AccountID + 1, StatementID: tuple.StatementID, GroupID: tuple.GroupID, + GroupEpoch: tuple.GroupEpoch, InvocationID: tuple.InvocationID, LeaseEpoch: tuple.LeaseEpoch, + }, func(control *protocol.Control) { + control.Sequence = 1 + control.ReleasedBytes = 1 + control.ReleasedBatches = 1 + })}, + want: "result tuple changed", + }, + {name: "result schema control before schema", results: []*flight.FlightData{gatewayControl(t, "ResultSchema", tuple)}, want: "invalid result schema metadata"}, + { + name: "input sequence mismatch", + results: []*flight.FlightData{inputConsumed(2, 1, 1)}, + want: "was consumed while waiting for result", + }, + { + name: "invalid released credits", + results: []*flight.FlightData{inputConsumed(1, 2048, 1)}, + want: "released invalid bytes/batches", + }, + {name: "worker error control", results: []*flight.FlightData{gatewayControl(t, "Error", tuple, func(control *protocol.Control) { + control.Status = "ERROR" + control.Reason = "handler failed" + })}, want: "worker error: handler failed"}, + {name: "Finish before result", results: []*flight.FlightData{gatewayControl(t, "Finish", tuple, func(control *protocol.Control) { + control.FinishID = "finish-1" + control.Status = statusOK + control.LastSequence = 1 + control.LastResultSequence = 0 + })}, want: "Finish arrived before result"}, + {name: "unknown control", results: []*flight.FlightData{{AppMetadata: []byte(`{"version":1,"kind":"Unknown","tuple":{"statement_id":"stmt","group_id":"group","group_epoch":1,"invocation_id":"invocation","lease_epoch":1}}`)}}, want: "unsupported control kind"}, + { + name: "schema frame contains a body", + results: []*flight.FlightData{{DataHeader: []byte("schema"), DataBody: []byte("body")}}, + want: "result schema contains a body", + }, + { + name: "schema metadata has wrong tuple", + results: []*flight.FlightData{func() *flight.FlightData { + data := gatewayControl(t, "ResultSchema", tuple) + data.DataHeader = []byte("schema") + otherTuple := tuple + otherTuple.AccountID++ + data.AppMetadata, _ = protocol.MarshalControl(protocol.Control{Kind: "ResultSchema", Tuple: otherTuple}) + return data + }()}, + want: "invalid result schema metadata", + }, + { + name: "record omitted schema metadata", + results: []*flight.FlightData{ + {DataHeader: []byte("schema")}, + resultBatch(tuple), + }, + want: "result schema metadata was not received", + }, + { + name: "result before input consumed", + initialSchema: true, + schemaReady: true, + results: []*flight.FlightData{resultBatch(tuple)}, + want: "arrived before InputConsumed", + }, + { + name: "duplicate input consumed", + results: []*flight.FlightData{ + inputConsumed(1, 1, 1), + inputConsumed(1, 1, 1), + }, + want: "was consumed more than once", + }, + } { + t.Run(tc.name, func(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer result.Free() + returnDescriptor, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + sequence := protocol.Sequence{} + require.NoError(t, sequence.AcceptInput(1)) + var schemaFrame *ArrowFrame + if tc.initialSchema { + schemaFrame = &ArrowFrame{Header: []byte("schema")} + } + schemaReady := tc.schemaReady + gateway := &Gateway{cfg: ClientConfig{MaxBatchBytes: 1024}} + _, err = gateway.receiveResultBatch( + context.Background(), nil, + &scriptedGatewayResultStream{results: tc.results, errors: tc.recvErrors}, + tuple, 1, 1, &schemaFrame, &schemaReady, returnDescriptor, result, mp, &sequence, + ) + require.ErrorContains(t, err, tc.want) + }) + } +} + +func TestReceiveResultBatchValidatesArrowPayloadAndResultAck(t *testing.T) { + type encodedResult struct { + frames []ArrowFrame + descriptor TypeDescriptor + } + encodeResult := func(t *testing.T, fieldName string) encodedResult { + t.Helper() + descriptor, err := NewTypeDescriptor(types.T_int64.ToType()) + require.NoError(t, err) + field, err := descriptor.Field(fieldName) + require.NoError(t, err) + builder := array.NewInt64Builder(memory.NewGoAllocator()) + builder.AppendValues([]int64{17}, nil) + values := builder.NewInt64Array() + defer values.Release() + record := array.NewRecordBatch(arrow.NewSchema([]arrow.Field{field}, nil), []arrow.Array{values}, 1) + defer record.Release() + frames, err := EncodeRecordBatch(record, DefaultMaxBatchBytes) + require.NoError(t, err) + return encodedResult{frames: frames, descriptor: descriptor} + } + + tuple := validInvocation().Tuple + encoded := encodeResult(t, "result") + wrongName := encodeResult(t, "other") + validAck, err := protocol.MarshalControl(protocol.Control{ + Kind: "Ack", Tuple: tuple, AckSequence: 1, Status: statusOK, + }) + require.NoError(t, err) + wrongAck, err := protocol.MarshalControl(protocol.Control{ + Kind: "Ack", Tuple: tuple, AckSequence: 2, Status: statusOK, + }) + require.NoError(t, err) + resultMetadata, err := protocol.MarshalControl(protocol.Control{ + Kind: "ResultBatch", Tuple: tuple, Sequence: 1, + }) + require.NoError(t, err) + schemaMetadata, err := protocol.MarshalControl(protocol.Control{ + Kind: "ResultSchema", Tuple: tuple, + }) + require.NoError(t, err) + inputConsumedMetadata, err := protocol.MarshalControl(protocol.Control{ + Kind: "InputConsumed", Tuple: tuple, Sequence: 1, ReleasedBytes: 1, ReleasedBatches: 1, + }) + require.NoError(t, err) + + for _, tc := range []struct { + name string + frames []ArrowFrame + descriptor TypeDescriptor + expectedRows int64 + maxBatchBytes int64 + maxResultBytes int64 + resultMetadata []byte + ackResponse []byte + ackError error + resultAlreadySeen bool + wantError string + }{ + {name: "valid one-row result is appended and acknowledged", frames: encoded.frames, descriptor: encoded.descriptor, expectedRows: 1, maxBatchBytes: DefaultMaxBatchBytes, resultMetadata: resultMetadata, ackResponse: validAck}, + {name: "malformed result metadata", frames: encoded.frames, descriptor: encoded.descriptor, expectedRows: 1, maxBatchBytes: DefaultMaxBatchBytes, resultMetadata: []byte("not-json"), wantError: "invalid character"}, + {name: "result sequence does not match input", frames: encoded.frames, descriptor: encoded.descriptor, expectedRows: 1, maxBatchBytes: DefaultMaxBatchBytes, resultMetadata: func() []byte { + metadata, marshalErr := protocol.MarshalControl(protocol.Control{Kind: "ResultBatch", Tuple: tuple, Sequence: 2}) + require.NoError(t, marshalErr) + return metadata + }(), wantError: "unexpected result sequence"}, + {name: "duplicate result sequence", frames: encoded.frames, descriptor: encoded.descriptor, expectedRows: 1, maxBatchBytes: DefaultMaxBatchBytes, resultMetadata: resultMetadata, resultAlreadySeen: true, wantError: "sequence violation"}, + {name: "corrupt Arrow record body", frames: func() []ArrowFrame { + frames := append([]ArrowFrame(nil), encoded.frames...) + frames[1].Body = []byte("not an Arrow body") + return frames + }(), descriptor: encoded.descriptor, expectedRows: 1, maxBatchBytes: DefaultMaxBatchBytes, resultMetadata: resultMetadata, wantError: "decode result"}, + {name: "unexpected row count", frames: encoded.frames, descriptor: encoded.descriptor, expectedRows: 2, maxBatchBytes: DefaultMaxBatchBytes, resultMetadata: resultMetadata, wantError: "result batch row count"}, + {name: "unexpected field name", frames: wrongName.frames, descriptor: wrongName.descriptor, expectedRows: 1, maxBatchBytes: DefaultMaxBatchBytes, resultMetadata: resultMetadata, wantError: "field has unexpected name"}, + {name: "descriptor mismatch", frames: encoded.frames, descriptor: func() TypeDescriptor { + descriptor, descriptorErr := NewTypeDescriptor(types.T_int32.ToType()) + require.NoError(t, descriptorErr) + return descriptor + }(), expectedRows: 1, maxBatchBytes: DefaultMaxBatchBytes, resultMetadata: resultMetadata, wantError: "Arrow type int64 does not match int32"}, + {name: "complete IPC payload exceeds limit", frames: encoded.frames, descriptor: encoded.descriptor, expectedRows: 1, maxBatchBytes: 1, resultMetadata: resultMetadata, wantError: "exceeds"}, + {name: "materialized result exceeds invocation budget", frames: encoded.frames, descriptor: encoded.descriptor, expectedRows: 1, maxBatchBytes: DefaultMaxBatchBytes, maxResultBytes: 1, resultMetadata: resultMetadata, wantError: "invocation result exceeds"}, + {name: "result ACK response lost", frames: encoded.frames, descriptor: encoded.descriptor, expectedRows: 1, maxBatchBytes: DefaultMaxBatchBytes, resultMetadata: resultMetadata, ackError: errors.New("injected ACK response loss"), wantError: "injected ACK response loss"}, + {name: "result ACK sequence mismatch", frames: encoded.frames, descriptor: encoded.descriptor, expectedRows: 1, maxBatchBytes: DefaultMaxBatchBytes, resultMetadata: resultMetadata, ackResponse: wrongAck, wantError: "ACK sequence 2, expected 1"}, + } { + t.Run(tc.name, func(t *testing.T) { + mp := mpool.MustNewZeroNoFixed() + defer mpool.DeleteMPool(mp) + result := vector.NewFunctionResultWrapper(types.T_int64.ToType(), mp) + defer result.Free() + require.NoError(t, result.PreExtendAndReset(int(tc.expectedRows))) + sequence := protocol.Sequence{} + require.NoError(t, sequence.AcceptInput(1)) + require.NoError(t, sequence.EndInput(1)) + if tc.resultAlreadySeen { + require.NoError(t, sequence.AcceptResult(1)) + } + schema := &flight.FlightData{DataHeader: tc.frames[0].Header, AppMetadata: schemaMetadata} + consumed := &flight.FlightData{AppMetadata: inputConsumedMetadata} + record := &flight.FlightData{ + DataHeader: tc.frames[1].Header, DataBody: tc.frames[1].Body, + AppMetadata: tc.resultMetadata, + } + stream := &gatewayResultStream{results: []*flight.FlightData{schema, consumed, record}} + client := &resultAckFlightClient{response: tc.ackResponse, err: tc.ackError} + gateway := &Gateway{cfg: ClientConfig{ + MaxBatchBytes: tc.maxBatchBytes, MaxInvocationResultBytes: tc.maxResultBytes, + }} + schemaFrame := (*ArrowFrame)(nil) + schemaReady := false + rows, callErr := gateway.receiveResultBatch( + context.Background(), client, stream, tuple, 1, tc.expectedRows, + &schemaFrame, &schemaReady, tc.descriptor, result, mp, &sequence, + ) + if tc.wantError != "" { + require.ErrorContains(t, callErr, tc.wantError) + return + } + require.NoError(t, callErr) + require.Equal(t, 1, rows) + require.Equal(t, []int64{17}, vector.MustFixedColNoTypeCheck[int64](result.GetResultVector())) + lastInput, lastResult, ackedResult, inputEnded := sequence.State() + require.Equal(t, uint64(1), lastInput) + require.Equal(t, uint64(1), lastResult) + require.Equal(t, uint64(1), ackedResult) + require.True(t, inputEnded) + }) + } +} + func TestFreezeResultFramesFreezesBothPartsAndChargesTotal(t *testing.T) { header := []byte("record-header") body := []byte("record-body") @@ -669,3 +1397,51 @@ func TestFreezeResultFramesFreezesBothPartsAndChargesTotal(t *testing.T) { _, _, err = freezeResultFrames(header, body, int64(len(header)+len(body)-1)) require.ErrorContains(t, err, "exceeds") } + +func TestChooseInputBatchBoundsEncodingAttemptsAndPropagatesErrors(t *testing.T) { + frame := ArrowFrame{Header: []byte("schema"), Body: []byte("record")} + t.Run("full candidate avoids a search when it fits", func(t *testing.T) { + var attempts []int64 + got, err := chooseInputBatchWithFullCandidate(8, 64, func(rows int64) ([]ArrowFrame, error) { + attempts = append(attempts, rows) + return []ArrowFrame{frame}, nil + }, true) + require.NoError(t, err) + require.Equal(t, int64(8), got.Rows) + require.Equal(t, []ArrowFrame{frame}, got.Frames) + require.Equal(t, []int64{8}, attempts) + }) + + t.Run("size limit uses bounded exponential and binary search", func(t *testing.T) { + var attempts []int64 + got, err := chooseInputBatchWithFullCandidate(10, 64, func(rows int64) ([]ArrowFrame, error) { + attempts = append(attempts, rows) + if rows > 5 { + return nil, errArrowBatchTooLarge + } + return []ArrowFrame{frame}, nil + }, true) + require.NoError(t, err) + require.Equal(t, int64(5), got.Rows) + require.Equal(t, []int64{10, 1, 2, 4, 8, 6, 5}, attempts) + }) + + t.Run("non-size errors do not trigger retries", func(t *testing.T) { + wantErr := errors.New("injected Arrow encoder failure") + attempts := 0 + _, err := chooseInputBatchWithFullCandidate(4, 64, func(int64) ([]ArrowFrame, error) { + attempts++ + return nil, wantErr + }, true) + require.ErrorIs(t, err, wantErr) + require.Equal(t, 1, attempts) + }) + + t.Run("one row larger than the byte limit is rejected", func(t *testing.T) { + got, err := chooseInputBatch(4, 1, func(int64) ([]ArrowFrame, error) { + return nil, errArrowBatchTooLarge + }) + require.ErrorIs(t, err, errArrowBatchTooLarge) + require.Zero(t, got.Rows) + }) +} diff --git a/pkg/udf/runtime_test.go b/pkg/udf/runtime_test.go index 4ee0bd5e7e4c0..d415df5c46a6e 100644 --- a/pkg/udf/runtime_test.go +++ b/pkg/udf/runtime_test.go @@ -45,6 +45,15 @@ func (r *closableRuntime) Close() error { return nil } +type readinessRuntime struct { + *closableRuntime + readyErr error +} + +func (r *readinessRuntime) CheckLanguageReady(context.Context, string) error { + return r.readyErr +} + func TestRuntimeRegistryClosesOwnedRuntimesOnce(t *testing.T) { python := &closableRuntime{language: LanguagePython} runtime, err := NewRuntime(python) @@ -56,6 +65,63 @@ func TestRuntimeRegistryClosesOwnedRuntimesOnce(t *testing.T) { require.Equal(t, int32(1), python.closed.Load()) } +func TestRuntimeRegistryFailsClosedForMissingCapabilities(t *testing.T) { + ctx := context.Background() + registry, err := NewRuntime() + require.NoError(t, err) + provider, ok := registry.(RuntimeStatusProvider) + require.True(t, ok) + snapshot := provider.StatusSnapshot(ctx, LanguagePython) + require.Equal(t, RuntimeStatusDisabled, snapshot.ErrorClass) + require.Equal(t, RuntimeStatusReasonRuntimeDisabled, snapshot.Reason) + require.Error(t, registry.(RuntimeReadiness).CheckLanguageReady(ctx, LanguagePython)) + require.Error(t, registry.(RuntimeDefinitionValidator).ValidateDefinition(ctx, nil)) + require.Error(t, registry.Execute(ctx, nil, nil, nil)) + + plain, err := NewRuntime(&closableRuntime{language: LanguagePython}) + require.NoError(t, err) + snapshot = plain.(RuntimeStatusProvider).StatusSnapshot(ctx, LanguagePython) + require.Equal(t, RuntimeStatusUnavailable, snapshot.ErrorClass) + require.Equal(t, RuntimeStatusReasonStatusUnavailable, snapshot.Reason) + require.Error(t, plain.(RuntimeReadiness).CheckLanguageReady(ctx, LanguagePython)) + require.Error(t, plain.(RuntimeDefinitionValidator).ValidateDefinition(ctx, &RoutineDefinition{Language: LanguagePython})) + require.Error(t, plain.Execute(ctx, &Invocation{Language: "missing"}, nil, nil)) +} + +func TestRuntimeRegistryUsesReadinessFallback(t *testing.T) { + ctx := context.Background() + ready, err := NewRuntime(&readinessRuntime{closableRuntime: &closableRuntime{language: LanguagePython}}) + require.NoError(t, err) + snapshot := ready.(RuntimeStatusProvider).StatusSnapshot(ctx, LanguagePython) + require.True(t, snapshot.Ready) + require.Empty(t, snapshot.ErrorClass) + require.Equal(t, RuntimeStatusReasonReady, snapshot.Reason) + + cause := context.DeadlineExceeded + unavailable, err := NewRuntime(&readinessRuntime{ + closableRuntime: &closableRuntime{language: LanguagePython}, + readyErr: cause, + }) + require.NoError(t, err) + snapshot = unavailable.(RuntimeStatusProvider).StatusSnapshot(ctx, LanguagePython) + require.True(t, snapshot.Enabled) + require.False(t, snapshot.Ready) + require.Equal(t, RuntimeStatusUnavailable, snapshot.ErrorClass) + require.Equal(t, RuntimeStatusReasonWorkerUnavailable, snapshot.Reason) +} + +func TestNewRuntimeRejectsInvalidAndDuplicateLanguageOwners(t *testing.T) { + _, err := NewRuntime(nil) + require.Error(t, err) + _, err = NewRuntime(&closableRuntime{}) + require.Error(t, err) + _, err = NewRuntime( + &closableRuntime{language: LanguagePython}, + &closableRuntime{language: LanguagePython}, + ) + require.Error(t, err) +} + func TestStatementContextFromMapProducesCanonicalTypedSnapshot(t *testing.T) { snapshot, err := StatementContextFromMap(map[string]string{ "statement_timestamp_utc": "1704067200123456", From 57d125a923fb4a6ccd3bc1c1de241ea3fe6ce750 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 23 Sep 2026 21:44:45 +0800 Subject: [PATCH 197/241] fix(optools): retain Python runtime loader path --- optools/ut_holder_test.go | 46 ++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/optools/ut_holder_test.go b/optools/ut_holder_test.go index fc2f5fc235d4e..a6b9bc5f00f6b 100644 --- a/optools/ut_holder_test.go +++ b/optools/ut_holder_test.go @@ -57,28 +57,51 @@ func TestUTAdmissionHolderEvidence(t *testing.T) { } } -func TestPythonStdlibEnvironmentDropsNativeAndImportOverrides(t *testing.T) { +func TestPythonStdlibEnvironmentUsesConfiguredRuntimeLibraryPath(t *testing.T) { + t.Setenv("pythonLocation", "/python/toolcache") t.Setenv("LD_LIBRARY_PATH", "/matrixone/cgo") t.Setenv("PYTHONPATH", "/matrixone/python") t.Setenv("PYTHONHOME", "/matrixone/python-home") t.Setenv("PYTHONUSERBASE", "/matrixone/user-site") + t.Setenv("PYTHONSTARTUP", "/matrixone/startup.py") + t.Setenv("PYTHONINSPECT", "1") + t.Setenv("MO_UT_ENV_SENTINEL", "preserved") env := pythonStdlibEnvironment() - if !strings.Contains(strings.Join(env, "\n"), "PATH=") { + values := make(map[string]string, len(env)) + for _, entry := range env { + key, value, _ := strings.Cut(entry, "=") + values[key] = value + } + if values["PATH"] == "" { t.Fatal("sanitized Python environment lost PATH") } - for _, entry := range env { - for _, forbidden := range []string{"LD_LIBRARY_PATH=", "PYTHONPATH=", "PYTHONHOME=", "PYTHONUSERBASE="} { - if strings.HasPrefix(entry, forbidden) { - t.Fatalf("Python stdlib helper inherited %q", entry) - } + if got, want := values["MO_UT_ENV_SENTINEL"], "preserved"; got != want { + t.Fatalf("sanitized Python environment changed unrelated variable: got %q, want %q", got, want) + } + if got, want := values["LD_LIBRARY_PATH"], filepath.Join("/python/toolcache", "lib"); got != want { + t.Fatalf("Python runtime loader path = %q, want %q", got, want) + } + for _, forbidden := range []string{ + "PYTHONPATH", "PYTHONHOME", "PYTHONUSERBASE", "PYTHONSTARTUP", "PYTHONINSPECT", + } { + if _, ok := values[forbidden]; ok { + t.Fatalf("Python stdlib helper inherited %q", forbidden) } } } -// pythonStdlibEnvironment keeps the configured interpreter discoverable while -// preventing MatrixOne's native-library and Python import paths from changing -// a standard-library-only report parser's runtime. +func TestPythonStdlibEnvironmentDropsNativeLoaderPathWithoutPythonLocation(t *testing.T) { + t.Setenv("pythonLocation", "") + t.Setenv("LD_LIBRARY_PATH", "/matrixone/cgo") + if got := pythonStdlibEnvironment(); strings.Contains(strings.Join(got, "\n"), "LD_LIBRARY_PATH=") { + t.Fatalf("Python stdlib helper inherited MatrixOne loader path: %q", got) + } +} + +// pythonStdlibEnvironment keeps the configured interpreter's matching runtime +// library available while preventing MatrixOne's native libraries and Python +// import overrides from changing a standard-library-only report parser. func pythonStdlibEnvironment() []string { env := make([]string, 0, len(os.Environ())) for _, entry := range os.Environ() { @@ -90,5 +113,8 @@ func pythonStdlibEnvironment() []string { env = append(env, entry) } } + if pythonLocation := os.Getenv("pythonLocation"); pythonLocation != "" { + env = append(env, "LD_LIBRARY_PATH="+filepath.Join(pythonLocation, "lib")) + } return env } From 68286bff927482f2b7f1a836e47bc8bd902e6104 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 24 Sep 2026 11:52:19 +0800 Subject: [PATCH 198/241] docs(udf): clarify test-stage acceptance scope --- docs/design/python_udf.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/design/python_udf.md b/docs/design/python_udf.md index dde191f159839..47fbfdf1e84a3 100644 --- a/docs/design/python_udf.md +++ b/docs/design/python_udf.md @@ -6,6 +6,20 @@ The shared Function Catalog design owns identity, revision and security semantic SQL and Python designs own their language contracts. This summary does not replace those contracts. +## Owner-approved stage scope + +On 2026-09-24, feature owner `iamlinjunhong` approved this PR for testing and +development-stage acceptance. The user guide and SQL examples are recorded in +[issue #28132](https://github.com/matrixorigin/matrixone/issues/28132#issuecomment-5748253137). +This PR does not claim production rollout, sandbox isolation, protection for +untrusted Python, or authenticated/TLS Flight transport. Those remain separate +production acceptance gates. Python stays disabled in generic launch and requires +explicit opt-in in the test/development configurations. + +This stage decision is the feature owner's authorization for the current PR +scope; it is not a claim that Architecture, Security, SQL/Planner, Runtime, +Catalog, or Operator owners have approved the future production design. + ## Execution and identity CREATE/REPLACE validates Python syntax and the handler contract before publishing From 30befe243803e53de24f948bf31495327c127b1c Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 24 Sep 2026 14:55:00 +0800 Subject: [PATCH 199/241] docs(udf): approve current-stage design contract --- docs/design/python_udf.md | 9 +- docs/design/python_udf_current_stage.md | 236 ++++++++++++++++++++++++ 2 files changed, 241 insertions(+), 4 deletions(-) create mode 100644 docs/design/python_udf_current_stage.md diff --git a/docs/design/python_udf.md b/docs/design/python_udf.md index 47fbfdf1e84a3..a2b7e02dd11f5 100644 --- a/docs/design/python_udf.md +++ b/docs/design/python_udf.md @@ -1,10 +1,11 @@ # Python UDF implementation and rollout scope This describes the implemented, owner-authorized external Python adapter and its -PR acceptance boundary. It does not approve a production tenant-isolation model. -The shared Function Catalog design owns identity, revision and security semantics; -SQL and Python designs own their language contracts. This summary does not replace -those contracts. +PR acceptance boundary. The relevant current-stage Catalog, SQL/planner, +migration/restore, Python ABI, Flight, and resource contracts are consolidated +in the [versioned current-stage design](python_udf_current_stage.md). Broader +long-term designs continue to inform future work; this page does not approve a +production tenant-isolation model. ## Owner-approved stage scope diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md new file mode 100644 index 0000000000000..2adcb1ec63ced --- /dev/null +++ b/docs/design/python_udf_current_stage.md @@ -0,0 +1,236 @@ +# Python UDF current-stage design contract + +| Field | Value | +| --- | --- | +| Design revision | `python-udf-current-stage-r1-2026-09-24` | +| Applies to | MatrixOne PR #29152, test/development-stage Python UDF | +| Implementation baseline reviewed | `9847da80d6c7096cb0460e46a5cf710e9714af3a` | +| Approval | Feature owner `iamlinjunhong` approved this exact revision for the current test/development stage on 2026-09-24. The traceable PR approval record is linked from the PR discussion for this revision. | +| Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | + +This is the approved governing contract for the current PR stage. It consolidates +the shared Catalog, SQL/planner, Python ABI, Flight, and resource-lifecycle +decisions needed to review this implementation. It does not approve future +sandbox or production deployment. The test/development scope is explicit: +Python is opt-in and unisolated; old demo definitions are rejected and must be +recreated through the current DDL. There is no legacy Python adapter or +fallback execution path. + +## Identity, Catalog, and publication + +Python functions use the shared `mo_user_defined_function` identity namespace. +The current catalog upgrade adds `active_revision`, `namespace_version`, the +canonical input/return descriptors, and signature schema/fingerprint columns. +`mo_function_revisions` stores the immutable typed revision keyed by +`(function_id, revision)`, including language, full argument and return +descriptors, ABI/adapter/SDK/schema contracts, artifact and environment digests, +NULL policy, volatility, security mode, and definition fingerprint. Revision +publication and head activation occur in the caller's catalog transaction. +Python executes as `INVOKER`, is `VOLATILE`, may error, and is not leakproof. + +The artifact is an immutable, account-scoped FileService object addressed by +digest; each artifact is at most 1 MiB. CN resolves the exact account/digest +before Open, and the worker receives verified source bytes without object-store +credentials or query-time dependency installation. CREATE/REPLACE validates the +current contract before committing a catalog definition. Artifact publication +precedes catalog commit, so a failed validation/transaction can leave an +unreferenced content-addressed object. No artifact garbage collector or +per-account total artifact quota exists today; per-object size is bounded, total +retained artifact storage is not. This is an explicit test/development-stage +limitation, not a production storage-retention claim. + +The type descriptor is canonical over SQL type ID and applicable width, scale, +charset, offset-width, JSON, and temporal encodings. The trusted adapter builds +Arrow field/schema metadata from that descriptor; it validates both physical +Arrow type and the SQL value domain. Handler-provided metadata cannot redefine +the function type. CREATE/REPLACE compiles the submitted module and checks the +declared synchronous module-level handler; it does not execute top-level user +code or install packages. The environment digest includes the current runtime +environment, including tzdata. An environment mismatch fails closed; definitions +must be explicitly recreated for a changed contract. + +The current mappings encode JSON as `canonical_text` and DATE/DATETIME/TIMESTAMP +with `sql_zero_struct`; SQL zero temporal values remain explicit values and are +never rewritten as NULL. SCALAR handlers receive `(ctx, scalar...)`; VECTOR +handlers receive `(ctx, arrays...)`. The default NULL policy calls the handler +without filtering NULL rows; `RETURNS NULL ON NULL INPUT` removes those rows +before the call and scatters NULLs into their result positions. + +`REPLACE` preserves language and the exact Python argument/return descriptors; +changing language or signature requires DROP/CREATE. DROP/CREATE receives a new +identity. Old Python demo rows without a current revision head, unsupported +definition/SDK/plan contracts, and corrupt revision heads fail closed before +user code runs. They are not auto-migrated. No query resolves a mutable `latest` +revision or takes source from an executable plan. + +## SQL compatibility, plans, and migration + +The shared revision catalog is additive to the existing SQL UDF contract. +During a rolling tenant upgrade, SQL UDF writers continue using the legacy +`mo_user_defined_function` row while `mo_function_revisions` is absent. Once the +revision catalog is available, SQL writers publish the compatibility row and +revision in the same transaction. Readers use the legacy SQL row only when the +revision schema/head is absent or both head fields are zero. A non-zero but +missing or malformed revision is a catalog error; it never silently falls back. +The SQL UDF language, body, security, and evaluation semantics remain owned by +the existing SQL path. The Python demo's old execution behavior is not a +compatibility promise. + +Upgrade `4.0.7` (minimum source `4.0.6`) changes the shared function identity +columns/index and creates `mo_function_revisions`. The upgrade handler is gated +on common MORPC protocol 61 so a tenant migration does not widen catalog tables +while an old writer can still serve them. Python DDL independently probes the +required tenant schema and refuses creation/replacement until it is present; +worker capability negotiation is a separate exact-contract gate. This is +feature-level admission, not a requirement that every component have the same +software version string. + +The migration has no down handler. Do not manually remove the revision table, +columns, or index, and do not claim that restoring an old binary restores Python +execution. Binary rollback after applying this catalog migration is not a +supported recovery path in this contract; ordinary SQL behavior in that mixed +state has not been verified here. Python definitions must remain intact and +require a current-contract binary to execute. The current evidence does not +include a tested downgrade after Python definitions have been written. +The upgrade-compatibility CI checks were skipped on the reviewed exact head. + +Current-contract snapshot restore preserves the selected revision and +republishes its artifact into the destination account's namespace. The SQL +control function and source-account isolation are covered in +[`snapshot_restore.sql`](../../test/distributed/cases/udf_python/snapshot_restore.sql). +Cross-version restore and downgrade are outside the evidence and remain +unsupported until tested. Restore must not synthesize a revision from a legacy +Python row. + +The plan contains a typed `RoutineCall`, an exact `FunctionRef` (account, +database, identity, revision, namespace), a typed implementation oneof, and a +dependency envelope. Python source is not embedded in the executable plan. +Plan reuse validates both the exact selected revision and a fingerprint of the +complete same-name overload namespace across SQL and Python. The dependency +closure is capped at 1,024 routines and 1 MiB. This invalidates prepared/cache +plans when a newly added overload changes binding, even if the previously +selected identity still exists. Plans without the namespace fingerprint rebind; +an overflowed namespace read makes the plan non-reusable rather than accepting a +truncated fingerprint. Execution uses the bound exact reference and never +resolves by name. Namespace validation reads at most 65,536 candidates (one +extra detects overflow) and 64 MiB of decoded metadata; on overflow it forces +rebind without rejecting otherwise valid SQL. + +## SQL evaluation and result semantics + +`ExternalRoutineEval` is a physical expression evaluator in the existing MO +expression framework. The parent supplies the batch and CASE/selection mask; +the evaluator runs each bound argument expression, including planned casts, +once under that mask, applies +`RETURNS NULL ON NULL INPUT`, compacts selected rows, validates the returned +Arrow schema and SQL value domain, then scatters results to original row +positions. Unselected CASE branches are not invoked. Python's default +volatility prevents planning-time constant folding. Empty input, a batch with +no rows selected, and a batch whose rows are all removed by strict NULL +filtering return locally without acquiring Gateway K, a worker group, or a +ledger entry. Zero-argument VECTOR calls receive `ctx.num_rows` for output +shape. + +The ordinary Python BVT includes SELECT, WHERE, JOIN ON/outer-join predicates, +aggregate arguments, window ordering, nested calls, INSERT/UPDATE/DELETE, and +failure atomicity. It also covers scalar/vector modes, NULL policies, create, +replace, exact-overload invalidation, drop/recreate, Arrow compute, and +current-contract account restore. These are current tested placements; this +contract does not claim every possible SQL syntactic position without a case. + +## Flight protocol and terminal ownership + +Gateway is a CN library; the worker is the Flight server. There is no separately +deployed Gateway daemon. The current capability vector must match exactly +(wire protocol 1, ABI/adapter/SDK/definition/plan/type contracts, tzdata, +modes, NULL policies, frame/handler limits, and worker lease epoch). The worker +advertises `window_batches=1` and `cumulative_ack=false`. A mismatch fails +before handler execution; there is no old-worker fallback. Control envelopes +are limited to 1 MiB, JSON nesting to 64, and each fencing ID component to +256 bytes. + +After admission reserves the group/member, K, and ledger, the Gateway opens the +exchange. With W=1, each non-final batch follows +`InputBatch(i) → InputConsumed(i) → ResultBatch(i) → AcknowledgeResults(i)` +before the Gateway sends batch `i+1`. After sending the final +`InputBatch(last_seq)`, the Gateway sends `EndInput(last_seq)` and half-closes +its send direction; it then receives the final `InputConsumed`, result, and ACK, +followed by `Finish → AcknowledgeFinish(finish_id) → terminal success`. + +`EndInput` closes only the input direction; Flight send-half-close is normal +and the result direction remains readable. `InputConsumed` returns ownership of +the corresponding input backing. The result slot remains charged until it has +been validated and materialized in MO. W=1 permits one batch of progress at a +time. Finish is valid only after EndInput and acknowledgement of all result +sequences. The worker freezes success only after accepting the idempotent +Finish acknowledgement. If the ACK was accepted but its response was lost, the +Gateway retries only that same idempotent ACK; if confirmation remains unknown, +it reports `FINISH_UNCONFIRMED`. It never retries Open or replays work that may +have reached STARTED. + +The CN Gateway owns K, group/member admission, and its terminal ledger. A +member releases only its own resources; the group owner releases the group and +reservation. The current integration uses one invocation member per group. +Empty and all-NULL work is completed locally by the evaluator, without a remote +group. For admitted work, partial Open, cancellation, and close have one owner +and a terminal outcome. The worker owns H, child process/session cleanup, and +its own ledger. Generation/lease fences reject stale callbacks and messages. A +terminal TTL alone never grants a new execution epoch. On cancel, timeout, or +transport failure, Gateway cancels/closes the exchange before returning its +local K or ledger ownership; the worker retains H and cleanup ownership until +the child is terminated and reaped. STARTED work is not transparently replayed. + +Worker handler children are process-group scoped and must be terminated and +reaped by the worker's cleanup owner before H is returned. A failed or partial +cleanup retains bounded cleanup ownership instead of releasing H early. Linux +process-tree failure tests provide implementation evidence; this process model +does not confine a handler's access to the host or its Python heap. + +## Resource budgets and trust boundary + +Zero in an enabled CN client config means the runtime default, not unlimited. +The current defaults are: + +| Resource | Owner and default | Contract | +| --- | --- | --- | +| K, active invocations | CN Gateway: 8 per CN | Non-blocking admission; a full budget rejects rather than queueing while holding input vectors. | +| W, stream window | Gateway/worker: 1 batch | No multiple in-flight batches or cumulative ACK. | +| H, handler subprocesses | Worker: 8 total, 8/account, 4/owner | Worker constants and capability contract; admission is all-or-nothing. | +| Batch | CN/worker: 16 MiB and 65,536 rows | Each Arrow batch is bounded before transfer. | +| Invocation | CN/worker: 1,048,576 rows; CN result: 256 MiB | Result bound is per invocation. At K=8, retained result vectors alone can reach 2 GiB per CN. | +| Request | CN: 30 s default; worker ACK: 60 s | Configured handler timeout and protocol ACK timeout have distinct owners. | +| CN terminal state | 8,192 entries, 8 MiB, 10 min | Active entries plus tombstones and separately reserved closed-group fences are bounded. | +| Worker terminal state | 10,000 entries, 16 MiB, 5 min | Independent bound; worker values intentionally differ from CN values. | +| Worker pending cleanup | 10,000 invocations | Derived from worker ledger capacity; cleanup failure retains ownership rather than releasing H. | +| Same-invocation burst reuse | Worker: 64 batches, 64 MiB, or 30 s | The first reached limit ends reuse; statement deadline and started inputs do not reset. | + +The per-invocation result maximum multiplied by K is a deliberate worst-case +capacity implication, not a process-wide RSS limit. Arrow/IPC, pickle/pipe, +temporary snapshots, materialization, Python heap, queues, file descriptors, +and child processes have different owners; wire-byte limits do not cap arbitrary +Python heap growth. Artifact count and total FileService bytes are not capped. +The CN's completion retention is longer than the worker's (10 versus 5 minutes); +the limits are compatible, not equal. The CN retains its own terminal/group +fences and never transparently resends STARTED work after a worker tombstone +expires. +The adapter is unisolated, Flight has no TLS/authentication in this stage, and +the fencing tuple is not an authentication token. These limits support +test/development correctness and backpressure, not hostile-code containment. + +## Evidence and remaining limits + +| Contract | Evidence on the reviewed branch/head | Status | +| --- | --- | --- | +| Shared revision schema and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_7/upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go` | Unit/schema contract covered; upgrade-compatibility CI was skipped. | +| Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | +| SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | +| Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | +| Flight state, ACK, cancellation, resource limits | `pkg/udf/python/gateway_test.go`, `gateway_admission_test.go`, `capability_lifecycle_test.go`, `gateway_integration_test.go`, `pkg/udf/python/worker/test_worker.py`, `test_watchdog.py` | Unit, process, and real Flight cases present; this design does not substitute for implementation/lifecycle review. | +| Exact-head CI | PR #29152 validation reported shared build, Linux UT, SCA, coverage, and active multi-CN BVT passed | Upgrade-compatibility checks skipped; no downgrade evidence. | + +The reviewed change is not declared production-ready. Artifact GC/total-storage +quota, cross-version migration rollback/restore, authenticated transport, and +sandboxing remain explicit limits. The owner-approved acceptance is limited to +the test/development stage. This approval closes the current-stage design gate; +the reviewer must still complete the implementation/lifecycle review before the +PR review is complete. From 8cd0ed1c2b3334f7c98cfda99a21e2ae3947c49f Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 24 Sep 2026 14:56:12 +0800 Subject: [PATCH 200/241] docs(udf): link design approval record --- docs/design/python_udf_current_stage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 2adcb1ec63ced..35741c3992f2c 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -5,7 +5,7 @@ | Design revision | `python-udf-current-stage-r1-2026-09-24` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | | Implementation baseline reviewed | `9847da80d6c7096cb0460e46a5cf710e9714af3a` | -| Approval | Feature owner `iamlinjunhong` approved this exact revision for the current test/development stage on 2026-09-24. The traceable PR approval record is linked from the PR discussion for this revision. | +| Approval | Feature owner `iamlinjunhong` approved this exact revision for the current test/development stage on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the approved governing contract for the current PR stage. It consolidates From daa490a2c16ee5b5430847b7fc5c37923fd09ab1 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 24 Sep 2026 18:25:55 +0800 Subject: [PATCH 201/241] docs(udf): record current-stage design approvals --- docs/design/python_udf_current_stage.md | 2 +- .../python_udf_current_stage_approval.md | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 docs/design/python_udf_current_stage_approval.md diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 35741c3992f2c..994b8016729d2 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -5,7 +5,7 @@ | Design revision | `python-udf-current-stage-r1-2026-09-24` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | | Implementation baseline reviewed | `9847da80d6c7096cb0460e46a5cf710e9714af3a` | -| Approval | Feature owner `iamlinjunhong` approved this exact revision for the current test/development stage on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). | +| Approval | Feature owner `iamlinjunhong` approved this exact revision for the current test/development stage on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The immutable artifact and independent-review status are recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the approved governing contract for the current PR stage. It consolidates diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md new file mode 100644 index 0000000000000..ae17966108032 --- /dev/null +++ b/docs/design/python_udf_current_stage_approval.md @@ -0,0 +1,67 @@ +# Python UDF current-stage design approval record + +| Field | Value | +| --- | --- | +| Record | `python-udf-current-stage-r1-2026-09-24-approval` | +| Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | +| Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | +| Current-stage contract | [`python-udf-current-stage-r1-2026-09-24`](python_udf_current_stage.md) | +| Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | + +This record separates the immutable current-stage design artifact, the feature +owner's scope authorization, and independent technical approval facts. It is a +traceability record; it does not create an approval that is not present in the +PR or issue history. + +## Immutable artifacts + +The design content accepted for the current test/development stage was published +in the rebased PR history at commit [`c6f9c7682279816872fc3b3f7d5cf41ffe940acc`](https://github.com/matrixorigin/matrixone/commit/c6f9c7682279816872fc3b3f7d5cf41ffe940acc). +The corresponding pre-rebase review commit was +[`610d1e4dcfe2bad2ed1060babe0acc60c89b1c60`](https://github.com/matrixorigin/matrixone/commit/610d1e4dcfe2bad2ed1060babe0acc60c89b1c60). +The exact Git blob for +[`docs/design/python_udf_current_stage.md`](https://github.com/matrixorigin/matrixone/blob/c6f9c7682279816872fc3b3f7d5cf41ffe940acc/docs/design/python_udf_current_stage.md) +at both design commits is +`2adcb1ec63ced2dfbdedf192509b07d5b7c9db31`. + +The design was written against implementation baseline +[`9847da80d6c7096cb0460e46a5cf710e9714af3a`](https://github.com/matrixorigin/matrixone/commit/9847da80d6c7096cb0460e46a5cf710e9714af3a). +The rebase-equivalent implementation baseline in the final PR history is +[`1a26a2f9046643a284df488f57470b811cca747a`](https://github.com/matrixorigin/matrixone/commit/1a26a2f9046643a284df488f57470b811cca747a). +The pre-rebase exact review head was +[`92a89d81588159a918458b1a930bccc9d0e75d4b`](https://github.com/matrixorigin/matrixone/commit/92a89d81588159a918458b1a930bccc9d0e75d4b). +The repair commit carrying this record is the final documentation commit on +top of the rebased PR history; its exact remote head is verified at delivery. +The final current-stage design blob is +`994b8016729d2e87a6a706a2833eee7faf50c89b`; its only difference from the +approved design blob is the link to this traceability record. + +The namespace-validation companion is the implementation contract from commit +[`284a1d971a1d2c763c6aed425d52f751735c409f`](https://github.com/matrixorigin/matrixone/commit/284a1d971a1d2c763c6aed425d52f751735c409f), +with current-head blob `51ccfb771db19321d03b292cd3d7219f698a11b8`. + +## Approval ledger + +| Decision area | Evidence and scope | Status | +| --- | --- | --- | +| Feature-owner acceptance | [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638) approves the exact current-stage contract for testing/development use. | Approved for this limited scope | +| Architecture review | No independent approval record naming the reviewer, exact design artifact, date, scope, and decision is present in the PR/issue history examined at pre-rebase head `92a89d81588159a918458b1a930bccc9d0e75d4b`. | Pending; not inferred | +| Security review | The contract records the unisolated, opt-in boundary and explicitly excludes sandboxing and authenticated/TLS Flight. That scope record is not a production security approval. | Pending for any production/security enablement; not inferred | +| SQL/Planner review | The current-stage document contains the shared Catalog, exact revision, overload, evaluation, migration, restore, and compatibility contract. No independent approval record for that exact artifact is present in the PR/issue history examined at the recorded pre-rebase head. | Pending; not inferred | +| Cloud/Operator review | The current-stage document records launch, init, endpoint, and rollout limits, and excludes Operator rollout acceptance. No independent approval record for production/operator rollout is present. | Pending; not inferred | + +The pending rows are external approval facts and are intentionally not replaced +by feature-owner authorization, passing CI, or implementation review. They must +remain separate from the test/development acceptance boundary. This PR does not +authorize production tenant isolation, sandboxing, authenticated transport, +Operator rollout, artifact garbage collection, total artifact quota, or +cross-version downgrade/restore. + +## Evidence boundary + +The design document's evidence table identifies the focused unit, process, Flight, +SQL/BVT, restore, and exact-head CI evidence. Upgrade-compatibility checks were +skipped at the recorded head; cross-version rollback/restore is unsupported in +this stage. Those gaps are recorded as limits and are not represented as passing +approval evidence. Full implementation/lifecycle review remains a separate PR +review step after the design record is accepted by the relevant reviewers. From 6b80eb5a2f93c949564e4a81726a58fcb818d05a Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 25 Sep 2026 10:04:06 +0800 Subject: [PATCH 202/241] fix(optools): keep watchdog diagnostics out of UT report --- docs/design/python_udf_current_stage.md | 2 +- optools/ut_embedded_schedule_test.go | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 994b8016729d2..61821b94cd015 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -226,7 +226,7 @@ test/development correctness and backpressure, not hostile-code containment. | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | | Flight state, ACK, cancellation, resource limits | `pkg/udf/python/gateway_test.go`, `gateway_admission_test.go`, `capability_lifecycle_test.go`, `gateway_integration_test.go`, `pkg/udf/python/worker/test_worker.py`, `test_watchdog.py` | Unit, process, and real Flight cases present; this design does not substitute for implementation/lifecycle review. | -| Exact-head CI | PR #29152 validation reported shared build, Linux UT, SCA, coverage, and active multi-CN BVT passed | Upgrade-compatibility checks skipped; no downgrade evidence. | +| Historical CI at the reviewed implementation baseline | PR #29152 baseline `9847da80d6c7096cb0460e46a5cf710e9714af3a`; [MatrixOne ALL CI run 35953275189](https://github.com/matrixorigin/matrixone/actions/runs/35953275189) passed | Exact-head run 35988821412 is tracked separately; its UT coverage producer failed, so it is not passing coverage evidence. Upgrade-compatibility checks skipped; no downgrade evidence. | The reviewed change is not declared production-ready. Artifact GC/total-storage quota, cross-version migration rollback/restore, authenticated transport, and diff --git a/optools/ut_embedded_schedule_test.go b/optools/ut_embedded_schedule_test.go index 92337489d203c..c5b36b8652d18 100644 --- a/optools/ut_embedded_schedule_test.go +++ b/optools/ut_embedded_schedule_test.go @@ -1051,6 +1051,15 @@ func TestEmbeddedPrebuiltFailureKeepsReportJSONOnly(t *testing.T) { t.Run("parallel="+parallel, func(t *testing.T) { script := embeddedSetup + ` function logger() { printf '%s\n' "$*"; } + # Keep both active-package group-alive probes false, then force the real + # watchdog cleanup wait through its bounded force-stop branch. The diagnostic + # must remain in UT_STDERR; a missing redirection contaminates UT_REPORT. +force_group_probe_count=0 +function ut_process_group_alive() { + force_group_probe_count=$((force_group_probe_count + 1)) + if (( force_group_probe_count >= 3 && force_group_probe_count <= 23 )); then return 0; fi + return 1 +} start_embedded_prebuild "$scope" 1 status=0 run_embedded_tests "$scope" 2 > "$CASE_DIR/outer-log" || status=$? @@ -1058,6 +1067,7 @@ run_embedded_tests "$scope" 2 > "$CASE_DIR/outer-log" || status=$? cat "$UT_REPORT" grep -q 'prebuilt embedded package example/b failed' "$UT_STDERR" || exit 92 +grep -q 'UT cancellation: force stopping process group' "$UT_STDERR" || exit 93 ` out, err := scheduleHarnessWithMockTransform(t, script, embeddedGoMock, nil, "MODE=test-failure", "UT_PREBUILD_EMBEDDED=1", "UT_HARD_TIMEOUT=", "UT_EMBEDDED_PACKAGE_PARALLEL="+parallel) From 80fc7b8708fc222cee205567917202eb197fabab Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 5 Oct 2026 14:10:48 +0800 Subject: [PATCH 203/241] fix(udf): preserve recovered catalog and protocol repair --- docs/design/python_udf_current_stage.md | 40 ++- pkg/bootstrap/versions/v4_0_12/upgrade.go | 17 +- .../versions/v4_0_12/upgrade_test.go | 291 +++++++++++------- .../versions/v4_0_7/tenant_upgrade_list.go | 7 + pkg/frontend/authenticate.go | 40 ++- pkg/frontend/compiler_context.go | 23 +- pkg/frontend/python_udf_catalog_test.go | 92 ++++++ pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 + 9 files changed, 366 insertions(+), 150 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 61821b94cd015..170a6705db11b 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r1-2026-09-24` | +| Design revision | `python-udf-current-stage-r2-2026-09-25` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Implementation baseline reviewed | `9847da80d6c7096cb0460e46a5cf710e9714af3a` | -| Approval | Feature owner `iamlinjunhong` approved this exact revision for the current test/development stage on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The immutable artifact and independent-review status are recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Implementation baseline reviewed | `9847da80d6c7096cb0460e46a5cf710e10714af3a` | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). This r2 addendum is a conservative mixed-version safety repair: it narrows revision admission and adds no production or security scope. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the approved governing contract for the current PR stage. It consolidates @@ -67,23 +67,31 @@ revision or takes source from an executable plan. The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy -`mo_user_defined_function` row while `mo_function_revisions` is absent. Once the -revision catalog is available, SQL writers publish the compatibility row and -revision in the same transaction. Readers use the legacy SQL row only when the -revision schema/head is absent or both head fields are zero. A non-zero but -missing or malformed revision is a catalog error; it never silently falls back. -The SQL UDF language, body, security, and evaluation semantics remain owned by -the existing SQL path. The Python demo's old execution behavior is not a -compatibility promise. +`mo_user_defined_function` row while `mo_function_revisions` is absent. The +revision-aware writer and reader contract is admitted only at the active common +MORPC protocol floor `107` (`latest + 1` for this PR). Below that floor, a new +binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly +use that row so an old writer and a new reader observe the same body. Replacing +a function that already has a non-zero shared revision head is rejected below +the floor; this prevents a legacy-only write from leaving a stale immutable +revision that would become authoritative later. At protocol 107 and above, +writers publish the compatibility row, immutable revision, and active head in +the same caller-owned transaction, and readers use the selected revision. +A non-zero head with a missing or malformed revision is a catalog error; it is +never silently repaired or synthesized. The SQL UDF language, body, security, +and evaluation semantics remain owned by the existing SQL path. The Python +demo's old execution behavior is not a compatibility promise. Upgrade `4.0.7` (minimum source `4.0.6`) changes the shared function identity columns/index and creates `mo_function_revisions`. The upgrade handler is gated on common MORPC protocol 61 so a tenant migration does not widen catalog tables while an old writer can still serve them. Python DDL independently probes the required tenant schema and refuses creation/replacement until it is present; -worker capability negotiation is a separate exact-contract gate. This is -feature-level admission, not a requirement that every component have the same -software version string. +shared revision publication and Python revision reads additionally require the +common protocol floor 107. The read-only `GetPythonUdfStatus` query method uses +the same new wire capability. Worker capability negotiation is a separate +exact-contract gate. This is feature-level admission, not a requirement that +every component have the same software version string. The migration has no down handler. Do not manually remove the revision table, columns, or index, and do not claim that restoring an old binary restores Python @@ -221,12 +229,12 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_7/upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go` | Unit/schema contract covered; upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-107 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_7/upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go` | Unit/schema contract, immediate-predecessor rollback gate, and old-writer/new-reader legacy-row contract covered; upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | | Flight state, ACK, cancellation, resource limits | `pkg/udf/python/gateway_test.go`, `gateway_admission_test.go`, `capability_lifecycle_test.go`, `gateway_integration_test.go`, `pkg/udf/python/worker/test_worker.py`, `test_watchdog.py` | Unit, process, and real Flight cases present; this design does not substitute for implementation/lifecycle review. | -| Historical CI at the reviewed implementation baseline | PR #29152 baseline `9847da80d6c7096cb0460e46a5cf710e9714af3a`; [MatrixOne ALL CI run 35953275189](https://github.com/matrixorigin/matrixone/actions/runs/35953275189) passed | Exact-head run 35988821412 is tracked separately; its UT coverage producer failed, so it is not passing coverage evidence. Upgrade-compatibility checks skipped; no downgrade evidence. | +| Historical CI at the reviewed implementation baseline | PR #29152 baseline `9847da80d6c7096cb0460e46a5cf710e10714af3a`; [MatrixOne ALL CI run 35953275189](https://github.com/matrixorigin/matrixone/actions/runs/35953275189) passed | Exact-head run 35988821412 is tracked separately; its UT coverage producer failed, so it is not passing coverage evidence. Upgrade-compatibility checks skipped; no downgrade evidence. | The reviewed change is not declared production-ready. Artifact GC/total-storage quota, cross-version migration rollback/restore, authenticated transport, and diff --git a/pkg/bootstrap/versions/v4_0_12/upgrade.go b/pkg/bootstrap/versions/v4_0_12/upgrade.go index d853f7a45c5fc..819fe8515e7cb 100644 --- a/pkg/bootstrap/versions/v4_0_12/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_12/upgrade.go @@ -19,6 +19,7 @@ import ( "time" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/catalog" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/runtime" @@ -27,17 +28,21 @@ import ( "go.uber.org/zap" ) -// Already-upgraded tenants must run the charset metadata refresh. An offset -// change is insufficient: old tenant workers compare only ToVersion. Keep the -// preceding semantic upgrade and its protocol floor; no new key format is enabled. +// 4.0.12 is a repair version, not a new schema contract. Some clusters have +// already persisted 4.0.7 or 4.0.8 while an older upgrade worker skipped the +// shared Python UDF catalog entries. A new semantic version is required so +// those clusters cannot finish the task with the old, empty handler. The +// entries are the original idempotent checks, so a normal 4.0.6 -> 4.0.7 -> +// 4.0.8 -> 4.0.12 upgrade and a repair of an existing 4.0.8 cluster converge +// on the same catalog state. var Handler = &versionHandle{ metadata: versions.Version{ Version: "4.0.12", MinUpgradeVersion: "4.0.11", UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, - VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion106, + VersionOffset: uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), + RequiredProtocolVersion: defines.MORPCVersion107, }, } @@ -56,7 +61,7 @@ func (v *versionHandle) Prepare(ctx context.Context, txn executor.TxnExecutor, f func (v *versionHandle) HandleTenantUpgrade(ctx context.Context, tenantID int32, txn executor.TxnExecutor) error { logger := runtime.ServiceRuntime(txn.Txn().TxnOptions().CN).Logger() - for _, entry := range tenantUpgEntries { + for _, entry := range v4_0_7.PythonRevisionUpgradeEntries() { start := time.Now() if err := entry.Upgrade(txn, uint32(tenantID)); err != nil { logger.Error("tenant upgrade entry execute error", diff --git a/pkg/bootstrap/versions/v4_0_12/upgrade_test.go b/pkg/bootstrap/versions/v4_0_12/upgrade_test.go index f213b055f08e2..68673d9998e54 100644 --- a/pkg/bootstrap/versions/v4_0_12/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_12/upgrade_test.go @@ -15,143 +15,200 @@ package v4_0_12 import ( - "errors" + "context" + "fmt" + "strings" "testing" "github.com/golang/mock/gomock" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/matrixorigin/matrixone/pkg/container/types" - "github.com/matrixorigin/matrixone/pkg/defines" mock_frontend "github.com/matrixorigin/matrixone/pkg/frontend/test" - pbtxn "github.com/matrixorigin/matrixone/pkg/pb/txn" + "github.com/matrixorigin/matrixone/pkg/pb/txn" "github.com/matrixorigin/matrixone/pkg/util/executor" - "github.com/matrixorigin/matrixone/pkg/util/sysview" "github.com/stretchr/testify/require" ) -func TestCharacterSetsUpgradeMetadata(t *testing.T) { - m := Handler.Metadata() - require.Equal(t, "4.0.12", m.Version) - require.Equal(t, "4.0.11", m.MinUpgradeVersion) - require.Equal(t, versions.Yes, m.UpgradeTenant) - require.Equal(t, versions.No, m.UpgradeCluster) - require.Equal(t, defines.MORPCVersion106, m.RequiredProtocolVersion) - require.Equal(t, uint32(1), m.VersionOffset) - check := sysview.InformationSchemaCharacterSetsCheckSQL() - require.Contains(t, check, "(SELECT COUNT(*) FROM information_schema.CHARACTER_SETS) = 3") - require.Contains(t, check, "CHARACTER_SET_NAME = 'utf8' AND DEFAULT_COLLATE_NAME = 'utf8_general_ci' AND MAXLEN = 4") - require.NotContains(t, check, "MAXLEN = 3") +func TestPythonRevisionRepairUpgradePath(t *testing.T) { + metadata := Handler.Metadata() + require.Equal(t, "4.0.12", metadata.Version) + require.Equal(t, "4.0.11", metadata.MinUpgradeVersion) + require.Equal(t, versions.No, metadata.UpgradeCluster) + require.Equal(t, versions.Yes, metadata.UpgradeTenant) + require.Equal(t, int64(107), metadata.RequiredProtocolVersion) + require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) + require.True(t, metadata.CanDirectUpgrade("4.0.11")) + require.False(t, metadata.CanDirectUpgrade("4.0.7")) + require.Len(t, v4_0_7.PythonRevisionUpgradeEntries(), 9) } -type scopedTxn struct { - executor.TxnExecutor - t *testing.T - accountID uint32 -} - -func (txn scopedTxn) Exec(sql string, options executor.StatementOption) (executor.Result, error) { - if sql != "SELECT mo_ctl('cn', 'GetProtocolVersion', '')" { - require.True(txn.t, options.HasAccountID()) - require.Equal(txn.t, txn.accountID, options.AccountID()) - } - return txn.TxnExecutor.Exec(sql, options) -} - -func TestCharacterSetsUpgradeAdmissionAndRetry(t *testing.T) { - entry := refreshInformationSchemaCharacterSets() - const protocolSQL = "SELECT mo_ctl('cn', 'GetProtocolVersion', '')" - checkSQL := sysview.InformationSchemaCharacterSetsCheckSQL() - injected := errors.New("injected charset metadata upgrade failure") - for _, tc := range []struct { - name string - ready bool - protocol string - failSQL string - wantErr bool - wantSQL []string +func TestPythonRevisionRepairIsIdempotentForPersisted407And408(t *testing.T) { + for _, test := range []struct { + name string + persistedVersion string + columns []string + newIndex bool + legacyIndex bool + revisionTable bool + wantFirstDDL int }{ - {name: "legacy utf8 maxlen three", protocol: `{"result":"cn0:106,cn1:106"}`, - wantSQL: []string{checkSQL, protocolSQL, entry.PreSql, entry.UpgSql}}, - {name: "fresh canonical catalog", ready: true, wantSQL: []string{checkSQL}}, - {name: "failed check", failSQL: checkSQL, wantErr: true, wantSQL: []string{checkSQL}}, - {name: "mixed protocol", protocol: `{"result":"cn0:106,cn1:105"}`, wantErr: true, - wantSQL: []string{checkSQL, protocolSQL}}, - {name: "failed protocol", failSQL: protocolSQL, wantErr: true, - wantSQL: []string{checkSQL, protocolSQL}}, - {name: "failed delete", protocol: `{"result":"cn0:106"}`, failSQL: entry.PreSql, wantErr: true, - wantSQL: []string{checkSQL, protocolSQL, entry.PreSql}}, - {name: "failed insert", protocol: `{"result":"cn0:106"}`, failSQL: entry.UpgSql, wantErr: true, - wantSQL: []string{checkSQL, protocolSQL, entry.PreSql, entry.UpgSql}}, + { + name: "persisted_4.0.7_missed_catalog", + persistedVersion: "4.0.7", + legacyIndex: true, + wantFirstDDL: 9, + }, + { + name: "persisted_4.0.8_partial_catalog", + persistedVersion: "4.0.8", + columns: []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + }, + legacyIndex: true, + wantFirstDDL: 3, + }, + { + name: "persisted_4.0.8_complete_catalog", + persistedVersion: "4.0.8", + columns: []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + }, + newIndex: true, + revisionTable: true, + wantFirstDDL: 0, + }, } { - t.Run(tc.name, func(t *testing.T) { + t.Run(test.name, func(t *testing.T) { runtime.RunTest("", func(runtime.Runtime) { - operator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) - operator.EXPECT().TxnOptions().Return(pbtxn.TxnOptions{}).AnyTimes() - mp := mpool.MustNewZero() - defer func() { - require.Zero(t, mp.CurrNB()) - mpool.DeleteMPool(mp) - }() - result := func(value string) executor.Result { - r := executor.NewMemResult([]types.Type{types.T_varchar.ToType()}, mp) - if value != "" { - r.NewBatchWithRowCount(1) - require.NoError(t, executor.AppendStringRows(r, 0, []string{value})) - } - return r.GetResult() + state := &pythonRevisionCatalogState{ + columns: make(map[string]bool), + newIndex: test.newIndex, + legacyIndex: test.legacyIndex, + revisionTable: test.revisionTable, } - var calls []string - ready := tc.ready - failSQL := tc.failSQL - protocol := tc.protocol - txn := scopedTxn{t: t, accountID: 7, TxnExecutor: executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { - calls = append(calls, sql) - if sql == failSQL { - return executor.Result{}, injected - } - switch sql { - case checkSQL: - if ready { - return result("1"), nil - } - return result(""), nil - case protocolSQL: - return result(protocol), nil - case entry.PreSql: - ready = false - case entry.UpgSql: - ready = true - default: - t.Fatalf("unexpected SQL: %s", sql) - } - return executor.Result{}, nil - }, operator)} - require.NoError(t, Handler.Prepare(t.Context(), txn, true)) - require.NoError(t, Handler.HandleClusterUpgrade(t.Context(), txn)) - require.Error(t, Handler.HandleCreateFrameworkDeps(txn)) - err := Handler.HandleTenantUpgrade(t.Context(), 7, txn) - if tc.failSQL != "" { - require.ErrorIs(t, err, injected) - } else if tc.wantErr { - require.Error(t, err) - } else { - require.NoError(t, err) - } - require.Equal(t, tc.wantSQL, calls) - if tc.wantErr { - // The owner transaction rolls back failed entries. On retry the - // handler must execute the repair, not treat MAXLEN=3 as ready. - ready, failSQL, protocol = false, "", `{"result":"cn0:106"}` - calls = nil - require.NoError(t, Handler.HandleTenantUpgrade(t.Context(), 7, txn)) - require.Equal(t, []string{checkSQL, protocolSQL, entry.PreSql, entry.UpgSql}, calls) + for _, column := range test.columns { + state.columns[column] = true } - calls = nil - require.NoError(t, Handler.HandleTenantUpgrade(t.Context(), 7, txn)) - require.Equal(t, []string{checkSQL}, calls, "a completed refresh must be idempotent") + txn := newRepairTxnExecutor(t, state) + require.NoError(t, Handler.Prepare(context.Background(), txn, true)) + require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) + require.Len(t, state.ddl, test.wantFirstDDL, + "repair from persisted %s must apply only missing catalog objects", test.persistedVersion) + firstDDL := append([]string(nil), state.ddl...) + require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) + require.Equal(t, firstDDL, state.ddl, + "a restart/retry from persisted %s must not repeat DDL", test.persistedVersion) }) }) } } + +type pythonRevisionCatalogState struct { + columns map[string]bool + newIndex bool + legacyIndex bool + revisionTable bool + ddl []string +} + +func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) executor.TxnExecutor { + t.Helper() + txnOperator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) + txnOperator.EXPECT().TxnOptions().Return(txn.TxnOptions{}).AnyTimes() + return executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { + lower := strings.ToLower(sql) + switch { + case strings.Contains(lower, "from mo_catalog.mo_columns"): + for column := range state.columns { + if strings.Contains(sql, fmt.Sprintf("attname = '%s'", column)) { + return repairColumnResult(t), nil + } + } + return executor.Result{}, nil + case strings.Contains(lower, "from `mo_catalog`.`mo_indexes`"): + if strings.Contains(sql, "name_db_arg_types_descriptor") && state.newIndex { + return repairStringResult(t, "name_db_arg_types_descriptor"), nil + } + if strings.Contains(sql, "name_db_arg_types'") && state.legacyIndex { + return repairStringResult(t, "name_db_arg_types"), nil + } + return executor.Result{}, nil + case strings.Contains(lower, "from mo_catalog.mo_tables"): + if state.revisionTable && strings.Contains(sql, "relname = 'mo_function_revisions'") { + return repairStringResult(t, "mo_function_revisions"), nil + } + return executor.Result{}, nil + case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:107"}`), nil + case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): + for column := range state.columns { + if strings.Contains(sql, "add column "+column+" ") { + return executor.Result{}, nil + } + } + for _, column := range []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + } { + if strings.Contains(sql, "add column "+column+" ") { + state.columns[column] = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + } + } + case strings.Contains(lower, "create unique index name_db_arg_types_descriptor"): + state.newIndex = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + case strings.Contains(lower, "drop index name_db_arg_types"): + state.legacyIndex = false + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + case strings.Contains(lower, "create table mo_catalog.mo_function_revisions"): + state.revisionTable = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + default: + return executor.Result{}, fmt.Errorf("unexpected repair SQL: %s", sql) + } + return executor.Result{}, nil + }, txnOperator) +} + +func repairStringResult(t *testing.T, value string) executor.Result { + t.Helper() + mp := mpool.MustNewZeroNoFixed() + t.Cleanup(func() { mpool.DeleteMPool(mp) }) + result := executor.NewMemResult([]types.Type{types.T_varchar.ToType()}, mp) + result.NewBatchWithRowCount(1) + require.NoError(t, executor.AppendStringRows(result, 0, []string{value})) + return result.GetResult() +} + +func repairColumnResult(t *testing.T) executor.Result { + t.Helper() + mp := mpool.MustNewZeroNoFixed() + t.Cleanup(func() { mpool.DeleteMPool(mp) }) + result := executor.NewMemResult([]types.Type{ + types.T_varchar.ToType(), types.T_varchar.ToType(), + types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), + types.T_int32.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), + }, mp) + result.NewBatchWithRowCount(1) + require.NoError(t, executor.AppendStringRows(result, 0, []string{"BIGINT UNSIGNED"})) + require.NoError(t, executor.AppendStringRows(result, 1, []string{"NO"})) + require.NoError(t, executor.AppendFixedRows(result, 2, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 3, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 4, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 5, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 6, []int32{1})) + require.NoError(t, executor.AppendStringRows(result, 7, []string{"0"})) + require.NoError(t, executor.AppendStringRows(result, 8, []string{""})) + require.NoError(t, executor.AppendStringRows(result, 9, []string{""})) + return result.GetResult() +} diff --git a/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go b/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go index b74bda45cab1c..4327ce0666de1 100644 --- a/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go +++ b/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go @@ -74,6 +74,13 @@ var tenantUpgEntries = []versions.UpgradeEntry{ }, } +// PythonRevisionUpgradeEntries returns the idempotent shared-routine catalog +// migrations so a later repair version can replay them for clusters that +// already recorded 4.0.7 or 4.0.8 without executing the original handler. +func PythonRevisionUpgradeEntries() []versions.UpgradeEntry { + return append([]versions.UpgradeEntry(nil), tenantUpgEntries...) +} + // addPythonSignatureIndex makes the shared function namespace distinguish the // exact current Python descriptor while preserving the historical logical // arg_types column for SQL UDFs and catalog readers. diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index e9eeec15b8d01..e8770090fff30 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -11791,6 +11791,12 @@ func Upload(ses FeSession, execCtx *ExecCtx, localPath string, storageDir string } func ensurePythonUdfCatalogReady(ctx context.Context, bh BackgroundExec) error { + if !sharedRoutineRevisionProtocolReady(bh.Service()) { + return moerr.NewNotSupportedNoCtxf( + "Python UDF catalog contract requires MORPC protocol version %d", + sharedRoutineRevisionProtocolVersion, + ) + } probes := []struct { query string expectedCols uint64 @@ -11831,11 +11837,20 @@ func ensurePythonUdfCatalogReady(ctx context.Context, bh BackgroundExec) error { return nil } +const sharedRoutineRevisionProtocolVersion = defines.MORPCVersion107 + +// sharedRoutineRevisionProtocolReady reports whether the deployment has +// reached the protocol floor at which every live CN understands the shared +// routine revision writer/reader contract. The protocol value is the active +// rollout floor, not merely the binary's compiled-in maximum. +func sharedRoutineRevisionProtocolReady(service string) bool { + return currentProtocolVersionForService(service) >= sharedRoutineRevisionProtocolVersion +} + // functionRevisionCatalogAvailable reports whether the current shared -// revision table can be used by the SQL UDF writer. Ordinary SQL UDFs remain -// writable during a rolling upgrade before v4_0_7 reaches every tenant; once -// the table is present, revision publication is part of the same caller-owned -// transaction as the legacy compatibility row. +// revision table exists. Ordinary SQL UDFs remain writable during a rolling +// upgrade before v4_0_7 reaches every tenant; revision publication is enabled +// only after both the table and the shared routine protocol floor are ready. func functionRevisionCatalogAvailable(ctx context.Context, bh BackgroundExec) (bool, error) { bh.ClearExecResultSet() if err := bh.Exec(ctx, functionRevisionCatalogSchemaCheck); err != nil { @@ -12525,6 +12540,19 @@ func persistUserDefinedFunction( if readErr != nil { return readErr } + if (previousRevision == 0) != (previousNamespace == 0) { + return moerr.NewInvalidInputNoCtxf( + "UNSUPPORTED_ROUTINE_VERSION: function identity %d has an invalid revision head", + *functionID, + ) + } + if (previousRevision != 0 || previousNamespace != 0) && + !sharedRoutineRevisionProtocolReady(bh.Service()) { + return moerr.NewNotSupportedNoCtxf( + "SQL UDF revision replacement requires MORPC protocol version %d", + sharedRoutineRevisionProtocolVersion, + ) + } previousReturnType, returnErr := readUserDefinedFunctionReturnType(ctx, bh, *functionID) if returnErr != nil { return returnErr @@ -12553,7 +12581,7 @@ func persistUserDefinedFunction( } return activateFunctionRevision(ctx, bh, *functionID, nextRevision, nextNamespace) } - if !revisionCatalogReady { + if !revisionCatalogReady || !sharedRoutineRevisionProtocolReady(bh.Service()) { return nil } nextRevision := previousRevision + 1 @@ -12614,7 +12642,7 @@ func persistUserDefinedFunction( } return activateFunctionRevision(ctx, bh, functionIDValue, 1, 1) } - if !revisionCatalogReady { + if !revisionCatalogReady || !sharedRoutineRevisionProtocolReady(bh.Service()) { return nil } functionIDValue, err := findPersistedSQLFunctionID(ctx, bh, definition) diff --git a/pkg/frontend/compiler_context.go b/pkg/frontend/compiler_context.go index 82fa672334591..0f20a334c5711 100644 --- a/pkg/frontend/compiler_context.go +++ b/pkg/frontend/compiler_context.go @@ -1258,16 +1258,25 @@ type sqlRevisionCatalogRow struct { } // readSQLRevision resolves the current shared revision head without making a -// legacy SQL row look current. A missing v4_0_7 table/column is reported as -// found=false so ordinary SQL remains available during a rolling upgrade; -// once a head is published, every missing or malformed revision is a hard -// catalog error. +// legacy SQL row look current. Below the shared revision protocol floor it +// returns found=false so the caller keeps using the legacy compatibility row; +// this is the explicit mixed-writer contract during a rolling upgrade. Once +// the floor is active, a missing v4_0_7 table/column is reported as found=false +// for ordinary SQL compatibility, while every non-zero head with a missing or +// malformed revision is a hard catalog error. func readSQLRevision( ctx context.Context, bh BackgroundExec, functionID int64, snapshot *plan2.Snapshot, ) (sqlRevisionCatalogRow, bool, error) { + if !sharedRoutineRevisionProtocolReady(bh.Service()) { + // During the rolling upgrade the legacy row is the only shared-writer + // contract. ResolveUdf already loaded that row, so returning found=false + // keeps old writers and new readers on the same body until every CN has + // reached the revision-aware protocol floor. + return sqlRevisionCatalogRow{}, false, nil + } baseTable := "mo_catalog.mo_user_defined_function" revisionTable := "mo_catalog.mo_function_revisions" if snapshot != nil && snapshot.TS != nil { @@ -1403,6 +1412,12 @@ func readSQLRevision( } func readPythonRevision(ctx context.Context, bh BackgroundExec, functionID int64, snapshot *plan2.Snapshot) (pythonRevisionCatalogRow, error) { + if !sharedRoutineRevisionProtocolReady(bh.Service()) { + return pythonRevisionCatalogRow{}, udferr.Newf( + "UNSUPPORTED_ROUTINE_VERSION: Python UDF revision contract requires MORPC protocol version %d", + sharedRoutineRevisionProtocolVersion, + ) + } bh.ClearExecResultSet() query := pythonRevisionCatalogSQL(snapshot, functionID) if err := bh.Exec(ctx, query); err != nil { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 849e7bdc85ec0..f40d88955826f 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -26,6 +26,7 @@ import ( "github.com/golang/mock/gomock" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" + moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/matrixorigin/matrixone/pkg/config" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -521,6 +522,97 @@ func TestPersistSQLCreateKeepsRollingCatalogCompatibility(t *testing.T) { require.NotContains(t, bh.executedSqls[1], "mo_function_revisions") } +func setSharedRoutineRevisionProtocolForTest(t *testing.T, version int64) { + t.Helper() + rt := moruntime.ServiceRuntime("") + previous, hadPrevious := rt.GetGlobalVariables(moruntime.MOProtocolVersion) + t.Cleanup(func() { + if hadPrevious { + rt.SetGlobalVariables(moruntime.MOProtocolVersion, previous) + } else { + rt.CompareAndDeleteGlobalVariables(moruntime.MOProtocolVersion, version) + } + }) + rt.SetGlobalVariables(moruntime.MOProtocolVersion, version) +} + +func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T) { + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion106) + + create := &backgroundExecTestWithHistory{} + create.init() + create.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) + err := persistUserDefinedFunction(context.Background(), create, &TenantInfo{User: "owner"}, 7, userDefinedFunctionDefinition{ + name: "legacy_until_ready", + args: `[{"name":"value","type":"bigint"}]`, + argTypes: `["bigint"]`, + retType: "bigint", + body: "select value + 1", + lang: string(tree.SQL), + dbName: "db1", + }, nil) + require.NoError(t, err) + require.Len(t, create.executedSqls, 2) + require.NotContains(t, create.executedSqls[1], "mo_function_revisions") + + functionID := int64(92) + replace := &backgroundExecTestWithHistory{} + replace.init() + replace.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) + replace.sql2result[fmt.Sprintf( + "select language from mo_catalog.mo_user_defined_function where function_id = %d;", functionID, + )] = singleStringResult("language", string(tree.SQL)) + replace.sql2result[fmt.Sprintf( + "select active_revision, namespace_version from mo_catalog.mo_user_defined_function where function_id = %d;", functionID, + )] = func() *MysqlResultSet { + result := &MysqlResultSet{} + for _, name := range []string{"active_revision", "namespace_version"} { + column := &MysqlColumn{} + column.SetName(name) + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + result.AddColumn(column) + } + result.AddRow([]interface{}{int64(1), int64(1)}) + return result + }() + err = persistUserDefinedFunction(context.Background(), replace, &TenantInfo{User: "owner"}, 7, userDefinedFunctionDefinition{ + name: "legacy_until_ready", + args: `[{"name":"value","type":"bigint"}]`, + argTypes: `["bigint"]`, + retType: "bigint", + body: "select value + 2", + lang: string(tree.SQL), + dbName: "db1", + }, &functionID) + require.ErrorContains(t, err, "SQL UDF revision replacement requires MORPC protocol version 107") + for _, sql := range replace.executedSqls { + require.NotContains(t, sql, "update mo_catalog.mo_user_defined_function") + } +} + +func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion106) + + background := &backgroundExecTestWithHistory{} + background.init() + got, found, err := readSQLRevision(context.Background(), background, 92, nil) + require.NoError(t, err) + require.False(t, found) + require.Equal(t, sqlRevisionCatalogRow{}, got) + require.Empty(t, background.executedSqls, + "ResolveUdf keeps the already-read legacy compatibility row while the shared revision contract is gated") +} + +func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion106) + + background := &backgroundExecTestWithHistory{} + background.init() + err := ensurePythonUdfCatalogReady(context.Background(), background) + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 107") + require.Empty(t, background.executedSqls) +} + func TestFunctionRevisionCatalogAvailablePropagatesMalformedProbeResult(t *testing.T) { bh := &backgroundExecTest{} bh.init() diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 202fe94d4b43e..1531a5423b027 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion72, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion107, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 2b4acc3771cf0..f41319ffe15c0 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,6 +37,10 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } +func TestGetPythonUdfStatusRequiresProtocolVersion107(t *testing.T) { + assert.Equal(t, defines.MORPCVersion107, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +} + // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. func TestRefreshSessionAuthRequiresProtocolVersion54(t *testing.T) { // A method's entry in methodVersions records the protocol it SHIPPED with, not whatever is From da24ce6ea638c6d13fe8227b3220dbe80a05153a Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 6 Oct 2026 12:48:13 +0800 Subject: [PATCH 204/241] fix(udf): close catalog and execution protocol admission --- docs/design/python_udf_current_stage.md | 53 +++++++----- .../python_udf_current_stage_approval.md | 18 ++++- pkg/bootstrap/versions/v4_0_12/upgrade.go | 12 ++- .../versions/v4_0_12/upgrade_test.go | 36 ++++----- pkg/frontend/authenticate.go | 11 ++- pkg/frontend/python_udf_catalog_test.go | 80 +++++++++++-------- pkg/frontend/routine_namespace_test.go | 2 + pkg/frontend/routine_plan_validation.go | 13 +++ pkg/frontend/routine_plan_validation_test.go | 28 +++++++ pkg/pb/plan/string_literal_form.go | 4 +- pkg/sql/colexec/external_routine_eval.go | 6 ++ pkg/sql/colexec/external_routine_eval_test.go | 30 +++++++ .../expression_destination_protocol.go | 3 + pkg/sql/compile/expression_protocol.go | 3 + pkg/sql/compile/expression_protocol_test.go | 25 ++++++ pkg/sql/compile/remoterun.go | 3 + pkg/udf/python_contract.go | 21 ++++- pkg/udf/testdata/python_status_wire.json | 20 ++--- 18 files changed, 270 insertions(+), 98 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 170a6705db11b..b13e8dce53cc9 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,13 +2,15 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r2-2026-09-25` | +| Design revision | `python-udf-current-stage-r3-2026-10-05` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Implementation baseline reviewed | `9847da80d6c7096cb0460e46a5cf710e10714af3a` | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). This r2 addendum is a conservative mixed-version safety repair: it narrows revision admission and adds no production or security scope. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `856e9ddbdd69b52d18f727c763ecd963e66644de` (MORPC 106, catalog 4.0.11) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r3 repair adds catalog 4.0.12 and protocol 107 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | -This is the approved governing contract for the current PR stage. It consolidates +This is the versioned governing proposal for the current PR stage. The owner +approved the historical r1 scope; that approval is not independent technical +approval of this revised contract. It consolidates the shared Catalog, SQL/planner, Python ABI, Flight, and resource-lifecycle decisions needed to review this implementation. It does not approve future sandbox or production deployment. The test/development scope is explicit: @@ -68,7 +70,7 @@ revision or takes source from an executable plan. The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The -revision-aware writer and reader contract is admitted only at the active common +revision-aware writer and reader contract is admitted only at the active service-runtime MORPC protocol floor `107` (`latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing @@ -82,22 +84,35 @@ never silently repaired or synthesized. The SQL UDF language, body, security, and evaluation semantics remain owned by the existing SQL path. The Python demo's old execution behavior is not a compatibility promise. -Upgrade `4.0.7` (minimum source `4.0.6`) changes the shared function identity -columns/index and creates `mo_function_revisions`. The upgrade handler is gated -on common MORPC protocol 61 so a tenant migration does not widen catalog tables -while an old writer can still serve them. Python DDL independently probes the -required tenant schema and refuses creation/replacement until it is present; -shared revision publication and Python revision reads additionally require the -common protocol floor 107. The read-only `GetPythonUdfStatus` query method uses -the same new wire capability. Worker capability negotiation is a separate -exact-contract gate. This is feature-level admission, not a requirement that -every component have the same software version string. +Upgrade `4.0.7` contains the original idempotent shared-function schema entries. +Its historical protocol-61 requirement belongs to the already-shipped provenance +contract; it does not prove Python revision capability. The registered repair +`4.0.12` (minimum direct source `4.0.11`) replays only the nine shared-function +entries. Upstream handlers `4.0.8` through `4.0.11` remain unchanged. Thus a tenant +already at upstream final `4.0.11`, including one lacking revision tables, still +receives the repair; earlier tenants traverse the normal chain first. Missing, +partial and complete schemas converge through idempotent checks. Repair metadata +requires protocol 107 before tenant tasks are created; `Prepare` only selects +`mo_catalog` and performs no DDL. + +Python DDL probes the required tenant schema and refuses admission until it is +present. Shared revision publication and Python reads require active protocol +107. That value is rollout state in the service runtime, not a computed live +cluster minimum. Cached/prepared Python plans and new or reused physical +evaluators check it again before catalog reads, input evaluation or worker calls. +Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy +row. Sender admission also probes the actual remote CN endpoint, and the receiver +checks its own active protocol; coordinator state alone cannot admit an old +receiver. Missing or malformed protocol state fails closed. The read-only +`GetPythonUdfStatus` method uses wire capability 107. Worker capability negotiation +remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, columns, or index, and do not claim that restoring an old binary restores Python execution. Binary rollback after applying this catalog migration is not a -supported recovery path in this contract; ordinary SQL behavior in that mixed -state has not been verified here. Python definitions must remain intact and +supported recovery path in this contract; the predecessor-floor tests exercise controlled transitions in current binaries, +not unrestricted rollback to old binaries. An old binary cannot obey the new +nonzero-head replacement guard, so arbitrary old-writer rollback is unsupported. Python definitions must remain intact and require a current-contract binary to execute. The current evidence does not include a tested downgrade after Python definitions have been written. The upgrade-compatibility CI checks were skipped on the reviewed exact head. @@ -229,12 +244,12 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-107 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_7/upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go` | Unit/schema contract, immediate-predecessor rollback gate, and old-writer/new-reader legacy-row contract covered; upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-107 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_12/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases; real persisted-service upgrade and downgrade are not verified by those mocks. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | | Flight state, ACK, cancellation, resource limits | `pkg/udf/python/gateway_test.go`, `gateway_admission_test.go`, `capability_lifecycle_test.go`, `gateway_integration_test.go`, `pkg/udf/python/worker/test_worker.py`, `test_watchdog.py` | Unit, process, and real Flight cases present; this design does not substitute for implementation/lifecycle review. | -| Historical CI at the reviewed implementation baseline | PR #29152 baseline `9847da80d6c7096cb0460e46a5cf710e10714af3a`; [MatrixOne ALL CI run 35953275189](https://github.com/matrixorigin/matrixone/actions/runs/35953275189) passed | Exact-head run 35988821412 is tracked separately; its UT coverage producer failed, so it is not passing coverage evidence. Upgrade-compatibility checks skipped; no downgrade evidence. | +| Historical CI at the reviewed implementation baseline | PR #29152 baseline `9847da80d6c7096cb0460e46a5cf710e9714af3a`; [MatrixOne ALL CI run 35953275189](https://github.com/matrixorigin/matrixone/actions/runs/35953275189) passed | Exact-head run 35988821412 is tracked separately; its UT coverage producer failed, so it is not passing coverage evidence. Upgrade-compatibility checks skipped; no downgrade evidence. | The reviewed change is not declared production-ready. Artifact GC/total-storage quota, cross-version migration rollback/restore, authenticated transport, and diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index ae17966108032..e7462d161deec 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage contract | [`python-udf-current-stage-r1-2026-09-24`](python_udf_current_stage.md) | +| Current-stage proposal | [`python-udf-current-stage-r3-2026-10-05`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -32,13 +32,13 @@ The pre-rebase exact review head was [`92a89d81588159a918458b1a930bccc9d0e75d4b`](https://github.com/matrixorigin/matrixone/commit/92a89d81588159a918458b1a930bccc9d0e75d4b). The repair commit carrying this record is the final documentation commit on top of the rebased PR history; its exact remote head is verified at delivery. -The final current-stage design blob is +The historical r1 design blob delivered with the approval-record link was `994b8016729d2e87a6a706a2833eee7faf50c89b`; its only difference from the approved design blob is the link to this traceability record. The namespace-validation companion is the implementation contract from commit [`284a1d971a1d2c763c6aed425d52f751735c409f`](https://github.com/matrixorigin/matrixone/commit/284a1d971a1d2c763c6aed425d52f751735c409f), -with current-head blob `51ccfb771db19321d03b292cd3d7219f698a11b8`. +with historical recorded blob `51ccfb771db19321d03b292cd3d7219f698a11b8`. ## Approval ledger @@ -65,3 +65,15 @@ skipped at the recorded head; cross-version rollback/restore is unsupported in this stage. Those gaps are recorded as limits and are not represented as passing approval evidence. Full implementation/lifecycle review remains a separate PR review step after the design record is accepted by the relevant reviewers. + +## r3 maintenance addendum (2026-10-05) + +The current document proposes protocol 107 and repair catalog 4.0.12 against +upstream `856e9ddbdd69b52d18f727c763ecd963e66644de`. It adds explicit sender, +receiver, prepared-reuse and physical execution admission, and schedules repair +for a tenant already at upstream-final 4.0.11. These are conservative corrections +within the opt-in development scope. The immutable r1 blobs above describe that +historical approval only; they are not the current proposal's content identity. +Architecture and SQL/Planner approval remain pending, as recorded in reviews +5302243148 and the exact-head review on 4ca229411166b9da09a702dbe1b799de43d8d694. +Code review and passing tests do not substitute for those independent decisions. diff --git a/pkg/bootstrap/versions/v4_0_12/upgrade.go b/pkg/bootstrap/versions/v4_0_12/upgrade.go index 819fe8515e7cb..a40b5e92bef2f 100644 --- a/pkg/bootstrap/versions/v4_0_12/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_12/upgrade.go @@ -28,13 +28,11 @@ import ( "go.uber.org/zap" ) -// 4.0.12 is a repair version, not a new schema contract. Some clusters have -// already persisted 4.0.7 or 4.0.8 while an older upgrade worker skipped the -// shared Python UDF catalog entries. A new semantic version is required so -// those clusters cannot finish the task with the old, empty handler. The -// entries are the original idempotent checks, so a normal 4.0.6 -> 4.0.7 -> -// 4.0.8 -> 4.0.12 upgrade and a repair of an existing 4.0.8 cluster converge -// on the same catalog state. +// 4.0.12 replays only the idempotent shared Python UDF catalog entries. +// An upstream-final 4.0.11 tenant may lack these entries; a strictly newer +// registered handler ensures the upgrade framework schedules their repair. +// Earlier tenants first traverse the unchanged upstream handlers through +// 4.0.11. Complete, partial and absent revision schemas converge on retry. var Handler = &versionHandle{ metadata: versions.Version{ Version: "4.0.12", diff --git a/pkg/bootstrap/versions/v4_0_12/upgrade_test.go b/pkg/bootstrap/versions/v4_0_12/upgrade_test.go index 68673d9998e54..55ad7dd646cde 100644 --- a/pkg/bootstrap/versions/v4_0_12/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_12/upgrade_test.go @@ -45,25 +45,25 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Len(t, v4_0_7.PythonRevisionUpgradeEntries(), 9) } -func TestPythonRevisionRepairIsIdempotentForPersisted407And408(t *testing.T) { +func TestPythonRevisionRepairIsIdempotentForCatalogStates(t *testing.T) { for _, test := range []struct { - name string - persistedVersion string - columns []string - newIndex bool - legacyIndex bool - revisionTable bool - wantFirstDDL int + name string + schemaOrigin string + columns []string + newIndex bool + legacyIndex bool + revisionTable bool + wantFirstDDL int }{ { - name: "persisted_4.0.7_missed_catalog", - persistedVersion: "4.0.7", - legacyIndex: true, - wantFirstDDL: 9, + name: "upstream_final_4.0.11_missed_catalog", + schemaOrigin: "4.0.11", + legacyIndex: true, + wantFirstDDL: 9, }, { - name: "persisted_4.0.8_partial_catalog", - persistedVersion: "4.0.8", + name: "partial_revision_catalog", + schemaOrigin: "4.0.8", columns: []string{ "active_revision", "namespace_version", "canonical_input_descriptor", "return_descriptor", "signature_key_schema_version", "signature_fingerprint", @@ -72,8 +72,8 @@ func TestPythonRevisionRepairIsIdempotentForPersisted407And408(t *testing.T) { wantFirstDDL: 3, }, { - name: "persisted_4.0.8_complete_catalog", - persistedVersion: "4.0.8", + name: "complete_revision_catalog", + schemaOrigin: "4.0.8", columns: []string{ "active_revision", "namespace_version", "canonical_input_descriptor", "return_descriptor", "signature_key_schema_version", "signature_fingerprint", @@ -98,11 +98,11 @@ func TestPythonRevisionRepairIsIdempotentForPersisted407And408(t *testing.T) { require.NoError(t, Handler.Prepare(context.Background(), txn, true)) require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) require.Len(t, state.ddl, test.wantFirstDDL, - "repair from persisted %s must apply only missing catalog objects", test.persistedVersion) + "repair of %s schema must apply only missing catalog objects", test.schemaOrigin) firstDDL := append([]string(nil), state.ddl...) require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) require.Equal(t, firstDDL, state.ddl, - "a restart/retry from persisted %s must not repeat DDL", test.persistedVersion) + "a restart/retry of %s schema must not repeat DDL", test.schemaOrigin) }) }) } diff --git a/pkg/frontend/authenticate.go b/pkg/frontend/authenticate.go index e8770090fff30..e50c489bff483 100644 --- a/pkg/frontend/authenticate.go +++ b/pkg/frontend/authenticate.go @@ -11837,14 +11837,13 @@ func ensurePythonUdfCatalogReady(ctx context.Context, bh BackgroundExec) error { return nil } -const sharedRoutineRevisionProtocolVersion = defines.MORPCVersion107 +const sharedRoutineRevisionProtocolVersion = udf.SharedRoutineRevisionProtocolVersion -// sharedRoutineRevisionProtocolReady reports whether the deployment has -// reached the protocol floor at which every live CN understands the shared -// routine revision writer/reader contract. The protocol value is the active -// rollout floor, not merely the binary's compiled-in maximum. +// sharedRoutineRevisionProtocolReady reads this service's active rollout +// floor, not its compiled-in maximum or a live cluster minimum. Remote +// dispatch independently probes its actual destination and the receiver. func sharedRoutineRevisionProtocolReady(service string) bool { - return currentProtocolVersionForService(service) >= sharedRoutineRevisionProtocolVersion + return udf.SharedRoutineRevisionProtocolReady(service) } // functionRevisionCatalogAvailable reports whether the current shared diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index f40d88955826f..f4cfb37ad87fe 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -555,38 +555,54 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T require.Len(t, create.executedSqls, 2) require.NotContains(t, create.executedSqls[1], "mo_function_revisions") - functionID := int64(92) - replace := &backgroundExecTestWithHistory{} - replace.init() - replace.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) - replace.sql2result[fmt.Sprintf( - "select language from mo_catalog.mo_user_defined_function where function_id = %d;", functionID, - )] = singleStringResult("language", string(tree.SQL)) - replace.sql2result[fmt.Sprintf( - "select active_revision, namespace_version from mo_catalog.mo_user_defined_function where function_id = %d;", functionID, - )] = func() *MysqlResultSet { - result := &MysqlResultSet{} - for _, name := range []string{"active_revision", "namespace_version"} { - column := &MysqlColumn{} - column.SetName(name) - column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) - result.AddColumn(column) - } - result.AddRow([]interface{}{int64(1), int64(1)}) - return result - }() - err = persistUserDefinedFunction(context.Background(), replace, &TenantInfo{User: "owner"}, 7, userDefinedFunctionDefinition{ - name: "legacy_until_ready", - args: `[{"name":"value","type":"bigint"}]`, - argTypes: `["bigint"]`, - retType: "bigint", - body: "select value + 2", - lang: string(tree.SQL), - dbName: "db1", - }, &functionID) - require.ErrorContains(t, err, "SQL UDF revision replacement requires MORPC protocol version 107") - for _, sql := range replace.executedSqls { - require.NotContains(t, sql, "update mo_catalog.mo_user_defined_function") + for _, test := range []struct { + name string + revision, namespace int64 + wantError string + }{ + {name: "legacy_zero_head"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 107"}, + {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, + {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, + } { + t.Run(test.name, func(t *testing.T) { + functionID := int64(92) + replace := &backgroundExecTestWithHistory{} + replace.init() + replace.sql2result[functionRevisionCatalogSchemaCheck] = emptyCatalogProbeResult(20) + replace.sql2result[fmt.Sprintf("select language from mo_catalog.mo_user_defined_function where function_id = %d;", functionID)] = singleStringResult("language", string(tree.SQL)) + replace.sql2result[fmt.Sprintf("select rettype from mo_catalog.mo_user_defined_function where function_id = %d;", functionID)] = singleStringResult("rettype", "bigint") + result := &MysqlResultSet{} + for _, name := range []string{"active_revision", "namespace_version"} { + column := &MysqlColumn{} + column.SetName(name) + column.SetColumnType(defines.MYSQL_TYPE_LONGLONG) + result.AddColumn(column) + } + result.AddRow([]interface{}{test.revision, test.namespace}) + replace.sql2result[fmt.Sprintf("select active_revision, namespace_version from mo_catalog.mo_user_defined_function where function_id = %d;", functionID)] = result + err := persistUserDefinedFunction(context.Background(), replace, &TenantInfo{User: "owner"}, 7, userDefinedFunctionDefinition{ + name: "legacy_until_ready", args: `[{"name":"value","type":"bigint"}]`, + argTypes: `["bigint"]`, retType: "bigint", body: "select value + 2", lang: string(tree.SQL), dbName: "db1", + }, &functionID) + if test.wantError != "" { + require.ErrorContains(t, err, test.wantError) + } else { + require.NoError(t, err) + } + var updates int + for _, sql := range replace.executedSqls { + require.NotContains(t, sql, "insert into mo_catalog.mo_function_revisions") + if strings.HasPrefix(sql, "update mo_catalog.mo_user_defined_function") { + updates++ + } + } + if test.wantError == "" { + require.Equal(t, 1, updates) + } else { + require.Zero(t, updates) + } + }) } } diff --git a/pkg/frontend/routine_namespace_test.go b/pkg/frontend/routine_namespace_test.go index 6b6478a36a89a..8806c9fdbe9ff 100644 --- a/pkg/frontend/routine_namespace_test.go +++ b/pkg/frontend/routine_namespace_test.go @@ -154,7 +154,9 @@ type namespaceValidationSession struct{ FeSession } func (*namespaceValidationSession) GetTxnCompileCtx() *TxnCompilerContext { return nil } func (*namespaceValidationSession) GetAccountId() uint32 { return 9 } +func (*namespaceValidationSession) GetService() string { return "" } func TestRoutinePlanWithoutNamespaceRebinds(t *testing.T) { + setSharedRoutineRevisionProtocolForTest(t, sharedRoutineRevisionProtocolVersion) dependency := testRoutinePlanDependency() dependency.NamespaceFingerprint = "" p := &planpb.Plan{Plan: &planpb.Plan_Query{Query: &planpb.Query{RoutineDependencies: []*planpb.RoutinePlanDependency{dependency}}}} diff --git a/pkg/frontend/routine_plan_validation.go b/pkg/frontend/routine_plan_validation.go index 7329e417a6a29..bb224ed4d5419 100644 --- a/pkg/frontend/routine_plan_validation.go +++ b/pkg/frontend/routine_plan_validation.go @@ -184,6 +184,19 @@ func validateRoutinePlanDependencies(ctx context.Context, ses FeSession, p *plan snapshot = tcc.GetSnapshot() } accountID := routineCatalogAccountID(ses.GetAccountId(), snapshot) + if !sharedRoutineRevisionProtocolReady(ses.GetService()) { + for _, dependency := range dependencies { + if err := validateRoutinePlanDependencyShape(dependency, accountID); err != nil { + return false, err + } + if dependency.Language == udf.LanguagePython { + return false, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python prepared execution requires MORPC protocol version %d", sharedRoutineRevisionProtocolVersion) + } + } + // Rebind revision-bearing SQL plans against the legacy compatibility + // row, which is the shared writer contract below the rollout floor. + return true, nil + } ids := make([]uint64, 0, len(dependencies)) seen := make(map[uint64]struct{}, len(dependencies)) for _, dependency := range dependencies { diff --git a/pkg/frontend/routine_plan_validation_test.go b/pkg/frontend/routine_plan_validation_test.go index 41d26bbfa2234..c01de5e2fa782 100644 --- a/pkg/frontend/routine_plan_validation_test.go +++ b/pkg/frontend/routine_plan_validation_test.go @@ -66,6 +66,8 @@ type routinePlanValidationSession struct { exec BackgroundExec } +func (s *routinePlanValidationSession) GetService() string { return "" } + func (s *routinePlanValidationSession) GetAccountId() uint32 { return 9 } func (s *routinePlanValidationSession) GetTxnCompileCtx() *TxnCompilerContext { return nil } @@ -310,6 +312,7 @@ func TestCachedRoutinePlanWithDependencyRequiresCatalogSession(t *testing.T) { } func TestValidateRoutinePlanDependenciesUsesCatalogTransactionAndFailsClosed(t *testing.T) { + setSharedRoutineRevisionProtocolForTest(t, sharedRoutineRevisionProtocolVersion) ctx := context.Background() plainPlan := &planpb.Plan{Plan: &planpb.Plan_Query{Query: &planpb.Query{}}} changed, err := validateRoutinePlanDependencies(ctx, nil, plainPlan) @@ -481,3 +484,28 @@ func TestRoutinePlanDependenciesVisitsSharedQueriesOnce(t *testing.T) { require.Len(t, dependencies, 1) require.Same(t, dependency, dependencies[0]) } + +func TestPreparedRoutinePlanRejectsProtocolRollbackBeforeCatalogRead(t *testing.T) { + setSharedRoutineRevisionProtocolForTest(t, sharedRoutineRevisionProtocolVersion-1) + for _, language := range []string{udf.LanguagePython, udf.LanguageSQL} { + t.Run(language, func(t *testing.T) { + dependency := testRoutinePlanDependency() + dependency.Language = language + if language == udf.LanguageSQL { + dependency.ArtifactDigest = "" + dependency.EnvironmentDigest = "" + } + p := &planpb.Plan{Plan: &planpb.Plan_Query{Query: &planpb.Query{RoutineDependencies: []*planpb.RoutinePlanDependency{dependency}}}} + exec := &routinePlanValidationExec{} + changed, err := validateRoutinePlanDependencies(context.Background(), &routinePlanValidationSession{exec: exec}, p) + if language == udf.LanguagePython { + require.ErrorContains(t, err, "Python prepared execution requires") + require.False(t, changed) + } else { + require.NoError(t, err) + require.True(t, changed) + } + require.Empty(t, exec.statements) + }) + } +} diff --git a/pkg/pb/plan/string_literal_form.go b/pkg/pb/plan/string_literal_form.go index 3ab80ed41a2f2..7001d6a934646 100644 --- a/pkg/pb/plan/string_literal_form.go +++ b/pkg/pb/plan/string_literal_form.go @@ -406,6 +406,7 @@ type RemoteExpressionFeatures struct { ScalarDivision bool // ViewMetadataFunctions requires v126 for MO_VIEW_DEFINITION/CHECK_OPTION. ViewMetadataFunctions bool + PythonRoutineContract bool JSONScalarLiteralContracts bool JSONInputContracts bool YearBitCast bool @@ -451,7 +452,7 @@ type RemoteExpressionFeatures struct { } func (features RemoteExpressionFeatures) Any() bool { - return features.LoadFKIgnoreCheck || features.DependentPrograms || features.CalendarIntervalNormalization || features.ViewMetadataFunctions || features.JSONScalarLiteralContracts || features.JSONInputContracts || features.YearBitCast || features.NumericPrefix || + return features.LoadFKIgnoreCheck || features.DependentPrograms || features.CalendarIntervalNormalization || features.ViewMetadataFunctions || features.PythonRoutineContract || features.JSONScalarLiteralContracts || features.JSONInputContracts || features.YearBitCast || features.NumericPrefix || features.JSONComparisonParam || features.MixedJSONBooleanEquality || features.FormatNumericArguments || @@ -943,6 +944,7 @@ func RequiredRemoteExpressionFeatures(owner any) (features RemoteExpressionFeatu } } fn := current.GetF() + features.PythonRoutineContract = features.PythonRoutineContract || (fn != nil && fn.RoutineCall != nil) if fn != nil && fn.Func != nil { id, overload := int32(fn.Func.Obj>>32), int32(fn.Func.Obj) if id == loadFKIgnoreCheckFunctionID { diff --git a/pkg/sql/colexec/external_routine_eval.go b/pkg/sql/colexec/external_routine_eval.go index 242dd13eb38d7..af8e6bc49a1e1 100644 --- a/pkg/sql/colexec/external_routine_eval.go +++ b/pkg/sql/colexec/external_routine_eval.go @@ -79,6 +79,9 @@ func newExternalRoutineEval( if err := validateRoutineCall(call); err != nil { return nil, err } + if !udf.SharedRoutineRevisionProtocolReady(proc.GetService()) { + return nil, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python execution requires MORPC protocol version %d", udf.SharedRoutineRevisionProtocolVersion) + } if len(call.ArgumentTypes) != len(parameters) { return nil, udferr.Newf("python udf: typed routine has %d argument descriptors but %d bound arguments", len(call.ArgumentTypes), len(parameters)) } @@ -204,6 +207,9 @@ func (e *ExternalRoutineEval) eval(proc *process.Process, batches []*batch.Batch if err := validateRoutineCall(e.call); err != nil { return nil, err } + if !udf.SharedRoutineRevisionProtocolReady(proc.GetService()) { + return nil, udferr.Newf("UNSUPPORTED_ROUTINE_VERSION: Python execution requires MORPC protocol version %d", udf.SharedRoutineRevisionProtocolVersion) + } accountID, err := defines.GetAccountId(proc.Ctx) if err != nil { return nil, err diff --git a/pkg/sql/colexec/external_routine_eval_test.go b/pkg/sql/colexec/external_routine_eval_test.go index d905cb55113ac..adf2e17d72c12 100644 --- a/pkg/sql/colexec/external_routine_eval_test.go +++ b/pkg/sql/colexec/external_routine_eval_test.go @@ -23,6 +23,7 @@ import ( "time" "github.com/matrixorigin/matrixone/pkg/common/mpool" + moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/matrixorigin/matrixone/pkg/container/batch" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -819,3 +820,32 @@ func TestExternalRoutineSkipsArgumentsForEmptySelection(t *testing.T) { }) } } + +func TestExternalRoutineEvalRejectsProtocolRollbackBeforeInputs(t *testing.T) { + proc := testutil.NewProcess(t) + defer proc.Free() + rt := moruntime.ServiceRuntime(proc.GetService()) + previous, present := rt.GetGlobalVariables(moruntime.MOProtocolVersion) + t.Cleanup(func() { + if present { + rt.SetGlobalVariables(moruntime.MOProtocolVersion, previous) + } else { + rt.CompareAndDeleteGlobalVariables(moruntime.MOProtocolVersion, udf.SharedRoutineRevisionProtocolVersion) + } + }) + rt.SetGlobalVariables(moruntime.MOProtocolVersion, udf.SharedRoutineRevisionProtocolVersion) + seen := 0 + evaluator, err := newExternalRoutineEval(proc, testExternalRoutineCall(t, "SCALAR", udf.NullCallHandler), []ExpressionExecutor{&externalRoutineTestExecutor{evalSeen: &seen}}, nil) + require.NoError(t, err) + defer evaluator.Free() + for _, version := range []any{udf.SharedRoutineRevisionProtocolVersion - 1, nil, "107"} { + rt.SetGlobalVariables(moruntime.MOProtocolVersion, version) + rejected, err := newExternalRoutineEval(proc, evaluator.call, evaluator.parameterExecutor, nil) + require.Nil(t, rejected) + require.ErrorContains(t, err, "Python execution requires") + _, err = evaluator.Eval(proc, nil, nil) + require.ErrorContains(t, err, "Python execution requires") + require.Zero(t, seen) + } + rt.SetGlobalVariables(moruntime.MOProtocolVersion, udf.SharedRoutineRevisionProtocolVersion) +} diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 858f4b81ee33a..599f03a53168f 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,6 +45,9 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, + {features.PythonRoutineContract, defines.MORPCVersion107, + "Python routine execution requires a versioned remote destination", + "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, "checked integer arithmetic requires a versioned remote destination", "remote destination does not support checked integer arithmetic (MORPC version %d)"}, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index a924be470ef9b..3a5af414ddf6e 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -84,6 +84,9 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int if features.TimestampDatetimeResultContracts || features.DynamicTimeResultContracts { required = max(required, defines.MORPCVersion122) } + if features.PythonRoutineContract { + required = max(required, defines.MORPCVersion107) + } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) } diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 6be9cfcf1132a..e562574298057 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -543,3 +543,28 @@ func TestRemoteExpressionDestinationUnknownEvidence(t *testing.T) { }) } } + +func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { + c, client := expressionProtocolTestCompile(t) + expr := &planpb.Expr{Expr: &planpb.Expr_F{F: &planpb.Function{RoutineCall: &planpb.RoutineCall{}}}} + p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr}}}} + features, err := planpb.RequiredRemoteExpressionFeatures(p) + require.NoError(t, err) + require.True(t, features.PythonRoutineContract) + require.Equal(t, defines.MORPCVersion107, remoteExpressionProtocolVersion(features)) + rt := moruntime.ServiceRuntime(c.proc.GetService()) + for _, version := range []int64{defines.MORPCVersion106, defines.MORPCVersion107} { + client.version = version + err := validateRemoteExpressionDestination(c.proc, p, features) + if version < defines.MORPCVersion107 { + require.ErrorContains(t, err, "remote destination does not support Python") + } else { + require.NoError(t, err) + } + } + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion106) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion107) + require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) + require.Equal(t, client.calls, client.releases) +} diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index c41001dd7bfa8..8958b4acb4dc8 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,6 +2335,9 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion107) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 107") + } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") } diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 60bfd4d12f679..1258d8b855fd1 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -20,14 +20,31 @@ import ( "encoding/hex" "fmt" + "github.com/matrixorigin/matrixone/pkg/common/runtime" + "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/udf/protocol" ) const ( - pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" - pythonEnvironmentDigestDomain = "matrixone-python-environment" + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion107 + pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" + pythonEnvironmentDigestDomain = "matrixone-python-environment" ) +// SharedRoutineRevisionProtocolReady checks this service's active rollout +// floor. Remote dispatch must also probe the destination; a local value does +// not prove that every live CN implements the contract. +func SharedRoutineRevisionProtocolReady(service string) bool { + rt := runtime.ServiceRuntime(service) + if rt == nil { + return false + } + value, present := rt.GetGlobalVariables(runtime.MOProtocolVersion) + version, valid := value.(int64) + return present && valid && version >= SharedRoutineRevisionProtocolVersion +} + // PythonInlineArtifactDigest identifies the exact source payload sent to the // worker. Length-prefixing each UTF-8 string prevents delimiter ambiguity and // gives the Python adapter an unambiguous, language-independent algorithm. diff --git a/pkg/udf/testdata/python_status_wire.json b/pkg/udf/testdata/python_status_wire.json index 6b35d431092a8..e0cbf0927428b 100644 --- a/pkg/udf/testdata/python_status_wire.json +++ b/pkg/udf/testdata/python_status_wire.json @@ -2,51 +2,51 @@ { "Class": "", "Reason": "CapabilityHandshakeReady", - "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICMQoEY24tMRIGcHl0aG9uGAEgASgBOhhDYXBhYmlsaXR5SGFuZHNoYWtlUmVhZHmwASo=" + "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDMQoEY24tMRIGcHl0aG9uGAEgASgBOhhDYXBhYmlsaXR5SGFuZHNoYWtlUmVhZHmwASo=" }, { "Class": "DISABLED", "Reason": "RuntimeDisabled", - "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICLgoEY24tMRIGcHl0aG9uIAEyCERJU0FCTEVEOg9SdW50aW1lRGlzYWJsZWSwASo=" + "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDLgoEY24tMRIGcHl0aG9uIAEyCERJU0FCTEVEOg9SdW50aW1lRGlzYWJsZWSwASo=" }, { "Class": "NOT_ALLOWED", "Reason": "UnisolatedExecutionNotAllowed", - "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICPwoEY24tMRIGcHl0aG9uGAEyC05PVF9BTExPV0VEOh1Vbmlzb2xhdGVkRXhlY3V0aW9uTm90QWxsb3dlZLABKg==" + "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDPwoEY24tMRIGcHl0aG9uGAEyC05PVF9BTExPV0VEOh1Vbmlzb2xhdGVkRXhlY3V0aW9uTm90QWxsb3dlZLABKg==" }, { "Class": "UNAVAILABLE", "Reason": "WorkerUnavailable", - "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICNQoEY24tMRIGcHl0aG9uGAEgATILVU5BVkFJTEFCTEU6EVdvcmtlclVuYXZhaWxhYmxlsAEq" + "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDNQoEY24tMRIGcHl0aG9uGAEgATILVU5BVkFJTEFCTEU6EVdvcmtlclVuYXZhaWxhYmxlsAEq" }, { "Class": "UNAVAILABLE", "Reason": "RuntimeStatusUnavailable", - "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICPAoEY24tMRIGcHl0aG9uGAEgATILVU5BVkFJTEFCTEU6GFJ1bnRpbWVTdGF0dXNVbmF2YWlsYWJsZbABKg==" + "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDPAoEY24tMRIGcHl0aG9uGAEgATILVU5BVkFJTEFCTEU6GFJ1bnRpbWVTdGF0dXNVbmF2YWlsYWJsZbABKg==" }, { "Class": "CONTRACT_MISMATCH", "Reason": "CapabilityContractMismatch", - "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICRAoEY24tMRIGcHl0aG9uGAEgATIRQ09OVFJBQ1RfTUlTTUFUQ0g6GkNhcGFiaWxpdHlDb250cmFjdE1pc21hdGNosAEq" + "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDRAoEY24tMRIGcHl0aG9uGAEgATIRQ09OVFJBQ1RfTUlTTUFUQ0g6GkNhcGFiaWxpdHlDb250cmFjdE1pc21hdGNosAEq" }, { "Class": "TIMEOUT", "Reason": "CapabilityRequestTimeout", - "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICOAoEY24tMRIGcHl0aG9uGAEgATIHVElNRU9VVDoYQ2FwYWJpbGl0eVJlcXVlc3RUaW1lb3V0sAEq" + "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDOAoEY24tMRIGcHl0aG9uGAEgATIHVElNRU9VVDoYQ2FwYWJpbGl0eVJlcXVlc3RUaW1lb3V0sAEq" }, { "Class": "CLOSED", "Reason": "RuntimeClosed", - "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICLAoEY24tMRIGcHl0aG9uGAEgATIGQ0xPU0VEOg1SdW50aW1lQ2xvc2VksAEq" + "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDLAoEY24tMRIGcHl0aG9uGAEgATIGQ0xPU0VEOg1SdW50aW1lQ2xvc2VksAEq" }, { "Class": "INVALID", "Reason": "InvalidLanguage", - "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICLwoEY24tMRIGcHl0aG9uGAEgATIHSU5WQUxJRDoPSW52YWxpZExhbmd1YWdlsAEq" + "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDLwoEY24tMRIGcHl0aG9uGAEgATIHSU5WQUxJRDoPSW52YWxpZExhbmd1YWdlsAEq" }, { "Class": "INTERNAL", "Reason": "RuntimeError", - "Wire": "CAcQKdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAOICLQoEY24tMRIGcHl0aG9uGAEgATIISU5URVJOQUw6DFJ1bnRpbWVFcnJvcrABKg==" + "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDLQoEY24tMRIGcHl0aG9uGAEgATIISU5URVJOQUw6DFJ1bnRpbWVFcnJvcrABKg==" } ] From 9ecc7ea18d444acea91f074f5e787e3949bcae41 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 8 Oct 2026 15:37:09 +0800 Subject: [PATCH 205/241] fix(udf): close catalog repair admission --- docs/design/python_udf_current_stage.md | 5 +- .../python_udf_current_stage_approval.md | 2 +- .../service_statistics_upgrade_test.go | 23 ++- pkg/bootstrap/versions/v4_0_12/upgrade.go | 5 + .../versions/v4_0_12/upgrade_test.go | 21 +++ .../upgrade/upgrade_v4_0_12_routine_test.go | 172 ++++++++++++++++++ .../upgrade/upgrade_v4_0_8_statistics_test.go | 1 + 7 files changed, 222 insertions(+), 7 deletions(-) create mode 100644 pkg/tests/upgrade/upgrade_v4_0_12_routine_test.go diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index b13e8dce53cc9..8a9b87ab1a768 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -4,7 +4,7 @@ | --- | --- | | Design revision | `python-udf-current-stage-r3-2026-10-05` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `856e9ddbdd69b52d18f727c763ecd963e66644de` (MORPC 106, catalog 4.0.11) | +| Upstream repair baseline | `c65991043b10fb39988d45b72af1485560ac5433` (MORPC 106, catalog 4.0.11) | | Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r3 repair adds catalog 4.0.12 and protocol 107 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | @@ -92,7 +92,8 @@ entries. Upstream handlers `4.0.8` through `4.0.11` remain unchanged. Thus a ten already at upstream final `4.0.11`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 107 before tenant tasks are created; `Prepare` only selects +requires protocol 107 before tenant tasks are created, and the repair handler +rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index e7462d161deec..e2a00c26c01ca 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -69,7 +69,7 @@ review step after the design record is accepted by the relevant reviewers. ## r3 maintenance addendum (2026-10-05) The current document proposes protocol 107 and repair catalog 4.0.12 against -upstream `856e9ddbdd69b52d18f727c763ecd963e66644de`. It adds explicit sender, +upstream `c65991043b10fb39988d45b72af1485560ac5433`. It adds explicit sender, receiver, prepared-reuse and physical execution admission, and schedules repair for a tenant already at upstream-final 4.0.11. These are conservative corrections within the opt-in development scope. The immutable r1 blobs above describe that diff --git a/pkg/bootstrap/service_statistics_upgrade_test.go b/pkg/bootstrap/service_statistics_upgrade_test.go index 27d9fcfeac292..2569065d8a243 100644 --- a/pkg/bootstrap/service_statistics_upgrade_test.go +++ b/pkg/bootstrap/service_statistics_upgrade_test.go @@ -439,7 +439,7 @@ func TestMaybeUpgradeTenantDoesNotCacheUncommittedOrFailedChecks(t *testing.T) { } }, txnOp) b := newServiceForTest("", &memLocker{}, clock.NewHLCClock(func() int64 { return 0 }, 0), - nil, exec, func(s *service) { s.initUpgrade() }) + nil, exec, initStatisticsUpgradeThroughV4011) defer b.stopper.Stop() for range 2 { var txnOp client.TxnOperator @@ -466,6 +466,21 @@ func TestMaybeUpgradeTenantDoesNotCacheUncommittedOrFailedChecks(t *testing.T) { } } +// These tests exercise the tenant-compensation state machine against the +// historical statistics-upgrade contract. Keep the synthetic service at the +// last pre-routine-catalog version so their SQL fixtures do not silently grow +// unrelated 4.0.12 catalog mutations. +func initStatisticsUpgradeThroughV4011(s *service) { + s.handles = append(s.handles, + v4_0_6.Handler, + v4_0_7.Handler, + v4_0_8.Handler, + v4_0_9.Handler, + v4_0_10.Handler, + v4_0_11.Handler, + ) +} + func TestMaybeUpgradeTenantRechecksVersionUnderLock(t *testing.T) { runtime.RunTest("", func(runtime.Runtime) { final := statisticsFinalUpgradeVersion() @@ -485,7 +500,7 @@ func TestMaybeUpgradeTenantRechecksVersionUnderLock(t *testing.T) { } }) b := newServiceForTest("", &memLocker{}, clock.NewHLCClock(func() int64 { return 0 }, 0), - nil, exec, func(s *service) { s.initUpgrade() }) + nil, exec, initStatisticsUpgradeThroughV4011) defer b.stopper.Stop() upgraded, err := b.MaybeUpgradeTenant(t.Context(), func() (int32, string, error) { return 11, final.Version, nil }, nil) @@ -513,7 +528,7 @@ func TestMaybeUpgradeTenantWaitHonorsCancellation(t *testing.T) { } }) b := newServiceForTest("", &memLocker{}, clock.NewHLCClock(func() int64 { return 0 }, 0), - nil, exec, func(s *service) { s.initUpgrade() }) + nil, exec, initStatisticsUpgradeThroughV4011) defer b.stopper.Stop() ctx, cancel := context.WithCancel(t.Context()) cancel() @@ -555,7 +570,7 @@ func TestMaybeUpgradeTenantRejectsConcurrentAccountDeletion(t *testing.T) { } })} b := newServiceForTest("", &memLocker{}, clock.NewHLCClock(func() int64 { return 0 }, 0), - nil, exec, func(s *service) { s.initUpgrade() }) + nil, exec, initStatisticsUpgradeThroughV4011) defer b.stopper.Stop() fetch := func() (int32, string, error) { authenticated = true diff --git a/pkg/bootstrap/versions/v4_0_12/upgrade.go b/pkg/bootstrap/versions/v4_0_12/upgrade.go index a40b5e92bef2f..ba48b616dcddc 100644 --- a/pkg/bootstrap/versions/v4_0_12/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_12/upgrade.go @@ -58,6 +58,11 @@ func (v *versionHandle) Prepare(ctx context.Context, txn executor.TxnExecutor, f } func (v *versionHandle) HandleTenantUpgrade(ctx context.Context, tenantID int32, txn executor.TxnExecutor) error { + // Login compensation invokes this handler without the cluster-upgrade + // scheduler, so enforce the same floor before any catalog mutation. + if err := versions.CheckCommonProtocolVersion(txn, v.metadata.RequiredProtocolVersion); err != nil { + return err + } logger := runtime.ServiceRuntime(txn.Txn().TxnOptions().CN).Logger() for _, entry := range v4_0_7.PythonRevisionUpgradeEntries() { start := time.Now() diff --git a/pkg/bootstrap/versions/v4_0_12/upgrade_test.go b/pkg/bootstrap/versions/v4_0_12/upgrade_test.go index 55ad7dd646cde..185ba1ddb8d69 100644 --- a/pkg/bootstrap/versions/v4_0_12/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_12/upgrade_test.go @@ -45,6 +45,27 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Len(t, v4_0_7.PythonRevisionUpgradeEntries(), 9) } +func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { + for _, response := range []string{ + `{"result":"cn-a:106"}`, + `{"result":"cn-a:107,cn-b:106"}`, + `{"result":""}`, + `invalid`, + } { + t.Run(response, func(t *testing.T) { + var statements []string + txn := executor.NewMemTxnExecutor(func(statement string) (executor.Result, error) { + statements = append(statements, statement) + require.Equal(t, "SELECT mo_ctl('cn', 'GetProtocolVersion', '')", statement) + return repairStringResult(t, response), nil + }, nil) + err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 107") + require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) + }) + } +} + func TestPythonRevisionRepairIsIdempotentForCatalogStates(t *testing.T) { for _, test := range []struct { name string diff --git a/pkg/tests/upgrade/upgrade_v4_0_12_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_12_routine_test.go new file mode 100644 index 0000000000000..ea7b3db5d9952 --- /dev/null +++ b/pkg/tests/upgrade/upgrade_v4_0_12_routine_test.go @@ -0,0 +1,172 @@ +// Copyright 2026 Matrix Origin +// +// 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 upgrade + +import ( + "context" + "database/sql" + "fmt" + "strings" + "testing" + "time" + + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_12" + "github.com/matrixorigin/matrixone/pkg/catalog" + moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/embed" + "github.com/matrixorigin/matrixone/pkg/tests/testutils" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/matrixorigin/matrixone/pkg/util/executor" + "github.com/stretchr/testify/require" +) + +// Reuse the upgrade package's single-CN fixture. A late tenant must be repaired +// on its first real login, even when the cluster has already completed upgrade. +func TestV4012LoginRepairsLegacyRoutineCatalog(t *testing.T) { + embed.RunSingleCNBaseClusterTests(t, func(cluster embed.Cluster) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) + defer cancel() + cn, err := cluster.GetCNService(0) + require.NoError(t, err) + port := cn.GetServiceConfig().CN.Frontend.Port + systemDB, err := sql.Open("mysql", fmt.Sprintf("dump:111@tcp(127.0.0.1:%d)/", port)) + require.NoError(t, err) + defer systemDB.Close() + const account = "routine_repair_4012" + _, err = systemDB.ExecContext(ctx, "create account "+account+" ADMIN_NAME 'root' IDENTIFIED BY '111'") + require.NoError(t, err) + defer func() { + cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cleanupCancel() + _, err := systemDB.ExecContext(cleanupCtx, "drop account "+account) + require.NoError(t, err) + var remaining int + require.NoError(t, systemDB.QueryRowContext(cleanupCtx, + "select count(*) from mo_catalog.mo_account where account_name = '"+account+"'").Scan(&remaining)) + require.Zero(t, remaining) + }() + var accountID uint32 + require.NoError(t, systemDB.QueryRowContext(ctx, + "select account_id from mo_catalog.mo_account where account_name = '"+account+"'").Scan(&accountID)) + sqlExecutor := testutils.GetSQLExecutor(cn) + // Model an old writer through a sys-owned transaction, without tenant + // authentication populating the bootstrap service's checked-tenant cache. + require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { + for _, statement := range []string{ + "create database routine_repair", + `insert into mo_catalog.mo_user_defined_function(name,owner,args,arg_types,rettype,body,language,db,definer,type,security_type) values ('legacy_plus_seven',2,'[{"name":"x","type":"bigint"}]','["bigint"]','bigint','$1 + 7','sql','routine_repair','root','SQL','INVOKER')`, + "drop table mo_catalog.mo_function_revisions", + } { + res, err := txn.Exec(statement, versions.UpgradeStatementOption(accountID)) + if err != nil { + return err + } + res.Close() + } + return versions.UpgradeTenantVersion(int32(accountID), "4.0.11", txn) + }, executor.Options{}.WithDatabase(catalog.MO_CATALOG). + WithAccountID(catalog.System_Account).WithWaitCommittedLogApplied())) + var functionID uint64 + checkCatalog := func(wantVersion string, wantTable bool) { + t.Helper() + var version string + require.NoError(t, systemDB.QueryRowContext(ctx, + fmt.Sprintf("select create_version from mo_catalog.mo_account where account_id = %d", accountID)).Scan(&version)) + require.Equal(t, wantVersion, version) + require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { + exists, err := versions.CheckTableDefinition(txn, accountID, catalog.MO_CATALOG, "mo_function_revisions") + if err != nil { + return err + } + require.Equal(t, wantTable, exists) + res, err := txn.Exec("select function_id,body,active_revision,namespace_version from mo_catalog.mo_user_defined_function where name = 'legacy_plus_seven'", versions.UpgradeStatementOption(accountID)) + if err != nil { + return err + } + defer res.Close() + require.Equal(t, 1, len(res.Batches)) + batch := res.Batches[0] + require.Equal(t, 1, batch.RowCount()) + id := uint64(vector.GetFixedAtWithTypeCheck[int32](batch.Vecs[0], 0)) + if functionID == 0 { + functionID = id + } + require.Equal(t, functionID, id) + require.Equal(t, "$1 + 7", batch.Vecs[1].GetStringAt(0)) + require.Equal(t, uint64(0), vector.GetFixedAtWithTypeCheck[uint64](batch.Vecs[2], 0)) + require.Equal(t, uint64(0), vector.GetFixedAtWithTypeCheck[uint64](batch.Vecs[3], 0)) + return nil + }, executor.Options{}.WithDatabase(catalog.MO_CATALOG).WithAccountID(catalog.System_Account))) + } + checkCatalog("4.0.11", false) + rt := moruntime.ServiceRuntime(cn.ServiceID()) + original, present := rt.GetGlobalVariables(moruntime.MOProtocolVersion) + require.True(t, present) + require.GreaterOrEqual(t, original.(int64), udf.SharedRoutineRevisionProtocolVersion) + defer rt.SetGlobalVariables(moruntime.MOProtocolVersion, original) + tenantDSN := fmt.Sprintf("%s#root#accountadmin:111@tcp(127.0.0.1:%d)/", account, port) + func() { + rt.SetGlobalVariables(moruntime.MOProtocolVersion, udf.SharedRoutineRevisionProtocolVersion-1) + defer rt.SetGlobalVariables(moruntime.MOProtocolVersion, original) + db, err := sql.Open("mysql", tenantDSN) + require.NoError(t, err) + defer db.Close() + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 107") + }() + checkCatalog("4.0.11", false) + tenantDB, err := sql.Open("mysql", tenantDSN) + require.NoError(t, err) + defer tenantDB.Close() + checkResult := func() { + t.Helper() + _, err := tenantDB.ExecContext(ctx, "use routine_repair") + require.NoError(t, err) + var result int64 + require.NoError(t, tenantDB.QueryRowContext(ctx, "select legacy_plus_seven(5)").Scan(&result)) + require.Equal(t, int64(12), result) + } + checkResult() + checkCatalog("4.0.12", true) + // Explicit replay reaches the handler; a cached second login would not + // prove that its DDL is idempotent against the persisted catalog. + for range 2 { + var mutations int + require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { + return v4_0_12.Handler.HandleTenantUpgrade(ctx, int32(accountID), + &routineRepairTxn{TxnExecutor: txn, mutations: &mutations}) + }, executor.Options{}.WithDatabase(catalog.MO_CATALOG). + WithAccountID(catalog.System_Account).WithWaitCommittedLogApplied())) + require.Zero(t, mutations) + checkCatalog("4.0.12", true) + checkResult() + } + }) +} + +type routineRepairTxn struct { + executor.TxnExecutor + mutations *int +} + +func (txn *routineRepairTxn) Exec(statement string, opts executor.StatementOption) (executor.Result, error) { + res, err := txn.TxnExecutor.Exec(statement, opts) + lower := strings.ToLower(strings.TrimSpace(statement)) + if err == nil && (strings.HasPrefix(lower, "alter table") || strings.HasPrefix(lower, "create table") || strings.HasPrefix(lower, "create unique index")) { + (*txn.mutations)++ + } + return res, err +} diff --git a/pkg/tests/upgrade/upgrade_v4_0_8_statistics_test.go b/pkg/tests/upgrade/upgrade_v4_0_8_statistics_test.go index cecdb06ace3e5..3708cc21f685d 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_8_statistics_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_8_statistics_test.go @@ -25,6 +25,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_8" "github.com/matrixorigin/matrixone/pkg/catalog" + "github.com/matrixorigin/matrixone/pkg/cnservice" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/embed" "github.com/matrixorigin/matrixone/pkg/frontend" From a192b905ac613f6a9f4e181f850d5e2755217829 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 8 Oct 2026 18:20:00 +0800 Subject: [PATCH 206/241] fix(udf): regenerate merged mysql parser --- pkg/sql/parsers/dialect/mysql/mysql_sql.go | 35655 +------------------ 1 file changed, 445 insertions(+), 35210 deletions(-) diff --git a/pkg/sql/parsers/dialect/mysql/mysql_sql.go b/pkg/sql/parsers/dialect/mysql/mysql_sql.go index 102f83064a7a5..fe1f30f9b0d60 100644 --- a/pkg/sql/parsers/dialect/mysql/mysql_sql.go +++ b/pkg/sql/parsers/dialect/mysql/mysql_sql.go @@ -1,68 +1,66 @@ -// Code generated by goyacc -o mysql_sql.go mysql_sql.y. DO NOT EDIT. +// Code generated by goyacc -v /Users/linjunhong/.loom/tmp/pr29152-79e4-parser.output -o mysql_sql.go mysql_sql.y. DO NOT EDIT. //line mysql_sql.y:16 package mysql - import ( - __yyfmt__ "fmt" - __yyunsafe__ "unsafe" +__yyfmt__ "fmt" +__yyunsafe__ "unsafe" ) - //line mysql_sql.y:16 - + import ( - "fmt" - "strings" + "fmt" + "strings" - "github.com/matrixorigin/matrixone/pkg/defines" - "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" - "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" - "github.com/matrixorigin/matrixone/pkg/sql/parsers/util" + "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" + "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" + "github.com/matrixorigin/matrixone/pkg/sql/parsers/util" + "github.com/matrixorigin/matrixone/pkg/defines" ) func sqlTaskNodeString(node tree.NodeFormatter) string { - if node == nil { - return "" - } - return tree.StringWithOpts(node, dialect.MYSQL, tree.WithQuoteIdentifier(), tree.WithSingleQuoteString()) + if node == nil { + return "" + } + return tree.StringWithOpts(node, dialect.MYSQL, tree.WithQuoteIdentifier(), tree.WithSingleQuoteString()) } // makeSelectStarFromTable builds the `SELECT * FROM tbl` clause used to desugar // MySQL TABLE query terms and their REPLACE source form. func makeSelectStarFromTable(tbl tree.TableExpr) *tree.SelectClause { - return &tree.SelectClause{ - Exprs: tree.SelectExprs{tree.SelectExpr{Expr: tree.StarExpr()}}, - From: &tree.From{ - Tables: tree.TableExprs{&tree.AliasedTableExpr{Expr: tbl}}, - }, - } + return &tree.SelectClause{ + Exprs: tree.SelectExprs{tree.SelectExpr{Expr: tree.StarExpr()}}, + From: &tree.From{ + Tables: tree.TableExprs{&tree.AliasedTableExpr{Expr: tbl}}, + }, + } } func sqlTaskBodyString(stmt tree.Statement) string { - compound, ok := stmt.(*tree.CompoundStmt) - if !ok || compound == nil { - return "" - } - parts := make([]string, 0, len(compound.Stmts)) - for _, s := range compound.Stmts { - if s != nil { - parts = append(parts, tree.StringWithOpts(s, dialect.MYSQL, tree.WithQuoteIdentifier(), tree.WithSingleQuoteString())) - } - } - return strings.Join(parts, "; ") + compound, ok := stmt.(*tree.CompoundStmt) + if !ok || compound == nil { + return "" + } + parts := make([]string, 0, len(compound.Stmts)) + for _, s := range compound.Stmts { + if s != nil { + parts = append(parts, tree.StringWithOpts(s, dialect.MYSQL, tree.WithQuoteIdentifier(), tree.WithSingleQuoteString())) + } + } + return strings.Join(parts, "; ") } func sqlTaskInt64(v any) int64 { - switch value := v.(type) { - case int: - return int64(value) - case int64: - return value - case uint64: - return int64(value) - default: - panic(fmt.Sprintf("unexpected integral type %T", v)) - } + switch value := v.(type) { + case int: + return int64(value) + case int64: + return value + case uint64: + return int64(value) + default: + panic(fmt.Sprintf("unexpected integral type %T", v)) + } } const restoreSnapshotFromSyntaxHint = `FROM SNAPSHOT is not supported; use RESTORE DATABASE [account.]database{snapshot="snapshot_name"}` @@ -78,108 +76,107 @@ func makeCharsetCastCharType(width int32, charsetName string) *tree.T { oid = uint32(defines.MYSQL_TYPE_VARCHAR) } return &tree.T{InternalType: tree.InternalType{ - Family: tree.StringFamily, - FamilyString: familyString, - DisplayWith: width, - Locale: &locale, - Oid: oid, + Family: tree.StringFamily, + FamilyString: familyString, + DisplayWith: width, + Locale: &locale, + Oid: oid, CastCharsetSpecified: true, - CastCharsetName: charsetName, + CastCharsetName: charsetName, }} } func mergeIndexOption(left, right *tree.IndexOption) *tree.IndexOption { - if left == nil { - return right - } - if right == nil { - return left - } - if right.IType != tree.INDEX_TYPE_INVALID { - left.IType = right.IType - } else if len(right.Comment) > 0 { - left.Comment = right.Comment - } else if right.KeyBlockSize > 0 { - left.KeyBlockSize = right.KeyBlockSize - } else if len(right.ParserName) > 0 { - left.ParserName = right.ParserName - } else if right.Visible != tree.VISIBLE_TYPE_INVALID { - left.Visible = right.Visible - } else if right.AlgoParamList > 0 { - left.AlgoParamList = right.AlgoParamList - } else if len(right.AlgoParamVectorOpType) > 0 { - left.AlgoParamVectorOpType = right.AlgoParamVectorOpType - } else if right.AlgoParamM > 0 { - left.AlgoParamM = right.AlgoParamM - } else if right.HnswEfConstruction > 0 { - left.HnswEfConstruction = right.HnswEfConstruction - } else if right.HnswEfSearch > 0 { - left.HnswEfSearch = right.HnswEfSearch - } else if right.Async { - left.Async = right.Async - } else if right.ForceSync { - left.ForceSync = right.ForceSync - } else if right.Merge { - left.Merge = right.Merge - } else if right.AutoUpdate { - left.AutoUpdate = right.AutoUpdate - } else if right.Day > 0 { - left.Day = right.Day - } else if right.Hour > 0 { - left.Hour = right.Hour - } else if right.Second > 0 { - left.Second = right.Second - } else if right.IntermediateGraphDegree > 0 { - left.IntermediateGraphDegree = right.IntermediateGraphDegree - } else if right.GraphDegree > 0 { - left.GraphDegree = right.GraphDegree - } else if right.BitsPerCode > 0 { - left.BitsPerCode = right.BitsPerCode - } else if len(right.Quantization) > 0 { - left.Quantization = right.Quantization - } else if len(right.DistributionMode) > 0 { - left.DistributionMode = right.DistributionMode - } else if right.ITopkSize > 0 { - left.ITopkSize = right.ITopkSize - } else if right.KmeansTrainPercent > 0 { - left.KmeansTrainPercent = right.KmeansTrainPercent - } else if right.KmeansMaxIteration > 0 { - left.KmeansMaxIteration = right.KmeansMaxIteration - } else if right.MaxIndexCapacity > 0 { - left.MaxIndexCapacity = right.MaxIndexCapacity - } else if right.MaxPostingsCapacity > 0 { - left.MaxPostingsCapacity = right.MaxPostingsCapacity - } else if right.QuantizerTrainLimit > 0 { - left.QuantizerTrainLimit = right.QuantizerTrainLimit - } else if right.PositionFreeSet { - left.PositionFree = right.PositionFree - left.PositionFreeSet = true - } else if len(right.IncludeColumns) > 0 { - left.IncludeColumns = right.IncludeColumns - } - return left + if left == nil { + return right + } + if right == nil { + return left + } + if right.IType != tree.INDEX_TYPE_INVALID { + left.IType = right.IType + } else if len(right.Comment) > 0 { + left.Comment = right.Comment + } else if right.KeyBlockSize > 0 { + left.KeyBlockSize = right.KeyBlockSize + } else if len(right.ParserName) > 0 { + left.ParserName = right.ParserName + } else if right.Visible != tree.VISIBLE_TYPE_INVALID { + left.Visible = right.Visible + } else if right.AlgoParamList > 0 { + left.AlgoParamList = right.AlgoParamList + } else if len(right.AlgoParamVectorOpType) > 0 { + left.AlgoParamVectorOpType = right.AlgoParamVectorOpType + } else if right.AlgoParamM > 0 { + left.AlgoParamM = right.AlgoParamM + } else if right.HnswEfConstruction > 0 { + left.HnswEfConstruction = right.HnswEfConstruction + } else if right.HnswEfSearch > 0 { + left.HnswEfSearch = right.HnswEfSearch + } else if right.Async { + left.Async = right.Async + } else if right.ForceSync { + left.ForceSync = right.ForceSync + } else if right.Merge { + left.Merge = right.Merge + } else if right.AutoUpdate { + left.AutoUpdate = right.AutoUpdate + } else if right.Day > 0 { + left.Day = right.Day + } else if right.Hour > 0 { + left.Hour = right.Hour + } else if right.Second > 0 { + left.Second = right.Second + } else if right.IntermediateGraphDegree > 0 { + left.IntermediateGraphDegree = right.IntermediateGraphDegree + } else if right.GraphDegree > 0 { + left.GraphDegree = right.GraphDegree + } else if right.BitsPerCode > 0 { + left.BitsPerCode = right.BitsPerCode + } else if len(right.Quantization) > 0 { + left.Quantization = right.Quantization + } else if len(right.DistributionMode) > 0 { + left.DistributionMode = right.DistributionMode + } else if right.ITopkSize > 0 { + left.ITopkSize = right.ITopkSize + } else if right.KmeansTrainPercent > 0 { + left.KmeansTrainPercent = right.KmeansTrainPercent + } else if right.KmeansMaxIteration > 0 { + left.KmeansMaxIteration = right.KmeansMaxIteration + } else if right.MaxIndexCapacity > 0 { + left.MaxIndexCapacity = right.MaxIndexCapacity + } else if right.MaxPostingsCapacity > 0 { + left.MaxPostingsCapacity = right.MaxPostingsCapacity + } else if right.QuantizerTrainLimit > 0 { + left.QuantizerTrainLimit = right.QuantizerTrainLimit + } else if right.PositionFreeSet { + left.PositionFree = right.PositionFree + left.PositionFreeSet = true + } else if len(right.IncludeColumns) > 0 { + left.IncludeColumns = right.IncludeColumns + } + return left } func makeWindowSpec(refName *tree.CStr, partitionBy tree.Exprs, orderBy tree.OrderBy, frame *tree.FrameClause) *tree.WindowSpec { - hasFrame := frame != nil - if frame == nil { - frame = &tree.FrameClause{Type: tree.Range} - frame.Start = &tree.FrameBound{Type: tree.Preceding, UnBounded: true} - if orderBy == nil { - frame.End = &tree.FrameBound{Type: tree.Following, UnBounded: true} - } else { - frame.End = &tree.FrameBound{Type: tree.CurrentRow} - } - } - return &tree.WindowSpec{ - RefName: refName, - PartitionBy: partitionBy, - OrderBy: orderBy, - Frame: frame, - HasFrame: hasFrame, - } + hasFrame := frame != nil + if frame == nil { + frame = &tree.FrameClause{Type: tree.Range} + frame.Start = &tree.FrameBound{Type: tree.Preceding, UnBounded: true} + if orderBy == nil { + frame.End = &tree.FrameBound{Type: tree.Following, UnBounded: true} + } else { + frame.End = &tree.FrameBound{Type: tree.CurrentRow} + } + } + return &tree.WindowSpec{ + RefName: refName, + PartitionBy: partitionBy, + OrderBy: orderBy, + Frame: frame, + HasFrame: hasFrame, + } } - const LEX_ERROR = 57346 const JSON_TABLE = 57347 const JSON_TABLE_PATH = 57348 @@ -642,309 +639,313 @@ const TEMPORARY = 57804 const ROUTINE = 57805 const EVENT = 57806 const SHUTDOWN = 57807 -const NULLX = 57808 -const AUTO_INCREMENT = 57809 -const APPROXNUM = 57810 -const ENGINES = 57811 -const LOW_CARDINALITY = 57812 -const AUTOEXTEND_SIZE = 57813 -const ADMIN_NAME = 57814 -const RANDOM = 57815 -const SUSPEND = 57816 -const ATTRIBUTE = 57817 -const HISTORY = 57818 -const REUSE = 57819 -const CURRENT = 57820 -const OPTIONAL = 57821 -const FAILED_LOGIN_ATTEMPTS = 57822 -const PASSWORD_LOCK_TIME = 57823 -const UNBOUNDED = 57824 -const SECONDARY = 57825 -const RESTRICTED = 57826 -const USER = 57827 -const IDENTIFIED = 57828 -const CIPHER = 57829 -const ISSUER = 57830 -const X509 = 57831 -const SUBJECT = 57832 -const SAN = 57833 -const REQUIRE = 57834 -const SSL = 57835 -const NONE = 57836 -const PASSWORD = 57837 -const SHARED = 57838 -const EXCLUSIVE = 57839 -const MAX_QUERIES_PER_HOUR = 57840 -const MAX_UPDATES_PER_HOUR = 57841 -const MAX_CONNECTIONS_PER_HOUR = 57842 -const MAX_USER_CONNECTIONS = 57843 -const FORMAT = 57844 -const VERBOSE = 57845 -const CONNECTION = 57846 -const TRIGGERS = 57847 -const PROFILES = 57848 -const PROFILE = 57849 -const LOAD = 57850 -const INLINE = 57851 -const INFILE = 57852 -const TERMINATED = 57853 -const OPTIONALLY = 57854 -const ENCLOSED = 57855 -const ESCAPED = 57856 -const STARTING = 57857 -const LINES = 57858 -const ROWS = 57859 -const IMPORT = 57860 -const DISCARD = 57861 -const JSONTYPE = 57862 -const MODUMP = 57863 -const OVER = 57864 -const PRECEDING = 57865 -const FOLLOWING = 57866 -const GROUPS = 57867 -const DATABASES = 57868 -const TABLES = 57869 -const SEQUENCES = 57870 -const EXTENDED = 57871 -const FULL = 57872 -const PROCESSLIST = 57873 -const FIELDS = 57874 -const COLUMNS = 57875 -const OPEN = 57876 -const ERRORS = 57877 -const WARNINGS = 57878 -const INDEXES = 57879 -const SCHEMAS = 57880 -const NODE = 57881 -const LOCKS = 57882 -const ROLES = 57883 -const RULE = 57884 -const RULES = 57885 -const TABLE_NUMBER = 57886 -const COLUMN_NUMBER = 57887 -const TABLE_VALUES = 57888 -const TABLE_SIZE = 57889 -const TASKS = 57890 -const RUNS = 57891 -const NAMES = 57892 -const GLOBAL = 57893 -const PERSIST = 57894 -const SESSION = 57895 -const ISOLATION = 57896 -const LEVEL = 57897 -const READ = 57898 -const WRITE = 57899 -const ONLY = 57900 -const REPEATABLE = 57901 -const COMMITTED = 57902 -const UNCOMMITTED = 57903 -const SERIALIZABLE = 57904 -const LOCAL = 57905 -const EVENTS = 57906 -const PLUGINS = 57907 -const CURRENT_TIMESTAMP = 57908 -const DATABASE = 57909 -const CURRENT_TIME = 57910 -const LOCALTIME = 57911 -const LOCALTIMESTAMP = 57912 -const UTC_DATE = 57913 -const UTC_TIME = 57914 -const UTC_TIMESTAMP = 57915 -const REPLACE = 57916 -const CONVERT = 57917 -const SEPARATOR = 57918 -const TIMESTAMPDIFF = 57919 -const TIMESTAMPADD = 57920 -const CURRENT_DATE = 57921 -const CURRENT_USER = 57922 -const CURRENT_ROLE = 57923 -const SECOND_MICROSECOND = 57924 -const MINUTE_MICROSECOND = 57925 -const MINUTE_SECOND = 57926 -const HOUR_MICROSECOND = 57927 -const HOUR_SECOND = 57928 -const HOUR_MINUTE = 57929 -const DAY_MICROSECOND = 57930 -const DAY_SECOND = 57931 -const DAY_MINUTE = 57932 -const DAY_HOUR = 57933 -const YEAR_MONTH = 57934 -const SQL_TSI_HOUR = 57935 -const SQL_TSI_DAY = 57936 -const SQL_TSI_WEEK = 57937 -const SQL_TSI_MONTH = 57938 -const SQL_TSI_QUARTER = 57939 -const SQL_TSI_YEAR = 57940 -const SQL_TSI_SECOND = 57941 -const SQL_TSI_MINUTE = 57942 -const RECURSIVE = 57943 -const CONFIG = 57944 -const DRAINER = 57945 -const DAEMON = 57946 -const PAUSE = 57947 -const CANCEL = 57948 -const RESUME = 57949 -const SCHEDULE = 57950 -const TIMEZONE = 57951 -const TIMEOUT = 57952 -const TASK = 57953 -const MATCH = 57954 -const AGAINST = 57955 -const BOOLEAN = 57956 -const LANGUAGE = 57957 -const QUERY = 57958 -const EXPANSION = 57959 -const WITHOUT = 57960 -const VALIDATION = 57961 -const UPGRADE = 57962 -const RETRY = 57963 -const ADDDATE = 57964 -const BIT_AND = 57965 -const BIT_OR = 57966 -const BIT_XOR = 57967 -const CAST = 57968 -const COUNT = 57969 -const APPROX_COUNT = 57970 -const APPROX_COUNT_DISTINCT = 57971 -const SERIAL_EXTRACT = 57972 -const APPROX_PERCENTILE = 57973 -const CURDATE = 57974 -const CURTIME = 57975 -const DATE_ADD = 57976 -const DATE_SUB = 57977 -const EXTRACT = 57978 -const GROUP_CONCAT = 57979 -const MAX = 57980 -const MID = 57981 -const MIN = 57982 -const NOW = 57983 -const POSITION = 57984 -const SESSION_USER = 57985 -const STD = 57986 -const STDDEV = 57987 -const MEDIAN = 57988 -const CLUSTER_CENTERS = 57989 -const KMEANS = 57990 -const STDDEV_POP = 57991 -const STDDEV_SAMP = 57992 -const SUBDATE = 57993 -const SUBSTR = 57994 -const SUBSTRING = 57995 -const SUM = 57996 -const SYSDATE = 57997 -const SYSTEM_USER = 57998 -const TRANSLATE = 57999 -const TRIM = 58000 -const VARIANCE = 58001 -const VAR_POP = 58002 -const VAR_SAMP = 58003 -const AVG = 58004 -const RANK = 58005 -const ROW_NUMBER = 58006 -const DENSE_RANK = 58007 -const CUME_DIST = 58008 -const BIT_CAST = 58009 -const LAG = 58010 -const LEAD = 58011 -const FIRST_VALUE = 58012 -const LAST_VALUE = 58013 -const NTH_VALUE = 58014 -const NTILE = 58015 -const PERCENT_RANK = 58016 -const BITMAP_BIT_POSITION = 58017 -const BITMAP_BUCKET_NUMBER = 58018 -const BITMAP_COUNT = 58019 -const BITMAP_CONSTRUCT_AGG = 58020 -const BITMAP_OR_AGG = 58021 -const JSON_ARRAYAGG = 58022 -const JSON_OBJECTAGG = 58023 -const GET_FORMAT = 58024 -const SRID = 58025 -const NEXTVAL = 58026 -const SETVAL = 58027 -const CURRVAL = 58028 -const LASTVAL = 58029 -const ROW = 58030 -const OUTFILE = 58031 -const HEADER = 58032 -const MAX_FILE_SIZE = 58033 -const FORCE_QUOTE = 58034 -const PARALLEL = 58035 -const STRICT = 58036 -const SPLITSIZE = 58037 -const UNUSED = 58038 -const BINDINGS = 58039 -const GENERATED = 58040 -const ALWAYS = 58041 -const STORED = 58042 -const VIRTUAL = 58043 -const DO = 58044 -const PERFORM = 58045 -const DECLARE = 58046 -const LOOP = 58047 -const WHILE = 58048 -const LEAVE = 58049 -const ITERATE = 58050 -const UNTIL = 58051 -const CALL = 58052 -const PREV = 58053 -const SLIDING = 58054 -const FILL = 58055 -const GAPFILL = 58056 -const SPBEGIN = 58057 -const BACKEND = 58058 -const SERVERS = 58059 -const HANDLER = 58060 -const PERCENT = 58061 -const SAMPLE = 58062 -const MO_TS = 58063 -const PITR = 58064 -const RECOVERY_WINDOW = 58065 -const INTERNAL = 58066 -const CDC_TASK_NAME = 58067 -const CDC = 58068 -const ICEBERG = 58069 -const CATALOG = 58070 -const CATALOGS = 58071 -const NAMESPACE = 58072 -const NAMESPACES = 58073 -const REF = 58074 -const FOR_ICEBERG = 58075 -const MONGODB = 58076 -const MONGODB_PATH = 58077 -const MONGODB_CONVERT = 58078 -const CONNECTIONS = 58079 -const DATASTREAM = 58080 -const ESQL = 58081 -const KAFKA = 58082 -const GROUPING = 58083 -const SETS = 58084 -const CUBE = 58085 -const ROLLUP = 58086 -const LOGSERVICE = 58087 -const REPLICAS = 58088 -const STORES = 58089 -const SETTINGS = 58090 -const DUMP = 58091 -const METADATA = 58092 -const KILL = 58093 -const BACKUP = 58094 -const FILESYSTEM = 58095 -const PARALLELISM = 58096 -const RESTORE = 58097 -const QUERY_RESULT = 58098 -const RETURNING = 58099 -const ARRAY = 58100 -const WITHIN = 58101 -const PERCENTILE_CONT = 58102 -const PERCENTILE_DISC = 58103 -const ASOF = 58104 -const TOLERANCE = 58105 -const WINDOW = 58106 -const WINDOW_NAME_EMPTY = 58107 -const RESPECT = 58108 -const MEMBER = 58109 -const AUTO_ID_CACHE = 58110 +const CALLED = 57808 +const INPUT = 57809 +const SCALAR = 57810 +const VECTOR = 57811 +const NULLX = 57812 +const AUTO_INCREMENT = 57813 +const APPROXNUM = 57814 +const ENGINES = 57815 +const LOW_CARDINALITY = 57816 +const AUTOEXTEND_SIZE = 57817 +const ADMIN_NAME = 57818 +const RANDOM = 57819 +const SUSPEND = 57820 +const ATTRIBUTE = 57821 +const HISTORY = 57822 +const REUSE = 57823 +const CURRENT = 57824 +const OPTIONAL = 57825 +const FAILED_LOGIN_ATTEMPTS = 57826 +const PASSWORD_LOCK_TIME = 57827 +const UNBOUNDED = 57828 +const SECONDARY = 57829 +const RESTRICTED = 57830 +const USER = 57831 +const IDENTIFIED = 57832 +const CIPHER = 57833 +const ISSUER = 57834 +const X509 = 57835 +const SUBJECT = 57836 +const SAN = 57837 +const REQUIRE = 57838 +const SSL = 57839 +const NONE = 57840 +const PASSWORD = 57841 +const SHARED = 57842 +const EXCLUSIVE = 57843 +const MAX_QUERIES_PER_HOUR = 57844 +const MAX_UPDATES_PER_HOUR = 57845 +const MAX_CONNECTIONS_PER_HOUR = 57846 +const MAX_USER_CONNECTIONS = 57847 +const FORMAT = 57848 +const VERBOSE = 57849 +const CONNECTION = 57850 +const TRIGGERS = 57851 +const PROFILES = 57852 +const PROFILE = 57853 +const LOAD = 57854 +const INLINE = 57855 +const INFILE = 57856 +const TERMINATED = 57857 +const OPTIONALLY = 57858 +const ENCLOSED = 57859 +const ESCAPED = 57860 +const STARTING = 57861 +const LINES = 57862 +const ROWS = 57863 +const IMPORT = 57864 +const DISCARD = 57865 +const JSONTYPE = 57866 +const MODUMP = 57867 +const OVER = 57868 +const PRECEDING = 57869 +const FOLLOWING = 57870 +const GROUPS = 57871 +const DATABASES = 57872 +const TABLES = 57873 +const SEQUENCES = 57874 +const EXTENDED = 57875 +const FULL = 57876 +const PROCESSLIST = 57877 +const FIELDS = 57878 +const COLUMNS = 57879 +const OPEN = 57880 +const ERRORS = 57881 +const WARNINGS = 57882 +const INDEXES = 57883 +const SCHEMAS = 57884 +const NODE = 57885 +const LOCKS = 57886 +const ROLES = 57887 +const RULE = 57888 +const RULES = 57889 +const TABLE_NUMBER = 57890 +const COLUMN_NUMBER = 57891 +const TABLE_VALUES = 57892 +const TABLE_SIZE = 57893 +const TASKS = 57894 +const RUNS = 57895 +const NAMES = 57896 +const GLOBAL = 57897 +const PERSIST = 57898 +const SESSION = 57899 +const ISOLATION = 57900 +const LEVEL = 57901 +const READ = 57902 +const WRITE = 57903 +const ONLY = 57904 +const REPEATABLE = 57905 +const COMMITTED = 57906 +const UNCOMMITTED = 57907 +const SERIALIZABLE = 57908 +const LOCAL = 57909 +const EVENTS = 57910 +const PLUGINS = 57911 +const CURRENT_TIMESTAMP = 57912 +const DATABASE = 57913 +const CURRENT_TIME = 57914 +const LOCALTIME = 57915 +const LOCALTIMESTAMP = 57916 +const UTC_DATE = 57917 +const UTC_TIME = 57918 +const UTC_TIMESTAMP = 57919 +const REPLACE = 57920 +const CONVERT = 57921 +const SEPARATOR = 57922 +const TIMESTAMPDIFF = 57923 +const TIMESTAMPADD = 57924 +const CURRENT_DATE = 57925 +const CURRENT_USER = 57926 +const CURRENT_ROLE = 57927 +const SECOND_MICROSECOND = 57928 +const MINUTE_MICROSECOND = 57929 +const MINUTE_SECOND = 57930 +const HOUR_MICROSECOND = 57931 +const HOUR_SECOND = 57932 +const HOUR_MINUTE = 57933 +const DAY_MICROSECOND = 57934 +const DAY_SECOND = 57935 +const DAY_MINUTE = 57936 +const DAY_HOUR = 57937 +const YEAR_MONTH = 57938 +const SQL_TSI_HOUR = 57939 +const SQL_TSI_DAY = 57940 +const SQL_TSI_WEEK = 57941 +const SQL_TSI_MONTH = 57942 +const SQL_TSI_QUARTER = 57943 +const SQL_TSI_YEAR = 57944 +const SQL_TSI_SECOND = 57945 +const SQL_TSI_MINUTE = 57946 +const RECURSIVE = 57947 +const CONFIG = 57948 +const DRAINER = 57949 +const DAEMON = 57950 +const PAUSE = 57951 +const CANCEL = 57952 +const RESUME = 57953 +const SCHEDULE = 57954 +const TIMEZONE = 57955 +const TIMEOUT = 57956 +const TASK = 57957 +const MATCH = 57958 +const AGAINST = 57959 +const BOOLEAN = 57960 +const LANGUAGE = 57961 +const QUERY = 57962 +const EXPANSION = 57963 +const WITHOUT = 57964 +const VALIDATION = 57965 +const UPGRADE = 57966 +const RETRY = 57967 +const ADDDATE = 57968 +const BIT_AND = 57969 +const BIT_OR = 57970 +const BIT_XOR = 57971 +const CAST = 57972 +const COUNT = 57973 +const APPROX_COUNT = 57974 +const APPROX_COUNT_DISTINCT = 57975 +const SERIAL_EXTRACT = 57976 +const APPROX_PERCENTILE = 57977 +const CURDATE = 57978 +const CURTIME = 57979 +const DATE_ADD = 57980 +const DATE_SUB = 57981 +const EXTRACT = 57982 +const GROUP_CONCAT = 57983 +const MAX = 57984 +const MID = 57985 +const MIN = 57986 +const NOW = 57987 +const POSITION = 57988 +const SESSION_USER = 57989 +const STD = 57990 +const STDDEV = 57991 +const MEDIAN = 57992 +const CLUSTER_CENTERS = 57993 +const KMEANS = 57994 +const STDDEV_POP = 57995 +const STDDEV_SAMP = 57996 +const SUBDATE = 57997 +const SUBSTR = 57998 +const SUBSTRING = 57999 +const SUM = 58000 +const SYSDATE = 58001 +const SYSTEM_USER = 58002 +const TRANSLATE = 58003 +const TRIM = 58004 +const VARIANCE = 58005 +const VAR_POP = 58006 +const VAR_SAMP = 58007 +const AVG = 58008 +const RANK = 58009 +const ROW_NUMBER = 58010 +const DENSE_RANK = 58011 +const CUME_DIST = 58012 +const BIT_CAST = 58013 +const LAG = 58014 +const LEAD = 58015 +const FIRST_VALUE = 58016 +const LAST_VALUE = 58017 +const NTH_VALUE = 58018 +const NTILE = 58019 +const PERCENT_RANK = 58020 +const BITMAP_BIT_POSITION = 58021 +const BITMAP_BUCKET_NUMBER = 58022 +const BITMAP_COUNT = 58023 +const BITMAP_CONSTRUCT_AGG = 58024 +const BITMAP_OR_AGG = 58025 +const JSON_ARRAYAGG = 58026 +const JSON_OBJECTAGG = 58027 +const GET_FORMAT = 58028 +const SRID = 58029 +const NEXTVAL = 58030 +const SETVAL = 58031 +const CURRVAL = 58032 +const LASTVAL = 58033 +const ROW = 58034 +const OUTFILE = 58035 +const HEADER = 58036 +const MAX_FILE_SIZE = 58037 +const FORCE_QUOTE = 58038 +const PARALLEL = 58039 +const STRICT = 58040 +const SPLITSIZE = 58041 +const UNUSED = 58042 +const BINDINGS = 58043 +const GENERATED = 58044 +const ALWAYS = 58045 +const STORED = 58046 +const VIRTUAL = 58047 +const DO = 58048 +const PERFORM = 58049 +const DECLARE = 58050 +const LOOP = 58051 +const WHILE = 58052 +const LEAVE = 58053 +const ITERATE = 58054 +const UNTIL = 58055 +const CALL = 58056 +const PREV = 58057 +const SLIDING = 58058 +const FILL = 58059 +const GAPFILL = 58060 +const SPBEGIN = 58061 +const BACKEND = 58062 +const SERVERS = 58063 +const HANDLER = 58064 +const PERCENT = 58065 +const SAMPLE = 58066 +const MO_TS = 58067 +const PITR = 58068 +const RECOVERY_WINDOW = 58069 +const INTERNAL = 58070 +const CDC_TASK_NAME = 58071 +const CDC = 58072 +const ICEBERG = 58073 +const CATALOG = 58074 +const CATALOGS = 58075 +const NAMESPACE = 58076 +const NAMESPACES = 58077 +const REF = 58078 +const FOR_ICEBERG = 58079 +const MONGODB = 58080 +const MONGODB_PATH = 58081 +const MONGODB_CONVERT = 58082 +const CONNECTIONS = 58083 +const DATASTREAM = 58084 +const ESQL = 58085 +const KAFKA = 58086 +const GROUPING = 58087 +const SETS = 58088 +const CUBE = 58089 +const ROLLUP = 58090 +const LOGSERVICE = 58091 +const REPLICAS = 58092 +const STORES = 58093 +const SETTINGS = 58094 +const DUMP = 58095 +const METADATA = 58096 +const KILL = 58097 +const BACKUP = 58098 +const FILESYSTEM = 58099 +const PARALLELISM = 58100 +const RESTORE = 58101 +const QUERY_RESULT = 58102 +const RETURNING = 58103 +const ARRAY = 58104 +const WITHIN = 58105 +const PERCENTILE_CONT = 58106 +const PERCENTILE_DISC = 58107 +const ASOF = 58108 +const TOLERANCE = 58109 +const WINDOW = 58110 +const WINDOW_NAME_EMPTY = 58111 +const RESPECT = 58112 +const MEMBER = 58113 +const AUTO_ID_CACHE = 58114 var yyToknames = [...]string{ "$end", @@ -1429,6 +1430,10 @@ var yyToknames = [...]string{ "ROUTINE", "EVENT", "SHUTDOWN", + "CALLED", + "INPUT", + "SCALAR", + "VECTOR", "NULLX", "AUTO_INCREMENT", "APPROXNUM", @@ -1630,34774 +1635,4 @@ var yyToknames = [...]string{ "ROW_NUMBER", "DENSE_RANK", "CUME_DIST", - "BIT_CAST", - "LAG", - "LEAD", - "FIRST_VALUE", - "LAST_VALUE", - "NTH_VALUE", - "NTILE", - "PERCENT_RANK", - "BITMAP_BIT_POSITION", - "BITMAP_BUCKET_NUMBER", - "BITMAP_COUNT", - "BITMAP_CONSTRUCT_AGG", - "BITMAP_OR_AGG", - "JSON_ARRAYAGG", - "JSON_OBJECTAGG", - "GET_FORMAT", - "SRID", - "NEXTVAL", - "SETVAL", - "CURRVAL", - "LASTVAL", - "ROW", - "OUTFILE", - "HEADER", - "MAX_FILE_SIZE", - "FORCE_QUOTE", - "PARALLEL", - "STRICT", - "SPLITSIZE", - "UNUSED", - "BINDINGS", - "GENERATED", - "ALWAYS", - "STORED", - "VIRTUAL", - "DO", - "PERFORM", - "DECLARE", - "LOOP", - "WHILE", - "LEAVE", - "ITERATE", - "UNTIL", - "CALL", - "PREV", - "SLIDING", - "FILL", - "GAPFILL", - "SPBEGIN", - "BACKEND", - "SERVERS", - "HANDLER", - "PERCENT", - "SAMPLE", - "MO_TS", - "PITR", - "RECOVERY_WINDOW", - "INTERNAL", - "CDC_TASK_NAME", - "CDC", - "ICEBERG", - "CATALOG", - "CATALOGS", - "NAMESPACE", - "NAMESPACES", - "REF", - "FOR_ICEBERG", - "MONGODB", - "MONGODB_PATH", - "MONGODB_CONVERT", - "CONNECTIONS", - "DATASTREAM", - "ESQL", - "KAFKA", - "GROUPING", - "SETS", - "CUBE", - "ROLLUP", - "LOGSERVICE", - "REPLICAS", - "STORES", - "SETTINGS", - "DUMP", - "METADATA", - "KILL", - "BACKUP", - "FILESYSTEM", - "PARALLELISM", - "RESTORE", - "QUERY_RESULT", - "RETURNING", - "ARRAY", - "WITHIN", - "PERCENTILE_CONT", - "PERCENTILE_DISC", - "ASOF", - "TOLERANCE", - "WINDOW", - "WINDOW_NAME_EMPTY", - "RESPECT", - "MEMBER", - "AUTO_ID_CACHE", - "';'", - "'{'", - "'}'", - "':'", - "'@'", -} - -var yyStatenames = [...]string{} - -const yyEofCode = 1 -const yyErrCode = 2 -const yyInitialStackSize = 16 - -//line mysql_sql.y:16990 - -//line yacctab:1 -var yyExca = [...]int{ - -1, 1, - 1, -1, - -2, 0, - -1, 153, - 52, 765, - 286, 765, - 313, 772, - 314, 772, - 554, 765, - -2, 805, - -1, 173, - 17, 1016, - 30, 1016, - -2, 1002, - -1, 199, - 284, 1615, - 286, 1435, - -2, 1518, - -1, 276, - 789, 2606, - -2, 638, - -1, 666, - 789, 2734, - -2, 465, - -1, 726, - 789, 2795, - -2, 463, - -1, 727, - 789, 2796, - -2, 464, - -1, 728, - 789, 2797, - -2, 466, - -1, 882, - 549, 805, - 550, 805, - -2, 766, - -1, 954, - 365, 217, - 526, 217, - 527, 217, - -2, 2449, - -1, 1024, - 96, 2178, - -2, 2668, - -1, 1025, - 96, 2199, - -2, 2637, - -1, 1029, - 96, 2200, - -2, 2667, - -1, 1077, - 96, 2099, - -2, 2889, - -1, 1078, - 96, 2100, - -2, 2888, - -1, 1079, - 96, 2101, - -2, 2878, - -1, 1080, - 96, 2849, - -2, 2869, - -1, 1081, - 96, 2850, - -2, 2870, - -1, 1082, - 96, 2851, - -2, 2880, - -1, 1083, - 96, 2852, - -2, 2858, - -1, 1084, - 96, 2853, - -2, 2867, - -1, 1085, - 96, 2854, - -2, 2882, - -1, 1086, - 96, 2855, - -2, 2887, - -1, 1087, - 96, 2856, - -2, 2892, - -1, 1088, - 96, 2857, - -2, 2893, - -1, 1089, - 96, 2174, - -2, 2707, - -1, 1090, - 96, 2175, - -2, 2432, - -1, 1091, - 96, 2176, - -2, 2717, - -1, 1092, - 96, 2177, - -2, 2443, - -1, 1094, - 96, 2180, - -2, 2451, - -1, 1096, - 96, 2182, - -2, 2742, - -1, 1098, - 96, 2184, - -2, 2475, - -1, 1099, - 96, 2185, - -2, 2402, - -1, 1101, - 96, 2187, - -2, 2754, - -1, 1102, - 96, 2188, - -2, 2753, - -1, 1103, - 96, 2189, - -2, 2561, - -1, 1104, - 96, 2190, - -2, 2663, - -1, 1105, - 96, 2191, - -2, 2581, - -1, 1108, - 96, 2194, - -2, 2765, - -1, 1109, - 96, 2195, - -2, 2605, - -1, 1111, - 96, 2197, - -2, 2768, - -1, 1112, - 96, 2198, - -2, 2770, - -1, 1113, - 96, 2201, - -2, 2777, - -1, 1114, - 96, 2202, - -2, 2646, - -1, 1115, - 96, 2203, - -2, 2694, - -1, 1116, - 96, 2204, - -2, 2657, - -1, 1117, - 96, 2205, - -2, 2683, - -1, 1128, - 96, 2075, - -2, 2883, - -1, 1129, - 96, 2076, - -2, 2884, - -1, 1130, - 96, 2077, - -2, 2885, - -1, 1259, - 138, 2432, - 149, 2432, - 182, 2432, - -2, 2393, - -1, 1408, - 30, 1051, - -2, 978, - -1, 1613, - 17, 1016, - 30, 1016, - -2, 1914, - -1, 1715, - 30, 1051, - -2, 978, - -1, 2052, - 52, 765, - 286, 765, - 313, 772, - 314, 772, - 554, 765, - -2, 805, - -1, 2162, - 96, 2263, - -2, 2665, - -1, 2163, - 96, 2264, - -2, 2666, - -1, 2472, - 17, 1016, - 30, 1016, - -2, 1197, - -1, 2963, - 97, 1291, - -2, 1297, - -1, 2981, - 121, 1513, - 169, 1513, - 217, 1513, - 220, 1513, - 326, 1513, - -2, 1506, - -1, 2984, - 44, 1549, - -2, 1497, - -1, 3497, - 97, 2379, - 183, 2379, - -2, 2648, - -1, 3498, - 97, 2379, - 183, 2379, - -2, 2647, - -1, 3500, - 97, 2375, - 183, 2375, - -2, 2634, - -1, 3501, - 97, 2331, - 183, 2331, - -2, 2639, - -1, 3502, - 97, 2332, - 183, 2332, - -2, 2547, - -1, 3503, - 97, 2333, - 183, 2333, - -2, 2540, - -1, 3504, - 97, 2375, - 183, 2375, - -2, 2417, - -1, 3505, - 97, 2335, - 183, 2335, - -2, 2636, - -1, 3506, - 97, 2336, - 183, 2336, - -2, 2545, - -1, 3507, - 97, 2337, - 183, 2337, - -2, 2539, - -1, 3508, - 97, 2338, - 183, 2338, - -2, 2515, - -1, 3509, - 97, 2379, - 183, 2379, - -2, 2516, - -1, 3510, - 97, 2379, - 183, 2379, - -2, 2517, - -1, 3511, - 97, 2379, - 183, 2379, - -2, 2518, - -1, 3512, - 97, 2379, - 183, 2379, - -2, 2519, - -1, 3513, - 97, 2379, - 183, 2379, - -2, 2520, - -1, 3514, - 97, 2379, - 183, 2379, - -2, 2521, - -1, 3516, - 97, 2347, - 183, 2347, - -2, 2683, - -1, 3517, - 97, 2318, - 183, 2318, - -2, 2668, - -1, 3518, - 97, 2377, - 183, 2377, - -2, 2637, - -1, 3519, - 97, 2377, - 183, 2377, - -2, 2667, - -1, 3520, - 97, 2377, - 183, 2377, - -2, 2452, - -1, 3521, - 97, 2375, - 183, 2375, - -2, 2657, - -1, 3522, - 96, 2298, - 97, 2298, - 172, 2298, - 173, 2298, - 175, 2298, - 183, 2298, - -2, 2416, - -1, 3523, - 96, 2299, - 97, 2299, - 172, 2299, - 173, 2299, - 175, 2299, - 183, 2299, - -2, 2418, - -1, 3524, - 96, 2300, - 97, 2300, - 172, 2300, - 173, 2300, - 175, 2300, - 183, 2300, - -2, 2713, - -1, 3525, - 96, 2302, - 97, 2302, - 172, 2302, - 173, 2302, - 175, 2302, - 183, 2302, - -2, 2638, - -1, 3526, - 96, 2304, - 97, 2304, - 172, 2304, - 173, 2304, - 175, 2304, - 183, 2304, - -2, 2616, - -1, 3527, - 96, 2306, - 97, 2306, - 172, 2306, - 173, 2306, - 175, 2306, - 183, 2306, - -2, 2546, - -1, 3528, - 96, 2308, - 97, 2308, - 172, 2308, - 173, 2308, - 175, 2308, - 183, 2308, - -2, 2501, - -1, 3529, - 96, 2309, - 97, 2309, - 172, 2309, - 173, 2309, - 175, 2309, - 183, 2309, - -2, 2502, - -1, 3530, - 96, 2311, - 97, 2311, - 172, 2311, - 173, 2311, - 175, 2311, - 183, 2311, - -2, 2415, - -1, 3531, - 97, 2382, - 172, 2382, - 173, 2382, - 175, 2382, - 183, 2382, - -2, 2459, - -1, 3532, - 97, 2382, - 172, 2382, - 173, 2382, - 175, 2382, - 183, 2382, - -2, 2476, - -1, 3533, - 97, 2385, - 172, 2385, - 173, 2385, - 175, 2385, - 183, 2385, - -2, 2453, - -1, 3534, - 97, 2385, - 172, 2385, - 173, 2385, - 175, 2385, - 183, 2385, - -2, 2566, - -1, 3535, - 97, 2382, - 172, 2382, - 173, 2382, - 175, 2382, - 183, 2382, - -2, 2596, - -1, 3536, - 97, 2355, - 183, 2355, - -2, 2480, - -1, 3537, - 97, 2356, - 183, 2356, - -2, 2581, - -1, 3538, - 97, 2357, - 183, 2357, - -2, 2536, - -1, 3539, - 97, 2358, - 183, 2358, - -2, 2582, - -1, 3540, - 97, 2359, - 183, 2359, - -2, 2481, - -1, 3541, - 97, 2360, - 183, 2360, - -2, 2553, - -1, 3542, - 97, 2361, - 183, 2361, - -2, 2552, - -1, 3543, - 97, 2362, - 183, 2362, - -2, 2554, - -1, 3544, - 97, 2363, - 183, 2363, - -2, 2483, - -1, 3545, - 97, 2364, - 183, 2364, - -2, 2482, - -1, 3546, - 97, 2365, - 183, 2365, - -2, 2484, - -1, 3547, - 97, 2366, - 183, 2366, - -2, 2485, - -1, 3548, - 97, 2367, - 183, 2367, - -2, 2486, - -1, 3549, - 97, 2368, - 183, 2368, - -2, 2487, - -1, 3550, - 97, 2369, - 183, 2369, - -2, 2488, - -1, 3551, - 97, 2370, - 183, 2370, - -2, 2489, - -1, 3552, - 97, 2371, - 183, 2371, - -2, 2490, - -1, 3553, - 97, 2372, - 183, 2372, - -2, 2491, - -1, 3589, - 121, 1513, - 169, 1513, - 217, 1513, - 220, 1513, - 326, 1513, - -2, 1507, - -1, 3605, - 44, 1550, - -2, 1552, - -1, 3606, - 44, 1551, - -2, 1553, - -1, 3639, - 93, 871, - 183, 871, - -2, 1775, - -1, 4165, - 220, 1513, - 350, 1876, - -2, 1840, - -1, 4221, - 17, 1016, - 30, 1016, - -2, 1914, - -1, 4413, - 44, 1549, - 121, 1513, - 169, 1513, - 217, 1513, - 220, 1513, - -2, 1706, - -1, 4422, - 121, 1513, - 169, 1513, - 217, 1513, - 220, 1513, - -2, 1706, - -1, 4440, - 93, 871, - 183, 871, - -2, 1775, - -1, 4473, - 220, 1513, - 350, 1876, - -2, 1841, - -1, 4684, - 121, 1513, - 169, 1513, - 217, 1513, - 220, 1513, - -2, 1707, - -1, 4728, - 97, 1633, - 183, 1633, - -2, 1513, - -1, 4949, - 102, 1206, - -2, 2400, - -1, 4955, - 97, 1633, - 183, 1633, - -2, 1513, - -1, 5240, - 97, 1637, - 183, 1637, - -2, 1513, - -1, 5312, - 97, 1638, - 183, 1638, - -2, 1513, -} - -const yyPrivate = 57344 - -const yyLast = 89990 - -var yyAct = [...]int{ - 990, 5369, 5358, 965, 5422, 5388, 5354, 5361, 4946, 5337, - 264, 5406, 1992, 5378, 5353, 5250, 3690, 992, 5244, 4957, - 3823, 2141, 4514, 5188, 975, 5243, 4955, 4578, 5254, 3970, - 4195, 5112, 4176, 4022, 5177, 3206, 4268, 5019, 5255, 4763, - 1991, 4841, 4490, 1878, 4947, 3260, 3476, 3705, 4790, 4888, - 4024, 2979, 5036, 4573, 4269, 1652, 781, 2216, 4940, 4954, - 4266, 1497, 5078, 4958, 4388, 1895, 4673, 5189, 5191, 3708, - 3596, 1021, 4717, 1258, 803, 4918, 4586, 4524, 4396, 1504, - 3860, 2203, 3472, 4158, 1932, 4686, 820, 830, 4402, 840, - 2200, 4445, 840, 3074, 4163, 1894, 3416, 3391, 3642, 3390, - 251, 5, 4474, 4680, 3608, 4093, 1472, 1265, 3474, 4702, - 3597, 2144, 4348, 4092, 4074, 967, 4656, 1267, 171, 1468, - 3598, 4249, 3253, 3384, 2473, 2998, 2599, 3822, 4078, 4386, - 3824, 2596, 917, 3721, 249, 2443, 1896, 3789, 4160, 1451, - 4191, 4423, 4170, 3679, 3819, 3673, 3299, 2466, 3492, 1414, - 834, 16, 4218, 3484, 3677, 2648, 908, 3671, 2094, 2770, - 16, 3443, 4338, 2199, 3575, 3810, 4056, 4043, 957, 912, - 2222, 4054, 3201, 4169, 1871, 3088, 4095, 4094, 4105, 2002, - 3004, 958, 3019, 3007, 2337, 1175, 4090, 2999, 832, 38, - 3590, 1980, 1975, 1800, 2923, 1768, 1908, 1984, 38, 4002, - 238, 820, 1219, 962, 2813, 3233, 826, 2653, 2766, 3490, - 2922, 3212, 2592, 3563, 3557, 3298, 3176, 2765, 3696, 3075, - 2487, 3078, 3611, 2474, 3646, 2613, 3018, 892, 4, 2475, - 1798, 3053, 3645, 260, 7, 781, 2467, 2981, 1331, 835, - 32, 3002, 2406, 259, 6, 1965, 2996, 2217, 820, 32, - 3723, 2136, 2005, 1933, 1880, 2767, 3009, 1887, 1717, 2740, - 3006, 966, 802, 2809, 264, 1856, 264, 1850, 1321, 1322, - 2971, 956, 1842, 2210, 2925, 2449, 820, 2433, 2178, 976, - 2127, 1997, 1649, 1449, 2974, 1249, 26, 1432, 1252, 2093, - 2015, 958, 2670, 905, 1940, 2397, 836, 44, 245, 1812, - 1486, 1817, 1274, 2401, 1852, 1251, 44, 2135, 1805, 1855, - 1139, 2405, 1454, 1218, 1140, 1743, 1840, 2427, 1801, 1138, - 244, 1136, 2223, 1507, 914, 250, 1482, 915, 1508, 3177, - 1141, 821, 86, 5338, 237, 1216, 54, 42, 1300, 1799, - 911, 78, 1198, 1211, 780, 877, 2745, 154, 81, 5, - 839, 29, 87, 80, 27, 28, 19, 10, 1269, 5063, - 2479, 1653, 1576, 76, 1577, 1575, 1576, 1135, 1577, 1575, - 1318, 1576, 964, 1577, 1575, 4914, 4282, 3440, 3440, 4013, - 3440, 4443, 831, 17, 2454, 2458, 2459, 2460, 2455, 2465, - 2456, 2462, 17, 4130, 2457, 4012, 2463, 3875, 1317, 16, - 1319, 833, 15, 2365, 3874, 2782, 1744, 1415, 4636, 4405, - 1416, 15, 812, 4261, 16, 3332, 16, 3239, 3237, 810, - 3236, 3234, 1745, 2354, 1947, 806, 807, 1943, 1314, 1313, - 248, 808, 3417, 4833, 4139, 3385, 2886, 38, 2997, 4446, - 1271, 809, 844, 3261, 805, 2921, 1415, 1738, 3252, 1464, - 1465, 1466, 38, 1854, 38, 1695, 5166, 1463, 2454, 2458, - 2459, 2460, 2455, 2465, 2456, 2462, 2695, 2140, 2457, 2006, - 2463, 1462, 3644, 5090, 4287, 2729, 3694, 1312, 1912, 2733, - 1314, 2734, 7, 1828, 1314, 1772, 4421, 2696, 32, 1603, - 3207, 1609, 6, 4014, 2927, 4620, 2011, 4010, 3178, 2937, - 2361, 1747, 3988, 32, 1132, 32, 3985, 1606, 1608, 1602, - 5349, 1607, 1589, 1588, 1598, 1599, 1600, 1601, 1591, 1592, - 1593, 1594, 1595, 1596, 1597, 1590, 1524, 9, 1604, 2348, - 2917, 1354, 1726, 1945, 4571, 3855, 2454, 2458, 2459, 2460, - 2455, 2465, 2456, 2462, 2833, 44, 2457, 3853, 2463, 3995, - 3993, 2658, 1264, 4755, 1960, 963, 1603, 1262, 1609, 3986, - 44, 3983, 44, 5252, 5251, 1162, 4275, 1159, 1263, 1266, - 5031, 4849, 4842, 4574, 1606, 1608, 1602, 4267, 1607, 1589, - 1588, 1598, 1599, 1600, 1601, 1591, 1592, 1593, 1594, 1595, - 1596, 1597, 1590, 5194, 3997, 1604, 2454, 2458, 2459, 2460, - 2455, 2465, 2456, 2462, 1076, 3001, 2457, 1576, 2463, 1577, - 1575, 2446, 1137, 2345, 1132, 2454, 2458, 2459, 2460, 2455, - 2465, 2456, 2462, 1647, 3948, 2457, 4041, 2463, 3152, 2677, - 2722, 17, 1576, 3117, 1577, 1575, 5393, 5046, 5345, 4625, - 4860, 2067, 4857, 5043, 1150, 2009, 17, 4900, 17, 4377, - 15, 3365, 2944, 4623, 1455, 5124, 1909, 1753, 1751, 1750, - 4372, 4044, 2961, 2201, 2202, 15, 2008, 15, 1372, 1373, - 1334, 1163, 1160, 1460, 1276, 1461, 3943, 910, 2548, 1794, - 5104, 946, 3817, 2975, 948, 2780, 3197, 1572, 1354, 947, - 2374, 1362, 1366, 1368, 1370, 1375, 2372, 1380, 1376, 1377, - 1378, 1379, 3829, 3830, 1357, 1358, 1359, 1360, 1332, 1333, - 1363, 2587, 1335, 3859, 1336, 1338, 1339, 1340, 1341, 1337, - 1342, 1343, 1344, 1345, 1346, 1353, 1355, 1347, 1348, 1349, - 1350, 1351, 1352, 1381, 1382, 1383, 1384, 1385, 1386, 1387, - 1388, 1390, 1389, 1391, 1392, 1393, 1394, 1395, 1396, 1397, - 1398, 1365, 1367, 1369, 1371, 1374, 1151, 3198, 2609, 2576, - 2577, 3987, 946, 3984, 4902, 948, 2085, 1760, 1157, 946, - 947, 3828, 948, 3184, 2575, 1459, 3183, 947, 3158, 3185, - 2379, 2380, 3157, 201, 246, 200, 233, 202, 3311, 3310, - 1494, 1163, 1356, 1160, 4180, 5310, 1946, 1944, 1552, 4455, - 1123, 1553, 1122, 1124, 1125, 820, 1126, 1127, 3559, 4021, - 1520, 1505, 1506, 1521, 2128, 820, 2258, 2132, 3560, 1857, - 820, 1859, 1418, 3254, 901, 1372, 1373, 1334, 2143, 1555, - 2563, 1503, 3998, 4178, 2109, 1502, 1505, 1506, 5258, 5259, - 1565, 2131, 840, 840, 1446, 5198, 820, 820, 1362, 1366, - 1368, 1370, 1375, 2461, 1380, 1376, 1377, 1378, 1379, 239, - 1570, 1357, 1358, 1359, 1360, 1332, 1333, 1363, 3558, 1335, - 1324, 1336, 1338, 1339, 1340, 1341, 1337, 1342, 1343, 1344, - 1345, 1346, 1353, 1355, 1347, 1348, 1349, 1350, 1351, 1352, - 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1390, 1389, - 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1365, 1367, - 1369, 1371, 1374, 1161, 1523, 1158, 201, 246, 200, 233, - 202, 1409, 2083, 1261, 5198, 5294, 1260, 2461, 1237, 5197, - 3040, 1408, 2459, 2460, 5196, 3471, 2893, 2064, 1501, 3467, - 1498, 5195, 1498, 5197, 5293, 5288, 4868, 1269, 5034, 1356, - 1410, 3861, 1737, 1835, 1550, 5210, 820, 5196, 5292, 5195, - 5291, 5179, 2364, 5182, 5062, 1474, 4859, 5340, 5341, 4845, - 2133, 5037, 5038, 5039, 5040, 1622, 1471, 3862, 4270, 3863, - 4913, 1615, 4294, 3905, 1480, 3439, 1416, 2781, 3996, 2147, - 2375, 1490, 239, 4627, 2130, 4270, 2373, 3283, 1416, 5179, - 1510, 1511, 1913, 1513, 1514, 2461, 1838, 1516, 3866, 1829, - 3469, 5074, 1416, 1773, 3464, 1419, 1551, 2784, 3743, 2593, - 3171, 4291, 2697, 1418, 1492, 2583, 3876, 1154, 2123, 1271, - 3873, 1422, 1426, 4070, 1429, 2818, 2744, 5257, 4387, 4015, - 2928, 2776, 1428, 3566, 1435, 1438, 4665, 247, 3160, 201, - 246, 1416, 2969, 4394, 3602, 201, 246, 200, 233, 202, - 2607, 2608, 3901, 3811, 1314, 2461, 2084, 2704, 1314, 1314, - 817, 1314, 4904, 4905, 3481, 1568, 1569, 4503, 1314, 1532, - 1314, 4715, 5212, 3324, 2461, 2464, 4624, 1269, 2062, 3899, - 2783, 3468, 3433, 4068, 4142, 3465, 1563, 1564, 1554, 1567, - 3604, 230, 1155, 1204, 1230, 1228, 4699, 1229, 1545, 3115, - 1522, 1547, 1540, 3802, 2129, 1439, 1440, 1779, 5023, 4572, - 3261, 3151, 1364, 3154, 3854, 3595, 3162, 1264, 4867, 2546, - 4910, 239, 1407, 4662, 3153, 1233, 4869, 4621, 1656, 1548, - 4075, 1777, 4064, 1263, 2147, 1605, 2062, 4065, 4066, 4421, - 2146, 2145, 3163, 3164, 1740, 1742, 5085, 1746, 1411, 2464, - 5086, 5089, 5088, 4067, 4076, 1745, 3442, 3174, 1745, 1271, - 1488, 1489, 812, 1764, 1562, 3599, 801, 1767, 2058, 810, - 247, 2586, 4533, 1156, 1776, 806, 807, 4988, 4858, 4182, - 2010, 808, 1444, 1445, 4193, 4194, 1483, 1487, 1487, 1487, - 4192, 809, 3235, 1515, 4389, 3994, 1518, 1519, 1238, 5066, - 2683, 1928, 1605, 820, 820, 820, 1752, 1749, 1219, 4529, - 4891, 1525, 1526, 1483, 1483, 1509, 1827, 1948, 1512, 4690, - 4637, 820, 1137, 1834, 1529, 3470, 1841, 2464, 4411, 3466, - 820, 1456, 4255, 1712, 781, 781, 1716, 1505, 1506, 4089, - 1531, 3562, 4106, 4626, 781, 781, 1715, 1623, 1882, 1882, - 1234, 820, 2547, 4951, 1541, 5108, 1329, 949, 950, 951, - 952, 953, 5092, 4062, 4903, 3612, 4930, 1719, 4352, 1364, - 4354, 2983, 1425, 1427, 1437, 1436, 1505, 1506, 838, 1164, - 1543, 840, 1493, 803, 1778, 842, 4076, 2464, 1417, 1936, - 841, 3815, 1884, 1546, 1549, 2146, 2145, 4184, 2977, 4185, - 4187, 4186, 4509, 247, 4003, 264, 2464, 5079, 3605, 247, - 1759, 4515, 1236, 5137, 781, 2956, 1542, 1153, 5113, 1557, - 4177, 3710, 1558, 4629, 4630, 4631, 2792, 2794, 2795, 4188, - 4522, 4366, 1617, 1618, 1619, 1620, 1621, 1481, 949, 950, - 951, 952, 953, 4897, 79, 949, 950, 951, 952, 953, - 1560, 4645, 2153, 2157, 2158, 4363, 1836, 2788, 2790, 2791, - 1889, 4034, 3150, 2154, 1770, 1771, 4535, 4534, 1774, 1905, - 1906, 5073, 1782, 1784, 1785, 1786, 1787, 4751, 1789, 5416, - 3706, 3707, 1793, 3710, 1839, 1668, 1669, 3128, 3607, 2461, - 1988, 3601, 4197, 4076, 1203, 1993, 3127, 1139, 1544, 4365, - 4589, 3170, 2155, 1442, 1479, 1207, 2007, 1208, 3148, 3149, - 4071, 838, 3572, 1329, 201, 246, 200, 233, 202, 2594, - 1876, 1877, 2078, 2059, 3565, 201, 246, 200, 233, 202, - 1722, 4198, 2033, 4740, 1723, 902, 5211, 1264, 1232, 3812, - 3902, 2063, 1710, 4952, 1867, 1816, 4746, 2065, 1866, 2062, - 4906, 2036, 1720, 1263, 1530, 16, 4931, 4183, 1711, 1478, - 3081, 1748, 2776, 1496, 1495, 2000, 3773, 1882, 1477, 3744, - 5114, 3745, 3746, 1841, 4919, 1556, 5242, 79, 830, 3569, - 3570, 1430, 4666, 4085, 4159, 2584, 4317, 2003, 2124, 1657, - 239, 5192, 829, 38, 3568, 4960, 3435, 3118, 1806, 2108, - 5054, 828, 5055, 4424, 3073, 1996, 1841, 4569, 1769, 2066, - 910, 2117, 2117, 1498, 1841, 1561, 1841, 1841, 1781, 3098, - 5176, 1853, 1861, 1863, 3055, 3057, 4063, 1882, 1755, 1882, - 1418, 904, 1874, 1875, 903, 1998, 1610, 1559, 4349, 1537, - 1804, 1977, 1978, 1811, 32, 1925, 1807, 1808, 5381, 1231, - 838, 4222, 1892, 1783, 1226, 1899, 1893, 4193, 4194, 1983, - 4432, 1227, 1987, 4202, 1865, 2079, 1955, 1986, 1757, 4449, - 2070, 2073, 2074, 2077, 1890, 3320, 3189, 1898, 1966, 3090, - 1612, 1611, 2112, 3156, 2041, 3073, 3092, 2099, 2091, 2092, - 3113, 2926, 1266, 1907, 2773, 2582, 1979, 2570, 812, 5056, - 1994, 44, 1949, 1882, 2107, 2101, 2102, 2110, 2111, 1766, - 3606, 3213, 3214, 1788, 3453, 4196, 79, 4547, 2982, 3609, - 2019, 1418, 2220, 2793, 2023, 2024, 1780, 2114, 1937, 3080, - 1938, 1923, 4238, 4224, 3082, 2957, 3904, 1615, 2271, 1919, - 4086, 1792, 5052, 3091, 1536, 2261, 2262, 2263, 1791, 2156, - 1790, 5054, 804, 5055, 2789, 1239, 4959, 846, 2277, 2001, - 845, 2278, 3796, 4380, 2113, 2785, 2786, 2252, 2253, 5048, - 3090, 2257, 2120, 2045, 4754, 1169, 3073, 3092, 247, 2272, - 4189, 3084, 2299, 2300, 824, 825, 5241, 17, 3083, 247, - 2562, 4297, 2279, 1206, 2281, 2356, 2282, 2283, 2284, 2056, - 815, 2021, 816, 4295, 5382, 1193, 15, 2025, 2119, 1220, - 3087, 3741, 2332, 2810, 2031, 4747, 4748, 4339, 4742, 1192, - 4449, 2089, 4741, 2289, 2291, 2290, 1418, 3056, 2552, 2550, - 2050, 201, 246, 2551, 3091, 1982, 3281, 2139, 2366, 1173, - 1139, 2561, 2369, 1269, 1171, 1170, 4281, 820, 820, 820, - 5056, 3774, 3776, 3777, 3778, 3775, 2384, 2386, 1815, 2387, - 3461, 2390, 2391, 3097, 2948, 2394, 2051, 3095, 803, 2398, - 2049, 2047, 2343, 2402, 2159, 1882, 2408, 2409, 1754, 2411, - 1841, 2089, 2100, 2089, 820, 2048, 2039, 1882, 2044, 2038, - 2043, 2037, 1763, 820, 2090, 2106, 1483, 2382, 2335, 2255, - 2095, 1219, 2097, 2098, 2444, 2121, 2122, 239, 2333, 2096, - 1487, 2288, 2469, 2469, 1827, 2469, 2042, 2105, 1769, 2480, - 2481, 820, 820, 1487, 2545, 1271, 4433, 1844, 2402, 2556, - 3880, 2338, 2080, 2081, 4356, 2040, 1172, 1882, 2567, 2568, - 2116, 2118, 2342, 1827, 3085, 781, 902, 201, 246, 2383, - 2134, 1981, 2357, 5379, 5380, 2138, 1176, 2204, 4280, 781, - 246, 1882, 2950, 2949, 201, 246, 200, 233, 202, 1222, - 1223, 1224, 2180, 3454, 4009, 1963, 2947, 1958, 1964, 1961, - 1962, 1756, 1758, 5049, 1761, 1762, 2497, 5190, 2711, 2708, - 2362, 2014, 1967, 1968, 1969, 1970, 1971, 1972, 3604, 2381, - 1165, 2625, 2627, 3140, 1166, 820, 2402, 1882, 2499, 2634, - 1275, 820, 908, 908, 4703, 2398, 4190, 5022, 2641, 838, - 2643, 2644, 2645, 239, 2716, 2717, 2649, 5418, 201, 246, - 838, 2020, 1269, 264, 2086, 239, 264, 264, 2412, 264, - 239, 4245, 904, 1240, 3640, 903, 1845, 2410, 2437, 1286, - 5463, 1235, 2017, 2854, 2358, 5186, 2554, 2853, 2392, 2393, - 2471, 2016, 2477, 2176, 2177, 2399, 2400, 2572, 2346, 2194, - 2195, 2270, 5462, 2198, 5164, 2610, 2413, 2414, 2415, 2434, - 201, 246, 2426, 2285, 2286, 79, 2647, 2341, 1574, 2344, - 3619, 2615, 2616, 2973, 2137, 247, 79, 1843, 2602, 2603, - 2692, 4244, 1473, 2703, 2436, 2062, 2142, 2685, 201, 246, - 2017, 2017, 1473, 2017, 1271, 246, 1264, 201, 246, 2016, - 2016, 2334, 2016, 4240, 1537, 2336, 2579, 2588, 2581, 2089, - 2396, 2689, 1263, 5447, 5049, 2667, 1574, 781, 5050, 2600, - 2601, 2089, 4661, 1574, 2630, 2355, 5445, 2359, 2910, 820, - 2636, 2444, 2363, 820, 2558, 1268, 2691, 4414, 1574, 4277, - 2726, 1268, 2728, 3487, 1844, 1901, 2732, 2657, 4116, 2595, - 2660, 2661, 2571, 2663, 2737, 2738, 2739, 2633, 2772, 2743, - 1574, 1841, 2681, 16, 239, 2425, 16, 16, 2611, 16, - 239, 2089, 2435, 239, 3764, 3765, 3179, 2218, 5453, 3488, - 3489, 5437, 3641, 2559, 5433, 5429, 2439, 2440, 2428, 2445, - 1841, 247, 2432, 2428, 2441, 2089, 892, 1882, 2769, 1574, - 902, 38, 4335, 247, 38, 38, 2972, 38, 247, 1473, - 2126, 2553, 1574, 2573, 2164, 2165, 2166, 2167, 2168, 2169, - 2170, 2171, 2172, 2173, 2174, 2175, 2557, 2698, 2565, 2032, - 2753, 5403, 201, 246, 2196, 2197, 1169, 4293, 4129, 4245, - 2578, 2089, 2580, 2674, 2589, 2029, 2030, 2727, 3112, 3048, - 2730, 2731, 32, 3048, 2735, 32, 32, 5431, 32, 1576, - 2221, 1577, 1575, 1845, 2797, 2256, 2720, 5103, 2747, 2748, - 5430, 5430, 247, 2772, 201, 246, 2620, 5400, 2750, 2751, - 2619, 2736, 2350, 1275, 2646, 2637, 2638, 5397, 2280, 2631, - 2639, 2705, 2706, 2624, 2632, 2755, 904, 3319, 2618, 903, - 1168, 1713, 1802, 2712, 2654, 1171, 1170, 1574, 239, 44, - 5395, 5390, 44, 44, 1843, 44, 3763, 5404, 3940, 3048, - 1999, 1537, 2407, 1576, 247, 1577, 1575, 2682, 3641, 2686, - 2758, 4205, 4203, 5375, 2421, 3978, 2760, 2672, 2762, 3579, - 3585, 3586, 3587, 3580, 3584, 3581, 3583, 3582, 2763, 4151, - 239, 2017, 247, 2687, 4148, 4050, 5329, 2125, 247, 2243, - 2016, 247, 1576, 5401, 1577, 1575, 4245, 5314, 1537, 2690, - 1269, 5274, 5273, 5398, 5272, 2864, 3975, 2709, 2867, 2707, - 2869, 2901, 2752, 2710, 2566, 2713, 2899, 2876, 1144, 1145, - 1146, 1147, 1308, 1309, 1310, 17, 2778, 5391, 17, 17, - 2889, 17, 2715, 1576, 4047, 1577, 1575, 1142, 1576, 4001, - 1577, 1575, 2719, 1576, 15, 1577, 1575, 15, 15, 5315, - 15, 3979, 1144, 1145, 1146, 1147, 2772, 1307, 2929, 2930, - 1304, 2932, 2933, 3625, 3436, 2936, 3319, 1534, 1167, 5267, - 2742, 1142, 5330, 820, 1841, 820, 1841, 5260, 1535, 838, - 2746, 2089, 1271, 5315, 2137, 2647, 2951, 5275, 1574, 1868, - 1574, 3258, 3976, 2958, 2959, 5238, 957, 2902, 2771, 5138, - 820, 820, 2900, 1904, 3200, 2970, 2764, 2816, 1713, 2574, - 5135, 3081, 3084, 2759, 820, 820, 820, 3067, 2892, 2894, - 2895, 2896, 2920, 2898, 2749, 2775, 247, 2907, 2906, 2908, - 2756, 2863, 1576, 2757, 1577, 1575, 5102, 3005, 3005, 3011, - 2796, 1487, 2909, 3081, 3084, 79, 3020, 1827, 1827, 1827, - 1827, 1827, 1827, 1827, 1827, 2778, 5096, 2862, 1535, 2811, - 2861, 2798, 2180, 2828, 2830, 2718, 2803, 2180, 247, 2469, - 4764, 4765, 4766, 4770, 4768, 4769, 4771, 4772, 4773, 4774, - 4767, 5239, 4979, 2820, 2827, 2778, 4978, 1148, 1469, 5013, - 2292, 3939, 1470, 2295, 2296, 2297, 2828, 3104, 2301, 2302, - 2303, 2304, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, - 2315, 2316, 2317, 2318, 2319, 1576, 2239, 1577, 1575, 2771, - 3059, 1148, 5103, 2236, 3296, 4975, 2605, 2238, 2235, 2237, - 2241, 2242, 2941, 2569, 2943, 2240, 1576, 4974, 1577, 1575, - 4973, 1810, 1574, 201, 246, 200, 233, 202, 1301, 1302, - 1303, 1306, 1174, 1305, 4972, 1269, 2799, 2800, 4971, 2207, - 4827, 2804, 2805, 1576, 1882, 1577, 1575, 4449, 2778, 4953, - 820, 2117, 2778, 3111, 2826, 3085, 1576, 4916, 1577, 1575, - 3080, 3073, 3079, 4443, 3076, 3082, 4885, 1576, 4882, 1577, - 1575, 781, 781, 4722, 4721, 3669, 3068, 4436, 3936, 1418, - 3845, 2912, 2913, 3643, 3624, 1882, 820, 3085, 3449, 1139, - 1424, 2828, 3080, 3073, 3079, 3322, 3076, 3082, 3008, 239, - 3321, 4647, 3412, 2828, 201, 246, 2828, 2065, 2915, 3208, - 3209, 3282, 2965, 4646, 2931, 2905, 820, 1271, 2935, 3083, - 2828, 803, 4542, 4393, 2828, 3168, 2824, 2849, 1936, 2832, - 2761, 3224, 2714, 3226, 4825, 4471, 264, 4470, 4466, 2652, - 2990, 2360, 2666, 2828, 3070, 3072, 3071, 2962, 3093, 3094, - 4460, 3083, 1574, 4457, 3016, 1275, 3021, 4430, 4328, 4723, - 3016, 3219, 3155, 2246, 2247, 2248, 2249, 2250, 2251, 2244, - 2245, 4324, 3005, 3005, 3267, 1144, 1145, 1146, 1147, 4213, - 239, 3278, 4111, 3927, 2012, 3047, 3871, 4151, 1631, 1441, - 1404, 3186, 1399, 3187, 1656, 3288, 3869, 3012, 3013, 4148, - 2815, 2814, 3629, 3627, 2989, 3077, 3621, 3410, 2062, 2994, - 3294, 3397, 3192, 3193, 3297, 3300, 2435, 2435, 3041, 3389, - 3302, 2801, 2802, 4471, 4467, 1882, 2806, 2807, 3180, 3022, - 3023, 3024, 3025, 3026, 3027, 3028, 4151, 3077, 4540, 4148, - 3361, 3362, 3316, 1574, 4329, 2769, 3046, 3355, 3334, 1953, - 1952, 3291, 1882, 1484, 1882, 3211, 2604, 4325, 1590, 1418, - 4134, 3249, 3247, 3066, 3245, 4214, 3243, 3333, 3622, 1574, - 3229, 3896, 3628, 5093, 1380, 1376, 1377, 1378, 1379, 3049, - 3015, 3360, 3622, 3359, 3358, 3356, 16, 247, 3630, 3628, - 1269, 2911, 3622, 1574, 2872, 3262, 2871, 1574, 2204, 2852, - 2843, 3354, 2842, 2841, 2829, 1574, 2777, 2104, 1882, 1418, - 2559, 1612, 1611, 3368, 2026, 2388, 3169, 3175, 4107, 5094, - 3181, 4595, 4564, 5419, 38, 4704, 3369, 4932, 3293, 1872, - 3377, 5405, 3295, 3910, 1574, 1882, 3307, 3016, 4427, 3195, - 1873, 4425, 3312, 3196, 1148, 1517, 3306, 3250, 3248, 3199, - 3244, 3363, 3244, 3008, 2389, 1870, 3313, 3314, 1610, 1861, - 1863, 1610, 5402, 1435, 1438, 3048, 3016, 3234, 247, 3357, - 5399, 4705, 1271, 5344, 3413, 32, 1485, 2910, 3378, 2564, - 1574, 3223, 1574, 3216, 4428, 1574, 1574, 4426, 1574, 1574, - 2828, 3303, 2778, 3317, 3284, 3285, 5064, 3286, 3287, 2655, - 2027, 4108, 1612, 1611, 1429, 1612, 1611, 1469, 3444, 3446, - 1469, 1470, 3887, 3263, 1470, 3451, 2260, 2259, 3455, 4933, - 3255, 5005, 2260, 2259, 5004, 820, 820, 820, 4915, 2075, - 3266, 3276, 44, 3265, 1439, 1591, 1592, 1593, 1594, 1595, - 1596, 1597, 1590, 4853, 3256, 1418, 3554, 4109, 3259, 4594, - 1469, 3392, 3383, 1882, 1470, 3387, 1841, 3398, 959, 4823, - 3290, 1869, 4788, 1841, 2556, 4934, 4744, 3348, 4743, 3351, - 3386, 3325, 4669, 3005, 3330, 3415, 3393, 2071, 3419, 3305, - 3421, 3422, 3304, 3366, 4437, 3429, 1593, 1594, 1595, 1596, - 1597, 1590, 4404, 2191, 4246, 4236, 3343, 3636, 3639, 4227, - 3318, 5231, 4215, 3323, 4153, 4150, 2089, 4080, 2089, 2188, - 2190, 2187, 3805, 2189, 3804, 3631, 3626, 3430, 17, 4259, - 3577, 3617, 1421, 1423, 3441, 3331, 3289, 3191, 838, 1827, - 2934, 1827, 2701, 2700, 2305, 3494, 2699, 15, 3632, 3633, - 2298, 3675, 3681, 3335, 3336, 3353, 2022, 3591, 3338, 3339, - 1469, 1418, 2076, 2018, 1470, 1657, 3364, 1796, 1795, 3613, - 3700, 1420, 1576, 3315, 1577, 1575, 3345, 3228, 3711, 1418, - 4446, 3713, 3714, 3715, 1418, 1418, 1418, 2117, 5230, 5098, - 1418, 3726, 4026, 3727, 3728, 2211, 3729, 2821, 3731, 3732, - 2186, 3594, 1802, 4023, 79, 5, 3479, 2211, 1469, 3726, - 2072, 1803, 1470, 1437, 1436, 3846, 2183, 2185, 2182, 5290, - 2184, 2497, 2469, 1576, 3573, 1577, 1575, 1576, 4758, 1577, - 1575, 3592, 4026, 1941, 4262, 2655, 3786, 4941, 3238, 1576, - 5279, 1577, 1575, 2499, 4884, 1803, 3684, 2429, 4260, 1576, - 4883, 1577, 1575, 781, 1575, 16, 1882, 3428, 1882, 1576, - 4733, 1577, 1575, 1577, 1575, 2556, 3692, 4757, 3347, 1418, - 1418, 3341, 4023, 3342, 2426, 1576, 4112, 1577, 1575, 1576, - 1882, 1577, 1575, 1941, 3431, 3432, 1803, 3733, 3230, 3716, - 3826, 3730, 3703, 38, 1576, 3701, 1577, 1575, 3376, 3806, - 4732, 820, 1633, 2993, 3576, 3571, 1418, 5157, 5158, 3842, - 4025, 5266, 3600, 1827, 3616, 1632, 1576, 2089, 1577, 1575, - 3929, 264, 2845, 3791, 3615, 1942, 264, 3202, 3203, 2137, - 1315, 1316, 5226, 3635, 3638, 1320, 5155, 5156, 7, 3808, - 5161, 3651, 3652, 5160, 32, 3328, 3649, 3650, 6, 5415, - 3634, 5159, 1936, 5317, 5009, 5010, 3555, 3556, 4670, 4671, - 4663, 3424, 3661, 3425, 3699, 3270, 3867, 3666, 3667, 3668, - 3662, 3603, 5154, 3878, 3663, 3269, 2275, 3683, 3686, 3797, - 1576, 5153, 1577, 1575, 3695, 3928, 3698, 3300, 3697, 3697, - 3702, 2276, 3914, 3697, 2844, 2218, 3494, 1576, 5152, 1577, - 1575, 44, 3827, 3719, 5151, 1576, 2825, 1577, 1575, 2004, - 1882, 4397, 1576, 3898, 1577, 1575, 5414, 3843, 2823, 3110, - 4391, 1576, 4664, 1577, 1575, 3116, 5150, 3813, 3119, 3120, - 3121, 3122, 3123, 3124, 3125, 3126, 3868, 3844, 3129, 3130, - 3131, 3132, 3133, 3134, 3135, 3136, 3137, 3138, 3139, 5149, - 3141, 3142, 3143, 3144, 3145, 3847, 3146, 5147, 3760, 3747, - 3851, 5146, 5145, 5144, 3800, 5143, 5247, 5142, 5140, 5139, - 3785, 16, 1576, 3809, 1577, 1575, 16, 5095, 3473, 4982, - 3783, 3165, 4392, 3167, 3372, 4963, 1576, 17, 1577, 1575, - 3881, 3781, 3883, 1576, 3834, 1577, 1575, 3831, 1576, 5371, - 1577, 1575, 3379, 3888, 3882, 3972, 15, 3885, 3886, 38, - 3890, 3891, 2204, 3840, 38, 3841, 3836, 1581, 1582, 1583, - 1584, 1585, 1586, 1587, 1579, 3892, 3770, 2836, 3849, 3848, - 2407, 3495, 3784, 4007, 2089, 4935, 3991, 5121, 4909, 5372, - 4011, 3803, 3782, 4876, 4881, 4016, 4843, 820, 1841, 4753, - 4707, 4706, 3889, 3780, 4516, 4429, 4028, 4030, 4031, 4033, - 32, 4035, 4036, 3932, 1576, 32, 1577, 1575, 4390, 4373, - 1576, 3835, 1577, 1575, 3944, 3900, 3946, 1418, 3949, 3950, - 3895, 4069, 3879, 3951, 3952, 3953, 3954, 3955, 3769, 3956, - 3957, 3958, 3959, 3960, 3961, 3962, 3963, 3858, 3965, 3966, - 3967, 3968, 3884, 3857, 3973, 3794, 5370, 3977, 4609, 3980, - 3981, 3768, 3767, 3766, 4607, 3758, 3752, 44, 3894, 3751, - 3750, 4598, 44, 5412, 3749, 3748, 1576, 3864, 1577, 1575, - 3926, 3908, 3437, 3907, 3909, 1576, 4403, 1577, 1575, 1273, - 77, 1576, 3920, 1577, 1575, 3292, 3251, 3188, 1576, 77, - 1577, 1575, 4058, 4060, 2919, 3712, 3922, 3923, 993, 1003, - 2723, 3717, 3718, 4073, 2089, 2676, 3722, 2675, 994, 820, - 995, 999, 1002, 998, 996, 997, 4051, 2673, 2669, 2668, - 4597, 2622, 2371, 2368, 4088, 2013, 1418, 1736, 4055, 5394, - 820, 1402, 820, 2556, 3919, 5392, 3921, 4000, 1418, 4907, - 4908, 1418, 5373, 17, 4579, 5342, 4019, 1576, 17, 1577, - 1575, 4596, 5308, 3005, 5298, 4120, 3005, 4110, 5237, 4123, - 4513, 4124, 15, 5207, 4313, 4005, 837, 15, 5205, 4004, - 4303, 1827, 3020, 4889, 4133, 3050, 1000, 5174, 1576, 5076, - 1577, 1575, 4674, 5070, 3982, 3825, 3825, 1576, 5061, 1577, - 1575, 1576, 1401, 1577, 1575, 4084, 3941, 1576, 4096, 1577, - 1575, 1076, 5059, 3675, 5041, 3591, 5032, 1001, 3934, 3681, - 4126, 1576, 4997, 1577, 1575, 4996, 4987, 4986, 3990, 4077, - 3104, 4962, 3495, 1576, 1418, 1577, 1575, 4167, 4961, 4167, - 4171, 3273, 4171, 4171, 3275, 1576, 3933, 1577, 1575, 3274, - 3989, 1864, 1977, 1978, 1269, 4912, 4896, 5456, 1418, 1133, - 4894, 4880, 4844, 4737, 1983, 3930, 4736, 1987, 4735, 4061, - 3594, 4206, 1986, 1576, 3411, 1577, 1575, 4678, 4667, 5455, - 1882, 1882, 4087, 4652, 4651, 4649, 4199, 2338, 4642, 4119, - 1966, 4640, 1576, 4122, 1577, 1575, 4619, 4618, 4617, 4613, - 4612, 1576, 3409, 1577, 1575, 4131, 4583, 1979, 1598, 1599, - 1600, 1601, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1590, - 4083, 4581, 4577, 4207, 4208, 4165, 4179, 4181, 820, 1576, - 4575, 1577, 1575, 4553, 4102, 4550, 1271, 4104, 77, 4164, - 3561, 4101, 4058, 4118, 4544, 4115, 3008, 4113, 1882, 4121, - 2426, 3790, 4385, 77, 4375, 77, 4358, 4128, 1841, 4340, - 3408, 2556, 2556, 4201, 4132, 5438, 4311, 4308, 5386, 1133, - 4149, 3406, 4276, 4152, 4234, 4233, 5384, 4230, 4229, 4166, - 3405, 4168, 4216, 4211, 3404, 5232, 3368, 1576, 4210, 1577, - 1575, 4231, 4147, 4081, 4263, 4200, 4045, 4037, 1576, 4027, - 1577, 1575, 4154, 4156, 3072, 3071, 4017, 1576, 4008, 1577, - 1575, 1576, 4006, 1577, 1575, 4172, 4173, 1589, 1588, 1598, - 1599, 1600, 1601, 1591, 1592, 1593, 1594, 1595, 1596, 1597, - 1590, 2924, 3403, 3906, 3603, 4204, 3903, 5116, 3877, 4174, - 3856, 3833, 3402, 3798, 3913, 820, 3795, 5042, 3792, 2856, - 3917, 3918, 4220, 3779, 3771, 3761, 3759, 3755, 4117, 1576, - 3754, 1577, 1575, 3401, 3753, 3655, 4301, 4212, 4886, 1576, - 4243, 1577, 1575, 4247, 3480, 3462, 3450, 4304, 3438, 1578, - 3400, 3268, 3739, 3740, 3399, 1076, 1075, 1614, 3257, 5134, - 1576, 3217, 1577, 1575, 2952, 2939, 2938, 1625, 3756, 3757, - 4217, 2787, 2680, 4048, 2679, 4241, 4242, 1576, 4226, 1577, - 1575, 1576, 4225, 1577, 1575, 4232, 4239, 2671, 4228, 4235, - 2404, 2370, 4155, 1635, 2367, 2353, 4273, 2352, 2115, 4283, - 3396, 3801, 4285, 4286, 3395, 5132, 4279, 3807, 3394, 4288, - 1664, 1660, 1659, 4875, 4284, 1406, 3388, 1152, 4874, 5367, - 3444, 4343, 4862, 5365, 3373, 3444, 4345, 1576, 2649, 1577, - 1575, 1576, 4856, 1577, 1575, 1576, 4650, 1577, 1575, 4616, - 4359, 4602, 4361, 1576, 5366, 1577, 1575, 4367, 5364, 3675, - 3681, 1576, 4591, 1577, 1575, 246, 200, 233, 202, 4545, - 4434, 1418, 4422, 1962, 3367, 4290, 2260, 2259, 4355, 3344, - 201, 246, 4420, 4289, 1967, 1968, 1969, 1970, 1971, 1972, - 4413, 4336, 4318, 4368, 4334, 4320, 820, 2556, 4296, 4331, - 4330, 1576, 4312, 1577, 1575, 4327, 1576, 2705, 1577, 1575, - 4412, 4326, 4314, 4310, 4307, 4265, 4264, 4254, 2904, 1005, - 173, 4418, 4248, 4140, 4127, 2903, 4049, 4046, 3999, 173, - 3937, 4332, 2314, 2897, 3924, 4362, 3916, 4364, 2866, 3915, - 239, 1724, 3912, 4383, 4384, 1576, 3670, 1577, 1575, 2469, - 1827, 4440, 1576, 3246, 1577, 1575, 239, 5454, 2444, 4379, - 1576, 3494, 1577, 1575, 4451, 1576, 3242, 1577, 1575, 3675, - 3241, 3300, 3681, 2865, 4462, 3240, 4401, 1418, 2206, 3205, - 4468, 4220, 3204, 1418, 4448, 2991, 4278, 4341, 4415, 4350, - 2877, 4342, 4337, 4347, 2870, 4167, 4344, 813, 2860, 2859, - 1576, 2858, 1577, 1575, 2857, 1576, 173, 1577, 1575, 2855, - 2992, 5130, 2851, 2850, 4370, 4374, 4369, 2848, 2839, 4381, - 4410, 4378, 2835, 1418, 1418, 2834, 4539, 2754, 2678, 4419, - 1882, 2325, 2323, 2322, 2321, 4398, 2320, 246, 200, 233, - 202, 4400, 2274, 2273, 2264, 4548, 246, 1903, 5452, 5410, - 5408, 3691, 4442, 5385, 5374, 5304, 5303, 5302, 4441, 820, - 5278, 2556, 4435, 5271, 5269, 1827, 1418, 5167, 5120, 1654, - 5115, 4497, 5026, 4541, 4439, 5025, 4565, 5024, 4995, 4504, - 203, 264, 3692, 4525, 4526, 4527, 4528, 4970, 4964, 1134, - 4787, 4778, 4333, 4447, 4756, 4750, 4438, 1935, 4724, 4708, - 4523, 4520, 4518, 4511, 4510, 4507, 4506, 4505, 4585, 4406, - 4357, 4353, 239, 4561, 4456, 4459, 4464, 4458, 4309, 4143, - 4137, 239, 1982, 1985, 1957, 1976, 1973, 1959, 1954, 4042, - 909, 4039, 4038, 3964, 3925, 3793, 4554, 4512, 3787, 3704, - 3620, 3614, 3610, 1813, 3434, 3215, 3190, 3147, 3033, 3014, - 4530, 2964, 2963, 2918, 2808, 2181, 239, 4538, 1650, 1270, - 4536, 2693, 2478, 2438, 2349, 2060, 1974, 1735, 173, 3603, - 3603, 4557, 4543, 1714, 2444, 4546, 4549, 4632, 1139, 1709, - 4551, 4638, 1708, 173, 4552, 173, 4588, 4644, 4556, 4558, - 4634, 1707, 1706, 4560, 837, 837, 4559, 837, 4555, 1134, - 1705, 1704, 1703, 1702, 1701, 1700, 1699, 1698, 1697, 1696, - 1695, 4584, 1694, 1693, 3603, 4570, 1692, 4580, 1691, 1690, - 1689, 1688, 1687, 4582, 1686, 1685, 1684, 1418, 1882, 1882, - 4601, 16, 4679, 4603, 1683, 1418, 4606, 1682, 4608, 4610, - 1681, 1680, 1679, 4604, 1678, 1677, 1676, 4600, 1675, 1674, - 1673, 4599, 1672, 1418, 1671, 1670, 1667, 4710, 1666, 1665, - 4103, 1663, 1662, 1661, 1658, 1651, 4641, 4720, 4643, 38, - 1648, 4676, 2082, 4709, 1647, 4614, 1646, 1645, 1644, 1643, - 1642, 1641, 1640, 4622, 4675, 1639, 1418, 1638, 1637, 1636, - 1630, 4654, 1418, 1629, 1628, 1627, 4635, 4685, 2103, 1626, - 1539, 1500, 1403, 5127, 4681, 1882, 4685, 4714, 4508, 4628, - 4677, 3647, 3648, 2741, 2980, 1447, 5411, 5321, 4655, 5319, - 32, 4658, 5256, 4223, 820, 3799, 1418, 1418, 1418, 3578, - 3210, 1418, 1418, 4668, 2997, 4691, 1538, 1467, 3045, 1418, - 4141, 1418, 3031, 3658, 4682, 4693, 4701, 3495, 4687, 4688, - 4700, 4781, 4698, 3030, 4683, 3043, 4716, 3044, 3659, 4442, - 4784, 3657, 4786, 3660, 4780, 4712, 4713, 3038, 4826, 4775, - 3656, 4727, 3039, 2149, 2150, 2151, 2152, 44, 3653, 4497, - 4726, 3042, 3029, 4760, 4761, 4762, 4738, 4504, 4776, 4777, - 3036, 4164, 4839, 4840, 4725, 3037, 4731, 4730, 3034, 82, - 5187, 4835, 5045, 3035, 4145, 5044, 5017, 4831, 5446, 1882, - 2698, 1882, 5442, 1882, 4146, 4562, 4729, 4431, 3870, 3623, - 1797, 2208, 2423, 2424, 4079, 2212, 2213, 2214, 2215, 3061, - 4822, 4417, 4611, 1614, 1824, 4161, 2254, 4162, 4870, 4829, - 3114, 4877, 4878, 1498, 820, 2265, 2418, 2419, 2420, 3974, - 3063, 3062, 4852, 3838, 4854, 4531, 4855, 4250, 4890, 4469, - 4892, 4828, 3735, 17, 4382, 4144, 4563, 4252, 4253, 2537, - 3736, 3737, 3738, 2293, 2294, 3618, 4251, 811, 1950, 1999, - 1142, 4846, 15, 2204, 1802, 4830, 3329, 4851, 3202, 3203, - 5235, 2946, 2945, 1995, 1225, 2954, 4893, 1999, 4895, 4537, - 3722, 2324, 2953, 2326, 2327, 2328, 2329, 2330, 2640, 2549, - 1533, 4925, 5165, 2339, 4967, 4921, 4648, 4097, 4053, 4861, - 818, 4052, 4863, 3685, 4871, 4847, 4872, 3271, 4873, 5236, - 3603, 3065, 2988, 2442, 2395, 5334, 1936, 2260, 2259, 4720, - 4720, 4936, 3825, 5305, 4944, 4948, 4966, 4592, 4898, 1733, - 1734, 1731, 1732, 4590, 4517, 4209, 4519, 1729, 1730, 2204, - 1727, 1728, 3172, 3166, 4917, 3161, 3060, 4911, 4923, 4899, - 2560, 1528, 1527, 4920, 4689, 1566, 3872, 2702, 2193, 4938, - 4924, 1144, 1145, 1146, 1147, 3665, 1268, 1499, 1142, 5285, - 2955, 2069, 4588, 1476, 1475, 4926, 1458, 4928, 1142, 1418, - 1142, 1499, 2431, 2725, 4660, 3327, 5283, 5216, 1418, 5184, - 5183, 4942, 4943, 4659, 3326, 5181, 5080, 5027, 4782, 4605, - 4939, 4576, 4568, 4454, 4453, 4272, 4271, 1718, 3099, 4981, - 3086, 1902, 4567, 4257, 3945, 1215, 3407, 1473, 5323, 5322, - 4937, 5228, 5229, 5322, 4965, 1882, 4639, 4360, 5014, 5289, - 4346, 4323, 3893, 3457, 5020, 3456, 4976, 1588, 1598, 1599, - 1600, 1601, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1590, - 2339, 3448, 4977, 3447, 3222, 2339, 2339, 3218, 2837, 2148, - 1443, 1412, 1311, 5323, 77, 4752, 5307, 5306, 5011, 1144, - 1145, 1146, 1147, 5225, 1268, 5015, 5016, 5234, 5223, 5221, - 3477, 2614, 3475, 2218, 5060, 4983, 4657, 2914, 1990, 1268, - 818, 5053, 5065, 1144, 1145, 1146, 1147, 5435, 5436, 5460, - 5461, 5072, 5309, 5107, 2192, 4322, 814, 5028, 1491, 3825, - 91, 2, 5347, 5348, 1, 4407, 4408, 4409, 3992, 2916, - 2656, 2347, 1725, 2659, 173, 173, 2662, 173, 1270, 2664, - 5067, 3340, 5068, 1143, 5047, 5051, 1858, 813, 3182, 1589, - 1588, 1598, 1599, 1600, 1601, 1591, 1592, 1593, 1594, 1595, - 1596, 1597, 1590, 2606, 5029, 1589, 1588, 1598, 1599, 1600, - 1601, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1590, 5057, - 5058, 1418, 1886, 837, 2351, 5110, 1149, 837, 837, 3603, - 5069, 5075, 2218, 2218, 2218, 3051, 5082, 2218, 2218, 5141, - 5084, 5091, 5081, 837, 3052, 2142, 1418, 2142, 3664, 5097, - 3054, 5100, 5101, 1498, 2623, 1453, 3463, 2774, 3814, 3159, - 2968, 4072, 1814, 1882, 5163, 5109, 1221, 5148, 2266, 1434, - 2028, 5118, 1433, 1431, 2209, 2287, 1007, 5171, 5125, 3000, - 3788, 3762, 4450, 5333, 4734, 5387, 5277, 5168, 5169, 5105, - 5336, 2684, 2055, 991, 5175, 4274, 3865, 5033, 5281, 5126, - 5128, 5129, 5131, 5133, 5035, 5172, 5162, 4850, 2779, 1571, - 4114, 872, 1053, 1019, 2688, 3947, 3942, 5206, 1613, 1018, - 4395, 3567, 5021, 5193, 4929, 873, 2665, 5030, 4848, 4789, - 1951, 1956, 5173, 3064, 1882, 4821, 4950, 5111, 5180, 5178, - 4728, 4157, 3709, 1989, 5199, 5201, 5136, 4521, 5203, 4866, - 4864, 4865, 3971, 5018, 4948, 4832, 5208, 916, 2585, 779, - 4779, 5200, 5202, 5204, 5240, 2995, 2243, 5213, 5077, 4969, - 1882, 1191, 4376, 2978, 1184, 3337, 5214, 5218, 5217, 5215, - 3589, 3588, 5219, 2160, 1580, 2179, 4315, 4316, 1624, 961, - 2819, 3564, 4491, 5227, 3832, 90, 89, 88, 5233, 1589, - 1588, 1598, 1599, 1600, 1601, 1591, 1592, 1593, 1594, 1595, - 1596, 1597, 1590, 5248, 272, 5020, 1010, 5261, 271, 4887, - 5262, 4672, 5263, 5170, 5264, 988, 987, 986, 5265, 985, - 984, 983, 2452, 2451, 2453, 2450, 2817, 2448, 2447, 1821, - 2822, 1820, 4256, 4566, 3220, 3221, 3725, 4532, 2831, 3720, - 2489, 2485, 5268, 1849, 2486, 3089, 3101, 2484, 5253, 5284, - 4298, 5286, 5287, 5282, 5280, 5276, 2838, 1418, 3603, 1589, - 1588, 1598, 1599, 1600, 1601, 1591, 1592, 1593, 1594, 1595, - 1596, 1597, 1590, 1134, 5295, 4593, 5296, 2840, 5122, 5123, - 4749, 1721, 3772, 5297, 4587, 2847, 2417, 3096, 2505, 3742, - 5301, 2502, 2501, 3734, 4745, 2218, 4739, 2534, 5087, 5357, - 5222, 5360, 5224, 4697, 2142, 4696, 5352, 5312, 5313, 5220, - 3972, 5311, 4695, 4461, 3680, 2868, 5332, 4694, 5316, 2271, - 2873, 2874, 2875, 4684, 5320, 2878, 2879, 2880, 2881, 2882, - 2883, 2884, 2885, 5318, 2887, 2888, 5339, 2890, 2891, 5328, - 4472, 1418, 4473, 5355, 5355, 5355, 1418, 4480, 1361, 2987, - 5359, 5362, 5331, 5343, 5346, 5193, 1330, 1325, 1327, 1328, - 1326, 3352, 5350, 4237, 5351, 1825, 5363, 3069, 4091, 3486, - 3485, 3483, 5110, 5377, 5376, 3482, 1775, 5383, 5389, 5324, - 5325, 5326, 5327, 2239, 5071, 5209, 4653, 3493, 3491, 1457, - 2236, 2061, 2057, 1448, 2238, 2235, 2237, 2241, 2242, 1400, - 3010, 4020, 2240, 1891, 1741, 5407, 1900, 5407, 5396, 1739, - 3654, 4824, 3032, 813, 2612, 4948, 3837, 1822, 5409, 1819, - 4138, 1818, 1299, 5413, 1298, 2617, 1272, 240, 1897, 241, - 172, 1131, 2271, 4351, 4416, 3816, 3173, 2535, 3272, 5355, - 5423, 5420, 5355, 5423, 5425, 5355, 5423, 5426, 5359, 5339, - 5428, 5362, 5427, 5421, 173, 3674, 4901, 2422, 1185, 1405, - 2976, 5432, 5389, 5434, 5439, 126, 5417, 48, 145, 1215, - 125, 5443, 5444, 219, 1413, 2537, 69, 5449, 5451, 218, - 68, 20, 143, 217, 67, 53, 52, 2218, 215, 121, - 120, 119, 118, 142, 5458, 214, 66, 3058, 256, 255, - 1450, 1452, 258, 257, 254, 5457, 3231, 5459, 3232, 253, - 1939, 252, 2142, 5185, 4692, 5270, 51, 50, 220, 49, - 127, 4956, 70, 47, 46, 2724, 4040, 2068, 4371, 3478, - 2960, 2512, 77, 45, 40, 77, 77, 14, 77, 2224, - 2225, 2226, 2227, 2228, 2229, 2230, 2231, 2232, 2233, 2234, - 2246, 2247, 2248, 2249, 2250, 2251, 2244, 2245, 12, 43, - 41, 25, 24, 173, 2034, 23, 31, 173, 173, 30, - 4927, 13, 39, 37, 201, 246, 200, 233, 202, 1830, - 1831, 36, 1833, 173, 164, 1837, 163, 1846, 1847, 1848, - 35, 162, 161, 160, 2046, 159, 158, 157, 2339, 156, - 2339, 226, 34, 22, 837, 837, 61, 60, 59, 58, - 1573, 57, 2528, 56, 8, 4444, 837, 139, 149, 2339, - 2339, 148, 150, 146, 141, 138, 33, 140, 1910, 1911, - 136, 137, 1914, 1915, 1916, 1917, 1918, 130, 1920, 1921, - 1922, 837, 1924, 4785, 1927, 129, 1929, 1930, 1931, 128, - 239, 122, 102, 101, 1076, 100, 2035, 115, 114, 113, - 112, 111, 4984, 4985, 110, 108, 1935, 109, 871, 4989, - 4990, 4991, 4992, 4993, 4994, 99, 98, 97, 4998, 4999, - 5000, 5001, 5002, 5003, 96, 95, 135, 134, 131, 5006, - 5007, 5008, 117, 124, 123, 106, 5012, 1589, 1588, 1598, - 1599, 1600, 1601, 1591, 1592, 1593, 1594, 1595, 1596, 1597, - 1590, 2516, 116, 107, 105, 104, 103, 94, 3277, 93, - 3280, 4783, 2522, 92, 133, 132, 147, 221, 71, 198, - 197, 196, 195, 5299, 194, 192, 193, 191, 190, 189, - 188, 187, 2510, 2544, 186, 62, 2511, 2513, 2515, 63, - 2517, 2518, 2519, 2523, 2524, 2525, 2527, 2530, 2531, 2532, - 64, 65, 210, 209, 211, 223, 222, 2520, 2529, 2521, - 213, 3308, 3309, 216, 1613, 1589, 1588, 1598, 1599, 1600, - 1601, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1590, 212, - 207, 205, 208, 206, 204, 5083, 1589, 1588, 1598, 1599, - 1600, 1601, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1590, - 1354, 83, 11, 144, 21, 18, 3, 2142, 5106, 5448, - 5450, 2536, 3825, 5368, 0, 0, 0, 0, 199, 231, - 243, 232, 0, 151, 0, 0, 0, 5119, 247, 0, - 3346, 3938, 0, 3350, 0, 0, 0, 0, 0, 0, - 0, 0, 2052, 225, 224, 3370, 3371, 0, 0, 0, - 0, 0, 0, 0, 3374, 3375, 0, 1215, 1215, 1809, - 0, 0, 0, 0, 0, 0, 0, 179, 0, 0, - 3380, 3381, 3382, 0, 0, 1832, 0, 0, 0, 0, - 0, 2533, 0, 0, 1851, 1589, 1588, 1598, 1599, 1600, - 1601, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1590, 2508, - 0, 0, 0, 2507, 0, 1888, 0, 0, 0, 3418, - 0, 3420, 0, 0, 3423, 0, 2149, 0, 0, 2339, - 0, 0, 0, 0, 0, 0, 0, 2526, 173, 0, - 0, 0, 2201, 2202, 0, 173, 2514, 1372, 1373, 1334, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2472, 0, 0, 0, 0, 0, 0, - 1362, 1366, 1368, 1370, 1375, 0, 1380, 1376, 1377, 1378, - 1379, 0, 0, 1357, 1358, 1359, 1360, 3349, 1333, 1363, - 0, 1335, 1825, 1336, 1338, 1339, 1340, 1341, 1337, 1342, - 1343, 1344, 1345, 1346, 1353, 1355, 1347, 1348, 1349, 1350, - 1351, 1352, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, - 1390, 1389, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, - 1365, 1367, 1369, 1371, 1374, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2621, 0, 0, - 0, 3931, 0, 0, 2535, 0, 0, 0, 0, 2495, - 0, 0, 2543, 0, 0, 0, 0, 0, 0, 0, - 0, 1356, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 173, 0, 0, 173, 173, 0, 173, 0, - 0, 0, 2537, 2504, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2538, 2539, 1589, 1588, 1598, 1599, 1600, - 1601, 1591, 1592, 1593, 1594, 1595, 1596, 1597, 1590, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2503, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 173, 0, 0, 79, 0, 0, 2512, 0, - 0, 0, 0, 0, 173, 173, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 173, 0, 928, 927, - 934, 924, 0, 0, 0, 0, 2053, 242, 2054, 0, - 0, 931, 932, 0, 933, 937, 0, 0, 918, 0, - 0, 173, 0, 0, 0, 0, 0, 0, 942, 2339, - 0, 0, 0, 0, 0, 0, 2812, 0, 0, 0, - 2509, 0, 0, 0, 0, 0, 0, 0, 0, 2614, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2528, - 1589, 1588, 1598, 1599, 1600, 1601, 1591, 1592, 1593, 1594, - 1595, 1596, 1597, 1590, 0, 77, 946, 0, 0, 948, - 0, 0, 0, 3850, 947, 3852, 0, 0, 0, 0, - 0, 0, 0, 2628, 2629, 0, 0, 0, 0, 0, - 2635, 0, 0, 0, 169, 0, 0, 0, 0, 2642, - 1935, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 837, 837, 0, - 837, 837, 0, 0, 0, 0, 0, 837, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2491, 2496, 2494, - 0, 1613, 0, 2488, 0, 0, 0, 0, 2516, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2522, - 0, 0, 0, 0, 0, 0, 0, 2506, 0, 2490, - 0, 0, 0, 0, 0, 2694, 0, 0, 0, 2510, - 2544, 0, 0, 2511, 2513, 2515, 3911, 2517, 2518, 2519, - 2523, 2524, 2525, 2527, 2530, 2531, 2532, 0, 0, 0, - 0, 0, 0, 0, 2520, 2529, 2521, 0, 0, 0, - 0, 0, 0, 0, 0, 3935, 2498, 0, 0, 0, - 0, 1364, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2376, 2377, 2378, 0, 0, 0, 0, 0, 0, - 0, 919, 921, 920, 0, 0, 0, 0, 0, 0, - 0, 3969, 0, 926, 0, 0, 0, 0, 2536, 0, - 0, 0, 0, 0, 0, 930, 0, 0, 2416, 0, - 0, 0, 945, 0, 0, 0, 0, 2430, 0, 923, - 0, 0, 0, 913, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2482, 2483, 0, 0, 0, - 2492, 2493, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2533, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2508, 0, 0, 0, - 2507, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1329, 0, 0, 0, 0, - 0, 0, 0, 0, 2526, 0, 0, 0, 1354, 0, - 0, 0, 0, 2514, 0, 0, 0, 173, 0, 1452, - 0, 0, 173, 0, 0, 1452, 1270, 2541, 2540, 173, - 173, 0, 0, 0, 0, 0, 1825, 1825, 1825, 1825, - 1825, 1825, 1825, 1825, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 77, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 925, 929, 935, 0, 936, 938, - 0, 0, 939, 940, 941, 0, 0, 0, 943, 944, - 0, 0, 0, 0, 2500, 0, 0, 0, 0, 2339, - 0, 0, 0, 0, 0, 2339, 0, 0, 0, 0, - 4125, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 4135, 0, 0, 4136, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2542, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1372, 1373, 1334, 0, 0, - 1354, 1323, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1450, 0, 0, 0, 2721, 1362, 1366, - 1368, 1370, 1375, 4175, 1380, 1376, 1377, 1378, 1379, 0, - 0, 1357, 1358, 1359, 1360, 1332, 1333, 1363, 0, 1335, - 0, 1336, 1338, 1339, 1340, 1341, 1337, 1342, 1343, 1344, - 1345, 1346, 1353, 1355, 1347, 1348, 1349, 1350, 1351, 1352, - 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1390, 1389, - 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1365, 1367, - 1369, 1371, 1374, 0, 922, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 173, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4219, 0, 0, 0, 0, 0, 0, 1356, - 77, 0, 0, 0, 0, 77, 0, 2509, 0, 0, - 0, 1270, 949, 950, 951, 952, 953, 1372, 1373, 1334, - 0, 0, 0, 0, 0, 0, 0, 173, 173, 0, - 173, 173, 0, 0, 0, 0, 0, 173, 0, 0, - 1362, 1366, 1368, 1370, 1375, 0, 1380, 1376, 1377, 1378, - 1379, 0, 0, 1357, 1358, 1359, 1360, 1332, 1333, 1363, - 0, 1335, 0, 1336, 1338, 1339, 1340, 1341, 1337, 1342, - 1343, 1344, 1345, 1346, 1353, 1355, 1347, 1348, 1349, 1350, - 1351, 1352, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, - 1390, 1389, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, - 1365, 1367, 1369, 1371, 1374, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 4302, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 4305, 4306, - 0, 1356, 0, 0, 0, 2535, 0, 0, 0, 0, - 2495, 0, 0, 2543, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4319, 0, 0, 4321, 0, - 0, 0, 0, 2537, 2504, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2538, 2539, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2940, 0, 2942, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2503, 0, 0, 0, 201, 246, 200, 233, 202, 0, - 0, 0, 0, 0, 2966, 2967, 0, 0, 0, 2512, - 0, 4219, 0, 0, 234, 0, 0, 0, 2984, 2985, - 2986, 226, 0, 0, 0, 235, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 203, 0, - 0, 0, 0, 0, 0, 170, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 155, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 239, 0, 0, 0, 173, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2528, 0, 0, 0, 0, 0, 0, 0, 0, 1364, - 0, 0, 0, 0, 173, 0, 0, 0, 0, 0, - 0, 0, 928, 927, 934, 924, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 931, 932, 0, 933, 937, - 0, 0, 918, 0, 0, 0, 0, 0, 1825, 0, - 1825, 0, 942, 0, 0, 0, 0, 0, 2535, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 180, 181, 0, 182, 183, 0, 0, 0, 184, 0, - 0, 185, 0, 0, 1851, 0, 0, 0, 3688, 3689, - 2494, 0, 0, 0, 3687, 0, 2537, 0, 1576, 2516, - 1577, 1575, 0, 0, 0, 0, 0, 2339, 0, 0, - 2522, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1888, 0, 0, 0, 0, 2339, 0, 0, 0, 0, - 2510, 2544, 0, 0, 2511, 2513, 2515, 0, 2517, 2518, - 2519, 2523, 2524, 2525, 2527, 2530, 2531, 2532, 0, 0, - 1452, 1364, 2512, 1329, 0, 2520, 2529, 2521, 199, 231, - 243, 232, 84, 151, 0, 0, 0, 2498, 247, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2535, - 0, 0, 153, 225, 224, 0, 0, 201, 246, 85, - 2243, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 179, 0, 2536, - 0, 0, 0, 0, 4615, 0, 0, 2537, 0, 0, - 0, 0, 1825, 0, 0, 0, 0, 0, 0, 4922, - 173, 0, 0, 2528, 152, 173, 0, 0, 3604, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 227, 228, 229, 0, 0, 0, 0, 0, 0, 0, - 0, 2492, 2493, 239, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2512, 0, 919, 921, 920, 0, 2533, - 0, 0, 0, 0, 0, 0, 0, 926, 0, 0, - 0, 0, 0, 0, 0, 1329, 0, 2508, 0, 930, - 0, 2507, 0, 0, 0, 0, 945, 0, 0, 0, - 0, 0, 0, 923, 0, 0, 4711, 0, 0, 0, - 0, 0, 0, 0, 0, 2526, 236, 0, 1635, 0, - 837, 0, 2516, 0, 2514, 0, 0, 0, 0, 0, - 0, 0, 0, 2522, 0, 0, 0, 165, 2541, 2540, - 0, 230, 0, 166, 2528, 0, 0, 0, 0, 0, - 0, 0, 0, 2510, 2544, 0, 0, 2511, 2513, 2515, - 0, 2517, 2518, 2519, 2523, 2524, 2525, 2527, 2530, 2531, - 2532, 0, 0, 0, 0, 2535, 0, 0, 2520, 2529, - 2521, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2500, 0, 0, 0, 167, - 0, 0, 0, 0, 0, 0, 0, 2239, 0, 0, - 0, 0, 75, 2537, 2236, 0, 0, 0, 2238, 2235, - 2237, 2241, 2242, 0, 0, 0, 2240, 0, 0, 0, - 0, 0, 2536, 0, 0, 0, 4834, 0, 2542, 0, - 0, 247, 0, 2516, 0, 0, 3605, 0, 0, 3458, - 3459, 3460, 0, 0, 2522, 0, 0, 0, 925, 929, - 935, 0, 936, 938, 0, 79, 939, 940, 941, 2512, - 0, 860, 943, 944, 2510, 2544, 0, 0, 2511, 2513, - 2515, 0, 2517, 2518, 2519, 2523, 2524, 2525, 2527, 2530, - 2531, 2532, 0, 0, 0, 0, 177, 242, 178, 2520, - 2529, 2521, 2533, 0, 0, 0, 0, 0, 0, 0, - 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, - 2508, 0, 3637, 0, 2507, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 856, 857, 0, 2526, 0, - 2528, 0, 0, 2536, 0, 0, 902, 2514, 0, 0, - 0, 0, 0, 2224, 2225, 2226, 2227, 2228, 2229, 2230, - 2231, 2232, 2233, 2234, 2246, 2247, 2248, 2249, 2250, 2251, - 2244, 2245, 0, 0, 1935, 1270, 0, 173, 2509, 0, - 0, 0, 0, 168, 169, 55, 0, 0, 0, 0, - 0, 73, 0, 0, 0, 0, 9, 0, 0, 0, - 0, 173, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2533, 0, 4968, 0, 0, 922, 0, - 1825, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 74, 2508, 174, 175, 0, 2507, 176, 0, 0, 2516, - 0, 0, 904, 0, 0, 903, 0, 0, 0, 0, - 2522, 0, 0, 0, 0, 0, 0, 0, 0, 2526, - 0, 0, 0, 0, 0, 173, 0, 0, 2514, 0, - 2510, 2544, 0, 0, 2511, 2513, 2515, 0, 2517, 2518, - 2519, 2523, 2524, 2525, 2527, 2530, 2531, 2532, 0, 0, - 77, 0, 0, 0, 0, 2520, 2529, 2521, 0, 889, - 0, 0, 0, 0, 0, 3839, 0, 0, 0, 861, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 4499, 0, 0, 0, 0, 0, 4478, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 863, 0, 3606, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2536, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 4492, 0, - 0, 0, 0, 4221, 0, 0, 860, 0, 0, 0, - 0, 0, 4481, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 4475, 0, 0, 0, 0, 4501, 4502, - 5099, 0, 0, 0, 4476, 0, 0, 0, 0, 0, - 0, 2509, 0, 885, 0, 887, 884, 0, 0, 2533, - 888, 0, 0, 5117, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2508, 0, 0, - 0, 2507, 0, 4477, 0, 4484, 0, 0, 0, 173, - 856, 857, 0, 0, 0, 0, 0, 0, 0, 0, - 173, 902, 0, 0, 0, 2526, 883, 0, 0, 0, - 0, 0, 0, 0, 2514, 0, 0, 0, 855, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 862, - 897, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 893, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 2509, 0, 0, 0, 0, 0, 1295, 0, - 4795, 0, 0, 0, 0, 0, 0, 894, 898, 848, - 0, 4018, 0, 0, 1207, 0, 1208, 904, 0, 0, - 903, 0, 0, 0, 0, 0, 0, 4500, 880, 3079, - 878, 882, 901, 0, 5245, 0, 879, 876, 874, 5249, - 881, 865, 866, 864, 4816, 854, 867, 868, 869, 870, - 849, 0, 0, 899, 4488, 900, 1189, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 895, 896, 0, 0, - 1202, 0, 1197, 2980, 889, 0, 4485, 4489, 4487, 4486, - 0, 0, 4221, 1296, 861, 0, 4794, 0, 0, 0, - 0, 0, 173, 173, 0, 0, 0, 0, 0, 0, - 4795, 0, 0, 0, 891, 0, 0, 0, 0, 0, - 0, 863, 0, 850, 0, 0, 0, 0, 0, 0, - 0, 0, 886, 0, 0, 0, 0, 0, 0, 875, - 0, 0, 0, 4082, 4495, 4496, 0, 173, 0, 0, - 0, 1178, 0, 0, 4816, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4098, 0, 4099, 0, 0, 0, - 0, 5245, 0, 0, 0, 0, 0, 0, 0, 1825, - 0, 0, 0, 1289, 0, 1281, 1285, 1287, 0, 0, - 0, 0, 0, 0, 0, 0, 4794, 0, 885, 0, - 887, 884, 0, 0, 0, 888, 0, 0, 2509, 0, - 0, 1292, 0, 0, 0, 1284, 0, 4503, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 890, 0, - 4479, 0, 0, 4494, 858, 859, 0, 0, 847, 851, - 0, 1204, 0, 1196, 5245, 0, 852, 0, 0, 0, - 0, 883, 1201, 1199, 0, 0, 0, 853, 0, 0, - 0, 0, 0, 855, 0, 0, 1290, 0, 0, 0, - 0, 0, 0, 1190, 862, 897, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 4791, 1293, 0, - 0, 0, 0, 0, 1825, 1294, 893, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 173, 0, 1206, 0, 0, 0, 0, 1195, 0, 0, - 0, 1194, 0, 0, 0, 0, 0, 1183, 0, 0, - 0, 0, 894, 898, 0, 0, 0, 0, 0, 0, - 1282, 0, 0, 0, 0, 0, 1188, 0, 5441, 0, - 0, 0, 1452, 880, 0, 878, 882, 901, 0, 0, - 0, 879, 876, 874, 1291, 881, 865, 866, 864, 0, - 854, 867, 868, 869, 870, 849, 0, 0, 899, 1205, - 900, 0, 0, 0, 0, 0, 0, 4791, 4796, 4797, - 0, 895, 896, 0, 1200, 0, 0, 0, 1186, 0, - 0, 0, 1283, 0, 0, 4792, 4793, 4221, 4800, 4799, - 4798, 4814, 4815, 4817, 4801, 4802, 4805, 4807, 4806, 4803, - 4804, 4808, 4810, 4811, 4812, 4809, 0, 4813, 0, 891, - 0, 0, 0, 4818, 0, 0, 0, 1205, 850, 0, - 4820, 0, 0, 0, 4819, 0, 4493, 886, 0, 0, - 0, 0, 0, 0, 875, 0, 0, 0, 0, 0, - 1187, 4498, 0, 173, 0, 0, 0, 0, 0, 4292, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1288, 0, 0, 0, 4796, 4797, - 0, 0, 0, 0, 0, 0, 0, 0, 4482, 4483, - 0, 0, 0, 0, 0, 4792, 4793, 0, 4800, 4799, - 4798, 4814, 4815, 4817, 4801, 4802, 4805, 4807, 4806, 4803, - 4804, 4808, 4810, 4811, 4812, 4809, 0, 4813, 1278, 0, - 0, 0, 0, 4818, 0, 0, 0, 0, 0, 0, - 4820, 0, 1203, 890, 4819, 0, 0, 0, 0, 858, - 859, 0, 0, 847, 851, 0, 0, 0, 0, 0, - 0, 852, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 853, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1182, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1297, - 1452, 0, 0, 1277, 1279, 0, 0, 0, 0, 0, - 0, 1280, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1179, 0, 0, - 0, 1177, 1180, 0, 0, 0, 0, 0, 0, 1181, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 173, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1452, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 341, 342, 343, 1099, 345, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 201, 246, 1026, 0, - 0, 0, 0, 0, 0, 0, 0, 506, 0, 0, - 650, 684, 673, 762, 637, 0, 0, 0, 0, 0, - 0, 977, 0, 0, 0, 400, 0, 0, 469, 688, - 669, 680, 670, 512, 655, 656, 657, 664, 412, 658, - 794, 660, 629, 661, 630, 662, 663, 1616, 687, 636, - 548, 488, 0, 704, 0, 0, 1100, 1110, 0, 0, - 0, 173, 0, 0, 0, 0, 1095, 0, 0, 0, - 0, 0, 968, 0, 0, 1006, 1076, 1075, 993, 1003, - 0, 0, 371, 270, 631, 758, 633, 632, 994, 0, - 995, 999, 1002, 998, 996, 997, 0, 1090, 0, 0, - 0, 0, 0, 0, 960, 972, 0, 978, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 969, 970, 0, 0, 0, 0, 1027, - 0, 971, 0, 973, 0, 0, 0, 0, 549, 577, - 0, 590, 0, 438, 439, 1022, 1000, 1004, 4759, 0, - 0, 0, 356, 556, 574, 372, 543, 588, 377, 551, - 567, 367, 505, 539, 0, 0, 358, 572, 550, 483, - 357, 0, 532, 397, 414, 394, 503, 1001, 0, 1025, - 1029, 393, 1116, 1023, 582, 360, 0, 581, 502, 475, - 568, 573, 484, 477, 0, 359, 570, 482, 476, 452, - 404, 1117, 453, 454, 455, 456, 457, 458, 418, 1105, - 473, 519, 419, 490, 489, 491, 420, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 0, 0, 0, 0, - 0, 612, 613, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 750, 1020, - 247, 755, 0, 584, 0, 0, 1097, 0, 0, 0, - 554, 0, 0, 459, 0, 0, 0, 1024, 4879, 535, - 508, 1113, 0, 0, 533, 471, 569, 520, 575, 557, - 583, 527, 521, 350, 558, 396, 485, 368, 370, 783, - 398, 401, 405, 406, 496, 497, 514, 542, 561, 562, - 563, 395, 382, 534, 383, 415, 384, 351, 387, 386, - 388, 544, 389, 353, 515, 566, 0, 411, 530, 480, - 354, 479, 516, 565, 564, 369, 592, 599, 600, 692, - 0, 605, 797, 798, 799, 614, 0, 522, 365, 362, - 0, 0, 0, 391, 517, 378, 380, 381, 379, 511, - 513, 619, 620, 621, 623, 624, 625, 626, 0, 0, - 0, 0, 627, 693, 711, 677, 646, 607, 701, 643, - 647, 648, 432, 433, 434, 435, 714, 0, 0, 0, - 598, 460, 461, 0, 403, 402, 481, 355, 0, 0, - 449, 431, 523, 361, 399, 451, 437, 462, 463, 464, - 465, 466, 0, 467, 468, 409, 340, 346, 791, 1094, - 504, 716, 753, 754, 638, 0, 1112, 1089, 1091, 1092, - 1096, 1101, 1102, 1103, 1104, 1106, 1108, 1111, 1115, 790, - 0, 694, 708, 795, 707, 787, 510, 0, 541, 705, - 652, 0, 698, 671, 672, 0, 699, 667, 703, 0, - 640, 0, 608, 611, 642, 729, 730, 731, 352, 610, - 733, 734, 735, 736, 737, 738, 739, 732, 1114, 675, - 651, 678, 589, 654, 653, 0, 0, 689, 1028, 690, - 691, 492, 493, 494, 495, 1098, 717, 376, 609, 525, - 526, 0, 676, 0, 0, 0, 0, 0, 0, 0, - 0, 681, 682, 679, 800, 0, 740, 741, 0, 0, - 603, 604, 408, 0, 622, 416, 375, 509, 410, 587, - 440, 0, 615, 683, 616, 528, 529, 744, 749, 745, - 746, 748, 769, 499, 430, 436, 545, 450, 472, 531, - 586, 507, 536, 373, 576, 547, 478, 668, 696, 1123, - 1093, 1122, 1124, 1125, 1121, 1126, 1127, 1107, 982, 0, - 1035, 1036, 1119, 1118, 1120, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 725, 724, 723, 722, - 721, 720, 719, 718, 0, 0, 665, 390, 788, 782, - 789, 770, 773, 772, 747, 989, 347, 645, 470, 524, - 407, 712, 713, 0, 768, 1083, 1046, 1047, 1048, 979, - 1049, 1043, 1044, 980, 1045, 1084, 1033, 1080, 1081, 1008, - 1038, 1050, 1079, 1051, 1082, 1009, 1085, 1128, 1129, 1057, - 1041, 303, 1130, 1054, 1086, 1078, 1077, 1052, 1034, 1087, - 1088, 1016, 1011, 1055, 1056, 1042, 1063, 1064, 1065, 1068, - 981, 1069, 1070, 1071, 1072, 1073, 1067, 1066, 1030, 1031, - 1032, 1058, 1059, 1061, 1062, 1037, 555, 1012, 1013, 1014, - 1015, 0, 0, 593, 594, 595, 618, 0, 596, 578, - 644, 417, 348, 559, 585, 785, 786, 0, 0, 0, - 0, 0, 0, 0, 695, 706, 742, 743, 0, 756, - 757, 759, 761, 1074, 763, 552, 553, 771, 0, 0, - 441, 363, 364, 500, 501, 538, 0, 442, 443, 444, - 448, 445, 446, 447, 1060, 766, 767, 764, 474, 537, - 560, 546, 784, 487, 0, 792, 634, 635, 793, 752, - 751, 349, 0, 1039, 1040, 709, 710, 0, 0, 1109, - 486, 641, 0, 974, 341, 342, 343, 1099, 345, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1026, 0, 0, 0, 0, 0, 0, 0, 0, 506, - 0, 0, 650, 684, 673, 762, 637, 0, 0, 0, - 0, 0, 0, 977, 0, 0, 0, 400, 0, 0, - 469, 688, 669, 680, 670, 512, 655, 656, 657, 664, - 412, 658, 794, 660, 629, 661, 630, 662, 663, 1017, - 687, 636, 548, 488, 0, 704, 0, 0, 1100, 1110, - 0, 0, 0, 0, 0, 0, 0, 0, 1095, 0, - 0, 0, 0, 0, 968, 0, 0, 1006, 1076, 1075, - 993, 1003, 0, 0, 371, 270, 631, 758, 633, 632, - 994, 0, 995, 999, 1002, 998, 996, 997, 0, 1090, - 0, 0, 0, 0, 0, 0, 960, 972, 0, 978, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 969, 970, 0, 0, 0, - 0, 1027, 0, 971, 0, 973, 0, 0, 0, 0, - 549, 577, 0, 590, 0, 438, 439, 1022, 1000, 1004, - 0, 0, 0, 0, 356, 556, 574, 372, 543, 588, - 377, 551, 567, 367, 505, 539, 0, 0, 358, 572, - 550, 483, 357, 0, 532, 397, 414, 394, 503, 1001, - 0, 1025, 1029, 393, 1116, 1023, 582, 360, 0, 581, - 502, 475, 568, 573, 484, 477, 0, 359, 570, 482, - 476, 452, 404, 1117, 453, 454, 455, 456, 457, 458, - 418, 1105, 473, 519, 419, 490, 489, 491, 420, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 0, 0, 0, 612, 613, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 750, 1020, 0, 755, 0, 584, 0, 0, 1097, 0, - 0, 0, 554, 0, 0, 459, 0, 0, 0, 1024, - 0, 535, 508, 1113, 0, 0, 533, 471, 569, 520, - 575, 557, 583, 527, 521, 350, 558, 396, 485, 368, - 370, 783, 398, 401, 405, 406, 496, 497, 514, 542, - 561, 562, 563, 395, 382, 534, 383, 415, 384, 351, - 387, 386, 388, 544, 389, 353, 515, 566, 0, 411, - 530, 480, 354, 479, 516, 565, 564, 369, 592, 599, - 600, 692, 0, 605, 797, 798, 799, 614, 0, 522, - 365, 362, 0, 0, 0, 391, 517, 378, 380, 381, - 379, 511, 513, 619, 620, 621, 623, 624, 625, 626, - 0, 0, 0, 0, 627, 693, 711, 677, 646, 607, - 701, 643, 647, 648, 432, 433, 434, 435, 714, 2268, - 2267, 2269, 598, 460, 461, 0, 403, 402, 481, 355, - 0, 0, 449, 431, 523, 361, 399, 451, 437, 462, - 463, 464, 465, 466, 0, 467, 468, 409, 340, 346, - 791, 1094, 504, 716, 753, 754, 638, 0, 1112, 1089, - 1091, 1092, 1096, 1101, 1102, 1103, 1104, 1106, 1108, 1111, - 1115, 790, 0, 694, 708, 795, 707, 787, 510, 0, - 541, 705, 652, 0, 698, 671, 672, 0, 699, 667, - 703, 0, 640, 0, 608, 611, 642, 729, 730, 731, - 352, 610, 733, 734, 735, 736, 737, 738, 739, 732, - 1114, 675, 651, 678, 589, 654, 653, 0, 0, 689, - 1028, 690, 691, 492, 493, 494, 495, 1098, 717, 376, - 609, 525, 526, 0, 676, 0, 0, 0, 0, 0, - 0, 0, 0, 681, 682, 679, 800, 0, 740, 741, - 0, 0, 603, 604, 408, 0, 622, 416, 375, 509, - 410, 587, 440, 0, 615, 683, 616, 528, 529, 744, - 749, 745, 746, 748, 769, 499, 430, 436, 545, 450, - 472, 531, 586, 507, 536, 373, 576, 547, 478, 668, - 696, 1123, 1093, 1122, 1124, 1125, 1121, 1126, 1127, 1107, - 982, 0, 1035, 1036, 1119, 1118, 1120, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 725, 724, - 723, 722, 721, 720, 719, 718, 0, 0, 665, 390, - 788, 782, 789, 770, 773, 772, 747, 989, 347, 645, - 470, 524, 407, 712, 713, 0, 768, 1083, 1046, 1047, - 1048, 979, 1049, 1043, 1044, 980, 1045, 1084, 1033, 1080, - 1081, 1008, 1038, 1050, 1079, 1051, 1082, 1009, 1085, 1128, - 1129, 1057, 1041, 303, 1130, 1054, 1086, 1078, 1077, 1052, - 1034, 1087, 1088, 1016, 1011, 1055, 1056, 1042, 1063, 1064, - 1065, 1068, 981, 1069, 1070, 1071, 1072, 1073, 1067, 1066, - 1030, 1031, 1032, 1058, 1059, 1061, 1062, 1037, 555, 1012, - 1013, 1014, 1015, 0, 0, 593, 594, 595, 618, 0, - 596, 578, 644, 417, 348, 559, 585, 785, 786, 0, - 0, 0, 0, 0, 0, 0, 695, 706, 742, 743, - 0, 756, 757, 759, 761, 1074, 763, 552, 553, 771, - 0, 0, 441, 363, 364, 500, 501, 538, 0, 442, - 443, 444, 448, 445, 446, 447, 1060, 766, 767, 764, - 474, 537, 560, 546, 784, 487, 0, 792, 634, 635, - 793, 752, 751, 349, 0, 1039, 1040, 709, 710, 0, - 0, 1109, 486, 641, 0, 974, 341, 342, 343, 1099, - 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 201, 246, 1026, 0, 0, 0, 0, 0, 0, 0, - 0, 506, 0, 0, 650, 684, 673, 762, 637, 0, - 0, 0, 0, 0, 0, 977, 0, 0, 0, 400, - 0, 0, 469, 688, 669, 680, 670, 512, 655, 656, - 657, 664, 412, 658, 794, 660, 629, 661, 630, 662, - 663, 1017, 687, 636, 548, 488, 0, 704, 0, 0, - 1100, 1110, 0, 0, 0, 0, 0, 0, 0, 0, - 1095, 0, 0, 0, 0, 0, 968, 0, 0, 1006, - 1076, 1075, 993, 1003, 0, 0, 371, 270, 631, 758, - 633, 632, 994, 0, 995, 999, 1002, 998, 996, 997, - 0, 1090, 0, 0, 0, 0, 0, 0, 960, 972, - 0, 978, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 969, 970, 0, - 0, 0, 0, 1027, 0, 971, 0, 973, 0, 0, - 0, 0, 549, 577, 0, 590, 0, 438, 439, 1022, - 1000, 1004, 0, 0, 0, 0, 356, 556, 574, 372, - 543, 588, 377, 551, 567, 367, 505, 539, 0, 0, - 358, 572, 550, 483, 357, 0, 532, 397, 414, 394, - 503, 1001, 0, 1025, 1029, 393, 1116, 1023, 582, 360, - 0, 581, 502, 475, 568, 573, 484, 477, 0, 359, - 570, 482, 476, 452, 404, 1117, 453, 454, 455, 456, - 457, 458, 418, 1105, 473, 519, 419, 490, 489, 491, - 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 0, 0, 0, 0, 612, 613, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 750, 1020, 0, 755, 0, 584, 0, 0, - 1097, 0, 0, 0, 554, 0, 0, 459, 0, 0, - 0, 1024, 0, 535, 508, 1113, 0, 0, 533, 471, - 569, 520, 575, 557, 583, 527, 521, 350, 558, 396, - 485, 368, 370, 783, 398, 401, 405, 406, 496, 497, - 514, 542, 561, 562, 563, 395, 382, 534, 383, 415, - 384, 351, 387, 386, 388, 544, 389, 353, 515, 566, - 0, 411, 530, 480, 354, 479, 516, 565, 564, 369, - 592, 599, 600, 692, 0, 605, 797, 798, 799, 614, - 0, 522, 365, 362, 0, 0, 0, 391, 517, 378, - 380, 381, 379, 511, 513, 619, 620, 621, 623, 624, - 625, 626, 0, 0, 0, 0, 627, 693, 711, 677, - 646, 607, 701, 643, 647, 648, 432, 433, 434, 435, - 714, 0, 0, 0, 598, 460, 461, 0, 403, 402, - 481, 355, 0, 0, 449, 431, 523, 361, 399, 451, - 437, 462, 463, 464, 465, 466, 0, 467, 468, 409, - 340, 346, 791, 1094, 504, 716, 753, 754, 638, 0, - 1112, 1089, 1091, 1092, 1096, 1101, 1102, 1103, 1104, 1106, - 1108, 1111, 1115, 790, 0, 694, 708, 795, 707, 787, - 510, 0, 541, 705, 652, 0, 698, 671, 672, 0, - 699, 667, 703, 0, 640, 0, 608, 611, 642, 729, - 730, 731, 352, 610, 733, 734, 735, 736, 737, 738, - 739, 732, 1114, 675, 651, 678, 589, 654, 653, 0, - 0, 689, 1028, 690, 691, 492, 493, 494, 495, 1098, - 717, 376, 609, 525, 526, 0, 676, 0, 0, 0, - 0, 0, 0, 0, 0, 681, 682, 679, 800, 0, - 740, 741, 0, 0, 603, 604, 408, 0, 622, 416, - 375, 509, 410, 587, 440, 0, 615, 683, 616, 528, - 529, 744, 749, 745, 746, 748, 769, 499, 430, 436, - 545, 450, 472, 531, 586, 507, 536, 373, 576, 547, - 478, 668, 696, 1123, 1093, 1122, 1124, 1125, 1121, 1126, - 1127, 1107, 982, 0, 1035, 1036, 1119, 1118, 1120, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 725, 724, 723, 722, 721, 720, 719, 718, 0, 0, - 665, 390, 788, 782, 789, 770, 773, 772, 747, 989, - 347, 645, 470, 524, 407, 712, 713, 0, 768, 1083, - 1046, 1047, 1048, 979, 1049, 1043, 1044, 980, 1045, 1084, - 1033, 1080, 1081, 1008, 1038, 1050, 1079, 1051, 1082, 1009, - 1085, 1128, 1129, 1057, 1041, 303, 1130, 1054, 1086, 1078, - 1077, 1052, 1034, 1087, 1088, 1016, 1011, 1055, 1056, 1042, - 1063, 1064, 1065, 1068, 981, 1069, 1070, 1071, 1072, 1073, - 1067, 1066, 1030, 1031, 1032, 1058, 1059, 1061, 1062, 1037, - 555, 1012, 1013, 1014, 1015, 0, 0, 593, 594, 595, - 618, 0, 596, 578, 644, 417, 348, 559, 585, 785, - 786, 0, 0, 0, 0, 0, 0, 0, 695, 706, - 742, 743, 0, 756, 757, 759, 761, 1074, 763, 552, - 553, 771, 0, 0, 441, 363, 364, 500, 501, 538, - 0, 442, 443, 444, 448, 445, 446, 447, 1060, 766, - 767, 764, 474, 537, 560, 546, 784, 487, 0, 792, - 634, 635, 793, 752, 751, 349, 0, 1039, 1040, 709, - 710, 0, 0, 1109, 486, 641, 0, 974, 341, 342, - 343, 1099, 345, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1026, 0, 0, 0, 0, 0, - 0, 0, 0, 506, 0, 0, 650, 684, 673, 762, - 637, 0, 0, 0, 0, 0, 0, 977, 0, 0, - 0, 400, 2340, 0, 469, 688, 669, 680, 670, 512, - 655, 656, 657, 664, 412, 658, 794, 660, 629, 661, - 630, 662, 663, 1017, 687, 636, 548, 488, 0, 704, - 0, 0, 1100, 1110, 0, 0, 0, 0, 0, 0, - 0, 0, 1095, 0, 2597, 0, 0, 0, 968, 0, - 0, 1006, 1076, 1075, 993, 1003, 0, 0, 371, 270, - 631, 758, 633, 632, 994, 0, 995, 999, 1002, 998, - 996, 997, 0, 1090, 0, 0, 0, 0, 0, 0, - 960, 972, 0, 978, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 969, - 970, 0, 0, 0, 0, 1027, 0, 971, 0, 973, - 0, 0, 0, 0, 549, 577, 0, 590, 0, 438, - 439, 2598, 1000, 1004, 0, 0, 0, 0, 356, 556, - 574, 372, 543, 588, 377, 551, 567, 367, 505, 539, - 0, 0, 358, 572, 550, 483, 357, 0, 532, 397, - 414, 394, 503, 1001, 0, 1025, 1029, 393, 1116, 1023, - 582, 360, 0, 581, 502, 475, 568, 573, 484, 477, - 0, 359, 570, 482, 476, 452, 404, 1117, 453, 454, - 455, 456, 457, 458, 418, 1105, 473, 519, 419, 490, - 489, 491, 420, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 0, 0, 0, 612, 613, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 750, 1020, 0, 755, 0, 584, - 0, 0, 1097, 0, 0, 0, 554, 0, 0, 459, - 0, 0, 0, 1024, 0, 535, 508, 1113, 0, 0, - 533, 471, 569, 520, 575, 557, 583, 527, 521, 350, - 558, 396, 485, 368, 370, 783, 398, 401, 405, 406, - 496, 497, 514, 542, 561, 562, 563, 395, 382, 534, - 383, 415, 384, 351, 387, 386, 388, 544, 389, 353, - 515, 566, 0, 411, 530, 480, 354, 479, 516, 565, - 564, 369, 592, 599, 600, 692, 0, 605, 797, 798, - 799, 614, 0, 522, 365, 362, 0, 0, 0, 391, - 517, 378, 380, 381, 379, 511, 513, 619, 620, 621, - 623, 624, 625, 626, 0, 0, 0, 0, 627, 693, - 711, 677, 646, 607, 701, 643, 647, 648, 432, 433, - 434, 435, 714, 0, 0, 0, 598, 460, 461, 0, - 403, 402, 481, 355, 0, 0, 449, 431, 523, 361, - 399, 451, 437, 462, 463, 464, 465, 466, 0, 467, - 468, 409, 340, 346, 791, 1094, 504, 716, 753, 754, - 638, 0, 1112, 1089, 1091, 1092, 1096, 1101, 1102, 1103, - 1104, 1106, 1108, 1111, 1115, 790, 0, 694, 708, 795, - 707, 787, 510, 0, 541, 705, 652, 0, 698, 671, - 672, 0, 699, 667, 703, 0, 640, 0, 608, 611, - 642, 729, 730, 731, 352, 610, 733, 734, 735, 736, - 737, 738, 739, 732, 1114, 675, 651, 678, 589, 654, - 653, 0, 0, 689, 1028, 690, 691, 492, 493, 494, - 495, 1098, 717, 376, 609, 525, 526, 0, 676, 0, - 0, 0, 0, 0, 0, 0, 0, 681, 682, 679, - 800, 0, 740, 741, 0, 0, 603, 604, 408, 0, - 622, 416, 375, 509, 410, 587, 440, 0, 615, 683, - 616, 528, 529, 744, 749, 745, 746, 748, 769, 499, - 430, 436, 545, 450, 472, 531, 586, 507, 536, 373, - 576, 547, 478, 668, 696, 1123, 1093, 1122, 1124, 1125, - 1121, 1126, 1127, 1107, 982, 0, 1035, 1036, 1119, 1118, - 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 725, 724, 723, 722, 721, 720, 719, 718, - 0, 0, 665, 390, 788, 782, 789, 770, 773, 772, - 747, 989, 347, 645, 470, 524, 407, 712, 713, 0, - 768, 1083, 1046, 1047, 1048, 979, 1049, 1043, 1044, 980, - 1045, 1084, 1033, 1080, 1081, 1008, 1038, 1050, 1079, 1051, - 1082, 1009, 1085, 1128, 1129, 1057, 1041, 303, 1130, 1054, - 1086, 1078, 1077, 1052, 1034, 1087, 1088, 1016, 1011, 1055, - 1056, 1042, 1063, 1064, 1065, 1068, 981, 1069, 1070, 1071, - 1072, 1073, 1067, 1066, 1030, 1031, 1032, 1058, 1059, 1061, - 1062, 1037, 555, 1012, 1013, 1014, 1015, 0, 0, 593, - 594, 595, 618, 0, 596, 578, 644, 417, 348, 559, - 585, 785, 786, 0, 0, 0, 0, 0, 0, 0, - 695, 706, 742, 743, 0, 756, 757, 759, 761, 1074, - 763, 552, 553, 771, 0, 0, 441, 363, 364, 500, - 501, 538, 0, 442, 443, 444, 448, 445, 446, 447, - 1060, 766, 767, 764, 474, 537, 560, 546, 784, 487, - 0, 792, 634, 635, 793, 752, 751, 349, 0, 1039, - 1040, 709, 710, 0, 0, 1109, 486, 641, 0, 974, - 341, 342, 343, 1099, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1026, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 977, - 0, 0, 0, 400, 5440, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 1017, 687, 636, 548, 488, - 0, 704, 0, 0, 1100, 1110, 0, 0, 0, 0, - 0, 0, 0, 0, 1095, 0, 0, 0, 0, 0, - 968, 0, 0, 1006, 1076, 1075, 993, 1003, 0, 0, - 371, 270, 631, 758, 633, 632, 994, 0, 995, 999, - 1002, 998, 996, 997, 0, 1090, 0, 0, 0, 0, - 0, 0, 960, 972, 0, 978, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 969, 970, 0, 0, 0, 0, 1027, 0, 971, - 0, 973, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 1022, 1000, 1004, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 1001, 0, 1025, 1029, 393, - 1116, 1023, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 1117, - 453, 454, 455, 456, 457, 458, 418, 1105, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 1020, 0, 755, - 0, 584, 0, 0, 1097, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 1024, 0, 535, 508, 1113, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 1094, 504, 716, - 753, 754, 638, 0, 1112, 1089, 1091, 1092, 1096, 1101, - 1102, 1103, 1104, 1106, 1108, 1111, 1115, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 1114, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 1028, 690, 691, 492, - 493, 494, 495, 1098, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 1123, 1093, 1122, - 1124, 1125, 1121, 1126, 1127, 1107, 982, 0, 1035, 1036, - 1119, 1118, 1120, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 989, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 1083, 1046, 1047, 1048, 979, 1049, 1043, - 1044, 980, 1045, 1084, 1033, 1080, 1081, 1008, 1038, 1050, - 1079, 1051, 1082, 1009, 1085, 1128, 1129, 1057, 1041, 303, - 1130, 1054, 1086, 1078, 1077, 1052, 1034, 1087, 1088, 1016, - 1011, 1055, 1056, 1042, 1063, 1064, 1065, 1068, 981, 1069, - 1070, 1071, 1072, 1073, 1067, 1066, 1030, 1031, 1032, 1058, - 1059, 1061, 1062, 1037, 555, 1012, 1013, 1014, 1015, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 1074, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 1060, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 1039, 1040, 709, 710, 0, 0, 1109, 486, 641, - 0, 974, 341, 342, 343, 1099, 345, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1026, 0, - 0, 0, 0, 0, 0, 0, 0, 506, 0, 0, - 650, 684, 673, 762, 637, 0, 0, 0, 0, 0, - 0, 977, 0, 0, 0, 400, 0, 0, 469, 688, - 669, 680, 670, 512, 655, 656, 657, 664, 412, 658, - 794, 660, 629, 661, 630, 662, 663, 1017, 687, 636, - 548, 488, 0, 704, 0, 0, 1100, 1110, 0, 0, - 0, 0, 0, 0, 0, 0, 1095, 0, 0, 0, - 0, 0, 968, 0, 0, 1006, 1076, 1075, 993, 1003, - 0, 0, 371, 270, 631, 758, 633, 632, 994, 0, - 995, 999, 1002, 998, 996, 997, 0, 1090, 0, 0, - 0, 0, 0, 0, 960, 972, 0, 978, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 969, 970, 0, 0, 0, 0, 1027, - 0, 971, 0, 973, 0, 0, 0, 0, 549, 577, - 0, 590, 0, 438, 439, 1022, 1000, 1004, 0, 0, - 0, 0, 356, 556, 574, 372, 543, 588, 377, 551, - 567, 367, 505, 539, 0, 0, 358, 572, 550, 483, - 357, 0, 532, 397, 414, 394, 503, 1001, 0, 1025, - 1029, 393, 1116, 1023, 582, 360, 0, 581, 502, 475, - 568, 573, 484, 477, 0, 359, 570, 482, 476, 452, - 404, 1117, 453, 454, 455, 456, 457, 458, 418, 1105, - 473, 519, 419, 490, 489, 491, 420, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 0, 0, 0, 0, - 0, 612, 613, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 750, 1020, - 0, 755, 0, 584, 0, 0, 1097, 0, 0, 0, - 554, 0, 0, 459, 0, 0, 0, 1024, 0, 535, - 508, 1113, 5246, 0, 533, 471, 569, 520, 575, 557, - 583, 527, 521, 350, 558, 396, 485, 368, 370, 783, - 398, 401, 405, 406, 496, 497, 514, 542, 561, 562, - 563, 395, 382, 534, 383, 415, 384, 351, 387, 386, - 388, 544, 389, 353, 515, 566, 0, 411, 530, 480, - 354, 479, 516, 565, 564, 369, 592, 599, 600, 692, - 0, 605, 797, 798, 799, 614, 0, 522, 365, 362, - 0, 0, 0, 391, 517, 378, 380, 381, 379, 511, - 513, 619, 620, 621, 623, 624, 625, 626, 0, 0, - 0, 0, 627, 693, 711, 677, 646, 607, 701, 643, - 647, 648, 432, 433, 434, 435, 714, 0, 0, 0, - 598, 460, 461, 0, 403, 402, 481, 355, 0, 0, - 449, 431, 523, 361, 399, 451, 437, 462, 463, 464, - 465, 466, 0, 467, 468, 409, 340, 346, 791, 1094, - 504, 716, 753, 754, 638, 0, 1112, 1089, 1091, 1092, - 1096, 1101, 1102, 1103, 1104, 1106, 1108, 1111, 1115, 790, - 0, 694, 708, 795, 707, 787, 510, 0, 541, 705, - 652, 0, 698, 671, 672, 0, 699, 667, 703, 0, - 640, 0, 608, 611, 642, 729, 730, 731, 352, 610, - 733, 734, 735, 736, 737, 738, 739, 732, 1114, 675, - 651, 678, 589, 654, 653, 0, 0, 689, 1028, 690, - 691, 492, 493, 494, 495, 1098, 717, 376, 609, 525, - 526, 0, 676, 0, 0, 0, 0, 0, 0, 0, - 0, 681, 682, 679, 800, 0, 740, 741, 0, 0, - 603, 604, 408, 0, 622, 416, 375, 509, 410, 587, - 440, 0, 615, 683, 616, 528, 529, 744, 749, 745, - 746, 748, 769, 499, 430, 436, 545, 450, 472, 531, - 586, 507, 536, 373, 576, 547, 478, 668, 696, 1123, - 1093, 1122, 1124, 1125, 1121, 1126, 1127, 1107, 982, 0, - 1035, 1036, 1119, 1118, 1120, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 725, 724, 723, 722, - 721, 720, 719, 718, 0, 0, 665, 390, 788, 782, - 789, 770, 773, 772, 747, 989, 347, 645, 470, 524, - 407, 712, 713, 0, 768, 1083, 1046, 1047, 1048, 979, - 1049, 1043, 1044, 980, 1045, 1084, 1033, 1080, 1081, 1008, - 1038, 1050, 1079, 1051, 1082, 1009, 1085, 1128, 1129, 1057, - 1041, 303, 1130, 1054, 1086, 1078, 1077, 1052, 1034, 1087, - 1088, 1016, 1011, 1055, 1056, 1042, 1063, 1064, 1065, 1068, - 981, 1069, 1070, 1071, 1072, 1073, 1067, 1066, 1030, 1031, - 1032, 1058, 1059, 1061, 1062, 1037, 555, 1012, 1013, 1014, - 1015, 0, 0, 593, 594, 595, 618, 0, 596, 578, - 644, 417, 348, 559, 585, 785, 786, 0, 0, 0, - 0, 0, 0, 0, 695, 706, 742, 743, 0, 756, - 757, 759, 761, 1074, 763, 552, 553, 771, 0, 0, - 441, 363, 364, 500, 501, 538, 0, 442, 443, 444, - 448, 445, 446, 447, 1060, 766, 767, 764, 474, 537, - 560, 546, 784, 487, 0, 792, 634, 635, 793, 752, - 751, 349, 0, 1039, 1040, 709, 710, 0, 0, 1109, - 486, 641, 0, 974, 341, 342, 343, 1099, 345, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1026, 0, 0, 0, 0, 0, 0, 0, 0, 506, - 0, 0, 650, 684, 673, 762, 637, 0, 0, 0, - 0, 0, 0, 977, 0, 0, 0, 400, 0, 0, - 469, 688, 669, 680, 670, 512, 655, 656, 657, 664, - 412, 658, 794, 660, 629, 661, 630, 662, 663, 1017, - 687, 636, 548, 488, 0, 704, 0, 0, 1100, 1110, - 0, 0, 0, 0, 0, 0, 0, 0, 1095, 0, - 0, 0, 0, 0, 968, 0, 0, 1006, 1076, 1075, - 993, 1003, 0, 0, 371, 270, 631, 758, 633, 632, - 994, 0, 995, 999, 1002, 998, 996, 997, 0, 1090, - 0, 0, 0, 0, 0, 0, 960, 972, 0, 978, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 969, 970, 1934, 0, 0, - 0, 1027, 0, 971, 0, 973, 0, 0, 0, 0, - 549, 577, 0, 590, 0, 438, 439, 1022, 1000, 1004, - 0, 0, 0, 0, 356, 556, 574, 372, 543, 588, - 377, 551, 567, 367, 505, 539, 0, 0, 358, 572, - 550, 483, 357, 0, 532, 397, 414, 394, 503, 1001, - 0, 1025, 1029, 393, 1116, 1023, 582, 360, 0, 581, - 502, 475, 568, 573, 484, 477, 0, 359, 570, 482, - 476, 452, 404, 1117, 453, 454, 455, 456, 457, 458, - 418, 1105, 473, 519, 419, 490, 489, 491, 420, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 0, 0, 0, 612, 613, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 750, 1020, 0, 755, 0, 584, 0, 0, 1097, 0, - 0, 0, 554, 0, 0, 459, 0, 0, 0, 1024, - 0, 535, 508, 1113, 0, 0, 533, 471, 569, 520, - 575, 557, 583, 527, 521, 350, 558, 396, 485, 368, - 370, 783, 398, 401, 405, 406, 496, 497, 514, 542, - 561, 562, 563, 395, 382, 534, 383, 415, 384, 351, - 387, 386, 388, 544, 389, 353, 515, 566, 0, 411, - 530, 480, 354, 479, 516, 565, 564, 369, 592, 599, - 600, 692, 0, 605, 797, 798, 799, 614, 0, 522, - 365, 362, 0, 0, 0, 391, 517, 378, 380, 381, - 379, 511, 513, 619, 620, 621, 623, 624, 625, 626, - 0, 0, 0, 0, 627, 693, 711, 677, 646, 607, - 701, 643, 647, 648, 432, 433, 434, 435, 714, 0, - 0, 0, 598, 460, 461, 0, 403, 402, 481, 355, - 0, 0, 449, 431, 523, 361, 399, 451, 437, 462, - 463, 464, 465, 466, 0, 467, 468, 409, 340, 346, - 791, 1094, 504, 716, 753, 754, 638, 0, 1112, 1089, - 1091, 1092, 1096, 1101, 1102, 1103, 1104, 1106, 1108, 1111, - 1115, 790, 0, 694, 708, 795, 707, 787, 510, 0, - 541, 705, 652, 0, 698, 671, 672, 0, 699, 667, - 703, 0, 640, 0, 608, 611, 642, 729, 730, 731, - 352, 610, 733, 734, 735, 736, 737, 738, 739, 732, - 1114, 675, 651, 678, 589, 654, 653, 0, 0, 689, - 1028, 690, 691, 492, 493, 494, 495, 1098, 717, 376, - 609, 525, 526, 0, 676, 0, 0, 0, 0, 0, - 0, 0, 0, 681, 682, 679, 800, 0, 740, 741, - 0, 0, 603, 604, 408, 0, 622, 416, 375, 509, - 410, 587, 440, 0, 615, 683, 616, 528, 529, 744, - 749, 745, 746, 748, 769, 499, 430, 436, 545, 450, - 472, 531, 586, 507, 536, 373, 576, 547, 478, 668, - 696, 1123, 1093, 1122, 1124, 1125, 1121, 1126, 1127, 1107, - 982, 0, 1035, 1036, 1119, 1118, 1120, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 725, 724, - 723, 722, 721, 720, 719, 718, 0, 0, 665, 390, - 788, 782, 789, 770, 773, 772, 747, 989, 347, 645, - 470, 524, 407, 712, 713, 0, 768, 1083, 1046, 1047, - 1048, 979, 1049, 1043, 1044, 980, 1045, 1084, 1033, 1080, - 1081, 1008, 1038, 1050, 1079, 1051, 1082, 1009, 1085, 1128, - 1129, 1057, 1041, 303, 1130, 1054, 1086, 1078, 1077, 1052, - 1034, 1087, 1088, 1016, 1011, 1055, 1056, 1042, 1063, 1064, - 1065, 1068, 981, 1069, 1070, 1071, 1072, 1073, 1067, 1066, - 1030, 1031, 1032, 1058, 1059, 1061, 1062, 1037, 555, 1012, - 1013, 1014, 1015, 0, 0, 593, 594, 595, 618, 0, - 596, 578, 644, 417, 348, 559, 585, 785, 786, 0, - 0, 0, 0, 0, 0, 0, 695, 706, 742, 743, - 0, 756, 757, 759, 761, 1074, 763, 552, 553, 771, - 0, 0, 441, 363, 364, 500, 501, 538, 0, 442, - 443, 444, 448, 445, 446, 447, 1060, 766, 767, 764, - 474, 537, 560, 546, 784, 487, 0, 792, 634, 635, - 793, 752, 751, 349, 0, 1039, 1040, 709, 710, 0, - 0, 1109, 486, 641, 0, 974, 341, 342, 343, 1099, - 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1026, 0, 0, 0, 0, 0, 0, 0, - 0, 506, 0, 0, 650, 684, 673, 762, 637, 0, - 0, 0, 0, 0, 0, 977, 0, 0, 0, 400, - 2340, 0, 469, 688, 669, 680, 670, 512, 655, 656, - 657, 664, 412, 658, 794, 660, 629, 661, 630, 662, - 663, 1017, 687, 636, 548, 488, 0, 704, 0, 0, - 1100, 1110, 0, 0, 0, 0, 0, 0, 0, 0, - 1095, 0, 0, 0, 0, 0, 968, 0, 0, 1006, - 1076, 1075, 993, 1003, 0, 0, 371, 270, 631, 758, - 633, 632, 994, 0, 995, 999, 1002, 998, 996, 997, - 0, 1090, 0, 0, 0, 0, 0, 0, 960, 972, - 0, 978, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 969, 970, 0, - 0, 0, 0, 1027, 0, 971, 0, 973, 0, 0, - 0, 0, 549, 577, 0, 590, 0, 438, 439, 1022, - 1000, 1004, 0, 0, 0, 0, 356, 556, 574, 372, - 543, 588, 377, 551, 567, 367, 505, 539, 0, 0, - 358, 572, 550, 483, 357, 0, 532, 397, 414, 394, - 503, 1001, 0, 1025, 1029, 393, 1116, 1023, 582, 360, - 0, 581, 502, 475, 568, 573, 484, 477, 0, 359, - 570, 482, 476, 452, 404, 1117, 453, 454, 455, 456, - 457, 458, 418, 1105, 473, 519, 419, 490, 489, 491, - 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 0, 0, 0, 0, 612, 613, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 750, 1020, 0, 755, 0, 584, 0, 0, - 1097, 0, 0, 0, 554, 0, 0, 459, 0, 0, - 0, 1024, 0, 535, 508, 1113, 0, 0, 533, 471, - 569, 520, 575, 557, 583, 527, 521, 350, 558, 396, - 485, 368, 370, 783, 398, 401, 405, 406, 496, 497, - 514, 542, 561, 562, 563, 395, 382, 534, 383, 415, - 384, 351, 387, 386, 388, 544, 389, 353, 515, 566, - 0, 411, 530, 480, 354, 479, 516, 565, 564, 369, - 592, 599, 600, 692, 0, 605, 797, 798, 799, 614, - 0, 522, 365, 362, 0, 0, 0, 391, 517, 378, - 380, 381, 379, 511, 513, 619, 620, 621, 623, 624, - 625, 626, 0, 0, 0, 0, 627, 693, 711, 677, - 646, 607, 701, 643, 647, 648, 432, 433, 434, 435, - 714, 0, 0, 0, 598, 460, 461, 0, 403, 402, - 481, 355, 0, 0, 449, 431, 523, 361, 399, 451, - 437, 462, 463, 464, 465, 466, 0, 467, 468, 409, - 340, 346, 791, 1094, 504, 716, 753, 754, 638, 0, - 1112, 1089, 1091, 1092, 1096, 1101, 1102, 1103, 1104, 1106, - 1108, 1111, 1115, 790, 0, 694, 708, 795, 707, 787, - 510, 0, 541, 705, 652, 0, 698, 671, 672, 0, - 699, 667, 703, 0, 640, 0, 608, 611, 642, 729, - 730, 731, 352, 610, 733, 734, 735, 736, 737, 738, - 739, 732, 1114, 675, 651, 678, 589, 654, 653, 0, - 0, 689, 1028, 690, 691, 492, 493, 494, 495, 1098, - 717, 376, 609, 525, 526, 0, 676, 0, 0, 0, - 0, 0, 0, 0, 0, 681, 682, 679, 800, 0, - 740, 741, 0, 0, 603, 604, 408, 0, 622, 416, - 375, 509, 410, 587, 440, 0, 615, 683, 616, 528, - 529, 744, 749, 745, 746, 748, 769, 499, 430, 436, - 545, 450, 472, 531, 586, 507, 536, 373, 576, 547, - 478, 668, 696, 1123, 1093, 1122, 1124, 1125, 1121, 1126, - 1127, 1107, 982, 0, 1035, 1036, 1119, 1118, 1120, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 725, 724, 723, 722, 721, 720, 719, 718, 0, 0, - 665, 390, 788, 782, 789, 770, 773, 772, 747, 989, - 347, 645, 470, 524, 407, 712, 713, 0, 768, 1083, - 1046, 1047, 1048, 979, 1049, 1043, 1044, 980, 1045, 1084, - 1033, 1080, 1081, 1008, 1038, 1050, 1079, 1051, 1082, 1009, - 1085, 1128, 1129, 1057, 1041, 303, 1130, 1054, 1086, 1078, - 1077, 1052, 1034, 1087, 1088, 1016, 1011, 1055, 1056, 1042, - 1063, 1064, 1065, 1068, 981, 1069, 1070, 1071, 1072, 1073, - 1067, 1066, 1030, 1031, 1032, 1058, 1059, 1061, 1062, 1037, - 555, 1012, 1013, 1014, 1015, 0, 0, 593, 594, 595, - 618, 0, 596, 578, 644, 417, 348, 559, 585, 785, - 786, 0, 0, 0, 0, 0, 0, 0, 695, 706, - 742, 743, 0, 756, 757, 759, 761, 1074, 763, 552, - 553, 771, 0, 0, 441, 363, 364, 500, 501, 538, - 0, 442, 443, 444, 448, 445, 446, 447, 1060, 766, - 767, 764, 474, 537, 560, 546, 784, 487, 0, 792, - 634, 635, 793, 752, 751, 349, 0, 1039, 1040, 709, - 710, 0, 0, 1109, 486, 641, 0, 974, 341, 342, - 343, 1099, 345, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1026, 0, 0, 2846, 0, 0, - 0, 0, 0, 506, 0, 0, 650, 684, 673, 762, - 637, 0, 0, 0, 0, 0, 0, 977, 0, 0, - 0, 400, 0, 0, 469, 688, 669, 680, 670, 512, - 655, 656, 657, 664, 412, 658, 794, 660, 629, 661, - 630, 662, 663, 1017, 687, 636, 548, 488, 0, 704, - 0, 0, 1100, 1110, 0, 0, 0, 0, 0, 0, - 0, 0, 1095, 0, 0, 0, 0, 0, 968, 0, - 0, 1006, 1076, 1075, 993, 1003, 0, 0, 371, 270, - 631, 758, 633, 632, 994, 0, 995, 999, 1002, 998, - 996, 997, 0, 1090, 0, 0, 0, 0, 0, 0, - 960, 972, 0, 978, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 969, - 970, 0, 0, 0, 0, 1027, 0, 971, 0, 973, - 0, 0, 0, 0, 549, 577, 0, 590, 0, 438, - 439, 1022, 1000, 1004, 0, 0, 0, 0, 356, 556, - 574, 372, 543, 588, 377, 551, 567, 367, 505, 539, - 0, 0, 358, 572, 550, 483, 357, 0, 532, 397, - 414, 394, 503, 1001, 0, 1025, 1029, 393, 1116, 1023, - 582, 360, 0, 581, 502, 475, 568, 573, 484, 477, - 0, 359, 570, 482, 476, 452, 404, 1117, 453, 454, - 455, 456, 457, 458, 418, 1105, 473, 519, 419, 490, - 489, 491, 420, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 0, 0, 0, 612, 613, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 750, 1020, 0, 755, 0, 584, - 0, 0, 1097, 0, 0, 0, 554, 0, 0, 459, - 0, 0, 0, 1024, 0, 535, 508, 1113, 0, 0, - 533, 471, 569, 520, 575, 557, 583, 527, 521, 350, - 558, 396, 485, 368, 370, 783, 398, 401, 405, 406, - 496, 497, 514, 542, 561, 562, 563, 395, 382, 534, - 383, 415, 384, 351, 387, 386, 388, 544, 389, 353, - 515, 566, 0, 411, 530, 480, 354, 479, 516, 565, - 564, 369, 592, 599, 600, 692, 0, 605, 797, 798, - 799, 614, 0, 522, 365, 362, 0, 0, 0, 391, - 517, 378, 380, 381, 379, 511, 513, 619, 620, 621, - 623, 624, 625, 626, 0, 0, 0, 0, 627, 693, - 711, 677, 646, 607, 701, 643, 647, 648, 432, 433, - 434, 435, 714, 0, 0, 0, 598, 460, 461, 0, - 403, 402, 481, 355, 0, 0, 449, 431, 523, 361, - 399, 451, 437, 462, 463, 464, 465, 466, 0, 467, - 468, 409, 340, 346, 791, 1094, 504, 716, 753, 754, - 638, 0, 1112, 1089, 1091, 1092, 1096, 1101, 1102, 1103, - 1104, 1106, 1108, 1111, 1115, 790, 0, 694, 708, 795, - 707, 787, 510, 0, 541, 705, 652, 0, 698, 671, - 672, 0, 699, 667, 703, 0, 640, 0, 608, 611, - 642, 729, 730, 731, 352, 610, 733, 734, 735, 736, - 737, 738, 739, 732, 1114, 675, 651, 678, 589, 654, - 653, 0, 0, 689, 1028, 690, 691, 492, 493, 494, - 495, 1098, 717, 376, 609, 525, 526, 0, 676, 0, - 0, 0, 0, 0, 0, 0, 0, 681, 682, 679, - 800, 0, 740, 741, 0, 0, 603, 604, 408, 0, - 622, 416, 375, 509, 410, 587, 440, 0, 615, 683, - 616, 528, 529, 744, 749, 745, 746, 748, 769, 499, - 430, 436, 545, 450, 472, 531, 586, 507, 536, 373, - 576, 547, 478, 668, 696, 1123, 1093, 1122, 1124, 1125, - 1121, 1126, 1127, 1107, 982, 0, 1035, 1036, 1119, 1118, - 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 725, 724, 723, 722, 721, 720, 719, 718, - 0, 0, 665, 390, 788, 782, 789, 770, 773, 772, - 747, 989, 347, 645, 470, 524, 407, 712, 713, 0, - 768, 1083, 1046, 1047, 1048, 979, 1049, 1043, 1044, 980, - 1045, 1084, 1033, 1080, 1081, 1008, 1038, 1050, 1079, 1051, - 1082, 1009, 1085, 1128, 1129, 1057, 1041, 303, 1130, 1054, - 1086, 1078, 1077, 1052, 1034, 1087, 1088, 1016, 1011, 1055, - 1056, 1042, 1063, 1064, 1065, 1068, 981, 1069, 1070, 1071, - 1072, 1073, 1067, 1066, 1030, 1031, 1032, 1058, 1059, 1061, - 1062, 1037, 555, 1012, 1013, 1014, 1015, 0, 0, 593, - 594, 595, 618, 0, 596, 578, 644, 417, 348, 559, - 585, 785, 786, 0, 0, 0, 0, 0, 0, 0, - 695, 706, 742, 743, 0, 756, 757, 759, 761, 1074, - 763, 552, 553, 771, 0, 0, 441, 363, 364, 500, - 501, 538, 0, 442, 443, 444, 448, 445, 446, 447, - 1060, 766, 767, 764, 474, 537, 560, 546, 784, 487, - 0, 792, 634, 635, 793, 752, 751, 349, 0, 1039, - 1040, 709, 710, 0, 0, 1109, 486, 641, 0, 974, - 341, 342, 343, 1099, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1026, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 977, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 1017, 687, 636, 548, 488, - 0, 704, 0, 0, 1100, 1110, 0, 0, 0, 0, - 0, 0, 0, 0, 1095, 0, 0, 0, 0, 0, - 968, 0, 0, 1006, 1076, 1075, 993, 1003, 0, 0, - 371, 270, 631, 758, 633, 632, 994, 0, 995, 999, - 1002, 998, 996, 997, 0, 1090, 0, 0, 0, 0, - 0, 0, 960, 972, 0, 978, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 969, 970, 2331, 0, 0, 0, 1027, 0, 971, - 0, 973, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 1022, 1000, 1004, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 1001, 0, 1025, 1029, 393, - 1116, 1023, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 1117, - 453, 454, 455, 456, 457, 458, 418, 1105, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 1020, 0, 755, - 0, 584, 0, 0, 1097, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 1024, 0, 535, 508, 1113, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 1094, 504, 716, - 753, 754, 638, 0, 1112, 1089, 1091, 1092, 1096, 1101, - 1102, 1103, 1104, 1106, 1108, 1111, 1115, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 1114, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 1028, 690, 691, 492, - 493, 494, 495, 1098, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 1123, 1093, 1122, - 1124, 1125, 1121, 1126, 1127, 1107, 982, 0, 1035, 1036, - 1119, 1118, 1120, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 989, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 1083, 1046, 1047, 1048, 979, 1049, 1043, - 1044, 980, 1045, 1084, 1033, 1080, 1081, 1008, 1038, 1050, - 1079, 1051, 1082, 1009, 1085, 1128, 1129, 1057, 1041, 303, - 1130, 1054, 1086, 1078, 1077, 1052, 1034, 1087, 1088, 1016, - 1011, 1055, 1056, 1042, 1063, 1064, 1065, 1068, 981, 1069, - 1070, 1071, 1072, 1073, 1067, 1066, 1030, 1031, 1032, 1058, - 1059, 1061, 1062, 1037, 555, 1012, 1013, 1014, 1015, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 1074, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 1060, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 1039, 1040, 709, 710, 0, 0, 1109, 486, 641, - 0, 974, 341, 342, 343, 1099, 345, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1026, 0, - 0, 0, 0, 0, 0, 0, 0, 506, 0, 0, - 650, 684, 673, 762, 637, 0, 0, 0, 0, 0, - 0, 977, 0, 0, 0, 400, 0, 0, 469, 688, - 669, 680, 670, 512, 655, 656, 657, 664, 412, 658, - 794, 660, 629, 661, 630, 662, 663, 1017, 687, 636, - 548, 488, 0, 704, 0, 0, 1100, 1110, 0, 0, - 0, 0, 0, 0, 0, 0, 1095, 0, 0, 0, - 0, 0, 968, 0, 0, 1006, 1076, 1075, 993, 1003, - 0, 0, 371, 270, 631, 758, 633, 632, 994, 0, - 995, 999, 1002, 998, 996, 997, 0, 1090, 0, 0, - 0, 0, 0, 0, 960, 972, 0, 978, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 969, 970, 0, 0, 0, 0, 1027, - 0, 971, 0, 973, 0, 0, 0, 0, 549, 577, - 0, 590, 0, 438, 439, 1022, 1000, 1004, 0, 0, - 0, 0, 356, 556, 574, 372, 543, 588, 377, 551, - 567, 367, 505, 539, 0, 0, 358, 572, 550, 483, - 357, 0, 532, 397, 414, 394, 503, 1001, 0, 1025, - 1029, 393, 1116, 1023, 582, 360, 0, 581, 502, 475, - 568, 573, 484, 477, 0, 359, 570, 482, 476, 452, - 404, 1117, 453, 454, 455, 456, 457, 458, 418, 1105, - 473, 519, 419, 490, 489, 491, 420, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 0, 0, 0, 0, - 0, 612, 613, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 750, 1020, - 0, 755, 0, 584, 0, 0, 1097, 0, 0, 0, - 554, 0, 0, 459, 0, 0, 0, 1024, 0, 535, - 508, 1113, 0, 0, 533, 471, 569, 520, 575, 557, - 583, 527, 521, 350, 558, 396, 485, 368, 370, 783, - 398, 401, 405, 406, 496, 497, 514, 542, 561, 562, - 563, 395, 382, 534, 383, 415, 384, 351, 387, 386, - 388, 544, 389, 353, 515, 566, 0, 411, 530, 480, - 354, 479, 516, 565, 564, 369, 592, 599, 600, 692, - 0, 605, 797, 798, 799, 614, 0, 522, 365, 362, - 0, 0, 0, 391, 517, 378, 380, 381, 379, 511, - 513, 619, 620, 621, 623, 624, 625, 626, 0, 0, - 0, 0, 627, 693, 711, 677, 646, 607, 701, 643, - 647, 648, 432, 433, 434, 435, 714, 0, 0, 0, - 598, 460, 461, 0, 403, 402, 481, 355, 0, 0, - 449, 431, 523, 361, 399, 451, 437, 462, 463, 464, - 465, 466, 0, 467, 468, 409, 340, 346, 791, 1094, - 504, 716, 753, 754, 638, 0, 1112, 1089, 1091, 1092, - 1096, 1101, 1102, 1103, 1104, 1106, 1108, 1111, 1115, 790, - 0, 694, 708, 795, 707, 787, 510, 0, 541, 705, - 652, 0, 698, 671, 672, 0, 699, 667, 703, 0, - 640, 0, 608, 611, 642, 729, 730, 731, 352, 610, - 733, 734, 735, 736, 737, 738, 739, 732, 1114, 675, - 651, 678, 589, 654, 653, 0, 0, 689, 1028, 690, - 691, 492, 493, 494, 495, 1098, 717, 376, 609, 525, - 526, 0, 676, 0, 0, 0, 0, 0, 0, 0, - 0, 681, 682, 679, 800, 0, 740, 741, 0, 0, - 603, 604, 408, 0, 622, 416, 375, 509, 410, 587, - 440, 0, 615, 683, 616, 528, 529, 744, 749, 745, - 746, 748, 769, 499, 430, 436, 545, 450, 472, 531, - 586, 507, 536, 373, 576, 547, 478, 668, 696, 1123, - 1093, 1122, 1124, 1125, 1121, 1126, 1127, 1107, 982, 0, - 1035, 1036, 1119, 1118, 1120, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 725, 724, 723, 722, - 721, 720, 719, 718, 0, 0, 665, 390, 788, 782, - 789, 770, 773, 772, 747, 989, 347, 645, 470, 524, - 407, 712, 713, 0, 768, 1083, 1046, 1047, 1048, 979, - 1049, 1043, 1044, 980, 1045, 1084, 1033, 1080, 1081, 1008, - 1038, 1050, 1079, 1051, 1082, 1009, 1085, 1128, 1129, 1057, - 1041, 303, 1130, 1054, 1086, 1078, 1077, 1052, 1034, 1087, - 1088, 1016, 1011, 1055, 1056, 1042, 1063, 1064, 1065, 1068, - 981, 1069, 1070, 1071, 1072, 1073, 1067, 1066, 1030, 1031, - 1032, 1058, 1059, 1061, 1062, 1037, 555, 1012, 1013, 1014, - 1015, 0, 0, 593, 594, 595, 618, 0, 596, 578, - 644, 417, 348, 559, 585, 785, 786, 0, 0, 0, - 0, 0, 0, 0, 695, 706, 742, 743, 0, 756, - 757, 759, 761, 1074, 763, 552, 553, 771, 0, 0, - 441, 363, 364, 500, 501, 538, 0, 442, 443, 444, - 448, 445, 446, 447, 1060, 766, 767, 764, 474, 537, - 560, 546, 784, 487, 0, 792, 634, 635, 793, 752, - 751, 349, 0, 1039, 1040, 709, 710, 0, 0, 1109, - 486, 641, 0, 974, 341, 342, 343, 1099, 345, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1026, 0, 0, 0, 0, 0, 0, 0, 0, 506, - 0, 0, 650, 684, 673, 762, 637, 0, 0, 0, - 0, 0, 0, 977, 0, 0, 0, 400, 0, 0, - 469, 688, 669, 680, 670, 512, 655, 656, 657, 664, - 412, 658, 794, 660, 629, 661, 630, 662, 663, 1017, - 687, 636, 548, 488, 0, 704, 0, 0, 1100, 1110, - 0, 0, 0, 0, 0, 0, 0, 0, 1095, 0, - 0, 0, 0, 0, 968, 0, 0, 1006, 1076, 1075, - 993, 1003, 0, 0, 371, 270, 631, 758, 633, 632, - 994, 0, 995, 999, 1002, 998, 996, 997, 0, 1090, - 0, 0, 0, 0, 0, 0, 960, 972, 0, 978, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 969, 970, 0, 0, 0, - 0, 1027, 0, 971, 0, 973, 0, 0, 0, 0, - 549, 577, 0, 590, 0, 438, 439, 1022, 1000, 1004, - 0, 0, 0, 0, 356, 556, 574, 372, 543, 588, - 377, 551, 567, 367, 505, 539, 0, 0, 358, 572, - 550, 483, 357, 0, 532, 397, 414, 394, 503, 1001, - 0, 1025, 1029, 393, 1116, 1023, 582, 360, 0, 581, - 502, 475, 568, 573, 484, 477, 0, 359, 570, 482, - 476, 452, 404, 1117, 453, 454, 455, 456, 457, 458, - 418, 1105, 473, 519, 419, 490, 489, 491, 420, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 0, 0, 0, 612, 613, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 750, 1020, 0, 755, 0, 584, 0, 0, 1097, 0, - 0, 0, 554, 0, 0, 459, 0, 0, 0, 1024, - 0, 535, 508, 1113, 0, 0, 533, 471, 569, 520, - 575, 557, 583, 527, 521, 350, 558, 396, 485, 368, - 370, 783, 398, 401, 405, 406, 496, 497, 514, 542, - 561, 562, 563, 395, 382, 534, 383, 415, 384, 351, - 387, 386, 388, 544, 389, 353, 515, 566, 0, 411, - 530, 480, 354, 479, 516, 565, 564, 369, 592, 599, - 600, 692, 0, 605, 797, 798, 799, 614, 0, 522, - 365, 362, 0, 0, 0, 391, 517, 378, 380, 381, - 379, 511, 513, 619, 620, 621, 623, 624, 625, 626, - 0, 0, 0, 0, 627, 693, 711, 677, 646, 607, - 701, 643, 647, 648, 432, 433, 434, 435, 714, 0, - 0, 0, 598, 460, 461, 0, 403, 402, 481, 355, - 0, 0, 449, 431, 523, 361, 399, 451, 437, 462, - 463, 464, 465, 466, 0, 467, 468, 409, 340, 346, - 791, 1094, 504, 716, 753, 754, 638, 0, 1112, 1089, - 1091, 1092, 1096, 1101, 1102, 1103, 1104, 1106, 1108, 1111, - 1115, 790, 0, 694, 708, 795, 707, 787, 510, 0, - 541, 705, 652, 0, 698, 671, 672, 0, 699, 667, - 703, 0, 640, 0, 608, 611, 642, 729, 730, 731, - 352, 610, 733, 734, 735, 736, 737, 738, 739, 732, - 1114, 675, 651, 678, 589, 654, 653, 0, 0, 689, - 1028, 690, 691, 492, 493, 494, 495, 1098, 717, 376, - 609, 525, 526, 0, 676, 0, 0, 0, 0, 0, - 0, 0, 0, 681, 682, 679, 800, 0, 740, 741, - 0, 0, 603, 604, 408, 0, 622, 416, 375, 509, - 410, 587, 440, 0, 615, 683, 616, 528, 529, 744, - 749, 745, 746, 748, 769, 499, 430, 436, 545, 450, - 472, 531, 586, 507, 536, 373, 576, 547, 478, 668, - 696, 1123, 1093, 1122, 1124, 1125, 1121, 1126, 1127, 1107, - 982, 0, 1035, 1036, 1119, 1118, 1120, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 725, 724, - 723, 722, 721, 720, 719, 718, 0, 0, 665, 390, - 788, 782, 789, 770, 773, 772, 747, 989, 347, 645, - 470, 524, 407, 712, 713, 0, 768, 1083, 1046, 1047, - 1048, 979, 1049, 1043, 1044, 980, 1045, 1084, 1033, 1080, - 1081, 1008, 1038, 1050, 1079, 1051, 1082, 1009, 1085, 1128, - 1129, 1057, 1041, 303, 1130, 1054, 1086, 1078, 1077, 1052, - 1034, 1087, 1088, 1016, 1011, 1055, 1056, 1042, 1063, 1064, - 1065, 1068, 981, 1069, 1070, 1071, 1072, 1073, 1067, 1066, - 1030, 1031, 1032, 1058, 1059, 1061, 1062, 1037, 555, 1012, - 1013, 1014, 1015, 0, 0, 593, 594, 595, 618, 0, - 596, 578, 644, 417, 348, 559, 585, 785, 786, 0, - 0, 0, 0, 0, 0, 0, 695, 706, 742, 743, - 0, 756, 757, 759, 761, 1074, 763, 552, 553, 771, - 0, 0, 441, 363, 364, 500, 501, 538, 0, 442, - 443, 444, 448, 445, 446, 447, 4836, 766, 4837, 4838, - 474, 537, 560, 546, 784, 487, 0, 792, 634, 635, - 793, 752, 751, 349, 0, 1039, 1040, 709, 710, 0, - 0, 1109, 486, 641, 0, 974, 341, 342, 343, 1099, - 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1026, 0, 0, 0, 0, 0, 0, 0, - 0, 506, 0, 0, 650, 684, 673, 762, 637, 0, - 0, 0, 0, 0, 0, 977, 0, 0, 0, 400, - 0, 0, 469, 688, 669, 680, 670, 512, 655, 656, - 657, 664, 412, 658, 794, 660, 629, 661, 630, 662, - 663, 1017, 687, 636, 548, 488, 0, 704, 0, 0, - 1100, 1110, 0, 0, 0, 0, 0, 0, 0, 0, - 1095, 0, 0, 0, 0, 0, 968, 0, 0, 1006, - 1076, 1075, 993, 1003, 0, 0, 371, 270, 631, 758, - 633, 632, 3426, 0, 3427, 999, 1002, 998, 996, 997, - 0, 1090, 0, 0, 0, 0, 0, 0, 960, 972, - 0, 978, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 969, 970, 0, - 0, 0, 0, 1027, 0, 971, 0, 973, 0, 0, - 0, 0, 549, 577, 0, 590, 0, 438, 439, 1022, - 1000, 1004, 0, 0, 0, 0, 356, 556, 574, 372, - 543, 588, 377, 551, 567, 367, 505, 539, 0, 0, - 358, 572, 550, 483, 357, 0, 532, 397, 414, 394, - 503, 1001, 0, 1025, 1029, 393, 1116, 1023, 582, 360, - 0, 581, 502, 475, 568, 573, 484, 477, 0, 359, - 570, 482, 476, 452, 404, 1117, 453, 454, 455, 456, - 457, 458, 418, 1105, 473, 519, 419, 490, 489, 491, - 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, - 0, 0, 0, 0, 0, 612, 613, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 750, 1020, 0, 755, 0, 584, 0, 0, - 1097, 0, 0, 0, 554, 0, 0, 459, 0, 0, - 0, 1024, 0, 535, 508, 1113, 0, 0, 533, 471, - 569, 520, 575, 557, 583, 527, 521, 350, 558, 396, - 485, 368, 370, 783, 398, 401, 405, 406, 496, 497, - 514, 542, 561, 562, 563, 395, 382, 534, 383, 415, - 384, 351, 387, 386, 388, 544, 389, 353, 515, 566, - 0, 411, 530, 480, 354, 479, 516, 565, 564, 369, - 592, 599, 600, 692, 0, 605, 797, 798, 799, 614, - 0, 522, 365, 362, 0, 0, 0, 391, 517, 378, - 380, 381, 379, 511, 513, 619, 620, 621, 623, 624, - 625, 626, 0, 0, 0, 0, 627, 693, 711, 677, - 646, 607, 701, 643, 647, 648, 432, 433, 434, 435, - 714, 0, 0, 0, 598, 460, 461, 0, 403, 402, - 481, 355, 0, 0, 449, 431, 523, 361, 399, 451, - 437, 462, 463, 464, 465, 466, 0, 467, 468, 409, - 340, 346, 791, 1094, 504, 716, 753, 754, 638, 0, - 1112, 1089, 1091, 1092, 1096, 1101, 1102, 1103, 1104, 1106, - 1108, 1111, 1115, 790, 0, 694, 708, 795, 707, 787, - 510, 0, 541, 705, 652, 0, 698, 671, 672, 0, - 699, 667, 703, 0, 640, 0, 608, 611, 642, 729, - 730, 731, 352, 610, 733, 734, 735, 736, 737, 738, - 739, 732, 1114, 675, 651, 678, 589, 654, 653, 0, - 0, 689, 1028, 690, 691, 492, 493, 494, 495, 1098, - 717, 376, 609, 525, 526, 0, 676, 0, 0, 0, - 0, 0, 0, 0, 0, 681, 682, 679, 800, 0, - 740, 741, 0, 0, 603, 604, 408, 0, 622, 416, - 375, 509, 410, 587, 440, 0, 615, 683, 616, 528, - 529, 744, 749, 745, 746, 748, 769, 499, 430, 436, - 545, 450, 472, 531, 586, 507, 536, 373, 576, 547, - 478, 668, 696, 1123, 1093, 1122, 1124, 1125, 1121, 1126, - 1127, 1107, 982, 0, 1035, 1036, 1119, 1118, 1120, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 725, 724, 723, 722, 721, 720, 719, 718, 0, 0, - 665, 390, 788, 782, 789, 770, 773, 772, 747, 989, - 347, 645, 470, 524, 407, 712, 713, 0, 768, 1083, - 1046, 1047, 1048, 979, 1049, 1043, 1044, 980, 1045, 1084, - 1033, 1080, 1081, 1008, 1038, 1050, 1079, 1051, 1082, 1009, - 1085, 1128, 1129, 1057, 1041, 303, 1130, 1054, 1086, 1078, - 1077, 1052, 1034, 1087, 1088, 1016, 1011, 1055, 1056, 1042, - 1063, 1064, 1065, 1068, 981, 1069, 1070, 1071, 1072, 1073, - 1067, 1066, 1030, 1031, 1032, 1058, 1059, 1061, 1062, 1037, - 555, 1012, 1013, 1014, 1015, 0, 0, 593, 594, 595, - 618, 0, 596, 578, 644, 417, 348, 559, 585, 785, - 786, 0, 0, 0, 0, 0, 0, 0, 695, 706, - 742, 743, 0, 756, 757, 759, 761, 1074, 763, 552, - 553, 771, 0, 0, 441, 363, 364, 500, 501, 538, - 0, 442, 443, 444, 448, 445, 446, 447, 1060, 766, - 767, 764, 474, 537, 560, 546, 784, 487, 0, 792, - 634, 635, 793, 752, 751, 349, 0, 1039, 1040, 709, - 710, 0, 0, 1109, 486, 641, 0, 974, 341, 342, - 343, 1099, 345, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1026, 0, 0, 0, 0, 0, - 0, 0, 0, 506, 0, 0, 650, 684, 673, 762, - 637, 0, 0, 2161, 0, 0, 0, 977, 0, 0, - 0, 400, 0, 0, 469, 688, 669, 680, 670, 512, - 655, 656, 657, 664, 412, 658, 794, 660, 629, 661, - 630, 662, 663, 1017, 687, 636, 548, 488, 0, 704, - 0, 0, 1100, 1110, 0, 0, 0, 0, 0, 0, - 0, 0, 1095, 0, 0, 0, 0, 0, 968, 0, - 0, 1006, 1076, 1075, 993, 1003, 0, 0, 371, 270, - 631, 758, 633, 632, 994, 0, 995, 999, 1002, 998, - 996, 997, 0, 1090, 0, 0, 0, 0, 0, 0, - 0, 972, 0, 978, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 969, - 970, 0, 0, 0, 0, 1027, 0, 971, 0, 973, - 0, 0, 0, 0, 549, 577, 0, 590, 0, 438, - 439, 1022, 1000, 1004, 0, 0, 0, 0, 356, 556, - 574, 372, 543, 588, 377, 551, 567, 367, 505, 539, - 0, 0, 358, 572, 550, 483, 357, 0, 532, 397, - 414, 394, 503, 1001, 0, 1025, 1029, 393, 1116, 1023, - 582, 360, 0, 581, 502, 475, 568, 573, 484, 477, - 0, 359, 570, 482, 476, 452, 404, 1117, 453, 454, - 455, 456, 457, 458, 418, 1105, 473, 519, 419, 490, - 489, 491, 420, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 0, 0, 0, 612, 613, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 750, 1020, 0, 755, 0, 584, - 0, 0, 1097, 0, 0, 0, 554, 0, 0, 459, - 0, 0, 0, 1024, 0, 535, 508, 1113, 0, 0, - 533, 471, 569, 520, 575, 557, 583, 527, 521, 350, - 558, 396, 485, 368, 370, 783, 398, 401, 405, 406, - 496, 497, 514, 542, 561, 562, 563, 395, 382, 534, - 383, 415, 384, 351, 387, 386, 388, 544, 389, 353, - 515, 566, 0, 411, 530, 480, 354, 479, 516, 565, - 564, 369, 592, 2162, 2163, 692, 0, 605, 797, 798, - 799, 614, 0, 522, 365, 362, 0, 0, 0, 391, - 517, 378, 380, 381, 379, 511, 513, 619, 620, 621, - 623, 624, 625, 626, 0, 0, 0, 0, 627, 693, - 711, 677, 646, 607, 701, 643, 647, 648, 432, 433, - 434, 435, 714, 0, 0, 0, 598, 460, 461, 0, - 403, 402, 481, 355, 0, 0, 449, 431, 523, 361, - 399, 451, 437, 462, 463, 464, 465, 466, 0, 467, - 468, 409, 340, 346, 791, 1094, 504, 716, 753, 754, - 638, 0, 1112, 1089, 1091, 1092, 1096, 1101, 1102, 1103, - 1104, 1106, 1108, 1111, 1115, 790, 0, 694, 708, 795, - 707, 787, 510, 0, 541, 705, 652, 0, 698, 671, - 672, 0, 699, 667, 703, 0, 640, 0, 608, 611, - 642, 729, 730, 731, 352, 610, 733, 734, 735, 736, - 737, 738, 739, 732, 1114, 675, 651, 678, 589, 654, - 653, 0, 0, 689, 1028, 690, 691, 492, 493, 494, - 495, 1098, 717, 376, 609, 525, 526, 0, 676, 0, - 0, 0, 0, 0, 0, 0, 0, 681, 682, 679, - 800, 0, 740, 741, 0, 0, 603, 604, 408, 0, - 622, 416, 375, 509, 410, 587, 440, 0, 615, 683, - 616, 528, 529, 744, 749, 745, 746, 748, 769, 499, - 430, 436, 545, 450, 472, 531, 586, 507, 536, 373, - 576, 547, 478, 668, 696, 1123, 1093, 1122, 1124, 1125, - 1121, 1126, 1127, 1107, 982, 0, 1035, 1036, 1119, 1118, - 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 725, 724, 723, 722, 721, 720, 719, 718, - 0, 0, 665, 390, 788, 782, 789, 770, 773, 772, - 747, 989, 347, 645, 470, 524, 407, 712, 713, 0, - 768, 1083, 1046, 1047, 1048, 979, 1049, 1043, 1044, 980, - 1045, 1084, 1033, 1080, 1081, 1008, 1038, 1050, 1079, 1051, - 1082, 1009, 1085, 1128, 1129, 1057, 1041, 303, 1130, 1054, - 1086, 1078, 1077, 1052, 1034, 1087, 1088, 1016, 1011, 1055, - 1056, 1042, 1063, 1064, 1065, 1068, 981, 1069, 1070, 1071, - 1072, 1073, 1067, 1066, 1030, 1031, 1032, 1058, 1059, 1061, - 1062, 1037, 555, 1012, 1013, 1014, 1015, 0, 0, 593, - 594, 595, 618, 0, 596, 578, 644, 417, 348, 559, - 585, 785, 786, 0, 0, 0, 0, 0, 0, 0, - 695, 706, 742, 743, 0, 756, 757, 759, 761, 1074, - 763, 552, 553, 771, 0, 0, 441, 363, 364, 500, - 501, 538, 0, 442, 443, 444, 448, 445, 446, 447, - 1060, 766, 767, 764, 474, 537, 560, 546, 784, 487, - 0, 792, 634, 635, 793, 752, 751, 349, 0, 1039, - 1040, 709, 710, 0, 0, 1109, 486, 641, 0, 974, - 341, 342, 343, 1099, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1026, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 977, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 1017, 687, 636, 548, 488, - 0, 704, 0, 0, 1100, 1110, 0, 0, 0, 0, - 0, 0, 0, 0, 1095, 0, 0, 0, 0, 0, - 1634, 0, 0, 1006, 1076, 1075, 993, 1003, 0, 0, - 371, 270, 631, 758, 633, 632, 994, 0, 995, 999, - 1002, 998, 996, 997, 0, 1090, 0, 0, 0, 0, - 0, 0, 960, 972, 0, 978, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 969, 970, 0, 0, 0, 0, 1027, 0, 971, - 0, 973, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 1022, 1000, 1004, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 1001, 0, 1025, 1029, 393, - 1116, 1023, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 1117, - 453, 454, 455, 456, 457, 458, 418, 1105, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 1020, 0, 755, - 0, 584, 0, 0, 1097, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 1024, 0, 535, 508, 1113, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 1094, 504, 716, - 753, 754, 638, 0, 1112, 1089, 1091, 1092, 1096, 1101, - 1102, 1103, 1104, 1106, 1108, 1111, 1115, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 1114, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 1028, 690, 691, 492, - 493, 494, 495, 1098, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 1123, 1093, 1122, - 1124, 1125, 1121, 1126, 1127, 1107, 982, 0, 1035, 1036, - 1119, 1118, 1120, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 989, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 1083, 1046, 1047, 1048, 979, 1049, 1043, - 1044, 980, 1045, 1084, 1033, 1080, 1081, 1008, 1038, 1050, - 1079, 1051, 1082, 1009, 1085, 1128, 1129, 1057, 1041, 303, - 1130, 1054, 1086, 1078, 1077, 1052, 1034, 1087, 1088, 1016, - 1011, 1055, 1056, 1042, 1063, 1064, 1065, 1068, 981, 1069, - 1070, 1071, 1072, 1073, 1067, 1066, 1030, 1031, 1032, 1058, - 1059, 1061, 1062, 1037, 555, 1012, 1013, 1014, 1015, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 1074, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 1060, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 1039, 1040, 709, 710, 0, 0, 1109, 486, 641, - 0, 974, 341, 342, 343, 1099, 345, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1026, 0, - 0, 0, 0, 0, 0, 0, 0, 506, 0, 0, - 650, 684, 673, 762, 637, 0, 0, 0, 0, 0, - 0, 977, 0, 0, 0, 400, 0, 0, 469, 688, - 669, 680, 670, 512, 655, 656, 657, 664, 412, 658, - 794, 660, 629, 661, 630, 662, 663, 1017, 687, 636, - 548, 488, 0, 704, 0, 0, 1100, 1110, 0, 0, - 0, 0, 0, 0, 0, 0, 1095, 0, 0, 0, - 0, 0, 968, 0, 0, 1006, 1076, 1075, 993, 1003, - 0, 0, 371, 270, 631, 758, 633, 632, 994, 0, - 995, 999, 1002, 998, 996, 997, 0, 1090, 0, 0, - 0, 0, 0, 0, 0, 972, 0, 978, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 969, 970, 0, 0, 0, 0, 1027, - 0, 971, 0, 973, 0, 0, 0, 0, 549, 577, - 0, 590, 0, 438, 439, 1022, 1000, 1004, 0, 0, - 0, 0, 356, 556, 574, 372, 543, 588, 377, 551, - 567, 367, 505, 539, 0, 0, 358, 572, 550, 483, - 357, 0, 532, 397, 414, 394, 503, 1001, 0, 1025, - 1029, 393, 1116, 1023, 582, 360, 0, 581, 502, 475, - 568, 573, 484, 477, 0, 359, 570, 482, 476, 452, - 404, 1117, 453, 454, 455, 456, 457, 458, 418, 1105, - 473, 519, 419, 490, 489, 491, 420, 421, 422, 423, - 424, 425, 426, 427, 428, 429, 0, 0, 0, 0, - 0, 612, 613, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 750, 1020, - 0, 755, 0, 584, 0, 0, 1097, 0, 0, 0, - 554, 0, 0, 459, 0, 0, 0, 1024, 0, 535, - 508, 1113, 0, 0, 533, 471, 569, 520, 575, 557, - 583, 527, 521, 350, 558, 396, 485, 368, 370, 783, - 398, 401, 405, 406, 496, 497, 514, 542, 561, 562, - 563, 395, 382, 534, 383, 415, 384, 351, 387, 386, - 388, 544, 389, 353, 515, 566, 0, 411, 530, 480, - 354, 479, 516, 565, 564, 369, 592, 599, 600, 692, - 0, 605, 797, 798, 799, 614, 0, 522, 365, 362, - 0, 0, 0, 391, 517, 378, 380, 381, 379, 511, - 513, 619, 620, 621, 623, 624, 625, 626, 0, 0, - 0, 0, 627, 693, 711, 677, 646, 607, 701, 643, - 647, 648, 432, 433, 434, 435, 714, 0, 0, 0, - 598, 460, 461, 0, 403, 402, 481, 355, 0, 0, - 449, 431, 523, 361, 399, 451, 437, 462, 463, 464, - 465, 466, 0, 467, 468, 409, 340, 346, 791, 1094, - 504, 716, 753, 754, 638, 0, 1112, 1089, 1091, 1092, - 1096, 1101, 1102, 1103, 1104, 1106, 1108, 1111, 1115, 790, - 0, 694, 708, 795, 707, 787, 510, 0, 541, 705, - 652, 0, 698, 671, 672, 0, 699, 667, 703, 0, - 640, 0, 608, 611, 642, 729, 730, 731, 352, 610, - 733, 734, 735, 736, 737, 738, 739, 732, 1114, 675, - 651, 678, 589, 654, 653, 0, 0, 689, 1028, 690, - 691, 492, 493, 494, 495, 1098, 717, 376, 609, 525, - 526, 0, 676, 0, 0, 0, 0, 0, 0, 0, - 0, 681, 682, 679, 800, 0, 740, 741, 0, 0, - 603, 604, 408, 0, 622, 416, 375, 509, 410, 587, - 440, 0, 615, 683, 616, 528, 529, 744, 749, 745, - 746, 748, 769, 499, 430, 436, 545, 450, 472, 531, - 586, 507, 536, 373, 576, 547, 478, 668, 696, 1123, - 1093, 1122, 1124, 1125, 1121, 1126, 1127, 1107, 982, 0, - 1035, 1036, 1119, 1118, 1120, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 725, 724, 723, 722, - 721, 720, 719, 718, 0, 0, 665, 390, 788, 782, - 789, 770, 773, 772, 747, 989, 347, 645, 470, 524, - 407, 712, 713, 0, 768, 1083, 1046, 1047, 1048, 979, - 1049, 1043, 1044, 980, 1045, 1084, 1033, 1080, 1081, 1008, - 1038, 1050, 1079, 1051, 1082, 1009, 1085, 1128, 1129, 1057, - 1041, 303, 1130, 1054, 1086, 1078, 1077, 1052, 1034, 1087, - 1088, 1016, 1011, 1055, 1056, 1042, 1063, 1064, 1065, 1068, - 981, 1069, 1070, 1071, 1072, 1073, 1067, 1066, 1030, 1031, - 1032, 1058, 1059, 1061, 1062, 1037, 555, 1012, 1013, 1014, - 1015, 0, 0, 593, 594, 595, 618, 0, 596, 578, - 644, 417, 348, 559, 585, 785, 786, 0, 0, 0, - 0, 0, 0, 0, 695, 706, 742, 743, 0, 756, - 757, 759, 761, 1074, 763, 552, 553, 771, 0, 0, - 441, 363, 364, 500, 501, 538, 0, 442, 443, 444, - 448, 445, 446, 447, 1060, 766, 767, 764, 474, 537, - 560, 546, 784, 487, 0, 792, 634, 635, 793, 752, - 751, 349, 0, 1039, 1040, 709, 710, 0, 0, 1109, - 486, 641, 0, 974, 341, 342, 343, 344, 345, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 201, 246, - 200, 233, 202, 0, 0, 0, 0, 0, 0, 506, - 0, 0, 650, 684, 673, 762, 637, 0, 234, 0, - 0, 0, 0, 0, 0, 226, 0, 400, 0, 235, - 469, 688, 669, 680, 670, 512, 655, 656, 657, 664, - 412, 658, 659, 660, 629, 661, 630, 662, 663, 170, - 687, 636, 548, 488, 0, 704, 0, 0, 0, 0, - 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 239, 0, 0, 269, 0, 0, - 0, 0, 0, 0, 371, 270, 631, 758, 633, 632, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 374, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 261, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 549, 577, 0, 590, 0, 438, 439, 0, 0, 0, - 0, 0, 0, 0, 356, 556, 574, 372, 543, 588, - 377, 551, 567, 367, 505, 539, 0, 0, 358, 572, - 550, 483, 357, 0, 532, 397, 414, 394, 503, 0, - 0, 571, 601, 393, 591, 0, 582, 360, 0, 581, - 502, 475, 568, 573, 484, 477, 0, 359, 570, 482, - 476, 452, 404, 617, 453, 454, 455, 456, 457, 458, - 418, 518, 473, 519, 419, 490, 489, 491, 420, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 0, 0, 0, 612, 613, 0, 0, 0, 0, 0, - 0, 0, 199, 231, 243, 232, 84, 151, 0, 0, - 750, 0, 247, 755, 0, 584, 0, 0, 262, 0, - 0, 0, 554, 0, 0, 459, 153, 225, 224, 602, - 0, 535, 508, 275, 0, 0, 533, 471, 569, 520, - 575, 557, 583, 527, 521, 350, 558, 396, 485, 368, - 370, 284, 398, 401, 405, 406, 496, 497, 514, 542, - 561, 562, 563, 395, 382, 534, 383, 415, 384, 351, - 387, 386, 388, 544, 389, 353, 515, 566, 152, 411, - 530, 480, 354, 479, 516, 565, 564, 369, 592, 599, - 600, 692, 0, 605, 726, 727, 728, 614, 0, 522, - 365, 362, 0, 0, 0, 391, 517, 378, 380, 381, - 379, 511, 513, 619, 620, 621, 623, 624, 625, 626, - 0, 0, 0, 0, 627, 693, 711, 677, 646, 607, - 701, 643, 647, 648, 432, 433, 434, 435, 714, 0, - 0, 0, 598, 460, 461, 0, 403, 402, 481, 355, - 0, 0, 449, 431, 523, 361, 399, 451, 437, 462, - 463, 464, 465, 466, 0, 467, 468, 409, 340, 346, - 579, 392, 504, 716, 753, 754, 638, 0, 702, 639, - 649, 385, 674, 686, 685, 498, 597, 265, 697, 700, - 628, 276, 0, 694, 708, 666, 707, 277, 510, 0, - 541, 705, 652, 0, 698, 671, 672, 0, 699, 667, - 703, 0, 640, 0, 608, 611, 642, 729, 730, 731, - 352, 610, 733, 734, 735, 736, 737, 738, 739, 732, - 580, 675, 651, 678, 589, 654, 653, 0, 0, 689, - 606, 690, 691, 492, 493, 494, 495, 413, 717, 376, - 609, 525, 526, 167, 676, 0, 0, 0, 0, 0, - 0, 0, 0, 681, 682, 679, 274, 0, 740, 741, - 0, 0, 603, 604, 408, 0, 622, 416, 375, 509, - 410, 587, 440, 0, 615, 683, 616, 528, 529, 744, - 749, 745, 746, 748, 769, 499, 430, 436, 545, 450, - 472, 531, 586, 507, 536, 373, 576, 547, 478, 668, - 696, 0, 0, 0, 0, 0, 0, 0, 0, 79, - 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 725, 724, - 723, 722, 721, 720, 719, 718, 0, 0, 665, 390, - 282, 366, 283, 770, 773, 772, 747, 0, 347, 645, - 470, 524, 407, 712, 713, 72, 768, 285, 286, 287, - 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, - 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, - 311, 715, 302, 303, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, - 0, 0, 334, 774, 775, 776, 777, 778, 0, 0, - 335, 336, 337, 0, 0, 300, 301, 328, 555, 329, - 330, 331, 332, 0, 0, 593, 594, 595, 618, 0, - 596, 578, 644, 417, 348, 559, 585, 278, 279, 55, - 263, 266, 268, 267, 0, 73, 695, 706, 742, 743, - 9, 756, 757, 759, 761, 760, 763, 552, 553, 771, - 0, 0, 441, 363, 364, 500, 501, 538, 0, 442, - 443, 444, 448, 445, 446, 447, 765, 766, 767, 764, - 474, 537, 560, 546, 273, 487, 174, 280, 634, 635, - 281, 752, 751, 349, 0, 338, 339, 709, 710, 0, - 0, 540, 486, 641, 341, 342, 343, 344, 345, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 201, 246, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 506, - 0, 0, 650, 684, 673, 762, 637, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 400, 0, 0, - 469, 688, 669, 680, 670, 512, 655, 656, 657, 664, - 412, 658, 794, 660, 629, 661, 630, 662, 663, 1275, - 687, 636, 548, 488, 0, 704, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 239, 0, 0, 269, 0, 0, - 0, 0, 0, 0, 371, 270, 631, 758, 633, 632, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 374, - 3081, 3084, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 549, 577, 0, 590, 0, 438, 439, 0, 0, 0, - 0, 0, 0, 0, 356, 556, 574, 372, 543, 588, - 377, 551, 567, 367, 505, 539, 0, 0, 358, 572, - 550, 483, 357, 0, 532, 397, 414, 394, 503, 0, - 0, 571, 601, 393, 591, 0, 582, 360, 0, 581, - 502, 475, 568, 573, 484, 477, 0, 359, 570, 482, - 476, 452, 404, 617, 453, 454, 455, 456, 457, 458, - 418, 518, 473, 519, 419, 490, 489, 491, 420, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 0, 0, 0, 612, 613, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 750, 0, 247, 755, 3085, 584, 0, 0, 0, 3080, - 0, 3079, 554, 3076, 3082, 459, 0, 0, 0, 602, - 0, 535, 508, 796, 0, 0, 533, 471, 569, 520, - 575, 557, 583, 527, 521, 350, 558, 396, 485, 368, - 370, 783, 398, 401, 405, 406, 496, 497, 514, 542, - 561, 562, 563, 395, 382, 534, 383, 415, 384, 351, - 387, 386, 388, 544, 389, 353, 515, 566, 3083, 411, - 530, 480, 354, 479, 516, 565, 564, 369, 592, 599, - 600, 692, 0, 605, 797, 798, 799, 614, 0, 522, - 365, 362, 0, 0, 0, 391, 517, 378, 380, 381, - 379, 511, 513, 619, 620, 621, 623, 624, 625, 626, - 0, 0, 0, 0, 627, 693, 711, 677, 646, 607, - 701, 643, 647, 648, 432, 433, 434, 435, 714, 0, - 0, 0, 598, 460, 461, 0, 403, 402, 481, 355, - 0, 0, 449, 431, 523, 361, 399, 451, 437, 462, - 463, 464, 465, 466, 3077, 467, 468, 409, 340, 346, - 791, 392, 504, 716, 753, 754, 638, 0, 702, 639, - 649, 385, 674, 686, 685, 498, 597, 0, 697, 700, - 628, 790, 0, 694, 708, 795, 707, 787, 510, 0, - 541, 705, 652, 0, 698, 671, 672, 0, 699, 667, - 703, 0, 640, 0, 608, 611, 642, 729, 730, 731, - 352, 610, 733, 734, 735, 736, 737, 738, 739, 732, - 580, 675, 651, 678, 589, 654, 653, 0, 0, 689, - 606, 690, 691, 492, 493, 494, 495, 413, 717, 376, - 609, 525, 526, 0, 676, 0, 0, 0, 0, 0, - 0, 0, 0, 681, 682, 679, 800, 0, 740, 741, - 0, 0, 603, 604, 408, 0, 622, 416, 375, 509, - 410, 587, 440, 0, 615, 683, 616, 528, 529, 744, - 749, 745, 746, 748, 769, 499, 430, 436, 545, 450, - 472, 531, 586, 507, 536, 373, 576, 547, 478, 668, - 696, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 725, 724, - 723, 722, 721, 720, 719, 718, 0, 0, 665, 390, - 788, 782, 789, 770, 773, 772, 747, 0, 347, 645, - 470, 524, 407, 712, 713, 0, 768, 285, 286, 287, - 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, - 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, - 311, 715, 302, 303, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, - 0, 0, 334, 774, 775, 776, 777, 778, 0, 0, - 335, 336, 337, 0, 0, 300, 301, 328, 555, 329, - 330, 331, 332, 0, 0, 593, 594, 595, 618, 0, - 596, 578, 644, 417, 348, 559, 585, 785, 786, 0, - 0, 0, 0, 0, 0, 0, 695, 706, 742, 743, - 0, 756, 757, 759, 761, 760, 763, 552, 553, 771, - 0, 0, 441, 363, 364, 500, 501, 538, 0, 442, - 443, 444, 448, 445, 446, 447, 765, 766, 767, 764, - 474, 537, 560, 546, 784, 487, 0, 792, 634, 635, - 793, 752, 751, 349, 0, 338, 339, 709, 710, 0, - 0, 540, 486, 641, 341, 342, 343, 344, 345, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 201, 246, - 200, 233, 202, 0, 0, 0, 0, 0, 0, 506, - 822, 0, 650, 684, 673, 762, 637, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 400, 0, 0, - 469, 688, 669, 680, 670, 512, 655, 656, 657, 664, - 412, 658, 794, 660, 629, 661, 630, 662, 663, 0, - 687, 636, 548, 488, 0, 704, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 829, 0, 0, 0, 0, - 0, 0, 0, 0, 828, 0, 0, 269, 0, 0, - 0, 0, 0, 0, 371, 270, 631, 758, 633, 632, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 374, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 549, 577, 0, 590, 0, 438, 439, 0, 0, 0, - 0, 0, 0, 0, 356, 556, 574, 372, 543, 588, - 377, 551, 567, 367, 505, 539, 0, 0, 358, 572, - 550, 483, 357, 0, 532, 397, 414, 394, 503, 0, - 0, 571, 601, 393, 591, 0, 582, 360, 0, 581, - 502, 475, 568, 573, 484, 477, 0, 359, 570, 482, - 476, 452, 404, 617, 453, 454, 455, 456, 457, 458, - 418, 518, 473, 519, 419, 490, 489, 491, 420, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 0, 0, 0, 612, 613, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 824, 825, 0, - 750, 0, 247, 755, 0, 584, 0, 0, 0, 0, - 0, 0, 554, 0, 0, 459, 0, 0, 0, 602, - 0, 535, 508, 796, 0, 0, 533, 471, 569, 520, - 575, 557, 583, 527, 521, 350, 558, 396, 485, 368, - 370, 783, 398, 401, 405, 406, 496, 497, 514, 542, - 561, 562, 563, 395, 382, 534, 383, 415, 384, 351, - 387, 386, 388, 544, 389, 353, 515, 566, 0, 411, - 530, 480, 354, 479, 516, 565, 564, 369, 592, 599, - 600, 692, 0, 605, 797, 798, 799, 614, 0, 522, - 365, 362, 0, 0, 0, 391, 517, 378, 380, 381, - 379, 511, 513, 619, 620, 621, 623, 624, 625, 626, - 0, 0, 0, 0, 627, 693, 711, 677, 646, 607, - 701, 643, 647, 648, 432, 433, 434, 435, 714, 0, - 0, 0, 598, 460, 461, 0, 403, 402, 481, 355, - 0, 0, 449, 431, 523, 361, 399, 451, 437, 462, - 463, 464, 465, 466, 0, 467, 468, 409, 340, 346, - 791, 392, 504, 716, 753, 754, 638, 0, 702, 639, - 649, 385, 674, 686, 685, 498, 597, 0, 697, 700, - 628, 790, 0, 694, 708, 795, 707, 787, 510, 0, - 541, 705, 652, 0, 698, 671, 672, 0, 699, 667, - 703, 0, 640, 0, 608, 611, 642, 729, 730, 731, - 352, 610, 733, 734, 735, 736, 737, 738, 739, 732, - 580, 675, 651, 678, 589, 654, 653, 0, 0, 689, - 606, 690, 691, 492, 493, 494, 495, 823, 827, 376, - 609, 525, 526, 838, 676, 0, 0, 0, 0, 0, - 0, 0, 0, 681, 682, 679, 800, 0, 740, 741, - 0, 0, 603, 604, 408, 0, 622, 416, 375, 509, - 410, 587, 440, 0, 615, 683, 616, 528, 529, 744, - 749, 745, 746, 748, 769, 499, 430, 436, 545, 450, - 472, 531, 586, 507, 536, 373, 576, 547, 478, 668, - 696, 0, 0, 0, 0, 0, 0, 0, 0, 79, - 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 725, 724, - 723, 722, 721, 720, 719, 718, 0, 0, 665, 390, - 788, 782, 789, 770, 773, 772, 747, 0, 347, 645, - 470, 524, 407, 712, 713, 0, 768, 285, 286, 287, - 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, - 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, - 311, 715, 302, 303, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, - 0, 0, 334, 774, 775, 776, 777, 778, 0, 0, - 335, 336, 337, 0, 0, 300, 301, 328, 555, 329, - 330, 331, 332, 0, 0, 593, 594, 595, 618, 0, - 596, 578, 644, 417, 348, 559, 585, 785, 786, 0, - 0, 0, 0, 0, 0, 0, 695, 706, 742, 743, - 0, 756, 757, 759, 761, 760, 763, 552, 553, 771, - 0, 0, 441, 363, 364, 500, 501, 538, 0, 442, - 443, 444, 448, 445, 446, 447, 765, 766, 767, 764, - 474, 537, 560, 546, 784, 487, 0, 792, 634, 635, - 793, 752, 751, 349, 0, 338, 339, 709, 710, 0, - 0, 540, 486, 641, 341, 342, 343, 344, 345, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 506, - 0, 0, 650, 684, 673, 762, 637, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 400, 0, 0, - 469, 688, 669, 680, 670, 512, 655, 656, 657, 664, - 412, 658, 794, 660, 629, 661, 630, 662, 663, 0, - 687, 636, 548, 488, 0, 704, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1655, 0, 0, 269, 0, 0, - 993, 1003, 0, 0, 371, 270, 631, 758, 633, 632, - 994, 0, 995, 999, 1002, 998, 996, 997, 0, 374, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 549, 577, 0, 590, 0, 438, 439, 0, 1000, 0, - 0, 0, 0, 0, 356, 556, 574, 372, 543, 588, - 377, 551, 567, 367, 505, 539, 0, 0, 358, 572, - 550, 483, 357, 0, 532, 397, 414, 394, 503, 1001, - 0, 571, 601, 393, 591, 0, 582, 360, 0, 581, - 502, 475, 568, 573, 484, 477, 0, 359, 570, 482, - 476, 452, 404, 617, 453, 454, 455, 456, 457, 458, - 418, 518, 473, 519, 419, 490, 489, 491, 420, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 0, 0, 0, 612, 613, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 750, 0, 0, 755, 0, 584, 0, 0, 0, 0, - 0, 0, 554, 0, 0, 459, 0, 0, 0, 602, - 0, 535, 508, 796, 0, 0, 533, 471, 569, 520, - 575, 557, 583, 527, 521, 350, 558, 396, 485, 368, - 370, 783, 398, 401, 405, 406, 496, 497, 514, 542, - 561, 562, 563, 395, 382, 534, 383, 415, 384, 351, - 387, 386, 388, 544, 389, 353, 515, 566, 0, 411, - 530, 480, 354, 479, 516, 565, 564, 369, 592, 599, - 600, 692, 0, 605, 797, 798, 799, 614, 0, 522, - 365, 362, 0, 0, 0, 391, 517, 378, 380, 381, - 379, 511, 513, 619, 620, 621, 623, 624, 625, 626, - 0, 0, 0, 0, 627, 693, 711, 677, 646, 607, - 701, 643, 647, 648, 432, 433, 434, 435, 714, 0, - 0, 0, 598, 460, 461, 0, 403, 402, 481, 355, - 0, 0, 449, 431, 523, 361, 399, 451, 437, 462, - 463, 464, 465, 466, 0, 467, 468, 409, 340, 346, - 791, 392, 504, 716, 753, 754, 638, 0, 702, 639, - 649, 385, 674, 686, 685, 498, 597, 0, 697, 700, - 628, 790, 0, 694, 708, 795, 707, 787, 510, 0, - 541, 705, 652, 0, 698, 671, 672, 0, 699, 667, - 703, 0, 640, 0, 608, 611, 642, 729, 730, 731, - 352, 610, 733, 734, 735, 736, 737, 738, 739, 732, - 580, 675, 651, 678, 589, 654, 653, 0, 0, 689, - 606, 690, 691, 492, 493, 494, 495, 413, 717, 376, - 609, 525, 526, 0, 676, 0, 0, 0, 0, 0, - 0, 0, 0, 681, 682, 679, 800, 0, 740, 741, - 0, 0, 603, 604, 408, 0, 622, 416, 375, 509, - 410, 587, 440, 0, 615, 683, 616, 528, 529, 744, - 749, 745, 746, 748, 769, 499, 430, 436, 545, 450, - 472, 531, 586, 507, 536, 373, 576, 547, 478, 668, - 696, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 725, 724, - 723, 722, 721, 720, 719, 718, 0, 0, 665, 390, - 788, 782, 789, 770, 773, 772, 747, 0, 347, 645, - 470, 524, 407, 712, 713, 0, 768, 285, 286, 287, - 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, - 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, - 311, 715, 302, 303, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, - 0, 0, 334, 774, 775, 776, 777, 778, 0, 0, - 335, 336, 337, 0, 0, 300, 301, 328, 555, 329, - 330, 331, 332, 0, 0, 593, 594, 595, 618, 0, - 596, 578, 644, 417, 348, 559, 585, 785, 786, 0, - 0, 0, 0, 0, 0, 0, 695, 706, 742, 743, - 0, 756, 757, 759, 761, 760, 763, 552, 553, 771, - 0, 0, 441, 363, 364, 500, 501, 538, 0, 442, - 443, 444, 448, 445, 446, 447, 765, 766, 767, 764, - 474, 537, 560, 546, 784, 487, 0, 792, 634, 635, - 793, 752, 751, 349, 0, 338, 339, 709, 710, 0, - 0, 540, 486, 641, 341, 342, 343, 344, 345, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 506, - 0, 0, 650, 684, 673, 762, 637, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 400, 0, 0, - 469, 688, 669, 680, 670, 512, 655, 656, 657, 664, - 412, 658, 794, 660, 629, 661, 630, 662, 663, 0, - 687, 636, 548, 488, 0, 704, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, - 0, 0, 0, 0, 371, 270, 631, 758, 633, 632, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 374, - 3081, 3084, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 549, 577, 0, 590, 0, 438, 439, 0, 0, 0, - 0, 0, 0, 0, 356, 556, 574, 372, 543, 588, - 377, 551, 567, 367, 505, 539, 0, 0, 358, 572, - 550, 483, 357, 0, 532, 397, 414, 394, 503, 0, - 0, 571, 601, 393, 591, 0, 582, 360, 0, 581, - 502, 475, 568, 573, 484, 477, 0, 359, 570, 482, - 476, 452, 404, 617, 453, 454, 455, 456, 457, 458, - 418, 518, 473, 519, 419, 490, 489, 491, 420, 421, - 422, 423, 424, 425, 426, 427, 428, 429, 0, 0, - 0, 0, 0, 612, 613, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 750, 0, 0, 755, 3085, 584, 0, 0, 0, 3080, - 0, 3079, 554, 3076, 3082, 459, 0, 0, 0, 602, - 0, 535, 508, 796, 0, 0, 533, 471, 569, 520, - 575, 557, 583, 527, 521, 350, 558, 396, 485, 368, - 370, 783, 398, 401, 405, 406, 496, 497, 514, 542, - 561, 562, 563, 395, 382, 534, 383, 415, 384, 351, - 387, 386, 388, 544, 389, 353, 515, 566, 3083, 411, - 530, 480, 354, 479, 516, 565, 564, 369, 592, 599, - 600, 692, 0, 605, 797, 798, 799, 614, 0, 522, - 365, 362, 0, 0, 0, 391, 517, 378, 380, 381, - 379, 511, 513, 619, 620, 621, 623, 624, 625, 626, - 0, 0, 0, 0, 627, 693, 711, 677, 646, 607, - 701, 643, 647, 648, 432, 433, 434, 435, 714, 0, - 0, 0, 598, 460, 461, 0, 403, 402, 481, 355, - 0, 0, 449, 431, 523, 361, 399, 451, 437, 462, - 463, 464, 465, 466, 3077, 467, 468, 409, 340, 346, - 791, 392, 504, 716, 753, 754, 638, 0, 702, 639, - 649, 385, 674, 686, 685, 498, 597, 0, 697, 700, - 628, 790, 0, 694, 708, 795, 707, 787, 510, 0, - 541, 705, 652, 0, 698, 671, 672, 0, 699, 667, - 703, 0, 640, 0, 608, 611, 642, 729, 730, 731, - 352, 610, 733, 734, 735, 736, 737, 738, 739, 732, - 580, 675, 651, 678, 589, 654, 653, 0, 0, 689, - 606, 690, 691, 492, 493, 494, 495, 413, 717, 376, - 609, 525, 526, 0, 676, 0, 0, 0, 0, 0, - 0, 0, 0, 681, 682, 679, 800, 0, 740, 741, - 0, 0, 603, 604, 408, 0, 622, 416, 375, 509, - 410, 587, 440, 0, 615, 683, 616, 528, 529, 744, - 749, 745, 746, 748, 769, 499, 430, 436, 545, 450, - 472, 531, 586, 507, 536, 373, 576, 547, 478, 668, - 696, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 725, 724, - 723, 722, 721, 720, 719, 718, 0, 0, 665, 390, - 788, 782, 789, 770, 773, 772, 747, 0, 347, 645, - 470, 524, 407, 712, 713, 0, 768, 285, 286, 287, - 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, - 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, - 311, 715, 302, 303, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, - 0, 0, 334, 774, 775, 776, 777, 778, 0, 0, - 335, 336, 337, 0, 0, 300, 301, 328, 555, 329, - 330, 331, 332, 0, 0, 593, 594, 595, 618, 0, - 596, 578, 644, 417, 348, 559, 585, 785, 786, 0, - 0, 0, 0, 0, 0, 0, 695, 706, 742, 743, - 0, 756, 757, 759, 761, 760, 763, 552, 553, 771, - 0, 0, 441, 363, 364, 500, 501, 538, 0, 442, - 443, 444, 448, 445, 446, 447, 765, 766, 767, 764, - 474, 537, 560, 546, 784, 487, 0, 792, 634, 635, - 793, 752, 751, 349, 0, 338, 339, 709, 710, 0, - 0, 540, 486, 641, 341, 342, 343, 344, 345, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 506, - 0, 0, 650, 684, 673, 762, 637, 0, 1354, 0, - 0, 0, 0, 0, 0, 0, 0, 400, 0, 0, - 469, 688, 669, 680, 670, 512, 655, 656, 657, 664, - 412, 658, 794, 660, 629, 661, 630, 662, 663, 0, - 687, 636, 548, 488, 0, 704, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, - 0, 0, 0, 0, 371, 270, 631, 758, 633, 632, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 374, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 549, 577, 0, 590, 0, 3528, 3529, 1334, 0, 0, - 0, 0, 0, 0, 356, 556, 574, 372, 543, 588, - 377, 551, 567, 367, 505, 539, 0, 0, 3522, 3525, - 3526, 3527, 3530, 0, 3535, 3531, 3532, 3533, 3534, 0, - 0, 3518, 3519, 3520, 3521, 1332, 3497, 3523, 0, 3498, - 502, 3499, 3500, 3501, 3502, 3503, 1337, 3504, 3505, 3506, - 3507, 3508, 3515, 3516, 3509, 3510, 3511, 3512, 3513, 3514, - 3536, 3537, 3538, 3539, 3540, 3541, 3542, 3543, 3545, 3544, - 3546, 3547, 3548, 3549, 3550, 3551, 3552, 3553, 1365, 1367, - 1369, 1371, 1374, 612, 613, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 750, 0, 0, 755, 0, 584, 0, 0, 0, 0, - 0, 0, 554, 0, 0, 459, 0, 0, 0, 3517, - 0, 535, 508, 796, 0, 0, 533, 471, 569, 520, - 575, 557, 583, 527, 521, 350, 558, 396, 485, 368, - 370, 783, 398, 401, 405, 406, 496, 497, 514, 542, - 561, 562, 563, 395, 382, 534, 383, 415, 384, 351, - 387, 386, 388, 544, 389, 353, 515, 566, 0, 411, - 530, 480, 354, 479, 516, 565, 564, 369, 592, 599, - 600, 692, 0, 605, 797, 798, 799, 614, 0, 522, - 365, 362, 0, 0, 0, 391, 517, 378, 380, 381, - 379, 511, 513, 619, 620, 621, 623, 624, 625, 626, - 0, 0, 0, 0, 627, 693, 711, 677, 646, 607, - 701, 643, 647, 648, 432, 433, 434, 435, 714, 0, - 0, 0, 598, 460, 461, 0, 403, 402, 481, 355, - 0, 0, 449, 431, 523, 361, 399, 451, 437, 462, - 463, 464, 465, 466, 0, 467, 468, 409, 340, 346, - 791, 392, 504, 716, 753, 754, 638, 0, 702, 639, - 649, 385, 674, 686, 685, 498, 597, 0, 697, 700, - 628, 790, 0, 694, 708, 795, 707, 787, 510, 0, - 541, 705, 652, 0, 698, 671, 672, 0, 699, 667, - 703, 0, 640, 0, 608, 611, 642, 729, 730, 731, - 352, 610, 733, 734, 735, 736, 737, 738, 739, 732, - 580, 675, 651, 678, 589, 654, 653, 0, 0, 689, - 606, 690, 691, 492, 493, 494, 495, 413, 717, 376, - 609, 525, 526, 0, 676, 0, 0, 0, 0, 0, - 0, 0, 0, 681, 682, 679, 800, 0, 740, 741, - 0, 0, 603, 604, 408, 0, 622, 416, 375, 509, - 410, 587, 440, 0, 615, 683, 616, 528, 529, 744, - 749, 745, 746, 748, 769, 499, 430, 436, 545, 450, - 472, 531, 586, 507, 536, 373, 576, 547, 478, 668, - 696, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 725, 724, - 723, 722, 721, 720, 719, 718, 0, 0, 665, 390, - 788, 782, 789, 770, 773, 772, 747, 0, 347, 3524, - 470, 524, 407, 712, 713, 0, 768, 285, 286, 287, - 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, - 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, - 311, 715, 302, 303, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, - 0, 0, 334, 774, 775, 776, 777, 778, 0, 0, - 335, 336, 337, 0, 0, 300, 301, 328, 555, 329, - 330, 331, 332, 0, 0, 593, 594, 595, 618, 0, - 596, 578, 644, 417, 348, 559, 585, 785, 786, 0, - 0, 0, 0, 0, 0, 0, 695, 706, 742, 743, - 0, 756, 757, 759, 761, 760, 763, 552, 553, 771, - 0, 0, 441, 363, 364, 500, 501, 538, 0, 442, - 443, 444, 448, 445, 446, 447, 765, 766, 767, 764, - 474, 537, 560, 546, 784, 487, 0, 792, 634, 635, - 793, 752, 751, 3496, 0, 338, 339, 709, 710, 0, - 0, 540, 486, 641, 1826, 341, 342, 343, 344, 345, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, - 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 506, 0, 0, 650, 684, 673, 762, 637, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 400, 0, - 0, 469, 688, 669, 680, 670, 512, 655, 656, 657, - 664, 412, 658, 794, 660, 629, 661, 630, 662, 663, - 1275, 687, 636, 548, 488, 0, 704, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1823, 0, 0, 269, 0, - 0, 0, 0, 0, 0, 371, 270, 631, 758, 633, - 632, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 374, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 549, 577, 0, 590, 0, 438, 439, 0, 0, - 0, 0, 0, 0, 0, 356, 556, 574, 372, 543, - 588, 377, 551, 567, 367, 505, 539, 0, 0, 358, - 572, 550, 483, 357, 0, 532, 397, 414, 394, 503, - 0, 0, 571, 601, 393, 591, 0, 582, 360, 0, - 581, 502, 475, 568, 573, 484, 477, 0, 359, 570, - 482, 476, 452, 404, 617, 453, 454, 455, 456, 457, - 458, 418, 518, 473, 519, 419, 490, 489, 491, 420, - 421, 422, 423, 424, 425, 426, 427, 428, 429, 0, - 0, 0, 0, 0, 612, 613, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 750, 0, 247, 755, 0, 584, 0, 0, 0, - 0, 0, 0, 554, 0, 0, 459, 0, 0, 0, - 602, 0, 535, 508, 796, 0, 0, 533, 471, 569, - 520, 575, 557, 583, 527, 521, 350, 558, 396, 485, - 368, 370, 783, 398, 401, 405, 406, 496, 497, 514, - 542, 561, 562, 563, 395, 382, 534, 383, 415, 384, - 351, 387, 386, 388, 544, 389, 353, 515, 566, 0, - 411, 530, 480, 354, 479, 516, 565, 564, 369, 592, - 599, 600, 692, 0, 605, 797, 798, 799, 614, 0, - 522, 365, 362, 0, 0, 0, 391, 517, 378, 380, - 381, 379, 511, 513, 619, 620, 621, 623, 624, 625, - 626, 0, 0, 0, 0, 627, 693, 711, 677, 646, - 607, 701, 643, 647, 648, 432, 433, 434, 435, 714, - 0, 0, 0, 598, 460, 461, 0, 403, 402, 481, - 355, 0, 0, 449, 431, 523, 361, 399, 451, 437, - 462, 463, 464, 465, 466, 0, 467, 468, 409, 340, - 346, 791, 392, 504, 716, 753, 754, 638, 0, 702, - 639, 649, 385, 674, 686, 685, 498, 597, 0, 697, - 700, 628, 790, 0, 694, 708, 795, 707, 787, 510, - 0, 541, 705, 652, 0, 698, 671, 672, 0, 699, - 667, 703, 0, 640, 0, 608, 611, 642, 729, 730, - 731, 352, 610, 733, 734, 735, 736, 737, 738, 739, - 732, 580, 675, 651, 678, 589, 654, 653, 0, 0, - 689, 606, 690, 691, 492, 493, 494, 495, 413, 717, - 376, 609, 525, 526, 0, 676, 0, 0, 0, 0, - 0, 0, 0, 0, 681, 682, 679, 800, 0, 740, - 741, 0, 0, 603, 604, 408, 0, 622, 416, 375, - 509, 410, 587, 440, 0, 615, 683, 616, 528, 529, - 744, 749, 745, 746, 748, 769, 499, 430, 436, 545, - 450, 472, 531, 586, 507, 536, 373, 576, 547, 478, - 668, 696, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 326, 327, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 725, - 724, 723, 722, 721, 720, 719, 718, 0, 0, 665, - 390, 788, 782, 789, 770, 773, 772, 747, 0, 347, - 645, 470, 524, 407, 712, 713, 0, 768, 285, 286, - 287, 288, 289, 290, 291, 292, 333, 293, 294, 295, - 296, 297, 298, 299, 304, 305, 306, 307, 308, 309, - 310, 311, 715, 302, 303, 312, 313, 314, 315, 316, - 317, 318, 319, 320, 321, 322, 323, 324, 325, 0, - 0, 0, 0, 334, 774, 775, 776, 777, 778, 0, - 0, 335, 336, 337, 0, 0, 300, 301, 328, 555, - 329, 330, 331, 332, 0, 0, 593, 594, 595, 618, - 0, 596, 578, 644, 417, 348, 559, 585, 785, 786, - 0, 0, 0, 0, 0, 0, 0, 695, 706, 742, - 743, 0, 756, 757, 759, 761, 760, 763, 552, 553, - 771, 0, 0, 441, 363, 364, 500, 501, 538, 0, - 442, 443, 444, 448, 445, 446, 447, 765, 766, 767, - 764, 474, 537, 560, 546, 784, 487, 0, 792, 634, - 635, 793, 752, 751, 349, 0, 338, 339, 709, 710, - 0, 0, 540, 486, 641, 0, 2476, 341, 342, 343, - 344, 345, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 506, 0, 0, 650, 684, 673, 762, 637, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 400, 0, 0, 469, 688, 669, 680, 670, 512, 655, - 656, 657, 664, 412, 658, 794, 660, 629, 661, 630, - 662, 663, 0, 687, 636, 548, 488, 0, 704, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 269, 0, 0, 0, 0, 0, 0, 371, 270, 631, - 758, 633, 632, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 374, 0, 3103, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 549, 577, 0, 590, 0, 438, 439, - 0, 0, 0, 0, 0, 0, 0, 356, 556, 574, - 372, 543, 588, 377, 551, 567, 367, 505, 539, 0, - 0, 358, 572, 550, 483, 357, 0, 532, 397, 414, - 394, 503, 0, 0, 571, 601, 393, 591, 0, 582, - 360, 0, 581, 502, 475, 568, 573, 484, 477, 0, - 359, 570, 482, 476, 452, 404, 617, 453, 454, 455, - 456, 457, 458, 418, 518, 473, 519, 419, 490, 489, - 491, 420, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 0, 0, 0, 0, 612, 613, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 750, 0, 0, 755, 3102, 584, 0, - 0, 0, 3109, 3105, 3107, 554, 0, 3106, 459, 0, - 0, 0, 602, 0, 535, 508, 796, 0, 3100, 533, - 471, 569, 520, 575, 557, 583, 527, 521, 350, 558, - 396, 485, 368, 370, 783, 398, 401, 405, 406, 496, - 497, 514, 542, 561, 562, 563, 395, 382, 534, 383, - 415, 384, 351, 387, 386, 388, 544, 389, 353, 515, - 566, 3108, 411, 530, 480, 354, 479, 516, 565, 564, - 369, 592, 599, 600, 692, 0, 605, 797, 798, 799, - 614, 0, 522, 365, 362, 0, 0, 0, 391, 517, - 378, 380, 381, 379, 511, 513, 619, 620, 621, 623, - 624, 625, 626, 0, 0, 0, 0, 627, 693, 711, - 677, 646, 607, 701, 643, 647, 648, 432, 433, 434, - 435, 714, 0, 0, 0, 598, 460, 461, 0, 403, - 402, 481, 355, 0, 0, 449, 431, 523, 361, 399, - 451, 437, 462, 463, 464, 465, 466, 0, 467, 468, - 409, 340, 346, 791, 392, 504, 716, 753, 754, 638, - 0, 702, 639, 649, 385, 674, 686, 685, 498, 597, - 0, 697, 700, 628, 790, 0, 694, 708, 795, 707, - 787, 510, 0, 541, 705, 652, 0, 698, 671, 672, - 0, 699, 667, 703, 0, 640, 0, 608, 611, 642, - 729, 730, 731, 352, 610, 733, 734, 735, 736, 737, - 738, 739, 732, 580, 675, 651, 678, 589, 654, 653, - 0, 0, 689, 606, 690, 691, 492, 493, 494, 495, - 413, 717, 376, 609, 525, 526, 0, 676, 0, 0, - 0, 0, 0, 0, 0, 0, 681, 682, 679, 800, - 0, 740, 741, 0, 0, 603, 604, 408, 0, 622, - 416, 375, 509, 410, 587, 440, 0, 615, 683, 616, - 528, 529, 744, 749, 745, 746, 748, 769, 499, 430, - 436, 545, 450, 472, 531, 586, 507, 536, 373, 576, - 547, 478, 668, 696, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 326, 327, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 725, 724, 723, 722, 721, 720, 719, 718, 0, - 0, 665, 390, 788, 782, 789, 770, 773, 772, 747, - 0, 347, 645, 470, 524, 407, 712, 713, 0, 768, - 285, 286, 287, 288, 289, 290, 291, 292, 333, 293, - 294, 295, 296, 297, 298, 299, 304, 305, 306, 307, - 308, 309, 310, 311, 715, 302, 303, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 0, 0, 0, 0, 334, 774, 775, 776, 777, - 778, 0, 0, 335, 336, 337, 0, 0, 300, 301, - 328, 555, 329, 330, 331, 332, 0, 0, 593, 594, - 595, 618, 0, 596, 578, 644, 417, 348, 559, 585, - 785, 786, 0, 0, 0, 0, 0, 0, 0, 695, - 706, 742, 743, 0, 756, 757, 759, 761, 760, 763, - 552, 553, 771, 0, 0, 441, 363, 364, 500, 501, - 538, 0, 442, 443, 444, 448, 445, 446, 447, 765, - 766, 767, 764, 474, 537, 560, 546, 784, 487, 0, - 792, 634, 635, 793, 752, 751, 349, 0, 338, 339, - 709, 710, 0, 0, 540, 486, 641, 341, 342, 343, - 344, 345, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 506, 0, 0, 650, 684, 673, 762, 637, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 400, 0, 0, 469, 688, 669, 680, 670, 512, 655, - 656, 657, 664, 412, 658, 794, 660, 629, 661, 630, - 662, 663, 0, 687, 636, 548, 488, 0, 704, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 269, 0, 0, 0, 0, 0, 0, 371, 270, 631, - 758, 633, 632, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 374, 0, 3103, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 549, 577, 0, 590, 0, 438, 439, - 0, 0, 0, 0, 0, 0, 0, 356, 556, 574, - 372, 543, 588, 377, 551, 567, 367, 505, 539, 0, - 0, 358, 572, 550, 483, 357, 0, 532, 397, 414, - 394, 503, 0, 0, 571, 601, 393, 591, 0, 582, - 360, 0, 581, 502, 475, 568, 573, 484, 477, 0, - 359, 570, 482, 476, 452, 404, 617, 453, 454, 455, - 456, 457, 458, 418, 518, 473, 519, 419, 490, 489, - 491, 420, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 0, 0, 0, 0, 612, 613, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 750, 0, 0, 755, 3102, 584, 0, - 0, 0, 3109, 3105, 3107, 554, 0, 3106, 459, 0, - 0, 0, 602, 0, 535, 508, 796, 0, 0, 533, - 471, 569, 520, 575, 557, 583, 527, 521, 350, 558, - 396, 485, 368, 370, 783, 398, 401, 405, 406, 496, - 497, 514, 542, 561, 562, 563, 395, 382, 534, 383, - 415, 384, 351, 387, 386, 388, 544, 389, 353, 515, - 566, 3108, 411, 530, 480, 354, 479, 516, 565, 564, - 369, 592, 599, 600, 692, 0, 605, 797, 798, 799, - 614, 0, 522, 365, 362, 0, 0, 0, 391, 517, - 378, 380, 381, 379, 511, 513, 619, 620, 621, 623, - 624, 625, 626, 0, 0, 0, 0, 627, 693, 711, - 677, 646, 607, 701, 643, 647, 648, 432, 433, 434, - 435, 714, 0, 0, 0, 598, 460, 461, 0, 403, - 402, 481, 355, 0, 0, 449, 431, 523, 361, 399, - 451, 437, 462, 463, 464, 465, 466, 0, 467, 468, - 409, 340, 346, 791, 392, 504, 716, 753, 754, 638, - 0, 702, 639, 649, 385, 674, 686, 685, 498, 597, - 0, 697, 700, 628, 790, 0, 694, 708, 795, 707, - 787, 510, 0, 541, 705, 652, 0, 698, 671, 672, - 0, 699, 667, 703, 0, 640, 0, 608, 611, 642, - 729, 730, 731, 352, 610, 733, 734, 735, 736, 737, - 738, 739, 732, 580, 675, 651, 678, 589, 654, 653, - 0, 0, 689, 606, 690, 691, 492, 493, 494, 495, - 413, 717, 376, 609, 525, 526, 0, 676, 0, 0, - 0, 0, 0, 0, 0, 0, 681, 682, 679, 800, - 0, 740, 741, 0, 0, 603, 604, 408, 0, 622, - 416, 375, 509, 410, 587, 440, 0, 615, 683, 616, - 528, 529, 744, 749, 745, 746, 748, 769, 499, 430, - 436, 545, 450, 472, 531, 586, 507, 536, 373, 576, - 547, 478, 668, 696, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 326, 327, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 725, 724, 723, 722, 721, 720, 719, 718, 0, - 0, 665, 390, 788, 782, 789, 770, 773, 772, 747, - 0, 347, 645, 470, 524, 407, 712, 713, 0, 768, - 285, 286, 287, 288, 289, 290, 291, 292, 333, 293, - 294, 295, 296, 297, 298, 299, 304, 305, 306, 307, - 308, 309, 310, 311, 715, 302, 303, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 0, 0, 0, 0, 334, 774, 775, 776, 777, - 778, 0, 0, 335, 336, 337, 0, 0, 300, 301, - 328, 555, 329, 330, 331, 332, 0, 0, 593, 594, - 595, 618, 0, 596, 578, 644, 417, 348, 559, 585, - 785, 786, 0, 0, 0, 0, 0, 0, 0, 695, - 706, 742, 743, 0, 756, 757, 759, 761, 760, 763, - 552, 553, 771, 0, 0, 441, 363, 364, 500, 501, - 538, 0, 442, 443, 444, 448, 445, 446, 447, 765, - 766, 767, 764, 474, 537, 560, 546, 784, 487, 0, - 792, 634, 635, 793, 752, 751, 349, 0, 338, 339, - 709, 710, 0, 0, 540, 486, 641, 341, 342, 343, - 344, 345, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 201, 246, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 506, 0, 0, 650, 684, 673, 762, 637, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 400, 0, 0, 469, 688, 669, 680, 670, 512, 655, - 656, 657, 664, 412, 658, 794, 660, 629, 661, 630, - 662, 663, 1275, 687, 636, 548, 488, 0, 704, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 239, 3264, 0, - 269, 0, 0, 0, 0, 0, 0, 371, 270, 631, - 758, 633, 632, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 374, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 549, 577, 0, 590, 0, 438, 439, - 0, 0, 0, 0, 0, 0, 0, 356, 556, 574, - 372, 543, 588, 377, 551, 567, 367, 505, 539, 0, - 0, 358, 572, 550, 483, 357, 0, 532, 397, 414, - 394, 503, 0, 0, 571, 601, 393, 591, 0, 582, - 360, 0, 581, 502, 475, 568, 573, 484, 477, 0, - 359, 570, 482, 476, 452, 404, 617, 453, 454, 455, - 456, 457, 458, 418, 518, 473, 519, 419, 490, 489, - 491, 420, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 0, 0, 0, 0, 612, 613, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 750, 0, 247, 755, 0, 584, 0, - 0, 0, 0, 0, 0, 554, 0, 0, 459, 0, - 0, 0, 602, 0, 535, 508, 796, 0, 0, 533, - 471, 569, 520, 575, 557, 583, 527, 521, 350, 558, - 396, 485, 368, 370, 783, 398, 401, 405, 406, 496, - 497, 514, 542, 561, 562, 563, 395, 382, 534, 383, - 415, 384, 351, 387, 386, 388, 544, 389, 353, 515, - 566, 0, 411, 530, 480, 354, 479, 516, 565, 564, - 369, 592, 599, 600, 692, 0, 605, 797, 798, 799, - 614, 0, 522, 365, 362, 0, 0, 0, 391, 517, - 378, 380, 381, 379, 511, 513, 619, 620, 621, 623, - 624, 625, 626, 0, 0, 0, 0, 627, 693, 711, - 677, 646, 607, 701, 643, 647, 648, 432, 433, 434, - 435, 714, 0, 0, 0, 598, 460, 461, 0, 403, - 402, 481, 355, 0, 0, 449, 431, 523, 361, 399, - 451, 437, 462, 463, 464, 465, 466, 0, 467, 468, - 409, 340, 346, 791, 392, 504, 716, 753, 754, 638, - 0, 702, 639, 649, 385, 674, 686, 685, 498, 597, - 0, 697, 700, 628, 790, 0, 694, 708, 795, 707, - 787, 510, 0, 541, 705, 652, 0, 698, 671, 672, - 0, 699, 667, 703, 0, 640, 0, 608, 611, 642, - 729, 730, 731, 352, 610, 733, 734, 735, 736, 737, - 738, 739, 732, 580, 675, 651, 678, 589, 654, 653, - 0, 0, 689, 606, 690, 691, 492, 493, 494, 495, - 413, 717, 376, 609, 525, 526, 0, 676, 0, 0, - 0, 0, 0, 0, 0, 0, 681, 682, 679, 800, - 0, 740, 741, 0, 0, 603, 604, 408, 0, 622, - 416, 375, 509, 410, 587, 440, 0, 615, 683, 616, - 528, 529, 744, 749, 745, 746, 748, 769, 499, 430, - 436, 545, 450, 472, 531, 586, 507, 536, 373, 576, - 547, 478, 668, 696, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 326, 327, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 725, 724, 723, 722, 721, 720, 719, 718, 0, - 0, 665, 390, 788, 782, 789, 770, 773, 772, 747, - 0, 347, 645, 470, 524, 407, 712, 713, 0, 768, - 285, 286, 287, 288, 289, 290, 291, 292, 333, 293, - 294, 295, 296, 297, 298, 299, 304, 305, 306, 307, - 308, 309, 310, 311, 715, 302, 303, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 0, 0, 0, 0, 334, 774, 775, 776, 777, - 778, 0, 0, 335, 336, 337, 0, 0, 300, 301, - 328, 555, 329, 330, 331, 332, 0, 0, 593, 594, - 595, 618, 0, 596, 578, 644, 417, 348, 559, 585, - 785, 786, 0, 0, 0, 0, 0, 0, 0, 695, - 706, 742, 743, 0, 756, 757, 759, 761, 760, 763, - 552, 553, 771, 0, 0, 441, 363, 364, 500, 501, - 538, 0, 442, 443, 444, 448, 445, 446, 447, 765, - 766, 767, 764, 474, 537, 560, 546, 784, 487, 0, - 792, 634, 635, 793, 752, 751, 349, 0, 338, 339, - 709, 710, 0, 0, 540, 486, 641, 341, 342, 343, - 344, 345, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 201, 246, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 506, 0, 0, 650, 684, 673, 762, 637, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 400, 0, 0, 469, 688, 669, 680, 670, 512, 655, - 656, 657, 664, 412, 658, 794, 660, 629, 661, 630, - 662, 663, 1275, 687, 636, 548, 488, 0, 704, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 239, 3003, 0, - 269, 0, 0, 0, 0, 0, 0, 371, 270, 631, - 758, 633, 632, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 374, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 549, 577, 0, 590, 0, 438, 439, - 0, 0, 0, 0, 0, 0, 0, 356, 556, 574, - 372, 543, 588, 377, 551, 567, 367, 505, 539, 0, - 0, 358, 572, 550, 483, 357, 0, 532, 397, 414, - 394, 503, 0, 0, 571, 601, 393, 591, 0, 582, - 360, 0, 581, 502, 475, 568, 573, 484, 477, 0, - 359, 570, 482, 476, 452, 404, 617, 453, 454, 455, - 456, 457, 458, 418, 518, 473, 519, 419, 490, 489, - 491, 420, 421, 422, 423, 424, 425, 426, 427, 428, - 429, 0, 0, 0, 0, 0, 612, 613, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 750, 0, 247, 755, 0, 584, 0, - 0, 0, 0, 0, 0, 554, 0, 0, 459, 0, - 0, 0, 602, 0, 535, 508, 796, 0, 0, 533, - 471, 569, 520, 575, 557, 583, 527, 521, 350, 558, - 396, 485, 368, 370, 783, 398, 401, 405, 406, 496, - 497, 514, 542, 561, 562, 563, 395, 382, 534, 383, - 415, 384, 351, 387, 386, 388, 544, 389, 353, 515, - 566, 0, 411, 530, 480, 354, 479, 516, 565, 564, - 369, 592, 599, 600, 692, 0, 605, 797, 798, 799, - 614, 0, 522, 365, 362, 0, 0, 0, 391, 517, - 378, 380, 381, 379, 511, 513, 619, 620, 621, 623, - 624, 625, 626, 0, 0, 0, 0, 627, 693, 711, - 677, 646, 607, 701, 643, 647, 648, 432, 433, 434, - 435, 714, 0, 0, 0, 598, 460, 461, 0, 403, - 402, 481, 355, 0, 0, 449, 431, 523, 361, 399, - 451, 437, 462, 463, 464, 465, 466, 0, 467, 468, - 409, 340, 346, 791, 392, 504, 716, 753, 754, 638, - 0, 702, 639, 649, 385, 674, 686, 685, 498, 597, - 0, 697, 700, 628, 790, 0, 694, 708, 795, 707, - 787, 510, 0, 541, 705, 652, 0, 698, 671, 672, - 0, 699, 667, 703, 0, 640, 0, 608, 611, 642, - 729, 730, 731, 352, 610, 733, 734, 735, 736, 737, - 738, 739, 732, 580, 675, 651, 678, 589, 654, 653, - 0, 0, 689, 606, 690, 691, 492, 493, 494, 495, - 413, 717, 376, 609, 525, 526, 0, 676, 0, 0, - 0, 0, 0, 0, 0, 0, 681, 682, 679, 800, - 0, 740, 741, 0, 0, 603, 604, 408, 0, 622, - 416, 375, 509, 410, 587, 440, 0, 615, 683, 616, - 528, 529, 744, 749, 745, 746, 748, 769, 499, 430, - 436, 545, 450, 472, 531, 586, 507, 536, 373, 576, - 547, 478, 668, 696, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 326, 327, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 725, 724, 723, 722, 721, 720, 719, 718, 0, - 0, 665, 390, 788, 782, 789, 770, 773, 772, 747, - 0, 347, 645, 470, 524, 407, 712, 713, 0, 768, - 285, 286, 287, 288, 289, 290, 291, 292, 333, 293, - 294, 295, 296, 297, 298, 299, 304, 305, 306, 307, - 308, 309, 310, 311, 715, 302, 303, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 0, 0, 0, 0, 334, 774, 775, 776, 777, - 778, 0, 0, 335, 336, 337, 0, 0, 300, 301, - 328, 555, 329, 330, 331, 332, 0, 0, 593, 594, - 595, 618, 0, 596, 578, 644, 417, 348, 559, 585, - 785, 786, 0, 0, 0, 0, 0, 0, 0, 695, - 706, 742, 743, 0, 756, 757, 759, 761, 760, 763, - 552, 553, 771, 0, 0, 441, 363, 364, 500, 501, - 538, 0, 442, 443, 444, 448, 445, 446, 447, 765, - 766, 767, 764, 474, 537, 560, 546, 784, 487, 0, - 792, 634, 635, 793, 752, 751, 349, 0, 338, 339, - 709, 710, 0, 0, 540, 486, 641, 1826, 341, 342, - 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 506, 0, 0, 650, 684, 673, 762, - 637, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 400, 0, 0, 469, 688, 669, 680, 670, 512, - 655, 656, 657, 664, 412, 658, 794, 660, 629, 661, - 630, 662, 663, 0, 687, 636, 548, 488, 0, 704, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1823, 0, - 0, 269, 0, 0, 0, 0, 0, 0, 371, 270, - 631, 758, 633, 632, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 374, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 549, 577, 0, 590, 0, 438, - 439, 0, 0, 0, 0, 0, 0, 0, 356, 556, - 574, 372, 543, 588, 377, 551, 567, 367, 505, 539, - 0, 0, 358, 572, 550, 483, 357, 0, 532, 397, - 414, 394, 503, 0, 0, 571, 601, 393, 591, 0, - 582, 360, 0, 581, 502, 475, 568, 573, 484, 477, - 0, 359, 570, 482, 476, 452, 404, 617, 453, 454, - 455, 456, 457, 458, 418, 518, 473, 519, 419, 490, - 489, 491, 420, 421, 422, 423, 424, 425, 426, 427, - 428, 429, 0, 0, 0, 0, 0, 612, 613, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 750, 0, 0, 755, 0, 584, - 0, 0, 0, 0, 0, 0, 554, 0, 0, 459, - 0, 0, 0, 602, 0, 535, 508, 796, 0, 0, - 533, 471, 569, 520, 575, 557, 583, 527, 521, 350, - 558, 396, 485, 368, 370, 783, 398, 401, 405, 406, - 496, 497, 514, 542, 561, 562, 563, 395, 382, 534, - 383, 415, 384, 351, 387, 386, 388, 544, 389, 353, - 515, 566, 0, 411, 530, 480, 354, 479, 516, 565, - 564, 369, 592, 599, 600, 692, 0, 605, 797, 798, - 799, 614, 0, 522, 365, 362, 0, 0, 0, 391, - 517, 378, 380, 381, 379, 511, 513, 619, 620, 621, - 623, 624, 625, 626, 0, 0, 0, 0, 627, 693, - 711, 677, 646, 607, 701, 643, 647, 648, 432, 433, - 434, 435, 714, 0, 0, 0, 598, 460, 461, 0, - 403, 402, 481, 355, 0, 0, 449, 431, 523, 361, - 399, 451, 437, 462, 463, 464, 465, 466, 0, 467, - 468, 409, 340, 346, 791, 392, 504, 716, 753, 754, - 638, 0, 702, 639, 649, 385, 674, 686, 685, 498, - 597, 0, 697, 700, 628, 790, 0, 694, 708, 795, - 707, 787, 510, 0, 541, 705, 652, 0, 698, 671, - 672, 0, 699, 667, 703, 0, 640, 0, 608, 611, - 642, 729, 730, 731, 352, 610, 733, 734, 735, 736, - 737, 738, 739, 732, 580, 675, 651, 678, 589, 654, - 653, 0, 0, 689, 606, 690, 691, 492, 493, 494, - 495, 413, 717, 376, 609, 525, 526, 0, 676, 0, - 0, 0, 0, 0, 0, 0, 0, 681, 682, 679, - 800, 0, 740, 741, 0, 0, 603, 604, 408, 0, - 622, 416, 375, 509, 410, 587, 440, 0, 615, 683, - 616, 528, 529, 744, 749, 745, 746, 748, 769, 499, - 430, 436, 545, 450, 472, 531, 586, 507, 536, 373, - 576, 547, 478, 668, 696, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 725, 724, 723, 722, 721, 720, 719, 718, - 0, 0, 665, 390, 788, 782, 789, 770, 773, 772, - 747, 0, 347, 645, 470, 524, 407, 712, 713, 0, - 768, 285, 286, 287, 288, 289, 290, 291, 292, 333, - 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, - 307, 308, 309, 310, 311, 715, 302, 303, 312, 313, - 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, - 324, 325, 0, 0, 0, 0, 334, 774, 775, 776, - 777, 778, 0, 0, 335, 336, 337, 0, 0, 300, - 301, 328, 555, 329, 330, 331, 332, 0, 0, 593, - 594, 595, 618, 0, 596, 578, 644, 417, 348, 559, - 585, 785, 786, 0, 0, 0, 0, 0, 0, 0, - 695, 706, 742, 743, 0, 756, 757, 759, 761, 760, - 763, 552, 553, 771, 0, 0, 441, 363, 364, 500, - 501, 538, 0, 442, 443, 444, 448, 445, 446, 447, - 765, 766, 767, 764, 474, 537, 560, 546, 784, 487, - 0, 792, 634, 635, 793, 752, 751, 349, 0, 338, - 339, 709, 710, 0, 0, 540, 486, 641, 0, 2476, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 1248, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 1255, 1256, 0, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1259, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 1242, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 904, 582, 360, 903, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 1246, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 1247, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 1250, 690, 691, 492, - 493, 494, 495, 413, 717, 1245, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 1257, 1243, 1253, 1244, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 1254, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 1241, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 1255, 1256, 0, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1259, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 904, 582, 360, 903, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 1257, 2590, 1253, 2591, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 1254, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 3818, 0, 0, 0, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 3821, 0, 0, 0, 0, 3820, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 2650, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 2651, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 1576, 0, - 1577, 1575, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 0, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 1885, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 1883, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 1881, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 1879, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 1883, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 1881, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 1844, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1845, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 1843, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 1209, 0, 0, 0, 0, - 0, 0, 1214, 400, 0, 0, 469, 688, 1210, 680, - 670, 1212, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 1213, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 5335, 0, 269, 1076, 0, 0, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 1883, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 1881, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 1883, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 2205, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 4718, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4719, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 2650, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 2651, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 4299, 4300, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 269, 0, 0, 4057, 4059, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 3678, 0, 0, 269, 0, 0, 3682, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 506, 0, 0, 650, 684, - 673, 762, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 400, 0, 0, 469, 688, 669, 680, - 670, 512, 655, 656, 657, 664, 412, 658, 794, 660, - 629, 661, 630, 662, 663, 0, 687, 636, 548, 488, - 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 3672, 0, 0, 269, 0, 0, 3676, 0, 0, 0, - 371, 270, 631, 758, 633, 632, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 549, 577, 0, 590, - 0, 438, 439, 0, 0, 0, 0, 0, 0, 0, - 356, 556, 574, 372, 543, 588, 377, 551, 567, 367, - 505, 539, 0, 0, 358, 572, 550, 483, 357, 0, - 532, 397, 414, 394, 503, 0, 0, 571, 601, 393, - 591, 0, 582, 360, 0, 581, 502, 475, 568, 573, - 484, 477, 0, 359, 570, 482, 476, 452, 404, 617, - 453, 454, 455, 456, 457, 458, 418, 518, 473, 519, - 419, 490, 489, 491, 420, 421, 422, 423, 424, 425, - 426, 427, 428, 429, 0, 0, 0, 0, 0, 612, - 613, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 750, 0, 0, 755, - 0, 584, 0, 0, 0, 0, 0, 0, 554, 0, - 0, 459, 0, 0, 0, 602, 0, 535, 508, 796, - 0, 0, 533, 471, 569, 520, 575, 557, 583, 527, - 521, 350, 558, 396, 485, 368, 370, 783, 398, 401, - 405, 406, 496, 497, 514, 542, 561, 562, 563, 395, - 382, 534, 383, 415, 384, 351, 387, 386, 388, 544, - 389, 353, 515, 566, 0, 411, 530, 480, 354, 479, - 516, 565, 564, 369, 592, 599, 600, 692, 0, 605, - 797, 798, 799, 614, 0, 522, 365, 362, 0, 0, - 0, 391, 517, 378, 380, 381, 379, 511, 513, 619, - 620, 621, 623, 624, 625, 626, 0, 0, 0, 0, - 627, 693, 711, 677, 646, 607, 701, 643, 647, 648, - 432, 433, 434, 435, 714, 0, 0, 0, 598, 460, - 461, 0, 403, 402, 481, 355, 0, 0, 449, 431, - 523, 361, 399, 451, 437, 462, 463, 464, 465, 466, - 0, 467, 468, 409, 340, 346, 791, 392, 504, 716, - 753, 754, 638, 0, 702, 639, 649, 385, 674, 686, - 685, 498, 597, 0, 697, 700, 628, 790, 0, 694, - 708, 795, 707, 787, 510, 0, 541, 705, 652, 0, - 698, 671, 672, 0, 699, 667, 703, 0, 640, 0, - 608, 611, 642, 729, 730, 731, 352, 610, 733, 734, - 735, 736, 737, 738, 739, 732, 580, 675, 651, 678, - 589, 654, 653, 0, 0, 689, 606, 690, 691, 492, - 493, 494, 495, 413, 717, 376, 609, 525, 526, 0, - 676, 0, 0, 0, 0, 0, 0, 0, 0, 681, - 682, 679, 800, 0, 740, 741, 0, 0, 603, 604, - 408, 0, 622, 416, 375, 509, 410, 587, 440, 0, - 615, 683, 616, 528, 529, 744, 749, 745, 746, 748, - 769, 499, 430, 436, 545, 450, 472, 531, 586, 507, - 536, 373, 576, 547, 478, 668, 696, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 725, 724, 723, 722, 721, 720, - 719, 718, 0, 0, 665, 390, 788, 782, 789, 770, - 773, 772, 747, 0, 347, 645, 470, 524, 407, 712, - 713, 0, 768, 285, 286, 287, 288, 289, 290, 291, - 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, - 305, 306, 307, 308, 309, 310, 311, 715, 302, 303, - 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 0, 0, 0, 0, 334, 774, - 775, 776, 777, 778, 0, 0, 335, 336, 337, 0, - 0, 300, 301, 328, 555, 329, 330, 331, 332, 0, - 0, 593, 594, 595, 618, 0, 596, 578, 644, 417, - 348, 559, 585, 785, 786, 0, 0, 0, 0, 0, - 0, 0, 695, 706, 742, 743, 0, 756, 757, 759, - 761, 760, 763, 552, 553, 771, 0, 0, 441, 363, - 364, 500, 501, 538, 0, 442, 443, 444, 448, 445, - 446, 447, 765, 766, 767, 764, 474, 537, 560, 546, - 784, 487, 0, 792, 634, 635, 793, 752, 751, 349, - 0, 338, 339, 709, 710, 0, 0, 540, 486, 641, - 1826, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1823, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 3194, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 1883, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 1883, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 2088, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 2087, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 5424, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 5356, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 1076, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 5300, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2219, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 4980, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 4945, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 4633, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4465, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 4463, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 3682, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 3301, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 3676, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 4452, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4134, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 2468, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 2470, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 0, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 4399, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 3445, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 4258, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 4100, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 4029, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3897, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 1883, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 2470, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 3724, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 3693, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 3593, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3574, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 3452, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 3414, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2768, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 3279, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3227, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 3225, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 3017, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 2403, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 1455, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 2626, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 2555, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 1926, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1214, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 819, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 1217, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 955, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 954, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 4949, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 4032, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 2468, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 2470, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 0, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 2385, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 1862, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 1860, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 1765, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 906, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 907, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 843, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 0, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 751, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 341, 342, 343, 344, 345, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 506, 0, 0, 650, - 684, 673, 762, 637, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 400, 0, 0, 469, 688, 669, - 680, 670, 512, 655, 656, 657, 664, 412, 658, 794, - 660, 629, 661, 630, 662, 663, 0, 687, 636, 548, - 488, 0, 704, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, - 0, 371, 270, 631, 758, 633, 632, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 549, 577, 0, - 590, 0, 438, 439, 0, 0, 0, 0, 0, 0, - 0, 356, 556, 574, 372, 543, 588, 377, 551, 567, - 367, 505, 539, 0, 0, 358, 572, 550, 483, 357, - 0, 532, 397, 414, 394, 503, 0, 0, 571, 601, - 393, 591, 0, 582, 360, 0, 581, 502, 475, 568, - 573, 484, 477, 0, 359, 570, 482, 476, 452, 404, - 617, 453, 454, 455, 456, 457, 458, 418, 518, 473, - 519, 419, 490, 489, 491, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 0, 0, 0, 0, 0, - 612, 613, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 750, 0, 0, - 755, 0, 584, 0, 0, 0, 0, 0, 0, 554, - 0, 0, 459, 0, 0, 0, 602, 0, 535, 508, - 796, 0, 0, 533, 471, 569, 520, 575, 557, 583, - 527, 521, 350, 558, 396, 485, 368, 370, 783, 398, - 401, 405, 406, 496, 497, 514, 542, 561, 562, 563, - 395, 382, 534, 383, 415, 384, 351, 387, 386, 388, - 544, 389, 353, 515, 566, 0, 411, 530, 480, 354, - 479, 516, 565, 564, 369, 592, 599, 600, 692, 0, - 605, 797, 798, 799, 614, 0, 522, 365, 362, 0, - 0, 0, 391, 517, 378, 380, 381, 379, 511, 513, - 619, 620, 621, 623, 624, 625, 626, 0, 0, 0, - 0, 627, 693, 711, 677, 646, 607, 701, 643, 647, - 648, 432, 433, 434, 435, 714, 0, 0, 0, 598, - 460, 461, 0, 403, 402, 481, 355, 0, 0, 449, - 431, 523, 361, 399, 451, 437, 462, 463, 464, 465, - 466, 0, 467, 468, 409, 340, 346, 791, 392, 504, - 716, 753, 754, 638, 0, 702, 639, 649, 385, 674, - 686, 685, 498, 597, 0, 697, 700, 628, 790, 0, - 694, 708, 795, 707, 787, 510, 0, 541, 705, 652, - 0, 698, 671, 672, 0, 699, 667, 703, 0, 640, - 0, 608, 611, 642, 729, 730, 731, 352, 610, 733, - 734, 735, 736, 737, 738, 739, 732, 580, 675, 651, - 678, 589, 654, 653, 0, 0, 689, 606, 690, 691, - 492, 493, 494, 495, 413, 717, 376, 609, 525, 526, - 0, 676, 0, 0, 0, 0, 0, 0, 0, 0, - 681, 682, 679, 800, 0, 740, 741, 0, 0, 603, - 604, 408, 0, 622, 416, 375, 509, 410, 587, 440, - 0, 615, 683, 616, 528, 529, 744, 749, 745, 746, - 748, 769, 499, 430, 436, 545, 450, 472, 531, 586, - 507, 536, 373, 576, 547, 478, 668, 696, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, - 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 725, 724, 723, 722, 721, - 720, 719, 718, 0, 0, 665, 390, 788, 782, 789, - 770, 773, 772, 747, 0, 347, 645, 470, 524, 407, - 712, 713, 0, 768, 285, 286, 287, 288, 289, 290, - 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, - 304, 305, 306, 307, 308, 309, 310, 311, 715, 302, - 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, - 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, - 774, 775, 776, 777, 778, 0, 0, 335, 336, 337, - 0, 0, 300, 301, 328, 555, 329, 330, 331, 332, - 0, 0, 593, 594, 595, 618, 0, 596, 578, 644, - 417, 348, 559, 585, 785, 786, 0, 0, 0, 0, - 0, 0, 0, 695, 706, 742, 743, 0, 756, 757, - 759, 761, 760, 763, 552, 553, 771, 0, 0, 441, - 363, 364, 500, 501, 538, 0, 442, 443, 444, 448, - 445, 446, 447, 765, 766, 767, 764, 474, 537, 560, - 546, 784, 487, 0, 792, 634, 635, 793, 752, 0, - 349, 0, 338, 339, 709, 710, 0, 0, 540, 486, - 641, 928, 927, 934, 924, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 931, 932, 0, 933, 937, 0, - 0, 918, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 942, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 946, - 0, 0, 948, 0, 0, 0, 0, 947, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 919, 921, 920, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 926, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 930, 0, - 0, 0, 0, 0, 0, 945, 0, 0, 0, 0, - 0, 0, 923, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 925, 929, 935, - 0, 936, 938, 0, 0, 939, 940, 941, 0, 0, - 0, 943, 944, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 922, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 949, 950, 951, 952, 953, -} - -var yyPact = [...]int{ - 6984, -1000, -1000, -356, -1000, -1000, -1000, -1000, -1000, 21448, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 79955, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 736, 79955, 1378, -329, -1000, 4196, -1000, 1439, - -1000, -1000, -1000, -1000, 592, 77615, 23008, -1000, 79955, 934, - 929, 86975, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 1386, 1383, 7545, -1000, 86195, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 1230, 6107, 79175, 16756, 4040, - -93, -1000, -1000, 2340, 123, 3905, 743, 172, 170, 916, - 1719, 1726, 2039, 1558, 79955, 1672, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 8008, - 36274, 78395, 1608, 4626, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 820, 1381, 1608, 30814, 382, 379, 2683, 4857, 2142, - -1000, -1000, 53, 7950, -1000, -1000, 2281, 79955, 6984, 294, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 16756, 16756, 21448, -419, 21448, 16756, 79955, 79955, -1000, - -1000, -1000, -1000, 1378, -329, 77615, 1230, 6107, 16756, 4040, - 3905, 743, 172, 170, 916, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 53, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 379, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 4626, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 6478, - -1000, 2530, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 3560, 4386, 2528, 79955, 3903, -1000, -1000, -1000, -1000, - -1000, -1000, 2683, 4749, 76835, -1000, -1000, 4836, -1000, 79955, - 225, 79955, 494, 2943, 2523, 763, -1000, 1404, 2604, 634, - 2527, -1000, -1000, -1000, -1000, -1000, -1000, 4024, 1090, 4835, - -1000, 79955, 79955, 79955, 4402, 79955, 79955, 613, 4744, -1000, - 209, -73, -297, -314, 4425, 2781, 2781, 4791, 4791, 4742, - 4741, 1165, 1156, 1101, 2781, 994, -1000, 2748, 2748, 2748, - 2748, 2781, 738, 1160, 4751, 4385, 4751, 287, 2748, 277, - 2781, 2781, 277, 2781, 2781, 809, -1000, 2824, 817, 526, - -208, -1000, -1000, -1000, 2748, 2748, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 4712, 4711, -1000, 582, 1149, -1000, 89300, - 4645, 2275, 1366, 4424, -1000, -1000, 4384, -1000, 647, 824, - 514, 1045, 734, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 553, -1000, 4719, -1000, -1000, 629, -1000, -1000, 602, -1000, - -1000, -1000, 316, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 107, 79955, -1000, -1000, 1815, 3035, - 16756, 3289, -1000, 428, 2753, -1000, -1000, -1000, 8936, 20666, - 20666, 20666, 20666, 20666, 79955, -1000, -1000, 4240, 16756, 4383, - 4379, 4378, 4377, -1000, -1000, -1000, -1000, -1000, -1000, 4374, - 2526, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 3110, -1000, -1000, -1000, 19884, -1000, 4373, 4372, 4371, 4369, - 4366, 4365, 4364, 4363, 4362, 4361, 4360, 4358, 4354, 4242, - 4349, 4153, 23788, 4348, 3900, 3899, 4347, 4346, 4345, 3898, - 4343, 4342, 4340, 4153, 4153, 4339, 4338, 4336, 4334, 4333, - 4332, 4330, 4329, 4328, 4326, 4325, 4324, 4321, 4318, 4310, - 4309, 4308, 4306, 4305, 4304, 4303, 4302, 4300, 4297, 4296, - 4294, 4293, 4292, 4291, 4290, 4289, 4288, 4287, 4286, 4285, - 4284, 4276, 4275, 4266, 4263, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 2683, 4205, 4881, 2048, -1000, 4257, 4872, 4778, - 4747, 1849, 16756, -197, 4699, 4696, 4690, 4688, 4251, 3485, - -1000, -1000, 182, 79955, 79955, 381, 79955, -238, 613, 828, - 31, 30, 827, 29, 1514, -1000, 747, -1000, -1000, 1699, - -1000, 1605, 85415, 1331, -1000, -1000, 79955, 1228, 1228, 1228, - -260, 492, 1228, 79955, 830, 1349, 1538, 1228, 1228, 1228, - 1228, 1337, 1228, 1376, 1374, 1367, 1228, 88, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 2940, 2939, 4531, 3064, - 2989, 1201, 76835, 76835, 79955, -1000, 2358, 79955, -1000, 4227, - 1569, -1000, -1000, -1000, -1000, 44075, -262, 488, 1230, 1230, - 79955, 1230, 79955, 663, 387, 35494, 1230, 1230, 1230, 79955, - 1242, -312, 248, 84635, 83855, 3612, 582, 1143, 1139, 2206, - 2843, -1000, 2711, 79955, 79955, 2711, 2711, 34714, 33934, -1000, - 79955, -1000, 4872, 1849, -1000, 4737, 2004, -1000, 4782, 4130, - 2306, 4857, 4857, 4205, -1000, -93, 28, 1230, 1230, -267, - 481, 1230, 1230, 1230, 1230, 1230, 1365, 1230, 1230, 1230, - 79955, 1230, 76055, 1230, 822, 1230, 1230, 1230, 13628, 2281, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 21448, 3061, 3102, 292, 74, -302, - 508, -1000, -1000, 79955, 4608, 2597, -1000, -1000, -1000, 4212, - 4208, -1000, 4211, 4211, 4211, 4211, 1667, -1000, 4208, -1000, - -1000, -1000, 4208, -1000, -1000, -1000, -1000, 4211, 4211, 4211, - 4211, 4211, 4211, 4210, 4250, -1000, -1000, 4209, 4209, 4209, - 4208, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 1649, 4206, 4207, 4207, - 4206, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 79955, - 4868, -1000, -1000, 16756, 79955, 1322, 4625, 4872, 4629, 4751, - 4778, 1190, 3211, -1000, -281, 79955, 452, -1000, 2522, 3483, - 1799, 2935, -1000, 1854, 634, 2928, -1000, 896, 896, -1000, - 634, 2737, -1000, 2057, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 79955, 107, 5514, -1000, -1000, -1000, 3845, 995, -1000, - 4249, 905, -1000, -1000, -1000, -1000, 79955, 4751, 8, 4739, - 2781, 2972, 2924, 2781, -1000, -1000, -1000, 1117, 4791, 20666, - 20666, -1000, -1000, 16756, -1000, 482, 45635, 2748, 2781, 2781, - -1000, -1000, 79955, -1000, -1000, -1000, 2748, 79955, 2748, 2748, - 4791, 2748, -1000, -1000, -1000, 2781, 2781, -1000, -1000, 16756, - 2668, -1000, -1000, 2748, 2748, -1000, -1000, 4791, 79955, 290, - 4791, 4791, 262, -1000, -1000, 79955, -1000, 2781, 3886, -1000, - 79955, 79955, 1228, 79955, -1000, 79955, 79955, -1000, -1000, -1000, - 987, 2195, 2115, -1000, 530, 7101, 63575, 582, 63575, 79955, - -1000, -1000, -1000, -1000, -1000, -1000, 284, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 624, -1000, 4834, 16756, 16756, 16756, 16756, -1000, 1245, - 19102, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 20666, 20666, - 20666, 20666, 20666, 20666, 20666, 20666, 20666, 20666, 20666, 20666, - 20666, 20666, 4239, 2980, 2883, 4725, 20666, 20666, 20666, 20666, - 20666, 491, 38614, 2306, 4061, 2376, 527, 2662, 2662, 2662, - 2662, 2662, 16756, -1000, 2985, 3035, 16756, 16756, 16756, 16756, - 49535, 79955, -1000, -1000, 8936, 7074, 16756, 16756, 4900, 20666, - 16756, 4676, 16756, 16756, 16756, 4127, 9718, 79955, 16756, -1000, - 4126, 4125, -1000, -1000, 3189, 16756, -1000, -1000, 16756, -1000, - -1000, 16756, 20666, 16756, -1000, 16756, 16756, 16756, -1000, -1000, - 2073, 2073, 1520, 4676, 16756, 16756, 4676, 4676, 2901, 16756, - 16756, 4676, 4676, 4676, 2895, 4676, 4676, 4676, 4676, 4676, - 4676, 4676, 4015, 4676, 4676, 4676, 4676, 4676, 4119, 4117, - 4116, 4115, 16756, 4114, 16756, 16756, 16756, 16756, 16756, 15974, - 4872, 2683, 4737, -93, 14410, 4629, 4751, 4611, -67, 4778, - -1000, -1000, -1000, -1000, 3035, -202, 4248, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 79955, 3885, 3883, -364, -365, - 1680, -365, 2479, -1000, -239, 1707, 378, 79955, -1000, 3882, - 3481, 79955, 3879, 3480, 412, 406, 79955, 79955, 79955, 206, - 1717, 1611, 1664, -1000, -1000, 79955, 83075, -1000, 79955, 2707, - 79955, 79955, 1228, 1228, 79955, 4670, -1000, 79955, 79955, 1228, - 1228, -1000, 73715, 3878, 63575, 79955, 79955, 582, 79955, 79955, - 1228, 1228, 1228, 79955, -1000, 4563, 63575, 4536, 2184, 3023, - -1000, -1000, 79955, 16756, 3023, 1918, 4247, 1201, 1201, -1000, - 79955, 2358, 4669, 79955, 1242, -1000, 518, -1000, -1000, -1000, - -1000, 82295, 82295, 26129, 82295, -1000, 4246, 264, 79955, 79955, - 79955, 79955, 6002, 79955, 638, 4644, 1462, 73715, 75275, 2024, - 1787, -1000, -1000, 4710, 1531, 2761, 63575, 79955, 79955, 2350, - -1000, 1319, 30032, -1000, 79955, 2226, -1000, 202, -1000, 185, - 248, 2711, 248, 2711, 1317, -1000, 984, 670, 31594, 917, - 63575, 11282, -1000, -1000, 2711, 2711, 11282, 11282, 2607, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 2343, -1000, 487, 4737, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -93, 16756, -1000, -1000, 4737, 4737, 1849, 2225, 3479, - 74495, 79955, 1230, 1230, 79955, 73715, 63575, 582, 79955, 1230, - 79955, 79955, 79955, -1000, 79955, -1000, 4643, 79955, 1230, 79955, - 79955, 79955, 2202, -1000, -1000, 33154, 2477, -1000, -1000, 3011, - -1000, 16756, 21448, -171, 16756, 21448, 21448, 16756, 21448, -1000, - 16756, 2487, -1000, -1000, 6620, -1000, -1000, 3477, -1000, 3476, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 3875, 3875, -1000, 3475, -1000, -1000, -1000, - -1000, 4206, 3465, -1000, -1000, 3463, -1000, -1000, -1000, -1000, - -9, 4111, 1815, -1000, 3862, 3860, 4737, -1000, 4778, 504, - 4778, 4611, 1970, 4245, 1230, -1000, 273, -377, 2918, 2915, - 2914, 4724, 79955, -1000, 1035, 896, -1000, -1000, 1797, -1000, - 634, -1000, 1796, -1000, -1000, -1000, 896, 765, -1000, -1000, - -1000, -1000, -1000, 2470, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 31594, -1000, -1000, -1000, - -1000, 1415, 7860, 51, 50, 2282, -1000, -1000, 79955, -1000, - 79955, -1000, 79955, -1000, -7, -1000, -1000, 3458, 4753, 79955, - 4791, 79955, -270, 4791, 4791, 79955, -266, 4791, 582, -1000, - 2753, 2753, 3035, 79955, 79955, 79955, 4400, 4242, 79955, 246, - 79955, 4791, 4791, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 2748, 4791, 4791, 2129, 4110, 2781, 2748, -1000, -1000, 2748, - -377, -1000, 2748, -1000, -1000, -1000, -377, 2468, -377, 79955, - -1000, -1000, -1000, -1000, -1000, 530, 63575, 69815, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 2336, -1000, -1000, -1000, 1316, - 538, 2729, -1000, -1000, 396, 303, 498, 1410, 3859, 3035, - -1000, 3047, 3037, -1000, 1250, 1219, -1000, -1000, -1000, -1000, - 4240, -1000, -1000, -1000, 3615, 4685, -1000, 2847, 2847, 2614, - 2614, 2614, 2614, 2614, 2798, 2798, 2753, 2753, -1000, -1000, - -1000, 8936, 4239, 20666, 20666, 20666, 20666, 4239, 20666, 20666, - 20666, 20666, 4238, -1000, 1421, 1421, 5605, 6039, 2662, -1000, - -1000, 2543, 2543, -1000, -1000, -1000, -1000, 16756, 247, 2973, - -1000, 16756, 3284, 2463, 3272, 2391, 2727, -1000, 4208, 16756, - 2467, 361, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 4108, 4105, 3412, 4833, 5068, 4101, 16756, -1000, - -1000, 2726, 2725, 2723, -1000, 3207, 15192, -1000, -1000, -1000, - 4100, 2465, 4096, -1000, -1000, -1000, 4095, 2722, 1870, 4092, - 3726, 4087, 4084, 4082, 4081, 2277, 2274, 2248, -1000, -1000, - -1000, -1000, 16756, 4056, 4021, 16756, 16756, 16756, 4077, 2719, - 2717, 16756, 16756, 16756, 16756, 4073, 16756, 16756, 16756, 16756, - 16756, 16756, 16756, 16756, -340, 16756, 16756, 16756, 16756, 16756, - 397, 397, 397, 397, 4016, 397, 2219, 2214, 4008, 4001, - 2452, 2245, 2244, 4737, 4872, -1000, -1000, 2714, -1000, 3035, - -1000, -1000, 4778, 4778, -1000, 4867, 4611, -200, 4237, 3452, - 2239, -1000, -1000, -326, 3789, 1313, 301, 79955, 79955, 1313, - 79955, 79955, 2912, 1313, 79955, -240, 3854, -1000, -1000, 3853, - -1000, -1000, 79955, 79955, 79955, 79955, 22, 4624, 4623, -1000, - -1000, 1693, 1577, 1676, -1000, 79955, -1000, 3852, 4637, 4630, - 4738, 1293, 79955, 79955, 37, 79955, 4236, 4235, 2450, 79955, - 79955, 563, -1000, -1000, 79955, 1953, -1000, 538, 99, 943, - 1851, 4401, 1256, 79955, 79955, 79955, 4668, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1721, -1000, 4616, - 4094, 3080, 1721, 4422, -100, -1000, 29251, 88535, 79955, 1918, - 1918, -1000, 4233, 2703, -1000, 72935, 44075, 44075, 44075, 44075, - 44075, 44075, 44075, 44075, -1000, 4484, 4444, 4232, -1000, 4500, - 4492, 4469, 852, 4483, 4457, 4429, 4227, -1000, 64355, -1000, - -1000, -1000, 2306, 2702, -1000, 537, 3546, 1448, 16756, 16756, - 4706, 4569, 4667, 4227, 2234, -1000, -1000, -1000, 2289, -1000, - 4781, 1303, 1222, 1222, 1485, 4779, 26911, -1000, 2761, 2009, - 1312, 4568, 643, -1000, 2761, -3, 1200, 2761, 2761, 2761, - 2761, 2761, 2761, 2761, 2761, 1082, 1073, 2761, 2761, 2761, - 2761, 2761, 2761, 2761, 2761, 2761, 2761, 2761, 1725, 2761, - 2761, 2761, 2761, 2761, -1000, 2761, 4231, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 1099, 1020, -1000, -1000, 496, 582, - 1305, 223, 219, 559, 4705, 680, -1000, 1787, 706, -1000, - 2761, 4703, 2761, 38614, -1000, 1953, 969, 4702, 727, 79955, - 79955, 458, 2066, 2711, 248, 200, -1000, -1000, 2226, 11282, - 2226, 11282, 3445, -1000, -1000, 1298, -1000, -1000, 1851, -1000, - 79955, 79955, -1000, -1000, 4230, 2909, -1000, -1000, 23788, -1000, - 11282, 11282, -1000, -1000, 44855, 79955, -1000, 106, -1000, 183, - 4778, 2225, 2221, -1000, 3191, 4065, 4062, -1000, -1000, -1000, - -1000, -1000, -1000, -251, -1000, -1000, 79955, -1000, 79955, 79955, - 1832, -1000, 2215, 1851, 4418, 79955, 1276, -1000, -1000, 4229, - 79955, -1000, 3849, -1000, 4832, -251, 4829, 13628, -1000, -1000, - 72155, -1000, 71375, 2952, -1000, 21448, 3065, 285, -1000, 483, - -306, 283, 3013, 282, 3035, -1000, -1000, 4058, 4053, 4049, - 2689, -1000, 2687, 4036, -1000, 2685, 2684, 3444, -1000, -319, - 274, 4778, 4611, 3846, 2208, -1000, 4611, -1000, -331, -100, - -1000, 28471, 88535, 79955, 3839, 3173, 4663, 3602, -281, 16756, - 70595, 16756, 1532, 2449, 476, -1000, -1000, 896, 896, -1000, - 896, 896, -1000, -1000, 79955, 2206, 2908, 1404, 3845, -1000, - 2674, -1000, -1000, -1000, -1000, 3443, -1000, -1000, 2781, 79955, - -1000, -1000, 2342, 79955, 54995, -1000, -1000, -1000, -1000, 79955, - -1000, 582, 4400, -1000, 63575, -1000, 2781, -1000, -1000, 4791, - -1000, -1000, 16756, 16756, 236, 4791, 2781, 2781, -1000, 2748, - -1000, 79955, -1000, -377, 69815, 2044, -1000, 1297, 2438, 2433, - -1000, 63575, 614, 63575, -1000, -1000, 4765, -1000, 79955, 4618, - -1000, -1000, -1000, 3789, 2907, -372, 79955, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 2671, -1000, 1421, - 1421, 5605, 4998, -1000, 1421, 1421, 5605, 4804, 20666, -1000, - 20666, -1000, 20666, -1000, -1000, -1000, -1000, 3962, -1000, 2951, - -1000, 16756, 3045, 5730, 16756, 491, 2588, 37834, 49535, 21, - 4622, 3957, 79955, 16756, -1000, -1000, 16756, 16756, 20666, -1000, - 3917, -1000, -1000, -1000, -1000, 16756, 16756, 3183, -1000, 79955, - -1000, -1000, -1000, -1000, 37834, -1000, 20666, -1000, -1000, -1000, - -1000, 16756, 16756, 16756, 2054, -341, -341, 2054, 3909, 2642, - 397, 397, -341, 3901, 3897, 3893, 2634, 397, 3847, 3843, - 3826, 3805, 3795, 3747, 3743, 3734, 4789, 3723, 3665, 2630, - 3637, 2439, -1000, 69035, -1000, -1000, -1000, 397, -1000, -351, - 16756, -351, 16756, -351, -351, 16756, 3159, 18320, 4778, 4737, - 14410, -1000, 4611, 4611, 622, -1000, -1000, 4228, 1199, 2181, - 3430, 3836, 197, -1000, 2906, -1000, 726, 59675, 79955, 4828, - 4826, -1000, 2426, 3834, 68255, -1000, 1599, 79955, -1000, -1000, - 4810, 4808, -1000, -1000, 79955, 79955, 79955, -1000, -1000, -1000, - 1573, -1000, 3833, -1000, -1000, 655, 651, 3276, 4862, 4860, - 2984, 3832, 597, 1925, 25348, 79955, 4227, 4227, 317, 2761, - 863, 992, 63575, 1107, -1000, 67475, 3105, 2902, 4417, -1000, - 1869, 4599, 79955, 66695, 1029, 1302, 4226, 890, 6620, -1000, - 4616, 4225, 79955, 4616, -1000, -331, -1000, 4606, 1817, -1000, - 4224, -1000, 2629, 4528, -1000, 2422, 2180, -1000, 2898, 2626, - 2625, 2897, -331, 346, 6984, -1000, 79955, 79955, 1929, -1000, - 2421, 380, 4399, 4399, 4399, -1000, 4399, 4399, -1000, -1000, - -1000, -1000, 4480, 3823, -1000, 4472, -1000, 4463, -1000, 4445, - -1000, -1000, -1000, -1000, 4460, -1000, -1000, -1000, 30032, -1000, - 44075, -1000, 1448, -1000, 4733, 1568, 1568, 1568, 2412, 4029, - 43294, 42514, -1000, -1000, 890, 6620, 4659, 6913, 4135, -1000, - 65915, -1000, -1000, -1000, 1348, -1000, 1568, 1568, 1228, 79955, - 3082, 1568, 3079, 4223, -1000, -1000, 1038, 79955, 79955, -1000, - 79955, 79955, 79955, 79955, 79955, 79955, 79955, -1000, -1000, 79955, - 65135, -1000, 79955, 79955, -1000, 79955, 3078, 79955, 79955, 3074, - 4592, 2761, 2761, 1501, -1000, -1000, 968, -1000, 65135, 3423, - 3422, 3418, 3417, 3414, 3822, 3818, 3815, 2761, 2761, 3413, - 3814, 64355, 3813, 2050, 3411, 3410, 3409, 3386, 3812, 1426, - -1000, 3811, 3351, 3340, 3330, 79955, 4222, 3709, -1000, -1000, - 3276, 3806, 4219, 3403, 3804, 1395, 582, 3801, 4413, 317, - 2761, 667, 79955, 2896, 2894, 37834, 2761, 38614, -1000, 992, - 957, 957, 936, 98, 32374, -1000, -1000, -1000, 79955, 79955, - 11282, -1000, -1000, 198, 125, -1000, -1000, -1000, -1000, 63575, - 3799, 917, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 4611, - 16756, 4580, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 79955, 1276, -1000, -1000, -1000, 25348, -1000, -1000, 79955, -1000, - 4791, -1000, 30032, -1000, -1000, -1000, 2418, -1000, 2994, -358, - 21448, 2785, 2751, -1000, 16756, 21448, 16756, -175, 665, -188, - -1000, -1000, -1000, -1000, 3798, -1000, -1000, -1000, 3401, -1000, - 3395, -1000, 138, 418, 449, 4611, -1000, 489, 3571, -1000, - -1000, 13628, 1817, 2619, 4527, 2180, 2609, -1000, -1000, -1000, - -1000, 4723, -1000, -1000, -1000, -1000, -1000, 242, -384, -391, - 238, 3796, 79955, 3380, -1000, -1000, -1000, -1000, -1000, 1738, - -1000, -1000, -1000, 4791, 2781, 4791, 54995, 2781, 2784, -1000, - -1000, -1000, -1000, 1851, -1000, -1000, 4791, -1000, 3035, 3035, - -1000, -1000, -377, 4791, 4791, 2781, -1000, -1000, 4807, 63575, - 582, 2632, 62795, -1000, 619, 2183, 960, 3794, -1000, 1362, - 195, 3791, 3789, -1000, -1000, -1000, -1000, 20666, -1000, -1000, - 20666, 2756, 2753, -1000, -1000, -1000, 3035, 16756, 4025, 4211, - 3258, 4022, 4019, -1000, -1000, 4211, 4211, -1000, 4208, 4209, - 4208, 2543, 2543, 4017, -1000, 4218, -1000, 4622, -1000, 2606, - 3198, 3628, 5914, 397, 3609, 3581, 16756, 2416, 4013, 5704, - 2308, 2065, 3569, 83, 397, 4787, 397, -41, 397, 397, - -1000, -1000, -1000, 397, 397, 397, 397, 397, -1000, 397, - 397, 397, 397, 397, 397, 397, 397, 4217, 397, 397, - 397, 397, 16756, -1000, 87755, -1000, 397, 4576, 2209, 397, - 2168, 397, 397, 3557, 27, -230, 25, -234, 4611, 4778, - -1000, -1000, -1000, 16756, 477, 4011, 4900, 2156, 954, 954, - 3789, 3770, 79955, -1000, -1000, -1000, 3766, 1691, -242, 79955, - -1000, -393, -409, 300, 79955, 3764, 79955, 79955, 259, 2981, - 3090, -1000, 3757, -1000, -1000, 62015, 79955, 79955, 81515, 1019, - 79955, 79955, 3755, -1000, -1000, 4216, -1000, 4215, -12, 4213, - 35, 3754, 4010, 2151, -1000, -1000, 79955, -1000, -1000, -1000, - 4009, 2102, -1000, -1000, -1000, 6620, 4212, 4211, 4211, 1667, - 4208, -1000, -1000, -1000, 4208, -1000, -1000, -1000, -1000, 4211, - 4211, 4211, 4211, 4211, 4211, 4210, -1000, -1000, 4209, 4209, - 4209, 4208, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 1649, 4206, 4207, 4207, 4206, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 4657, 4654, 3492, -1000, -1000, - -1000, 41734, 79955, 957, -1000, -1000, -1000, 1092, 654, 3379, - 921, -1000, 79955, 856, 724, 4542, 2889, 3751, 79955, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 4599, - -1000, 1324, -377, 79955, 861, 22228, -1000, 1837, 4653, 79955, - -1000, 79955, 61235, -1000, -93, -1000, -1000, 24568, -1000, 2761, - 24568, 865, 2809, -1000, 16756, 2605, 4616, -1000, 3063, -100, - 14410, 2007, 79955, -100, 79955, 79955, 14410, -1000, 79955, -1000, - 79955, 16756, -1000, -1000, -331, 4007, -1000, 1190, 2075, 211, - 30032, 79955, -1000, 57335, 16756, -1000, -1000, 16756, 4204, -1000, - -1000, -1000, -346, -1000, 4006, -1000, -1000, -1000, -1000, -1000, - 4442, -1000, 306, -1000, 4203, 4567, -1000, -1000, -1000, 3750, - -1000, 2101, 55775, -1000, 2887, -1000, -1000, 2096, 54215, -1000, - 2886, -1000, -1000, 865, -1000, 1721, -1000, 2321, 1394, 27691, - -1000, 1187, 4561, 79955, 6620, -1000, 79955, -1000, 79955, 79955, - -1000, 79955, 79955, 1228, 16756, 974, 737, 698, -1000, 1066, - -1000, 903, 1650, 796, 1274, 1274, 4561, 79955, 1285, -1000, - 2079, -1000, 4622, -1000, -1000, 2078, -1000, -1000, -1000, -1000, - 79955, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 37834, - 37834, 4695, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 3746, 3741, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 79955, 2602, -1000, - 2884, 3740, 35, 10500, -1000, -1000, 1273, -1000, 4411, 1359, - 3492, 41734, 2881, 2711, 3736, 3735, -1000, 37834, -1000, 957, - -1000, 3733, 3732, -1000, 3105, 2877, 1358, 79955, -1000, 1850, - 79955, 79955, -1000, 1986, -1000, 2876, 2113, -1000, -1000, -1000, - -1000, 2044, 4005, -1000, -1000, 4605, -1000, -1000, 4593, -1000, - -1000, 4000, 854, 4786, 2000, 60455, -1000, -358, 2904, -1000, - 3025, 278, 3009, 79955, -1000, -1000, -1000, 3999, 3998, -1000, - -130, 450, 4777, 4776, 4605, -146, 3730, -1000, 1813, 1998, - -100, -1000, 1654, -1000, -1000, -1000, -1000, -412, -1000, -1000, - 896, -1000, 4791, -1000, 2781, 4791, 4791, -271, -1000, -1000, - -1000, -1000, 4791, 582, -1000, 2068, -1000, -1000, -1000, -1000, - -1000, -1000, 509, -1000, 79955, -1000, 1984, 194, -1000, -1000, - -1000, 3035, -1000, 1493, 491, -1000, -1000, -1000, 1481, -1000, - -1000, -1000, -1000, -1000, -1000, 40954, -1000, -1000, -1000, 16756, - -1000, -1000, -1000, -1000, -1000, 3543, 79955, -1000, -1000, 16756, - 16756, -1000, 3997, 3725, -1000, 4202, -1000, 3996, 3724, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 4872, -1000, -1000, -1000, -1000, 3537, - 3995, 1189, -1000, -1000, -1000, -351, 16756, -1000, -351, 16756, - -1000, -1000, 4806, 2594, 3994, 3988, 2581, 3983, 3982, 4605, - 4611, 1815, 3977, 1949, -1000, -1000, -1000, -1000, -1000, -1000, - 3974, 4900, 1513, 3717, 1513, -1000, -1000, -1000, -1000, 59675, - 79955, -1000, -1000, -1000, 59675, 79955, 4805, 40174, 1260, -377, - 895, 4195, -1000, 901, 2981, 1651, 4194, 3714, -1000, 79955, - 4802, 79955, 3276, 1013, 3276, 1057, 79955, -251, 55775, 54215, - 33, 3367, 10500, -1000, 3712, -1000, 17, 1925, 6620, 1391, - 25348, 4594, 1837, 1837, -1000, 3710, 535, -1000, -1000, -1000, - 811, -1000, 3366, -1000, -1000, 3280, 2462, 558, -1000, -1000, - -1000, -1000, -1000, -1000, 3215, 79955, 58895, 3215, 3440, 2874, - -378, -1000, 4193, -1000, 2761, 2761, 2761, 1260, 850, 79955, - 3973, 1884, -1000, -1000, -1000, -1000, -1000, 1837, -1000, 4551, - 79955, 2048, 3965, -258, 3955, 1207, 2749, 2746, -1000, 3353, - 2580, 4526, 1547, -1000, 3953, 1875, -100, -1000, -1000, 1817, - 2415, -1000, -1000, -1000, 2866, 3035, -1000, -1000, 58115, 30032, - 57335, 1996, -1000, 2401, -1000, 2958, 3035, 79955, -1000, 2386, - -1000, -1000, -1000, 56555, -1000, 4775, 4774, 249, 55775, 2576, - 54995, 54215, 2573, 53435, 1207, -1000, 52655, 2561, -1000, 79955, - -1000, -1000, 79955, 2560, -1000, 7796, 4191, -1000, 4190, 4189, - 4395, 952, 4188, 4187, 79955, 3533, 964, 3352, 20666, 4186, - 20666, 4185, 986, 4184, -1000, -1000, -1000, -1000, -1000, 1169, - 4585, -1000, 759, -1000, -1000, -1000, -1000, 1026, 1025, -1000, - -1000, 4561, 79955, 79955, -1000, 79955, -1000, 2589, -1000, 37834, - -1000, -1000, 2545, -1000, 3709, 3702, -1000, -1000, 3952, 3035, - -1000, 2340, 582, 1343, 79955, -1000, 535, 3693, 11282, -1000, - -1000, -1000, -1000, -1000, -1000, 4542, 3691, 3215, 79955, -1000, - 79955, 1850, 1850, 4872, 30032, 79955, 14410, -331, -1000, -1000, - 4572, 2694, -1000, -1000, -1000, 79955, 4784, 4773, -1000, 1227, - 21448, -189, 660, -1000, -1000, -1000, -135, 3688, -1000, -1000, - 4772, 3680, 3512, -1000, 274, 3679, -1000, -100, -1000, 1817, - 3664, -1000, -1000, -1000, 4791, -1000, -1000, 79955, -1000, 1851, - -1000, -1000, 1735, 1087, -1000, 4693, 3945, 4687, 2821, -1000, - -1000, -1000, 3524, -1000, -1000, 3493, 3434, -341, -1000, 4872, - 397, -1000, 3934, 397, -1000, 4872, -1000, 4770, 397, 3427, - 397, 3421, -351, 4558, -1000, 3658, -1000, -1000, -1000, 3657, - -1000, -1000, -1000, 4605, -1000, 16756, -1000, 3932, -1000, 3656, - -1000, -1000, -1000, 3655, -1000, 3654, -244, -1000, -1000, 697, - 1260, -1000, 609, 79955, 953, -1000, 51875, 10500, -379, 842, - 79955, 4801, 3649, 3276, 3646, 3276, 79955, 1009, -1000, 2536, - 2524, 4652, 3643, -1000, 3929, -1000, 3642, 3641, -1000, -1000, - 6620, -1000, 3466, 4866, 4866, -1000, -1000, 4764, -1000, 1871, - 690, -1000, -1000, 3220, 996, -1000, -1000, 3636, 963, -1000, - 1850, -1000, -1000, 2854, 3150, 3550, 49535, 37834, 38614, 3635, - -1000, 79955, -1000, 7267, 24568, -1000, 1260, 4718, 841, 4737, - 779, 4862, 7473, 1737, 2733, -1000, 3349, -1000, 3348, -1000, - -1000, 4183, 79955, -1000, -1000, 1817, 79955, 16756, 4791, 1996, - 199, -331, -1000, 2621, 307, -1000, 39394, 2497, -1000, 16756, - 2496, -1000, -1000, -1000, -1000, 4182, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 1737, 79955, -1000, 1187, 4525, -1000, - -1000, 79955, -1000, 7796, -1000, -1000, 3093, 3053, 20666, -1000, - -1000, 3626, 3624, 3621, 38614, 1393, 2850, 2848, 1406, 4179, - -1000, 1037, 4842, 3347, -1000, -1000, -1000, 1464, -163, 4178, - 3054, 3015, -1000, 79955, -1000, 49535, 49535, 49535, 2070, 2070, - 49535, 49535, 4175, 1274, 4135, 4769, -1000, 5584, 79955, 5506, - 79955, 4174, 2844, 20666, 8140, 8140, 8140, 8140, 8140, 20666, - -1000, -1000, -1000, 2841, -1000, -1000, -1000, -1000, -1000, -1000, - 2761, 2485, -1000, -1000, -1000, -1000, -1000, 79955, 2378, -1000, - -1000, -1000, 3440, -1000, -1000, 1832, -1000, 4751, 1996, -1000, - -1000, -1000, -1000, -1000, 4513, -1000, -348, 16756, 17538, -1000, - -358, 79955, 79955, -137, 3344, -1000, 3620, 439, -1000, -1000, - 418, -1000, 1817, -1000, -1000, 2781, -139, 262, 37834, 2825, - 37834, -1000, 37834, 3925, 557, 7, -1000, -1000, -1000, 397, - 3915, -1000, 397, -1000, 594, 16756, -1000, -351, -1000, -351, - 397, -1000, 3911, 3906, -1000, 3356, -1000, -1000, -1000, -1000, - 79955, 79955, -1000, 79955, 3619, 3342, -1000, -1000, 2491, -1000, - -1000, -1000, 3033, 3027, 2489, 3831, 3541, 79955, 832, 79955, - -251, 3618, -251, 3614, 1001, 3276, -1000, -1000, -205, -1000, - -1000, -1000, -1000, 15, -1000, -1000, -1000, 694, -1000, 970, - 3507, 3336, -1000, -1000, 687, -1000, -1000, -1000, 3215, 3613, - -1000, -1000, 192, -1000, 2810, 2480, -1000, -1000, -1000, 811, - 1177, -1000, 1837, 4651, 7146, -1000, 2009, -1000, -1000, -1000, - 79955, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1735, 2761, - -1000, 1177, 1080, 2827, -1000, 3333, -1000, -1000, 16756, 1768, - -1000, 3035, 4872, -331, -1000, 13628, -1000, 3020, 79955, 79955, - -1000, -1000, -1000, 51095, 80735, 1067, 2472, -1000, 5385, 1357, - -1000, -1000, -1000, -1000, 5605, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 3596, 3589, -1000, -1000, -1000, -1000, -1000, - 3283, 4172, 217, -1000, 4686, 4650, 16756, -1000, -1000, 4171, - 2461, 2457, 2443, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 2440, 2428, 49535, -1000, - -1000, -1000, 976, -1000, 2389, -1000, 2385, 50315, 3277, 4788, - -1000, 2761, 2761, 3585, 3584, 790, -1000, -1000, 2761, 2761, - 2761, 2761, 2761, 2761, 4162, 3583, 3580, 2761, 2761, 2761, - 2761, 2761, 2761, 2806, -1000, -1000, -1000, 2803, 2761, 2761, - 2761, 5605, 8140, 3146, 37834, 2761, 2307, 79955, -1000, -331, - -331, 4511, -1000, 79955, 3035, 1907, 359, 4161, 4159, -1000, - -1000, -1000, 4156, -1000, -1000, 4768, -130, 4791, -141, 3574, - 415, 443, -1000, 3572, 3810, -1000, -1000, 11, 4510, 4507, - 3, -1000, -1000, -1000, -1000, -1000, 1549, -1000, -1000, -1000, - 1815, 397, 397, -1000, -1000, -1000, -1000, 3570, -1000, -1000, - -1000, -1000, -1000, 79955, 3556, -1000, -1000, 176, -1000, 2778, - -1000, 79955, 821, -1000, -251, -1000, -251, 3276, 3551, -1000, - 79955, 1031, -1000, -1000, -1000, -1000, 499, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 3550, 3547, -1000, -1000, 958, 4767, - -1000, 1837, 7473, -1000, 2761, 811, -1000, 405, 958, -1000, - 886, -1000, 2681, -1000, 3275, -1000, 2359, 4751, -1000, 1813, - 2966, 16756, 3020, 3020, -1000, -1000, 2339, -1000, 648, 4897, - -1000, 879, -1000, -1000, -1000, 5385, 971, -1000, -1000, 1170, - 4154, -1000, -1000, 3800, 16756, 4153, 2761, 4152, 3350, 26, - 49535, 4390, -1000, 4098, 3902, 3856, 2313, 965, -1000, -1000, - -1000, 2302, -1000, -1000, 3267, 3266, -1000, -1000, 79955, 3265, - 3263, 3261, 3260, 3259, 3255, 79955, -1000, -1000, 3247, 3224, - 3202, 3196, 3179, 3170, 3128, 3099, 3149, 3141, 3138, -1000, - -1000, -1000, 37834, 79955, -1000, -1000, -1000, -1000, 1801, -1000, - 4648, -1000, -305, 4151, 16756, 16756, 79955, 3512, -135, -1000, - -1000, 3545, -1000, 1241, 467, 443, -1000, 4766, 433, 4761, - 4760, 1782, -1000, 4505, -1000, -1000, -1000, -1000, 1398, -112, - 401, 394, 389, 305, -1000, -1000, -1000, -1000, -1000, -1000, - 3050, 3050, -251, 3541, 3536, -1000, 79955, -1000, -1000, 3531, - -251, 911, -1000, 612, -1000, -1000, -1000, 8040, -1000, 4758, - 1038, -1000, -1000, 37834, -1000, 4860, 4859, 4858, 4853, -1000, - -1000, -1000, -1000, -1000, 3130, -1000, -1000, -331, 4798, 3035, - 2965, 2888, 3748, 80735, 4869, 4664, 3526, -1000, -1000, -1000, - -1000, 2298, -1000, 79955, 1390, 12846, -1000, 3279, -1000, 37834, - 16756, -154, 4410, -1000, 490, 2280, 8140, 2070, 8140, 8140, - 2070, 8140, 2070, 8140, 2070, 606, -1000, 3109, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 2272, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 79955, 4148, -1000, 4147, 2207, 2205, - 2204, -1000, -1000, -137, -1000, 4144, 3038, 450, 429, 4757, - -1000, 3512, 4740, 3512, 3512, -1000, 408, 4809, 3002, -1000, - 419, 417, 403, 384, -1000, -1000, -1000, -1000, -1000, -1000, - 2981, -1000, 2981, -1000, -1000, -1000, -1000, -251, -1000, 3522, - -1000, -1000, -1000, -1000, -1000, -1000, 48755, 974, -1000, -1000, - -1000, 4141, -1000, 4140, -1000, 4139, -1000, -1000, 4683, -1000, - 4845, 4844, -1000, -1000, -1000, 3520, 4896, 245, -1000, 971, - 7473, -1000, 12846, 2200, -1000, 3035, -1000, 1274, -1000, 3166, - -1000, -1000, -1000, -1000, 4407, 4405, 4795, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 87755, - 2189, 16756, -1000, -1000, -1000, 79955, -1000, 4675, 37054, 434, - -1000, -1000, -1000, 3513, -1000, 3512, -1000, -1000, 2755, 5, - 1398, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -225, -1000, - 79955, 964, 47195, 47195, 47195, 79955, 3942, 3938, 3399, 3510, - 4138, -1000, 7473, 2166, -1000, 12846, -1000, -154, -1000, 4840, - -1000, 4799, 1518, 1518, 8140, 8140, 8140, 8140, 3739, -1000, - 4137, 3731, -1000, -1000, 79955, -1000, 2144, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 3503, 2, -1000, -1000, -1000, 3497, - 2143, 4135, 2120, -1000, 2752, -1000, -1000, 2110, -1000, 2744, - 2064, -1000, 2713, 1768, 79955, 4134, 79955, 4133, -1000, 4404, - -1000, -1000, 3431, -1000, 80735, -1000, -1000, -1000, -1000, -1000, - -1000, 3209, 1042, -1000, -1000, 16756, -1000, 1754, -1000, 2705, - -1000, 47975, -1000, -1000, -1000, -1000, -1000, -1000, 47195, 46415, - -1000, 47195, 46415, -1000, 47195, 46415, 2018, 2005, 16756, 2017, - 16756, 4888, -1000, 2014, -1000, -1000, -1000, 3728, 79955, 12064, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 4521, - 79955, 79955, 1959, 4517, 1946, 3399, 3399, -1000, -1000, -1000, - -1000, 3035, 4132, 1926, -1000, -1000, 4041, -1000, -1000, 3647, - -1000, 3625, 16756, 79955, 16756, 4889, 4891, 1885, -1000, 1863, - -1000, -1000, -1000, -1000, -} - -var yyPgo = [...]int{ - 0, 44, 5783, 8, 1, 5780, 5779, 5778, 228, 100, - 325, 243, 5776, 134, 357, 401, 363, 382, 5775, 356, - 355, 5774, 5773, 5772, 353, 348, 5771, 5754, 5753, 5752, - 5751, 5750, 5749, 5733, 5730, 5726, 5725, 5724, 5723, 5722, - 5721, 5720, 5709, 5705, 5704, 5701, 5700, 5699, 5698, 5697, - 5696, 5695, 5694, 5692, 5691, 5690, 5689, 5688, 5687, 5686, - 5685, 5684, 354, 5683, 5679, 5677, 5676, 5675, 5674, 5673, - 5672, 5655, 5654, 5653, 5652, 5648, 5647, 5646, 5645, 5644, - 5637, 5636, 5635, 5628, 5627, 5625, 5624, 5621, 5620, 5619, - 5618, 5617, 5615, 5613, 5612, 5611, 5609, 5605, 5597, 5591, - 5590, 5587, 239, 5586, 347, 5585, 5584, 5583, 5582, 5581, - 5578, 5577, 4579, 5575, 91, 58, 72, 5574, 5573, 5571, - 5569, 5568, 5567, 5566, 5563, 352, 206, 5562, 5559, 5557, - 5556, 5555, 5553, 5552, 5551, 5550, 5546, 5544, 5541, 5533, - 188, 5532, 5531, 351, 5529, 5526, 5525, 5524, 5522, 286, - 5521, 150, 5520, 337, 233, 5519, 5518, 5497, 5494, 5493, - 5490, 5489, 152, 167, 5488, 5487, 5486, 5485, 5484, 5483, - 5482, 5480, 5479, 5478, 5477, 5476, 196, 5475, 321, 281, - 111, 5474, 76, 5473, 315, 161, 274, 5471, 294, 5470, - 207, 5469, 205, 5468, 5466, 5464, 5463, 5462, 5459, 5458, - 5456, 5455, 5453, 5452, 5451, 5450, 5449, 5448, 5446, 5445, - 5444, 5443, 5442, 5441, 5440, 5439, 5436, 5433, 5430, 5428, - 5427, 5425, 5420, 78, 5418, 342, 5417, 116, 5416, 120, - 110, 215, 5415, 146, 5398, 237, 5396, 114, 5395, 336, - 112, 5394, 33, 50, 5393, 296, 70, 118, 5391, 5390, - 334, 4099, 320, 5389, 200, 5388, 298, 5387, 5386, 5385, - 302, 84, 45, 253, 5384, 5382, 338, 226, 5381, 5380, - 5379, 343, 5377, 301, 229, 223, 124, 172, 5376, 225, - 5374, 117, 107, 123, 61, 65, 95, 136, 258, 180, - 5372, 5370, 135, 299, 179, 256, 144, 5369, 5364, 5361, - 11, 241, 308, 5360, 224, 232, 121, 5359, 5353, 283, - 5352, 5351, 5349, 295, 209, 5348, 148, 5347, 5346, 5345, - 35, 5344, 5336, 271, 262, 5335, 5331, 153, 5330, 5329, - 149, 252, 186, 5328, 113, 177, 219, 176, 5327, 4614, - 182, 139, 5323, 105, 163, 5321, 90, 5320, 5319, 5318, - 5317, 238, 5316, 5309, 204, 5308, 102, 5307, 5302, 5300, - 103, 5283, 104, 108, 157, 145, 5277, 46, 154, 143, - 5274, 5273, 5272, 5269, 5266, 14, 6, 4, 5265, 5263, - 5262, 5261, 7, 5260, 5259, 2, 5258, 43, 5257, 81, - 5256, 5254, 5253, 5252, 5251, 5249, 5248, 5247, 5246, 5244, - 5242, 5240, 53, 5239, 5238, 5235, 5210, 13, 28, 38, - 5208, 42, 5207, 220, 5206, 5205, 216, 5204, 5203, 267, - 5201, 5200, 138, 133, 5199, 140, 5197, 250, 5196, 63, - 5195, 5194, 106, 5193, 5192, 5191, 330, 5189, 5188, 5187, - 275, 5185, 5184, 5183, 5182, 816, 5181, 5180, 5179, 5177, - 5176, 5175, 476, 333, 3, 292, 41, 5173, 194, 210, - 5171, 66, 49, 5169, 73, 158, 289, 199, 162, 5168, - 5166, 5164, 830, 175, 147, 254, 0, 155, 293, 236, - 332, 5147, 5146, 350, 5145, 331, 300, 329, 119, 345, - 323, 5144, 5142, 93, 5141, 213, 115, 68, 203, 555, - 24, 372, 5140, 2978, 18, 263, 5139, 278, 5138, 40, - 25, 12, 187, 5137, 5136, 55, 361, 5135, 5134, 5133, - 190, 272, 5131, 5130, 316, 195, 85, 5124, 1729, 5123, - 51, 5122, 5121, 57, 5119, 247, 77, 48, 5118, 5117, - 169, 259, 327, 132, 467, 208, 251, 242, 217, 307, - 311, 130, 20, 246, 5115, 2368, 212, 159, 30, 5110, - 15, 305, 285, 288, 174, 5109, 131, 5108, 324, 340, - 280, 5107, 255, 21, 75, 62, 47, 69, 22, 99, - 97, 29, 37, 5105, 5103, 5102, 5101, 5100, 23, 67, - 5099, 79, 5097, 32, 5096, 5093, 82, 64, 5092, 83, - 16, 5091, 5090, 26, 19, 31, 5087, 59, 279, 222, - 178, 141, 109, 5086, 5083, 245, 554, 5081, 192, 191, - 197, 5080, 60, 5078, 5077, 5076, 5075, 4310, 1715, 5074, - 211, 5072, 5071, 5070, 5069, 5066, 5065, 277, 341, 193, - 230, 317, 318, 339, 5064, 125, 71, 282, 5063, 5062, - 5061, 126, 184, 5060, 5059, 5058, 5057, 52, 122, 5054, - 27, 5048, 36, 34, 54, 5047, 80, 5046, 5045, 5044, - 17, 261, 5043, 5042, 5041, 9, 5040, 5036, 5, 5035, - 5033, 173, 5032, 142, 39, 218, 221, 5031, 5030, 137, - 260, 183, 5029, 5026, 170, 322, 5025, 273, 5024, 3549, - 313, 335, 5023, 287, 5022, 5020, 5019, 290, 5018, 1719, - 5016, 5012, 304, 98, 127, 5011, 303, 166, 5010, 5009, - 129, 214, 171, 165, 88, 128, 5008, 164, 284, 5007, - 270, 5006, 312, 5005, 5004, 5000, 4998, 231, 4994, 4985, - 4976, 4974, 257, 4972, 4953, 265, 309, 4938, 4936, 319, - 314, 4933, 4922, 4921, 4919, 4918, 4914, 4913, 4912, 94, - 4911, 4910, 326, 328, 4908, 4906, 96, 4905, 4904, -} - -//line mysql_sql.y:16990 -type yySymType struct { - union interface{} - id int - str string - item interface{} - pos int - yys int -} - -func (st *yySymType) PartitionNamesUnion() tree.IdentifierList { - v, _ := st.union.(tree.IdentifierList) - return v -} - -func (st *yySymType) accessModeUnion() tree.AccessModeType { - v, _ := st.union.(tree.AccessModeType) - return v -} - -func (st *yySymType) accountAuthOptionUnion() tree.AccountAuthOption { - v, _ := st.union.(tree.AccountAuthOption) - return v -} - -func (st *yySymType) accountCommentUnion() tree.AccountComment { - v, _ := st.union.(tree.AccountComment) - return v -} - -func (st *yySymType) accountCommentOrAttributeUnion() tree.AccountCommentOrAttribute { - v, _ := st.union.(tree.AccountCommentOrAttribute) - return v -} - -func (st *yySymType) accountIdentifiedUnion() tree.AccountIdentified { - v, _ := st.union.(tree.AccountIdentified) - return v -} - -func (st *yySymType) accountRoleUnion() *tree.Role { - v, _ := st.union.(*tree.Role) - return v -} - -func (st *yySymType) accountStatusUnion() tree.AccountStatus { - v, _ := st.union.(tree.AccountStatus) - return v -} - -func (st *yySymType) accountsSetOptionUnion() *tree.AccountsSetOption { - v, _ := st.union.(*tree.AccountsSetOption) - return v -} - -func (st *yySymType) aliasedTableExprUnion() *tree.AliasedTableExpr { - v, _ := st.union.(*tree.AliasedTableExpr) - return v -} - -func (st *yySymType) allCDCOptionUnion() *tree.AllOrNotCDC { - v, _ := st.union.(*tree.AllOrNotCDC) - return v -} - -func (st *yySymType) alterAccountAuthOptionUnion() tree.AlterAccountAuthOption { - v, _ := st.union.(tree.AlterAccountAuthOption) - return v -} - -func (st *yySymType) alterColPositionUnion() *tree.ColumnPosition { - v, _ := st.union.(*tree.ColumnPosition) - return v -} - -func (st *yySymType) alterColumnOrderUnion() *tree.AlterColumnOrder { - v, _ := st.union.(*tree.AlterColumnOrder) - return v -} - -func (st *yySymType) alterColumnOrderByUnion() []*tree.AlterColumnOrder { - v, _ := st.union.([]*tree.AlterColumnOrder) - return v -} - -func (st *yySymType) alterPartitionOptionUnion() tree.AlterPartitionOption { - v, _ := st.union.(tree.AlterPartitionOption) - return v -} - -func (st *yySymType) alterTableUnion() tree.AlterTable { - v, _ := st.union.(tree.AlterTable) - return v -} - -func (st *yySymType) alterTableOptionUnion() tree.AlterTableOption { - v, _ := st.union.(tree.AlterTableOption) - return v -} - -func (st *yySymType) alterTableOptionsUnion() tree.AlterTableOptions { - v, _ := st.union.(tree.AlterTableOptions) - return v -} - -func (st *yySymType) alterTypeOptionUnion() *tree.TypeOption { - v, _ := st.union.(*tree.TypeOption) - return v -} - -func (st *yySymType) analyzeTableEntriesUnion() []*tree.AnalyzeTableEntry { - v, _ := st.union.([]*tree.AnalyzeTableEntry) - return v -} - -func (st *yySymType) analyzeTableEntryUnion() *tree.AnalyzeTableEntry { - v, _ := st.union.(*tree.AnalyzeTableEntry) - return v -} - -func (st *yySymType) applyTableExprUnion() *tree.ApplyTableExpr { - v, _ := st.union.(*tree.ApplyTableExpr) - return v -} - -func (st *yySymType) assignmentUnion() *tree.Assignment { - v, _ := st.union.(*tree.Assignment) - return v -} - -func (st *yySymType) assignmentsUnion() []*tree.Assignment { - v, _ := st.union.([]*tree.Assignment) - return v -} - -func (st *yySymType) atTimeStampUnion() *tree.AtTimeStamp { - v, _ := st.union.(*tree.AtTimeStamp) - return v -} - -func (st *yySymType) attributeNullUnion() tree.AttributeNull { - v, _ := st.union.(tree.AttributeNull) - return v -} - -func (st *yySymType) attributeReferenceUnion() *tree.AttributeReference { - v, _ := st.union.(*tree.AttributeReference) - return v -} - -func (st *yySymType) authRecordUnion() *tree.AuthRecord { - v, _ := st.union.(*tree.AuthRecord) - return v -} - -func (st *yySymType) boolValUnion() bool { - v, _ := st.union.(bool) - return v -} - -func (st *yySymType) checkTableOptionUnion() tree.CheckTableOption { - v, _ := st.union.(tree.CheckTableOption) - return v -} - -func (st *yySymType) clusterByOptionUnion() *tree.ClusterByOption { - v, _ := st.union.(*tree.ClusterByOption) - return v -} - -func (st *yySymType) columnAttributeUnion() tree.ColumnAttribute { - v, _ := st.union.(tree.ColumnAttribute) - return v -} - -func (st *yySymType) columnAttributesUnion() []tree.ColumnAttribute { - v, _ := st.union.([]tree.ColumnAttribute) - return v -} - -func (st *yySymType) columnTableDefUnion() *tree.ColumnTableDef { - v, _ := st.union.(*tree.ColumnTableDef) - return v -} - -func (st *yySymType) columnTypeUnion() *tree.T { - v, _ := st.union.(*tree.T) - return v -} - -func (st *yySymType) comparisionExprUnion() *tree.ComparisonExpr { - v, _ := st.union.(*tree.ComparisonExpr) - return v -} - -func (st *yySymType) comparisonOpUnion() tree.ComparisonOp { - v, _ := st.union.(tree.ComparisonOp) - return v -} - -func (st *yySymType) completionTypeUnion() tree.CompletionType { - v, _ := st.union.(tree.CompletionType) - return v -} - -func (st *yySymType) conflictOptUnion() *tree.ConflictOpt { - v, _ := st.union.(*tree.ConflictOpt) - return v -} - -func (st *yySymType) createOptionUnion() tree.CreateOption { - v, _ := st.union.(tree.CreateOption) - return v -} - -func (st *yySymType) createOptionsUnion() []tree.CreateOption { - v, _ := st.union.([]tree.CreateOption) - return v -} - -func (st *yySymType) cstrUnion() *tree.CStr { - v, _ := st.union.(*tree.CStr) - return v -} - -func (st *yySymType) cteUnion() *tree.CTE { - v, _ := st.union.(*tree.CTE) - return v -} - -func (st *yySymType) cteListUnion() []*tree.CTE { - v, _ := st.union.([]*tree.CTE) - return v -} - -func (st *yySymType) cycleOptionUnion() *tree.CycleOption { - v, _ := st.union.(*tree.CycleOption) - return v -} - -func (st *yySymType) datastreamOptionUnion() *tree.DataStreamOption { - v, _ := st.union.(*tree.DataStreamOption) - return v -} - -func (st *yySymType) datastreamOptionsUnion() tree.DataStreamOptions { - v, _ := st.union.(tree.DataStreamOptions) - return v -} - -func (st *yySymType) datastreamTableParamUnion() *tree.DataStreamTableParam { - v, _ := st.union.(*tree.DataStreamTableParam) - return v -} - -func (st *yySymType) defaultOptionalUnion() bool { - v, _ := st.union.(bool) - return v -} - -func (st *yySymType) diffOutputOptUnion() *tree.DiffOutputOpt { - v, _ := st.union.(*tree.DiffOutputOpt) - return v -} - -func (st *yySymType) directionUnion() tree.Direction { - v, _ := st.union.(tree.Direction) - return v -} - -func (st *yySymType) duplicateKeyUnion() tree.DuplicateKey { - v, _ := st.union.(tree.DuplicateKey) - return v -} - -func (st *yySymType) elseIfClauseUnion() *tree.ElseIfStmt { - v, _ := st.union.(*tree.ElseIfStmt) - return v -} - -func (st *yySymType) elseIfClauseListUnion() []*tree.ElseIfStmt { - v, _ := st.union.([]*tree.ElseIfStmt) - return v -} - -func (st *yySymType) explainOptionUnion() tree.OptionElem { - v, _ := st.union.(tree.OptionElem) - return v -} - -func (st *yySymType) explainOptionsUnion() []tree.OptionElem { - v, _ := st.union.([]tree.OptionElem) - return v -} - -func (st *yySymType) exportParmUnion() *tree.ExportParam { - v, _ := st.union.(*tree.ExportParam) - return v -} - -func (st *yySymType) exprUnion() tree.Expr { - v, _ := st.union.(tree.Expr) - return v -} - -func (st *yySymType) exprsUnion() tree.Exprs { - v, _ := st.union.(tree.Exprs) - return v -} - -func (st *yySymType) fieldsUnion() *tree.Fields { - v, _ := st.union.(*tree.Fields) - return v -} - -func (st *yySymType) fieldsListUnion() []*tree.Fields { - v, _ := st.union.([]*tree.Fields) - return v -} - -func (st *yySymType) fillModeUnion() tree.FillMode { - v, _ := st.union.(tree.FillMode) - return v -} - -func (st *yySymType) foreignTableOptionUnion() tree.ForeignTableOption { - v, _ := st.union.(tree.ForeignTableOption) - return v -} - -func (st *yySymType) foreignTableOptionsUnion() tree.ForeignTableOptions { - v, _ := st.union.(tree.ForeignTableOptions) - return v -} - -func (st *yySymType) foreignTableParamUnion() *tree.ForeignTableParam { - v, _ := st.union.(*tree.ForeignTableParam) - return v -} - -func (st *yySymType) frameBoundUnion() *tree.FrameBound { - v, _ := st.union.(*tree.FrameBound) - return v -} - -func (st *yySymType) frameClauseUnion() *tree.FrameClause { - v, _ := st.union.(*tree.FrameClause) - return v -} - -func (st *yySymType) frameTypeUnion() tree.FrameType { - v, _ := st.union.(tree.FrameType) - return v -} - -func (st *yySymType) fromUnion() *tree.From { - v, _ := st.union.(*tree.From) - return v -} - -func (st *yySymType) fullOptUnion() bool { - v, _ := st.union.(bool) - return v -} - -func (st *yySymType) fullTextSearchTypeUnion() tree.FullTextSearchType { - v, _ := st.union.(tree.FullTextSearchType) - return v -} - -func (st *yySymType) funcArgUnion() tree.FunctionArg { - v, _ := st.union.(tree.FunctionArg) - return v -} - -func (st *yySymType) funcArgDeclUnion() *tree.FunctionArgDecl { - v, _ := st.union.(*tree.FunctionArgDecl) - return v -} - -func (st *yySymType) funcArgsUnion() tree.FunctionArgs { - v, _ := st.union.(tree.FunctionArgs) - return v -} - -func (st *yySymType) funcExprUnion() *tree.FuncExpr { - v, _ := st.union.(*tree.FuncExpr) - return v -} - -func (st *yySymType) funcReturnUnion() *tree.ReturnType { - v, _ := st.union.(*tree.ReturnType) - return v -} - -func (st *yySymType) funcTypeUnion() tree.FuncType { - v, _ := st.union.(tree.FuncType) - return v -} - -func (st *yySymType) functionNameUnion() *tree.FunctionName { - v, _ := st.union.(*tree.FunctionName) - return v -} - -func (st *yySymType) groupByUnion() *tree.GroupByClause { - v, _ := st.union.(*tree.GroupByClause) - return v -} - -func (st *yySymType) icebergOptionUnion() *tree.IcebergOption { - v, _ := st.union.(*tree.IcebergOption) - return v -} - -func (st *yySymType) icebergOptionsUnion() tree.IcebergOptions { - v, _ := st.union.(tree.IcebergOptions) - return v -} - -func (st *yySymType) icebergRefSpecUnion() *tree.IcebergRefSpec { - v, _ := st.union.(*tree.IcebergRefSpec) - return v -} - -func (st *yySymType) icebergTableParamUnion() *tree.IcebergTableParam { - v, _ := st.union.(*tree.IcebergTableParam) - return v -} - -func (st *yySymType) identifierListUnion() tree.IdentifierList { - v, _ := st.union.(tree.IdentifierList) - return v -} - -func (st *yySymType) ifNotExistsUnion() bool { - v, _ := st.union.(bool) - return v -} - -func (st *yySymType) incrementByOptionUnion() *tree.IncrementByOption { - v, _ := st.union.(*tree.IncrementByOption) - return v -} - -func (st *yySymType) indexCategoryUnion() tree.IndexCategory { - v, _ := st.union.(tree.IndexCategory) - return v -} - -func (st *yySymType) indexHintUnion() *tree.IndexHint { - v, _ := st.union.(*tree.IndexHint) - return v -} - -func (st *yySymType) indexHintListUnion() []*tree.IndexHint { - v, _ := st.union.([]*tree.IndexHint) - return v -} - -func (st *yySymType) indexHintScopeUnion() tree.IndexHintScope { - v, _ := st.union.(tree.IndexHintScope) - return v -} - -func (st *yySymType) indexHintTypeUnion() tree.IndexHintType { - v, _ := st.union.(tree.IndexHintType) - return v -} - -func (st *yySymType) indexOptionUnion() *tree.IndexOption { - v, _ := st.union.(*tree.IndexOption) - return v -} - -func (st *yySymType) indexTypeUnion() tree.IndexType { - v, _ := st.union.(tree.IndexType) - return v -} - -func (st *yySymType) indexVisibilityUnion() tree.VisibleType { - v, _ := st.union.(tree.VisibleType) - return v -} - -func (st *yySymType) insertUnion() *tree.Insert { - v, _ := st.union.(*tree.Insert) - return v -} - -func (st *yySymType) insertColumnsUnion() tree.InsertColumns { - v, _ := st.union.(tree.InsertColumns) - return v -} - -func (st *yySymType) insertPartitionUnion() *tree.InsertPartitionClause { - v, _ := st.union.(*tree.InsertPartitionClause) - return v -} - -func (st *yySymType) int64ValUnion() int64 { - v, _ := st.union.(int64) - return v -} - -func (st *yySymType) isolationLevelUnion() tree.IsolationLevelType { - v, _ := st.union.(tree.IsolationLevelType) - return v -} - -func (st *yySymType) joinCondUnion() tree.JoinCond { - v, _ := st.union.(tree.JoinCond) - return v -} - -func (st *yySymType) joinTableExprUnion() *tree.JoinTableExpr { - v, _ := st.union.(*tree.JoinTableExpr) - return v -} - -func (st *yySymType) jsonTableColumnUnion() *tree.JSONTableColumn { - v, _ := st.union.(*tree.JSONTableColumn) - return v -} - -func (st *yySymType) jsonTableColumnsUnion() []*tree.JSONTableColumn { - v, _ := st.union.([]*tree.JSONTableColumn) - return v -} - -func (st *yySymType) jsonTableResponseUnion() *tree.JSONTableResponse { - v, _ := st.union.(*tree.JSONTableResponse) - return v -} - -func (st *yySymType) kafkaTableOptionUnion() *tree.KafkaTableOption { - v, _ := st.union.(*tree.KafkaTableOption) - return v -} - -func (st *yySymType) kafkaTableOptionsUnion() tree.KafkaTableOptions { - v, _ := st.union.(tree.KafkaTableOptions) - return v -} - -func (st *yySymType) kafkaTableParamUnion() *tree.KafkaTableParam { - v, _ := st.union.(*tree.KafkaTableParam) - return v -} - -func (st *yySymType) keyPartUnion() *tree.KeyPart { - v, _ := st.union.(*tree.KeyPart) - return v -} - -func (st *yySymType) keyPartsUnion() []*tree.KeyPart { - v, _ := st.union.([]*tree.KeyPart) - return v -} - -func (st *yySymType) killOptionUnion() tree.KillOption { - v, _ := st.union.(tree.KillOption) - return v -} - -func (st *yySymType) lengthOptUnion() int32 { - v, _ := st.union.(int32) - return v -} - -func (st *yySymType) lengthScaleOptUnion() tree.LengthScaleOpt { - v, _ := st.union.(tree.LengthScaleOpt) - return v -} - -func (st *yySymType) limitUnion() *tree.Limit { - v, _ := st.union.(*tree.Limit) - return v -} - -func (st *yySymType) linesUnion() *tree.Lines { - v, _ := st.union.(*tree.Lines) - return v -} - -func (st *yySymType) loadColumnUnion() tree.LoadColumn { - v, _ := st.union.(tree.LoadColumn) - return v -} - -func (st *yySymType) loadColumnsUnion() []tree.LoadColumn { - v, _ := st.union.([]tree.LoadColumn) - return v -} - -func (st *yySymType) loadParamUnion() *tree.ExternParam { - v, _ := st.union.(*tree.ExternParam) - return v -} - -func (st *yySymType) matchTypeUnion() tree.MatchType { - v, _ := st.union.(tree.MatchType) - return v -} - -func (st *yySymType) maxValueOptionUnion() *tree.MaxValueOption { - v, _ := st.union.(*tree.MaxValueOption) - return v -} - -func (st *yySymType) mergeUnion() *tree.Merge { - v, _ := st.union.(*tree.Merge) - return v -} - -func (st *yySymType) mergeClauseUnion() *tree.MergeClause { - v, _ := st.union.(*tree.MergeClause) - return v -} - -func (st *yySymType) mergeClausesUnion() tree.MergeClauses { - v, _ := st.union.(tree.MergeClauses) - return v -} - -func (st *yySymType) minValueOptionUnion() *tree.MinValueOption { - v, _ := st.union.(*tree.MinValueOption) - return v -} - -func (st *yySymType) mongodbOptionUnion() *tree.MongoDBOption { - v, _ := st.union.(*tree.MongoDBOption) - return v -} - -func (st *yySymType) mongodbOptionsUnion() tree.MongoDBOptions { - v, _ := st.union.(tree.MongoDBOptions) - return v -} - -func (st *yySymType) mongodbTableParamUnion() *tree.MongoDBTableParam { - v, _ := st.union.(*tree.MongoDBTableParam) - return v -} - -func (st *yySymType) multiInsertTargetUnion() *tree.MultiInsertTarget { - v, _ := st.union.(*tree.MultiInsertTarget) - return v -} - -func (st *yySymType) multiInsertTargetsUnion() []*tree.MultiInsertTarget { - v, _ := st.union.([]*tree.MultiInsertTarget) - return v -} - -func (st *yySymType) multiInsertWhenUnion() *tree.MultiInsertWhen { - v, _ := st.union.(*tree.MultiInsertWhen) - return v -} - -func (st *yySymType) multiInsertWhensUnion() []*tree.MultiInsertWhen { - v, _ := st.union.([]*tree.MultiInsertWhen) - return v -} - -func (st *yySymType) nullsPositionUnion() tree.NullsPosition { - v, _ := st.union.(tree.NullsPosition) - return v -} - -func (st *yySymType) numValUnion() *tree.NumVal { - v, _ := st.union.(*tree.NumVal) - return v -} - -func (st *yySymType) objectTypeUnion() tree.ObjectType { - v, _ := st.union.(tree.ObjectType) - return v -} - -func (st *yySymType) orderUnion() *tree.Order { - v, _ := st.union.(*tree.Order) - return v -} - -func (st *yySymType) orderByUnion() tree.OrderBy { - v, _ := st.union.(tree.OrderBy) - return v -} - -func (st *yySymType) parenTableExprUnion() *tree.ParenTableExpr { - v, _ := st.union.(*tree.ParenTableExpr) - return v -} - -func (st *yySymType) partitionUnion() *tree.Partition { - v, _ := st.union.(*tree.Partition) - return v -} - -func (st *yySymType) partitionByUnion() *tree.PartitionBy { - v, _ := st.union.(*tree.PartitionBy) - return v -} - -func (st *yySymType) partitionOptionUnion() *tree.PartitionOption { - v, _ := st.union.(*tree.PartitionOption) - return v -} - -func (st *yySymType) partitionValuesUnion() tree.PartitionValues { - v, _ := st.union.(tree.PartitionValues) - return v -} - -func (st *yySymType) partitionsUnion() []*tree.Partition { - v, _ := st.union.([]*tree.Partition) - return v -} - -func (st *yySymType) pickKeysUnion() *tree.PickKeys { - v, _ := st.union.(*tree.PickKeys) - return v -} - -func (st *yySymType) privilegeUnion() *tree.Privilege { - v, _ := st.union.(*tree.Privilege) - return v -} - -func (st *yySymType) privilegeLevelUnion() *tree.PrivilegeLevel { - v, _ := st.union.(*tree.PrivilegeLevel) - return v -} - -func (st *yySymType) privilegeTypeUnion() tree.PrivilegeType { - v, _ := st.union.(tree.PrivilegeType) - return v -} - -func (st *yySymType) privilegesUnion() []*tree.Privilege { - v, _ := st.union.([]*tree.Privilege) - return v -} - -func (st *yySymType) procArgUnion() tree.ProcedureArg { - v, _ := st.union.(tree.ProcedureArg) - return v -} - -func (st *yySymType) procArgDeclUnion() *tree.ProcedureArgDecl { - v, _ := st.union.(*tree.ProcedureArgDecl) - return v -} - -func (st *yySymType) procArgTypeUnion() tree.InOutArgType { - v, _ := st.union.(tree.InOutArgType) - return v -} - -func (st *yySymType) procArgsUnion() tree.ProcedureArgs { - v, _ := st.union.(tree.ProcedureArgs) - return v -} - -func (st *yySymType) procNameUnion() *tree.ProcedureName { - v, _ := st.union.(*tree.ProcedureName) - return v -} - -func (st *yySymType) propertiesUnion() []tree.Property { - v, _ := st.union.([]tree.Property) - return v -} - -func (st *yySymType) propertyUnion() tree.Property { - v, _ := st.union.(tree.Property) - return v -} - -func (st *yySymType) rankOptionUnion() *tree.RankOption { - v, _ := st.union.(*tree.RankOption) - return v -} - -func (st *yySymType) referenceOnRecordUnion() *tree.ReferenceOnRecord { - v, _ := st.union.(*tree.ReferenceOnRecord) - return v -} - -func (st *yySymType) referenceOptionTypeUnion() tree.ReferenceOptionType { - v, _ := st.union.(tree.ReferenceOptionType) - return v -} - -func (st *yySymType) renameTableOptionUnion() *tree.AlterTable { - v, _ := st.union.(*tree.AlterTable) - return v -} - -func (st *yySymType) renameTableOptionsUnion() []*tree.AlterTable { - v, _ := st.union.([]*tree.AlterTable) - return v -} - -func (st *yySymType) replaceUnion() *tree.Replace { - v, _ := st.union.(*tree.Replace) - return v -} - -func (st *yySymType) resourceOptionUnion() tree.ResourceOption { - v, _ := st.union.(tree.ResourceOption) - return v -} - -func (st *yySymType) resourceOptionsUnion() []tree.ResourceOption { - v, _ := st.union.([]tree.ResourceOption) - return v -} - -func (st *yySymType) roleUnion() *tree.Role { - v, _ := st.union.(*tree.Role) - return v -} - -func (st *yySymType) rolesUnion() []*tree.Role { - v, _ := st.union.([]*tree.Role) - return v -} - -func (st *yySymType) rowFormatTypeUnion() tree.RowFormatType { - v, _ := st.union.(tree.RowFormatType) - return v -} - -func (st *yySymType) rowsExprsUnion() []tree.Exprs { - v, _ := st.union.([]tree.Exprs) - return v -} - -func (st *yySymType) selectUnion() *tree.Select { - v, _ := st.union.(*tree.Select) - return v -} - -func (st *yySymType) selectExprUnion() tree.SelectExpr { - v, _ := st.union.(tree.SelectExpr) - return v -} - -func (st *yySymType) selectExprsUnion() tree.SelectExprs { - v, _ := st.union.(tree.SelectExprs) - return v -} - -func (st *yySymType) selectIntoUnion() *tree.SelectInto { - v, _ := st.union.(*tree.SelectInto) - return v -} - -func (st *yySymType) selectLockInfoUnion() *tree.SelectLockInfo { - v, _ := st.union.(*tree.SelectLockInfo) - return v -} - -func (st *yySymType) selectOptionUnion() uint64 { - v, _ := st.union.(uint64) - return v -} - -func (st *yySymType) selectOptionsUnion() uint64 { - v, _ := st.union.(uint64) - return v -} - -func (st *yySymType) selectStatementUnion() tree.SelectStatement { - v, _ := st.union.(tree.SelectStatement) - return v -} - -func (st *yySymType) setDefaultRoleUnion() *tree.SetDefaultRole { - v, _ := st.union.(*tree.SetDefaultRole) - return v -} - -func (st *yySymType) setRoleUnion() *tree.SetRole { - v, _ := st.union.(*tree.SetRole) - return v -} - -func (st *yySymType) showTypeUnion() tree.ShowType { - v, _ := st.union.(tree.ShowType) - return v -} - -func (st *yySymType) snapshotObjectUnion() tree.ObjectInfo { - v, _ := st.union.(tree.ObjectInfo) - return v -} - -func (st *yySymType) sourceOptionalUnion() bool { - v, _ := st.union.(bool) - return v -} - -func (st *yySymType) sqlTaskScheduleUnion() *tree.SQLTaskSchedule { - v, _ := st.union.(*tree.SQLTaskSchedule) - return v -} - -func (st *yySymType) stageCommentUnion() tree.StageComment { - v, _ := st.union.(tree.StageComment) - return v -} - -func (st *yySymType) stageCredentialsUnion() tree.StageCredentials { - v, _ := st.union.(tree.StageCredentials) - return v -} - -func (st *yySymType) stageStatusUnion() tree.StageStatus { - v, _ := st.union.(tree.StageStatus) - return v -} - -func (st *yySymType) stageUrlUnion() tree.StageUrl { - v, _ := st.union.(tree.StageUrl) - return v -} - -func (st *yySymType) startWithOptionUnion() *tree.StartWithOption { - v, _ := st.union.(*tree.StartWithOption) - return v -} - -func (st *yySymType) statementUnion() tree.Statement { - v, _ := st.union.(tree.Statement) - return v -} - -func (st *yySymType) statementOptionUnion() tree.StatementOption { - v, _ := st.union.(tree.StatementOption) - return v -} - -func (st *yySymType) statementsUnion() []tree.Statement { - v, _ := st.union.([]tree.Statement) - return v -} - -func (st *yySymType) strsUnion() []string { - v, _ := st.union.([]string) - return v -} - -func (st *yySymType) subPartitionUnion() *tree.SubPartition { - v, _ := st.union.(*tree.SubPartition) - return v -} - -func (st *yySymType) subPartitionsUnion() []*tree.SubPartition { - v, _ := st.union.([]*tree.SubPartition) - return v -} - -func (st *yySymType) subqueryUnion() *tree.Subquery { - v, _ := st.union.(*tree.Subquery) - return v -} - -func (st *yySymType) subscriptionOptionUnion() *tree.SubscriptionOption { - v, _ := st.union.(*tree.SubscriptionOption) - return v -} - -func (st *yySymType) tableDefUnion() tree.TableDef { - v, _ := st.union.(tree.TableDef) - return v -} - -func (st *yySymType) tableDefsUnion() tree.TableDefs { - v, _ := st.union.(tree.TableDefs) - return v -} - -func (st *yySymType) tableExprUnion() tree.TableExpr { - v, _ := st.union.(tree.TableExpr) - return v -} - -func (st *yySymType) tableExprsUnion() tree.TableExprs { - v, _ := st.union.(tree.TableExprs) - return v -} - -func (st *yySymType) tableLockUnion() tree.TableLock { - v, _ := st.union.(tree.TableLock) - return v -} - -func (st *yySymType) tableLockTypeUnion() tree.TableLockType { - v, _ := st.union.(tree.TableLockType) - return v -} - -func (st *yySymType) tableLocksUnion() []tree.TableLock { - v, _ := st.union.([]tree.TableLock) - return v -} - -func (st *yySymType) tableNameUnion() *tree.TableName { - v, _ := st.union.(*tree.TableName) - return v -} - -func (st *yySymType) tableNamesUnion() tree.TableNames { - v, _ := st.union.(tree.TableNames) - return v -} - -func (st *yySymType) tableOptionUnion() tree.TableOption { - v, _ := st.union.(tree.TableOption) - return v -} - -func (st *yySymType) tableOptionsUnion() []tree.TableOption { - v, _ := st.union.([]tree.TableOption) - return v -} - -func (st *yySymType) tailParamUnion() *tree.TailParameter { - v, _ := st.union.(*tree.TailParameter) - return v -} - -func (st *yySymType) timeFillUnion() *tree.Fill { - v, _ := st.union.(*tree.Fill) - return v -} - -func (st *yySymType) timeIntervalUnion() *tree.Interval { - v, _ := st.union.(*tree.Interval) - return v -} - -func (st *yySymType) timeSlidingUnion() *tree.Sliding { - v, _ := st.union.(*tree.Sliding) - return v -} - -func (st *yySymType) timeWindowUnion() *tree.TimeWindow { - v, _ := st.union.(*tree.TimeWindow) - return v -} - -func (st *yySymType) tlsOptionUnion() tree.TlsOption { - v, _ := st.union.(tree.TlsOption) - return v -} - -func (st *yySymType) tlsOptionsUnion() []tree.TlsOption { - v, _ := st.union.([]tree.TlsOption) - return v -} - -func (st *yySymType) toAccountOptUnion() *tree.ToAccountOpt { - v, _ := st.union.(*tree.ToAccountOpt) - return v -} - -func (st *yySymType) transactionCharacteristicUnion() *tree.TransactionCharacteristic { - v, _ := st.union.(*tree.TransactionCharacteristic) - return v -} - -func (st *yySymType) transactionCharacteristicListUnion() []*tree.TransactionCharacteristic { - v, _ := st.union.([]*tree.TransactionCharacteristic) - return v -} - -func (st *yySymType) tupleUnion() *tree.Tuple { - v, _ := st.union.(*tree.Tuple) - return v -} - -func (st *yySymType) uint64ValUnion() uint64 { - v, _ := st.union.(uint64) - return v -} - -func (st *yySymType) unionTypeRecordUnion() *tree.UnionTypeRecord { - v, _ := st.union.(*tree.UnionTypeRecord) - return v -} - -func (st *yySymType) unresolveNamesUnion() []*tree.UnresolvedName { - v, _ := st.union.([]*tree.UnresolvedName) - return v -} - -func (st *yySymType) unresolvedNameUnion() *tree.UnresolvedName { - v, _ := st.union.(*tree.UnresolvedName) - return v -} - -func (st *yySymType) unresolvedObjectNameUnion() *tree.UnresolvedObjectName { - v, _ := st.union.(*tree.UnresolvedObjectName) - return v -} - -func (st *yySymType) unsignedOptUnion() bool { - v, _ := st.union.(bool) - return v -} - -func (st *yySymType) updateExprUnion() *tree.UpdateExpr { - v, _ := st.union.(*tree.UpdateExpr) - return v -} - -func (st *yySymType) updateExprsUnion() tree.UpdateExprs { - v, _ := st.union.(tree.UpdateExprs) - return v -} - -func (st *yySymType) upgrade_targetUnion() *tree.Target { - v, _ := st.union.(*tree.Target) - return v -} - -func (st *yySymType) userUnion() *tree.User { - v, _ := st.union.(*tree.User) - return v -} - -func (st *yySymType) userIdentifiedUnion() *tree.AccountIdentified { - v, _ := st.union.(*tree.AccountIdentified) - return v -} - -func (st *yySymType) userMiscOptionUnion() tree.UserMiscOption { - v, _ := st.union.(tree.UserMiscOption) - return v -} - -func (st *yySymType) userMiscOptionsUnion() []tree.UserMiscOption { - v, _ := st.union.([]tree.UserMiscOption) - return v -} - -func (st *yySymType) usernameRecordUnion() *tree.UsernameRecord { - v, _ := st.union.(*tree.UsernameRecord) - return v -} - -func (st *yySymType) usersUnion() []*tree.User { - v, _ := st.union.([]*tree.User) - return v -} - -func (st *yySymType) valuesUnion() tree.Values { - v, _ := st.union.(tree.Values) - return v -} - -func (st *yySymType) varAssignmentExprUnion() *tree.VarAssignmentExpr { - v, _ := st.union.(*tree.VarAssignmentExpr) - return v -} - -func (st *yySymType) varAssignmentExprsUnion() []*tree.VarAssignmentExpr { - v, _ := st.union.([]*tree.VarAssignmentExpr) - return v -} - -func (st *yySymType) varExprUnion() *tree.VarExpr { - v, _ := st.union.(*tree.VarExpr) - return v -} - -func (st *yySymType) varExprsUnion() []*tree.VarExpr { - v, _ := st.union.([]*tree.VarExpr) - return v -} - -func (st *yySymType) whenClauseUnion() *tree.When { - v, _ := st.union.(*tree.When) - return v -} - -func (st *yySymType) whenClause2Union() *tree.WhenStmt { - v, _ := st.union.(*tree.WhenStmt) - return v -} - -func (st *yySymType) whenClauseListUnion() []*tree.When { - v, _ := st.union.([]*tree.When) - return v -} - -func (st *yySymType) whenClauseList2Union() []*tree.WhenStmt { - v, _ := st.union.([]*tree.WhenStmt) - return v -} - -func (st *yySymType) whereUnion() *tree.Where { - v, _ := st.union.(*tree.Where) - return v -} - -func (st *yySymType) windowDefinitionUnion() *tree.WindowDefinition { - v, _ := st.union.(*tree.WindowDefinition) - return v -} - -func (st *yySymType) windowDefinitionsUnion() tree.WindowDefinitions { - v, _ := st.union.(tree.WindowDefinitions) - return v -} - -func (st *yySymType) windowSpecUnion() *tree.WindowSpec { - v, _ := st.union.(*tree.WindowSpec) - return v -} - -func (st *yySymType) withClauseUnion() *tree.With { - v, _ := st.union.(*tree.With) - return v -} - -func (st *yySymType) zeroFillOptUnion() bool { - v, _ := st.union.(bool) - return v -} - -var yyR1 = [...]int{ - 0, 756, 760, 12, 12, 9, 13, 13, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 8, - 8, 8, 8, 8, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 168, - 168, 467, 467, 468, 468, 170, 463, 463, 462, 462, - 171, 172, 173, 733, 733, 734, 734, 732, 732, 174, - 175, 214, 731, 731, 731, 731, 731, 731, 731, 731, - 216, 216, 216, 216, 216, 216, 216, 596, 169, 169, - 169, 169, 169, 169, 169, 297, 297, 298, 298, 184, - 184, 185, 185, 186, 186, 220, 220, 220, 220, 220, - 220, 220, 159, 740, 740, 740, 741, 741, 156, 197, - 196, 199, 199, 198, 198, 195, 195, 191, 194, 194, - 193, 193, 192, 187, 189, 189, 188, 190, 190, 157, - 140, 142, 142, 141, 158, 680, 680, 679, 679, 678, - 678, 623, 623, 624, 624, 454, 454, 454, 677, 677, - 677, 676, 676, 675, 675, 673, 673, 674, 674, 671, - 671, 672, 670, 669, 669, 669, 665, 665, 665, 661, - 661, 663, 662, 662, 664, 656, 656, 659, 659, 657, - 657, 657, 657, 660, 655, 655, 655, 654, 654, 139, - 139, 139, 557, 557, 138, 138, 572, 572, 572, 572, - 572, 570, 570, 570, 570, 570, 570, 569, 569, 568, - 568, 573, 573, 571, 571, 571, 571, 571, 571, 571, - 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, - 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, - 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, - 571, 571, 571, 571, 571, 571, 571, 571, 571, 571, - 571, 571, 571, 571, 127, 127, 127, 127, 127, 127, - 127, 134, 132, 132, 132, 133, 746, 746, 745, 745, - 747, 747, 747, 747, 748, 748, 130, 130, 130, 131, - 567, 567, 567, 128, 129, 129, 556, 556, 562, 562, - 561, 561, 561, 561, 561, 561, 561, 561, 561, 561, - 561, 561, 561, 566, 566, 566, 564, 564, 563, 563, - 565, 565, 117, 117, 117, 117, 117, 117, 121, 122, - 123, 123, 123, 123, 120, 119, 555, 555, 555, 555, - 555, 555, 555, 555, 555, 118, 118, 118, 118, 118, - 118, 103, 103, 103, 103, 103, 102, 102, 104, 104, - 104, 552, 552, 551, 135, 135, 136, 743, 743, 742, - 744, 744, 744, 744, 137, 147, 147, 147, 147, 147, - 147, 147, 147, 147, 147, 147, 147, 147, 147, 146, - 146, 146, 149, 149, 149, 148, 150, 126, 126, 126, - 126, 126, 126, 124, 124, 124, 124, 124, 125, 125, - 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, - 125, 125, 125, 125, 125, 125, 706, 706, 706, 706, - 706, 707, 707, 481, 482, 761, 484, 480, 480, 480, - 702, 702, 703, 704, 705, 705, 705, 705, 143, 310, - 310, 308, 308, 309, 309, 144, 311, 311, 311, 145, - 312, 312, 23, 307, 307, 595, 595, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 109, 109, 110, 110, 110, 110, 22, 101, - 106, 106, 106, 108, 418, 418, 419, 417, 417, 417, - 417, 417, 412, 412, 420, 420, 219, 59, 59, 59, - 59, 59, 59, 107, 107, 107, 107, 421, 421, 421, - 427, 427, 428, 428, 413, 413, 413, 413, 413, 413, - 413, 413, 413, 413, 413, 413, 413, 413, 413, 413, - 413, 413, 413, 413, 413, 413, 397, 397, 397, 392, - 392, 392, 392, 393, 393, 394, 394, 395, 395, 395, - 395, 396, 396, 473, 473, 422, 422, 422, 424, 424, - 423, 416, 414, 414, 414, 414, 414, 414, 414, 414, - 415, 415, 415, 415, 425, 425, 426, 426, 99, 111, - 111, 524, 524, 521, 521, 521, 521, 105, 105, 105, - 105, 719, 719, 100, 100, 100, 730, 730, 627, 627, - 495, 495, 494, 494, 494, 494, 494, 494, 494, 494, - 494, 494, 494, 494, 494, 494, 494, 494, 632, 633, - 491, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 62, 62, 62, 60, 61, 165, 165, 167, - 167, 76, 76, 76, 76, 76, 76, 76, 76, 76, - 76, 77, 231, 96, 97, 98, 75, 69, 72, 73, - 218, 221, 221, 221, 221, 68, 68, 68, 68, 541, - 541, 67, 762, 762, 466, 466, 85, 84, 71, 86, - 87, 88, 89, 90, 91, 66, 83, 83, 83, 83, - 83, 83, 83, 83, 94, 650, 650, 764, 764, 764, - 92, 93, 626, 626, 626, 82, 82, 81, 81, 80, - 79, 78, 78, 65, 65, 64, 64, 70, 203, 205, - 74, 204, 204, 206, 206, 488, 488, 488, 490, 490, - 486, 763, 763, 591, 591, 489, 489, 63, 63, 63, - 63, 95, 487, 487, 465, 485, 485, 485, 21, 21, - 19, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, - 26, 58, 35, 36, 34, 37, 39, 549, 549, 546, - 38, 29, 28, 31, 27, 27, 30, 32, 33, 33, - 17, 17, 17, 17, 24, 24, 25, 267, 267, 340, - 340, 713, 713, 709, 709, 710, 710, 710, 711, 711, - 712, 712, 765, 765, 765, 151, 644, 644, 644, 644, - 644, 644, 15, 15, 15, 15, 638, 638, 638, 643, - 643, 642, 641, 641, 640, 640, 639, 639, 639, 639, - 16, 16, 16, 16, 262, 262, 18, 18, 112, 112, - 113, 113, 114, 114, 114, 114, 114, 114, 116, 115, - 115, 296, 296, 637, 637, 637, 637, 637, 637, 554, - 554, 553, 553, 690, 690, 690, 691, 301, 301, 289, - 289, 289, 300, 300, 300, 300, 645, 645, 512, 692, - 692, 653, 653, 652, 652, 651, 651, 294, 294, 302, - 302, 302, 303, 303, 295, 295, 271, 271, 179, 179, - 179, 667, 667, 668, 668, 658, 658, 658, 658, 666, - 666, 622, 622, 402, 402, 456, 456, 457, 457, 249, - 245, 245, 245, 246, 246, 247, 247, 247, 247, 247, - 247, 247, 247, 247, 247, 247, 749, 749, 750, 751, - 752, 752, 753, 753, 754, 754, 754, 755, 755, 755, - 755, 755, 699, 699, 701, 701, 700, 293, 293, 284, - 284, 286, 286, 286, 285, 285, 285, 287, 288, 288, - 282, 282, 283, 283, 281, 280, 280, 279, 277, 277, - 277, 278, 278, 278, 306, 306, 306, 306, 251, 251, - 251, 251, 250, 250, 250, 250, 250, 250, 250, 250, - 250, 253, 254, 254, 256, 255, 255, 255, 255, 257, - 258, 258, 260, 259, 259, 259, 259, 436, 436, 436, - 436, 436, 436, 436, 436, 436, 436, 436, 436, 252, - 264, 264, 265, 265, 266, 266, 266, 266, 266, 266, - 266, 266, 266, 266, 433, 433, 434, 434, 434, 434, - 434, 177, 177, 631, 631, 432, 432, 261, 261, 263, - 263, 263, 263, 431, 431, 430, 276, 276, 275, 275, - 274, 274, 274, 268, 268, 268, 268, 268, 268, 270, - 442, 442, 441, 441, 440, 440, 440, 440, 440, 440, - 443, 444, 444, 444, 269, 269, 155, 176, 176, 178, - 291, 290, 439, 438, 438, 438, 438, 305, 305, 304, - 304, 292, 292, 273, 273, 273, 273, 437, 272, 272, - 3, 3, 1, 1, 1, 1, 7, 7, 4, 4, - 4, 2, 2, 2, 5, 5, 6, 6, 435, 739, - 739, 738, 738, 737, 735, 735, 735, 736, 736, 736, - 736, 682, 682, 682, 682, 682, 474, 474, 474, 479, - 479, 477, 477, 477, 477, 477, 483, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 43, 43, 43, - 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, - 52, 53, 57, 160, 160, 163, 163, 161, 161, 162, - 162, 166, 166, 164, 164, 49, 322, 323, 50, 324, - 324, 325, 325, 326, 326, 327, 328, 329, 329, 329, - 329, 531, 531, 48, 313, 313, 314, 314, 315, 315, - 316, 317, 317, 317, 321, 318, 319, 319, 758, 758, - 757, 47, 47, 40, 40, 224, 224, 225, 225, 225, - 227, 227, 398, 398, 398, 226, 226, 228, 228, 228, - 714, 716, 716, 718, 717, 717, 717, 720, 720, 720, - 720, 720, 721, 721, 721, 721, 722, 722, 41, 200, - 200, 200, 237, 237, 210, 725, 725, 725, 724, 724, - 597, 597, 726, 726, 727, 727, 460, 460, 461, 461, - 222, 223, 223, 212, 202, 236, 236, 236, 236, 236, - 238, 238, 342, 342, 201, 207, 208, 209, 211, 213, - 215, 215, 217, 715, 723, 723, 723, 550, 550, 547, - 548, 548, 545, 544, 544, 544, 729, 729, 728, 728, - 728, 475, 475, 42, 540, 540, 542, 543, 543, 543, - 543, 543, 543, 543, 543, 532, 532, 532, 532, 532, - 46, 536, 536, 538, 538, 539, 539, 537, 537, 537, - 537, 537, 537, 537, 537, 537, 537, 537, 537, 537, - 537, 537, 537, 537, 537, 537, 537, 537, 537, 537, - 537, 537, 537, 537, 537, 537, 537, 537, 537, 533, - 533, 535, 535, 529, 529, 530, 530, 530, 530, 530, - 530, 530, 530, 530, 45, 45, 45, 235, 235, 528, - 528, 525, 525, 525, 320, 320, 522, 522, 523, 523, - 520, 520, 520, 526, 526, 54, 55, 56, 527, 527, - 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, - 239, 299, 299, 244, 244, 244, 244, 244, 244, 242, - 242, 242, 242, 243, 243, 240, 240, 241, 241, 229, - 229, 229, 230, 230, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 181, 180, 180, 180, 180, 180, 183, - 183, 459, 459, 458, 458, 182, 399, 399, 51, 353, - 353, 614, 614, 609, 609, 609, 609, 609, 629, 629, - 629, 610, 610, 610, 611, 611, 611, 613, 613, 613, - 612, 612, 612, 612, 612, 628, 628, 630, 630, 630, - 574, 574, 575, 575, 575, 578, 578, 600, 600, 601, - 601, 599, 599, 607, 607, 606, 606, 605, 605, 603, - 603, 604, 602, 602, 602, 602, 594, 594, 593, 593, - 576, 576, 576, 576, 576, 577, 577, 577, 592, 592, - 598, 598, 362, 363, 363, 364, 364, 365, 232, 232, - 233, 233, 366, 367, 367, 368, 368, 369, 370, 370, - 371, 371, 372, 373, 373, 374, 374, 375, 378, 379, - 380, 380, 381, 381, 382, 386, 386, 383, 383, 384, - 384, 385, 376, 376, 377, 377, 360, 360, 361, 361, - 361, 429, 429, 429, 429, 429, 429, 429, 429, 429, - 429, 429, 429, 429, 429, 429, 429, 429, 429, 429, - 429, 429, 429, 429, 429, 429, 429, 429, 429, 429, - 429, 429, 429, 429, 429, 429, 429, 688, 688, 689, - 388, 388, 400, 400, 400, 400, 400, 400, 387, 387, - 389, 389, 341, 341, 339, 339, 331, 331, 331, 331, - 331, 331, 234, 234, 234, 330, 330, 330, 330, 330, - 330, 332, 332, 333, 333, 334, 334, 334, 338, 338, - 337, 337, 337, 337, 337, 335, 335, 336, 336, 336, - 336, 336, 336, 559, 559, 685, 685, 686, 686, 681, - 681, 681, 684, 684, 684, 684, 684, 684, 684, 684, - 684, 684, 684, 687, 687, 687, 683, 683, 343, 453, - 453, 453, 476, 476, 476, 476, 478, 452, 452, 452, - 359, 359, 358, 358, 356, 356, 356, 356, 356, 356, - 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, - 356, 356, 356, 356, 356, 356, 356, 356, 356, 356, - 560, 560, 560, 558, 558, 558, 492, 492, 493, 493, - 411, 410, 410, 410, 410, 410, 408, 409, 407, 407, - 407, 407, 407, 404, 404, 403, 403, 403, 405, 405, - 405, 405, 405, 405, 534, 534, 401, 401, 391, 391, - 391, 390, 390, 390, 608, 499, 499, 499, 499, 499, - 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, - 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, - 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, - 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, - 501, 406, 406, 406, 450, 450, 450, 450, 450, 450, - 450, 450, 450, 450, 450, 450, 450, 450, 450, 451, - 451, 451, 451, 451, 451, 451, 451, 502, 502, 508, - 508, 698, 698, 697, 344, 344, 344, 345, 345, 345, - 345, 345, 345, 345, 345, 345, 345, 345, 354, 354, - 354, 588, 588, 588, 588, 588, 589, 589, 589, 589, - 589, 590, 590, 590, 586, 586, 587, 587, 513, 514, - 514, 635, 635, 636, 636, 579, 579, 580, 580, 581, - 585, 585, 583, 583, 584, 584, 582, 449, 449, 449, - 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, - 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, - 449, 449, 449, 449, 449, 649, 649, 649, 446, 446, - 446, 446, 446, 446, 446, 446, 446, 446, 446, 446, - 446, 446, 446, 446, 446, 446, 708, 708, 708, 693, - 693, 693, 694, 694, 694, 694, 694, 694, 694, 694, - 694, 694, 694, 694, 695, 695, 695, 695, 695, 695, - 695, 695, 695, 695, 695, 695, 695, 695, 695, 695, - 695, 696, 696, 696, 696, 448, 448, 448, 448, 448, - 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, - 447, 447, 447, 447, 447, 447, 447, 447, 515, 515, - 516, 516, 646, 646, 646, 646, 646, 646, 647, 647, - 648, 648, 648, 648, 634, 634, 634, 634, 634, 634, - 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, - 634, 634, 634, 634, 634, 634, 634, 634, 634, 634, - 634, 634, 634, 634, 634, 634, 500, 445, 445, 445, - 517, 509, 509, 510, 510, 511, 511, 503, 503, 503, - 503, 503, 504, 504, 506, 506, 506, 506, 506, 506, - 506, 506, 506, 506, 506, 506, 506, 506, 506, 498, - 498, 498, 498, 498, 498, 498, 498, 498, 498, 498, - 498, 498, 498, 498, 498, 498, 505, 505, 768, 768, - 507, 507, 519, 519, 519, 518, 518, 518, 518, 518, - 518, 518, 357, 357, 357, 357, 497, 497, 497, 496, - 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, - 496, 346, 346, 346, 346, 346, 350, 350, 352, 352, - 352, 352, 352, 352, 352, 352, 352, 352, 352, 352, - 352, 352, 351, 351, 351, 351, 351, 351, 349, 349, - 349, 349, 349, 347, 347, 347, 347, 347, 347, 347, - 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, - 347, 347, 347, 347, 347, 347, 347, 347, 152, 153, - 248, 248, 154, 154, 348, 355, 355, 355, 355, 355, - 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, - 355, 355, 355, 455, 455, 615, 615, 618, 618, 616, - 616, 617, 619, 619, 619, 620, 620, 620, 621, 621, - 621, 625, 625, 464, 464, 464, 472, 472, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 471, - 471, 471, 471, 471, 471, 471, 471, 471, 471, 470, - 470, 470, 470, 470, 470, 470, 470, 470, 469, 469, - 469, 469, 469, 469, 469, 469, 469, 469, 469, 469, - 469, 469, 469, 469, 469, 469, 469, 469, 469, 469, - 469, 469, 469, 469, 469, 469, 469, 469, 469, 469, - 469, 469, 469, 469, 469, 469, 469, 469, 469, 469, - 469, 469, 469, 469, 469, 469, 469, 469, 469, 469, - 469, 469, 469, 766, 766, 767, 767, 412, 412, 759, - 759, -} - -var yyR2 = [...]int{ - 0, 1, 1, 1, 3, 3, 1, 3, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, - 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, - 8, 0, 2, 0, 2, 12, 1, 3, 0, 3, - 3, 3, 5, 0, 1, 1, 1, 1, 2, 4, - 5, 6, 1, 2, 1, 2, 3, 7, 6, 5, - 10, 10, 11, 11, 12, 8, 13, 1, 5, 6, - 8, 5, 3, 5, 8, 1, 3, 3, 5, 5, - 5, 1, 1, 0, 3, 5, 7, 9, 9, 11, - 8, 6, 4, 0, 1, 1, 0, 1, 5, 2, - 2, 6, 9, 6, 9, 4, 7, 8, 0, 1, - 1, 2, 4, 6, 1, 2, 4, 0, 2, 10, - 11, 5, 7, 5, 2, 0, 2, 1, 3, 3, - 3, 0, 2, 0, 2, 1, 3, 5, 0, 2, - 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, - 1, 1, 1, 0, 3, 3, 0, 3, 3, 0, - 1, 3, 0, 1, 3, 0, 2, 1, 2, 3, - 4, 3, 3, 1, 0, 1, 1, 0, 1, 8, - 5, 7, 0, 3, 8, 5, 1, 3, 3, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, - 4, 1, 3, 1, 2, 2, 2, 2, 2, 2, - 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, - 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, - 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, - 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, - 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 6, 3, 4, 4, 5, 1, 3, 3, 1, - 2, 2, 2, 1, 2, 2, 3, 4, 4, 6, - 1, 1, 1, 2, 4, 6, 1, 4, 1, 3, - 3, 4, 4, 4, 4, 3, 3, 2, 4, 4, - 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, - 1, 3, 1, 1, 1, 1, 1, 1, 2, 3, - 3, 4, 5, 4, 2, 2, 0, 1, 4, 2, - 4, 1, 5, 3, 2, 1, 2, 2, 4, 4, - 5, 2, 1, 3, 4, 4, 1, 2, 10, 8, - 10, 1, 3, 3, 1, 1, 3, 1, 3, 2, - 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 1, 1, 1, 1, 4, - 4, 4, 3, 2, 4, 3, 3, 1, 1, 1, - 1, 1, 1, 2, 3, 4, 7, 1, 5, 5, - 6, 6, 6, 6, 2, 3, 3, 4, 3, 4, - 4, 5, 3, 4, 4, 5, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 3, 2, 1, 1, 1, 1, 1, 4, 0, - 1, 1, 3, 1, 4, 4, 0, 1, 2, 4, - 0, 3, 4, 1, 1, 0, 3, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 6, 8, 6, 8, 5, 5, 10, 7, - 4, 4, 4, 3, 1, 3, 3, 5, 5, 5, - 5, 5, 1, 3, 1, 6, 7, 4, 4, 7, - 8, 6, 6, 8, 6, 11, 10, 3, 3, 3, - 1, 1, 1, 3, 2, 4, 5, 5, 6, 5, - 5, 3, 2, 2, 1, 3, 4, 3, 7, 5, - 8, 2, 2, 1, 3, 2, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 1, 0, 1, 2, 1, 3, - 2, 1, 2, 2, 1, 2, 3, 2, 2, 2, - 3, 5, 3, 3, 1, 1, 3, 3, 7, 4, - 3, 1, 2, 4, 5, 3, 4, 7, 7, 8, - 8, 0, 4, 7, 6, 6, 0, 3, 0, 2, - 0, 1, 1, 1, 1, 4, 2, 2, 3, 3, - 4, 5, 3, 4, 4, 2, 2, 2, 3, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 2, 5, 0, 2, 0, - 2, 5, 7, 8, 5, 5, 7, 9, 8, 8, - 11, 5, 1, 3, 3, 3, 5, 4, 3, 3, - 3, 4, 5, 6, 5, 2, 5, 6, 5, 0, - 2, 7, 0, 1, 0, 1, 5, 5, 3, 3, - 2, 4, 4, 4, 4, 4, 1, 1, 1, 3, - 3, 1, 1, 1, 6, 0, 1, 1, 1, 1, - 5, 5, 0, 1, 1, 3, 6, 3, 6, 3, - 4, 7, 7, 5, 4, 7, 8, 3, 3, 4, - 2, 3, 4, 4, 3, 0, 2, 2, 0, 2, - 2, 1, 1, 1, 1, 0, 1, 5, 5, 6, - 4, 3, 1, 3, 1, 1, 3, 5, 2, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 4, 5, 5, 4, 4, 4, 1, 3, 1, - 4, 6, 6, 5, 4, 4, 3, 7, 3, 5, - 1, 1, 2, 2, 12, 9, 10, 1, 3, 2, - 4, 0, 2, 0, 1, 1, 1, 1, 0, 1, - 0, 1, 0, 1, 1, 6, 2, 1, 5, 4, - 4, 2, 1, 2, 1, 2, 4, 5, 5, 1, - 2, 4, 0, 2, 1, 2, 2, 6, 5, 9, - 6, 6, 6, 7, 0, 2, 1, 2, 8, 10, - 1, 2, 7, 5, 13, 13, 10, 10, 1, 0, - 2, 1, 3, 2, 1, 5, 4, 4, 2, 0, - 1, 5, 4, 0, 1, 3, 3, 1, 3, 1, - 3, 5, 1, 3, 3, 5, 1, 3, 4, 0, - 1, 0, 1, 1, 3, 1, 1, 0, 4, 0, - 4, 4, 3, 5, 1, 3, 2, 1, 0, 10, - 2, 0, 2, 0, 2, 0, 4, 7, 4, 0, - 2, 0, 2, 0, 2, 0, 4, 1, 3, 3, - 1, 1, 1, 1, 4, 7, 4, 6, 4, 5, - 6, 8, 4, 6, 5, 6, 0, 1, 4, 8, - 0, 6, 0, 4, 0, 4, 6, 1, 1, 1, - 1, 1, 2, 3, 1, 3, 6, 0, 3, 0, - 1, 0, 1, 1, 2, 4, 4, 2, 0, 5, - 0, 1, 0, 5, 3, 1, 3, 3, 0, 1, - 1, 0, 2, 2, 0, 2, 2, 4, 3, 3, - 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, - 3, 5, 1, 3, 2, 1, 1, 1, 2, 5, - 1, 3, 2, 1, 1, 1, 1, 1, 2, 2, - 1, 2, 2, 1, 2, 2, 1, 2, 2, 9, - 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 2, 0, 4, 7, 6, - 6, 3, 5, 0, 2, 0, 2, 1, 3, 1, - 2, 3, 5, 0, 1, 2, 1, 3, 1, 4, - 1, 1, 1, 4, 4, 4, 3, 4, 5, 3, - 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, - 2, 2, 3, 4, 0, 2, 4, 1, 3, 4, - 1, 3, 1, 1, 2, 2, 3, 0, 1, 2, - 4, 1, 3, 1, 3, 2, 3, 1, 10, 4, - 1, 3, 3, 5, 5, 7, 0, 1, 1, 1, - 2, 0, 4, 4, 0, 3, 0, 3, 3, 0, - 1, 1, 2, 5, 2, 2, 2, 0, 2, 3, - 3, 0, 1, 3, 1, 3, 0, 1, 2, 1, - 1, 0, 1, 2, 1, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 6, 6, 10, 0, 3, 0, 2, 0, 4, 1, - 1, 0, 2, 0, 2, 7, 1, 1, 9, 1, - 3, 0, 1, 1, 3, 1, 3, 0, 1, 1, - 1, 0, 2, 14, 1, 3, 0, 1, 1, 3, - 1, 1, 2, 4, 1, 1, 1, 1, 0, 1, - 2, 9, 9, 7, 8, 1, 2, 3, 3, 3, - 0, 4, 1, 1, 1, 1, 1, 0, 1, 1, - 1, 1, 1, 4, 1, 1, 1, 3, 3, 4, - 3, 3, 0, 1, 1, 1, 0, 2, 7, 8, - 10, 8, 2, 2, 8, 0, 3, 3, 0, 3, - 0, 3, 0, 3, 0, 5, 1, 3, 0, 3, - 3, 0, 2, 9, 8, 0, 2, 2, 3, 3, - 0, 2, 0, 2, 4, 5, 4, 4, 4, 6, - 4, 8, 5, 1, 0, 2, 2, 1, 3, 2, - 1, 3, 2, 1, 3, 2, 0, 1, 3, 4, - 3, 1, 1, 4, 1, 3, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, - 11, 0, 2, 0, 2, 1, 1, 3, 3, 2, - 2, 3, 1, 1, 3, 3, 3, 3, 3, 3, - 4, 2, 2, 3, 3, 3, 3, 3, 3, 3, - 3, 1, 1, 1, 3, 3, 3, 3, 3, 1, - 3, 3, 4, 0, 1, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 6, 8, 10, 0, 4, 1, - 1, 0, 3, 3, 0, 1, 0, 1, 1, 2, - 4, 4, 4, 0, 1, 4, 4, 4, 0, 2, - 8, 9, 5, 5, 8, 7, 8, 12, 12, 13, - 13, 0, 4, 0, 3, 3, 3, 2, 2, 0, - 3, 3, 3, 4, 4, 0, 3, 0, 2, 0, - 1, 1, 1, 1, 11, 9, 9, 9, 9, 9, - 9, 6, 11, 6, 9, 7, 10, 8, 11, 7, - 6, 9, 11, 2, 2, 9, 4, 5, 3, 0, - 4, 1, 3, 0, 3, 6, 0, 2, 10, 0, - 2, 0, 2, 0, 3, 2, 4, 3, 0, 2, - 1, 0, 2, 3, 0, 2, 3, 0, 2, 1, - 0, 3, 2, 4, 3, 0, 1, 0, 1, 1, - 0, 6, 0, 3, 5, 0, 4, 0, 3, 1, - 3, 4, 5, 0, 3, 1, 3, 2, 3, 1, - 2, 1, 0, 4, 6, 5, 0, 2, 0, 2, - 4, 5, 4, 5, 1, 5, 6, 5, 0, 3, - 0, 1, 4, 0, 4, 1, 3, 3, 1, 1, - 1, 1, 4, 0, 4, 1, 3, 3, 1, 1, - 1, 1, 4, 0, 4, 1, 3, 3, 4, 4, - 0, 4, 1, 3, 3, 1, 1, 0, 4, 1, - 3, 3, 1, 1, 1, 1, 0, 1, 1, 3, - 2, 3, 3, 3, 3, 4, 4, 3, 3, 3, - 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, - 3, 3, 3, 3, 1, 5, 4, 1, 3, 3, - 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 3, 5, 0, 3, 3, 6, - 5, 3, 1, 1, 1, 0, 5, 5, 5, 5, - 6, 0, 1, 1, 3, 1, 1, 1, 1, 1, - 7, 9, 7, 7, 9, 2, 1, 7, 9, 7, - 9, 8, 5, 0, 1, 0, 1, 1, 1, 1, - 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 0, 1, 3, 1, - 3, 5, 1, 1, 1, 1, 1, 1, 3, 5, - 0, 1, 1, 2, 1, 2, 2, 2, 1, 1, - 2, 2, 2, 2, 2, 3, 3, 2, 2, 1, - 5, 6, 4, 2, 1, 1, 1, 5, 7, 5, - 0, 1, 1, 1, 2, 2, 0, 1, 1, 2, - 5, 0, 1, 1, 2, 2, 3, 3, 1, 1, - 2, 2, 2, 0, 1, 2, 2, 2, 0, 4, - 7, 3, 3, 3, 0, 3, 0, 3, 1, 1, - 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, - 1, 1, 1, 3, 3, 5, 2, 2, 2, 2, - 2, 4, 1, 1, 2, 5, 6, 10, 8, 6, - 3, 6, 6, 1, 1, 1, 1, 1, 1, 3, - 9, 1, 1, 1, 4, 4, 4, 4, 5, 4, - 6, 8, 10, 6, 8, 10, 6, 6, 9, 7, - 9, 7, 7, 7, 9, 7, 7, 0, 2, 0, - 1, 1, 2, 4, 1, 2, 2, 1, 1, 2, - 2, 5, 1, 2, 2, 2, 2, 2, 0, 1, - 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 1, 1, 1, 2, 5, 0, 1, 3, 0, - 1, 0, 2, 0, 2, 0, 1, 2, 4, 4, - 0, 1, 0, 2, 1, 3, 5, 9, 6, 6, - 8, 6, 6, 5, 5, 6, 6, 6, 6, 6, - 5, 6, 6, 6, 6, 6, 6, 6, 6, 9, - 6, 6, 6, 6, 8, 1, 1, 1, 4, 6, - 4, 6, 8, 6, 6, 4, 6, 4, 4, 4, - 3, 4, 6, 6, 7, 4, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 2, 2, 8, 8, 6, - 4, 2, 3, 2, 4, 2, 2, 4, 6, 2, - 2, 4, 6, 4, 2, 4, 4, 4, 0, 1, - 2, 3, 1, 1, 1, 1, 1, 1, 0, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 3, 0, 1, 1, - 3, 0, 1, 1, 3, 1, 3, 3, 3, 3, - 2, 1, 1, 1, 3, 4, 4, 3, 4, 4, - 3, 4, 4, 3, 4, 4, 3, 4, 1, 3, - 4, 4, 6, 4, 5, 5, 4, 5, 5, 3, - 4, 4, 5, 6, 6, 1, 0, 2, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, - 2, 3, 1, 1, 1, 4, 2, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 3, 2, 2, 2, 2, 1, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, - 2, 1, 1, 1, 2, 1, 1, 1, 1, 2, - 2, 2, 2, 2, 2, 4, 4, 1, 2, 2, - 7, 8, 3, 5, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 0, 1, 0, 3, 0, - 3, 3, 0, 3, 5, 0, 3, 5, 0, 1, - 1, 0, 1, 1, 2, 2, 0, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 2, 0, 2, 5, 7, 1, - 3, -} - -var yyChk = [...]int{ - -1000, -756, -760, -12, -8, -9, -11, -154, -117, 732, - -14, -23, -156, -142, -157, -15, -151, -17, -18, -19, - -213, -21, -124, -146, -148, -150, -149, -62, -20, -143, - -144, -145, -102, -103, -127, -135, -138, -139, -140, -141, - -158, -152, -153, -155, -245, -159, -168, -169, -220, -172, - -174, -175, -208, -209, -239, 721, -118, -119, -120, -121, - -122, -123, -43, -42, -41, -40, -200, -210, -214, -216, - -170, -57, 637, 727, 766, 538, -16, -699, -638, 591, - -24, -25, -112, -26, 278, 305, -480, -125, -481, -482, - -484, -761, -63, -64, -65, -78, -79, -80, -81, -82, - -92, -93, -94, -66, -67, -68, -71, -69, -85, -84, - -86, -87, -88, -89, -90, -91, -70, -74, -203, -204, - -205, -206, -95, -72, -73, -218, -221, -171, -96, -97, - -98, -75, -60, -61, -76, -77, -100, -99, -105, -111, - -101, -106, -202, -212, -22, -219, -107, -59, -109, -110, - -108, 279, 350, 298, -104, 86, -128, -129, -130, -131, - -132, -133, -134, -136, -137, 463, 469, 525, 719, 720, - 71, -247, -249, -251, 768, 769, 772, 622, 624, 323, - 186, 187, 189, 190, 194, 197, -44, -45, -46, -47, - -48, -49, -51, -50, -52, -53, -54, -55, -56, 274, - 22, 20, 24, 64, -27, -30, -28, -31, -29, -38, - -39, -37, -32, -34, -201, -207, -33, -211, -215, -217, - -173, -58, -35, -36, 300, 299, 47, 366, 367, 368, - 467, 275, 277, 23, 40, 51, 442, -250, -254, 96, - -257, -253, 623, 276, -252, -256, 21, 284, 786, -13, - -10, -9, -187, -191, -195, -198, -199, -196, -197, -11, - -154, 131, 290, 722, -476, 459, 723, 725, 724, 99, - 107, -469, -471, 766, 538, 305, 463, 469, 719, 720, - 769, 772, 622, 624, 323, 639, 640, 641, 642, 643, - 644, 645, 646, 648, 649, 650, 651, 652, 653, 654, - 697, 698, 664, 665, 655, 656, 657, 658, 659, 660, - 661, 662, 666, 667, 668, 669, 670, 671, 672, 673, - 674, 675, 676, 677, 678, 679, 594, 595, 699, 701, - 702, 703, 704, 647, 684, 692, 693, 694, 777, 778, - 440, 6, 7, 8, 9, 10, 441, 630, 716, 775, - 317, 341, 492, 347, 354, 421, 186, 204, 200, 229, - 219, 427, 373, 745, 746, 372, 623, 195, 321, 359, - 322, 106, 189, 577, 121, 550, 521, 192, 379, 382, - 380, 381, 336, 338, 340, 453, 343, 342, 344, 346, - 621, 377, 443, 215, 209, 335, 319, 207, 324, 428, - 49, 325, 419, 418, 234, 326, 327, 634, 546, 439, - 552, 351, 62, 519, 208, 339, 549, 715, 242, 246, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, - 568, 425, 406, 407, 408, 409, 569, 430, 177, 178, - 554, 744, 751, 752, 753, 755, 756, 757, 754, 424, - 571, 429, 233, 236, 237, 238, 239, 240, 241, 297, - 415, 416, 431, 432, 433, 434, 435, 437, 438, 52, - 632, 309, 572, 244, 762, 223, 232, 227, 580, 355, - 353, 420, 231, 203, 226, 320, 784, 767, 75, 248, - 247, 249, 515, 516, 517, 518, 328, 329, 457, 567, - 747, 748, 222, 210, 444, 196, 31, 575, 304, 551, - 470, 383, 57, 384, 330, 348, 356, 378, 243, 245, - 311, 316, 371, 426, 633, 523, 524, 315, 559, 560, - 352, 573, 206, 308, 337, 303, 576, 763, 749, 197, - 783, 472, 331, 190, 345, 570, 765, 579, 74, 172, - 202, 193, 739, 740, 294, 700, 187, 313, 318, 717, - 764, 332, 333, 334, 358, 357, 349, 194, 224, 310, - 230, 213, 201, 225, 188, 312, 578, 173, 713, 442, - 502, 221, 218, 314, 287, 718, 574, 553, 191, 506, - 175, 216, 360, 707, 708, 709, 712, 458, 414, 361, - 362, 214, 301, 544, 545, 365, 512, 401, 486, 522, - 493, 487, 265, 266, 369, 556, 558, 235, 710, 385, - 386, 387, 548, 388, 389, 390, 391, 396, 462, 66, - 68, 108, 111, 110, 770, 771, 73, 38, 448, 451, - 484, 785, 488, 403, 714, 631, 400, 404, 405, 452, - 34, 504, 474, 508, 507, 58, 59, 60, 63, 64, - 65, 67, 69, 70, 61, 620, 467, 481, 581, 54, - 56, 477, 478, 36, 454, 503, 526, 399, 505, 537, - 55, 535, 536, 557, 35, 456, 455, 72, 53, 511, - 513, 514, 363, 397, 465, 728, 582, 460, 476, 480, - 461, 402, 450, 482, 77, 473, 729, 468, 466, 779, - 780, 398, 635, 636, 410, 663, 445, 520, 617, 616, - 615, 614, 613, 612, 611, 610, 366, 367, 368, 489, - 490, 491, 501, 494, 495, 496, 497, 498, 499, 500, - 540, 541, 730, 731, 561, 563, 564, 628, 565, 562, - 282, 774, 773, 446, 447, 285, 733, 734, 109, 735, - 737, 736, 37, 738, 761, 758, 759, 760, 638, 566, - 625, 741, 627, 626, 685, 686, 687, 688, 689, -565, - -563, -476, 623, 323, 766, 719, 720, 469, 622, 624, - 463, 442, 769, 772, 64, 467, 305, 366, 367, 368, - 538, 440, -324, -476, 284, 773, -104, -25, -24, -16, - -638, -112, -250, -251, -765, 271, 273, 478, -339, 284, - -476, -485, 32, 519, 279, 280, -126, 520, 96, 87, - -476, -17, -140, -15, -151, -102, -245, -699, 525, -483, - -476, 366, 366, 628, -483, 284, 284, 743, 524, 565, - 628, 744, 751, 762, 560, 453, 110, 111, 739, 740, - 36, 284, 464, 311, 558, 556, 557, 561, 562, 563, - 564, -83, -650, -626, 553, 644, 552, -489, 545, 551, - 543, 555, 546, 441, 391, 388, 637, 390, 395, 274, - 733, 619, -464, 486, 522, 581, 582, 465, 523, 568, - 570, 547, 121, 220, 217, -478, 315, 500, -476, -627, - 290, -569, -540, 316, -568, -542, -571, -543, 41, 274, - 276, 275, 637, 312, 24, 467, 286, 22, 21, 468, - 298, 34, 35, 37, 23, 469, 471, 38, 472, 475, - 476, 477, 51, 481, 482, 305, 99, 107, 102, 685, - 686, 687, 688, 689, 323, 284, -323, -476, -511, -503, - 128, -506, -498, -499, -501, -454, -671, -496, 96, 157, - 158, 165, 129, 167, 787, -500, -608, 45, 131, 643, - 647, 684, 592, -446, -447, -448, -449, -450, -451, 629, - -476, -672, -670, 102, 112, 114, 118, 119, 117, 115, - 180, 211, 116, 103, 181, -251, 99, -693, 653, 659, - -470, 676, 701, 702, 703, 704, 675, 71, -634, -648, - 283, -646, 179, 217, 301, 213, 22, 163, 512, 214, - 692, 693, 694, 650, 672, 594, 595, 699, 654, 777, - 778, 664, 679, 645, 646, 648, 640, 641, 642, 644, - 655, 657, 671, -649, 667, 677, 678, 663, 695, 696, - 758, 697, 698, 680, 681, 682, 691, 690, 683, 685, - 686, 687, 688, 689, 737, 101, 100, 670, 669, 656, - 651, 652, 658, 639, 649, 660, 668, 673, 674, 451, - 121, 452, 453, 584, 443, 90, 454, 290, 519, 9, - 80, 455, 456, 457, 458, 243, 459, 591, 460, 783, - 81, 461, 450, 305, 502, 462, 216, 235, 597, 596, - 598, 588, 585, 583, 586, 587, 589, 590, 661, 662, - 666, -248, -250, -699, -251, -176, -178, 705, -749, -287, - -750, -436, 31, -751, 12, 13, 14, 15, 181, -740, - 521, 633, 102, 584, 284, 359, 440, 25, 743, 395, - 621, 743, 395, 621, 373, 191, 188, -555, 191, 127, - 197, 196, 288, 191, -555, -476, 194, 743, 193, 739, - 744, 751, 628, 369, -527, -224, 440, 502, 388, 108, - 315, -532, -528, -628, 363, 359, 285, 124, -225, 295, - 436, 294, 122, 584, 283, 479, 354, 66, 68, 41, - 54, -271, 57, 289, 48, -339, -701, 618, -700, -476, - -709, -710, 271, 272, 273, 48, 744, 751, 285, 287, - 284, 739, 628, 315, 440, -528, 502, 108, 388, 284, - -709, 762, 188, 568, 570, 521, 315, 500, 50, -562, - 512, -561, -563, 569, 580, 100, 101, 567, -464, 121, - 544, 544, -749, -436, -750, -282, -436, -281, 17, -247, - -251, -254, -258, -699, -260, 71, 621, 743, 628, 744, - 751, 285, 440, 502, 315, 286, -628, 287, 584, 283, - 366, 464, 311, 388, 395, 108, 193, 739, -264, -265, - -266, 267, 268, 269, 79, 272, 270, 76, 41, 42, - 43, -339, -8, 135, 786, -503, -503, -13, 789, -13, - -503, -476, -476, 183, -346, -350, -347, -349, -348, 775, - -352, -351, 217, 218, 179, 221, 223, 228, 224, 225, - 226, 227, 229, 230, 231, 232, 233, 236, 237, 238, - 239, 240, 241, 234, 40, 235, 301, 213, 214, 215, - 216, -355, 200, 219, 631, 260, 201, 261, 202, 262, - 203, 263, 177, 178, 264, 204, 207, 208, 209, 210, - 206, 242, 243, 244, 245, 246, 247, 248, 249, 251, - 250, 252, 253, 254, 255, 256, 257, 258, 259, 182, - -307, 102, 41, 96, 182, -339, 102, -749, -281, -282, - -287, -271, 25, -339, -330, 182, 787, -452, -476, 521, - 138, 519, -126, 520, 87, 519, -126, 520, 279, -126, - 87, -702, -703, -704, -706, 279, 520, 519, 280, 350, - -149, 182, 323, 25, -483, -483, -476, 93, -308, -309, - -339, -341, -339, -733, -732, 41, 628, -312, 32, 566, - 746, 748, 544, 754, 763, 764, 765, 92, -488, 146, - 150, -488, -432, 26, -432, 32, 32, 313, 313, 313, - -488, 353, -762, -763, 25, 148, -486, -763, -486, -486, - -488, -764, 286, 554, 52, 314, 313, -284, -285, 30, - 96, -284, 548, 544, -591, 549, 550, -490, -763, -489, - -488, -488, -489, -488, -488, 394, -488, 41, 389, 390, - 284, 287, 584, 388, 734, -762, -762, 40, 40, -542, - 315, -569, -540, 45, 92, 183, 288, 183, 92, 96, - 465, 440, 502, 466, 584, 284, 479, 287, 315, 480, - 440, 502, 284, 287, 584, 315, 440, 284, 287, 502, - 315, 480, 440, 543, 544, 287, 36, 470, 473, 474, - 544, -654, 580, -339, 183, 127, 124, 126, -503, 145, - -518, 138, 139, 140, 141, 142, 143, 144, 152, 151, - 164, 157, 158, 159, 160, 161, 162, 163, 153, 154, - 155, 156, 148, 128, 167, 784, 146, 150, 147, 130, - 125, 170, 169, -251, -503, -511, 71, -501, -501, -501, - -501, -501, -476, -608, -508, -503, 96, 96, 96, 96, - 96, 182, 115, 102, 96, -503, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, -647, - 96, 96, -515, -516, 96, 96, -496, -452, 96, 102, - 102, 96, 96, 96, 102, 96, 96, 96, -516, -516, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - -749, -250, -282, 183, 96, -281, -282, -288, 29, -287, - -252, -251, -256, -260, -503, -752, 729, 41, 42, 41, - 42, 41, 42, 41, 42, 96, 112, 770, 265, -297, - -476, -298, -476, -184, 25, 787, -476, 739, -732, 389, - 628, 628, 389, 628, 274, 24, 377, 64, 378, 573, - 20, 195, 196, 197, -476, 194, 288, -476, -525, 290, - -525, -525, 745, 521, -525, -322, -476, 311, 464, 287, - 287, -225, -525, 25, -525, -525, -525, -525, 286, -525, - 284, 284, 284, -525, 591, 138, 138, 69, -640, -643, - -639, -642, 48, 132, -643, -302, 307, -271, -271, -339, - 183, -701, -293, 96, -711, 199, -274, -273, -268, -270, - -435, -437, -272, 96, -339, -251, 5, -476, 745, 521, - -627, -627, -339, -627, -476, 290, -543, -627, 619, -465, - -524, -476, -521, 220, 50, 169, -627, -627, -627, -418, - -419, -339, -712, 289, 765, -746, -745, 571, -748, 573, - 188, -563, 188, -563, 99, -542, 315, 315, 183, 138, - 32, -564, 138, 149, -563, -563, -564, -564, -387, 50, - -475, 179, -476, 102, -387, 50, -743, -742, -339, -282, - -252, -251, -256, -260, -286, -285, -287, -255, -252, -256, - -251, 71, 29, 97, 97, -282, -282, -436, -176, 628, - -627, -627, 745, 521, -627, -627, -627, -627, -627, 284, - -627, -627, -627, -483, -627, -324, 290, -627, 389, -627, - -627, -627, -261, -263, 159, -503, -476, -266, -10, -189, - -188, 132, 133, 135, 723, 459, 722, 726, 719, -563, - 50, -621, 173, 172, 96, -615, -617, 96, -616, 96, - -616, -616, -616, 218, 221, -615, -615, -616, -616, -616, - -616, -616, -616, 96, 96, -618, 96, -618, -618, -615, - -619, 212, 96, -619, -620, 96, -620, -619, -476, -595, - 20, -509, -511, -476, 288, 48, -282, -179, -287, 48, - -285, -288, -294, 307, 108, -331, 750, -476, 214, 193, - 738, 44, 182, 112, 102, -707, 233, 224, 138, -126, - 87, -149, 138, -126, -126, -149, 97, 183, -705, 118, - 119, -707, 102, -476, -147, 102, -670, -14, -20, -125, - -15, -151, -17, -19, -62, -102, 40, -153, -143, -239, - -245, -480, 298, 622, 624, -673, -671, -310, 183, 438, - 96, -311, 183, 546, 32, -476, -284, 633, -165, 32, - -488, 25, 148, -488, -488, 25, 148, -488, 315, -432, - -501, -501, -503, 440, 584, 284, -544, 597, 315, -475, - -762, -488, -488, -466, -465, -490, -485, -490, -490, -432, - -486, -488, -488, -503, 159, -490, -486, -432, -476, 544, - -432, -432, -591, -465, -488, 102, -487, -476, -487, -525, - -465, -466, -466, 41, 511, 92, 25, -570, 284, 584, - 464, 311, 287, 440, -568, -549, -546, -544, -542, -545, - -544, -573, -452, 544, -180, 527, 526, 365, 25, -503, - -503, -503, -503, 117, 128, 167, 414, 118, 119, -498, - -519, 41, 361, 362, -499, -499, -499, -499, -499, -499, - -499, -499, -499, -499, -499, -499, -501, -501, -507, -517, - -608, 96, 148, 146, 150, 147, 130, 148, 146, 150, - 147, 130, -768, 33, -501, -501, -499, -499, -501, -344, - -346, 172, 173, -389, -475, 179, 97, 183, -503, -698, - -697, 132, -503, -503, -503, -503, -533, -535, -452, 96, - -476, -499, -694, -695, 599, 600, 601, 602, 603, 604, - 605, 606, 607, 608, 609, 455, 450, 456, 454, 443, - 462, 457, 458, 216, 616, 617, 610, 611, 612, 613, - 614, 615, -509, -509, -503, -694, -499, -509, -445, 42, - 41, -511, -511, -511, 97, -503, -708, 412, 411, 413, - -453, -476, -509, 97, 97, 97, 112, -511, -511, -509, - -499, -509, -509, -509, -509, -695, -695, -696, 301, 213, - 215, 214, -445, -503, -503, -445, -445, -445, 159, -511, - -511, -445, -445, -445, -445, 159, -445, -445, -445, -445, - -445, -445, -445, -445, 97, -445, -445, -445, -445, -445, - 97, 97, 97, 97, -503, 97, -503, -503, -503, -503, - -503, 159, -511, -282, -749, -286, -178, -652, -651, -503, - 50, -179, -287, -285, -179, 680, -288, -753, 731, 96, - -452, -741, 102, 102, 787, -184, 25, 182, 284, -184, - 182, 739, 193, -184, 584, 25, -476, 102, 112, -476, - 102, 112, 284, 584, 284, 584, -339, -339, -339, 574, - 575, 192, 196, 195, -476, 194, -476, -476, 128, 167, - -476, -476, -525, -525, -476, 44, -324, -313, -476, -525, - -525, -716, -476, 103, 102, -550, -547, -544, -476, -476, - -540, -476, -465, -525, -525, -525, -339, -398, 63, 64, - 65, -544, -226, 66, 67, -245, -639, -641, -642, 134, - -339, -503, -641, -637, 71, -245, 96, 40, 96, -302, - -302, -700, 44, -292, -476, -712, 93, -438, -439, -440, - -441, -443, -444, -442, 78, 82, 84, 88, 79, 80, - 81, 547, 85, 90, 779, 83, -474, -479, 44, -476, - 102, -474, -251, -276, -275, -274, 787, -474, 96, 96, - -476, -476, -339, -339, -412, -420, -417, -413, 281, -421, - 307, 275, 448, 449, 277, 17, 276, -429, 354, -526, - 592, -393, -394, 87, 51, -396, 305, 488, 484, 785, - 317, 321, 106, 322, 521, 323, 286, 325, 326, 327, - 342, 344, 297, 328, 329, 330, 512, 331, 187, 343, - 332, 333, 334, 466, -388, 12, 396, 50, 61, 62, - 536, 535, 635, 20, 318, -476, 491, 624, 40, 45, - 277, 281, 276, -716, -714, 40, -476, -524, 40, -521, - 40, 220, 169, -472, 138, -550, -544, -476, -476, 183, - 288, -274, -276, -563, 183, 572, 574, 575, -746, -564, - -746, -564, 288, 41, 511, -567, 511, 41, -540, -561, - 568, 570, -556, 102, 512, -545, -566, 92, 179, -651, - -564, -564, -566, -566, 169, 183, -744, 573, 574, 271, - -286, -176, -280, -279, -503, -286, -286, -259, -252, -260, - -256, -251, 112, -734, -732, -476, 628, -476, -627, -627, - -341, -716, -549, -540, -476, -627, -341, -478, -478, -313, - 45, -476, -627, -476, -476, -476, -179, 183, -477, -476, - 44, 102, 182, -190, -188, 134, -503, -13, 722, -503, - -13, -13, -503, -13, -503, -625, 175, -346, 112, 112, - -455, 102, -455, 112, -619, 112, 112, 638, 97, 102, - 102, -286, -288, 706, -674, -670, -288, -179, -644, 71, - -245, 96, 40, 96, -627, 193, 214, 749, -330, 138, - 138, 138, 33, -476, 32, -126, -126, -707, 102, -149, - -707, 102, -126, -703, 182, -562, 519, 520, 183, -309, - -292, -339, 637, 112, -167, 30, -476, -432, -476, 745, - -432, -432, -476, 745, 747, -432, -543, -476, -476, -476, - -541, 93, -647, -476, 790, 100, -466, -432, -432, -490, - -432, -432, 183, 31, 97, -488, -490, -490, -330, -486, - -330, 182, -330, -465, -570, -548, -545, -572, 159, -476, - -557, 183, 20, 288, -729, -728, 503, 97, 183, -655, - 289, 591, 102, 787, 519, 265, 266, 102, 117, 414, - 118, 119, 117, 414, 118, 119, -608, -511, -507, -501, - -501, -499, -499, -507, -501, -501, -499, -499, 96, -505, - 302, -505, 127, -354, 178, 177, -354, -503, 788, -502, - -697, 134, -503, 44, 183, 44, 183, 93, 183, 97, - -615, -503, 182, 183, 97, 97, 25, 25, 148, 97, - -503, 97, 97, 97, 97, 25, 25, -503, 97, 182, - 97, 97, 97, 97, 93, 97, 183, 97, 97, 97, - 97, 183, 183, 183, -511, 97, 97, -511, -503, -511, - 97, 97, 97, -503, -503, -503, -511, 97, -503, -503, - -503, -503, -503, -503, -503, -503, 776, -503, -503, -511, - -503, -503, -580, 539, -580, -580, -580, 97, -580, 97, - 183, 97, 183, 97, 97, 183, 183, 183, -286, -282, - 183, 97, -288, -288, 20, -179, -754, 730, 96, 112, - 183, 771, -459, -458, 102, -186, 288, 193, 739, -476, - -476, -186, -476, -476, 138, -186, -476, 739, 102, 102, - -339, -465, -339, -465, 630, 48, 48, 193, 197, 197, - 196, -476, 102, 45, 45, 32, 32, 352, -476, -476, - -160, 625, -323, 96, 96, 182, -339, -339, -718, 489, - -476, -730, 183, 50, -728, 584, -222, 365, -529, -530, - 93, -235, 372, 25, -339, -339, -339, -353, 44, -245, - -640, 71, 96, 133, -245, -554, -553, 92, -645, -512, - -692, 705, -301, 97, -289, -476, -690, -691, -289, -295, - -303, -476, -637, -637, 96, 97, 183, 25, -267, -340, - -476, -274, -273, -273, -273, -273, -273, -273, -273, 78, - 89, 78, -290, 96, 78, 83, 78, 83, 78, 83, - 78, -440, 78, 78, 80, 89, -293, -479, 183, 97, - 99, -739, -738, -737, -735, 86, 289, 87, -503, -509, - 40, 40, 62, 61, -614, 44, -293, 183, 307, -338, - -473, -335, -337, 292, -493, -336, 295, 436, -686, 293, - 291, 122, 296, 350, 123, 286, 29, 417, -473, -415, - 286, 350, 293, -473, -473, 292, -397, 288, 44, 29, - 307, -414, 286, 123, -476, 292, 296, 293, 350, 291, - -472, -464, 169, 288, 52, 466, -472, 636, 307, -472, - -472, -472, -472, -472, -472, -472, -472, 324, 324, -472, - -472, -472, -472, -472, -472, -472, -472, -472, -472, -472, - 188, -472, -472, -472, -472, -472, -472, 96, 319, 320, - 352, 625, 132, 638, 627, -543, 288, 559, 559, -719, - 489, 40, 446, 446, 447, -472, 40, -472, -389, -730, - 442, 51, 40, -236, 440, -419, -416, -487, 40, 40, - -564, -745, -747, 576, 573, 579, -566, -566, 112, 288, - 96, 138, -566, -566, 50, -475, -742, 580, 574, -288, - 183, -277, 46, 47, 97, 97, -320, 741, -476, -476, - 92, -341, -630, 345, 346, 96, -324, 102, 25, -320, - -431, -430, 25, -263, -476, 102, -476, 159, 135, -13, - 133, -194, -193, -192, 136, 719, 726, 135, 135, 135, - 97, 97, 97, 97, 183, 97, 97, 97, 183, 97, - 183, 112, 767, -658, 549, -288, -179, 102, 183, -179, - -262, 774, -645, -301, 97, -690, -295, -476, 102, 112, - 102, 44, -234, 99, 107, 102, -331, -503, -476, 102, - -503, 214, 182, 521, -126, -126, -126, -126, -476, 138, - -671, 97, 112, -488, -476, -488, 182, -476, -231, -233, - -476, 102, -476, -540, -541, -475, -488, -432, -503, -503, - 553, 552, -432, -488, -488, -490, -476, -330, -572, 183, - 288, 182, 182, -546, 469, -548, 29, 20, -452, 48, - -459, 138, 787, -476, 97, -505, -505, 127, -505, -505, - 127, -501, -501, -498, 97, 135, -503, 133, -344, 217, - -503, -344, -345, -351, 233, 179, 217, 301, 216, 215, - 213, 172, 173, -387, -535, 630, -277, 97, -476, -511, - -503, -503, -499, 97, -503, -503, 25, -476, -387, -499, - -503, -503, -503, -282, -283, 776, -283, -282, 97, 97, - -579, -580, -579, -283, 97, 97, 97, 97, -579, 97, - 97, 97, 97, 97, 97, 97, 97, 27, 97, 97, - 97, 97, 183, -476, 96, -580, -766, 783, -503, -766, - -503, -766, -766, -503, 112, 114, 112, 114, -288, -286, - -651, -179, -179, 470, 96, 307, 183, 112, 102, 788, - 183, 138, 440, -185, -476, 102, -476, 25, 25, 182, - 102, -476, 102, 25, 284, -476, 25, 25, -339, -339, - -339, 197, 102, -731, 359, 440, 584, 284, 440, 359, - 584, 284, -596, 112, -363, 20, -367, 20, -161, 132, - 102, 477, -325, -326, -327, -328, -329, 148, 184, 185, - -314, -315, -316, -317, -346, -452, 775, 218, 221, 223, - 224, 225, 226, 227, 229, 230, 231, 232, 233, 236, - 237, 238, 239, 240, 241, 234, 235, 301, 213, 214, - 215, 216, 200, 219, 631, 201, 202, 203, 177, 178, - 204, 207, 208, 209, 210, 206, 242, 243, 244, 245, - 246, 247, 248, 249, 251, 250, 252, 253, 254, 255, - 256, 257, 258, 259, -476, -293, -293, -721, 551, 491, - 501, -472, 388, -495, -494, 442, 51, -632, 512, 497, - 498, -547, 315, -465, 159, -727, 109, 138, 92, 400, - 404, 406, 408, 407, 405, 401, 402, 403, -522, -523, - -520, -526, -465, 102, -714, 96, -246, -230, -229, 146, - -235, 372, 25, -245, 71, 289, 591, 96, -362, 327, - 96, -609, 385, -346, 96, -301, -640, -262, 49, 183, - 96, 97, 183, 71, 182, 183, 138, 97, 183, 97, - 183, 138, -262, -262, -553, -8, -476, -339, -267, -476, - 25, 183, -713, 182, 92, -305, -304, 92, 93, -305, - -305, -304, -304, 78, -291, 102, 78, 78, 78, 78, - 83, -275, -274, -737, -736, 32, -686, -686, -686, 183, - 97, -364, 96, -365, -232, -476, 102, -368, 96, -369, - -370, -476, 102, -609, -346, 44, -413, 281, 275, 276, - -600, 96, -343, 96, -452, -336, -685, -686, -685, -525, - -476, 123, -685, 123, 96, -576, 352, 353, -577, -598, - 355, -476, -452, -476, -476, -476, -343, -452, -452, -416, - -424, -423, -452, -427, 41, -428, -476, -476, -476, -476, - 123, -476, -476, 123, -392, 50, 58, 59, 60, -472, - -472, 220, -395, 50, 511, 513, 514, -427, 112, 112, - 112, 112, 112, 102, 102, 102, -472, -472, 112, 102, - -479, 102, -687, 196, 54, 55, 112, 112, 112, 112, - 50, 102, -400, 50, 335, 339, 336, 337, 338, 102, - 112, 50, 112, 50, 112, 50, -476, 96, -688, -689, - 102, -596, 102, 96, 112, 102, 277, -543, 102, 92, - -721, -472, 446, -563, 138, 138, -387, -472, -389, -495, - -723, 106, 492, -723, -726, 365, -238, 584, 41, -296, - 281, 276, -714, -552, -551, -452, -552, -566, 573, 577, - 578, -548, -491, 102, -556, -179, -279, -278, 53, -339, - -630, -314, -476, -432, -276, 182, 131, -13, -190, -192, - -503, -13, -503, 722, 459, 723, 102, 112, 112, 575, - -666, 533, 528, 530, -179, -667, 519, -670, -261, 97, - 71, 97, 33, 788, 788, 788, 788, 102, -476, 112, - 102, -432, -488, -432, -231, -488, -488, 148, -432, -330, - -432, -432, -488, 25, -545, -540, 159, 159, -476, 470, - -557, 102, 490, 102, 284, 788, 102, -459, -498, -498, - 97, -503, 97, -616, 44, 97, 97, -616, -616, -615, - -618, -615, -354, -354, 97, 96, -277, 97, 97, 32, - 97, 97, -579, 97, 97, -503, 182, 97, 97, 183, - 183, 97, -635, 593, -579, 27, -579, -636, 665, -579, - -579, -579, -579, -579, -579, -579, -579, -579, -579, -579, - -579, -579, -579, -579, 96, -579, -579, -579, -579, -503, - -581, -585, -476, -580, 53, 97, 183, -580, 97, 183, - -580, -580, 97, 534, 736, 736, 534, 736, 736, -179, - -288, -511, -755, 73, 728, 72, 511, 117, 355, 97, - -694, 183, -467, 360, -467, -458, 102, -476, 102, 193, - 739, -476, 788, 788, 193, 739, -476, 102, -339, -465, - -299, 550, -242, 132, -243, 130, 52, 102, -476, 25, - -476, -476, 352, -476, 352, -476, -476, 102, 96, 96, - -166, 638, 96, -163, 626, 102, 97, 183, -452, 97, - 183, -346, 44, 44, -722, 106, -717, 102, -476, 103, - -476, -723, 181, 444, 50, 493, 494, 509, 439, 112, - 112, 499, -715, -476, -237, 284, 440, -237, -725, 62, - 138, 102, -339, -520, -464, 169, 326, -330, -476, 388, - -332, -333, -334, -343, -335, -337, -246, 44, -339, -339, - 102, -176, -332, -472, -332, -610, 387, 29, 112, 158, - -511, 97, 123, -512, -653, -652, 71, -245, -289, -645, - -476, -691, -651, -476, -476, -503, -262, 97, -294, 93, - 182, -276, -340, -476, 159, -503, -503, 96, -269, 780, - 97, 78, 788, 96, 78, 17, 27, 102, 183, -364, - 138, 183, -368, 138, -610, -245, -473, -601, -599, 307, - -422, 54, 56, -759, -343, -346, -683, -476, -683, -681, - -683, -476, -681, -681, -525, -503, -593, 356, 96, -591, - 96, -591, 123, 401, 404, 406, 408, 407, 436, 40, - 276, -425, 404, 398, 399, -558, 351, 128, 167, -558, - -422, -343, 288, 183, -277, 183, -476, -387, -387, 40, - 102, 102, -341, 97, 183, 138, 102, -163, -162, -503, - -247, -251, 288, 92, 284, -722, -717, 138, -564, 102, - 102, -387, -723, 102, 102, -727, 138, -342, 284, -465, - 183, -296, -296, -432, 25, 183, 138, -432, 97, -306, - 32, 51, 54, 55, 97, 388, -434, 27, 159, 135, - 133, 135, 135, -476, 97, 97, -622, 707, -662, -664, - 528, 29, 29, -306, -668, 712, 102, 71, -245, -645, - 214, 102, 788, -432, -488, -432, -432, 745, -432, -540, - -557, 512, -339, 183, 788, 220, -344, 220, -406, 102, - 103, -476, -503, 97, -476, -503, -503, 97, 102, 96, - 97, 102, -281, 97, 97, -514, -513, 307, -766, -503, - -766, -503, -767, 25, 97, 183, 97, 97, 97, 183, - 97, 97, -306, -179, 97, 183, 97, -694, -468, 214, - 102, -468, -185, -476, -185, -476, 25, -477, -240, 288, - -330, -244, 383, 96, 379, -242, 193, 96, 102, -476, - 25, -476, -596, 352, -596, 352, 284, -476, -320, -364, - -368, -164, 627, 112, -162, 102, -531, 632, -327, -346, - 282, -316, 50, -246, -246, 102, -720, 503, -597, 393, - 112, 50, 112, 181, 495, -633, -223, 106, -341, 41, - -296, -223, -724, 106, 138, 787, 96, -472, -472, -472, - -240, 388, -476, 97, 183, -246, -241, 60, -476, -282, - 97, 744, 97, -611, 306, 112, 158, 112, 158, 112, - 97, 71, 23, 289, 97, -645, 182, 138, -474, -276, - -476, -432, -713, 182, -113, -114, 132, -292, -500, 181, - -682, -476, 291, 29, 29, 550, -365, 97, -233, -369, - 97, -371, -476, 102, -611, 96, 97, 183, -476, -452, - 97, 183, -359, -358, -356, 117, 128, 167, 50, 484, - -357, 106, 752, 753, 169, 340, 343, 342, 318, 341, - -411, -492, 92, 700, 487, 398, 399, -526, 715, 44, - 291, 122, 123, 471, -493, 96, 96, 96, 93, 360, - 96, 96, -683, 97, -578, 357, 112, -499, 96, -499, - 96, -592, 354, 96, -536, -536, -536, -536, -536, 50, - -425, 50, -426, 423, 351, 351, -422, -452, -423, -476, - 169, -387, 97, -689, 102, 97, -543, 284, -476, -720, - 102, -566, -725, 102, -223, -341, -714, -282, -276, -551, - -651, -262, 23, 74, 148, -476, -433, 28, 29, 290, - -13, 723, 459, -402, 708, 102, 29, 102, -660, 102, - -658, 102, -645, 102, -432, -476, -182, -399, -464, 323, - 40, 97, 40, -405, 148, 20, 97, 97, 97, -283, - -281, -579, 97, -579, -282, 29, -580, 97, -580, 97, - -766, 54, 102, 102, -306, -503, 97, 102, 102, 102, - 739, 440, -240, 44, 477, 30, 644, 384, -292, 380, - 381, 382, -476, 102, -511, -247, 787, 388, -476, 25, - 102, -596, 102, -596, -476, 352, 97, 97, 44, 102, - 97, 102, 102, -318, -346, -496, -227, 20, -227, 29, - 20, 181, 443, 50, 112, 50, 496, 102, -237, 138, - 118, 119, -460, -461, 102, -533, -387, -389, 102, -476, - -360, -246, -230, -229, -361, -429, -526, -334, -240, 36, - 388, -286, -181, -362, -366, -372, -378, -379, -180, 327, - -363, -360, -612, 187, 112, 158, 112, 112, 96, -552, - -476, -503, -432, -432, -262, 774, -114, -116, 128, 167, - -476, 97, 97, 183, 96, -612, -759, -599, -602, 71, - -343, -356, 117, 117, -499, 102, 102, 102, -389, -390, - 50, 339, 335, 138, 138, -391, 50, 319, 320, -401, - 96, 350, 23, 112, 220, 716, 96, 123, 123, -339, - -533, -533, -533, -684, 400, 401, 402, 410, 404, 405, - 403, 406, 407, 408, 409, -684, -533, -533, 96, -559, - -558, -600, 29, 97, -573, 97, -573, 96, 138, -499, - -537, 297, 415, 416, 106, 20, 398, 399, 420, 419, - 418, 424, 425, 429, 430, 426, 428, 427, 431, 435, - 432, 433, 434, 437, 421, 422, 64, 423, 443, 454, - 450, -499, -536, 138, -472, 169, -476, 182, -724, -284, - -432, 74, -583, 781, -503, -511, 758, 760, 761, -476, - -476, -456, 709, 112, 102, 530, -666, -488, -623, 710, - -656, -591, -387, 138, -387, -387, 97, 85, 631, 409, - 633, -579, 97, -579, -587, -586, -590, 534, 352, 542, - -511, -766, -766, -580, 97, 97, 97, -476, -476, -339, - 102, 112, 97, 127, 127, 97, 97, -463, -462, 102, - -476, 388, -476, -320, 102, -320, 102, 352, -596, -9, - 632, -228, 70, 580, 102, 103, 490, 102, 103, 112, - 443, -223, 102, 788, 183, 138, 97, -597, -574, 307, - -246, 44, 183, -429, -464, -476, -182, -472, -574, -629, - 196, 386, 20, 112, 158, 112, -511, -282, -262, -261, - -115, 127, -116, -116, -476, 291, -3, -1, -476, 7, - -613, 196, 386, 97, -607, -603, 96, -604, -429, 309, - 148, 102, 102, 112, 96, -646, 40, 44, -503, -534, - 96, 97, 97, 97, 97, 97, -533, -577, 97, 97, - 97, -573, 112, 97, -472, -472, 102, 102, 397, -472, - -472, -472, -472, -472, -472, 96, 102, 102, -472, -472, - -472, -472, -472, -472, 138, 138, -472, -472, -472, 118, - 119, -387, -472, 182, -476, -262, -262, 75, -584, -582, - -476, -631, 20, 759, 96, 96, 96, 29, -622, -432, - -624, 711, 102, -665, 533, -659, -657, 528, 529, 530, - 531, 102, 97, 632, 75, 75, 634, -589, 130, 495, - 499, -497, 103, -500, 112, 114, 211, -580, -580, 102, - -476, 102, 788, 183, 138, -476, 388, -320, -320, -596, - 102, -321, -476, 350, 512, -461, 102, -538, -575, 359, - 29, -246, -429, -472, -597, 751, 755, -386, 757, 756, - 68, -575, 386, 112, 158, 112, 97, -284, 133, -503, - -115, -115, 97, 183, 32, -346, -7, 6, 386, -607, - -604, -606, -605, 357, 310, 96, 97, -503, -515, -472, - 96, 97, -404, -403, 629, -533, -536, 93, -536, -536, - 93, -536, 93, -536, 93, 97, -594, 358, 97, 112, - 112, -476, 112, 112, 112, 112, 112, 112, -573, 112, - 112, 112, 112, 112, 112, 118, 119, 118, 119, 112, - 112, 112, -387, -476, 183, 44, 761, 96, -511, -511, - -457, -476, -660, -402, 102, -669, 289, -663, -664, 532, - -657, 29, 530, 29, 29, -183, 183, 75, -588, -589, - 499, -497, 103, -500, 705, 540, 540, 540, 540, -242, - -243, -242, -243, -320, -462, 102, -476, 102, -320, -319, - 44, 535, 470, -539, -537, -530, 29, -576, -387, -367, - -373, 20, -383, 20, -380, 20, 112, -262, 23, 24, - 133, 133, 97, -1, 8, 6, 45, 102, 97, 183, - -476, 306, 96, -510, -504, -503, 306, 97, -387, -503, - -560, 718, 717, -410, -408, -409, 92, 547, 348, 349, - 97, -684, -684, -684, -684, -411, 112, 97, -582, 96, - -177, 96, 97, 97, 97, 183, -456, -677, 96, 112, - -662, -661, -663, 29, -660, 29, -660, -660, 537, 20, - 127, 541, 541, 541, 541, -242, -242, -320, 102, -452, - 96, -593, 96, 96, 96, 40, 22, 22, 102, 6, - 550, -605, -603, -510, 97, 183, -558, 97, -409, 92, - -408, 92, 24, 23, -536, -536, -536, -536, -581, 97, - 183, -509, -476, -680, 40, 97, -676, -675, -453, -670, - 533, 534, 102, -660, 138, 633, -588, -758, -757, 735, - -573, -578, -374, -375, -376, -476, 102, -384, -385, -376, - -381, -382, -376, -552, 96, 71, 96, 71, -2, -4, - 117, 10, 50, 102, 96, 97, -504, -560, -407, 345, - 346, 40, 196, -407, 97, 96, 97, -679, -678, -454, - 97, 183, 102, 634, 102, 97, -600, 97, 183, 138, - 97, 183, 138, 97, 183, 138, -300, -476, 96, -300, - 96, 92, 102, -3, 117, 50, 347, -509, 183, 138, - -675, -375, -377, -476, 102, -385, -377, -382, -377, 97, - 183, 182, -511, 97, -511, 9, 10, 97, 97, -678, - 50, -503, 71, -476, -476, 97, 71, 97, -6, -4, - -5, -4, 96, 182, 96, 92, 92, -511, -476, -511, - 10, 9, 97, 97, -} - -var yyDef = [...]int{ - 23, -2, 1, 2, 3, 19, 20, 21, 22, 18, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 0, 352, 353, 354, 355, - 356, 357, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, - 1255, 1256, 0, 0, 0, 0, 892, 0, 894, 882, - 860, 861, 916, 820, 0, 0, 0, 437, 0, 0, - 0, 0, 661, 662, 663, 664, 665, 666, 667, 668, - 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, - 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, - 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, - 699, 700, 701, 702, 703, 704, 497, 498, 499, 500, - 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, - 511, 0, 0, -2, 386, 382, 294, 295, 296, 297, - 298, 299, 300, 394, 395, 638, 0, 0, 0, 0, - 0, 1000, 1001, -2, 133, 0, 0, 0, 0, 0, - 375, 0, 366, 366, 0, 0, 1257, 1258, 1259, 1260, - 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, -2, - 0, 0, 873, 0, 821, 822, 823, 824, 825, 826, - 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, - 837, 838, 839, 840, 467, 468, 469, 463, 464, 466, - 465, 0, 0, 873, 0, 0, 0, 1016, 1050, 0, - 1070, 1071, 0, 1615, 1072, 1082, 1110, 0, 23, 0, - 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 0, 0, 18, 0, 18, 0, 0, 0, 1832, - 1833, 1834, 1835, 2456, 2809, 2777, -2, 2499, 2457, 2458, - 2700, 2701, 2588, 2604, 2449, 2858, 2859, 2860, 2861, 2862, - 2863, 2864, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2872, - 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2880, 2881, 2882, - 2883, 2884, 2885, 2886, 2887, 2888, 2889, 2890, 2891, 2892, - 2893, 2894, 2895, 2896, 2897, 2898, 2899, 2900, 2901, 2902, - 2903, 2904, 2905, 2906, 2907, 2908, 2909, 2910, 2911, 2912, - 2398, 2399, 2400, 2401, 2402, 2403, 2404, 2405, 2406, 2407, - 2408, 2409, 2410, 2411, 2412, 2413, 2414, 2415, 2416, 2417, - 2418, 2419, 2420, 2421, 2422, 2423, 2424, 2425, 2426, 2427, - 2428, 2429, 2430, 2431, 2432, 2433, 2434, 2435, 2436, 2437, - 2438, 2439, 2440, 2441, 2442, 2443, 2444, 2445, 2446, 2447, - 2448, 2450, 2451, 2452, 2453, 2454, 2455, 2459, 2460, 2461, - 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 2470, 2471, - 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, 2480, 2481, - 2482, 2483, 2484, 2485, 2486, 2487, 2488, 2489, 2490, 2491, - 2492, 2493, 2494, 2495, 2496, 2497, 2498, 2500, 2501, 2502, - 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512, - 2513, 2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, 2522, - 2523, 2524, 2525, 2526, 2527, 2528, 2529, 2530, 2531, 2532, - 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2540, 2541, 2542, - 2543, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, 2552, - 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, 2562, - 2563, 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572, - 2573, 2574, 2575, 2576, 2577, 2578, 2579, 2580, 2581, 2582, - 2583, 2584, 2585, 2586, 2587, 2589, 2590, 2591, 2592, 2593, - 2594, 2595, 2596, 2597, 2598, 2599, 2600, 2601, 2602, 2603, - 2605, 2607, 2608, 2609, 2610, 2611, 2612, 2613, 2614, 2615, - 2616, 2617, 2618, 2619, 2620, 2621, 2622, 2623, 2624, 2625, - 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, - 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, 2645, - 2646, 2647, 2648, 2649, 2650, 2651, 2652, 2653, 2654, 2655, - 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, 2665, - 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, - 2676, 2677, 2678, 2679, 2680, 2681, 2682, 2683, 2684, 2685, - 2686, 2687, 2688, 2689, 2690, 2691, 2692, 2693, 2694, 2695, - 2696, 2697, 2698, 2699, 2702, 2703, 2704, 2705, 2706, 2707, - 2708, 2709, 2710, 2711, 2712, 2713, 2714, 2715, 2716, 2717, - 2718, 2719, 2720, 2721, 2722, 2723, 2724, 2725, 2726, 2727, - 2728, 2729, 2730, 2731, 2732, 2733, -2, 2735, 2736, 2737, - 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745, 2746, 2747, - 2748, 2749, 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, - 2758, 2759, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, - 2768, 2769, 2770, 2771, 2772, 2773, 2774, 2775, 2776, 2778, - 2779, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, - 2789, 2790, 2791, 2792, 2793, 2794, -2, -2, -2, 2798, - 2799, 2800, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2808, - 2810, 2811, 2812, 2813, 2814, 2815, 2816, 2817, 2818, 2819, - 2820, 2821, 2822, 2823, 2824, 2825, 2826, 2827, 2828, 2829, - 2830, 2831, 2832, 2833, 2834, 2835, 2836, 2837, 2838, 2839, - 2840, 2841, 2842, 2843, 2844, 2845, 2846, 2847, 2848, 0, - 350, 348, 2424, 2449, 2456, 2457, 2458, 2499, 2588, 2604, - 2606, 2645, 2700, 2701, 2727, 2734, 2777, 2795, 2796, 2797, - 2809, 0, 0, 1289, 0, 0, 387, 862, 863, 893, - 895, 917, 1016, 1050, 0, 883, 884, 0, 818, 0, - 1775, 433, 0, 2475, 0, 0, 444, 2786, 0, 0, - 815, 427, 428, 429, 430, 431, 432, 0, 0, 0, - 1246, 0, 0, 2817, 423, 0, 0, 83, 490, 705, - 0, 0, 0, 0, 0, 795, 795, 1135, 1135, 0, - 735, 0, 0, 0, 795, 0, 750, 742, 0, 0, - 0, 795, 0, 0, 1039, 0, 1039, 0, 798, 805, - 795, 795, -2, 795, 795, 0, 790, 795, 0, 0, - 0, 756, 757, 758, 742, 742, 761, 762, 763, 773, - 774, 806, 2393, 0, 0, 381, 2591, 2808, 1836, 0, - 0, 0, 0, 0, 237, 1424, 239, 1426, 243, 251, - 0, 0, 0, 256, 257, 260, 261, 262, 263, 264, - 0, 268, 0, 270, 273, 0, 275, 276, 0, 279, - 280, 281, 0, 291, 292, 293, 1427, 1428, 1429, 1430, - 1431, 1432, 1433, 1434, -2, 0, 164, 1287, 2348, 2215, - 0, 2221, 2238, 2255, 1929, 1930, 1931, 1932, 0, 0, - 0, 0, 0, 0, 0, 1942, 1943, 0, 1989, 2862, - 2906, 2907, 0, 1953, 1954, 1955, 1956, 1957, 1958, 0, - 175, 189, 190, 2279, 2280, 2281, 2282, 2283, 2284, 2285, - 0, 2287, 2288, 2289, 0, 1914, 1832, 0, 2871, 2881, - 0, 2895, 2902, 2903, 2904, 2905, 2894, 0, 0, 2168, - 0, 2158, 0, 0, -2, -2, 0, 0, 2672, -2, - 2908, 2909, 2910, 2868, 2891, 2899, 2900, 2901, 2872, 2911, - 2912, 2875, 2898, 2864, 2865, 2866, 2859, 2860, 2861, 2863, - 2877, 2879, 2890, 0, 2886, 2896, 2897, 2784, 0, 0, - 2835, 2873, 2874, 0, 0, 0, 0, 0, 0, 2844, - 2845, 2846, 2847, 2848, 2830, 191, 192, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, 2179, -2, 2181, -2, 2183, -2, -2, - 2186, -2, -2, -2, -2, -2, 2192, 2193, -2, -2, - 2196, -2, -2, -2, -2, -2, -2, -2, 2170, 2171, - 2172, 2173, 2162, 2163, 2164, 2165, 2166, 2167, -2, -2, - -2, 2349, 1016, 0, 0, 1050, 1177, 0, 1050, 1048, - 1017, 0, 0, 1020, 1097, 1100, 1103, 1106, 0, 0, - 134, 135, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 376, 377, 365, 367, 0, - 371, 0, 0, 367, 364, 358, 0, 1501, 1501, 1501, - 0, 0, 1501, 0, 0, 0, 1501, 1501, 1501, 1501, - 1501, 0, 1501, 0, 0, 0, 1501, 0, 1325, 1436, - 1437, 1438, 1439, 1499, 1500, 1616, 0, 0, 0, 0, - 2737, 969, 2575, 0, 0, 977, 1032, 0, 1034, 1037, - 878, 874, 875, 876, 877, 0, 0, 0, 638, 638, - 0, 638, 0, 0, 638, 0, 638, 638, 638, 0, - 880, 2537, 2640, 2492, 2611, 2434, 2591, 2808, 0, 323, - 2672, 328, 0, 2498, 2541, 0, 0, 2562, 0, -2, - 0, 404, 1050, 0, 1017, 1041, 0, 1051, 0, 0, - 1016, 1050, 1050, 0, 1090, 0, 0, 638, 638, 0, - 0, 638, 638, 638, 638, 638, 0, 638, 638, 638, - 0, 638, 0, 638, 0, 638, 638, 638, 0, 1111, - 1112, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, - 1123, 1084, 4, 5, 18, 0, 0, 0, 0, 0, - 0, 140, 139, 0, 2352, 2388, 2292, 2293, 2294, 0, - 2375, 2297, 2379, 2379, 2379, 2379, 0, 2329, 2375, 2331, - 2332, 2333, 2375, 2335, 2336, 2337, 2338, 2379, 2379, 2379, - 2379, 2379, 2379, 0, 0, 2347, 2318, 2377, 2377, 2377, - 2375, 2354, 2298, 2299, 2300, 2301, 2302, 2303, 2304, 2305, - 2306, 2307, 2308, 2309, 2310, 2311, 2382, 2382, 2385, 2385, - 2382, 2355, 2356, 2357, 2358, 2359, 2360, 2361, 2362, 2363, - 2364, 2365, 2366, 2367, 2368, 2369, 2370, 2371, 2372, 0, - 495, 493, 494, 2211, 0, 0, 0, 1050, -2, 0, - 1048, 967, 0, 819, 1766, 0, 0, 434, 1837, 0, - 0, 0, 446, 0, 0, 0, 448, 0, 0, 445, - 0, 0, 470, 0, 473, 456, 457, 458, 459, 460, - 452, 0, 217, 0, 425, 426, 422, 0, 479, 481, - 483, 486, 1762, 80, 84, 87, 0, 1039, 0, 707, - 795, 795, 795, 795, 723, 724, 725, 0, 1135, 0, - 0, 728, 729, 0, 730, 0, 0, 742, 795, 795, - 748, 749, 744, 743, 801, 802, 798, 0, 798, 798, - 1135, 0, 767, 768, 769, 795, 795, 775, 1040, 0, - 0, 777, 779, 798, 0, 803, 804, 1135, 0, 0, - 1135, 1135, 0, 787, 788, 0, 791, 795, 0, 794, - 0, 0, 1501, 0, 811, 744, 744, 2394, 2395, 383, - 0, 0, 0, 639, 0, 0, 0, 0, 0, 0, - 248, 244, 252, 255, 265, 272, 0, 284, 286, 289, - 245, 253, 258, 259, 266, 287, 246, 249, 250, 254, - 288, 290, 247, 267, 271, 285, 269, 274, 277, 278, - 283, 0, 218, 0, 0, 0, 0, 0, 2220, 0, - 0, 2265, 2266, 2267, 2268, 2269, 2270, 2271, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2258, 0, 0, 0, 0, - 0, 0, 0, -2, 2215, 0, 0, 1936, 1937, 1938, - 1939, 1940, 0, 1944, 0, 1990, 0, 0, 0, 0, - 0, 0, 2286, 2290, 0, 0, 2211, 2211, 0, 0, - 2211, 2207, 0, 0, 0, 0, 0, 0, 2211, 2141, - 0, 0, 2143, 2159, 0, 0, 2145, 2146, 0, 2149, - 2150, 2211, 0, 2211, 2154, 2211, 2211, 2211, 2135, 2136, - 0, 0, 0, 2207, 0, 0, 2207, 2207, 2207, 0, - 0, 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, - 2207, 2207, 2207, 2207, 2207, 2207, 2207, 2207, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1050, 1016, 1041, 0, 0, -2, 0, 978, 0, 1048, - 1074, 1076, 1078, 1080, 1047, 1022, 0, 1098, 1099, 1101, - 1102, 1104, 1105, 1107, 1108, 0, 136, 0, 0, 0, - 115, 0, 0, 112, 0, 0, 0, 0, 81, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 369, 0, 374, 360, 2633, 0, 359, 0, 0, - 0, 0, 1501, 1501, 0, 0, 1286, 0, 0, 1501, - 1501, 1326, 0, 0, 0, 0, 0, 0, 0, 0, - 1501, 1501, 1501, 0, 1519, 0, 0, 0, 0, 902, - 904, 899, 0, 0, 902, 0, 0, 969, 969, 976, - 0, 1033, 0, 0, 880, 879, 0, 1150, 1151, 1152, - 1193, 1236, 1236, 0, 1236, 1197, 0, 1775, 0, 0, - 0, 0, 1513, 0, 0, 0, 0, 0, 0, 0, - 620, 814, 621, 0, 0, 2396, 0, 0, 0, 523, - 524, 0, 0, 881, 0, 302, 306, 0, 309, 0, - 2640, 0, 2640, 0, 0, 316, 0, 0, 0, 0, - 0, 0, 346, 347, 0, 0, 0, 0, 337, 340, - 1758, 1759, 1421, 1422, 341, 342, 396, 397, 0, 1041, - 1073, 1075, 1077, 1079, 999, 1042, 1043, 1083, 1085, 1086, - 1087, 0, 0, 1068, 1069, 1041, 1041, 0, 1092, 0, - 0, 0, 638, 638, 0, 0, 0, 0, 0, 638, - 0, 0, 0, 856, 0, 858, 0, 0, 638, 0, - 0, 0, 978, 1137, 1139, 1241, 175, 1113, 7, 157, - 154, 0, 18, 0, 0, 18, 18, 0, 18, 351, - 0, 2391, 2389, 2390, 0, 2296, 2376, 0, 2323, 0, - 2324, 2325, 2326, 2327, 2328, 2330, 2334, 2339, 2340, 2341, - 2342, 2343, 2344, 0, 0, 2319, 0, 2320, 2321, 2322, - 2312, 2382, 0, 2314, 2315, 0, 2316, 2317, 349, 492, - 0, 0, 2212, 1290, 0, 0, 1041, 1012, 1048, 0, - 1048, 978, 0, 0, 638, 1764, 0, 1775, 0, 0, - 0, 0, 0, 435, 0, 0, 461, 462, 0, 447, - 0, 454, 0, 449, 450, 453, 0, 0, 472, 474, - 475, 476, 477, 816, 419, 420, 421, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 0, 415, 416, 417, - 418, 0, -2, 0, 0, 424, 185, 478, 0, 480, - 0, 485, 0, 487, 0, 88, 489, 0, 709, 0, - 1135, 0, 0, 1135, 1135, 0, 0, 1135, 0, 727, - 796, 797, 1136, 731, 0, 0, 739, 2168, 2591, 1413, - 744, 1135, 1135, 751, 745, 752, 800, 753, 754, 755, - 798, 1135, 1135, 1044, 0, 795, 798, 780, 799, 798, - 1775, 784, 0, 789, 792, 793, 1775, 812, 1775, 0, - 810, 759, 760, 384, 385, 0, 0, 0, 231, 232, - 233, 234, 235, 236, 238, 222, 847, 849, 1425, 0, - 1416, 0, 241, 282, 214, 0, 0, 0, 0, 2216, - 2217, 2218, 2219, 2224, 0, 0, 2227, 2230, 2233, 2236, - 0, 2262, -2, -2, 1915, 1916, 1917, 1918, 1919, 1920, - 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 2239, 2260, - 2261, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 2259, 2256, 2256, 2249, 0, 1933, 1950, - 1994, 2008, 2008, 1959, 1760, 1761, 1934, 0, 0, 1987, - 1991, 0, 0, 0, 0, 0, 0, 1479, 2375, 0, - 176, 2255, 2206, 2102, 2103, 2104, 2105, 2106, 2107, 2108, - 2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, - 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, - 2129, 2130, 0, 0, 2215, 0, 0, 0, 0, 2208, - 2209, 0, 0, 0, 2090, 0, 0, 2096, 2097, 2098, - 0, 1829, 0, 2169, 2142, 2160, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 2131, 2132, - 2133, 2134, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1041, 1050, 1176, 1178, 0, 963, 965, - 966, 1006, 1048, 1048, 1008, 0, 978, 1024, 0, 0, - 0, 132, 137, 0, 1583, 123, 0, 0, 0, 123, - 0, 0, 0, 123, 0, 0, 0, 1397, 1515, 89, - 1396, 1517, 0, 0, 0, 0, 0, 0, 0, 378, - 379, 0, 0, 373, 361, 2633, 363, 0, 0, 0, - 0, 0, 0, 0, 1273, 0, 0, 0, 1304, 0, - 0, 0, 1341, 1342, 0, 636, 1407, 0, 0, 0, - 1423, 1483, 1497, 0, 0, 0, 1589, 1327, 1332, 1333, - 1334, 1328, 1329, 1335, 1336, 896, 905, 0, 900, 0, - 906, 0, 0, 939, 959, 934, 0, 943, 0, 0, - 0, 1035, 0, 0, 1191, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1183, 0, 0, 0, 1182, 0, - 0, 0, 0, 0, 0, 0, 1037, 1237, 0, 1239, - 1240, 1195, -2, 0, 1146, 1148, 0, 1219, 0, 2211, - 0, 0, 1591, 1037, 520, 521, 522, 532, 593, 534, - 0, 593, 593, 593, 576, 0, 0, 564, 2396, 0, - 0, 0, 0, 573, 2396, 0, 0, 2396, 2396, 2396, - 2396, 2396, 2396, 2396, 2396, 0, 0, 2396, 2396, 2396, - 2396, 2396, 2396, 2396, 2396, 2396, 2396, 2396, 0, 2396, - 2396, 2396, 2396, 2396, 1744, 2396, 0, 1514, 583, 584, - 585, 586, 591, 592, 0, 0, 537, 538, 0, 0, - 0, 0, 0, 631, 0, 0, 1340, 619, 0, 622, - 2396, 0, 2396, 0, 2397, 636, 0, 0, 1385, 0, - 0, 1148, 0, 0, 0, 0, 314, 315, 303, 0, - 304, 0, 0, 317, 318, 0, 320, 321, 322, 329, - 2492, 2611, 324, 326, 0, 0, 330, 343, 344, 345, - 0, 0, 335, 336, 0, 0, 399, 400, 402, 0, - 1048, 1088, 1054, 1055, 1058, 0, 0, 1091, 1093, 1094, - 1095, 1096, 1516, 1504, 85, 86, 2817, 841, 0, 0, - 844, 845, 846, 850, 0, 0, 1617, 854, 855, 0, - 0, 1394, 0, 1398, 1400, 1504, 1143, 0, 1140, 1242, - 0, 1244, 0, 0, 155, 18, 0, 148, 145, 0, - 0, 0, 0, 0, 2353, 2291, 2392, 0, 0, 0, - 0, 2373, 0, 0, 2313, 0, 0, 0, 138, 161, - 985, 1048, 978, 0, 980, 187, 978, 1014, 914, 959, - 887, 0, 943, 0, 0, 0, 0, 0, 1766, 0, - 0, 0, 0, 1838, 0, 439, 438, 0, 0, 455, - 0, 0, 451, 471, 0, 414, 0, 0, 0, 482, - 0, 1763, 488, 491, 706, 0, 708, 711, 795, 0, - 714, 715, 795, 0, 0, 721, 726, 734, 732, 0, - 736, 0, 739, 738, 0, 1415, 795, 746, 747, 1135, - 770, 771, 0, 0, 0, 1135, 795, 795, 783, 798, - 807, 0, 808, 1775, 0, 225, 1410, 0, 226, 230, - 220, 0, 0, 0, 1412, 1417, 0, 240, 0, 0, - 215, 216, 1574, 1583, 0, 0, 0, 163, 2225, 2228, - 2231, 2234, 2226, 2229, 2232, 2235, 2237, 0, 2240, 2256, - 2256, 2250, 0, 2241, 2256, 2256, 2251, 0, 0, 2243, - 0, 2246, 0, 1995, 2009, 2010, 1996, 2216, 1941, 0, - 1992, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1058, 0, 0, 0, 2078, 2080, 0, 0, 0, 2085, - 0, 2087, 2088, 2089, 2091, 0, 0, 0, 2095, 0, - 2140, 2161, 2144, 2147, 0, 2151, 0, 2153, 2155, 2156, - 2157, 0, 0, 0, 1050, 1052, 1052, 1050, 0, 0, - 2035, 2035, 1052, 0, 0, 0, 0, 2035, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1964, 0, 1965, 1966, 1967, 0, 1969, 2913, - 0, 2913, 0, 2913, 2913, 0, 0, 0, 1048, 1041, - 0, 1179, 978, 978, 0, 1009, 1018, 0, 0, 0, - 0, 0, 0, 1581, 0, 108, 0, 0, 0, 116, - 0, 111, 117, 0, 0, 113, 0, 0, 125, 90, - 0, 0, 1522, 1523, 0, 0, 0, 380, 368, 370, - 0, 362, 0, 1502, 1503, 0, 0, 0, 1663, 1673, - 1277, 0, 0, -2, 1306, 0, 1037, 1037, 1352, 2396, - 0, 640, 0, 0, 1409, 0, 1374, 0, 0, 1484, - 0, -2, 0, 0, -2, 0, 0, 1593, 0, 897, - 903, 0, 0, 0, 898, 914, 940, 0, 933, 956, - 0, 960, 0, 0, 947, 949, 938, 944, 0, 0, - 0, 974, 914, 914, 23, 1038, 0, 0, 0, 867, - 871, 0, 1187, 1187, 1187, 1156, 0, 0, 1159, 1184, - 1160, 1185, 0, 0, 1164, 0, 1166, 0, 1168, 0, - 1162, 1163, 1170, 1171, 0, 1161, 1194, 1238, 0, 1196, - 0, 1218, 1220, 1221, 1227, 0, 0, 0, 0, 0, - 0, 0, 516, 517, 1593, 0, 0, 1513, 1627, 554, - 0, 1788, 1789, 594, 0, 1796, 1805, 1805, 1501, 1878, - 0, 1805, 0, 0, 1807, 1808, 1660, 0, 0, 563, - 0, 0, 0, 0, 0, 0, 0, 577, 578, 0, - 0, 562, 0, 0, 604, 0, 0, 0, 0, 0, - 0, 2396, 2396, 0, 571, 572, 0, 575, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2396, 2396, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1735, 0, 0, 0, 0, 0, 0, 0, 1750, 1751, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1352, - 2396, 0, 0, 0, 0, 0, 2396, 0, 625, 640, - 1404, 1404, 1372, 1390, 0, 525, 526, 601, 0, 0, - 0, 307, 308, 0, 0, 313, 331, 333, 305, 0, - 0, 0, 332, 334, 338, 339, 398, 401, 403, 978, - 0, 1061, 1059, 1060, 1081, 1089, 82, 1505, 842, 843, - 0, 1617, 853, 1618, 1619, 1306, 859, 1395, 0, 1402, - 1135, 1144, 0, 1138, 1243, 1245, 176, 1141, 0, 158, - 18, 157, 149, 150, 0, 18, 0, 0, 0, 0, - 2295, 2381, 2380, 2345, 0, 2346, 2378, 2383, 0, 2386, - 0, 496, 0, 989, 0, 978, 1015, 981, 0, 1013, - 885, 0, 886, 0, 0, 891, 0, 974, 1399, 1767, - 1768, 0, 1771, 1772, 1773, 1774, 1765, 0, 0, 0, - 0, 0, 0, 0, 440, 441, 442, 443, 817, 0, - 186, 484, 710, 1135, 795, 1135, 0, 795, 795, 722, - 1670, 1671, 733, 740, 737, 1414, 1135, 764, 1045, 1046, - 776, 778, 1775, 1135, 1135, 795, 813, 809, 0, 0, - 0, 0, 0, 848, 0, 222, 0, 0, 242, 0, - 0, 0, 1583, 1578, 2210, 2244, 2247, 0, 2245, 2248, - 0, 0, 2257, 2252, 1935, 1945, 1988, 0, 0, 2379, - 0, 0, 0, 1997, 1998, 2379, 2379, 2002, 2375, 2377, - 2375, 2008, 2008, 0, 1480, 0, 1481, 1058, 177, 0, - 0, 0, 0, 2035, 0, 0, 0, 1830, 0, 0, - 0, 0, 0, 2031, 2035, 0, 2035, 2033, 2035, 2035, - 2053, 2036, 2054, 2035, 2035, 2035, 2035, 2035, 2060, 2035, - 2035, 2035, 2035, 2035, 2035, 2035, 2035, 0, 2035, 2035, - 2035, 2035, 0, 2037, 2040, 1968, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2280, 2281, 978, 1048, - 964, 1010, 1007, 0, 0, 0, 0, 0, 71, 71, - 1583, 0, 0, 109, 121, 122, 0, 0, 0, 0, - 131, 0, 0, 0, 0, 0, 0, 0, 1531, 1539, - 0, 372, 0, 91, 92, 94, 0, 0, 0, 0, - 0, 0, 0, 107, 1270, 0, 1271, 0, 1281, 0, - 1275, 0, 0, 1292, 1293, 1295, 0, 1298, 1299, 1300, - 0, 1307, 1308, 1310, 1311, 0, 2407, -2, -2, 2538, - -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, -2, 2466, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, - -2, -2, -2, -2, 1305, 0, 0, 1356, 1353, 1354, - 1355, 0, 0, 1404, 641, 642, 643, 644, 0, 0, - 0, 1408, 0, 0, 0, 1365, 0, 0, 0, 1485, - 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, 1494, -2, - 1508, 0, 1775, 0, 0, 1781, 1563, 0, 0, 0, - 1570, 0, 0, 1003, 0, -2, -2, 1781, 1561, 2396, - 1781, 1601, 0, 1590, 0, 0, 901, 910, 0, 959, - 961, 0, 0, 959, 0, 0, 0, 970, 0, 971, - 0, 0, 911, 912, 914, 0, 1192, 967, 0, -2, - 0, 0, 869, 0, 0, 1153, 1188, 0, 0, 1154, - 1155, 1157, 1174, 1186, 0, 1180, 1165, 1167, 1169, 1172, - 0, 1147, 0, 1222, 0, 0, 1224, 1225, 1226, 0, - 1199, 512, 0, 1665, 0, 1668, 1669, 514, 0, 1675, - 0, 1678, 1679, 1601, 1592, 0, 533, 593, 593, 0, - 547, 0, 595, 0, 0, 1795, 1826, 1806, 1826, 1826, - 1879, 1826, 1826, 1501, 0, 1648, 0, 0, 1654, 0, - 1661, 0, 0, 0, 0, 0, 595, 0, 0, 565, - 561, 598, 1058, 548, 550, 551, 552, 602, 603, 605, - 0, 607, 608, 609, 567, 579, 580, 581, 582, 0, - 0, 0, 574, 587, 588, 589, 590, 549, 1711, 1712, - 1713, 1714, 1717, 1718, 1719, 1720, 0, 0, 1723, 1724, - 1725, 1726, 1727, 1823, 1824, 1825, 1728, 1729, 1730, 1731, - 1732, 1733, 1734, 1752, 1753, 1754, 1755, 1756, 1757, 1736, - 1737, 1738, 1739, 1740, 1741, 1742, 1743, 0, 0, 1747, - 0, 0, 1275, 0, 541, 542, 0, 544, 0, 0, - 1356, 0, 0, 0, 0, 0, 623, 0, 626, 1404, - 634, 0, 0, 635, 1374, 0, 1392, 0, 1386, 1387, - 0, 0, 931, 1135, 391, 0, 1135, 301, 310, 311, - 312, 319, 0, 660, 325, 1064, 1056, 1057, 0, 851, - 852, 0, 0, 1126, 1145, 0, 153, 156, 0, 151, - 0, 0, 0, 0, 143, 141, 2374, 0, 0, 162, - 991, 202, 0, 0, 1064, 983, 0, 188, 915, 0, - 959, 968, 0, 1776, 1777, 1778, 1779, 0, 1839, 436, - 0, 712, 1135, 716, 795, 1135, 1135, 0, 741, 781, - 785, 782, 1135, 0, 1411, 222, 227, 228, 229, 223, - 221, 1418, 0, 1420, 0, 1576, 0, 0, 2253, 2254, - 2242, 1993, 1946, 2323, 0, 1949, 1951, 1999, 2000, 2003, - 2004, 2005, 2006, 2007, 1952, 0, 1482, 2079, 2081, 0, - 2083, 2084, 2086, 2092, 2093, 0, 0, 2148, 2152, 0, - 0, 2139, 0, 0, 2048, 0, 2049, 0, 0, 2051, - 2052, 2055, 2056, 2057, 2058, 2059, 2061, 2062, 2063, 2064, - 2065, 2066, 2067, 2068, 0, 2070, 2071, 2072, 2073, 0, - 0, 2029, 2041, 1970, 2914, 2913, 0, 1973, 2913, 0, - 1976, 1977, 2915, 0, 0, 0, 0, 0, 0, 1064, - 978, 1049, 0, 0, 1027, 1028, 1029, 1030, 1031, 1023, - 0, 0, 73, 0, 73, 1582, 1584, 124, 126, 0, - 0, 118, 119, 120, 0, 0, 0, 1241, 1545, 1775, - 1533, 0, 1525, 0, 1539, 0, 0, 0, 93, 0, - 95, 0, 2594, 0, 0, 0, 0, 1504, 0, 0, - 1283, 0, 0, 1274, 0, 1285, 1301, 1297, 0, 0, - 0, 1312, 0, 0, 1323, 0, 0, 1344, 1345, 1346, - 1370, 1358, 0, 646, 647, 0, 0, 0, 659, 655, - 656, 657, 637, 1403, 1381, 0, 0, 1381, 1368, 0, - 0, 1380, 0, 1509, 2396, 2396, 2396, 1545, 0, 0, - 0, 1782, 1783, 1785, 1786, 1787, 1565, 0, 1569, 1547, - 0, 1050, 0, 0, 0, 1604, 0, 0, 1595, 0, - 0, 908, 0, 957, 0, 962, 959, 937, 948, 936, - 950, 945, 946, 975, 0, 972, 913, 1036, 1236, 0, - 0, 1135, 868, 871, 872, 0, 1189, 0, 1158, 0, - 1181, 1173, 1149, 1231, 1228, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1604, 519, 0, 0, 1629, 0, - 566, 596, 0, 0, 2919, -2, 0, 1827, 0, 0, - 1809, 1827, 0, 0, 1826, 0, 1625, 0, 0, 0, - 0, 0, 1658, 0, 1441, 1441, 1441, 1441, 1441, 0, - 0, 610, 0, 614, 615, 612, 1873, 0, 0, 613, - 555, 595, 0, 0, 600, 0, 606, 1715, 1716, 0, - 1721, 1722, 0, 1746, 0, 0, 536, 539, 0, 1279, - 1280, -2, 0, 0, 0, 618, 0, 0, 0, 627, - 628, 624, 633, 1405, 1406, 1365, 0, 1381, 0, 1391, - 0, 1388, 1389, 1050, 0, 0, 0, 914, 327, 1005, - 0, 0, 1062, 1063, 857, 0, 1124, 0, 1142, 0, - 18, 0, 0, 146, 2384, 2387, 993, 0, 990, 203, - 0, 0, 0, 1011, 985, 0, 982, 959, 890, 889, - 0, 1770, 1780, 713, 1135, 718, 719, 0, 786, 224, - 219, 1419, 1586, 0, 1577, 0, 0, 0, 1898, 1961, - 1962, 1963, 0, 2094, 1831, 0, 0, 1052, 2032, 0, - 2035, 2034, 0, 2035, 2038, 1050, 2030, 0, 0, 0, - 0, 0, 2913, 0, 1979, 0, 1981, 1982, 1983, 0, - 1985, 1986, 2350, 1064, 1025, 0, 1021, 0, 69, 0, - 72, 70, 110, 0, 114, 0, 0, 130, 1520, 0, - 1545, 1524, 0, 0, 0, 1526, 0, 0, 0, 0, - 0, 96, 0, 0, 0, 0, 0, 0, 105, 0, - 0, 0, 0, 1282, 0, 1276, 0, 0, 1294, 1296, - 0, 1309, 0, 1330, 1330, 1357, 1343, 0, 1324, 0, - 0, 648, 649, 0, 652, 658, 1359, 0, 0, 1362, - 1363, 1361, 1364, 0, 0, 1378, 0, 0, 0, 0, - 1495, 0, 1498, -2, 0, 1567, 1545, 0, 0, 1041, - 0, 1663, -2, 1610, 0, 1602, 0, 1594, 0, 1597, - 907, 0, 0, 942, 958, 935, 0, 0, 1135, 1135, - -2, 914, 870, 0, 918, 920, 0, 0, 1175, 0, - 0, 1232, 1234, 1229, 1230, 0, 1666, 513, 1667, 1676, - 515, 1677, 1680, 1681, 1610, 0, 1628, 0, 1642, 597, - 2917, 0, 1828, -2, 1842, 1844, 0, 0, 1514, 1848, - 1849, 0, 0, 0, 0, 0, 0, 0, 0, 1906, - 1859, 0, 0, 0, 1864, 1865, 1866, 0, 0, 0, - 0, 2274, 2275, 0, 1877, 0, 0, 0, 0, 0, - 0, 0, 0, 1803, 1627, 0, 1649, 0, 0, 0, - 0, 0, 0, 0, 527, 528, 529, 530, 531, 0, - 559, 560, 1441, 0, 1874, 1875, 556, 557, 599, 553, - 2396, 569, 1745, 1748, 1749, 540, 543, 0, 0, 632, - 629, 630, 1368, 1373, 1384, 1393, 932, 1039, 1135, 392, - 393, 389, 1065, 1066, 0, 1401, 2042, 0, 0, 147, - 152, 0, 0, 995, 0, 992, 0, 986, 988, 213, - 989, 984, 888, 1769, 717, 795, 171, 205, 0, 0, - 0, 1948, 0, 0, 0, 0, 2082, 2137, 2138, 2035, - 0, 2050, 2035, 2074, 2026, 0, 1971, 2913, 1974, 2913, - 0, 2916, 0, 0, 2351, 0, 1019, 74, 128, 127, - 0, 0, 1521, 0, 0, 0, 1537, 1538, 0, 1540, - 1541, 1542, 0, 0, 0, 0, 78, 0, 0, 0, - 1504, 0, 1504, 0, 0, 0, 1664, 1674, 0, 1284, - 1278, 1288, 1302, 0, 1315, 1313, 1322, 1337, 1321, 0, - 0, 0, 645, 650, 0, 653, 654, 1382, 1381, 0, - 1366, 1367, 0, 1376, 0, 0, 1510, 1511, 1512, 1370, - 1620, 1564, 0, 0, -2, 1708, 0, 1784, 1571, 1548, - 0, 1004, 1555, 1556, 1557, 1558, 1559, 1560, 1586, 2396, - 1662, 1620, 1598, 0, 1605, 0, 1603, 1596, 0, 941, - 951, 973, 1050, 914, 865, 0, 921, 929, 0, 0, - 928, 1190, 1223, 0, 0, 1607, 0, 1630, -2, 0, - 2920, 1843, 1845, 1846, 1847, 1850, 1851, 1852, 1853, 1854, - 1911, 1912, 1913, 0, 0, 1857, 1908, 1909, 1910, 1858, - 0, 0, 0, 1863, 0, 0, 0, 2272, 2273, 1904, - 0, 0, 0, 1810, 1812, 1813, 1814, 1815, 1816, 1817, - 1818, 1819, 1820, 1821, 1822, 1811, 0, 0, 0, 1802, - 1804, 535, 1660, 1650, 0, 1652, 0, 0, 0, 0, - 1442, 2396, 2396, 0, 0, 0, 1452, 1453, 2396, 2396, - 2396, 2396, 2396, 2396, 0, 0, 0, 2396, 2396, 2396, - 2396, 2396, 2396, 0, 1471, 1472, 1473, 0, 2396, 2396, - 2396, 558, 611, 0, 0, 2396, 0, 0, 1383, 914, - 914, 0, 1109, 0, 1125, 1133, 2835, 2837, 2834, 142, - 144, 159, 0, 994, 204, 0, 991, 1135, 173, 0, - 196, 0, 1587, 0, 0, 2001, 1960, 0, 0, 0, - 0, 2047, 1053, 2069, 2039, 2027, 0, 2021, 2022, 2023, - 2028, 0, 0, 1978, 1980, 1984, 1026, 0, 1546, 1534, - 1535, 1536, 1532, 0, 0, 1543, 1544, 0, 76, 0, - 99, 0, 0, 100, 1504, 101, 1504, 0, 0, 1272, - 0, 0, 1338, 1339, 1347, 1348, 0, 1350, 1351, 1371, - 651, 1360, 1369, 1375, 1378, 0, 1443, 1496, 1622, 0, - 1566, 0, 1513, 1710, 2396, 1370, 1573, 0, 1622, 1588, - 0, 1600, 0, 1612, 0, 1606, 0, 1039, 866, 919, - 0, 0, 929, 929, 1233, 1235, 0, 1200, 0, -2, - 518, 0, 1609, 2918, 1631, -2, 0, 1639, 1641, 0, - 0, 1855, 1856, 0, 0, 2158, 2396, 0, 0, 1893, - 0, 1441, 1441, 1441, 1441, 1441, 0, 1646, 1651, 1653, - 1655, 0, 1659, 1657, 0, 0, 1449, 1450, 0, 0, - 0, 0, 0, 0, 0, 0, 1461, 1462, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 616, - 617, 568, 0, 0, 546, 388, 390, 1067, 2043, 2044, - 0, 1127, 0, 0, 0, 0, 0, 0, 993, 720, - 160, 0, 172, 193, 0, 206, 207, 0, 0, 0, - 0, 1579, 1947, 0, 1901, 1903, 1902, 2024, 0, 0, - 0, 0, 0, 0, 2276, 2277, 2278, 1972, 1975, 129, - 1539, 1539, 1504, 78, 0, 98, 0, 102, 103, 0, - 1504, 0, 1314, 0, 1349, 1377, 1379, 1440, 1554, 0, - 1660, 1568, 1709, 0, 1572, 1673, 1683, 1697, 1690, 1695, - 1696, 1562, 1599, 1611, 0, 1614, 909, 914, 0, 930, - 0, 0, 0, 0, 0, 0, 0, 1207, 1608, 1632, - 1640, 0, 1635, 0, 0, 0, 1907, 0, 1862, 0, - 0, 1870, 1881, 1894, 0, 0, 1790, 0, 1792, 1793, - 0, 1797, 0, 1799, 0, 0, 1626, 0, 1656, 1447, - 1448, 1451, 1454, 1455, 1456, 1457, 1458, 1459, 0, 1463, - 1464, 1465, 1466, 1467, 1468, 1469, 1470, 1474, 1475, 1476, - 1477, 1478, 570, 545, 0, 0, 1134, 0, 0, 0, - 0, 997, 987, 995, 174, 178, 0, 202, 199, 0, - 208, 0, 0, 0, 0, 1575, 0, 1899, 0, 2011, - 0, 0, 0, 0, 2016, 2017, 2018, 2019, 2020, 1527, - 1539, 1528, 1539, 75, 77, 79, 97, 1504, 104, 0, - 1316, 1317, 1331, 1444, 1445, 1446, 0, 1648, 1715, 1672, - 1682, 0, 1688, 0, 1689, 0, 1613, 864, 0, 923, - 0, 0, 1198, 1201, 1202, 0, 0, 0, 1634, 0, - -2, 1643, 0, 0, 2213, 2222, 2223, 1860, 1867, 0, - 1869, 1871, 1872, 1880, 1882, 1883, 0, 1895, 1896, 1897, - 1905, 1441, 1441, 1441, 1441, 1801, 1647, 1460, 2045, 2040, - 0, 2211, 1129, 1130, 996, 0, 979, 165, 0, 0, - 197, 198, 200, 0, 209, 0, 211, 212, 0, 0, - 0, 2012, 2013, 2014, 2015, 1529, 1530, 106, 1318, 1623, - 0, 1625, 0, 0, 0, 0, 0, 0, 1211, 0, - 0, 1636, -2, 0, 1645, 0, 1861, 1870, 1884, 0, - 1885, 0, 0, 0, 1791, 1794, 1798, 1800, 0, 1128, - 0, 0, 998, 1585, 0, 179, 0, 181, 183, 184, - 194, 195, 201, 210, 0, 0, 2025, 1303, 1319, 0, - 0, 1627, 0, 1685, 0, 1702, 1703, 0, 1699, 0, - 0, 1692, 0, 922, 0, 0, 0, 0, 1203, 0, - 1208, 1209, 0, 1204, 0, 1644, 2214, 1868, 1886, 1888, - 1889, 0, 0, 1887, 2046, 2211, 1131, 166, 167, 0, - 180, 0, 1580, 1900, 1320, 1624, 1621, 1684, 0, 0, - 1698, 0, 0, 1691, 0, 0, 0, 952, 0, 0, - 0, 0, 1210, 0, 1890, 1892, 1891, 0, 0, 0, - 182, 1686, 1687, 1704, 1705, 1700, 1701, 1693, 1694, 0, - 0, 0, 0, 0, 0, 1216, 1214, 1205, 1132, 168, - 169, 170, 0, 954, 953, 926, 0, 927, 1212, 0, - 1213, 0, 0, 0, 0, 0, 0, 0, 955, 0, - 1217, 1215, 924, 925, -} - -var yyTok1 = [...]int{ - 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 129, 3, 3, 3, 162, 152, 3, - 96, 97, 159, 157, 183, 158, 182, 160, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 789, 786, - 139, 138, 140, 3, 790, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 164, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 787, 151, 788, 165, -} - -var yyTok2 = [...]int{ - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, - 135, 136, 137, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 153, 154, 155, 156, 161, 163, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, -} - -var yyTok3 = [...]int{ - 57600, 275, 57601, 276, 57602, 277, 57603, 278, 57604, 279, - 57605, 280, 57606, 281, 57607, 282, 57608, 283, 57609, 284, - 57610, 285, 57611, 286, 57612, 287, 57613, 288, 57614, 289, - 57615, 290, 57616, 291, 57617, 292, 57618, 293, 57619, 294, - 57620, 295, 57621, 296, 57622, 297, 57623, 298, 57624, 299, - 57625, 300, 57626, 301, 57627, 302, 57628, 303, 57629, 304, - 57630, 305, 57631, 306, 57632, 307, 57633, 308, 57634, 309, - 57635, 310, 57636, 311, 57637, 312, 57638, 313, 57639, 314, - 57640, 315, 57641, 316, 57642, 317, 57643, 318, 57644, 319, - 57645, 320, 57646, 321, 57647, 322, 57648, 323, 57649, 324, - 57650, 325, 57651, 326, 57652, 327, 57653, 328, 57654, 329, - 57655, 330, 57656, 331, 57657, 332, 57658, 333, 57659, 334, - 57660, 335, 57661, 336, 57662, 337, 57663, 338, 57664, 339, - 57665, 340, 57666, 341, 57667, 342, 57668, 343, 57669, 344, - 57670, 345, 57671, 346, 57672, 347, 57673, 348, 57674, 349, - 57675, 350, 57676, 351, 57677, 352, 57678, 353, 57679, 354, - 57680, 355, 57681, 356, 57682, 357, 57683, 358, 57684, 359, - 57685, 360, 57686, 361, 57687, 362, 57688, 363, 57689, 364, - 57690, 365, 57691, 366, 57692, 367, 57693, 368, 57694, 369, - 57695, 370, 57696, 371, 57697, 372, 57698, 373, 57699, 374, - 57700, 375, 57701, 376, 57702, 377, 57703, 378, 57704, 379, - 57705, 380, 57706, 381, 57707, 382, 57708, 383, 57709, 384, - 57710, 385, 57711, 386, 57712, 387, 57713, 388, 57714, 389, - 57715, 390, 57716, 391, 57717, 392, 57718, 393, 57719, 394, - 57720, 395, 57721, 396, 57722, 397, 57723, 398, 57724, 399, - 57725, 400, 57726, 401, 57727, 402, 57728, 403, 57729, 404, - 57730, 405, 57731, 406, 57732, 407, 57733, 408, 57734, 409, - 57735, 410, 57736, 411, 57737, 412, 57738, 413, 57739, 414, - 57740, 415, 57741, 416, 57742, 417, 57743, 418, 57744, 419, - 57745, 420, 57746, 421, 57747, 422, 57748, 423, 57749, 424, - 57750, 425, 57751, 426, 57752, 427, 57753, 428, 57754, 429, - 57755, 430, 57756, 431, 57757, 432, 57758, 433, 57759, 434, - 57760, 435, 57761, 436, 57762, 437, 57763, 438, 57764, 439, - 57765, 440, 57766, 441, 57767, 442, 57768, 443, 57769, 444, - 57770, 445, 57771, 446, 57772, 447, 57773, 448, 57774, 449, - 57775, 450, 57776, 451, 57777, 452, 57778, 453, 57779, 454, - 57780, 455, 57781, 456, 57782, 457, 57783, 458, 57784, 459, - 57785, 460, 57786, 461, 57787, 462, 57788, 463, 57789, 464, - 57790, 465, 57791, 466, 57792, 467, 57793, 468, 57794, 469, - 57795, 470, 57796, 471, 57797, 472, 57798, 473, 57799, 474, - 57800, 475, 57801, 476, 57802, 477, 57803, 478, 57804, 479, - 57805, 480, 57806, 481, 57807, 482, 57808, 483, 57809, 484, - 57810, 485, 57811, 486, 57812, 487, 57813, 488, 57814, 489, - 57815, 490, 57816, 491, 57817, 492, 57818, 493, 57819, 494, - 57820, 495, 57821, 496, 57822, 497, 57823, 498, 57824, 499, - 57825, 500, 57826, 501, 57827, 502, 57828, 503, 57829, 504, - 57830, 505, 57831, 506, 57832, 507, 57833, 508, 57834, 509, - 57835, 510, 57836, 511, 57837, 512, 57838, 513, 57839, 514, - 57840, 515, 57841, 516, 57842, 517, 57843, 518, 57844, 519, - 57845, 520, 57846, 521, 57847, 522, 57848, 523, 57849, 524, - 57850, 525, 57851, 526, 57852, 527, 57853, 528, 57854, 529, - 57855, 530, 57856, 531, 57857, 532, 57858, 533, 57859, 534, - 57860, 535, 57861, 536, 57862, 537, 57863, 538, 57864, 539, - 57865, 540, 57866, 541, 57867, 542, 57868, 543, 57869, 544, - 57870, 545, 57871, 546, 57872, 547, 57873, 548, 57874, 549, - 57875, 550, 57876, 551, 57877, 552, 57878, 553, 57879, 554, - 57880, 555, 57881, 556, 57882, 557, 57883, 558, 57884, 559, - 57885, 560, 57886, 561, 57887, 562, 57888, 563, 57889, 564, - 57890, 565, 57891, 566, 57892, 567, 57893, 568, 57894, 569, - 57895, 570, 57896, 571, 57897, 572, 57898, 573, 57899, 574, - 57900, 575, 57901, 576, 57902, 577, 57903, 578, 57904, 579, - 57905, 580, 57906, 581, 57907, 582, 57908, 583, 57909, 584, - 57910, 585, 57911, 586, 57912, 587, 57913, 588, 57914, 589, - 57915, 590, 57916, 591, 57917, 592, 57918, 593, 57919, 594, - 57920, 595, 57921, 596, 57922, 597, 57923, 598, 57924, 599, - 57925, 600, 57926, 601, 57927, 602, 57928, 603, 57929, 604, - 57930, 605, 57931, 606, 57932, 607, 57933, 608, 57934, 609, - 57935, 610, 57936, 611, 57937, 612, 57938, 613, 57939, 614, - 57940, 615, 57941, 616, 57942, 617, 57943, 618, 57944, 619, - 57945, 620, 57946, 621, 57947, 622, 57948, 623, 57949, 624, - 57950, 625, 57951, 626, 57952, 627, 57953, 628, 57954, 629, - 57955, 630, 57956, 631, 57957, 632, 57958, 633, 57959, 634, - 57960, 635, 57961, 636, 57962, 637, 57963, 638, 57964, 639, - 57965, 640, 57966, 641, 57967, 642, 57968, 643, 57969, 644, - 57970, 645, 57971, 646, 57972, 647, 57973, 648, 57974, 649, - 57975, 650, 57976, 651, 57977, 652, 57978, 653, 57979, 654, - 57980, 655, 57981, 656, 57982, 657, 57983, 658, 57984, 659, - 57985, 660, 57986, 661, 57987, 662, 57988, 663, 57989, 664, - 57990, 665, 57991, 666, 57992, 667, 57993, 668, 57994, 669, - 57995, 670, 57996, 671, 57997, 672, 57998, 673, 57999, 674, - 58000, 675, 58001, 676, 58002, 677, 58003, 678, 58004, 679, - 58005, 680, 58006, 681, 58007, 682, 58008, 683, 58009, 684, - 58010, 685, 58011, 686, 58012, 687, 58013, 688, 58014, 689, - 58015, 690, 58016, 691, 58017, 692, 58018, 693, 58019, 694, - 58020, 695, 58021, 696, 58022, 697, 58023, 698, 58024, 699, - 58025, 700, 58026, 701, 58027, 702, 58028, 703, 58029, 704, - 58030, 705, 58031, 706, 58032, 707, 58033, 708, 58034, 709, - 58035, 710, 58036, 711, 58037, 712, 58038, 713, 58039, 714, - 58040, 715, 58041, 716, 58042, 717, 58043, 718, 58044, 719, - 58045, 720, 58046, 721, 58047, 722, 58048, 723, 58049, 724, - 58050, 725, 58051, 726, 58052, 727, 58053, 728, 58054, 729, - 58055, 730, 58056, 731, 58057, 732, 58058, 733, 58059, 734, - 58060, 735, 58061, 736, 58062, 737, 58063, 738, 58064, 739, - 58065, 740, 58066, 741, 58067, 742, 58068, 743, 58069, 744, - 58070, 745, 58071, 746, 58072, 747, 58073, 748, 58074, 749, - 58075, 750, 58076, 751, 58077, 752, 58078, 753, 58079, 754, - 58080, 755, 58081, 756, 58082, 757, 58083, 758, 58084, 759, - 58085, 760, 58086, 761, 58087, 762, 58088, 763, 58089, 764, - 58090, 765, 58091, 766, 58092, 767, 58093, 768, 58094, 769, - 58095, 770, 58096, 771, 58097, 772, 58098, 773, 58099, 774, - 58100, 775, 58101, 776, 58102, 777, 58103, 778, 58104, 779, - 58105, 780, 58106, 781, 58107, 782, 58108, 783, 58109, 784, - 58110, 785, 0, -} - -var yyErrorMessages = [...]struct { - state int - token int - msg string -}{} - -//line yaccpar:1 - -/* parser for yacc output */ - -func yyIaddr(v interface{}) __yyunsafe__.Pointer { - type h struct { - t __yyunsafe__.Pointer - p __yyunsafe__.Pointer - } - return (*h)(__yyunsafe__.Pointer(&v)).p -} - -var ( - yyDebug = 0 - yyErrorVerbose = false -) - -type yyLexer interface { - Lex(lval *yySymType) int - Error(s string) -} - -type yyParser interface { - Parse(yyLexer) int - Lookahead() int -} - -type yyParserImpl struct { - lval yySymType - stack [yyInitialStackSize]yySymType - char int -} - -func (p *yyParserImpl) Lookahead() int { - return p.char -} - -func yyNewParser() yyParser { - return &yyParserImpl{} -} - -const yyFlag = -1000 - -func yyTokname(c int) string { - if c >= 1 && c-1 < len(yyToknames) { - if yyToknames[c-1] != "" { - return yyToknames[c-1] - } - } - return __yyfmt__.Sprintf("tok-%v", c) -} - -func yyStatname(s int) string { - if s >= 0 && s < len(yyStatenames) { - if yyStatenames[s] != "" { - return yyStatenames[s] - } - } - return __yyfmt__.Sprintf("state-%v", s) -} - -func yyErrorMessage(state, lookAhead int) string { - const TOKSTART = 4 - - if !yyErrorVerbose { - return "syntax error" - } - - for _, e := range yyErrorMessages { - if e.state == state && e.token == lookAhead { - return "syntax error: " + e.msg - } - } - - res := "syntax error: unexpected " + yyTokname(lookAhead) - - // To match Bison, suggest at most four expected tokens. - expected := make([]int, 0, 4) - - // Look for shiftable tokens. - base := yyPact[state] - for tok := TOKSTART; tok-1 < len(yyToknames); tok++ { - if n := base + tok; n >= 0 && n < yyLast && yyChk[yyAct[n]] == tok { - if len(expected) == cap(expected) { - return res - } - expected = append(expected, tok) - } - } - - if yyDef[state] == -2 { - i := 0 - for yyExca[i] != -1 || yyExca[i+1] != state { - i += 2 - } - - // Look for tokens that we accept or reduce. - for i += 2; yyExca[i] >= 0; i += 2 { - tok := yyExca[i] - if tok < TOKSTART || yyExca[i+1] == 0 { - continue - } - if len(expected) == cap(expected) { - return res - } - expected = append(expected, tok) - } - - // If the default action is to accept or reduce, give up. - if yyExca[i+1] != 0 { - return res - } - } - - for i, tok := range expected { - if i == 0 { - res += ", expecting " - } else { - res += " or " - } - res += yyTokname(tok) - } - return res -} - -func yylex1(lex yyLexer, lval *yySymType) (char, token int) { - token = 0 - char = lex.Lex(lval) - if char <= 0 { - token = yyTok1[0] - goto out - } - if char < len(yyTok1) { - token = yyTok1[char] - goto out - } - if char >= yyPrivate { - if char < yyPrivate+len(yyTok2) { - token = yyTok2[char-yyPrivate] - goto out - } - } - for i := 0; i < len(yyTok3); i += 2 { - token = yyTok3[i+0] - if token == char { - token = yyTok3[i+1] - goto out - } - } - -out: - if token == 0 { - token = yyTok2[1] /* unknown char */ - } - if yyDebug >= 3 { - __yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char)) - } - return char, token -} - -func yyParse(yylex yyLexer) int { - return yyNewParser().Parse(yylex) -} - -func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int { - var yyn int - var yyVAL yySymType - var yyDollar []yySymType - _ = yyDollar // silence set and not used - yyS := yyrcvr.stack[:] - - Nerrs := 0 /* number of errors */ - Errflag := 0 /* error recovery flag */ - yystate := 0 - yyrcvr.char = -1 - yytoken := -1 // yyrcvr.char translated into internal numbering - defer func() { - // Make sure we report no lookahead when not parsing. - yystate = -1 - yyrcvr.char = -1 - yytoken = -1 - }() - yyp := -1 - goto yystack - -ret0: - return 0 - -ret1: - return 1 - -yystack: - /* put a state and value onto the stack */ - if yyDebug >= 4 { - __yyfmt__.Printf("char %v in %v\n", yyTokname(yytoken), yyStatname(yystate)) - } - - yyp++ - if yyp >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyS[yyp] = yyVAL - yyS[yyp].yys = yystate - -yynewstate: - yyn = yyPact[yystate] - if yyn <= yyFlag { - goto yydefault /* simple state */ - } - if yyrcvr.char < 0 { - yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval) - } - yyn += yytoken - if yyn < 0 || yyn >= yyLast { - goto yydefault - } - yyn = yyAct[yyn] - if yyChk[yyn] == yytoken { /* valid shift */ - yyrcvr.char = -1 - yytoken = -1 - yyVAL = yyrcvr.lval - yystate = yyn - if Errflag > 0 { - Errflag-- - } - goto yystack - } - -yydefault: - /* default state action */ - yyn = yyDef[yystate] - if yyn == -2 { - if yyrcvr.char < 0 { - yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval) - } - - /* look through exception table */ - xi := 0 - for { - if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { - break - } - xi += 2 - } - for xi += 2; ; xi += 2 { - yyn = yyExca[xi+0] - if yyn < 0 || yyn == yytoken { - break - } - } - yyn = yyExca[xi+1] - if yyn < 0 { - goto ret0 - } - } - if yyn == 0 { - /* error ... attempt to resume parsing */ - switch Errflag { - case 0: /* brand new error */ - yylex.Error(yyErrorMessage(yystate, yytoken)) - Nerrs++ - if yyDebug >= 1 { - __yyfmt__.Printf("%s", yyStatname(yystate)) - __yyfmt__.Printf(" saw %s\n", yyTokname(yytoken)) - } - fallthrough - - case 1, 2: /* incompletely recovered error ... try again */ - Errflag = 3 - - /* find a state where "error" is a legal shift action */ - for yyp >= 0 { - yyn = yyPact[yyS[yyp].yys] + yyErrCode - if yyn >= 0 && yyn < yyLast { - yystate = yyAct[yyn] /* simulate a shift of "error" */ - if yyChk[yystate] == yyErrCode { - goto yystack - } - } - - /* the current p has no shift on "error", pop stack */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) - } - yyp-- - } - /* there is no state on the stack with an error shift ... abort */ - goto ret1 - - case 3: /* no shift yet; clobber input char */ - if yyDebug >= 2 { - __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yytoken)) - } - if yytoken == yyEofCode { - goto ret1 - } - yyrcvr.char = -1 - yytoken = -1 - goto yynewstate /* try again in the same state */ - } - } - - /* reduction by production yyn */ - if yyDebug >= 2 { - __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) - } - - yynt := yyn - yypt := yyp - _ = yypt // guard against "declared and not used" - - yyp -= yyR2[yyn] - // yyp is now the index of $0. Perform the default action. Iff the - // reduced production is ε, $1 is possibly out of range. - if yyp+1 >= len(yyS) { - nyys := make([]yySymType, len(yyS)*2) - copy(nyys, yyS) - yyS = nyys - } - yyVAL = yyS[yyp+1] - - /* consult goto table to find next state */ - yyn = yyR1[yyn] - yyg := yyPgo[yyn] - yyj := yyg + yyS[yyp].yys + 1 - - if yyj >= yyLast { - yystate = yyAct[yyg] - } else { - yystate = yyAct[yyj] - if yyChk[yystate] != -yyn { - yystate = yyAct[yyg] - } - } - // dummy call; replaced with literal code - switch yynt { - - case 3: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:1177 - { - if yyDollar[1].statementUnion() != nil { - yylex.(*Lexer).AppendStmt(yyDollar[1].statementUnion()) - } - } - case 4: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:1183 - { - yylex.(*Lexer).AppendTopLevelSemicolon(yyDollar[2].pos) - if yyDollar[3].statementUnion() != nil { - yylex.(*Lexer).AppendStmt(yyDollar[3].statementUnion()) - } - } - case 5: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1192 - { - yyLOCAL = tree.NewCompoundStmt(yyDollar[2].statementsUnion()) - } - yyVAL.union = yyLOCAL - case 6: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.Statement -//line mysql_sql.y:1198 - { - yyLOCAL = []tree.Statement{yyDollar[1].statementUnion()} - } - yyVAL.union = yyLOCAL - case 7: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []tree.Statement -//line mysql_sql.y:1202 - { - yyLOCAL = append(yyDollar[1].statementsUnion(), yyDollar[3].statementUnion()) - } - yyVAL.union = yyLOCAL - case 17: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1217 - { - yyLOCAL = yyDollar[1].statementUnion() - } - yyVAL.union = yyLOCAL - case 18: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1221 - { - yyLOCAL = tree.Statement(nil) - } - yyVAL.union = yyLOCAL - case 19: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1227 - { - yyLOCAL = yyDollar[1].statementUnion() - } - yyVAL.union = yyLOCAL - case 20: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1231 - { - yyLOCAL = yyDollar[1].statementUnion() - } - yyVAL.union = yyLOCAL - case 22: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1236 - { - yyLOCAL = yyDollar[1].statementUnion() - } - yyVAL.union = yyLOCAL - case 23: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1240 - { - yyLOCAL = tree.Statement(nil) - } - yyVAL.union = yyLOCAL - case 58: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1280 - { - yyLOCAL = yyDollar[1].selectUnion() - } - yyVAL.union = yyLOCAL - case 69: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1296 - { - var timestamp = yyDollar[2].str - var isS3 = false - var dir = yyDollar[4].str - var parallelism = yyDollar[6].str - var option []string - var backuptype = yyDollar[7].str - var backupts = yyDollar[8].str - yyLOCAL = tree.NewBackupStart(timestamp, isS3, dir, parallelism, option, backuptype, backupts) - } - yyVAL.union = yyLOCAL - case 70: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1307 - { - var timestamp = yyDollar[2].str - var isS3 = true - var dir string - var parallelism string - var option = yyDollar[5].strsUnion() - var backuptype = yyDollar[7].str - var backupts = yyDollar[8].str - yyLOCAL = tree.NewBackupStart(timestamp, isS3, dir, parallelism, option, backuptype, backupts) - } - yyVAL.union = yyLOCAL - case 71: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:1319 - { - yyVAL.str = "" - } - case 72: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:1323 - { - yyVAL.str = yyDollar[2].str - } - case 73: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:1328 - { - yyVAL.str = "" - } - case 74: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:1332 - { - yyVAL.str = yyDollar[2].str - } - case 75: - yyDollar = yyS[yypt-12 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1338 - { - yyLOCAL = &tree.CreateCDC{ - IfNotExists: yyDollar[3].ifNotExistsUnion(), - TaskName: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - SourceUri: yyDollar[5].str, - SinkType: yyDollar[6].str, - SinkUri: yyDollar[7].str, - Tables: yyDollar[8].str, - Option: yyDollar[10].strsUnion(), - Internal: yyDollar[12].boolValUnion(), - } - } - yyVAL.union = yyLOCAL - case 76: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:1353 - { - yyLOCAL = yyDollar[1].strsUnion() - } - yyVAL.union = yyLOCAL - case 77: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:1357 - { - yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].strsUnion()...) - } - yyVAL.union = yyLOCAL - case 78: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:1361 - { - yyLOCAL = []string{} - } - yyVAL.union = yyLOCAL - case 79: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:1365 - { - yyLOCAL = append(yyLOCAL, yyDollar[1].str) - yyLOCAL = append(yyLOCAL, yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 80: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1372 - { - yyLOCAL = &tree.ShowCDC{ - Option: yyDollar[3].allCDCOptionUnion(), - } - } - yyVAL.union = yyLOCAL - case 81: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1380 - { - yyLOCAL = &tree.PauseCDC{ - Option: yyDollar[3].allCDCOptionUnion(), - } - } - yyVAL.union = yyLOCAL - case 82: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1388 - { - yyLOCAL = tree.NewDropCDC(yyDollar[4].allCDCOptionUnion(), yyDollar[3].boolValUnion(), yyDollar[5].boolValUnion()) - } - yyVAL.union = yyLOCAL - case 83: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.AllOrNotCDC -//line mysql_sql.y:1393 - { - yyLOCAL = &tree.AllOrNotCDC{ - All: true, - TaskName: "", - } - } - yyVAL.union = yyLOCAL - case 84: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.AllOrNotCDC -//line mysql_sql.y:1400 - { - yyLOCAL = yyDollar[1].allCDCOptionUnion() - } - yyVAL.union = yyLOCAL - case 85: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.AllOrNotCDC -//line mysql_sql.y:1406 - { - yyLOCAL = yyDollar[1].allCDCOptionUnion() - } - yyVAL.union = yyLOCAL - case 86: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.AllOrNotCDC -//line mysql_sql.y:1411 - { - yyLOCAL = &tree.AllOrNotCDC{ - All: false, - TaskName: tree.Identifier(yyDollar[1].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 87: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.AllOrNotCDC -//line mysql_sql.y:1420 - { - yyLOCAL = &tree.AllOrNotCDC{ - All: true, - TaskName: "", - } - } - yyVAL.union = yyLOCAL - case 88: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.AllOrNotCDC -//line mysql_sql.y:1427 - { - yyLOCAL = &tree.AllOrNotCDC{ - All: false, - TaskName: tree.Identifier(yyDollar[2].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 89: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1436 - { - yyLOCAL = &tree.ResumeCDC{ - TaskName: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 90: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1444 - { - yyLOCAL = &tree.RestartCDC{ - TaskName: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 91: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1452 - { - yyLOCAL = &tree.CreateSnapShot{ - IfNotExists: yyDollar[3].ifNotExistsUnion(), - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Object: yyDollar[6].snapshotObjectUnion(), - } - } - yyVAL.union = yyLOCAL - case 92: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ObjectInfo -//line mysql_sql.y:1462 - { - spLevel := tree.SnapshotLevelType{ - Level: tree.SNAPSHOTLEVELCLUSTER, - } - yyLOCAL = tree.ObjectInfo{ - SLevel: spLevel, - ObjName: "", - } - } - yyVAL.union = yyLOCAL - case 93: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ObjectInfo -//line mysql_sql.y:1472 - { - spLevel := tree.SnapshotLevelType{ - Level: tree.SNAPSHOTLEVELACCOUNT, - } - yyLOCAL = tree.ObjectInfo{ - SLevel: spLevel, - ObjName: tree.Identifier(yyDollar[2].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 94: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ObjectInfo -//line mysql_sql.y:1482 - { - spLevel := tree.SnapshotLevelType{ - Level: tree.SNAPSHOTLEVELACCOUNT, - } - yyLOCAL = tree.ObjectInfo{ - SLevel: spLevel, - ObjName: tree.Identifier(""), - } - } - yyVAL.union = yyLOCAL - case 95: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ObjectInfo -//line mysql_sql.y:1492 - { - spLevel := tree.SnapshotLevelType{ - Level: tree.SNAPSHOTLEVELDATABASE, - } - yyLOCAL = tree.ObjectInfo{ - SLevel: spLevel, - ObjName: tree.Identifier(yyDollar[2].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 96: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.ObjectInfo -//line mysql_sql.y:1502 - { - spLevel := tree.SnapshotLevelType{ - Level: tree.SNAPSHOTLEVELTABLE, - } - yyLOCAL = tree.ObjectInfo{ - SLevel: spLevel, - ObjName: tree.Identifier(yyDollar[2].cstrUnion().Compare() + "." + yyDollar[3].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 97: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.ObjectInfo -//line mysql_sql.y:1512 - { - spLevel := tree.SnapshotLevelType{ - Level: tree.SNAPSHOTLEVELTABLE, - } - yyLOCAL = tree.ObjectInfo{ - SLevel: spLevel, - ObjName: tree.Identifier(yyDollar[2].cstrUnion().Compare() + "." + yyDollar[3].cstrUnion().Compare()), - AccountName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - PubName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 98: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.ObjectInfo -//line mysql_sql.y:1524 - { - spLevel := tree.SnapshotLevelType{ - Level: tree.SNAPSHOTLEVELDATABASE, - } - yyLOCAL = tree.ObjectInfo{ - SLevel: spLevel, - ObjName: tree.Identifier(yyDollar[2].cstrUnion().Compare()), - AccountName: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - PubName: tree.Identifier(yyDollar[6].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 99: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.ObjectInfo -//line mysql_sql.y:1536 - { - spLevel := tree.SnapshotLevelType{ - Level: tree.SNAPSHOTLEVELACCOUNT, - } - yyLOCAL = tree.ObjectInfo{ - SLevel: spLevel, - AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - PubName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 100: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1549 - { - yyLOCAL = &tree.CreatePitr{ - IfNotExists: yyDollar[3].ifNotExistsUnion(), - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Level: tree.PITRLEVELACCOUNT, - PitrValue: yyDollar[8].int64ValUnion(), - PitrUnit: yyDollar[9].str, - Internal: yyDollar[10].boolValUnion(), - } - } - yyVAL.union = yyLOCAL - case 101: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1560 - { - yyLOCAL = &tree.CreatePitr{ - IfNotExists: yyDollar[3].ifNotExistsUnion(), - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Level: tree.PITRLEVELCLUSTER, - PitrValue: yyDollar[8].int64ValUnion(), - PitrUnit: yyDollar[9].str, - Internal: yyDollar[10].boolValUnion(), - } - } - yyVAL.union = yyLOCAL - case 102: - yyDollar = yyS[yypt-11 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1571 - { - yyLOCAL = &tree.CreatePitr{ - IfNotExists: yyDollar[3].ifNotExistsUnion(), - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Level: tree.PITRLEVELACCOUNT, - AccountName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), - PitrValue: yyDollar[9].int64ValUnion(), - PitrUnit: yyDollar[10].str, - Internal: yyDollar[11].boolValUnion(), - } - } - yyVAL.union = yyLOCAL - case 103: - yyDollar = yyS[yypt-11 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1583 - { - yyLOCAL = &tree.CreatePitr{ - IfNotExists: yyDollar[3].ifNotExistsUnion(), - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Level: tree.PITRLEVELDATABASE, - DatabaseName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), - PitrValue: yyDollar[9].int64ValUnion(), - PitrUnit: yyDollar[10].str, - Internal: yyDollar[11].boolValUnion(), - } - } - yyVAL.union = yyLOCAL - case 104: - yyDollar = yyS[yypt-12 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1595 - { - yyLOCAL = &tree.CreatePitr{ - IfNotExists: yyDollar[3].ifNotExistsUnion(), - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Level: tree.PITRLEVELTABLE, - DatabaseName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), - TableName: tree.Identifier(yyDollar[8].cstrUnion().Compare()), - PitrValue: yyDollar[10].int64ValUnion(), - PitrUnit: yyDollar[11].str, - Internal: yyDollar[12].boolValUnion(), - } - } - yyVAL.union = yyLOCAL - case 105: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1608 - { - yyLOCAL = &tree.CreatePitr{ - IfNotExists: yyDollar[3].ifNotExistsUnion(), - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Level: tree.PITRLEVELACCOUNT, - PitrValue: yyDollar[6].int64ValUnion(), - PitrUnit: yyDollar[7].str, - Internal: yyDollar[8].boolValUnion(), - } - } - yyVAL.union = yyLOCAL - case 106: - yyDollar = yyS[yypt-13 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1619 - { - yyLOCAL = &tree.CreatePitr{ - IfNotExists: yyDollar[3].ifNotExistsUnion(), - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Level: tree.PITRLEVELTABLE, - DatabaseName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), - TableName: tree.Identifier(yyDollar[9].cstrUnion().Compare()), - PitrValue: yyDollar[11].int64ValUnion(), - PitrUnit: yyDollar[12].str, - Internal: yyDollar[13].boolValUnion(), - } - } - yyVAL.union = yyLOCAL - case 107: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:1634 - { - value, ok := signedIntegral(yylex, yyDollar[1].item) - if !ok { - goto ret1 - } - yyLOCAL = value - } - yyVAL.union = yyLOCAL - case 108: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1643 - { - var account tree.Identifier - var database tree.Identifier - switch len(yyDollar[3].identifierListUnion()) { - case 1: - database = yyDollar[3].identifierListUnion()[0] - case 2: - account = yyDollar[3].identifierListUnion()[0] - database = yyDollar[3].identifierListUnion()[1] - default: - yylex.Error("invalid restore database target") - goto ret1 - } - - snapshotName := tree.Identifier(yyDollar[4].str) - result := &tree.RestoreSnapShot{ - Level: tree.RESTORELEVELDATABASE, - DatabaseName: database, - SnapShotName: snapshotName, - } - - if len(account) > 0 { - result.AccountName = account - } - - if len(yyDollar[5].str) > 0 { - result.ToAccountName = tree.Identifier(yyDollar[5].str) - } - - yyLOCAL = result - } - yyVAL.union = yyLOCAL - case 109: - yyDollar = yyS[yypt-6 : yypt+1] -//line mysql_sql.y:1675 - { - yylex.Error(restoreSnapshotFromSyntaxHint) - goto ret1 - } - case 110: - yyDollar = yyS[yypt-8 : yypt+1] -//line mysql_sql.y:1680 - { - yylex.Error(restoreSnapshotFromSyntaxHint) - goto ret1 - } - case 111: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1685 - { - var account tree.Identifier - var database tree.Identifier - var table tree.Identifier - - switch len(yyDollar[3].identifierListUnion()) { - case 2: - database = yyDollar[3].identifierListUnion()[0] - table = yyDollar[3].identifierListUnion()[1] - case 3: - account = yyDollar[3].identifierListUnion()[0] - database = yyDollar[3].identifierListUnion()[1] - table = yyDollar[3].identifierListUnion()[2] - default: - yylex.Error("invalid restore table target") - goto ret1 - } - - snapshotName := tree.Identifier(yyDollar[4].str) - result := &tree.RestoreSnapShot{ - Level: tree.RESTORELEVELTABLE, - DatabaseName: database, - TableName: table, - SnapShotName: snapshotName, - } - - if len(account) > 0 { - result.AccountName = account - } - - if len(yyDollar[5].str) > 0 { - result.ToAccountName = tree.Identifier(yyDollar[5].str) - } - - yyLOCAL = result - } - yyVAL.union = yyLOCAL - case 112: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1722 - { - yyLOCAL = &tree.RestoreSnapShot{ - Level: tree.RESTORELEVELCLUSTER, - SnapShotName: tree.Identifier(yyDollar[3].str), - } - } - yyVAL.union = yyLOCAL - case 113: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1729 - { - result := &tree.RestoreSnapShot{ - Level: tree.RESTORELEVELACCOUNT, - AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - SnapShotName: tree.Identifier(yyDollar[4].str), - } - - if len(yyDollar[5].str) > 0 { - result.ToAccountName = tree.Identifier(yyDollar[5].str) - } - - yyLOCAL = result - } - yyVAL.union = yyLOCAL - case 114: - yyDollar = yyS[yypt-8 : yypt+1] -//line mysql_sql.y:1743 - { - yylex.Error(restoreSnapshotFromSyntaxHint) - goto ret1 - } - case 115: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:1750 - { - yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 116: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:1754 - { - yyLOCAL = tree.IdentifierList{ - tree.Identifier(yyDollar[1].cstrUnion().Compare()), - tree.Identifier(yyDollar[3].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 117: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:1763 - { - yyLOCAL = tree.IdentifierList{ - tree.Identifier(yyDollar[1].cstrUnion().Compare()), - tree.Identifier(yyDollar[3].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 118: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:1770 - { - yyLOCAL = tree.IdentifierList{ - tree.Identifier(yyDollar[1].cstrUnion().Compare()), - tree.Identifier(yyDollar[3].cstrUnion().Compare()), - tree.Identifier(yyDollar[5].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 119: - yyDollar = yyS[yypt-5 : yypt+1] -//line mysql_sql.y:1780 - { - yyVAL.str = yyDollar[4].cstrUnion().Compare() - } - case 120: - yyDollar = yyS[yypt-5 : yypt+1] -//line mysql_sql.y:1784 - { - yyVAL.str = strings.ToLower(yyDollar[4].str) - } - case 121: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:1790 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 122: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:1794 - { - yyVAL.str = yyDollar[1].str - } - case 123: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:1799 - { - yyVAL.str = "" - } - case 124: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:1803 - { - yyVAL.str = yyDollar[3].cstrUnion().Compare() - } - case 125: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1809 - { - yyLOCAL = &tree.RestorePitr{ - Level: tree.RESTORELEVELACCOUNT, - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - TimeStamp: yyDollar[5].str, - } - } - yyVAL.union = yyLOCAL - case 126: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1817 - { - yyLOCAL = &tree.RestorePitr{ - Level: tree.RESTORELEVELDATABASE, - DatabaseName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - Name: tree.Identifier(yyDollar[6].cstrUnion().Compare()), - TimeStamp: yyDollar[7].str, - } - } - yyVAL.union = yyLOCAL - case 127: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1826 - { - yyLOCAL = &tree.RestorePitr{ - Level: tree.RESTORELEVELDATABASE, - AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - DatabaseName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - Name: tree.Identifier(yyDollar[8].cstrUnion().Compare()), - TimeStamp: yyDollar[9].str, - } - } - yyVAL.union = yyLOCAL - case 128: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1836 - { - yyLOCAL = &tree.RestorePitr{ - Level: tree.RESTORELEVELTABLE, - DatabaseName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - TableName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - Name: tree.Identifier(yyDollar[8].cstrUnion().Compare()), - TimeStamp: yyDollar[9].str, - } - } - yyVAL.union = yyLOCAL - case 129: - yyDollar = yyS[yypt-11 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1846 - { - yyLOCAL = &tree.RestorePitr{ - Level: tree.RESTORELEVELTABLE, - AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - DatabaseName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - TableName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), - Name: tree.Identifier(yyDollar[10].cstrUnion().Compare()), - TimeStamp: yyDollar[11].str, - } - } - yyVAL.union = yyLOCAL - case 130: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1857 - { - yyLOCAL = &tree.RestorePitr{ - Level: tree.RESTORELEVELACCOUNT, - AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - Name: tree.Identifier(yyDollar[6].cstrUnion().Compare()), - TimeStamp: yyDollar[7].str, - SrcAccountName: tree.Identifier(yyDollar[8].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 131: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1867 - { - yyLOCAL = &tree.RestorePitr{ - Level: tree.RESTORELEVELCLUSTER, - Name: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - TimeStamp: yyDollar[6].str, - } - } - yyVAL.union = yyLOCAL - case 132: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1877 - { - var connectionId uint64 - switch v := yyDollar[3].item.(type) { - case uint64: - connectionId = v - case int64: - connectionId = uint64(v) - default: - yylex.Error("parse integral fail") - goto ret1 - } - - yyLOCAL = &tree.Kill{ - Option: yyDollar[2].killOptionUnion(), - ConnectionId: connectionId, - StmtOption: yyDollar[4].statementOptionUnion(), - } - } - yyVAL.union = yyLOCAL - case 133: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.KillOption -//line mysql_sql.y:1897 - { - yyLOCAL = tree.KillOption{ - Exist: false, - } - } - yyVAL.union = yyLOCAL - case 134: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.KillOption -//line mysql_sql.y:1903 - { - yyLOCAL = tree.KillOption{ - Exist: true, - Typ: tree.KillTypeConnection, - } - } - yyVAL.union = yyLOCAL - case 135: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.KillOption -//line mysql_sql.y:1910 - { - yyLOCAL = tree.KillOption{ - Exist: true, - Typ: tree.KillTypeQuery, - } - } - yyVAL.union = yyLOCAL - case 136: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.StatementOption -//line mysql_sql.y:1918 - { - yyLOCAL = tree.StatementOption{ - Exist: false, - } - } - yyVAL.union = yyLOCAL - case 137: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.StatementOption -//line mysql_sql.y:1924 - { - yyLOCAL = tree.StatementOption{ - Exist: true, - StatementId: yyDollar[1].str, - } - } - yyVAL.union = yyLOCAL - case 138: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1933 - { - yyLOCAL = &tree.CallStmt{ - Name: yyDollar[2].procNameUnion(), - Args: yyDollar[4].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 139: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1942 - { - yyLOCAL = &tree.LeaveStmt{ - Name: tree.Identifier(yyDollar[2].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 140: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1950 - { - yyLOCAL = &tree.IterateStmt{ - Name: tree.Identifier(yyDollar[2].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 141: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1958 - { - yyLOCAL = &tree.WhileStmt{ - Name: "", - Cond: yyDollar[2].exprUnion(), - Body: yyDollar[4].statementsUnion(), - } - } - yyVAL.union = yyLOCAL - case 142: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1966 - { - yyLOCAL = &tree.WhileStmt{ - Name: tree.Identifier(yyDollar[1].cstrUnion().Compare()), - Cond: yyDollar[4].exprUnion(), - Body: yyDollar[6].statementsUnion(), - } - } - yyVAL.union = yyLOCAL - case 143: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1976 - { - yyLOCAL = &tree.RepeatStmt{ - Name: "", - Body: yyDollar[2].statementsUnion(), - Cond: yyDollar[4].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 144: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1984 - { - yyLOCAL = &tree.RepeatStmt{ - Name: tree.Identifier(yyDollar[1].cstrUnion().Compare()), - Body: yyDollar[4].statementsUnion(), - Cond: yyDollar[6].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 145: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:1994 - { - yyLOCAL = &tree.LoopStmt{ - Name: "", - Body: yyDollar[2].statementsUnion(), - } - } - yyVAL.union = yyLOCAL - case 146: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2001 - { - yyLOCAL = &tree.LoopStmt{ - Name: tree.Identifier(yyDollar[1].cstrUnion().Compare()), - Body: yyDollar[4].statementsUnion(), - } - } - yyVAL.union = yyLOCAL - case 147: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2010 - { - yyLOCAL = &tree.IfStmt{ - Cond: yyDollar[2].exprUnion(), - Body: yyDollar[4].statementsUnion(), - Elifs: yyDollar[5].elseIfClauseListUnion(), - Else: yyDollar[6].statementsUnion(), - } - } - yyVAL.union = yyLOCAL - case 148: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []*tree.ElseIfStmt -//line mysql_sql.y:2020 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 149: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.ElseIfStmt -//line mysql_sql.y:2024 - { - yyLOCAL = yyDollar[1].elseIfClauseListUnion() - } - yyVAL.union = yyLOCAL - case 150: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.ElseIfStmt -//line mysql_sql.y:2030 - { - yyLOCAL = []*tree.ElseIfStmt{yyDollar[1].elseIfClauseUnion()} - } - yyVAL.union = yyLOCAL - case 151: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []*tree.ElseIfStmt -//line mysql_sql.y:2034 - { - yyLOCAL = append(yyDollar[1].elseIfClauseListUnion(), yyDollar[2].elseIfClauseUnion()) - } - yyVAL.union = yyLOCAL - case 152: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.ElseIfStmt -//line mysql_sql.y:2040 - { - yyLOCAL = &tree.ElseIfStmt{ - Cond: yyDollar[2].exprUnion(), - Body: yyDollar[4].statementsUnion(), - } - } - yyVAL.union = yyLOCAL - case 153: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2049 - { - yyLOCAL = &tree.CaseStmt{ - Expr: yyDollar[2].exprUnion(), - Whens: yyDollar[3].whenClauseList2Union(), - Else: yyDollar[4].statementsUnion(), - } - } - yyVAL.union = yyLOCAL - case 154: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.WhenStmt -//line mysql_sql.y:2059 - { - yyLOCAL = []*tree.WhenStmt{yyDollar[1].whenClause2Union()} - } - yyVAL.union = yyLOCAL - case 155: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []*tree.WhenStmt -//line mysql_sql.y:2063 - { - yyLOCAL = append(yyDollar[1].whenClauseList2Union(), yyDollar[2].whenClause2Union()) - } - yyVAL.union = yyLOCAL - case 156: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.WhenStmt -//line mysql_sql.y:2069 - { - yyLOCAL = &tree.WhenStmt{ - Cond: yyDollar[2].exprUnion(), - Body: yyDollar[4].statementsUnion(), - } - } - yyVAL.union = yyLOCAL - case 157: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []tree.Statement -//line mysql_sql.y:2078 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 158: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []tree.Statement -//line mysql_sql.y:2082 - { - yyLOCAL = yyDollar[2].statementsUnion() - } - yyVAL.union = yyLOCAL - case 159: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2088 - { - ep := &tree.ExportParam{ - Outfile: true, - QueryId: yyDollar[3].str, - FilePath: yyDollar[5].str, - Fields: yyDollar[6].fieldsUnion(), - Lines: yyDollar[7].linesUnion(), - Header: yyDollar[8].unsignedOptUnion(), - MaxFileSize: uint64(yyDollar[9].int64ValUnion()) * 1024, - ForceQuote: yyDollar[10].strsUnion(), - } - yyLOCAL = &tree.MoDump{ - ExportParams: ep, - } - } - yyVAL.union = yyLOCAL - case 160: - yyDollar = yyS[yypt-11 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2106 - { - yyLOCAL = &tree.Load{ - Local: yyDollar[3].boolValUnion(), - Param: yyDollar[4].loadParamUnion(), - DuplicateHandling: yyDollar[5].duplicateKeyUnion(), - Table: yyDollar[8].tableNameUnion(), - } - yyLOCAL.(*tree.Load).Param.Tail = yyDollar[9].tailParamUnion() - setLoadParallelOption(yyLOCAL.(*tree.Load).Param, yyDollar[10].int64ValUnion()) - yyLOCAL.(*tree.Load).Param.Strict = yyDollar[11].unsignedOptUnion() - } - yyVAL.union = yyLOCAL - case 161: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2120 - { - yyLOCAL = &tree.DumpTable{Table: yyDollar[3].tableNameUnion(), Path: yyDollar[5].str} - } - yyVAL.union = yyLOCAL - case 162: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2124 - { - yyLOCAL = &tree.DumpTable{Table: yyDollar[3].tableNameUnion(), Path: yyDollar[5].str, MetadataOnly: true} - } - yyVAL.union = yyLOCAL - case 163: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2130 - { - yyLOCAL = &tree.LoadTable{Table: yyDollar[3].tableNameUnion(), Path: yyDollar[5].str} - } - yyVAL.union = yyLOCAL - case 164: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2136 - { - yyLOCAL = &tree.LoadExtension{ - Name: tree.Identifier(yyDollar[2].str), - } - } - yyVAL.union = yyLOCAL - case 165: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.UpdateExprs -//line mysql_sql.y:2143 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 166: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.UpdateExprs -//line mysql_sql.y:2147 - { - yyLOCAL = yyDollar[2].updateExprsUnion() - } - yyVAL.union = yyLOCAL - case 167: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.UpdateExprs -//line mysql_sql.y:2153 - { - yyLOCAL = tree.UpdateExprs{yyDollar[1].updateExprUnion()} - } - yyVAL.union = yyLOCAL - case 168: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.UpdateExprs -//line mysql_sql.y:2157 - { - yyLOCAL = append(yyDollar[1].updateExprsUnion(), yyDollar[3].updateExprUnion()) - } - yyVAL.union = yyLOCAL - case 169: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.UpdateExpr -//line mysql_sql.y:2163 - { - yyLOCAL = &tree.UpdateExpr{ - Names: []*tree.UnresolvedName{yyDollar[1].unresolvedNameUnion()}, - Expr: &tree.DefaultVal{}, - } - } - yyVAL.union = yyLOCAL - case 170: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.UpdateExpr -//line mysql_sql.y:2170 - { - yyLOCAL = &tree.UpdateExpr{ - Names: []*tree.UnresolvedName{yyDollar[1].unresolvedNameUnion()}, - Expr: yyDollar[3].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 171: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:2178 - { - yyLOCAL = -1 - } - yyVAL.union = yyLOCAL - case 172: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:2182 - { - str := strings.ToLower(yyDollar[2].str) - if str == "true" { - yyLOCAL = 1 - } else if str == "false" { - yyLOCAL = 0 - } else { - yylex.Error("error strict flag") - goto ret1 - } - } - yyVAL.union = yyLOCAL - case 173: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:2194 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 174: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:2198 - { - str := strings.ToLower(yyDollar[2].str) - if str == "true" { - yyLOCAL = true - } else if str == "false" { - yyLOCAL = false - } else { - yylex.Error("error parallel flag") - goto ret1 - } - } - yyVAL.union = yyLOCAL - case 175: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:2212 - { - yyLOCAL = tree.NewUnresolvedName(yyDollar[1].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 176: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:2216 - { - tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedName(tblNameCStr, yyDollar[3].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 177: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:2221 - { - dbNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) - tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[3].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedName(dbNameCStr, tblNameCStr, yyDollar[5].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 178: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []tree.LoadColumn -//line mysql_sql.y:2228 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 179: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []tree.LoadColumn -//line mysql_sql.y:2232 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 180: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []tree.LoadColumn -//line mysql_sql.y:2236 - { - yyLOCAL = yyDollar[2].loadColumnsUnion() - } - yyVAL.union = yyLOCAL - case 181: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.LoadColumn -//line mysql_sql.y:2242 - { - switch yyDollar[1].loadColumnUnion().(type) { - case *tree.UnresolvedName: - yyLOCAL = []tree.LoadColumn{yyDollar[1].loadColumnUnion().(*tree.UnresolvedName)} - case *tree.VarExpr: - yyLOCAL = []tree.LoadColumn{yyDollar[1].loadColumnUnion().(*tree.VarExpr)} - } - } - yyVAL.union = yyLOCAL - case 182: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []tree.LoadColumn -//line mysql_sql.y:2251 - { - switch yyDollar[3].loadColumnUnion().(type) { - case *tree.UnresolvedName: - yyLOCAL = append(yyDollar[1].loadColumnsUnion(), yyDollar[3].loadColumnUnion().(*tree.UnresolvedName)) - case *tree.VarExpr: - yyLOCAL = append(yyDollar[1].loadColumnsUnion(), yyDollar[3].loadColumnUnion().(*tree.VarExpr)) - } - } - yyVAL.union = yyLOCAL - case 183: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.LoadColumn -//line mysql_sql.y:2262 - { - yyLOCAL = yyDollar[1].unresolvedNameUnion() - } - yyVAL.union = yyLOCAL - case 184: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.LoadColumn -//line mysql_sql.y:2266 - { - yyLOCAL = yyDollar[1].varExprUnion() - } - yyVAL.union = yyLOCAL - case 185: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.VarExpr -//line mysql_sql.y:2272 - { - yyLOCAL = []*tree.VarExpr{yyDollar[1].varExprUnion()} - } - yyVAL.union = yyLOCAL - case 186: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.VarExpr -//line mysql_sql.y:2276 - { - yyLOCAL = append(yyDollar[1].varExprsUnion(), yyDollar[3].varExprUnion()) - } - yyVAL.union = yyLOCAL - case 187: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.VarExpr -//line mysql_sql.y:2282 - { - yyLOCAL = []*tree.VarExpr{yyDollar[1].varExprUnion()} - } - yyVAL.union = yyLOCAL - case 188: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.VarExpr -//line mysql_sql.y:2286 - { - yyLOCAL = append(yyDollar[1].varExprsUnion(), yyDollar[3].varExprUnion()) - } - yyVAL.union = yyLOCAL - case 189: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.VarExpr -//line mysql_sql.y:2292 - { - yyLOCAL = yyDollar[1].varExprUnion() - } - yyVAL.union = yyLOCAL - case 190: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.VarExpr -//line mysql_sql.y:2296 - { - yyLOCAL = yyDollar[1].varExprUnion() - } - yyVAL.union = yyLOCAL - case 191: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.VarExpr -//line mysql_sql.y:2302 - { - v := strings.ToLower(yyDollar[1].str) - var isGlobal bool - if strings.HasPrefix(v, "global.") { - isGlobal = true - v = strings.TrimPrefix(v, "global.") - } else if strings.HasPrefix(v, "session.") { - v = strings.TrimPrefix(v, "session.") - } else if strings.HasPrefix(v, "local.") { - v = strings.TrimPrefix(v, "local.") - } - yyLOCAL = &tree.VarExpr{ - Name: v, - System: true, - Global: isGlobal, - } - } - yyVAL.union = yyLOCAL - case 192: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.VarExpr -//line mysql_sql.y:2322 - { - // vs := strings.Split($1, ".") - // var r string - // if len(vs) == 2 { - // r = vs[1] - // } else if len(vs) == 1 { - // r = vs[0] - // } else { - // yylex.Error("variable syntax error") - // goto ret1 - // } - yyLOCAL = &tree.VarExpr{ - Name: yyDollar[1].str, - System: false, - Global: false, - } - } - yyVAL.union = yyLOCAL - case 193: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:2341 - { - yyLOCAL = 0 - } - yyVAL.union = yyLOCAL - case 194: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:2345 - { - value, ok := signedIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - yyLOCAL = value - } - yyVAL.union = yyLOCAL - case 195: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:2351 - { - value, ok := signedIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - yyLOCAL = value - } - yyVAL.union = yyLOCAL - case 196: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.Lines -//line mysql_sql.y:2358 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 197: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.Lines -//line mysql_sql.y:2362 - { - yyLOCAL = &tree.Lines{ - StartingBy: yyDollar[2].str, - TerminatedBy: &tree.Terminated{ - Value: yyDollar[3].str, - }, - } - } - yyVAL.union = yyLOCAL - case 198: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.Lines -//line mysql_sql.y:2371 - { - yyLOCAL = &tree.Lines{ - StartingBy: yyDollar[3].str, - TerminatedBy: &tree.Terminated{ - Value: yyDollar[2].str, - }, - } - } - yyVAL.union = yyLOCAL - case 199: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:2381 - { - yyVAL.str = "" - } - case 201: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:2388 - { - yyVAL.str = yyDollar[3].str - } - case 202: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:2393 - { - yyVAL.str = "\n" - } - case 204: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:2400 - { - yyVAL.str = yyDollar[3].str - } - case 205: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.Fields -//line mysql_sql.y:2405 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 206: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.Fields -//line mysql_sql.y:2409 - { - res := &tree.Fields{ - Terminated: &tree.Terminated{ - Value: "\t", - }, - EnclosedBy: &tree.EnclosedBy{ - Value: byte(0), - }, - } - for _, f := range yyDollar[2].fieldsListUnion() { - if f.Terminated != nil { - res.Terminated = f.Terminated - } - if f.Optionally { - res.Optionally = f.Optionally - } - if f.EnclosedBy != nil { - res.EnclosedBy = f.EnclosedBy - } - if f.EscapedBy != nil { - res.EscapedBy = f.EscapedBy - } - } - yyLOCAL = res - } - yyVAL.union = yyLOCAL - case 207: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.Fields -//line mysql_sql.y:2437 - { - yyLOCAL = []*tree.Fields{yyDollar[1].fieldsUnion()} - } - yyVAL.union = yyLOCAL - case 208: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []*tree.Fields -//line mysql_sql.y:2441 - { - yyLOCAL = append(yyDollar[1].fieldsListUnion(), yyDollar[2].fieldsUnion()) - } - yyVAL.union = yyLOCAL - case 209: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.Fields -//line mysql_sql.y:2447 - { - yyLOCAL = &tree.Fields{ - Terminated: &tree.Terminated{ - Value: yyDollar[3].str, - }, - } - } - yyVAL.union = yyLOCAL - case 210: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Fields -//line mysql_sql.y:2455 - { - str := yyDollar[4].str - if str != "\\" && len(str) > 1 { - yylex.Error("error field terminator") - goto ret1 - } - var b byte - if len(str) != 0 { - b = byte(str[0]) - } else { - b = 0 - } - yyLOCAL = &tree.Fields{ - Optionally: true, - EnclosedBy: &tree.EnclosedBy{ - Value: b, - }, - } - } - yyVAL.union = yyLOCAL - case 211: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.Fields -//line mysql_sql.y:2475 - { - str := yyDollar[3].str - if str != "\\" && len(str) > 1 { - yylex.Error("error field terminator") - goto ret1 - } - var b byte - if len(str) != 0 { - b = byte(str[0]) - } else { - b = 0 - } - yyLOCAL = &tree.Fields{ - EnclosedBy: &tree.EnclosedBy{ - Value: b, - }, - } - } - yyVAL.union = yyLOCAL - case 212: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.Fields -//line mysql_sql.y:2494 - { - str := yyDollar[3].str - if str != "\\" && len(str) > 1 { - yylex.Error("error field terminator") - goto ret1 - } - var b byte - if len(str) != 0 { - b = byte(str[0]) - } else { - b = 0 - } - yyLOCAL = &tree.Fields{ - EscapedBy: &tree.EscapedBy{ - Value: b, - }, - } - } - yyVAL.union = yyLOCAL - case 214: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.DuplicateKey -//line mysql_sql.y:2519 - { - yyLOCAL = &tree.DuplicateKeyError{} - } - yyVAL.union = yyLOCAL - case 215: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.DuplicateKey -//line mysql_sql.y:2523 - { - yyLOCAL = &tree.DuplicateKeyIgnore{} - } - yyVAL.union = yyLOCAL - case 216: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.DuplicateKey -//line mysql_sql.y:2527 - { - yyLOCAL = &tree.DuplicateKeyReplace{} - } - yyVAL.union = yyLOCAL - case 217: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:2532 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 218: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:2536 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 219: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2542 - { - yyLOCAL = &tree.Grant{ - Typ: tree.GrantTypePrivilege, - GrantPrivilege: tree.GrantPrivilege{ - Privileges: yyDollar[2].privilegesUnion(), - ObjType: yyDollar[4].objectTypeUnion(), - Level: yyDollar[5].privilegeLevelUnion(), - Roles: yyDollar[7].rolesUnion(), - GrantOption: yyDollar[8].boolValUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 220: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2555 - { - yyLOCAL = &tree.Grant{ - Typ: tree.GrantTypeRole, - GrantRole: tree.GrantRole{ - Roles: yyDollar[2].rolesUnion(), - Users: yyDollar[4].usersUnion(), - GrantOption: yyDollar[5].boolValUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 221: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2566 - { - yyLOCAL = &tree.Grant{ - Typ: tree.GrantTypeProxy, - GrantProxy: tree.GrantProxy{ - ProxyUser: yyDollar[4].userUnion(), - Users: yyDollar[6].usersUnion(), - GrantOption: yyDollar[7].boolValUnion(), - }, - } - - } - yyVAL.union = yyLOCAL - case 222: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:2579 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 223: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:2583 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 224: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2593 - { - yyLOCAL = &tree.Revoke{ - Typ: tree.RevokeTypePrivilege, - RevokePrivilege: tree.RevokePrivilege{ - IfExists: yyDollar[2].boolValUnion(), - Privileges: yyDollar[3].privilegesUnion(), - ObjType: yyDollar[5].objectTypeUnion(), - Level: yyDollar[6].privilegeLevelUnion(), - Roles: yyDollar[8].rolesUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 225: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2606 - { - yyLOCAL = &tree.Revoke{ - Typ: tree.RevokeTypeRole, - RevokeRole: tree.RevokeRole{ - IfExists: yyDollar[2].boolValUnion(), - Roles: yyDollar[3].rolesUnion(), - Users: yyDollar[5].usersUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 226: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.PrivilegeLevel -//line mysql_sql.y:2619 - { - yyLOCAL = &tree.PrivilegeLevel{ - Level: tree.PRIVILEGE_LEVEL_TYPE_STAR, - } - } - yyVAL.union = yyLOCAL - case 227: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.PrivilegeLevel -//line mysql_sql.y:2625 - { - yyLOCAL = &tree.PrivilegeLevel{ - Level: tree.PRIVILEGE_LEVEL_TYPE_STAR_STAR, - } - } - yyVAL.union = yyLOCAL - case 228: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.PrivilegeLevel -//line mysql_sql.y:2631 - { - tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - yyLOCAL = &tree.PrivilegeLevel{ - Level: tree.PRIVILEGE_LEVEL_TYPE_DATABASE_STAR, - DbName: tblName, - } - } - yyVAL.union = yyLOCAL - case 229: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.PrivilegeLevel -//line mysql_sql.y:2639 - { - dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[3].cstrUnion().Origin()) - yyLOCAL = &tree.PrivilegeLevel{ - Level: tree.PRIVILEGE_LEVEL_TYPE_DATABASE_TABLE, - DbName: dbName, - TabName: tblName, - } - } - yyVAL.union = yyLOCAL - case 230: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.PrivilegeLevel -//line mysql_sql.y:2649 - { - tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - yyLOCAL = &tree.PrivilegeLevel{ - Level: tree.PRIVILEGE_LEVEL_TYPE_TABLE, - TabName: tblName, - } - } - yyVAL.union = yyLOCAL - case 231: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ObjectType -//line mysql_sql.y:2659 - { - yyLOCAL = tree.OBJECT_TYPE_TABLE - } - yyVAL.union = yyLOCAL - case 232: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ObjectType -//line mysql_sql.y:2663 - { - yyLOCAL = tree.OBJECT_TYPE_DATABASE - } - yyVAL.union = yyLOCAL - case 233: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ObjectType -//line mysql_sql.y:2667 - { - yyLOCAL = tree.OBJECT_TYPE_FUNCTION - } - yyVAL.union = yyLOCAL - case 234: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ObjectType -//line mysql_sql.y:2671 - { - yyLOCAL = tree.OBJECT_TYPE_PROCEDURE - } - yyVAL.union = yyLOCAL - case 235: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ObjectType -//line mysql_sql.y:2675 - { - yyLOCAL = tree.OBJECT_TYPE_VIEW - } - yyVAL.union = yyLOCAL - case 236: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ObjectType -//line mysql_sql.y:2679 - { - yyLOCAL = tree.OBJECT_TYPE_ACCOUNT - } - yyVAL.union = yyLOCAL - case 237: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.Privilege -//line mysql_sql.y:2685 - { - yyLOCAL = []*tree.Privilege{yyDollar[1].privilegeUnion()} - } - yyVAL.union = yyLOCAL - case 238: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.Privilege -//line mysql_sql.y:2689 - { - yyLOCAL = append(yyDollar[1].privilegesUnion(), yyDollar[3].privilegeUnion()) - } - yyVAL.union = yyLOCAL - case 239: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Privilege -//line mysql_sql.y:2695 - { - yyLOCAL = &tree.Privilege{ - Type: yyDollar[1].privilegeTypeUnion(), - ColumnList: nil, - } - } - yyVAL.union = yyLOCAL - case 240: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Privilege -//line mysql_sql.y:2702 - { - yyLOCAL = &tree.Privilege{ - Type: yyDollar[1].privilegeTypeUnion(), - ColumnList: yyDollar[3].unresolveNamesUnion(), - } - } - yyVAL.union = yyLOCAL - case 241: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.UnresolvedName -//line mysql_sql.y:2711 - { - yyLOCAL = []*tree.UnresolvedName{yyDollar[1].unresolvedNameUnion()} - } - yyVAL.union = yyLOCAL - case 242: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.UnresolvedName -//line mysql_sql.y:2715 - { - yyLOCAL = append(yyDollar[1].unresolveNamesUnion(), yyDollar[3].unresolvedNameUnion()) - } - yyVAL.union = yyLOCAL - case 243: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2721 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALL - } - yyVAL.union = yyLOCAL - case 244: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2725 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_ACCOUNT - } - yyVAL.union = yyLOCAL - case 245: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2729 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_ACCOUNT - } - yyVAL.union = yyLOCAL - case 246: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2733 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_ACCOUNT - } - yyVAL.union = yyLOCAL - case 247: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2737 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_UPGRADE_ACCOUNT - } - yyVAL.union = yyLOCAL - case 248: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2741 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALL - } - yyVAL.union = yyLOCAL - case 249: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2745 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_TABLE - } - yyVAL.union = yyLOCAL - case 250: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2749 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_VIEW - } - yyVAL.union = yyLOCAL - case 251: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2753 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE - } - yyVAL.union = yyLOCAL - case 252: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2757 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_USER - } - yyVAL.union = yyLOCAL - case 253: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2761 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_USER - } - yyVAL.union = yyLOCAL - case 254: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2765 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_USER - } - yyVAL.union = yyLOCAL - case 255: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2769 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_TABLESPACE - } - yyVAL.union = yyLOCAL - case 256: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2773 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_TRIGGER - } - yyVAL.union = yyLOCAL - case 257: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2777 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DELETE - } - yyVAL.union = yyLOCAL - case 258: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2781 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_TABLE - } - yyVAL.union = yyLOCAL - case 259: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2785 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_VIEW - } - yyVAL.union = yyLOCAL - case 260: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2789 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_EXECUTE - } - yyVAL.union = yyLOCAL - case 261: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2793 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_INDEX - } - yyVAL.union = yyLOCAL - case 262: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2797 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_INSERT - } - yyVAL.union = yyLOCAL - case 263: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2801 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SELECT - } - yyVAL.union = yyLOCAL - case 264: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2805 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SUPER - } - yyVAL.union = yyLOCAL - case 265: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2809 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_DATABASE - } - yyVAL.union = yyLOCAL - case 266: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2813 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_DATABASE - } - yyVAL.union = yyLOCAL - case 267: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2817 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SHOW_DATABASES - } - yyVAL.union = yyLOCAL - case 268: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2821 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CONNECT - } - yyVAL.union = yyLOCAL - case 269: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2825 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_MANAGE_GRANTS - } - yyVAL.union = yyLOCAL - case 270: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2829 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_OWNERSHIP - } - yyVAL.union = yyLOCAL - case 271: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2833 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SHOW_TABLES - } - yyVAL.union = yyLOCAL - case 272: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2837 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_TABLE - } - yyVAL.union = yyLOCAL - case 273: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2841 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_UPDATE - } - yyVAL.union = yyLOCAL - case 274: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2845 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_GRANT_OPTION - } - yyVAL.union = yyLOCAL - case 275: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2849 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_REFERENCES - } - yyVAL.union = yyLOCAL - case 276: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2853 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_REFERENCE - } - yyVAL.union = yyLOCAL - case 277: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2857 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_REPLICATION_SLAVE - } - yyVAL.union = yyLOCAL - case 278: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2861 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_REPLICATION_CLIENT - } - yyVAL.union = yyLOCAL - case 279: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2865 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_USAGE - } - yyVAL.union = yyLOCAL - case 280: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2869 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_RELOAD - } - yyVAL.union = yyLOCAL - case 281: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2873 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_FILE - } - yyVAL.union = yyLOCAL - case 282: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2877 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_TEMPORARY_TABLES - } - yyVAL.union = yyLOCAL - case 283: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2881 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_LOCK_TABLES - } - yyVAL.union = yyLOCAL - case 284: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2885 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_VIEW - } - yyVAL.union = yyLOCAL - case 285: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2889 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SHOW_VIEW - } - yyVAL.union = yyLOCAL - case 286: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2893 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_ROLE - } - yyVAL.union = yyLOCAL - case 287: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2897 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_ROLE - } - yyVAL.union = yyLOCAL - case 288: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2901 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_ROLE - } - yyVAL.union = yyLOCAL - case 289: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2905 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_ROUTINE - } - yyVAL.union = yyLOCAL - case 290: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2909 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_ROUTINE - } - yyVAL.union = yyLOCAL - case 291: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2913 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_EVENT - } - yyVAL.union = yyLOCAL - case 292: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2917 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SHUTDOWN - } - yyVAL.union = yyLOCAL - case 293: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.PrivilegeType -//line mysql_sql.y:2921 - { - yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_TRUNCATE - } - yyVAL.union = yyLOCAL - case 301: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2936 - { - yyLOCAL = &tree.SetLogserviceSettings{ - Name: yyDollar[4].str, - Value: yyDollar[6].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 302: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2945 - { - yyLOCAL = &tree.SetTransaction{ - Scope: tree.TransactionScopeNext, - CharacterList: yyDollar[3].transactionCharacteristicListUnion(), - } - } - yyVAL.union = yyLOCAL - case 303: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2952 - { - yyLOCAL = &tree.SetTransaction{ - Scope: tree.TransactionScopeGlobal, - CharacterList: yyDollar[4].transactionCharacteristicListUnion(), - } - } - yyVAL.union = yyLOCAL - case 304: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2959 - { - yyLOCAL = &tree.SetTransaction{ - Scope: tree.TransactionScopeSession, - CharacterList: yyDollar[4].transactionCharacteristicListUnion(), - } - } - yyVAL.union = yyLOCAL - case 305: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:2968 - { - var connID uint32 - switch v := yyDollar[5].item.(type) { - case uint64: - connID = uint32(v) - case int64: - connID = uint32(v) - default: - yylex.Error("parse integral fail") - goto ret1 - } - yyLOCAL = &tree.SetConnectionID{ - ConnectionID: connID, - } - } - yyVAL.union = yyLOCAL - case 306: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.TransactionCharacteristic -//line mysql_sql.y:2986 - { - yyLOCAL = []*tree.TransactionCharacteristic{yyDollar[1].transactionCharacteristicUnion()} - } - yyVAL.union = yyLOCAL - case 307: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.TransactionCharacteristic -//line mysql_sql.y:2990 - { - yyLOCAL = append(yyDollar[1].transactionCharacteristicListUnion(), yyDollar[3].transactionCharacteristicUnion()) - } - yyVAL.union = yyLOCAL - case 308: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.TransactionCharacteristic -//line mysql_sql.y:2996 - { - yyLOCAL = &tree.TransactionCharacteristic{ - IsLevel: true, - Isolation: yyDollar[3].isolationLevelUnion(), - } - } - yyVAL.union = yyLOCAL - case 309: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.TransactionCharacteristic -//line mysql_sql.y:3003 - { - yyLOCAL = &tree.TransactionCharacteristic{ - Access: yyDollar[1].accessModeUnion(), - } - } - yyVAL.union = yyLOCAL - case 310: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IsolationLevelType -//line mysql_sql.y:3011 - { - yyLOCAL = tree.ISOLATION_LEVEL_REPEATABLE_READ - } - yyVAL.union = yyLOCAL - case 311: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IsolationLevelType -//line mysql_sql.y:3015 - { - yyLOCAL = tree.ISOLATION_LEVEL_READ_COMMITTED - } - yyVAL.union = yyLOCAL - case 312: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IsolationLevelType -//line mysql_sql.y:3019 - { - yyLOCAL = tree.ISOLATION_LEVEL_READ_UNCOMMITTED - } - yyVAL.union = yyLOCAL - case 313: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IsolationLevelType -//line mysql_sql.y:3023 - { - yyLOCAL = tree.ISOLATION_LEVEL_SERIALIZABLE - } - yyVAL.union = yyLOCAL - case 314: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AccessModeType -//line mysql_sql.y:3029 - { - yyLOCAL = tree.ACCESS_MODE_READ_WRITE - } - yyVAL.union = yyLOCAL - case 315: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AccessModeType -//line mysql_sql.y:3033 - { - yyLOCAL = tree.ACCESS_MODE_READ_ONLY - } - yyVAL.union = yyLOCAL - case 316: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3039 - { - yyLOCAL = &tree.SetRole{ - SecondaryRole: false, - Role: yyDollar[3].roleUnion(), - } - } - yyVAL.union = yyLOCAL - case 317: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3046 - { - yyLOCAL = &tree.SetRole{ - SecondaryRole: true, - SecondaryRoleType: tree.SecondaryRoleTypeAll, - } - } - yyVAL.union = yyLOCAL - case 318: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3053 - { - yyLOCAL = &tree.SetRole{ - SecondaryRole: true, - SecondaryRoleType: tree.SecondaryRoleTypeNone, - } - } - yyVAL.union = yyLOCAL - case 319: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3062 - { - dr := yyDollar[4].setDefaultRoleUnion() - dr.Users = yyDollar[6].usersUnion() - yyLOCAL = dr - } - yyVAL.union = yyLOCAL - case 320: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.SetDefaultRole -//line mysql_sql.y:3092 - { - yyLOCAL = &tree.SetDefaultRole{Type: tree.SET_DEFAULT_ROLE_TYPE_NONE, Roles: nil} - } - yyVAL.union = yyLOCAL - case 321: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.SetDefaultRole -//line mysql_sql.y:3096 - { - yyLOCAL = &tree.SetDefaultRole{Type: tree.SET_DEFAULT_ROLE_TYPE_ALL, Roles: nil} - } - yyVAL.union = yyLOCAL - case 322: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.SetDefaultRole -//line mysql_sql.y:3100 - { - yyLOCAL = &tree.SetDefaultRole{Type: tree.SET_DEFAULT_ROLE_TYPE_NORMAL, Roles: yyDollar[1].rolesUnion()} - } - yyVAL.union = yyLOCAL - case 323: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3106 - { - yyLOCAL = &tree.SetVar{Assignments: yyDollar[2].varAssignmentExprsUnion()} - } - yyVAL.union = yyLOCAL - case 324: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3112 - { - yyLOCAL = &tree.SetPassword{Password: yyDollar[4].str} - } - yyVAL.union = yyLOCAL - case 325: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3116 - { - yyLOCAL = &tree.SetPassword{User: yyDollar[4].userUnion(), Password: yyDollar[6].str} - } - yyVAL.union = yyLOCAL - case 327: - yyDollar = yyS[yypt-4 : yypt+1] -//line mysql_sql.y:3123 - { - yyVAL.str = yyDollar[3].str - } - case 328: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.VarAssignmentExpr -//line mysql_sql.y:3129 - { - yyLOCAL = []*tree.VarAssignmentExpr{yyDollar[1].varAssignmentExprUnion()} - } - yyVAL.union = yyLOCAL - case 329: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.VarAssignmentExpr -//line mysql_sql.y:3133 - { - yyLOCAL = append(yyDollar[1].varAssignmentExprsUnion(), yyDollar[3].varAssignmentExprUnion()) - } - yyVAL.union = yyLOCAL - case 330: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3139 - { - yyLOCAL = &tree.VarAssignmentExpr{ - System: true, - TxnScope: tree.TransactionScopeSession, - Name: yyDollar[1].str, - Value: yyDollar[3].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 331: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3148 - { - yyLOCAL = &tree.VarAssignmentExpr{ - System: true, - Global: true, - TxnScope: tree.TransactionScopeGlobal, - Name: yyDollar[2].str, - Value: yyDollar[4].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 332: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3158 - { - yyLOCAL = &tree.VarAssignmentExpr{ - System: true, - Global: true, - TxnScope: tree.TransactionScopeGlobal, - Name: yyDollar[2].str, - Value: yyDollar[4].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 333: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3168 - { - yyLOCAL = &tree.VarAssignmentExpr{ - System: true, - TxnScope: tree.TransactionScopeSession, - Name: yyDollar[2].str, - Value: yyDollar[4].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 334: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3177 - { - yyLOCAL = &tree.VarAssignmentExpr{ - System: true, - TxnScope: tree.TransactionScopeSession, - Name: yyDollar[2].str, - Value: yyDollar[4].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 335: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3186 - { - vs := strings.Split(yyDollar[1].str, ".") - var isGlobal bool - if strings.ToLower(vs[0]) == "global" { - isGlobal = true - } - var r string - if len(vs) == 2 { - r = vs[1] - } else if len(vs) == 1 { - r = vs[0] - } else { - yylex.Error("variable syntax error") - goto ret1 - } - yyLOCAL = &tree.VarAssignmentExpr{ - System: false, - Global: isGlobal, - Name: r, - Value: yyDollar[3].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 336: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3209 - { - v := strings.ToLower(yyDollar[1].str) - var isGlobal bool - txnScope := tree.TransactionScopeNext - if strings.HasPrefix(v, "global.") { - isGlobal = true - txnScope = tree.TransactionScopeGlobal - v = strings.TrimPrefix(v, "global.") - } else if strings.HasPrefix(v, "session.") { - txnScope = tree.TransactionScopeSession - v = strings.TrimPrefix(v, "session.") - } else if strings.HasPrefix(v, "local.") { - txnScope = tree.TransactionScopeSession - v = strings.TrimPrefix(v, "local.") - } - yyLOCAL = &tree.VarAssignmentExpr{ - System: true, - Global: isGlobal, - TxnScope: txnScope, - Name: v, - Value: yyDollar[3].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 337: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3233 - { - yyLOCAL = &tree.VarAssignmentExpr{ - SetNames: true, - Name: strings.ToLower(yyDollar[1].str), - Value: tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char), - } - } - yyVAL.union = yyLOCAL - case 338: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3241 - { - yyLOCAL = &tree.VarAssignmentExpr{ - SetNames: true, - Name: strings.ToLower(yyDollar[1].str), - Value: tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char), - } - } - yyVAL.union = yyLOCAL - case 339: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3249 - { - yyLOCAL = &tree.VarAssignmentExpr{ - SetNames: true, - Name: strings.ToLower(yyDollar[1].str), - Value: tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char), - Reserved: tree.NewNumVal(yyDollar[4].str, yyDollar[4].str, false, tree.P_char), - } - } - yyVAL.union = yyLOCAL - case 340: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3258 - { - yyLOCAL = &tree.VarAssignmentExpr{ - SetNames: true, - Name: strings.ToLower(yyDollar[1].str), - Value: &tree.DefaultVal{}, - } - } - yyVAL.union = yyLOCAL - case 341: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3266 - { - yyLOCAL = &tree.VarAssignmentExpr{ - CharsetRequest: true, - Name: strings.ToLower(yyDollar[1].str), - Value: tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char), - } - } - yyVAL.union = yyLOCAL - case 342: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.VarAssignmentExpr -//line mysql_sql.y:3274 - { - yyLOCAL = &tree.VarAssignmentExpr{ - CharsetRequest: true, - Name: strings.ToLower(yyDollar[1].str), - Value: &tree.DefaultVal{}, - } - } - yyVAL.union = yyLOCAL - case 343: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:3284 - { - yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_char) - } - yyVAL.union = yyLOCAL - case 344: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:3288 - { - yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_char) - } - yyVAL.union = yyLOCAL - case 345: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:3292 - { - yyLOCAL = yyDollar[1].exprUnion() - } - yyVAL.union = yyLOCAL - case 346: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:3298 - { - yyVAL.str = string(yyDollar[1].str) - } - case 347: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:3302 - { - yyVAL.str = yyDollar[1].str - } - case 348: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:3308 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 349: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:3312 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() + "." + yyDollar[3].cstrUnion().Compare() - } - case 350: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:3318 - { - yyLOCAL = []string{yyDollar[1].str} - } - yyVAL.union = yyLOCAL - case 351: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:3322 - { - yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 358: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3336 - { - yyLOCAL = &tree.SavePoint{Name: tree.Identifier(yyDollar[2].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 359: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3342 - { - yyLOCAL = &tree.ReleaseSavePoint{Name: tree.Identifier(yyDollar[3].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 360: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3348 - { - yyLOCAL = &tree.RollbackToSavePoint{Name: tree.Identifier(yyDollar[3].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 361: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3353 - { - yyLOCAL = &tree.RollbackToSavePoint{Name: tree.Identifier(yyDollar[4].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 362: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3358 - { - yyLOCAL = &tree.RollbackToSavePoint{Name: tree.Identifier(yyDollar[5].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 363: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3363 - { - yyLOCAL = &tree.RollbackToSavePoint{Name: tree.Identifier(yyDollar[4].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 364: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3369 - { - yyLOCAL = &tree.RollbackTransaction{Type: yyDollar[2].completionTypeUnion()} - } - yyVAL.union = yyLOCAL - case 365: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3375 - { - yyLOCAL = &tree.CommitTransaction{Type: yyDollar[2].completionTypeUnion()} - } - yyVAL.union = yyLOCAL - case 366: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.CompletionType -//line mysql_sql.y:3380 - { - yyLOCAL = tree.COMPLETION_TYPE_NO_CHAIN - } - yyVAL.union = yyLOCAL - case 367: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.CompletionType -//line mysql_sql.y:3384 - { - yyLOCAL = tree.COMPLETION_TYPE_NO_CHAIN - } - yyVAL.union = yyLOCAL - case 368: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.CompletionType -//line mysql_sql.y:3388 - { - yyLOCAL = tree.COMPLETION_TYPE_CHAIN - } - yyVAL.union = yyLOCAL - case 369: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.CompletionType -//line mysql_sql.y:3392 - { - yyLOCAL = tree.COMPLETION_TYPE_CHAIN - } - yyVAL.union = yyLOCAL - case 370: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.CompletionType -//line mysql_sql.y:3396 - { - yyLOCAL = tree.COMPLETION_TYPE_RELEASE - } - yyVAL.union = yyLOCAL - case 371: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.CompletionType -//line mysql_sql.y:3400 - { - yyLOCAL = tree.COMPLETION_TYPE_RELEASE - } - yyVAL.union = yyLOCAL - case 372: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.CompletionType -//line mysql_sql.y:3404 - { - yyLOCAL = tree.COMPLETION_TYPE_NO_CHAIN - } - yyVAL.union = yyLOCAL - case 373: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.CompletionType -//line mysql_sql.y:3408 - { - yyLOCAL = tree.COMPLETION_TYPE_NO_CHAIN - } - yyVAL.union = yyLOCAL - case 374: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.CompletionType -//line mysql_sql.y:3412 - { - yyLOCAL = tree.COMPLETION_TYPE_NO_CHAIN - } - yyVAL.union = yyLOCAL - case 375: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3418 - { - yyLOCAL = &tree.BeginTransaction{} - } - yyVAL.union = yyLOCAL - case 376: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3422 - { - yyLOCAL = &tree.BeginTransaction{} - } - yyVAL.union = yyLOCAL - case 377: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3426 - { - yyLOCAL = &tree.BeginTransaction{} - } - yyVAL.union = yyLOCAL - case 378: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3430 - { - m := tree.MakeTransactionModes(tree.READ_WRITE_MODE_READ_WRITE) - yyLOCAL = &tree.BeginTransaction{Modes: m} - } - yyVAL.union = yyLOCAL - case 379: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3435 - { - m := tree.MakeTransactionModes(tree.READ_WRITE_MODE_READ_ONLY) - yyLOCAL = &tree.BeginTransaction{Modes: m} - } - yyVAL.union = yyLOCAL - case 380: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3440 - { - yyLOCAL = &tree.BeginTransaction{} - } - yyVAL.union = yyLOCAL - case 381: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3446 - { - name := yyDollar[2].cstrUnion() - secondaryRole := false - var secondaryRoleType tree.SecondaryRoleType = 0 - var role *tree.Role - yyLOCAL = tree.NewUse( - name, - secondaryRole, - secondaryRoleType, - role, - ) - } - yyVAL.union = yyLOCAL - case 382: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3459 - { - name := yylex.(*Lexer).GetDbOrTblNameCStr("") - secondaryRole := false - var secondaryRoleType tree.SecondaryRoleType = 0 - var role *tree.Role - yyLOCAL = tree.NewUse( - name, - secondaryRole, - secondaryRoleType, - role, - ) - } - yyVAL.union = yyLOCAL - case 383: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3472 - { - name := yylex.(*Lexer).GetDbOrTblNameCStr("") - secondaryRole := false - var secondaryRoleType tree.SecondaryRoleType = 0 - role := yyDollar[3].roleUnion() - yyLOCAL = tree.NewUse( - name, - secondaryRole, - secondaryRoleType, - role, - ) - } - yyVAL.union = yyLOCAL - case 384: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3485 - { - name := yylex.(*Lexer).GetDbOrTblNameCStr("") - secondaryRole := true - secondaryRoleType := tree.SecondaryRoleTypeAll - var role *tree.Role - yyLOCAL = tree.NewUse( - name, - secondaryRole, - secondaryRoleType, - role, - ) - } - yyVAL.union = yyLOCAL - case 385: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3498 - { - name := yylex.(*Lexer).GetDbOrTblNameCStr("") - secondaryRole := true - secondaryRoleType := tree.SecondaryRoleTypeNone - var role *tree.Role - yyLOCAL = tree.NewUse( - name, - secondaryRole, - secondaryRoleType, - role, - ) - } - yyVAL.union = yyLOCAL - case 386: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3513 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[1].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = yyDollar[1].statementUnion() - } - yyVAL.union = yyLOCAL - case 387: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3521 - { - yyDollar[2].statementUnion().(*tree.Update).With = yyDollar[1].withClauseUnion() - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[2].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = yyDollar[2].statementUnion() - } - yyVAL.union = yyLOCAL - case 388: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3532 - { - // Single-table syntax - yyLOCAL = &tree.Update{ - Tables: tree.TableExprs{yyDollar[4].tableExprUnion()}, - Exprs: yyDollar[6].updateExprsUnion(), - Priority: yyDollar[2].str, - Ignore: yyDollar[3].str != "", - Where: yyDollar[7].whereUnion(), - OrderBy: yyDollar[8].orderByUnion(), - Limit: yyDollar[9].limitUnion(), - Returning: yyDollar[10].selectExprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 389: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3546 - { - // Multiple-table syntax - yyLOCAL = &tree.Update{ - Tables: tree.TableExprs{yyDollar[4].tableExprUnion()}, - Exprs: yyDollar[6].updateExprsUnion(), - Priority: yyDollar[2].str, - Ignore: yyDollar[3].str != "", - Where: yyDollar[7].whereUnion(), - Returning: yyDollar[8].selectExprsUnion(), - MultiTable: true, - } - } - yyVAL.union = yyLOCAL - case 390: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3559 - { - // PostgreSQL-style UPDATE target SET ... FROM source_tables WHERE ... - // The target table is kept in Tables; FROM-clause sources are stored - // separately in From so the binder/planner can treat them as read-only - // join sources rather than DML targets. - yyLOCAL = &tree.Update{ - Tables: tree.TableExprs{yyDollar[4].tableExprUnion()}, - Exprs: yyDollar[6].updateExprsUnion(), - Priority: yyDollar[2].str, - Ignore: yyDollar[3].str != "", - From: &tree.From{Tables: tree.TableExprs{yyDollar[8].tableExprUnion()}}, - Where: yyDollar[9].whereUnion(), - Returning: yyDollar[10].selectExprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 391: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.UpdateExprs -//line mysql_sql.y:3577 - { - yyLOCAL = tree.UpdateExprs{yyDollar[1].updateExprUnion()} - } - yyVAL.union = yyLOCAL - case 392: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.UpdateExprs -//line mysql_sql.y:3581 - { - yyLOCAL = append(yyDollar[1].updateExprsUnion(), yyDollar[3].updateExprUnion()) - } - yyVAL.union = yyLOCAL - case 393: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.UpdateExpr -//line mysql_sql.y:3587 - { - yyLOCAL = &tree.UpdateExpr{Names: []*tree.UnresolvedName{yyDollar[1].unresolvedNameUnion()}, Expr: yyDollar[3].exprUnion()} - } - yyVAL.union = yyLOCAL - case 396: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3597 - { - yyLOCAL = &tree.LockTableStmt{TableLocks: yyDollar[3].tableLocksUnion()} - } - yyVAL.union = yyLOCAL - case 397: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.TableLock -//line mysql_sql.y:3603 - { - yyLOCAL = []tree.TableLock{yyDollar[1].tableLockUnion()} - } - yyVAL.union = yyLOCAL - case 398: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []tree.TableLock -//line mysql_sql.y:3607 - { - yyLOCAL = append(yyDollar[1].tableLocksUnion(), yyDollar[3].tableLockUnion()) - } - yyVAL.union = yyLOCAL - case 399: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.TableLock -//line mysql_sql.y:3613 - { - yyLOCAL = tree.TableLock{Table: *yyDollar[1].tableNameUnion(), LockType: yyDollar[2].tableLockTypeUnion()} - } - yyVAL.union = yyLOCAL - case 400: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableLockType -//line mysql_sql.y:3619 - { - yyLOCAL = tree.TableLockRead - } - yyVAL.union = yyLOCAL - case 401: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.TableLockType -//line mysql_sql.y:3623 - { - yyLOCAL = tree.TableLockReadLocal - } - yyVAL.union = yyLOCAL - case 402: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableLockType -//line mysql_sql.y:3627 - { - yyLOCAL = tree.TableLockWrite - } - yyVAL.union = yyLOCAL - case 403: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.TableLockType -//line mysql_sql.y:3631 - { - yyLOCAL = tree.TableLockLowPriorityWrite - } - yyVAL.union = yyLOCAL - case 404: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3637 - { - yyLOCAL = &tree.UnLockTableStmt{} - } - yyVAL.union = yyLOCAL - case 414: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3652 - { - yyLOCAL = &tree.SetVar{Assignments: yyDollar[2].varAssignmentExprsUnion()} - } - yyVAL.union = yyLOCAL - case 418: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3659 - { - yyLOCAL = yyDollar[1].selectUnion() - } - yyVAL.union = yyLOCAL - case 419: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3665 - { - yyLOCAL = tree.NewPrepareStmt(tree.Identifier(yyDollar[2].str), yyDollar[4].statementUnion()) - } - yyVAL.union = yyLOCAL - case 420: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3669 - { - yyLOCAL = tree.NewPrepareString(tree.Identifier(yyDollar[2].str), yyDollar[4].str) - } - yyVAL.union = yyLOCAL - case 421: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3673 - { - yyLOCAL = tree.NewPrepareVar(tree.Identifier(yyDollar[2].str), yyDollar[4].varExprUnion()) - } - yyVAL.union = yyLOCAL - case 422: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3679 - { - yyLOCAL = &tree.ExecuteSQLTask{ - Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 423: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3685 - { - yyLOCAL = tree.NewExecute(tree.Identifier(yyDollar[2].str)) - } - yyVAL.union = yyLOCAL - case 424: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3689 - { - yyLOCAL = tree.NewExecuteWithVariables(tree.Identifier(yyDollar[2].str), yyDollar[4].varExprsUnion()) - } - yyVAL.union = yyLOCAL - case 425: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3695 - { - yyLOCAL = tree.NewDeallocate(tree.Identifier(yyDollar[3].str), false) - } - yyVAL.union = yyLOCAL - case 426: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3701 - { - yyLOCAL = tree.NewReset(tree.Identifier(yyDollar[3].str)) - } - yyVAL.union = yyLOCAL - case 432: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3712 - { - yyLOCAL = yyDollar[1].selectUnion() - } - yyVAL.union = yyLOCAL - case 433: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3718 - { - yyLOCAL = &tree.ShowColumns{Table: yyDollar[2].unresolvedObjectNameUnion()} - } - yyVAL.union = yyLOCAL - case 434: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3722 - { - yyLOCAL = &tree.ShowColumns{Table: yyDollar[2].unresolvedObjectNameUnion(), ColName: yyDollar[3].unresolvedNameUnion()} - } - yyVAL.union = yyLOCAL - case 435: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3726 - { - yyLOCAL = tree.NewExplainFor("", integralToUint64(yyDollar[4].item)) - } - yyVAL.union = yyLOCAL - case 436: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3730 - { - yyLOCAL = tree.NewExplainFor(yyDollar[4].str, integralToUint64(yyDollar[7].item)) - } - yyVAL.union = yyLOCAL - case 437: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3734 - { - yyLOCAL = yyDollar[1].statementUnion() - } - yyVAL.union = yyLOCAL - case 438: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3740 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[5].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.FormatOption, yyDollar[4].str), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[5].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 439: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3751 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[5].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.FormatOption, yyDollar[4].str), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[5].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 440: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3762 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[6].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), - tree.MakeOptionElem(tree.FormatOption, yyDollar[5].str), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[6].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 441: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3774 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[6].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), - tree.MakeOptionElem(tree.FormatOption, yyDollar[5].str), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[6].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 442: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3786 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[6].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.PhyPlanOption, "NULL"), - tree.MakeOptionElem(tree.FormatOption, yyDollar[5].str), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[6].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 443: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3798 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[6].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.PhyPlanOption, "NULL"), - tree.MakeOptionElem(tree.FormatOption, yyDollar[5].str), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[6].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 444: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3810 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[2].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = tree.NewExplainStmt(yyDollar[2].statementUnion(), "text") - } - yyVAL.union = yyLOCAL - case 445: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3818 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[3].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.VerboseOption, "NULL"), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[3].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 446: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3829 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[3].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[3].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 447: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3840 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[4].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), - tree.MakeOptionElem(tree.VerboseOption, "NULL"), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[4].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 448: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3852 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[3].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.PhyPlanOption, "NULL"), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[3].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 449: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3863 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[4].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.PhyPlanOption, "NULL"), - tree.MakeOptionElem(tree.VerboseOption, "NULL"), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[4].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 450: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3875 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[4].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.PhyPlanOption, "NULL"), - tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[4].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 451: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3887 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[5].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[5].statementUnion(), yyDollar[3].explainOptionsUnion()) - } - yyVAL.union = yyLOCAL - case 452: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3895 - { - yyLOCAL = tree.MakeExplainStmt(yyDollar[3].statementUnion(), nil) - } - yyVAL.union = yyLOCAL - case 453: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3899 - { - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.VerboseOption, "NULL"), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[4].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 454: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3906 - { - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[4].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 455: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3913 - { - options := []tree.OptionElem{ - tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), - tree.MakeOptionElem(tree.VerboseOption, "NULL"), - } - yyLOCAL = tree.MakeExplainStmt(yyDollar[5].statementUnion(), options) - } - yyVAL.union = yyLOCAL - case 470: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.OptionElem -//line mysql_sql.y:3951 - { - yyLOCAL = []tree.OptionElem{yyDollar[1].explainOptionUnion()} - } - yyVAL.union = yyLOCAL - case 471: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []tree.OptionElem -//line mysql_sql.y:3955 - { - yyLOCAL = append(yyDollar[1].explainOptionsUnion(), yyDollar[3].explainOptionUnion()) - } - yyVAL.union = yyLOCAL - case 472: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.OptionElem -//line mysql_sql.y:3961 - { - yyLOCAL = tree.MakeOptionElem(yyDollar[1].str, yyDollar[2].str) - } - yyVAL.union = yyLOCAL - case 473: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:3967 - { - yyVAL.str = yyDollar[1].str - } - case 474: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:3972 - { - yyVAL.str = "true" - } - case 475: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:3973 - { - yyVAL.str = "false" - } - case 476: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:3974 - { - yyVAL.str = yyDollar[1].str - } - case 477: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:3975 - { - yyVAL.str = yyDollar[1].str - } - case 478: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:3979 - { - stmt := tree.NewAnalyzeStmt(yyDollar[3].analyzeTableEntriesUnion()) - stmt.FullScan = yyDollar[4].boolValUnion() - yyLOCAL = stmt - } - yyVAL.union = yyLOCAL - case 479: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:3987 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 480: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:3991 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 481: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.AnalyzeTableEntry -//line mysql_sql.y:3997 - { - yyLOCAL = []*tree.AnalyzeTableEntry{yyDollar[1].analyzeTableEntryUnion()} - } - yyVAL.union = yyLOCAL - case 482: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.AnalyzeTableEntry -//line mysql_sql.y:4001 - { - yyLOCAL = append(yyDollar[1].analyzeTableEntriesUnion(), yyDollar[3].analyzeTableEntryUnion()) - } - yyVAL.union = yyLOCAL - case 483: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.AnalyzeTableEntry -//line mysql_sql.y:4007 - { - yyLOCAL = &tree.AnalyzeTableEntry{Table: yyDollar[1].tableNameUnion()} - } - yyVAL.union = yyLOCAL - case 484: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.AnalyzeTableEntry -//line mysql_sql.y:4011 - { - yyLOCAL = &tree.AnalyzeTableEntry{Table: yyDollar[1].tableNameUnion(), Cols: yyDollar[3].identifierListUnion()} - } - yyVAL.union = yyLOCAL - case 485: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4017 - { - yyLOCAL = tree.NewCheckTableStmt(yyDollar[3].tableNamesUnion(), yyDollar[4].checkTableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 486: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.CheckTableOption -//line mysql_sql.y:4023 - { - yyLOCAL = tree.CheckTableOptionNone - } - yyVAL.union = yyLOCAL - case 487: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.CheckTableOption -//line mysql_sql.y:4027 - { - yyLOCAL = tree.CheckTableOptionExtended - } - yyVAL.union = yyLOCAL - case 488: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.CheckTableOption -//line mysql_sql.y:4031 - { - yyLOCAL = tree.CheckTableOptionForUpgrade - } - yyVAL.union = yyLOCAL - case 489: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4037 - { - yyLOCAL = tree.NewShowProfileStmt(yyDollar[3].int64ValUnion(), yyDollar[4].limitUnion()) - } - yyVAL.union = yyLOCAL - case 490: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:4043 - { - yyLOCAL = 0 - } - yyVAL.union = yyLOCAL - case 491: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:4047 - { - value, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - yyLOCAL = value - } - yyVAL.union = yyLOCAL - case 492: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4055 - { - yyLOCAL = &tree.UpgradeStatement{ - Target: yyDollar[3].upgrade_targetUnion(), - Retry: yyDollar[4].int64ValUnion(), - } - } - yyVAL.union = yyLOCAL - case 493: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Target -//line mysql_sql.y:4064 - { - yyLOCAL = &tree.Target{ - AccountName: yyDollar[1].str, - IsALLAccount: false, - } - } - yyVAL.union = yyLOCAL - case 494: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Target -//line mysql_sql.y:4071 - { - yyLOCAL = &tree.Target{ - AccountName: "", - IsALLAccount: true, - } - } - yyVAL.union = yyLOCAL - case 495: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:4079 - { - yyLOCAL = -1 - } - yyVAL.union = yyLOCAL - case 496: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:4083 - { - res, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if res <= 0 { - yylex.Error("retry value can not less than 0") - yyLOCAL = -1 - } - yyLOCAL = res - } - yyVAL.union = yyLOCAL - case 512: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4113 - { - yyLOCAL = &tree.AlterIcebergCatalog{ - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Options: yyDollar[6].icebergOptionsUnion(), - } - } - yyVAL.union = yyLOCAL - case 513: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4120 - { - yyLOCAL = &tree.AlterIcebergCatalog{ - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Options: yyDollar[7].icebergOptionsUnion(), - } - } - yyVAL.union = yyLOCAL - case 514: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4129 - { - yyLOCAL = &tree.AlterMongoDBConnection{ - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Action: tree.AlterMongoDBConnectionSet, - Options: yyDollar[6].mongodbOptionsUnion(), - } - } - yyVAL.union = yyLOCAL - case 515: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4137 - { - yyLOCAL = &tree.AlterMongoDBConnection{ - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Action: tree.AlterMongoDBConnectionSet, - Options: yyDollar[7].mongodbOptionsUnion(), - } - } - yyVAL.union = yyLOCAL - case 516: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4145 - { - yyLOCAL = &tree.AlterMongoDBConnection{ - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Action: tree.AlterMongoDBConnectionEnable, - } - } - yyVAL.union = yyLOCAL - case 517: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4152 - { - yyLOCAL = &tree.AlterMongoDBConnection{ - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - Action: tree.AlterMongoDBConnectionDisable, - } - } - yyVAL.union = yyLOCAL - case 518: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4161 - { - var ifExists = yyDollar[3].boolValUnion() - var name = yyDollar[4].tableNameUnion() - var typ = yyDollar[5].alterTypeOptionUnion() - var incrementBy = yyDollar[6].incrementByOptionUnion() - var minValue = yyDollar[7].minValueOptionUnion() - var maxValue = yyDollar[8].maxValueOptionUnion() - var startWith = yyDollar[9].startWithOptionUnion() - var cycle = yyDollar[10].cycleOptionUnion() - yyLOCAL = tree.NewAlterSequence( - ifExists, - name, - typ, - incrementBy, - minValue, - maxValue, - startWith, - cycle, - ) - } - yyVAL.union = yyLOCAL - case 519: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4184 - { - var ifExists = yyDollar[3].boolValUnion() - var name = yyDollar[4].tableNameUnion() - var colNames = yyDollar[5].identifierListUnion() - var asSource = yyDollar[7].selectUnion() - yyLOCAL = tree.NewAlterView(ifExists, name, colNames, asSource) - } - yyVAL.union = yyLOCAL - case 520: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4194 - { - var table = yyDollar[3].tableNameUnion() - alterTable := tree.NewAlterTable(table) - alterTable.Options = yyDollar[4].alterTableOptionsUnion() - yyLOCAL = alterTable - } - yyVAL.union = yyLOCAL - case 521: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4201 - { - var table = yyDollar[3].tableNameUnion() - alterTable := tree.NewAlterTable(table) - alterTable.PartitionOption = yyDollar[4].alterPartitionOptionUnion() - yyLOCAL = alterTable - } - yyVAL.union = yyLOCAL - case 522: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4208 - { - var table = yyDollar[3].tableNameUnion() - alterTable := tree.NewAlterTable(table) - alterTable.Options = []tree.AlterTableOption{yyDollar[4].alterTableOptionUnion()} - yyLOCAL = alterTable - } - yyVAL.union = yyLOCAL - case 523: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4217 - { - alterTables := yyDollar[3].renameTableOptionsUnion() - renameTables := tree.NewRenameTable(alterTables) - yyLOCAL = renameTables - } - yyVAL.union = yyLOCAL - case 524: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.AlterTable -//line mysql_sql.y:4225 - { - yyLOCAL = []*tree.AlterTable{yyDollar[1].renameTableOptionUnion()} - } - yyVAL.union = yyLOCAL - case 525: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.AlterTable -//line mysql_sql.y:4229 - { - yyLOCAL = append(yyDollar[1].renameTableOptionsUnion(), yyDollar[3].renameTableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 526: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.AlterTable -//line mysql_sql.y:4235 - { - var table = yyDollar[1].tableNameUnion() - alterTable := tree.NewAlterTable(table) - opt := tree.AlterTableOption(yyDollar[3].alterTableOptionUnion()) - alterTable.Options = []tree.AlterTableOption{opt} - yyLOCAL = alterTable - } - yyVAL.union = yyLOCAL - case 527: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4245 - { - var io *tree.IndexOption = nil - if yyDollar[5].indexOptionUnion() == nil { - io = tree.NewIndexOption() - io.IType = tree.INDEX_TYPE_IVFFLAT - } else { - io = yyDollar[5].indexOptionUnion() - io.IType = tree.INDEX_TYPE_IVFFLAT - } - var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) - yyLOCAL = tree.NewAlterOptionAlterReIndex(name, io) - } - yyVAL.union = yyLOCAL - case 528: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4258 - { - var io *tree.IndexOption = nil - if yyDollar[5].indexOptionUnion() == nil { - io = tree.NewIndexOption() - io.IType = tree.INDEX_TYPE_HNSW - } else { - io = yyDollar[5].indexOptionUnion() - io.IType = tree.INDEX_TYPE_HNSW - } - var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) - yyLOCAL = tree.NewAlterOptionAlterReIndex(name, io) - } - yyVAL.union = yyLOCAL - case 529: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4271 - { - var io *tree.IndexOption = nil - if yyDollar[5].indexOptionUnion() == nil { - io = tree.NewIndexOption() - io.IType = tree.INDEX_TYPE_IVFPQ - } else { - io = yyDollar[5].indexOptionUnion() - io.IType = tree.INDEX_TYPE_IVFPQ - } - var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) - yyLOCAL = tree.NewAlterOptionAlterReIndex(name, io) - } - yyVAL.union = yyLOCAL - case 530: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4284 - { - var io *tree.IndexOption = nil - if yyDollar[5].indexOptionUnion() == nil { - io = tree.NewIndexOption() - io.IType = tree.INDEX_TYPE_CAGRA - } else { - io = yyDollar[5].indexOptionUnion() - io.IType = tree.INDEX_TYPE_CAGRA - } - var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) - yyLOCAL = tree.NewAlterOptionAlterReIndex(name, io) - } - yyVAL.union = yyLOCAL - case 531: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4297 - { - var io *tree.IndexOption = nil - if yyDollar[5].indexOptionUnion() == nil { - io = tree.NewIndexOption() - io.IType = tree.INDEX_TYPE_FULLTEXT2 - } else { - io = yyDollar[5].indexOptionUnion() - io.IType = tree.INDEX_TYPE_FULLTEXT2 - } - var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) - yyLOCAL = tree.NewAlterOptionAlterReIndex(name, io) - } - yyVAL.union = yyLOCAL - case 532: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.AlterTableOptions -//line mysql_sql.y:4312 - { - yyLOCAL = []tree.AlterTableOption{yyDollar[1].alterTableOptionUnion()} - } - yyVAL.union = yyLOCAL - case 533: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterTableOptions -//line mysql_sql.y:4316 - { - yyLOCAL = append(yyDollar[1].alterTableOptionsUnion(), yyDollar[3].alterTableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 534: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.AlterPartitionOption -//line mysql_sql.y:4322 - { - yyLOCAL = yyDollar[1].alterPartitionOptionUnion() - } - yyVAL.union = yyLOCAL - case 535: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.AlterPartitionOption -//line mysql_sql.y:4326 - { - yyDollar[3].partitionByUnion().Num = uint64(yyDollar[4].int64ValUnion()) - var PartBy = yyDollar[3].partitionByUnion() - var SubPartBy = yyDollar[5].partitionByUnion() - var Partitions = yyDollar[6].partitionsUnion() - - partitionDef := tree.NewPartitionOption( - PartBy, - SubPartBy, - Partitions, - ) - - var typ tree.AlterPartitionOptionType - - opt := tree.NewAlterPartitionRedefinePartitionClause( - typ, - partitionDef, - ) - - yyLOCAL = tree.AlterPartitionOption(opt) - } - yyVAL.union = yyLOCAL - case 536: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4350 - { - var ifExists = yyDollar[3].boolValUnion() - var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - var pitrValue = yyDollar[6].int64ValUnion() - var pitrUnit = yyDollar[7].str - yyLOCAL = tree.NewAlterPitr(ifExists, name, pitrValue, pitrUnit) - } - yyVAL.union = yyLOCAL - case 537: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4360 - { - yyLOCAL = &tree.AlterSQLTask{ - Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - Action: tree.AlterTaskSuspend, - } - } - yyVAL.union = yyLOCAL - case 538: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4367 - { - yyLOCAL = &tree.AlterSQLTask{ - Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - Action: tree.AlterTaskResume, - } - } - yyVAL.union = yyLOCAL - case 539: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4374 - { - yyLOCAL = &tree.AlterSQLTask{ - Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - Action: tree.AlterTaskSetSchedule, - CronExpr: yyDollar[6].str, - Timezone: yyDollar[7].str, - } - } - yyVAL.union = yyLOCAL - case 540: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4383 - { - yyLOCAL = &tree.AlterSQLTask{ - Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - Action: tree.AlterTaskSetWhen, - GateCondition: sqlTaskNodeString(yyDollar[7].exprUnion()), - } - } - yyVAL.union = yyLOCAL - case 541: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4391 - { - yyLOCAL = &tree.AlterSQLTask{ - Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - Action: tree.AlterTaskSetRetry, - RetryLimit: sqlTaskInt64(yyDollar[6].item), - } - } - yyVAL.union = yyLOCAL - case 542: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4399 - { - yyLOCAL = &tree.AlterSQLTask{ - Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - Action: tree.AlterTaskSetTimeout, - Timeout: yyDollar[6].str, - } - } - yyVAL.union = yyLOCAL - case 543: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4409 - { - var oldName = yyDollar[5].cstrUnion().Compare() - var newName = yyDollar[8].cstrUnion().Compare() - yyLOCAL = tree.NewAlterRole(true, oldName, newName) - } - yyVAL.union = yyLOCAL - case 544: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4415 - { - var oldName = yyDollar[3].cstrUnion().Compare() - var newName = yyDollar[6].cstrUnion().Compare() - yyLOCAL = tree.NewAlterRole(false, oldName, newName) - } - yyVAL.union = yyLOCAL - case 545: - yyDollar = yyS[yypt-11 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4421 - { - var roleName = yyDollar[3].cstrUnion().Compare() - var ruleSQL = yyDollar[6].str - var dbName = yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[9].cstrUnion().Origin()).Compare() - var tblName = yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[11].cstrUnion().Origin()).Compare() - var ruleName = dbName + "." + tblName - yyLOCAL = tree.NewAlterRoleAddRule(roleName, ruleName, ruleSQL, dbName, tblName) - } - yyVAL.union = yyLOCAL - case 546: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4430 - { - var roleName = yyDollar[3].cstrUnion().Compare() - var dbName = yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[8].cstrUnion().Origin()).Compare() - var tblName = yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[10].cstrUnion().Origin()).Compare() - yyLOCAL = tree.NewAlterRoleDropRule(roleName, dbName, tblName) - } - yyVAL.union = yyLOCAL - case 547: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterPartitionOption -//line mysql_sql.y:4439 - { - var typ = tree.AlterPartitionAddPartition - var partitions = yyDollar[3].partitionsUnion() - opt := tree.NewAlterPartitionAddPartitionClause( - typ, - partitions, - ) - yyLOCAL = tree.AlterPartitionOption(opt) - } - yyVAL.union = yyLOCAL - case 548: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterPartitionOption -//line mysql_sql.y:4449 - { - var typ = tree.AlterPartitionDropPartition - var partitionNames = yyDollar[3].PartitionNamesUnion() - opt := tree.NewAlterPartitionDropPartitionClause( - typ, - partitionNames, - ) - - if yyDollar[3].PartitionNamesUnion() == nil { - opt.OnAllPartitions = true - } else { - opt.PartitionNames = yyDollar[3].PartitionNamesUnion() - } - yyLOCAL = tree.AlterPartitionOption(opt) - } - yyVAL.union = yyLOCAL - case 549: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterPartitionOption -//line mysql_sql.y:4465 - { - var typ = tree.AlterPartitionTruncatePartition - var partitionNames = yyDollar[3].PartitionNamesUnion() - opt := tree.NewAlterPartitionTruncatePartitionClause( - typ, - partitionNames, - ) - - if yyDollar[3].PartitionNamesUnion() == nil { - opt.OnAllPartitions = true - } else { - opt.PartitionNames = yyDollar[3].PartitionNamesUnion() - } - yyLOCAL = tree.AlterPartitionOption(opt) - } - yyVAL.union = yyLOCAL - case 550: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:4483 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 551: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:4487 - { - yyLOCAL = yyDollar[1].PartitionNamesUnion() - } - yyVAL.union = yyLOCAL - case 552: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:4493 - { - yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 553: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:4497 - { - yyLOCAL = append(yyDollar[1].PartitionNamesUnion(), tree.Identifier(yyDollar[3].cstrUnion().Compare())) - } - yyVAL.union = yyLOCAL - case 554: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4503 - { - var def = yyDollar[2].tableDefUnion() - opt := tree.NewAlterOptionAdd(def) - yyLOCAL = tree.AlterTableOption(opt) - } - yyVAL.union = yyLOCAL - case 555: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4509 - { - var typ = tree.AlterTableModifyColumn - var newColumn = yyDollar[3].columnTableDefUnion() - var position = yyDollar[4].alterColPositionUnion() - opt := tree.NewAlterTableModifyColumnClause(typ, newColumn, position) - yyLOCAL = tree.AlterTableOption(opt) - } - yyVAL.union = yyLOCAL - case 556: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4517 - { - // Type OldColumnName NewColumn Position - var typ = tree.AlterTableChangeColumn - var oldColumnName = yyDollar[3].unresolvedNameUnion() - var newColumn = yyDollar[4].columnTableDefUnion() - var position = yyDollar[5].alterColPositionUnion() - opt := tree.NewAlterTableChangeColumnClause(typ, oldColumnName, newColumn, position) - yyLOCAL = tree.AlterTableOption(opt) - } - yyVAL.union = yyLOCAL - case 557: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4527 - { - var typ = tree.AlterTableRenameColumn - var oldColumnName = yyDollar[3].unresolvedNameUnion() - var newColumnName = yyDollar[5].unresolvedNameUnion() - opt := tree.NewAlterTableRenameColumnClause(typ, oldColumnName, newColumnName) - yyLOCAL = tree.AlterTableOption(opt) - } - yyVAL.union = yyLOCAL - case 558: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4535 - { - var typ = tree.AlterTableAlterColumn - var columnName = yyDollar[3].unresolvedNameUnion() - var defaultExpr = tree.NewAttributeDefault(yyDollar[6].exprUnion()) - var visibility tree.VisibleType - var optionType = tree.AlterColumnOptionSetDefault - opt := tree.NewAlterTableAlterColumnClause(typ, columnName, defaultExpr, visibility, optionType) - yyLOCAL = tree.AlterTableOption(opt) - } - yyVAL.union = yyLOCAL - case 559: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4545 - { - var typ = tree.AlterTableAlterColumn - var columnName = yyDollar[3].unresolvedNameUnion() - var defaultExpr = tree.NewAttributeDefault(nil) - var visibility = yyDollar[5].indexVisibilityUnion() - var optionType = tree.AlterColumnOptionSetVisibility - opt := tree.NewAlterTableAlterColumnClause(typ, columnName, defaultExpr, visibility, optionType) - yyLOCAL = tree.AlterTableOption(opt) - } - yyVAL.union = yyLOCAL - case 560: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4555 - { - var typ = tree.AlterTableAlterColumn - var columnName = yyDollar[3].unresolvedNameUnion() - var defaultExpr = tree.NewAttributeDefault(nil) - var visibility tree.VisibleType - var optionType = tree.AlterColumnOptionDropDefault - opt := tree.NewAlterTableAlterColumnClause(typ, columnName, defaultExpr, visibility, optionType) - yyLOCAL = tree.AlterTableOption(opt) - } - yyVAL.union = yyLOCAL - case 561: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4565 - { - var orderByClauseType = tree.AlterTableOrderByColumn - var orderByColumnList = yyDollar[3].alterColumnOrderByUnion() - opt := tree.NewAlterTableOrderByColumnClause(orderByClauseType, orderByColumnList) - yyLOCAL = tree.AlterTableOption(opt) - } - yyVAL.union = yyLOCAL - case 562: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4572 - { - yyLOCAL = tree.AlterTableOption(yyDollar[2].alterTableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 563: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4576 - { - yyLOCAL = tree.AlterTableOption(yyDollar[2].alterTableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 564: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4580 - { - yyLOCAL = tree.AlterTableOption(yyDollar[1].tableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 565: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4584 - { - yyLOCAL = tree.AlterTableOption(yyDollar[3].alterTableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 566: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4588 - { - var column = yyDollar[3].columnTableDefUnion() - var position = yyDollar[4].alterColPositionUnion() - opt := tree.NewAlterAddCol(column, position) - yyLOCAL = tree.AlterTableOption(opt) - } - yyVAL.union = yyLOCAL - case 567: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4595 - { - yyLOCAL = tree.NewAlterOptionAlgorithm(yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 568: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4599 - { - opt := tree.NewTableOptionCharset(yyDollar[4].str) - opt.Collate = yyDollar[7].str - yyLOCAL = opt - } - yyVAL.union = yyLOCAL - case 569: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4605 - { - opt := tree.NewTableOptionCharset(yyDollar[5].str) - opt.Convert = true - yyLOCAL = opt - } - yyVAL.union = yyLOCAL - case 570: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4611 - { - opt := tree.NewTableOptionCharset(yyDollar[5].str) - opt.Collate = yyDollar[8].str - opt.Convert = true - yyLOCAL = opt - } - yyVAL.union = yyLOCAL - case 571: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4618 - { - opt := tree.NewTableOptionCharset(yyDollar[1].str) - opt.NonCharsetSyntax = true - yyLOCAL = opt - } - yyVAL.union = yyLOCAL - case 572: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4624 - { - opt := tree.NewTableOptionCharset(yyDollar[1].str) - opt.NonCharsetSyntax = true - yyLOCAL = opt - } - yyVAL.union = yyLOCAL - case 573: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4630 - { - opt := tree.NewTableOptionCharset(yyDollar[1].str) - opt.NonCharsetSyntax = true - yyLOCAL = opt - } - yyVAL.union = yyLOCAL - case 574: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4636 - { - yyLOCAL = tree.NewAlterOptionLock(yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 575: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4640 - { - opt := tree.NewTableOptionCharset(yyDollar[1].str) - opt.NonCharsetSyntax = true - yyLOCAL = opt - } - yyVAL.union = yyLOCAL - case 576: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:4647 - { - yyVAL.str = "" - } - case 593: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:4678 - { - yyVAL.str = "" - } - case 594: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:4682 - { - yyVAL.str = string("COLUMN") - } - case 595: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.ColumnPosition -//line mysql_sql.y:4687 - { - var typ = tree.ColumnPositionNone - var relativeColumn *tree.UnresolvedName - yyLOCAL = tree.NewColumnPosition(typ, relativeColumn) - } - yyVAL.union = yyLOCAL - case 596: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.ColumnPosition -//line mysql_sql.y:4693 - { - var typ = tree.ColumnPositionFirst - var relativeColumn *tree.UnresolvedName - yyLOCAL = tree.NewColumnPosition(typ, relativeColumn) - } - yyVAL.union = yyLOCAL - case 597: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.ColumnPosition -//line mysql_sql.y:4699 - { - var typ = tree.ColumnPositionAfter - var relativeColumn = yyDollar[2].unresolvedNameUnion() - yyLOCAL = tree.NewColumnPosition(typ, relativeColumn) - } - yyVAL.union = yyLOCAL - case 598: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.AlterColumnOrder -//line mysql_sql.y:4707 - { - yyLOCAL = []*tree.AlterColumnOrder{yyDollar[1].alterColumnOrderUnion()} - } - yyVAL.union = yyLOCAL - case 599: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.AlterColumnOrder -//line mysql_sql.y:4711 - { - yyLOCAL = append(yyDollar[1].alterColumnOrderByUnion(), yyDollar[3].alterColumnOrderUnion()) - } - yyVAL.union = yyLOCAL - case 600: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.AlterColumnOrder -//line mysql_sql.y:4717 - { - var column = yyDollar[1].unresolvedNameUnion() - var direction = yyDollar[2].directionUnion() - yyLOCAL = tree.NewAlterColumnOrder(column, direction) - } - yyVAL.union = yyLOCAL - case 601: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4725 - { - var name = yyDollar[1].unresolvedObjectNameUnion() - yyLOCAL = tree.NewAlterOptionTableName(name) - } - yyVAL.union = yyLOCAL - case 602: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4732 - { - var dropType = tree.AlterTableDropIndex - var name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) - yyLOCAL = tree.NewAlterOptionDrop(dropType, name) - } - yyVAL.union = yyLOCAL - case 603: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4738 - { - var dropType = tree.AlterTableDropKey - var name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) - yyLOCAL = tree.NewAlterOptionDrop(dropType, name) - } - yyVAL.union = yyLOCAL - case 604: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4744 - { - var dropType = tree.AlterTableDropColumn - var name = tree.Identifier(yyDollar[1].cstrUnion().Compare()) - yyLOCAL = tree.NewAlterOptionDrop(dropType, name) - } - yyVAL.union = yyLOCAL - case 605: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4750 - { - var dropType = tree.AlterTableDropColumn - var name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) - yyLOCAL = tree.NewAlterOptionDrop(dropType, name) - } - yyVAL.union = yyLOCAL - case 606: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4756 - { - var dropType = tree.AlterTableDropForeignKey - var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) - yyLOCAL = tree.NewAlterOptionDrop(dropType, name) - - } - yyVAL.union = yyLOCAL - case 607: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4763 - { - yyLOCAL = &tree.AlterOptionDrop{ - Typ: tree.AlterTableDropConstraint, - Name: tree.Identifier(yyDollar[2].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 608: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4770 - { - yyLOCAL = tree.NewAlterOptionDrop(tree.AlterTableDropCheck, tree.Identifier(yyDollar[2].cstrUnion().Compare())) - } - yyVAL.union = yyLOCAL - case 609: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4774 - { - var dropType = tree.AlterTableDropPrimaryKey - var name = tree.Identifier("") - yyLOCAL = tree.NewAlterOptionDrop(dropType, name) - } - yyVAL.union = yyLOCAL - case 610: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4782 - { - var indexName = tree.Identifier(yyDollar[2].cstrUnion().Compare()) - var visibility = yyDollar[3].indexVisibilityUnion() - yyLOCAL = tree.NewAlterOptionAlterIndex(indexName, visibility) - } - yyVAL.union = yyLOCAL - case 611: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4788 - { - var io *tree.IndexOption = nil - if yyDollar[5].indexOptionUnion() == nil { - io = tree.NewIndexOption() - io.IType = tree.INDEX_TYPE_IVFFLAT - } else { - io = yyDollar[5].indexOptionUnion() - io.IType = tree.INDEX_TYPE_IVFFLAT - } - var name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) - var auto_update = yyDollar[4].boolValUnion() - io.AutoUpdate = auto_update - yyLOCAL = tree.NewAlterOptionAlterAutoUpdate(name, io) - } - yyVAL.union = yyLOCAL - case 612: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4803 - { - var checkType = yyDollar[1].str - var enforce = yyDollar[3].boolValUnion() - yyLOCAL = tree.NewAlterOptionAlterCheck(checkType, enforce) - } - yyVAL.union = yyLOCAL - case 613: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterTableOption -//line mysql_sql.y:4809 - { - var checkType = yyDollar[1].str - var enforce = yyDollar[3].boolValUnion() - yyLOCAL = tree.NewAlterOptionAlterCheck(checkType, enforce) - } - yyVAL.union = yyLOCAL - case 614: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.VisibleType -//line mysql_sql.y:4817 - { - yyLOCAL = tree.VISIBLE_TYPE_VISIBLE - } - yyVAL.union = yyLOCAL - case 615: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.VisibleType -//line mysql_sql.y:4821 - { - yyLOCAL = tree.VISIBLE_TYPE_INVISIBLE - } - yyVAL.union = yyLOCAL - case 616: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:4827 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 617: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:4831 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 618: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4837 - { - var ifExists = yyDollar[3].boolValUnion() - var name = yyDollar[4].exprUnion() - var authOption = yyDollar[5].alterAccountAuthOptionUnion() - var statusOption = yyDollar[6].accountStatusUnion() - var comment = yyDollar[7].accountCommentUnion() - - yyLOCAL = tree.NewAlterAccount( - ifExists, - name, - authOption, - statusOption, - comment, - ) - } - yyVAL.union = yyLOCAL - case 619: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4855 - { - yyLOCAL = &tree.AlterDatabase{Name: tree.Identifier(yyDollar[3].str), Options: yyDollar[4].createOptionsUnion()} - } - yyVAL.union = yyLOCAL - case 620: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4859 - { - yyLOCAL = &tree.AlterDatabase{Options: yyDollar[3].createOptionsUnion()} - } - yyVAL.union = yyLOCAL - case 621: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.CreateOption -//line mysql_sql.y:4865 - { - yyLOCAL = []tree.CreateOption{yyDollar[1].createOptionUnion()} - } - yyVAL.union = yyLOCAL - case 622: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []tree.CreateOption -//line mysql_sql.y:4869 - { - yyLOCAL = append(yyDollar[1].createOptionsUnion(), yyDollar[2].createOptionUnion()) - } - yyVAL.union = yyLOCAL - case 623: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.CreateOption -//line mysql_sql.y:4875 - { - yyLOCAL = tree.NewCreateOptionCharset(false, yyDollar[4].str) - } - yyVAL.union = yyLOCAL - case 624: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.CreateOption -//line mysql_sql.y:4879 - { - yyLOCAL = tree.NewCreateOptionCharset(true, yyDollar[5].str) - } - yyVAL.union = yyLOCAL - case 625: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.CreateOption -//line mysql_sql.y:4883 - { - yyLOCAL = tree.NewCreateOptionCollate(false, yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 626: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.CreateOption -//line mysql_sql.y:4887 - { - yyLOCAL = tree.NewCreateOptionCollate(true, yyDollar[4].str) - } - yyVAL.union = yyLOCAL - case 627: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4893 - { - var accountName = "" - var dbName = yyDollar[3].str - var isAccountLevel = false - var updateConfig = yyDollar[7].str - - yyLOCAL = tree.NewAlterDataBaseConfig( - accountName, - dbName, - isAccountLevel, - tree.MYSQL_COMPATIBILITY_MODE, - updateConfig, - ) - } - yyVAL.union = yyLOCAL - case 628: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4908 - { - var accountName = "" - var dbName = yyDollar[3].str - var isAccountLevel = false - var updateConfig = yyDollar[7].str - - yyLOCAL = tree.NewAlterDataBaseConfig( - accountName, - dbName, - isAccountLevel, - tree.UNIQUE_CHECK_ON_AUTOINCR, - updateConfig, - ) - } - yyVAL.union = yyLOCAL - case 629: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4923 - { - var accountName = yyDollar[4].str - var dbName = "" - var isAccountLevel = true - var updateConfig = yyDollar[8].str - - yyLOCAL = tree.NewAlterDataBaseConfig( - accountName, - dbName, - isAccountLevel, - tree.MYSQL_COMPATIBILITY_MODE, - updateConfig, - ) - } - yyVAL.union = yyLOCAL - case 630: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4938 - { - assignments := []*tree.VarAssignmentExpr{ - { - System: true, - Global: true, - Name: yyDollar[6].str, - Value: yyDollar[8].exprUnion(), - }, - } - yyLOCAL = &tree.SetVar{Assignments: assignments} - } - yyVAL.union = yyLOCAL - case 631: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.AlterAccountAuthOption -//line mysql_sql.y:4951 - { - yyLOCAL = tree.AlterAccountAuthOption{ - Exist: false, - } - } - yyVAL.union = yyLOCAL - case 632: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.AlterAccountAuthOption -//line mysql_sql.y:4957 - { - yyLOCAL = tree.AlterAccountAuthOption{ - Exist: true, - Equal: yyDollar[2].str, - AdminName: yyDollar[3].exprUnion(), - IdentifiedType: yyDollar[4].accountIdentifiedUnion(), - } - } - yyVAL.union = yyLOCAL - case 633: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4968 - { - // Create temporary variables with meaningful names - ifExists := yyDollar[3].boolValUnion() - users := yyDollar[4].usersUnion() - role := yyDollar[5].accountRoleUnion() - miscOpt := yyDollar[6].userMiscOptionUnion() - commentOrAttribute := yyDollar[7].accountCommentOrAttributeUnion() - - // Use the temporary variables to call the function - yyLOCAL = tree.NewAlterUser(ifExists, users, role, miscOpt, commentOrAttribute) - } - yyVAL.union = yyLOCAL - case 634: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4980 - { - ifExists := yyDollar[3].boolValUnion() - var Username = yyDollar[4].usernameRecordUnion().Username - var Hostname = yyDollar[4].usernameRecordUnion().Hostname - user := tree.NewUser(Username, Hostname, nil) - users := []*tree.User{user} - miscOpt := tree.NewUserMiscOptionAccountUnlock() - commentOrAttribute := yyDollar[6].accountCommentOrAttributeUnion() - yyLOCAL = tree.NewAlterUser(ifExists, users, nil, miscOpt, commentOrAttribute) - } - yyVAL.union = yyLOCAL - case 635: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:4991 - { - ifExists := yyDollar[3].boolValUnion() - var Username = yyDollar[4].usernameRecordUnion().Username - var Hostname = yyDollar[4].usernameRecordUnion().Hostname - user := tree.NewUser(Username, Hostname, nil) - users := []*tree.User{user} - miscOpt := tree.NewUserMiscOptionAccountLock() - commentOrAttribute := yyDollar[6].accountCommentOrAttributeUnion() - yyLOCAL = tree.NewAlterUser(ifExists, users, nil, miscOpt, commentOrAttribute) - } - yyVAL.union = yyLOCAL - case 636: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.Role -//line mysql_sql.y:5003 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 637: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.Role -//line mysql_sql.y:5007 - { - var UserName = yyDollar[3].str - yyLOCAL = tree.NewRole( - UserName, - ) - } - yyVAL.union = yyLOCAL - case 638: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:5015 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 639: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:5019 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 640: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5024 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 641: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5028 - { - yyLOCAL = yyDollar[1].userMiscOptionUnion() - } - yyVAL.union = yyLOCAL - case 642: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5044 - { - yyLOCAL = tree.NewUserMiscOptionAccountUnlock() - } - yyVAL.union = yyLOCAL - case 643: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5048 - { - yyLOCAL = tree.NewUserMiscOptionAccountLock() - } - yyVAL.union = yyLOCAL - case 644: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5052 - { - yyLOCAL = tree.NewUserMiscOptionPasswordExpireNone() - } - yyVAL.union = yyLOCAL - case 645: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5056 - { - Value, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - yyLOCAL = tree.NewUserMiscOptionPasswordExpireInterval( - Value, - ) - } - yyVAL.union = yyLOCAL - case 646: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5064 - { - yyLOCAL = tree.NewUserMiscOptionPasswordExpireNever() - } - yyVAL.union = yyLOCAL - case 647: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5068 - { - yyLOCAL = tree.NewUserMiscOptionPasswordExpireDefault() - } - yyVAL.union = yyLOCAL - case 648: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5072 - { - yyLOCAL = tree.NewUserMiscOptionPasswordHistoryDefault() - } - yyVAL.union = yyLOCAL - case 649: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5076 - { - Value, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - yyLOCAL = tree.NewUserMiscOptionPasswordHistoryCount( - Value, - ) - } - yyVAL.union = yyLOCAL - case 650: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5084 - { - yyLOCAL = tree.NewUserMiscOptionPasswordReuseIntervalDefault() - } - yyVAL.union = yyLOCAL - case 651: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5088 - { - Value, ok := signedIntegral(yylex, yyDollar[4].item) - if !ok { - goto ret1 - } - yyLOCAL = tree.NewUserMiscOptionPasswordReuseIntervalCount( - Value, - ) - } - yyVAL.union = yyLOCAL - case 652: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5096 - { - yyLOCAL = tree.NewUserMiscOptionPasswordRequireCurrentNone() - } - yyVAL.union = yyLOCAL - case 653: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5100 - { - yyLOCAL = tree.NewUserMiscOptionPasswordRequireCurrentDefault() - } - yyVAL.union = yyLOCAL - case 654: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5104 - { - yyLOCAL = tree.NewUserMiscOptionPasswordRequireCurrentOptional() - } - yyVAL.union = yyLOCAL - case 655: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5108 - { - Value, ok := signedIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - yyLOCAL = tree.NewUserMiscOptionFailedLoginAttempts( - Value, - ) - } - yyVAL.union = yyLOCAL - case 656: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5116 - { - Value, ok := signedIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - yyLOCAL = tree.NewUserMiscOptionPasswordLockTimeCount( - Value, - ) - } - yyVAL.union = yyLOCAL - case 657: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.UserMiscOption -//line mysql_sql.y:5124 - { - yyLOCAL = tree.NewUserMiscOptionPasswordLockTimeUnbounded() - } - yyVAL.union = yyLOCAL - case 658: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:5130 - { - yyVAL.item = nil - } - case 659: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:5135 - { - yyVAL.item = nil - } - case 705: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5190 - { - yyLOCAL = &tree.ShowSQLTasks{} - } - yyVAL.union = yyLOCAL - case 706: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5196 - { - stmt := &tree.ShowSQLTaskRuns{} - if yyDollar[4].str != "" { - stmt.TaskName = tree.Identifier(yyDollar[4].str) - stmt.HasTask = true - } - if yyDollar[5].int64ValUnion() >= 0 { - stmt.Limit = yyDollar[5].int64ValUnion() - stmt.HasLimit = true - } - yyLOCAL = stmt - } - yyVAL.union = yyLOCAL - case 707: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:5210 - { - yyVAL.str = "" - } - case 708: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:5214 - { - yyVAL.str = yyDollar[2].cstrUnion().Compare() - } - case 709: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:5219 - { - yyLOCAL = -1 - } - yyVAL.union = yyLOCAL - case 710: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:5223 - { - yyLOCAL = sqlTaskInt64(yyDollar[2].item) - } - yyVAL.union = yyLOCAL - case 711: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5229 - { - yyLOCAL = &tree.ShowIcebergCatalogs{ - Like: yyDollar[4].comparisionExprUnion(), - Where: yyDollar[5].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 712: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5237 - { - yyLOCAL = &tree.ShowIcebergNamespaces{ - Catalog: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - Like: yyDollar[6].comparisionExprUnion(), - Where: yyDollar[7].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 713: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5245 - { - yyLOCAL = &tree.ShowIcebergNamespaces{ - Catalog: tree.Identifier(yyDollar[6].cstrUnion().Compare()), - Like: yyDollar[7].comparisionExprUnion(), - Where: yyDollar[8].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 714: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5253 - { - yyLOCAL = &tree.ShowIcebergNamespaces{ - Like: yyDollar[4].comparisionExprUnion(), - Where: yyDollar[5].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 715: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5260 - { - yyLOCAL = &tree.ShowIcebergTables{ - Like: yyDollar[4].comparisionExprUnion(), - Where: yyDollar[5].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 716: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5267 - { - yyLOCAL = &tree.ShowIcebergTables{ - Catalog: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - Like: yyDollar[6].comparisionExprUnion(), - Where: yyDollar[7].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 717: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5275 - { - yyLOCAL = &tree.ShowIcebergTables{ - Catalog: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - Namespace: yyDollar[7].str, - Like: yyDollar[8].comparisionExprUnion(), - Where: yyDollar[9].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 718: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5284 - { - yyLOCAL = &tree.ShowIcebergTables{ - Catalog: tree.Identifier(yyDollar[6].cstrUnion().Compare()), - Like: yyDollar[7].comparisionExprUnion(), - Where: yyDollar[8].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 719: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5292 - { - yyLOCAL = &tree.ShowIcebergTables{ - Namespace: yyDollar[6].str, - Like: yyDollar[7].comparisionExprUnion(), - Where: yyDollar[8].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 720: - yyDollar = yyS[yypt-11 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5300 - { - yyLOCAL = &tree.ShowIcebergTables{ - Namespace: yyDollar[6].str, - Catalog: tree.Identifier(yyDollar[9].cstrUnion().Compare()), - Like: yyDollar[10].comparisionExprUnion(), - Where: yyDollar[11].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 721: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5311 - { - yyLOCAL = &tree.ShowMongoDBConnections{ - Like: yyDollar[4].comparisionExprUnion(), - Where: yyDollar[5].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 722: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:5320 - { - yyVAL.str = yyDollar[1].str - } - case 723: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5326 - { - yyLOCAL = &tree.ShowLogserviceReplicas{} - } - yyVAL.union = yyLOCAL - case 724: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5332 - { - yyLOCAL = &tree.ShowLogserviceStores{} - } - yyVAL.union = yyLOCAL - case 725: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5338 - { - yyLOCAL = &tree.ShowLogserviceSettings{} - } - yyVAL.union = yyLOCAL - case 726: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5344 - { - yyLOCAL = &tree.ShowRules{ - RoleName: yyDollar[5].cstrUnion().Compare(), - } - } - yyVAL.union = yyLOCAL - case 727: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5352 - { - yyLOCAL = &tree.ShowCollation{ - Like: yyDollar[3].comparisionExprUnion(), - Where: yyDollar[4].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 728: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5361 - { - yyLOCAL = &tree.ShowStages{ - Like: yyDollar[3].comparisionExprUnion(), - } - } - yyVAL.union = yyLOCAL - case 729: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5369 - { - yyLOCAL = &tree.ShowSnapShots{ - Where: yyDollar[3].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 730: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5377 - { - yyLOCAL = &tree.ShowPitr{ - Where: yyDollar[3].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 731: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5385 - { - yyLOCAL = &tree.ShowRecoveryWindow{ - Level: tree.RECOVERYWINDOWLEVELACCOUNT, - } - } - yyVAL.union = yyLOCAL - case 732: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5391 - { - yyLOCAL = &tree.ShowRecoveryWindow{ - Level: tree.RECOVERYWINDOWLEVELDATABASE, - DatabaseName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 733: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5398 - { - yyLOCAL = &tree.ShowRecoveryWindow{ - Level: tree.RECOVERYWINDOWLEVELTABLE, - DatabaseName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - TableName: tree.Identifier(yyDollar[6].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 734: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5406 - { - yyLOCAL = &tree.ShowRecoveryWindow{ - Level: tree.RECOVERYWINDOWLEVELACCOUNT, - AccountName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 735: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5415 - { - yyLOCAL = &tree.ShowGrants{ShowGrantType: tree.GrantForUser} - } - yyVAL.union = yyLOCAL - case 736: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5419 - { - yyLOCAL = &tree.ShowGrants{Username: yyDollar[4].usernameRecordUnion().Username, Hostname: yyDollar[4].usernameRecordUnion().Hostname, Roles: yyDollar[5].rolesUnion(), ShowGrantType: tree.GrantForUser} - } - yyVAL.union = yyLOCAL - case 737: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5423 - { - yyLOCAL = &tree.ShowGrants{CurrentUser: true, Roles: yyDollar[6].rolesUnion(), ShowGrantType: tree.GrantForUser} - } - yyVAL.union = yyLOCAL - case 738: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5427 - { - s := &tree.ShowGrants{} - roles := []*tree.Role{ - {UserName: yyDollar[5].cstrUnion().Compare()}, - } - s.Roles = roles - s.ShowGrantType = tree.GrantForRole - yyLOCAL = s - } - yyVAL.union = yyLOCAL - case 739: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []*tree.Role -//line mysql_sql.y:5438 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 740: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []*tree.Role -//line mysql_sql.y:5442 - { - yyLOCAL = yyDollar[2].rolesUnion() - } - yyVAL.union = yyLOCAL - case 741: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5448 - { - yyLOCAL = &tree.ShowTableStatus{DbName: yyDollar[5].str, Like: yyDollar[6].comparisionExprUnion(), Where: yyDollar[7].whereUnion()} - } - yyVAL.union = yyLOCAL - case 742: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:5453 - { - } - case 744: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:5457 - { - } - case 746: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5462 - { - yyLOCAL = &tree.ShowFunctionOrProcedureStatus{ - Like: yyDollar[4].comparisionExprUnion(), - Where: yyDollar[5].whereUnion(), - IsFunction: true, - } - } - yyVAL.union = yyLOCAL - case 747: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5472 - { - yyLOCAL = &tree.ShowFunctionOrProcedureStatus{ - Like: yyDollar[4].comparisionExprUnion(), - Where: yyDollar[5].whereUnion(), - IsFunction: false, - } - } - yyVAL.union = yyLOCAL - case 748: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5482 - { - yyLOCAL = &tree.ShowRolesStmt{ - Like: yyDollar[3].comparisionExprUnion(), - } - } - yyVAL.union = yyLOCAL - case 749: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5490 - { - yyLOCAL = &tree.ShowNodeList{} - } - yyVAL.union = yyLOCAL - case 750: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5496 - { - yyLOCAL = &tree.ShowLocks{} - } - yyVAL.union = yyLOCAL - case 751: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5502 - { - yyLOCAL = &tree.ShowTableNumber{DbName: yyDollar[4].str} - } - yyVAL.union = yyLOCAL - case 752: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5508 - { - yyLOCAL = &tree.ShowColumnNumber{Table: yyDollar[3].unresolvedObjectNameUnion(), DbName: yyDollar[4].str} - } - yyVAL.union = yyLOCAL - case 753: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5514 - { - yyLOCAL = &tree.ShowTableValues{Table: yyDollar[3].unresolvedObjectNameUnion(), DbName: yyDollar[4].str} - } - yyVAL.union = yyLOCAL - case 754: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5520 - { - yyLOCAL = &tree.ShowTableSize{Table: yyDollar[3].unresolvedObjectNameUnion(), DbName: yyDollar[4].str} - } - yyVAL.union = yyLOCAL - case 755: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5526 - { - s := yyDollar[2].statementUnion().(*tree.ShowTarget) - s.Like = yyDollar[3].comparisionExprUnion() - s.Where = yyDollar[4].whereUnion() - yyLOCAL = s - } - yyVAL.union = yyLOCAL - case 756: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5535 - { - yyLOCAL = &tree.ShowTarget{Type: tree.ShowConfig} - } - yyVAL.union = yyLOCAL - case 757: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5539 - { - yyLOCAL = &tree.ShowTarget{Type: tree.ShowCharset} - } - yyVAL.union = yyLOCAL - case 758: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5543 - { - yyLOCAL = &tree.ShowTarget{Type: tree.ShowEngines} - } - yyVAL.union = yyLOCAL - case 759: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5547 - { - yyLOCAL = &tree.ShowTarget{DbName: yyDollar[3].str, Type: tree.ShowTriggers} - } - yyVAL.union = yyLOCAL - case 760: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5551 - { - yyLOCAL = &tree.ShowTarget{DbName: yyDollar[3].str, Type: tree.ShowEvents} - } - yyVAL.union = yyLOCAL - case 761: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5555 - { - yyLOCAL = &tree.ShowTarget{Type: tree.ShowPlugins} - } - yyVAL.union = yyLOCAL - case 762: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5559 - { - yyLOCAL = &tree.ShowTarget{Type: tree.ShowPrivileges} - } - yyVAL.union = yyLOCAL - case 763: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5563 - { - yyLOCAL = &tree.ShowTarget{Type: tree.ShowProfiles} - } - yyVAL.union = yyLOCAL - case 764: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5569 - { - yyLOCAL = &tree.ShowIndex{ - TableName: yyDollar[4].unresolvedObjectNameUnion(), - DbName: yyDollar[5].str, - Where: yyDollar[6].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 765: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:5578 - { - } - case 766: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:5580 - { - } - case 770: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5589 - { - yyLOCAL = &tree.ShowVariables{ - Global: yyDollar[2].boolValUnion(), - Like: yyDollar[4].comparisionExprUnion(), - Where: yyDollar[5].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 771: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5599 - { - yyLOCAL = &tree.ShowStatus{ - Global: yyDollar[2].boolValUnion(), - Like: yyDollar[4].comparisionExprUnion(), - Where: yyDollar[5].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 772: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:5608 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 773: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:5612 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 774: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:5616 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 775: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5622 - { - yyLOCAL = &tree.ShowWarnings{Limit: yyDollar[3].limitUnion()} - } - yyVAL.union = yyLOCAL - case 776: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5626 - { - yyLOCAL = &tree.ShowWarnings{Count: true} - } - yyVAL.union = yyLOCAL - case 777: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5632 - { - yyLOCAL = &tree.ShowErrors{Limit: yyDollar[3].limitUnion()} - } - yyVAL.union = yyLOCAL - case 778: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5636 - { - yyLOCAL = &tree.ShowErrors{Count: true} - } - yyVAL.union = yyLOCAL - case 779: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5642 - { - yyLOCAL = &tree.ShowProcessList{Full: yyDollar[2].fullOptUnion()} - } - yyVAL.union = yyLOCAL - case 780: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5648 - { - yyLOCAL = &tree.ShowSequences{ - DBName: yyDollar[3].str, - Where: yyDollar[4].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 781: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5657 - { - yyLOCAL = &tree.ShowTables{ - Open: false, - Full: yyDollar[2].fullOptUnion(), - DBName: yyDollar[4].str, - Like: yyDollar[5].comparisionExprUnion(), - Where: yyDollar[6].whereUnion(), - AtTsExpr: yyDollar[7].atTimeStampUnion(), - } - } - yyVAL.union = yyLOCAL - case 782: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5668 - { - yyLOCAL = &tree.ShowTables{ - Open: true, - Full: yyDollar[3].fullOptUnion(), - DBName: yyDollar[5].str, - Like: yyDollar[6].comparisionExprUnion(), - Where: yyDollar[7].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 783: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5680 - { - yyLOCAL = &tree.ShowDatabases{ - Like: yyDollar[3].comparisionExprUnion(), - Where: yyDollar[4].whereUnion(), - AtTsExpr: yyDollar[5].atTimeStampUnion(), - } - } - yyVAL.union = yyLOCAL - case 784: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5688 - { - yyLOCAL = &tree.ShowDatabases{Like: yyDollar[3].comparisionExprUnion(), Where: yyDollar[4].whereUnion()} - } - yyVAL.union = yyLOCAL - case 785: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5694 - { - yyLOCAL = &tree.ShowColumns{ - Ext: false, - Full: yyDollar[2].fullOptUnion(), - Table: yyDollar[4].unresolvedObjectNameUnion(), - // colName: $3, - DBName: yyDollar[5].str, - Like: yyDollar[6].comparisionExprUnion(), - Where: yyDollar[7].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 786: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5706 - { - yyLOCAL = &tree.ShowColumns{ - Ext: true, - Full: yyDollar[3].fullOptUnion(), - Table: yyDollar[5].unresolvedObjectNameUnion(), - // colName: $3, - DBName: yyDollar[6].str, - Like: yyDollar[7].comparisionExprUnion(), - Where: yyDollar[8].whereUnion(), - } - } - yyVAL.union = yyLOCAL - case 787: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5720 - { - yyLOCAL = &tree.ShowAccounts{Like: yyDollar[3].comparisionExprUnion()} - } - yyVAL.union = yyLOCAL - case 788: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5726 - { - yyLOCAL = &tree.ShowPublications{Like: yyDollar[3].comparisionExprUnion()} - } - yyVAL.union = yyLOCAL - case 789: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5732 - { - yyLOCAL = &tree.ShowPublicationCoverage{Name: yyDollar[4].str} - } - yyVAL.union = yyLOCAL - case 790: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5738 - { - yyLOCAL = &tree.ShowAccountUpgrade{} - } - yyVAL.union = yyLOCAL - case 791: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5744 - { - yyLOCAL = &tree.ShowSubscriptions{Like: yyDollar[3].comparisionExprUnion()} - } - yyVAL.union = yyLOCAL - case 792: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5748 - { - yyLOCAL = &tree.ShowSubscriptions{All: true, Like: yyDollar[4].comparisionExprUnion()} - } - yyVAL.union = yyLOCAL - case 793: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5754 - { - yyLOCAL = &tree.ShowCcprSubscriptions{TaskId: yyDollar[4].str} - } - yyVAL.union = yyLOCAL - case 794: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5758 - { - yyLOCAL = &tree.ShowCcprSubscriptions{} - } - yyVAL.union = yyLOCAL - case 795: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.ComparisonExpr -//line mysql_sql.y:5763 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 796: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.ComparisonExpr -//line mysql_sql.y:5767 - { - yyLOCAL = tree.NewComparisonExpr(tree.LIKE, nil, yyDollar[2].exprUnion()) - } - yyVAL.union = yyLOCAL - case 797: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.ComparisonExpr -//line mysql_sql.y:5771 - { - yyLOCAL = tree.NewComparisonExpr(tree.ILIKE, nil, yyDollar[2].exprUnion()) - } - yyVAL.union = yyLOCAL - case 798: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:5776 - { - yyVAL.str = "" - } - case 799: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:5780 - { - yyVAL.str = yyDollar[2].cstrUnion().Compare() - } - case 800: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.UnresolvedObjectName -//line mysql_sql.y:5786 - { - yyLOCAL = yyDollar[2].unresolvedObjectNameUnion() - } - yyVAL.union = yyLOCAL - case 805: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:5799 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 806: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:5803 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 807: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5809 - { - yyLOCAL = &tree.ShowCreateTable{ - Name: yyDollar[4].unresolvedObjectNameUnion(), - AtTsExpr: yyDollar[5].atTimeStampUnion(), - } - } - yyVAL.union = yyLOCAL - case 808: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5817 - { - yyLOCAL = &tree.ShowCreateView{ - Name: yyDollar[4].unresolvedObjectNameUnion(), - AtTsExpr: yyDollar[5].atTimeStampUnion(), - } - } - yyVAL.union = yyLOCAL - case 809: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5824 - { - yyLOCAL = &tree.ShowCreateDatabase{ - IfNotExists: yyDollar[4].ifNotExistsUnion(), - Name: yyDollar[5].str, - AtTsExpr: yyDollar[6].atTimeStampUnion(), - } - } - yyVAL.union = yyLOCAL - case 810: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5832 - { - yyLOCAL = &tree.ShowCreatePublications{Name: yyDollar[4].str} - } - yyVAL.union = yyLOCAL - case 811: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5838 - { - yyLOCAL = &tree.ShowBackendServers{} - } - yyVAL.union = yyLOCAL - case 812: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.UnresolvedObjectName -//line mysql_sql.y:5844 - { - tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedObjectName(tblName) - } - yyVAL.union = yyLOCAL - case 813: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.UnresolvedObjectName -//line mysql_sql.y:5849 - { - dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[3].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedObjectName(dbName, tblName) - } - yyVAL.union = yyLOCAL - case 814: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:5857 - { - yyVAL.str = yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - } - case 815: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.UnresolvedObjectName -//line mysql_sql.y:5863 - { - tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedObjectName(tblName) - } - yyVAL.union = yyLOCAL - case 816: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.UnresolvedObjectName -//line mysql_sql.y:5868 - { - dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[3].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedObjectName(dbName, tblName) - } - yyVAL.union = yyLOCAL - case 817: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.UnresolvedObjectName -//line mysql_sql.y:5874 - { - yyLOCAL = tree.NewUnresolvedObjectName(yyDollar[1].cstrUnion().Compare(), yyDollar[3].cstrUnion().Compare(), yyDollar[5].cstrUnion().Compare()) - } - yyVAL.union = yyLOCAL - case 818: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5880 - { - yyLOCAL = tree.NewTruncateTable(yyDollar[2].tableNameUnion()) - } - yyVAL.union = yyLOCAL - case 819: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5884 - { - yyLOCAL = tree.NewTruncateTable(yyDollar[3].tableNameUnion()) - } - yyVAL.union = yyLOCAL - case 841: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5915 - { - yyLOCAL = &tree.DropSQLTask{ - IfExists: yyDollar[3].boolValUnion(), - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 842: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5924 - { - yyLOCAL = &tree.DropIcebergCatalog{ - IfExists: yyDollar[4].boolValUnion(), - Name: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 843: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5933 - { - yyLOCAL = &tree.DropMongoDBConnection{ - IfExists: yyDollar[4].boolValUnion(), - Name: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 844: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5942 - { - var ifExists = yyDollar[3].boolValUnion() - var name = yyDollar[4].tableNamesUnion() - yyLOCAL = tree.NewDropSequence(ifExists, name) - } - yyVAL.union = yyLOCAL - case 845: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5950 - { - var ifExists = yyDollar[3].boolValUnion() - var name = yyDollar[4].exprUnion() - yyLOCAL = tree.NewDropAccount(ifExists, name) - } - yyVAL.union = yyLOCAL - case 846: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5958 - { - var ifExists = yyDollar[3].boolValUnion() - var users = yyDollar[4].usersUnion() - yyLOCAL = tree.NewDropUser(ifExists, users) - } - yyVAL.union = yyLOCAL - case 847: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.User -//line mysql_sql.y:5966 - { - yyLOCAL = []*tree.User{yyDollar[1].userUnion()} - } - yyVAL.union = yyLOCAL - case 848: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.User -//line mysql_sql.y:5970 - { - yyLOCAL = append(yyDollar[1].usersUnion(), yyDollar[3].userUnion()) - } - yyVAL.union = yyLOCAL - case 849: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.User -//line mysql_sql.y:5976 - { - var Username = yyDollar[1].usernameRecordUnion().Username - var Hostname = yyDollar[1].usernameRecordUnion().Hostname - var AuthOption *tree.AccountIdentified - yyLOCAL = tree.NewUser( - Username, - Hostname, - AuthOption, - ) - } - yyVAL.union = yyLOCAL - case 850: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5989 - { - var ifExists = yyDollar[3].boolValUnion() - var roles = yyDollar[4].rolesUnion() - yyLOCAL = tree.NewDropRole(ifExists, roles) - } - yyVAL.union = yyLOCAL - case 851: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:5997 - { - var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - var tableName = yyDollar[6].tableNameUnion() - var ifExists = yyDollar[3].boolValUnion() - yyLOCAL = tree.NewDropIndex(name, tableName, ifExists) - } - yyVAL.union = yyLOCAL - case 852: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6006 - { - var ifExists = yyDollar[4].boolValUnion() - var names = yyDollar[5].tableNamesUnion() - var stmt = tree.NewDropTable(ifExists, names) - stmt.Temporary = yyDollar[2].boolValUnion() - yyLOCAL = stmt - } - yyVAL.union = yyLOCAL - case 853: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6016 - { - var ifExists = yyDollar[3].boolValUnion() - var names = yyDollar[4].tableNamesUnion() - yyLOCAL = tree.NewDropView(ifExists, names) - } - yyVAL.union = yyLOCAL - case 854: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6024 - { - var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - var ifExists = yyDollar[3].boolValUnion() - yyLOCAL = tree.NewDropDatabase(name, ifExists) - } - yyVAL.union = yyLOCAL - case 855: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6030 - { - var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - var ifExists = yyDollar[3].boolValUnion() - yyLOCAL = tree.NewDropDatabase(name, ifExists) - } - yyVAL.union = yyLOCAL - case 856: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6038 - { - yyLOCAL = tree.NewDeallocate(tree.Identifier(yyDollar[3].str), true) - } - yyVAL.union = yyLOCAL - case 857: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6044 - { - var ifExists = yyDollar[3].boolValUnion() - var name = yyDollar[4].functionNameUnion() - var args = yyDollar[6].funcArgsUnion() - var dropFunction = tree.NewDropFunction(name, args) - dropFunction.IfExists = ifExists - yyLOCAL = dropFunction - } - yyVAL.union = yyLOCAL - case 858: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6055 - { - var name = yyDollar[3].procNameUnion() - var ifExists = false - yyLOCAL = tree.NewDropProcedure(name, ifExists) - } - yyVAL.union = yyLOCAL - case 859: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6061 - { - var name = yyDollar[5].procNameUnion() - var ifExists = true - yyLOCAL = tree.NewDropProcedure(name, ifExists) - } - yyVAL.union = yyLOCAL - case 860: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6069 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[1].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = yyDollar[1].statementUnion() - } - yyVAL.union = yyLOCAL - case 861: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6077 - { - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[1].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = yyDollar[1].statementUnion() - } - yyVAL.union = yyLOCAL - case 862: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6085 - { - yyDollar[2].statementUnion().(*tree.Delete).With = yyDollar[1].withClauseUnion() - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[2].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = yyDollar[2].statementUnion() - } - yyVAL.union = yyLOCAL - case 863: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6094 - { - yyDollar[2].statementUnion().(*tree.Delete).With = yyDollar[1].withClauseUnion() - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[2].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = yyDollar[2].statementUnion() - } - yyVAL.union = yyLOCAL - case 864: - yyDollar = yyS[yypt-12 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6105 - { - // Single-Table Syntax - t := &tree.AliasedTableExpr{ - Expr: yyDollar[6].tableNameUnion(), - As: tree.AliasClause{ - Alias: tree.Identifier(yyDollar[8].str), - }, - } - yyLOCAL = &tree.Delete{ - Tables: tree.TableExprs{t}, - Priority: yyDollar[2].str, - Quick: yyDollar[3].str != "", - Ignore: yyDollar[4].str != "", - PartitionNames: yyDollar[7].identifierListUnion(), - Where: yyDollar[9].whereUnion(), - OrderBy: yyDollar[10].orderByUnion(), - Limit: yyDollar[11].limitUnion(), - Returning: yyDollar[12].selectExprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 865: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6126 - { - // Multiple-Table Syntax - yyLOCAL = &tree.Delete{ - Tables: yyDollar[5].tableExprsUnion(), - Priority: yyDollar[2].str, - Quick: yyDollar[3].str != "", - Ignore: yyDollar[4].str != "", - Where: yyDollar[8].whereUnion(), - TableRefs: tree.TableExprs{yyDollar[7].tableExprUnion()}, - Returning: yyDollar[9].selectExprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 866: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6141 - { - // Multiple-Table Syntax - yyLOCAL = &tree.Delete{ - Tables: yyDollar[6].tableExprsUnion(), - Priority: yyDollar[2].str, - Quick: yyDollar[3].str != "", - Ignore: yyDollar[4].str != "", - Where: yyDollar[9].whereUnion(), - TableRefs: tree.TableExprs{yyDollar[8].tableExprUnion()}, - Returning: yyDollar[10].selectExprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 867: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableExprs -//line mysql_sql.y:6156 - { - yyLOCAL = tree.TableExprs{yyDollar[1].tableNameUnion()} - } - yyVAL.union = yyLOCAL - case 868: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableExprs -//line mysql_sql.y:6160 - { - yyLOCAL = append(yyDollar[1].tableExprsUnion(), yyDollar[3].tableNameUnion()) - } - yyVAL.union = yyLOCAL - case 869: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.TableName -//line mysql_sql.y:6166 - { - tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - prefix := tree.ObjectNamePrefix{ExplicitSchema: false} - yyLOCAL = tree.NewTableName(tree.Identifier(tblName), prefix, nil) - } - yyVAL.union = yyLOCAL - case 870: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.TableName -//line mysql_sql.y:6172 - { - dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[3].cstrUnion().Origin()) - prefix := tree.ObjectNamePrefix{SchemaName: tree.Identifier(dbName), ExplicitSchema: true} - yyLOCAL = tree.NewTableName(tree.Identifier(tblName), prefix, nil) - } - yyVAL.union = yyLOCAL - case 871: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:6181 - { - } - case 872: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:6183 - { - } - case 873: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:6186 - { - yyVAL.str = "" - } - case 878: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:6195 - { - yyVAL.str = "" - } - case 880: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:6199 - { - yyVAL.str = "" - } - case 881: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:6203 - { - yyVAL.str = "ignore" - } - case 882: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:6211 - { - } - case 885: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6217 - { - rep := yyDollar[5].replaceUnion() - if intoErr := tree.ValidateSelectIntoNotAllowed(rep.Rows); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - rep.Table = yyDollar[3].tableExprUnion() - target := yyDollar[3].tableExprUnion().(*tree.TableName) - rep.TargetDatabaseName = target.SchemaName - rep.TargetTableName = target.ObjectName - rep.PartitionNames = yyDollar[4].identifierListUnion() - rep.Returning = yyDollar[6].selectExprsUnion() - yyLOCAL = rep - } - yyVAL.union = yyLOCAL - case 886: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.Replace -//line mysql_sql.y:6234 - { - vc := tree.NewValuesClause(yyDollar[2].rowsExprsUnion()) - yyLOCAL = &tree.Replace{ - Rows: tree.NewSelect(vc, nil, nil), - } - } - yyVAL.union = yyLOCAL - case 887: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Replace -//line mysql_sql.y:6241 - { - yyLOCAL = &tree.Replace{ - Rows: yyDollar[1].selectUnion(), - } - } - yyVAL.union = yyLOCAL - case 888: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.Replace -//line mysql_sql.y:6247 - { - vc := tree.NewValuesClause(yyDollar[5].rowsExprsUnion()) - yyLOCAL = &tree.Replace{ - Columns: yyDollar[2].insertColumnsUnion().Identifiers, - ColumnNames: yyDollar[2].insertColumnsUnion().Names, - Rows: tree.NewSelect(vc, nil, nil), - } - } - yyVAL.union = yyLOCAL - case 889: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Replace -//line mysql_sql.y:6256 - { - vc := tree.NewValuesClause(yyDollar[4].rowsExprsUnion()) - yyLOCAL = &tree.Replace{ - Rows: tree.NewSelect(vc, nil, nil), - } - } - yyVAL.union = yyLOCAL - case 890: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Replace -//line mysql_sql.y:6263 - { - yyLOCAL = &tree.Replace{ - Columns: yyDollar[2].insertColumnsUnion().Identifiers, - ColumnNames: yyDollar[2].insertColumnsUnion().Names, - Rows: yyDollar[4].selectUnion(), - } - } - yyVAL.union = yyLOCAL - case 891: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.Replace -//line mysql_sql.y:6271 - { - if yyDollar[2].assignmentsUnion() == nil { - yylex.Error("the set list of replace can not be empty") - goto ret1 - } - var identList tree.IdentifierList - var columnNames []*tree.UnresolvedName - var valueList tree.Exprs - for _, a := range yyDollar[2].assignmentsUnion() { - identList = append(identList, a.Column) - columnNames = append(columnNames, a.ColumnName) - valueList = append(valueList, a.Expr) - } - vc := tree.NewValuesClause([]tree.Exprs{valueList}) - yyLOCAL = &tree.Replace{ - Columns: identList, - ColumnNames: columnNames, - Rows: tree.NewSelect(vc, nil, nil), - IsSetFormat: true, - } - } - yyVAL.union = yyLOCAL - case 893: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6296 - { - yyDollar[2].statementUnion().(*tree.Insert).With = yyDollar[1].withClauseUnion() - if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[2].statementUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = yyDollar[2].statementUnion() - } - yyVAL.union = yyLOCAL - case 895: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6306 - { - yyDollar[2].statementUnion().(*tree.MultiInsert).With = yyDollar[1].withClauseUnion() - yyLOCAL = yyDollar[2].statementUnion() - } - yyVAL.union = yyLOCAL - case 896: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6316 - { - if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[4].selectUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = &tree.MultiInsert{Targets: yyDollar[3].multiInsertTargetsUnion(), Source: yyDollar[4].selectUnion()} - } - yyVAL.union = yyLOCAL - case 897: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6324 - { - if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[5].selectUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = &tree.MultiInsert{Whens: yyDollar[3].multiInsertWhensUnion(), Else: yyDollar[4].multiInsertTargetsUnion(), Source: yyDollar[5].selectUnion()} - } - yyVAL.union = yyLOCAL - case 898: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6332 - { - if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[5].selectUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = &tree.MultiInsert{First: true, Whens: yyDollar[3].multiInsertWhensUnion(), Else: yyDollar[4].multiInsertTargetsUnion(), Source: yyDollar[5].selectUnion()} - } - yyVAL.union = yyLOCAL - case 899: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.MultiInsertWhen -//line mysql_sql.y:6342 - { - yyLOCAL = []*tree.MultiInsertWhen{yyDollar[1].multiInsertWhenUnion()} - } - yyVAL.union = yyLOCAL - case 900: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []*tree.MultiInsertWhen -//line mysql_sql.y:6346 - { - yyLOCAL = append(yyDollar[1].multiInsertWhensUnion(), yyDollar[2].multiInsertWhenUnion()) - } - yyVAL.union = yyLOCAL - case 901: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.MultiInsertWhen -//line mysql_sql.y:6352 - { - yyLOCAL = &tree.MultiInsertWhen{Cond: yyDollar[2].exprUnion(), Targets: yyDollar[4].multiInsertTargetsUnion()} - } - yyVAL.union = yyLOCAL - case 902: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []*tree.MultiInsertTarget -//line mysql_sql.y:6357 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 903: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []*tree.MultiInsertTarget -//line mysql_sql.y:6361 - { - yyLOCAL = yyDollar[2].multiInsertTargetsUnion() - } - yyVAL.union = yyLOCAL - case 904: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.MultiInsertTarget -//line mysql_sql.y:6367 - { - yyLOCAL = []*tree.MultiInsertTarget{yyDollar[1].multiInsertTargetUnion()} - } - yyVAL.union = yyLOCAL - case 905: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []*tree.MultiInsertTarget -//line mysql_sql.y:6371 - { - yyLOCAL = append(yyDollar[1].multiInsertTargetsUnion(), yyDollar[2].multiInsertTargetUnion()) - } - yyVAL.union = yyLOCAL - case 906: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.MultiInsertTarget -//line mysql_sql.y:6377 - { - yyLOCAL = &tree.MultiInsertTarget{Table: yyDollar[2].tableNameUnion()} - } - yyVAL.union = yyLOCAL - case 907: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.MultiInsertTarget -//line mysql_sql.y:6381 - { - yyLOCAL = &tree.MultiInsertTarget{Table: yyDollar[2].tableNameUnion(), Values: yyDollar[5].exprsUnion()} - } - yyVAL.union = yyLOCAL - case 908: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.MultiInsertTarget -//line mysql_sql.y:6385 - { - yyLOCAL = &tree.MultiInsertTarget{Table: yyDollar[2].tableNameUnion(), Columns: yyDollar[4].insertColumnsUnion().Identifiers, ColumnNames: yyDollar[4].insertColumnsUnion().Names} - } - yyVAL.union = yyLOCAL - case 909: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL *tree.MultiInsertTarget -//line mysql_sql.y:6389 - { - yyLOCAL = &tree.MultiInsertTarget{Table: yyDollar[2].tableNameUnion(), Columns: yyDollar[4].insertColumnsUnion().Identifiers, ColumnNames: yyDollar[4].insertColumnsUnion().Names, Values: yyDollar[8].exprsUnion()} - } - yyVAL.union = yyLOCAL - case 910: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6395 - { - ins := yyDollar[4].insertUnion() - if intoErr := tree.ValidateSelectIntoNotAllowed(ins.Rows); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - ins.Table = yyDollar[2].tableExprUnion() - target := yyDollar[2].tableExprUnion().(*tree.TableName) - ins.TargetDatabaseName = target.SchemaName - ins.TargetTableName = target.ObjectName - if yyDollar[3].insertPartitionUnion() != nil { - ins.PartitionNames = yyDollar[3].insertPartitionUnion().Names - ins.PartitionValues = yyDollar[3].insertPartitionUnion().Values - } - ins.OnDuplicateUpdate = yyDollar[5].updateExprsUnion() - if len(ins.OnDuplicateUpdate) == 1 && ins.OnDuplicateUpdate[0] == nil { - ins.Ignore = true - ins.OnDuplicateUpdate = nil - } - ins.Returning = yyDollar[6].selectExprsUnion() - yyLOCAL = ins - } - yyVAL.union = yyLOCAL - case 911: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6418 - { - ins := yyDollar[5].insertUnion() - if intoErr := tree.ValidateSelectIntoNotAllowed(ins.Rows); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - ins.Table = yyDollar[3].tableExprUnion() - target := yyDollar[3].tableExprUnion().(*tree.TableName) - ins.TargetDatabaseName = target.SchemaName - ins.TargetTableName = target.ObjectName - if yyDollar[4].insertPartitionUnion() != nil { - ins.PartitionNames = yyDollar[4].insertPartitionUnion().Names - ins.PartitionValues = yyDollar[4].insertPartitionUnion().Values - } - ins.Overwrite = true - ins.Returning = yyDollar[6].selectExprsUnion() - yyLOCAL = ins - } - yyVAL.union = yyLOCAL - case 912: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6437 - { - ins := yyDollar[5].insertUnion() - if intoErr := tree.ValidateSelectIntoNotAllowed(ins.Rows); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - ins.Table = yyDollar[3].tableExprUnion() - target := yyDollar[3].tableExprUnion().(*tree.TableName) - ins.TargetDatabaseName = target.SchemaName - ins.TargetTableName = target.ObjectName - if yyDollar[4].insertPartitionUnion() != nil { - ins.PartitionNames = yyDollar[4].insertPartitionUnion().Names - ins.PartitionValues = yyDollar[4].insertPartitionUnion().Values - } - ins.Ignore = true - ins.OnDuplicateUpdate = nil - ins.Returning = yyDollar[6].selectExprsUnion() - yyLOCAL = ins - } - yyVAL.union = yyLOCAL - case 913: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6457 - { - ins := yyDollar[5].insertUnion() - if intoErr := tree.ValidateSelectIntoNotAllowed(ins.Rows); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - ins.Table = yyDollar[3].tableExprUnion() - target := yyDollar[3].tableExprUnion().(*tree.TableName) - ins.TargetDatabaseName = target.SchemaName - ins.TargetTableName = target.ObjectName - if yyDollar[4].insertPartitionUnion() != nil { - ins.PartitionNames = yyDollar[4].insertPartitionUnion().Names - ins.PartitionValues = yyDollar[4].insertPartitionUnion().Values - } - ins.Ignore = true - ins.OnDuplicateUpdate = yyDollar[6].updateExprsUnion() - if len(ins.OnDuplicateUpdate) == 1 && ins.OnDuplicateUpdate[0] == nil { - ins.OnDuplicateUpdate = nil - } - ins.Returning = yyDollar[7].selectExprsUnion() - yyLOCAL = ins - } - yyVAL.union = yyLOCAL - case 914: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.SelectExprs -//line mysql_sql.y:6481 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 915: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.SelectExprs -//line mysql_sql.y:6485 - { - yyLOCAL = yyDollar[2].selectExprsUnion() - } - yyVAL.union = yyLOCAL - case 916: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6491 - { - yyLOCAL = yyDollar[1].mergeUnion() - } - yyVAL.union = yyLOCAL - case 917: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:6495 - { - yyDollar[2].mergeUnion().With = yyDollar[1].withClauseUnion() - yyLOCAL = yyDollar[2].mergeUnion() - } - yyVAL.union = yyLOCAL - case 918: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL *tree.Merge -//line mysql_sql.y:6502 - { - yyLOCAL = &tree.Merge{ - Target: yyDollar[3].tableExprUnion(), - Source: yyDollar[5].tableExprUnion(), - On: yyDollar[7].exprUnion(), - Clauses: yyDollar[8].mergeClausesUnion(), - } - } - yyVAL.union = yyLOCAL - case 919: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL *tree.Merge -//line mysql_sql.y:6511 - { - yyLOCAL = &tree.Merge{ - Target: yyDollar[3].tableExprUnion(), - Source: yyDollar[5].tableExprUnion(), - On: yyDollar[7].exprUnion(), - Clauses: yyDollar[8].mergeClausesUnion(), - Returning: yyDollar[10].selectExprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 920: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.MergeClauses -//line mysql_sql.y:6523 - { - yyLOCAL = tree.MergeClauses{yyDollar[1].mergeClauseUnion()} - } - yyVAL.union = yyLOCAL - case 921: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.MergeClauses -//line mysql_sql.y:6527 - { - yyLOCAL = append(yyDollar[1].mergeClausesUnion(), yyDollar[2].mergeClauseUnion()) - } - yyVAL.union = yyLOCAL - case 922: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL *tree.MergeClause -//line mysql_sql.y:6533 - { - yyLOCAL = &tree.MergeClause{ - Matched: true, - Condition: yyDollar[3].exprUnion(), - Action: tree.MergeActionUpdate, - UpdateExprs: yyDollar[7].updateExprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 923: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.MergeClause -//line mysql_sql.y:6542 - { - yyLOCAL = &tree.MergeClause{ - Matched: true, - Condition: yyDollar[3].exprUnion(), - Action: tree.MergeActionDelete, - } - } - yyVAL.union = yyLOCAL - case 924: - yyDollar = yyS[yypt-13 : yypt+1] - var yyLOCAL *tree.MergeClause -//line mysql_sql.y:6550 - { - yyLOCAL = &tree.MergeClause{ - Matched: false, - Condition: yyDollar[4].exprUnion(), - Action: tree.MergeActionInsert, - InsertColumns: yyDollar[8].identifierListUnion(), - InsertValues: yyDollar[12].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 925: - yyDollar = yyS[yypt-13 : yypt+1] - var yyLOCAL *tree.MergeClause -//line mysql_sql.y:6560 - { - yyLOCAL = &tree.MergeClause{ - Matched: false, - Condition: yyDollar[4].exprUnion(), - Action: tree.MergeActionInsert, - InsertColumns: yyDollar[8].identifierListUnion(), - InsertValues: yyDollar[12].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 926: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL *tree.MergeClause -//line mysql_sql.y:6570 - { - yyLOCAL = &tree.MergeClause{ - Matched: false, - Condition: yyDollar[4].exprUnion(), - Action: tree.MergeActionInsert, - InsertValues: yyDollar[9].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 927: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL *tree.MergeClause -//line mysql_sql.y:6579 - { - yyLOCAL = &tree.MergeClause{ - Matched: false, - Condition: yyDollar[4].exprUnion(), - Action: tree.MergeActionInsert, - InsertValues: yyDollar[9].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 928: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:6590 - { - if !strings.EqualFold(yyDollar[1].cstrUnion().Origin(), "matched") { - yylex.Error("expected MATCHED") - goto ret1 - } - yyVAL.str = yyDollar[1].cstrUnion().Origin() - } - case 929: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:6599 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 930: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:6603 - { - yyLOCAL = yyDollar[2].exprUnion() - } - yyVAL.union = yyLOCAL - case 931: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:6609 - { - yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].str)} - } - yyVAL.union = yyLOCAL - case 932: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:6613 - { - yyLOCAL = append(yyDollar[1].identifierListUnion(), tree.Identifier(yyDollar[3].str)) - } - yyVAL.union = yyLOCAL - case 933: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.Insert -//line mysql_sql.y:6619 - { - vc := tree.NewValuesClause(yyDollar[2].rowsExprsUnion()) - yyLOCAL = &tree.Insert{ - Rows: tree.NewSelect(vc, nil, nil), - } - } - yyVAL.union = yyLOCAL - case 934: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Insert -//line mysql_sql.y:6626 - { - yyLOCAL = &tree.Insert{ - Rows: yyDollar[1].selectUnion(), - } - } - yyVAL.union = yyLOCAL - case 935: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.Insert -//line mysql_sql.y:6632 - { - vc := tree.NewValuesClause(yyDollar[5].rowsExprsUnion()) - yyLOCAL = &tree.Insert{ - Columns: yyDollar[2].insertColumnsUnion().Identifiers, - ColumnNames: yyDollar[2].insertColumnsUnion().Names, - Rows: tree.NewSelect(vc, nil, nil), - } - } - yyVAL.union = yyLOCAL - case 936: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Insert -//line mysql_sql.y:6641 - { - vc := tree.NewValuesClause(yyDollar[4].rowsExprsUnion()) - yyLOCAL = &tree.Insert{ - Rows: tree.NewSelect(vc, nil, nil), - } - } - yyVAL.union = yyLOCAL - case 937: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Insert -//line mysql_sql.y:6648 - { - yyLOCAL = &tree.Insert{ - Columns: yyDollar[2].insertColumnsUnion().Identifiers, - ColumnNames: yyDollar[2].insertColumnsUnion().Names, - Rows: yyDollar[4].selectUnion(), - } - } - yyVAL.union = yyLOCAL - case 938: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.Insert -//line mysql_sql.y:6656 - { - if yyDollar[2].assignmentsUnion() == nil { - yylex.Error("the set list of insert can not be empty") - goto ret1 - } - var identList tree.IdentifierList - var columnNames []*tree.UnresolvedName - var valueList tree.Exprs - for _, a := range yyDollar[2].assignmentsUnion() { - identList = append(identList, a.Column) - columnNames = append(columnNames, a.ColumnName) - valueList = append(valueList, a.Expr) - } - vc := tree.NewValuesClause([]tree.Exprs{valueList}) - yyLOCAL = &tree.Insert{ - Columns: identList, - ColumnNames: columnNames, - Rows: tree.NewSelect(vc, nil, nil), - } - } - yyVAL.union = yyLOCAL - case 939: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.UpdateExprs -//line mysql_sql.y:6678 - { - yyLOCAL = []*tree.UpdateExpr{} - } - yyVAL.union = yyLOCAL - case 940: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.UpdateExprs -//line mysql_sql.y:6682 - { - yyLOCAL = yyDollar[1].updateExprsUnion() - } - yyVAL.union = yyLOCAL - case 941: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.UpdateExprs -//line mysql_sql.y:6688 - { - yyLOCAL = yyDollar[5].updateExprsUnion() - } - yyVAL.union = yyLOCAL - case 942: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.UpdateExprs -//line mysql_sql.y:6692 - { - yyLOCAL = []*tree.UpdateExpr{nil} - } - yyVAL.union = yyLOCAL - case 943: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []*tree.Assignment -//line mysql_sql.y:6698 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 944: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.Assignment -//line mysql_sql.y:6702 - { - yyLOCAL = []*tree.Assignment{yyDollar[1].assignmentUnion()} - } - yyVAL.union = yyLOCAL - case 945: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.Assignment -//line mysql_sql.y:6706 - { - yyLOCAL = append(yyDollar[1].assignmentsUnion(), yyDollar[3].assignmentUnion()) - } - yyVAL.union = yyLOCAL - case 946: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.Assignment -//line mysql_sql.y:6712 - { - yyLOCAL = &tree.Assignment{ - Column: tree.Identifier(yyDollar[1].unresolvedNameUnion().ColName()), - ColumnName: yyDollar[1].unresolvedNameUnion(), - Expr: yyDollar[3].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 947: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.InsertColumns -//line mysql_sql.y:6722 - { - yyLOCAL = tree.InsertColumns{ - Identifiers: tree.IdentifierList{tree.Identifier(yyDollar[1].unresolvedNameUnion().ColName())}, - Names: []*tree.UnresolvedName{yyDollar[1].unresolvedNameUnion()}, - } - } - yyVAL.union = yyLOCAL - case 948: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.InsertColumns -//line mysql_sql.y:6729 - { - yyLOCAL = yyDollar[1].insertColumnsUnion() - yyLOCAL.Identifiers = append(yyDollar[1].insertColumnsUnion().Identifiers, tree.Identifier(yyDollar[3].unresolvedNameUnion().ColName())) - yyLOCAL.Names = append(yyDollar[1].insertColumnsUnion().Names, yyDollar[3].unresolvedNameUnion()) - } - yyVAL.union = yyLOCAL - case 949: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:6737 - { - yyLOCAL = tree.NewUnresolvedName(yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin())) - } - yyVAL.union = yyLOCAL - case 950: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:6741 - { - tblName := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedName(tblName, yyDollar[3].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 951: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:6746 - { - dbName := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) - tblName := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[3].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedName(dbName, tblName, yyDollar[5].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 952: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:6754 - { - yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 953: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:6758 - { - yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[3].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 954: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:6762 - { - yyLOCAL = append(yyDollar[1].identifierListUnion(), tree.Identifier(yyDollar[3].cstrUnion().Compare())) - } - yyVAL.union = yyLOCAL - case 955: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:6766 - { - yyLOCAL = append(yyDollar[1].identifierListUnion(), tree.Identifier(yyDollar[5].cstrUnion().Compare())) - } - yyVAL.union = yyLOCAL - case 956: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.Exprs -//line mysql_sql.y:6772 - { - yyLOCAL = []tree.Exprs{yyDollar[1].exprsUnion()} - } - yyVAL.union = yyLOCAL - case 957: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []tree.Exprs -//line mysql_sql.y:6776 - { - yyLOCAL = append(yyDollar[1].rowsExprsUnion(), yyDollar[3].exprsUnion()) - } - yyVAL.union = yyLOCAL - case 958: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:6782 - { - yyLOCAL = yyDollar[3].exprsUnion() - } - yyVAL.union = yyLOCAL - case 959: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:6787 - { - } - case 961: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:6791 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 963: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:6798 - { - yyLOCAL = tree.Exprs{yyDollar[1].exprUnion()} - } - yyVAL.union = yyLOCAL - case 964: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:6802 - { - yyLOCAL = append(yyDollar[1].exprsUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 966: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:6809 - { - yyLOCAL = &tree.DefaultVal{} - } - yyVAL.union = yyLOCAL - case 967: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:6814 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 968: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:6818 - { - yyLOCAL = yyDollar[3].identifierListUnion() - } - yyVAL.union = yyLOCAL - case 969: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.InsertPartitionClause -//line mysql_sql.y:6823 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 970: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.InsertPartitionClause -//line mysql_sql.y:6827 - { - yyLOCAL = &tree.InsertPartitionClause{Names: yyDollar[3].identifierListUnion()} - } - yyVAL.union = yyLOCAL - case 971: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.InsertPartitionClause -//line mysql_sql.y:6831 - { - yyLOCAL = &tree.InsertPartitionClause{Values: yyDollar[3].partitionValuesUnion()} - } - yyVAL.union = yyLOCAL - case 972: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.PartitionValues -//line mysql_sql.y:6837 - { - yyLOCAL = tree.PartitionValues{{Name: tree.Identifier(yyDollar[1].cstrUnion().Compare()), Expr: yyDollar[3].exprUnion()}} - } - yyVAL.union = yyLOCAL - case 973: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.PartitionValues -//line mysql_sql.y:6841 - { - yyLOCAL = append(yyDollar[1].partitionValuesUnion(), tree.PartitionValue{Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), Expr: yyDollar[5].exprUnion()}) - } - yyVAL.union = yyLOCAL - case 974: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:6847 - { - yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 975: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:6851 - { - yyLOCAL = append(yyDollar[1].identifierListUnion(), tree.Identifier(yyDollar[3].cstrUnion().Compare())) - } - yyVAL.union = yyLOCAL - case 976: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:6857 - { - yyLOCAL = yyDollar[2].tableNameUnion() - } - yyVAL.union = yyLOCAL - case 977: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:6861 - { - yyLOCAL = yyDollar[1].tableNameUnion() - } - yyVAL.union = yyLOCAL - case 978: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.SelectInto -//line mysql_sql.y:6867 - { - yyLOCAL = &tree.SelectInto{} - } - yyVAL.union = yyLOCAL - case 979: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL *tree.SelectInto -//line mysql_sql.y:6871 - { - yyLOCAL = &tree.SelectInto{Export: &tree.ExportParam{ - Outfile: true, - FilePath: yyDollar[3].str, - ExportFormat: yyDollar[4].str, - SplitSize: yyDollar[5].uint64ValUnion(), - Fields: yyDollar[6].fieldsUnion(), - Lines: yyDollar[7].linesUnion(), - Header: yyDollar[8].unsignedOptUnion(), - MaxFileSize: uint64(yyDollar[9].int64ValUnion()) * 1024, - ForceQuote: yyDollar[10].strsUnion(), - }} - } - yyVAL.union = yyLOCAL - case 980: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.SelectInto -//line mysql_sql.y:6885 - { - yyLOCAL = &tree.SelectInto{UserVars: yyDollar[2].varExprsUnion()} - } - yyVAL.union = yyLOCAL - case 981: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:6890 - { - yyVAL.str = "" - } - case 982: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:6894 - { - str := strings.ToLower(yyDollar[2].str) - if str != "csv" && str != "jsonline" && str != "parquet" { - yylex.Error("invalid format, must be csv, jsonline or parquet") - goto ret1 - } - yyVAL.str = str - } - case 983: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:6904 - { - yyLOCAL = uint64(0) - } - yyVAL.union = yyLOCAL - case 984: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:6908 - { - size, err := util.ParseDataSize(yyDollar[2].str) - if err != nil { - yylex.Error("invalid splitsize format: " + err.Error()) - goto ret1 - } - yyLOCAL = size - } - yyVAL.union = yyLOCAL - case 985: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.Fields -//line mysql_sql.y:6918 - { - yyLOCAL = &tree.Fields{ - Terminated: &tree.Terminated{ - Value: ",", - }, - EnclosedBy: &tree.EnclosedBy{ - Value: '"', - }, - } - } - yyVAL.union = yyLOCAL - case 986: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Fields -//line mysql_sql.y:6929 - { - yyLOCAL = &tree.Fields{ - Terminated: &tree.Terminated{ - Value: yyDollar[4].str, - }, - EnclosedBy: &tree.EnclosedBy{ - Value: '"', - }, - } - } - yyVAL.union = yyLOCAL - case 987: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL *tree.Fields -//line mysql_sql.y:6940 - { - str := yyDollar[7].str - if str != "\\" && len(str) > 1 { - yylex.Error("export1 error field terminator") - goto ret1 - } - var b byte - if len(str) != 0 { - b = byte(str[0]) - } else { - b = 0 - } - yyLOCAL = &tree.Fields{ - Terminated: &tree.Terminated{ - Value: yyDollar[4].str, - }, - EnclosedBy: &tree.EnclosedBy{ - Value: b, - }, - } - } - yyVAL.union = yyLOCAL - case 988: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Fields -//line mysql_sql.y:6962 - { - str := yyDollar[4].str - if str != "\\" && len(str) > 1 { - yylex.Error("export2 error field terminator") - goto ret1 - } - var b byte - if len(str) != 0 { - b = byte(str[0]) - } else { - b = 0 - } - yyLOCAL = &tree.Fields{ - Terminated: &tree.Terminated{ - Value: ",", - }, - EnclosedBy: &tree.EnclosedBy{ - Value: b, - }, - } - } - yyVAL.union = yyLOCAL - case 989: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.Lines -//line mysql_sql.y:6985 - { - yyLOCAL = &tree.Lines{ - TerminatedBy: &tree.Terminated{ - Value: "\n", - }, - } - } - yyVAL.union = yyLOCAL - case 990: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.Lines -//line mysql_sql.y:6993 - { - yyLOCAL = &tree.Lines{ - TerminatedBy: &tree.Terminated{ - Value: yyDollar[2].str, - }, - } - } - yyVAL.union = yyLOCAL - case 991: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:7002 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 992: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:7006 - { - str := strings.ToLower(yyDollar[2].str) - if str == "true" { - yyLOCAL = true - } else if str == "false" { - yyLOCAL = false - } else { - yylex.Error("error header flag") - goto ret1 - } - } - yyVAL.union = yyLOCAL - case 993: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:7019 - { - yyLOCAL = 0 - } - yyVAL.union = yyLOCAL - case 994: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:7023 - { - value, ok := signedIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - yyLOCAL = value - } - yyVAL.union = yyLOCAL - case 995: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:7030 - { - yyLOCAL = []string{} - } - yyVAL.union = yyLOCAL - case 996: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:7034 - { - yyLOCAL = yyDollar[3].strsUnion() - } - yyVAL.union = yyLOCAL - case 997: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:7040 - { - yyLOCAL = make([]string, 0, 4) - yyLOCAL = append(yyLOCAL, yyDollar[1].cstrUnion().Compare()) - } - yyVAL.union = yyLOCAL - case 998: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:7045 - { - yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].cstrUnion().Compare()) - } - yyVAL.union = yyLOCAL - case 999: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7054 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), OrderBy: yyDollar[2].orderByUnion(), Limit: yyDollar[3].limitUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), nil), IntoVars: intoVars, DeprecatedInto: deprecatedInto} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1001: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7070 - { - yyLOCAL = yyDollar[1].selectUnion() - } - yyVAL.union = yyLOCAL - case 1002: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7074 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), IntoVars: intoVars, DeprecatedInto: deprecatedInto} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1003: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7094 - { - yyLOCAL = yyDollar[1].selectUnion() - } - yyVAL.union = yyLOCAL - case 1004: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7098 - { - yyLOCAL = tree.NewSelect(&tree.ValuesClause{Rows: yyDollar[2].rowsExprsUnion(), RowWord: true}, yyDollar[3].orderByUnion(), yyDollar[4].limitUnion()) - } - yyVAL.union = yyLOCAL - case 1005: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7104 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion()) { - yylex.Error(tree.MisplacedIntoClauseMessage) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[6].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, SelectLockInfo: yyDollar[7].selectLockInfoUnion()} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1006: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7121 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[4].selectIntoUnion()) { - yylex.Error(tree.MisplacedIntoClauseMessage) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), OrderBy: yyDollar[3].orderByUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[4].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[4].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1007: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7138 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion()) { - yylex.Error(tree.MisplacedIntoClauseMessage) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[6].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1008: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7155 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[4].selectIntoUnion()) { - yylex.Error(tree.MisplacedIntoClauseMessage) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), Limit: yyDollar[2].limitUnion(), RankOption: yyDollar[3].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[4].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[4].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1009: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7172 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[5].selectIntoUnion()) { - yylex.Error(tree.MisplacedIntoClauseMessage) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), Limit: yyDollar[3].limitUnion(), RankOption: yyDollar[4].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[5].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[5].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1010: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7189 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion()) { - yylex.Error(tree.MisplacedIntoClauseMessage) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[6].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1011: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7206 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[2].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - if tree.SelectIntoActionConflict(yyDollar[2].selectStatementUnion(), yyDollar[7].selectIntoUnion()) { - yylex.Error(tree.MisplacedIntoClauseMessage) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), TimeWindow: yyDollar[3].timeWindowUnion(), OrderBy: yyDollar[4].orderByUnion(), Limit: yyDollar[5].limitUnion(), RankOption: yyDollar[6].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[7].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[7].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, SelectLockInfo: yyDollar[8].selectLockInfoUnion(), With: yyDollar[1].withClauseUnion()} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1012: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7223 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[2].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - if tree.SelectIntoActionConflict(yyDollar[2].selectStatementUnion(), yyDollar[4].selectIntoUnion()) { - yylex.Error(tree.MisplacedIntoClauseMessage) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), OrderBy: yyDollar[3].orderByUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[4].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[4].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, With: yyDollar[1].withClauseUnion()} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1013: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7240 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[2].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - if tree.SelectIntoActionConflict(yyDollar[2].selectStatementUnion(), yyDollar[6].selectIntoUnion()) { - yylex.Error(tree.MisplacedIntoClauseMessage) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[6].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, With: yyDollar[1].withClauseUnion()} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1014: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7257 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[2].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - if tree.SelectIntoActionConflict(yyDollar[2].selectStatementUnion(), yyDollar[5].selectIntoUnion()) { - yylex.Error(tree.MisplacedIntoClauseMessage) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), Limit: yyDollar[3].limitUnion(), RankOption: yyDollar[4].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[5].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[5].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, With: yyDollar[1].withClauseUnion()} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1015: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:7274 - { - intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[2].selectStatementUnion()) - if intoErr != "" { - yylex.Error(intoErr) - return 1 - } - if tree.SelectIntoActionConflict(yyDollar[2].selectStatementUnion(), yyDollar[6].selectIntoUnion()) { - yylex.Error(tree.MisplacedIntoClauseMessage) - return 1 - } - yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[6].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, With: yyDollar[1].withClauseUnion()} - if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 1016: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.TimeWindow -//line mysql_sql.y:7292 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1017: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.TimeWindow -//line mysql_sql.y:7296 - { - yyLOCAL = yyDollar[1].timeWindowUnion() - } - yyVAL.union = yyLOCAL - case 1018: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.TimeWindow -//line mysql_sql.y:7302 - { - yyLOCAL = &tree.TimeWindow{ - Interval: yyDollar[1].timeIntervalUnion(), - Sliding: yyDollar[2].timeSlidingUnion(), - GapFill: yyDollar[3].boolValUnion(), - Fill: yyDollar[4].timeFillUnion(), - } - } - yyVAL.union = yyLOCAL - case 1019: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL *tree.Interval -//line mysql_sql.y:7313 - { - str := fmt.Sprintf("%v", yyDollar[5].item) - v, errStr := util.GetInt64(yyDollar[5].item) - if errStr != "" { - yylex.Error(errStr) - goto ret1 - } - yyLOCAL = &tree.Interval{ - Col: yyDollar[3].unresolvedNameUnion(), - Val: tree.NewNumVal(v, str, false, tree.P_int64), - Unit: yyDollar[7].str, - } - } - yyVAL.union = yyLOCAL - case 1020: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.Sliding -//line mysql_sql.y:7328 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1021: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.Sliding -//line mysql_sql.y:7332 - { - str := fmt.Sprintf("%v", yyDollar[3].item) - v, errStr := util.GetInt64(yyDollar[3].item) - if errStr != "" { - yylex.Error(errStr) - goto ret1 - } - yyLOCAL = &tree.Sliding{ - Val: tree.NewNumVal(v, str, false, tree.P_int64), - Unit: yyDollar[5].str, - } - } - yyVAL.union = yyLOCAL - case 1022: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:7346 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1023: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:7350 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1024: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.Fill -//line mysql_sql.y:7355 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1025: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Fill -//line mysql_sql.y:7359 - { - yyLOCAL = &tree.Fill{ - Mode: yyDollar[3].fillModeUnion(), - } - } - yyVAL.union = yyLOCAL - case 1026: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.Fill -//line mysql_sql.y:7365 - { - yyLOCAL = &tree.Fill{ - Mode: tree.FillValue, - Val: yyDollar[5].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 1027: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FillMode -//line mysql_sql.y:7374 - { - yyLOCAL = tree.FillPrev - } - yyVAL.union = yyLOCAL - case 1028: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FillMode -//line mysql_sql.y:7378 - { - yyLOCAL = tree.FillNext - } - yyVAL.union = yyLOCAL - case 1029: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FillMode -//line mysql_sql.y:7382 - { - yyLOCAL = tree.FillNone - } - yyVAL.union = yyLOCAL - case 1030: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FillMode -//line mysql_sql.y:7386 - { - yyLOCAL = tree.FillNull - } - yyVAL.union = yyLOCAL - case 1031: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FillMode -//line mysql_sql.y:7390 - { - yyLOCAL = tree.FillLinear - } - yyVAL.union = yyLOCAL - case 1032: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.With -//line mysql_sql.y:7396 - { - yyLOCAL = &tree.With{ - IsRecursive: false, - CTEs: yyDollar[2].cteListUnion(), - } - } - yyVAL.union = yyLOCAL - case 1033: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.With -//line mysql_sql.y:7403 - { - yyLOCAL = &tree.With{ - IsRecursive: true, - CTEs: yyDollar[3].cteListUnion(), - } - } - yyVAL.union = yyLOCAL - case 1034: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.CTE -//line mysql_sql.y:7412 - { - yyLOCAL = []*tree.CTE{yyDollar[1].cteUnion()} - } - yyVAL.union = yyLOCAL - case 1035: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.CTE -//line mysql_sql.y:7416 - { - yyLOCAL = append(yyDollar[1].cteListUnion(), yyDollar[3].cteUnion()) - } - yyVAL.union = yyLOCAL - case 1036: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.CTE -//line mysql_sql.y:7422 - { - // stmt has an EMPTY alternative used for bare trailing semicolons. - // Inside a CTE body that produces a nil Stmt and panics in Format - // (CTAS / PREPARE). Reject like MySQL. See #30146. - if yyDollar[5].statementUnion() == nil { - yylex.Error("empty common table expression body") - goto ret1 - } - yyLOCAL = &tree.CTE{ - Name: &tree.AliasClause{Alias: tree.Identifier(yyDollar[1].cstrUnion().Compare()), Cols: yyDollar[2].identifierListUnion()}, - Stmt: yyDollar[5].statementUnion(), - } - } - yyVAL.union = yyLOCAL - case 1037: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:7437 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1038: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:7441 - { - yyLOCAL = yyDollar[2].identifierListUnion() - } - yyVAL.union = yyLOCAL - case 1039: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.Limit -//line mysql_sql.y:7446 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1040: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Limit -//line mysql_sql.y:7450 - { - yyLOCAL = yyDollar[1].limitUnion() - } - yyVAL.union = yyLOCAL - case 1041: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.Limit -//line mysql_sql.y:7455 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1042: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Limit -//line mysql_sql.y:7459 - { - yyLOCAL = yyDollar[1].limitUnion() - } - yyVAL.union = yyLOCAL - case 1043: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Limit -//line mysql_sql.y:7463 - { - yyLOCAL = yyDollar[1].limitUnion() - } - yyVAL.union = yyLOCAL - case 1044: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.Limit -//line mysql_sql.y:7469 - { - yyLOCAL = &tree.Limit{Count: yyDollar[2].exprUnion()} - } - yyVAL.union = yyLOCAL - case 1045: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Limit -//line mysql_sql.y:7473 - { - yyLOCAL = &tree.Limit{Offset: yyDollar[2].exprUnion(), Count: yyDollar[4].exprUnion()} - } - yyVAL.union = yyLOCAL - case 1046: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Limit -//line mysql_sql.y:7477 - { - yyLOCAL = &tree.Limit{Offset: yyDollar[4].exprUnion(), Count: yyDollar[2].exprUnion()} - } - yyVAL.union = yyLOCAL - case 1047: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.Limit -//line mysql_sql.y:7483 - { - yyLOCAL = &tree.Limit{Offset: yyDollar[2].exprUnion()} - } - yyVAL.union = yyLOCAL - case 1048: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.RankOption -//line mysql_sql.y:7488 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1049: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.RankOption -//line mysql_sql.y:7492 - { - // Parse option strings to extract key=value pairs into a map - optionMap := make(map[string]string) - - for _, expr := range yyDollar[5].exprsUnion() { - var str string - // Handle both NumVal (P_char) and StrVal - if numVal, ok := expr.(*tree.NumVal); ok && numVal.ValType == tree.P_char { - str = numVal.String() - } else if strVal, ok := expr.(*tree.StrVal); ok { - str = strVal.String() - } else { - yylex.Error("rank options must be string literals containing key=value") - return 1 - } - - // Remove quotes if present - if len(str) >= 2 && ((str[0] == '\'' && str[len(str)-1] == '\'') || (str[0] == '"' && str[len(str)-1] == '"')) { - str = str[1 : len(str)-1] - } - - // Parse key=value pairs - parts := strings.Split(str, "=") - if len(parts) != 2 || strings.TrimSpace(parts[0]) == "" || strings.TrimSpace(parts[1]) == "" { - yylex.Error("rank options must contain a nonempty key=value pair") - return 1 - } - key := strings.TrimSpace(strings.ToLower(parts[0])) - value := strings.TrimSpace(parts[1]) - optionMap[key] = value - } - - yyLOCAL = &tree.RankOption{ - Option: optionMap, - } - } - yyVAL.union = yyLOCAL - case 1050: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.OrderBy -//line mysql_sql.y:7530 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1051: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.OrderBy -//line mysql_sql.y:7534 - { - yyLOCAL = yyDollar[1].orderByUnion() - } - yyVAL.union = yyLOCAL - case 1052: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.OrderBy -//line mysql_sql.y:7539 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1053: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.OrderBy -//line mysql_sql.y:7543 - { - yyLOCAL = yyDollar[4].orderByUnion() - } - yyVAL.union = yyLOCAL - case 1054: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.OrderBy -//line mysql_sql.y:7549 - { - yyLOCAL = yyDollar[3].orderByUnion() - } - yyVAL.union = yyLOCAL - case 1055: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.OrderBy -//line mysql_sql.y:7555 - { - yyLOCAL = tree.OrderBy{yyDollar[1].orderUnion()} - } - yyVAL.union = yyLOCAL - case 1056: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.OrderBy -//line mysql_sql.y:7559 - { - yyLOCAL = append(yyDollar[1].orderByUnion(), yyDollar[3].orderUnion()) - } - yyVAL.union = yyLOCAL - case 1057: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.Order -//line mysql_sql.y:7565 - { - yyLOCAL = &tree.Order{Expr: yyDollar[1].exprUnion(), Direction: yyDollar[2].directionUnion(), NullsPosition: yyDollar[3].nullsPositionUnion()} - } - yyVAL.union = yyLOCAL - case 1058: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Direction -//line mysql_sql.y:7570 - { - yyLOCAL = tree.DefaultDirection - } - yyVAL.union = yyLOCAL - case 1059: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Direction -//line mysql_sql.y:7574 - { - yyLOCAL = tree.Ascending - } - yyVAL.union = yyLOCAL - case 1060: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Direction -//line mysql_sql.y:7578 - { - yyLOCAL = tree.Descending - } - yyVAL.union = yyLOCAL - case 1061: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.NullsPosition -//line mysql_sql.y:7583 - { - yyLOCAL = tree.DefaultNullsPosition - } - yyVAL.union = yyLOCAL - case 1062: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:7587 - { - yylex.Error("NULLS FIRST is not supported in MySQL syntax") - return 1 - } - case 1063: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:7591 - { - yylex.Error("NULLS LAST is not supported in MySQL syntax") - return 1 - } - case 1064: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.SelectLockInfo -//line mysql_sql.y:7596 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1065: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.SelectLockInfo -//line mysql_sql.y:7600 - { - yyLOCAL = &tree.SelectLockInfo{ - LockType: tree.SelectLockForUpdate, - } - if strings.EqualFold(yyDollar[2].str, "update nowait") { - yyLOCAL.LockType = tree.SelectLockForUpdateNoWait - } - } - yyVAL.union = yyLOCAL - case 1066: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.SelectLockInfo -//line mysql_sql.y:7609 - { - yyLOCAL = &tree.SelectLockInfo{ - LockType: tree.SelectLockForShare, - } - if strings.EqualFold(yyDollar[2].str, "share nowait") { - yyLOCAL.LockType = tree.SelectLockForShareNoWait - } else if strings.EqualFold(yyDollar[2].str, "share skip locked") { - yyLOCAL.LockType = tree.SelectLockForShareSkipLocked - } - } - yyVAL.union = yyLOCAL - case 1067: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.SelectLockInfo -//line mysql_sql.y:7620 - { - yyLOCAL = &tree.SelectLockInfo{ - LockType: tree.SelectLockForShare, - } - } - yyVAL.union = yyLOCAL - case 1068: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7628 - { - yyLOCAL = &tree.ParenSelect{Select: yyDollar[2].selectUnion()} - } - yyVAL.union = yyLOCAL - case 1069: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7632 - { - yyLOCAL = &tree.ParenSelect{Select: &tree.Select{Select: yyDollar[2].selectStatementUnion()}} - } - yyVAL.union = yyLOCAL - case 1070: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7636 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1071: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7640 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1072: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7645 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1073: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7649 - { - yyLOCAL = &tree.UnionClause{ - Type: yyDollar[2].unionTypeRecordUnion().Type, - Left: yyDollar[1].selectStatementUnion(), - Right: yyDollar[3].selectStatementUnion(), - All: yyDollar[2].unionTypeRecordUnion().All, - Distinct: yyDollar[2].unionTypeRecordUnion().Distinct, - } - } - yyVAL.union = yyLOCAL - case 1074: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7659 - { - yyLOCAL = &tree.UnionClause{ - Type: yyDollar[2].unionTypeRecordUnion().Type, - Left: yyDollar[1].selectStatementUnion(), - Right: yyDollar[3].selectStatementUnion(), - All: yyDollar[2].unionTypeRecordUnion().All, - Distinct: yyDollar[2].unionTypeRecordUnion().Distinct, - } - } - yyVAL.union = yyLOCAL - case 1075: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7669 - { - yyLOCAL = &tree.UnionClause{ - Type: yyDollar[2].unionTypeRecordUnion().Type, - Left: yyDollar[1].selectStatementUnion(), - Right: yyDollar[3].selectStatementUnion(), - All: yyDollar[2].unionTypeRecordUnion().All, - Distinct: yyDollar[2].unionTypeRecordUnion().Distinct, - } - } - yyVAL.union = yyLOCAL - case 1076: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7679 - { - yyLOCAL = &tree.UnionClause{ - Type: yyDollar[2].unionTypeRecordUnion().Type, - Left: yyDollar[1].selectStatementUnion(), - Right: yyDollar[3].selectStatementUnion(), - All: yyDollar[2].unionTypeRecordUnion().All, - Distinct: yyDollar[2].unionTypeRecordUnion().Distinct, - } - } - yyVAL.union = yyLOCAL - case 1077: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7689 - { - yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} - } - yyVAL.union = yyLOCAL - case 1078: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7693 - { - yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} - } - yyVAL.union = yyLOCAL - case 1079: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7697 - { - yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} - } - yyVAL.union = yyLOCAL - case 1080: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7701 - { - yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} - } - yyVAL.union = yyLOCAL - case 1081: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7709 - { - yyLOCAL = &tree.ParenSelect{Select: tree.NewSelect(yyDollar[2].selectStatementUnion(), yyDollar[3].orderByUnion(), yyDollar[4].limitUnion())} - } - yyVAL.union = yyLOCAL - case 1082: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7715 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1083: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7719 - { - yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} - } - yyVAL.union = yyLOCAL - case 1084: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7725 - { - yyLOCAL = makeSelectStarFromTable(yyDollar[2].tableNameUnion()) - } - yyVAL.union = yyLOCAL - case 1085: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7730 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1086: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7734 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1087: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7738 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1088: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7742 - { - yyLOCAL = &tree.ValuesClause{Rows: yyDollar[2].rowsExprsUnion(), RowWord: true} - } - yyVAL.union = yyLOCAL - case 1089: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7748 - { - yyLOCAL = &tree.ParenSelect{Select: tree.NewSelect(yyDollar[2].selectStatementUnion(), yyDollar[3].orderByUnion(), yyDollar[4].limitUnion())} - } - yyVAL.union = yyLOCAL - case 1090: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7754 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1091: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7758 - { - yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} - } - yyVAL.union = yyLOCAL - case 1092: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7764 - { - yyLOCAL = &tree.ValuesClause{Rows: yyDollar[2].rowsExprsUnion(), RowWord: true} - } - yyVAL.union = yyLOCAL - case 1093: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7770 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1094: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7774 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1095: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7778 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1096: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7782 - { - yyLOCAL = yyDollar[1].selectStatementUnion() - } - yyVAL.union = yyLOCAL - case 1097: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7788 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.UNION, - All: false, - Distinct: false, - } - } - yyVAL.union = yyLOCAL - case 1098: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7796 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.UNION, - All: true, - Distinct: false, - } - } - yyVAL.union = yyLOCAL - case 1099: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7804 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.UNION, - All: false, - Distinct: true, - } - } - yyVAL.union = yyLOCAL - case 1100: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7813 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.EXCEPT, - All: false, - Distinct: false, - } - } - yyVAL.union = yyLOCAL - case 1101: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7821 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.EXCEPT, - All: true, - Distinct: false, - } - } - yyVAL.union = yyLOCAL - case 1102: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7829 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.EXCEPT, - All: false, - Distinct: true, - } - } - yyVAL.union = yyLOCAL - case 1103: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7837 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.INTERSECT, - All: false, - Distinct: false, - } - } - yyVAL.union = yyLOCAL - case 1104: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7845 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.INTERSECT, - All: true, - Distinct: false, - } - } - yyVAL.union = yyLOCAL - case 1105: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7853 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.INTERSECT, - All: false, - Distinct: true, - } - } - yyVAL.union = yyLOCAL - case 1106: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7861 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.UT_MINUS, - All: false, - Distinct: false, - } - } - yyVAL.union = yyLOCAL - case 1107: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7869 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.UT_MINUS, - All: true, - Distinct: false, - } - } - yyVAL.union = yyLOCAL - case 1108: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.UnionTypeRecord -//line mysql_sql.y:7877 - { - yyLOCAL = &tree.UnionTypeRecord{ - Type: tree.UT_MINUS, - All: false, - Distinct: true, - } - } - yyVAL.union = yyLOCAL - case 1109: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.SelectStatement -//line mysql_sql.y:7887 - { - yyLOCAL = &tree.SelectClause{ - Distinct: tree.QuerySpecOptionDistinct&yyDollar[2].selectOptionsUnion() != 0, - Exprs: yyDollar[3].selectExprsUnion(), - IntoVars: yyDollar[4].selectIntoUnion().UserVars, - IntoExport: yyDollar[4].selectIntoUnion().Export, - From: yyDollar[5].fromUnion(), - Where: yyDollar[6].whereUnion(), - GroupBy: yyDollar[7].groupByUnion(), - Having: yyDollar[8].whereUnion(), - Windows: yyDollar[9].windowDefinitionsUnion(), - Option: yyDollar[2].selectOptionsUnion(), - } - } - yyVAL.union = yyLOCAL - case 1110: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7904 - { - yyLOCAL = tree.QuerySpecOptionNone - } - yyVAL.union = yyLOCAL - case 1111: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7908 - { - yyLOCAL = yyDollar[1].selectOptionsUnion() - } - yyVAL.union = yyLOCAL - case 1112: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7914 - { - yyLOCAL = yyDollar[1].selectOptionUnion() - } - yyVAL.union = yyLOCAL - case 1113: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7918 - { - yyLOCAL = yyDollar[1].selectOptionsUnion() | yyDollar[2].selectOptionUnion() - } - yyVAL.union = yyLOCAL - case 1114: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7924 - { - yyLOCAL = tree.QuerySpecOptionSqlSmallResult - } - yyVAL.union = yyLOCAL - case 1115: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7928 - { - yyLOCAL = tree.QuerySpecOptionSqlBigResult - } - yyVAL.union = yyLOCAL - case 1116: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7932 - { - yyLOCAL = tree.QuerySpecOptionSqlBufferResult - } - yyVAL.union = yyLOCAL - case 1117: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7936 - { - yyLOCAL = tree.QuerySpecOptionStraightJoin - } - yyVAL.union = yyLOCAL - case 1118: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7940 - { - yyLOCAL = tree.QuerySpecOptionHighPriority - } - yyVAL.union = yyLOCAL - case 1119: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7944 - { - yyLOCAL = tree.QuerySpecOptionSqlCalcFoundRows - } - yyVAL.union = yyLOCAL - case 1120: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7948 - { - yyLOCAL = tree.QuerySpecOptionSqlNoCache - } - yyVAL.union = yyLOCAL - case 1121: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7952 - { - yyLOCAL = tree.QuerySpecOptionAll - } - yyVAL.union = yyLOCAL - case 1122: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7956 - { - yyLOCAL = tree.QuerySpecOptionDistinct - } - yyVAL.union = yyLOCAL - case 1123: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL uint64 -//line mysql_sql.y:7960 - { - yyLOCAL = tree.QuerySpecOptionDistinctRow - } - yyVAL.union = yyLOCAL - case 1124: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.Where -//line mysql_sql.y:7982 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1125: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.Where -//line mysql_sql.y:7986 - { - yyLOCAL = &tree.Where{Type: tree.AstHaving, Expr: yyDollar[2].exprUnion()} - } - yyVAL.union = yyLOCAL - case 1126: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.GroupByClause -//line mysql_sql.y:7991 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1127: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.GroupByClause -//line mysql_sql.y:7995 - { - exprsList := []tree.Exprs{yyDollar[3].exprsUnion()} - yyLOCAL = &tree.GroupByClause{ - GroupByExprsList: exprsList, - Apart: false, - Cube: false, - Rollup: yyDollar[4].boolValUnion(), - } - } - yyVAL.union = yyLOCAL - case 1128: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL *tree.GroupByClause -//line mysql_sql.y:8005 - { - yyLOCAL = &tree.GroupByClause{ - GroupByExprsList: yyDollar[6].rowsExprsUnion(), - Apart: false, - Cube: false, - GroupingSets: true, - Rollup: false, - } - } - yyVAL.union = yyLOCAL - case 1129: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.GroupByClause -//line mysql_sql.y:8015 - { - yyLOCAL = &tree.GroupByClause{ - GroupByExprsList: []tree.Exprs{yyDollar[5].exprsUnion()}, - Apart: false, - Cube: true, - Rollup: false, - } - } - yyVAL.union = yyLOCAL - case 1130: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.GroupByClause -//line mysql_sql.y:8024 - { - yyLOCAL = &tree.GroupByClause{ - GroupByExprsList: []tree.Exprs{yyDollar[5].exprsUnion()}, - Apart: false, - Cube: false, - Rollup: true, - } - } - yyVAL.union = yyLOCAL - case 1131: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []tree.Exprs -//line mysql_sql.y:8035 - { - yyLOCAL = []tree.Exprs{yyDollar[2].exprsUnion()} - } - yyVAL.union = yyLOCAL - case 1132: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL []tree.Exprs -//line mysql_sql.y:8039 - { - yyLOCAL = append(yyDollar[1].rowsExprsUnion(), yyDollar[4].exprsUnion()) - } - yyVAL.union = yyLOCAL - case 1133: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:8045 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1134: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:8049 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1135: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.Where -//line mysql_sql.y:8054 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1136: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.Where -//line mysql_sql.y:8058 - { - yyLOCAL = &tree.Where{Type: tree.AstWhere, Expr: yyDollar[2].exprUnion()} - } - yyVAL.union = yyLOCAL - case 1137: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectExprs -//line mysql_sql.y:8064 - { - yyLOCAL = tree.SelectExprs{yyDollar[1].selectExprUnion()} - } - yyVAL.union = yyLOCAL - case 1138: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectExprs -//line mysql_sql.y:8068 - { - yyLOCAL = append(yyDollar[1].selectExprsUnion(), yyDollar[3].selectExprUnion()) - } - yyVAL.union = yyLOCAL - case 1139: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.SelectExpr -//line mysql_sql.y:8074 - { - yyLOCAL = tree.SelectExpr{Expr: tree.StarExpr()} - } - yyVAL.union = yyLOCAL - case 1140: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.SelectExpr -//line mysql_sql.y:8078 - { - yyLOCAL = tree.SelectExpr{Expr: yyDollar[1].exprUnion(), As: yyDollar[2].cstrUnion()} - } - yyVAL.union = yyLOCAL - case 1141: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.SelectExpr -//line mysql_sql.y:8082 - { - yyLOCAL = tree.SelectExpr{Expr: tree.NewUnresolvedNameWithStar(yyDollar[1].cstrUnion())} - } - yyVAL.union = yyLOCAL - case 1142: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.SelectExpr -//line mysql_sql.y:8086 - { - yyLOCAL = tree.SelectExpr{Expr: tree.NewUnresolvedNameWithStar(yyDollar[1].cstrUnion(), yyDollar[3].cstrUnion())} - } - yyVAL.union = yyLOCAL - case 1143: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.From -//line mysql_sql.y:8091 - { - prefix := tree.ObjectNamePrefix{ExplicitSchema: false} - tn := tree.NewTableName(tree.Identifier(""), prefix, nil) - yyLOCAL = &tree.From{ - Tables: tree.TableExprs{&tree.AliasedTableExpr{Expr: tn}}, - } - } - yyVAL.union = yyLOCAL - case 1144: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.From -//line mysql_sql.y:8099 - { - yyLOCAL = yyDollar[1].fromUnion() - } - yyVAL.union = yyLOCAL - case 1145: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.From -//line mysql_sql.y:8105 - { - yyLOCAL = &tree.From{ - Tables: tree.TableExprs{yyDollar[2].tableExprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 1146: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:8113 - { - if t, ok := yyDollar[1].tableExprUnion().(*tree.JoinTableExpr); ok { - yyLOCAL = t - } else if t, ok := yyDollar[1].tableExprUnion().(*tree.ApplyTableExpr); ok { - yyLOCAL = t - } else { - yyLOCAL = &tree.JoinTableExpr{Left: yyDollar[1].tableExprUnion(), Right: nil, JoinType: tree.JOIN_TYPE_CROSS} - } - } - yyVAL.union = yyLOCAL - case 1147: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:8123 - { - yyLOCAL = &tree.JoinTableExpr{Left: yyDollar[1].tableExprUnion(), Right: yyDollar[3].tableExprUnion(), JoinType: tree.JOIN_TYPE_CROSS} - } - yyVAL.union = yyLOCAL - case 1149: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:8130 - { - if !strings.EqualFold(yyDollar[2].str, "OJ") { - yylex.Error("expected OJ in table reference escape") - goto ret1 - } - yyLOCAL = yyDollar[3].tableExprUnion() - } - yyVAL.union = yyLOCAL - case 1151: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:8141 - { - yyLOCAL = yyDollar[1].joinTableExprUnion() - } - yyVAL.union = yyLOCAL - case 1152: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:8145 - { - yyLOCAL = yyDollar[1].applyTableExprUnion() - } - yyVAL.union = yyLOCAL - case 1153: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.JoinTableExpr -//line mysql_sql.y:8151 - { - if strings.Contains(yyDollar[2].str, ":") { - ss := strings.SplitN(yyDollar[2].str, ":", 2) - yyLOCAL = &tree.JoinTableExpr{ - Left: yyDollar[1].tableExprUnion(), - JoinType: ss[0], - Right: yyDollar[3].tableExprUnion(), - Cond: yyDollar[4].joinCondUnion(), - Option: ss[1], - } - } else { - yyLOCAL = &tree.JoinTableExpr{ - Left: yyDollar[1].tableExprUnion(), - JoinType: yyDollar[2].str, - Right: yyDollar[3].tableExprUnion(), - Cond: yyDollar[4].joinCondUnion(), - } - } - } - yyVAL.union = yyLOCAL - case 1154: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.JoinTableExpr -//line mysql_sql.y:8171 - { - yyLOCAL = &tree.JoinTableExpr{ - Left: yyDollar[1].tableExprUnion(), - JoinType: yyDollar[2].str, - Right: yyDollar[3].tableExprUnion(), - Cond: yyDollar[4].joinCondUnion(), - } - } - yyVAL.union = yyLOCAL - case 1155: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.JoinTableExpr -//line mysql_sql.y:8180 - { - if yyDollar[4].joinCondUnion() == nil { - yylex.Error("outer join requires ON/USING clause") - goto ret1 - } - yyLOCAL = &tree.JoinTableExpr{ - Left: yyDollar[1].tableExprUnion(), - JoinType: yyDollar[2].str, - Right: yyDollar[3].tableExprUnion(), - Cond: yyDollar[4].joinCondUnion(), - } - } - yyVAL.union = yyLOCAL - case 1156: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.JoinTableExpr -//line mysql_sql.y:8193 - { - yyLOCAL = &tree.JoinTableExpr{ - Left: yyDollar[1].tableExprUnion(), - JoinType: yyDollar[2].str, - Right: yyDollar[3].tableExprUnion(), - } - } - yyVAL.union = yyLOCAL - case 1157: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.JoinTableExpr -//line mysql_sql.y:8201 - { - yyLOCAL = &tree.JoinTableExpr{ - Left: yyDollar[1].tableExprUnion(), - JoinType: yyDollar[2].str, - Right: yyDollar[3].tableExprUnion(), - Cond: yyDollar[4].joinCondUnion(), - } - } - yyVAL.union = yyLOCAL - case 1158: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.JoinTableExpr -//line mysql_sql.y:8210 - { - if !hasAsofLeftFactorAlias(yyDollar[1].tableExprUnion()) { - yylex.Error("native ASOF JOIN requires an aliased left table factor") - goto ret1 - } - yyLOCAL = &tree.JoinTableExpr{ - Left: yyDollar[1].tableExprUnion(), - JoinType: yyDollar[2].str, - Right: yyDollar[3].tableExprUnion(), - Cond: yyDollar[4].joinCondUnion(), - Tolerance: yyDollar[5].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 1159: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.ApplyTableExpr -//line mysql_sql.y:8226 - { - yyLOCAL = &tree.ApplyTableExpr{ - Left: yyDollar[1].tableExprUnion(), - ApplyType: yyDollar[2].str, - Right: yyDollar[3].tableExprUnion(), - } - } - yyVAL.union = yyLOCAL - case 1160: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8236 - { - yyVAL.str = tree.APPLY_TYPE_CROSS - } - case 1161: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8240 - { - yyVAL.str = tree.APPLY_TYPE_OUTER - } - case 1162: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8246 - { - yyVAL.str = tree.JOIN_TYPE_NATURAL - } - case 1163: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8250 - { - switch yyDollar[2].str { - case tree.JOIN_TYPE_LEFT: - yyVAL.str = tree.JOIN_TYPE_NATURAL_LEFT - case tree.JOIN_TYPE_RIGHT: - yyVAL.str = tree.JOIN_TYPE_NATURAL_RIGHT - case tree.JOIN_TYPE_FULL: - yyVAL.str = tree.JOIN_TYPE_NATURAL_FULL - } - } - case 1164: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8263 - { - yyVAL.str = tree.JOIN_TYPE_LEFT - } - case 1165: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:8267 - { - yyVAL.str = tree.JOIN_TYPE_LEFT - } - case 1166: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8271 - { - yyVAL.str = tree.JOIN_TYPE_RIGHT - } - case 1167: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:8275 - { - yyVAL.str = tree.JOIN_TYPE_RIGHT - } - case 1168: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8279 - { - yyVAL.str = tree.JOIN_TYPE_FULL - } - case 1169: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:8283 - { - yyVAL.str = tree.JOIN_TYPE_FULL - } - case 1170: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8289 - { - yyVAL.str = tree.JOIN_TYPE_DEDUP - } - case 1171: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8295 - { - yyVAL.str = tree.JOIN_TYPE_ASOF - } - case 1172: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:8299 - { - yyVAL.str = tree.JOIN_TYPE_ASOF_LEFT - } - case 1173: - yyDollar = yyS[yypt-4 : yypt+1] -//line mysql_sql.y:8303 - { - yyVAL.str = tree.JOIN_TYPE_ASOF_LEFT - } - case 1174: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:8308 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1175: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:8312 - { - yyLOCAL = yyDollar[2].exprUnion() - } - yyVAL.union = yyLOCAL - case 1176: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:8318 - { - stmt := &tree.ValuesStatement{ - Rows: yyDollar[2].rowsExprsUnion(), - OrderBy: yyDollar[3].orderByUnion(), - Limit: yyDollar[4].limitUnion(), - } - if intoErr := tree.ValidateValuesIntoPlacement(stmt); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - yyLOCAL = stmt - } - yyVAL.union = yyLOCAL - case 1177: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.Exprs -//line mysql_sql.y:8333 - { - yyLOCAL = []tree.Exprs{yyDollar[1].exprsUnion()} - } - yyVAL.union = yyLOCAL - case 1178: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []tree.Exprs -//line mysql_sql.y:8337 - { - yyLOCAL = append(yyDollar[1].rowsExprsUnion(), yyDollar[3].exprsUnion()) - } - yyVAL.union = yyLOCAL - case 1179: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:8343 - { - yyLOCAL = yyDollar[3].exprsUnion() - } - yyVAL.union = yyLOCAL - case 1180: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:8349 - { - yyVAL.str = yyDollar[1].str - } - case 1181: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:8355 - { - yyVAL.str = yyDollar[2].str - } - case 1182: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:8361 - { - yyVAL.str = tree.JOIN_TYPE_STRAIGHT - } - case 1183: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:8367 - { - yyVAL.str = tree.JOIN_TYPE_INNER - } - case 1184: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8371 - { - yyVAL.str = tree.JOIN_TYPE_INNER - } - case 1185: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8375 - { - yyVAL.str = tree.JOIN_TYPE_CROSS - } - case 1186: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:8379 - { - yyVAL.str = tree.JOIN_TYPE_CENTROIDX + ":" + yyDollar[2].str - } - case 1187: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.JoinCond -//line mysql_sql.y:8385 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1188: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.JoinCond -//line mysql_sql.y:8389 - { - yyLOCAL = yyDollar[1].joinCondUnion() - } - yyVAL.union = yyLOCAL - case 1189: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.JoinCond -//line mysql_sql.y:8395 - { - yyLOCAL = &tree.OnJoinCond{Expr: yyDollar[2].exprUnion()} - } - yyVAL.union = yyLOCAL - case 1190: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.JoinCond -//line mysql_sql.y:8399 - { - yyLOCAL = &tree.UsingJoinCond{Cols: yyDollar[3].identifierListUnion()} - } - yyVAL.union = yyLOCAL - case 1191: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:8405 - { - yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].cstrUnion().Compare())} - } - yyVAL.union = yyLOCAL - case 1192: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:8409 - { - yyLOCAL = append(yyDollar[1].identifierListUnion(), tree.Identifier(yyDollar[3].cstrUnion().Compare())) - } - yyVAL.union = yyLOCAL - case 1193: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:8415 - { - yyLOCAL = yyDollar[1].aliasedTableExprUnion() - } - yyVAL.union = yyLOCAL - case 1194: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:8419 - { - yyLOCAL = &tree.AliasedTableExpr{ - Expr: yyDollar[1].parenTableExprUnion(), - As: tree.AliasClause{ - Alias: tree.Identifier(yyDollar[2].str), - Cols: yyDollar[3].identifierListUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 1195: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:8429 - { - if yyDollar[2].str != "" { - yyLOCAL = &tree.AliasedTableExpr{ - Expr: yyDollar[1].tableExprUnion(), - As: tree.AliasClause{ - Alias: tree.Identifier(yyDollar[2].str), - }, - } - } else { - yyLOCAL = yyDollar[1].tableExprUnion() - } - } - yyVAL.union = yyLOCAL - case 1196: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:8442 - { - yyLOCAL = yyDollar[2].tableExprUnion() - } - yyVAL.union = yyLOCAL - case 1197: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.ParenTableExpr -//line mysql_sql.y:8450 - { - yyLOCAL = &tree.ParenTableExpr{Expr: yyDollar[1].selectStatementUnion().(*tree.ParenSelect).Select} - } - yyVAL.union = yyLOCAL - case 1198: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:8456 - { - name := tree.NewUnresolvedName(tree.NewCStr("json_table", 1)) - yyLOCAL = &tree.TableFunction{ - Func: &tree.FuncExpr{Func: tree.FuncName2ResolvableFunctionReference(name), FuncName: tree.NewCStr("json_table", 1), Exprs: tree.Exprs{yyDollar[3].exprUnion()}, Type: tree.FUNC_TYPE_TABLE}, - JSONTable: &tree.JSONTable{Path: yyDollar[5].str, Columns: yyDollar[8].jsonTableColumnsUnion()}, - } - } - yyVAL.union = yyLOCAL - case 1199: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.TableExpr -//line mysql_sql.y:8465 - { - name := tree.NewUnresolvedName(yyDollar[1].cstrUnion()) - yyLOCAL = &tree.TableFunction{ - Func: &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: yyDollar[1].cstrUnion(), - Exprs: yyDollar[3].exprsUnion(), - Type: tree.FUNC_TYPE_TABLE, - }, - } - } - yyVAL.union = yyLOCAL - case 1200: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.JSONTableColumn -//line mysql_sql.y:8479 - { - yyLOCAL = []*tree.JSONTableColumn{yyDollar[1].jsonTableColumnUnion()} - } - yyVAL.union = yyLOCAL - case 1201: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.JSONTableColumn -//line mysql_sql.y:8481 - { - yyLOCAL = append(yyDollar[1].jsonTableColumnsUnion(), yyDollar[3].jsonTableColumnUnion()) - } - yyVAL.union = yyLOCAL - case 1202: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.JSONTableColumn -//line mysql_sql.y:8485 - { - yyLOCAL = &tree.JSONTableColumn{Name: yyDollar[1].cstrUnion().Origin(), Kind: "ordinality"} - } - yyVAL.union = yyLOCAL - case 1203: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.JSONTableColumn -//line mysql_sql.y:8487 - { - yyLOCAL = yyDollar[5].jsonTableColumnUnion() - yyLOCAL.Name = yyDollar[1].cstrUnion().Origin() - yyLOCAL.Kind = "path" - yyLOCAL.Type = yyDollar[2].columnTypeUnion() - yyLOCAL.Path = yyDollar[4].str - } - yyVAL.union = yyLOCAL - case 1204: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.JSONTableColumn -//line mysql_sql.y:8489 - { - yyLOCAL = &tree.JSONTableColumn{Name: yyDollar[1].cstrUnion().Origin(), Kind: "exists", Type: yyDollar[2].columnTypeUnion(), Path: yyDollar[5].str} - } - yyVAL.union = yyLOCAL - case 1205: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL *tree.JSONTableColumn -//line mysql_sql.y:8491 - { - yyLOCAL = &tree.JSONTableColumn{Kind: "nested", Path: yyDollar[3].str, Children: yyDollar[6].jsonTableColumnsUnion()} - } - yyVAL.union = yyLOCAL - case 1206: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:8494 - { - yyVAL.str = "" - } - case 1207: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:8496 - { - yyVAL.str = yyDollar[1].str - } - case 1208: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.JSONTableResponse -//line mysql_sql.y:8500 - { - yyLOCAL = &tree.JSONTableResponse{Action: "null"} - } - yyVAL.union = yyLOCAL - case 1209: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.JSONTableResponse -//line mysql_sql.y:8502 - { - yyLOCAL = &tree.JSONTableResponse{Action: "error"} - } - yyVAL.union = yyLOCAL - case 1210: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.JSONTableResponse -//line mysql_sql.y:8504 - { - yyLOCAL = &tree.JSONTableResponse{Action: "default", Default: yyDollar[2].str} - } - yyVAL.union = yyLOCAL - case 1211: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.JSONTableColumn -//line mysql_sql.y:8507 - { - yyLOCAL = &tree.JSONTableColumn{} - } - yyVAL.union = yyLOCAL - case 1212: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.JSONTableColumn -//line mysql_sql.y:8509 - { - yyLOCAL = &tree.JSONTableColumn{OnEmpty: yyDollar[1].jsonTableResponseUnion(), OnError: yyDollar[4].jsonTableResponseUnion()} - } - yyVAL.union = yyLOCAL - case 1213: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.JSONTableColumn -//line mysql_sql.y:8511 - { - yyLOCAL = &tree.JSONTableColumn{OnEmpty: yyDollar[4].jsonTableResponseUnion(), OnError: yyDollar[1].jsonTableResponseUnion(), ReversePolicies: yyDollar[4].jsonTableResponseUnion() != nil} - } - yyVAL.union = yyLOCAL - case 1214: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.JSONTableResponse -//line mysql_sql.y:8514 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1215: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.JSONTableResponse -//line mysql_sql.y:8516 - { - yyLOCAL = yyDollar[1].jsonTableResponseUnion() - } - yyVAL.union = yyLOCAL - case 1216: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.JSONTableResponse -//line mysql_sql.y:8519 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1217: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.JSONTableResponse -//line mysql_sql.y:8521 - { - yyLOCAL = yyDollar[1].jsonTableResponseUnion() - } - yyVAL.union = yyLOCAL - case 1218: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.AliasedTableExpr -//line mysql_sql.y:8525 - { - yyLOCAL = &tree.AliasedTableExpr{ - Expr: yyDollar[1].tableNameUnion(), - As: tree.AliasClause{ - Alias: tree.Identifier(yyDollar[2].str), - }, - IndexHints: yyDollar[3].indexHintListUnion(), - } - } - yyVAL.union = yyLOCAL - case 1219: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []*tree.IndexHint -//line mysql_sql.y:8536 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1221: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.IndexHint -//line mysql_sql.y:8543 - { - yyLOCAL = []*tree.IndexHint{yyDollar[1].indexHintUnion()} - } - yyVAL.union = yyLOCAL - case 1222: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []*tree.IndexHint -//line mysql_sql.y:8547 - { - yyLOCAL = append(yyDollar[1].indexHintListUnion(), yyDollar[2].indexHintUnion()) - } - yyVAL.union = yyLOCAL - case 1223: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.IndexHint -//line mysql_sql.y:8553 - { - yyLOCAL = &tree.IndexHint{ - IndexNames: yyDollar[4].strsUnion(), - HintType: yyDollar[1].indexHintTypeUnion(), - HintScope: yyDollar[2].indexHintScopeUnion(), - } - } - yyVAL.union = yyLOCAL - case 1224: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexHintType -//line mysql_sql.y:8563 - { - yyLOCAL = tree.HintUse - } - yyVAL.union = yyLOCAL - case 1225: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexHintType -//line mysql_sql.y:8567 - { - yyLOCAL = tree.HintIgnore - } - yyVAL.union = yyLOCAL - case 1226: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexHintType -//line mysql_sql.y:8571 - { - yyLOCAL = tree.HintForce - } - yyVAL.union = yyLOCAL - case 1227: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.IndexHintScope -//line mysql_sql.y:8576 - { - yyLOCAL = tree.HintForScan - } - yyVAL.union = yyLOCAL - case 1228: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexHintScope -//line mysql_sql.y:8580 - { - yyLOCAL = tree.HintForJoin - } - yyVAL.union = yyLOCAL - case 1229: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IndexHintScope -//line mysql_sql.y:8584 - { - yyLOCAL = tree.HintForOrderBy - } - yyVAL.union = yyLOCAL - case 1230: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IndexHintScope -//line mysql_sql.y:8588 - { - yyLOCAL = tree.HintForGroupBy - } - yyVAL.union = yyLOCAL - case 1231: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:8593 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1232: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:8597 - { - yyLOCAL = []string{yyDollar[1].cstrUnion().Compare()} - } - yyVAL.union = yyLOCAL - case 1233: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:8601 - { - yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].cstrUnion().Compare()) - } - yyVAL.union = yyLOCAL - case 1234: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:8605 - { - yyLOCAL = []string{yyDollar[1].str} - } - yyVAL.union = yyLOCAL - case 1235: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:8609 - { - yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1236: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:8615 - { - yyVAL.str = "" - } - case 1237: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:8619 - { - yyVAL.str = yyDollar[1].str - } - case 1238: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8623 - { - yyVAL.str = yyDollar[2].str - } - case 1239: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:8629 - { - yyVAL.str = yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - } - case 1240: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:8633 - { - yyVAL.str = yylex.(*Lexer).GetDbOrTblName(yyDollar[1].str) - } - case 1241: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:8639 - { - yyLOCAL = tree.NewCStr("", 1) - } - yyVAL.union = yyLOCAL - case 1242: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:8643 - { - yyLOCAL = yyDollar[1].cstrUnion() - } - yyVAL.union = yyLOCAL - case 1243: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:8647 - { - yyLOCAL = yyDollar[2].cstrUnion() - } - yyVAL.union = yyLOCAL - case 1244: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:8651 - { - yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) - } - yyVAL.union = yyLOCAL - case 1245: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:8655 - { - yyLOCAL = tree.NewCStr(yyDollar[2].str, 1) - } - yyVAL.union = yyLOCAL - case 1246: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:8661 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1270: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:8704 - { - yyLOCAL = &tree.CreateIcebergCatalog{ - IfNotExists: yyDollar[4].ifNotExistsUnion(), - Name: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - Options: yyDollar[6].icebergOptionsUnion(), - } - } - yyVAL.union = yyLOCAL - case 1271: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:8714 - { - yyLOCAL = &tree.CreateMongoDBConnection{ - IfNotExists: yyDollar[4].ifNotExistsUnion(), - Name: tree.Identifier(yyDollar[5].cstrUnion().Compare()), - Options: yyDollar[6].mongodbOptionsUnion(), - } - } - yyVAL.union = yyLOCAL - case 1272: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:8724 - { - cronExpr := "" - timezone := "" - if yyDollar[5].sqlTaskScheduleUnion() != nil { - cronExpr = yyDollar[5].sqlTaskScheduleUnion().CronExpr - timezone = yyDollar[5].sqlTaskScheduleUnion().Timezone - } - yyLOCAL = &tree.CreateSQLTask{ - IfNotExists: yyDollar[3].ifNotExistsUnion(), - Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), - CronExpr: cronExpr, - Timezone: timezone, - GateCondition: sqlTaskNodeString(yyDollar[6].exprUnion()), - RetryLimit: yyDollar[7].int64ValUnion(), - Timeout: yyDollar[8].str, - SQLBody: sqlTaskBodyString(yyDollar[10].statementUnion()), - } - } - yyVAL.union = yyLOCAL - case 1273: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.SQLTaskSchedule -//line mysql_sql.y:8744 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1274: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.SQLTaskSchedule -//line mysql_sql.y:8748 - { - yyLOCAL = &tree.SQLTaskSchedule{ - CronExpr: yyDollar[2].str, - Timezone: yyDollar[3].str, - } - } - yyVAL.union = yyLOCAL - case 1275: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:8756 - { - yyVAL.str = "" - } - case 1276: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8760 - { - yyVAL.str = yyDollar[2].str - } - case 1277: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:8765 - { - yyLOCAL = tree.Expr(nil) - } - yyVAL.union = yyLOCAL - case 1278: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:8769 - { - yyLOCAL = yyDollar[3].exprUnion() - } - yyVAL.union = yyLOCAL - case 1279: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:8775 - { - yyLOCAL = yyDollar[1].exprUnion() - } - yyVAL.union = yyLOCAL - case 1280: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:8779 - { - yyLOCAL = tree.NewSubquery(yyDollar[1].selectUnion(), false) - } - yyVAL.union = yyLOCAL - case 1281: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:8784 - { - yyLOCAL = 0 - } - yyVAL.union = yyLOCAL - case 1282: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:8788 - { - yyLOCAL = sqlTaskInt64(yyDollar[2].item) - } - yyVAL.union = yyLOCAL - case 1283: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:8793 - { - yyVAL.str = "" - } - case 1284: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8797 - { - yyVAL.str = yyDollar[2].str - } - case 1285: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:8803 - { - var Language = yyDollar[3].str - var Name = tree.Identifier(yyDollar[5].str) - var Filename = tree.Identifier(yyDollar[7].str) - yyLOCAL = tree.NewCreateExtension( - Language, - Name, - Filename, - ) - } - yyVAL.union = yyLOCAL - case 1286: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:8816 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1287: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:8822 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1288: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:8828 - { - yyLOCAL = tree.NewCreateProcedure( - yyDollar[2].sourceOptionalUnion(), yyDollar[4].procNameUnion(), yyDollar[6].procArgsUnion(), yyDollar[8].str, yyDollar[9].str, - ) - } - yyVAL.union = yyLOCAL - case 1289: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.ProcedureName -//line mysql_sql.y:8836 - { - prefix := tree.ObjectNamePrefix{ExplicitSchema: false} - yyLOCAL = tree.NewProcedureName(tree.Identifier(yyDollar[1].cstrUnion().Compare()), prefix) - } - yyVAL.union = yyLOCAL - case 1290: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.ProcedureName -//line mysql_sql.y:8841 - { - dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - prefix := tree.ObjectNamePrefix{SchemaName: tree.Identifier(dbName), ExplicitSchema: true} - yyLOCAL = tree.NewProcedureName(tree.Identifier(yyDollar[3].cstrUnion().Compare()), prefix) - } - yyVAL.union = yyLOCAL - case 1291: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.ProcedureArgs -//line mysql_sql.y:8848 - { - yyLOCAL = tree.ProcedureArgs(nil) - } - yyVAL.union = yyLOCAL - case 1293: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ProcedureArgs -//line mysql_sql.y:8855 - { - yyLOCAL = tree.ProcedureArgs{yyDollar[1].procArgUnion()} - } - yyVAL.union = yyLOCAL - case 1294: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.ProcedureArgs -//line mysql_sql.y:8859 - { - yyLOCAL = append(yyDollar[1].procArgsUnion(), yyDollar[3].procArgUnion()) - } - yyVAL.union = yyLOCAL - case 1295: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ProcedureArg -//line mysql_sql.y:8865 - { - yyLOCAL = tree.ProcedureArg(yyDollar[1].procArgDeclUnion()) - } - yyVAL.union = yyLOCAL - case 1296: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.ProcedureArgDecl -//line mysql_sql.y:8871 - { - yyLOCAL = tree.NewProcedureArgDecl(yyDollar[1].procArgTypeUnion(), yyDollar[2].unresolvedNameUnion(), yyDollar[3].columnTypeUnion()) - } - yyVAL.union = yyLOCAL - case 1297: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.InOutArgType -//line mysql_sql.y:8876 - { - yyLOCAL = tree.TYPE_IN - } - yyVAL.union = yyLOCAL - case 1298: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.InOutArgType -//line mysql_sql.y:8880 - { - yyLOCAL = tree.TYPE_IN - } - yyVAL.union = yyLOCAL - case 1299: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.InOutArgType -//line mysql_sql.y:8884 - { - yyLOCAL = tree.TYPE_OUT - } - yyVAL.union = yyLOCAL - case 1300: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.InOutArgType -//line mysql_sql.y:8888 - { - yyLOCAL = tree.TYPE_INOUT - } - yyVAL.union = yyLOCAL - case 1301: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:8893 - { - yyVAL.str = "sql" - } - case 1302: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:8897 - { - yyVAL.str = yyDollar[2].str - } - case 1303: - yyDollar = yyS[yypt-14 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:8903 - { - if yyDollar[13].str == "" { - yylex.Error("no function body error") - goto ret1 - } - if yyDollar[11].str == "python" && yyDollar[14].str == "" { - yylex.Error("no handler error") - goto ret1 - } - - var Replace = yyDollar[2].sourceOptionalUnion() - var Name = yyDollar[4].functionNameUnion() - var Args = yyDollar[6].funcArgsUnion() - var ReturnType = yyDollar[9].funcReturnUnion() - var Language = yyDollar[11].str - var Import = yyDollar[12].boolValUnion() - var Body = yyDollar[13].str - var Handler = yyDollar[14].str - - yyLOCAL = tree.NewCreateFunction( - Replace, - Name, - Args, - ReturnType, - Language, - Import, - Body, - Handler, - ) - } - yyVAL.union = yyLOCAL - case 1304: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.FunctionName -//line mysql_sql.y:8936 - { - prefix := tree.ObjectNamePrefix{ExplicitSchema: false} - yyLOCAL = tree.NewFuncName(tree.Identifier(yyDollar[1].cstrUnion().Compare()), prefix) - } - yyVAL.union = yyLOCAL - case 1305: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.FunctionName -//line mysql_sql.y:8941 - { - dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - prefix := tree.ObjectNamePrefix{SchemaName: tree.Identifier(dbName), ExplicitSchema: true} - yyLOCAL = tree.NewFuncName(tree.Identifier(yyDollar[3].cstrUnion().Compare()), prefix) - } - yyVAL.union = yyLOCAL - case 1306: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.FunctionArgs -//line mysql_sql.y:8948 - { - yyLOCAL = tree.FunctionArgs(nil) - } - yyVAL.union = yyLOCAL - case 1308: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FunctionArgs -//line mysql_sql.y:8955 - { - yyLOCAL = tree.FunctionArgs{yyDollar[1].funcArgUnion()} - } - yyVAL.union = yyLOCAL - case 1309: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.FunctionArgs -//line mysql_sql.y:8959 - { - yyLOCAL = append(yyDollar[1].funcArgsUnion(), yyDollar[3].funcArgUnion()) - } - yyVAL.union = yyLOCAL - case 1310: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FunctionArg -//line mysql_sql.y:8965 - { - yyLOCAL = tree.FunctionArg(yyDollar[1].funcArgDeclUnion()) - } - yyVAL.union = yyLOCAL - case 1311: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.FunctionArgDecl -//line mysql_sql.y:8971 - { - yyLOCAL = tree.NewFunctionArgDecl(nil, yyDollar[1].columnTypeUnion(), nil) - } - yyVAL.union = yyLOCAL - case 1312: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FunctionArgDecl -//line mysql_sql.y:8975 - { - yyLOCAL = tree.NewFunctionArgDecl(yyDollar[1].unresolvedNameUnion(), yyDollar[2].columnTypeUnion(), nil) - } - yyVAL.union = yyLOCAL - case 1313: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FunctionArgDecl -//line mysql_sql.y:8979 - { - yyLOCAL = tree.NewFunctionArgDecl(yyDollar[1].unresolvedNameUnion(), yyDollar[2].columnTypeUnion(), yyDollar[4].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1314: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:8985 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1315: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.ReturnType -//line mysql_sql.y:8991 - { - yyLOCAL = tree.NewReturnType(yyDollar[1].columnTypeUnion()) - } - yyVAL.union = yyLOCAL - case 1316: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:8997 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1317: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:9001 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1318: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:9006 - { - yyVAL.str = "" - } - case 1320: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:9013 - { - yyVAL.str = yyDollar[2].str - } - case 1321: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9019 - { - var Replace bool - var Name = yyDollar[5].tableNameUnion() - var ColNames = yyDollar[6].identifierListUnion() - var AsSource = yyDollar[8].selectUnion() - var IfNotExists = yyDollar[4].ifNotExistsUnion() - var CheckOption = yyDollar[9].str - if intoErr := tree.ValidateSelectIntoNotAllowed(AsSource); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = tree.NewCreateView( - Replace, - Name, - ColNames, - AsSource, - IfNotExists, CheckOption, - ) - } - yyVAL.union = yyLOCAL - case 1322: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9038 - { - var Replace = yyDollar[2].sourceOptionalUnion() - var Name = yyDollar[5].tableNameUnion() - var ColNames = yyDollar[6].identifierListUnion() - var AsSource = yyDollar[8].selectUnion() - var IfNotExists = yyDollar[4].ifNotExistsUnion() - var CheckOption = yyDollar[9].str - if intoErr := tree.ValidateSelectIntoNotAllowed(AsSource); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - yyLOCAL = tree.NewCreateView( - Replace, - Name, - ColNames, - AsSource, - IfNotExists, CheckOption, - ) - } - yyVAL.union = yyLOCAL - case 1323: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9059 - { - var IfNotExists = yyDollar[3].ifNotExistsUnion() - var Name = yyDollar[4].exprUnion() - var AuthOption = yyDollar[5].accountAuthOptionUnion() - var StatusOption = yyDollar[6].accountStatusUnion() - var Comment = yyDollar[7].accountCommentUnion() - yyLOCAL = tree.NewCreateAccount( - IfNotExists, - Name, - AuthOption, - StatusOption, - Comment, - ) - } - yyVAL.union = yyLOCAL - case 1324: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9074 - { - var FromUri = yyDollar[4].str - var SubscriptionAccountName = yyDollar[5].cstrUnion().Compare() - var PubName = tree.Identifier(yyDollar[7].cstrUnion().Compare()) - var SyncInterval = yyDollar[8].int64ValUnion() - var cs = tree.NewCreateSubscription( - true, // isDatabase - tree.Identifier(""), // dbName (empty for account level) - "", // tableName - FromUri, - SubscriptionAccountName, - PubName, - SyncInterval, - ) - yyLOCAL = cs - } - yyVAL.union = yyLOCAL - case 1325: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:9093 - { - yyVAL.str = yyDollar[1].str - } - case 1326: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:9097 - { - yyVAL.str = yyVAL.str + yyDollar[2].str - } - case 1327: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:9103 - { - yyVAL.str = "ALGORITHM = " + yyDollar[3].str - } - case 1328: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:9107 - { - yyVAL.str = "DEFINER = " - } - case 1329: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:9111 - { - yyVAL.str = "SQL SECURITY " + yyDollar[3].str - } - case 1330: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:9116 - { - yyVAL.str = "NONE" - } - case 1331: - yyDollar = yyS[yypt-4 : yypt+1] -//line mysql_sql.y:9120 - { - yyVAL.str = yyDollar[2].str - if yyVAL.str == "" { - yyVAL.str = "CASCADED" - } - } - case 1337: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:9134 - { - yyVAL.str = "" - } - case 1340: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:9142 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1341: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:9148 - { - var str = yyDollar[1].cstrUnion().Compare() - yyLOCAL = tree.NewNumVal(str, str, false, tree.P_char) - } - yyVAL.union = yyLOCAL - case 1342: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:9153 - { - yyLOCAL = tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()) - } - yyVAL.union = yyLOCAL - case 1343: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.AccountAuthOption -//line mysql_sql.y:9159 - { - var Equal = yyDollar[2].str - var AdminName = yyDollar[3].exprUnion() - var IdentifiedType = yyDollar[4].accountIdentifiedUnion() - yyLOCAL = *tree.NewAccountAuthOption( - Equal, - AdminName, - IdentifiedType, - ) - } - yyVAL.union = yyLOCAL - case 1344: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:9172 - { - var str = yyDollar[1].str - yyLOCAL = tree.NewNumVal(str, str, false, tree.P_char) - } - yyVAL.union = yyLOCAL - case 1345: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:9177 - { - var str = yyDollar[1].cstrUnion().Compare() - yyLOCAL = tree.NewNumVal(str, str, false, tree.P_char) - } - yyVAL.union = yyLOCAL - case 1346: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:9182 - { - yyLOCAL = tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()) - } - yyVAL.union = yyLOCAL - case 1347: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AccountIdentified -//line mysql_sql.y:9188 - { - yyLOCAL = *tree.NewAccountIdentified( - tree.AccountIdentifiedByPassword, - tree.NewNumVal(yyDollar[3].str, yyDollar[3].str, false, tree.P_char), - ) - } - yyVAL.union = yyLOCAL - case 1348: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AccountIdentified -//line mysql_sql.y:9195 - { - yyLOCAL = *tree.NewAccountIdentified( - tree.AccountIdentifiedByPassword, - tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()), - ) - } - yyVAL.union = yyLOCAL - case 1349: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.AccountIdentified -//line mysql_sql.y:9202 - { - yyLOCAL = *tree.NewAccountIdentified( - tree.AccountIdentifiedByRandomPassword, - nil, - ) - } - yyVAL.union = yyLOCAL - case 1350: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AccountIdentified -//line mysql_sql.y:9209 - { - yyLOCAL = *tree.NewAccountIdentified( - tree.AccountIdentifiedWithSSL, - tree.NewNumVal(yyDollar[3].str, yyDollar[3].str, false, tree.P_char), - ) - } - yyVAL.union = yyLOCAL - case 1351: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AccountIdentified -//line mysql_sql.y:9216 - { - yyLOCAL = *tree.NewAccountIdentified( - tree.AccountIdentifiedWithSSL, - tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()), - ) - } - yyVAL.union = yyLOCAL - case 1352: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.AccountStatus -//line mysql_sql.y:9224 - { - as := tree.NewAccountStatus() - as.Exist = false - yyLOCAL = *as - } - yyVAL.union = yyLOCAL - case 1353: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.AccountStatus -//line mysql_sql.y:9230 - { - as := tree.NewAccountStatus() - as.Exist = true - as.Option = tree.AccountStatusOpen - yyLOCAL = *as - } - yyVAL.union = yyLOCAL - case 1354: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.AccountStatus -//line mysql_sql.y:9237 - { - as := tree.NewAccountStatus() - as.Exist = true - as.Option = tree.AccountStatusSuspend - yyLOCAL = *as - } - yyVAL.union = yyLOCAL - case 1355: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.AccountStatus -//line mysql_sql.y:9244 - { - as := tree.NewAccountStatus() - as.Exist = true - as.Option = tree.AccountStatusRestricted - yyLOCAL = *as - } - yyVAL.union = yyLOCAL - case 1356: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.AccountComment -//line mysql_sql.y:9252 - { - ac := tree.NewAccountComment() - ac.Exist = false - yyLOCAL = *ac - } - yyVAL.union = yyLOCAL - case 1357: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AccountComment -//line mysql_sql.y:9258 - { - ac := tree.NewAccountComment() - ac.Exist = true - ac.Comment = yyDollar[2].str - yyLOCAL = *ac - } - yyVAL.union = yyLOCAL - case 1358: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9267 - { - var IfNotExists = yyDollar[3].ifNotExistsUnion() - var Users = yyDollar[4].usersUnion() - var Role = yyDollar[5].accountRoleUnion() - var MiscOpt = yyDollar[6].userMiscOptionUnion() - var CommentOrAttribute = yyDollar[7].accountCommentOrAttributeUnion() - yyLOCAL = tree.NewCreateUser( - IfNotExists, - Users, - Role, - MiscOpt, - CommentOrAttribute, - ) - } - yyVAL.union = yyLOCAL - case 1359: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9284 - { - var IfNotExists = yyDollar[3].ifNotExistsUnion() - var Name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - var Database = tree.Identifier(yyDollar[6].str) - var AccountsSet = yyDollar[7].accountsSetOptionUnion() - var Comment = yyDollar[8].str - yyLOCAL = tree.NewCreatePublication( - IfNotExists, - Name, - Database, - nil, - AccountsSet, - Comment, - ) - } - yyVAL.union = yyLOCAL - case 1360: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9300 - { - var IfNotExists = yyDollar[3].ifNotExistsUnion() - var Name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - var Database = tree.Identifier(yyDollar[6].str) - var Table = yyDollar[8].tableNamesUnion() - var AccountsSet = yyDollar[9].accountsSetOptionUnion() - var Comment = yyDollar[10].str - yyLOCAL = tree.NewCreatePublication( - IfNotExists, - Name, - Database, - Table, - AccountsSet, - Comment, - ) - } - yyVAL.union = yyLOCAL - case 1361: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9317 - { - var IfNotExists = yyDollar[3].ifNotExistsUnion() - var Name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - var Database = tree.Identifier("*") - var AccountsSet = yyDollar[7].accountsSetOptionUnion() - var Comment = yyDollar[8].str - yyLOCAL = tree.NewCreatePublication( - IfNotExists, - Name, - Database, - nil, - AccountsSet, - Comment, - ) - } - yyVAL.union = yyLOCAL - case 1362: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.AccountsSetOption -//line mysql_sql.y:9335 - { - yyLOCAL = &tree.AccountsSetOption{ - All: true, - } - } - yyVAL.union = yyLOCAL - case 1363: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.AccountsSetOption -//line mysql_sql.y:9341 - { - yyLOCAL = &tree.AccountsSetOption{ - SetAccounts: yyDollar[2].identifierListUnion(), - } - } - yyVAL.union = yyLOCAL - case 1364: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9349 - { - var IfNotExists = yyDollar[3].ifNotExistsUnion() - var Name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - var Url = yyDollar[5].str - var Credentials = yyDollar[6].stageCredentialsUnion() - var Status = yyDollar[7].stageStatusUnion() - var Comment = yyDollar[8].stageCommentUnion() - yyLOCAL = tree.NewCreateStage( - IfNotExists, - Name, - Url, - Credentials, - Status, - Comment, - ) - } - yyVAL.union = yyLOCAL - case 1365: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.StageStatus -//line mysql_sql.y:9367 - { - yyLOCAL = tree.StageStatus{ - Exist: false, - } - } - yyVAL.union = yyLOCAL - case 1366: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.StageStatus -//line mysql_sql.y:9373 - { - yyLOCAL = tree.StageStatus{ - Exist: true, - Option: tree.StageStatusEnabled, - } - } - yyVAL.union = yyLOCAL - case 1367: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.StageStatus -//line mysql_sql.y:9380 - { - yyLOCAL = tree.StageStatus{ - Exist: true, - Option: tree.StageStatusDisabled, - } - } - yyVAL.union = yyLOCAL - case 1368: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.StageComment -//line mysql_sql.y:9388 - { - yyLOCAL = tree.StageComment{ - Exist: false, - } - } - yyVAL.union = yyLOCAL - case 1369: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.StageComment -//line mysql_sql.y:9394 - { - yyLOCAL = tree.StageComment{ - Exist: true, - Comment: yyDollar[3].str, - } - } - yyVAL.union = yyLOCAL - case 1370: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:9403 - { - yyLOCAL = int64(0) - } - yyVAL.union = yyLOCAL - case 1371: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:9407 - { - switch v := yyDollar[3].item.(type) { - case int64: - yyLOCAL = v - case uint64: - yyLOCAL = int64(v) - default: - yyLOCAL = int64(0) - } - } - yyVAL.union = yyLOCAL - case 1372: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.StageUrl -//line mysql_sql.y:9419 - { - yyLOCAL = tree.StageUrl{ - Exist: false, - } - } - yyVAL.union = yyLOCAL - case 1373: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.StageUrl -//line mysql_sql.y:9425 - { - yyLOCAL = tree.StageUrl{ - Exist: true, - Url: yyDollar[3].str, - } - } - yyVAL.union = yyLOCAL - case 1374: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.StageCredentials -//line mysql_sql.y:9433 - { - yyLOCAL = tree.StageCredentials{ - Exist: false, - } - } - yyVAL.union = yyLOCAL - case 1375: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.StageCredentials -//line mysql_sql.y:9439 - { - yyLOCAL = tree.StageCredentials{ - Exist: true, - Credentials: yyDollar[4].strsUnion(), - } - } - yyVAL.union = yyLOCAL - case 1376: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:9448 - { - yyLOCAL = yyDollar[1].strsUnion() - } - yyVAL.union = yyLOCAL - case 1377: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:9452 - { - yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].strsUnion()...) - } - yyVAL.union = yyLOCAL - case 1378: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:9457 - { - yyLOCAL = []string{} - } - yyVAL.union = yyLOCAL - case 1379: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:9461 - { - yyLOCAL = append(yyLOCAL, yyDollar[1].str) - yyLOCAL = append(yyLOCAL, yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1380: - yyDollar = yyS[yypt-3 : yypt+1] -//line mysql_sql.y:9468 - { - yyVAL.str = yyDollar[3].str - } - case 1381: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:9473 - { - yyVAL.str = "" - } - case 1382: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:9477 - { - yyVAL.str = yyDollar[2].str - } - case 1383: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9483 - { - var ifNotExists = yyDollar[3].boolValUnion() - var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - var urlOption = yyDollar[6].stageUrlUnion() - var credentialsOption = yyDollar[7].stageCredentialsUnion() - var statusOption = yyDollar[8].stageStatusUnion() - var comment = yyDollar[9].stageCommentUnion() - yyLOCAL = tree.NewAlterStage(ifNotExists, name, urlOption, credentialsOption, statusOption, comment) - } - yyVAL.union = yyLOCAL - case 1384: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9495 - { - var ifExists = yyDollar[3].boolValUnion() - var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - var accountsSet = yyDollar[5].accountsSetOptionUnion() - var dbName = yyDollar[6].str - var table = yyDollar[7].tableNamesUnion() - var comment = yyDollar[8].str - yyLOCAL = tree.NewAlterPublication(ifExists, name, accountsSet, dbName, table, comment) - } - yyVAL.union = yyLOCAL - case 1385: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.AccountsSetOption -//line mysql_sql.y:9506 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1386: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.AccountsSetOption -//line mysql_sql.y:9510 - { - yyLOCAL = &tree.AccountsSetOption{ - All: true, - } - } - yyVAL.union = yyLOCAL - case 1387: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.AccountsSetOption -//line mysql_sql.y:9516 - { - yyLOCAL = &tree.AccountsSetOption{ - SetAccounts: yyDollar[2].identifierListUnion(), - } - } - yyVAL.union = yyLOCAL - case 1388: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.AccountsSetOption -//line mysql_sql.y:9522 - { - yyLOCAL = &tree.AccountsSetOption{ - AddAccounts: yyDollar[3].identifierListUnion(), - } - } - yyVAL.union = yyLOCAL - case 1389: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.AccountsSetOption -//line mysql_sql.y:9528 - { - yyLOCAL = &tree.AccountsSetOption{ - DropAccounts: yyDollar[3].identifierListUnion(), - } - } - yyVAL.union = yyLOCAL - case 1390: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:9535 - { - yyVAL.str = "" - } - case 1391: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:9539 - { - yyVAL.str = yyDollar[2].str - } - case 1392: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.TableNames -//line mysql_sql.y:9544 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1393: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.TableNames -//line mysql_sql.y:9548 - { - yyLOCAL = yyDollar[2].tableNamesUnion() - } - yyVAL.union = yyLOCAL - case 1394: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9554 - { - var ifExists = yyDollar[3].boolValUnion() - var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - yyLOCAL = tree.NewDropPublication(ifExists, name) - } - yyVAL.union = yyLOCAL - case 1395: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9562 - { - var ifExists = yyDollar[4].boolValUnion() - var taskID = yyDollar[5].str - yyLOCAL = tree.NewDropCcprSubscription(ifExists, taskID) - } - yyVAL.union = yyLOCAL - case 1396: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9570 - { - var taskID = yyDollar[4].str - yyLOCAL = tree.NewResumeCcprSubscription(taskID) - } - yyVAL.union = yyLOCAL - case 1397: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9577 - { - var taskID = yyDollar[4].str - yyLOCAL = tree.NewPauseCcprSubscription(taskID) - } - yyVAL.union = yyLOCAL - case 1398: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9584 - { - var ifNotExists = yyDollar[3].boolValUnion() - var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - yyLOCAL = tree.NewDropStage(ifNotExists, name) - } - yyVAL.union = yyLOCAL - case 1399: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9592 - { - var ifExists = yyDollar[5].boolValUnion() - var path = yyDollar[6].str - yyLOCAL = tree.NewRemoveStageFiles(ifExists, path) - } - yyVAL.union = yyLOCAL - case 1400: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9600 - { - var ifExists = yyDollar[3].boolValUnion() - var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - yyLOCAL = tree.NewDropSnapShot(ifExists, name, "", "") - } - yyVAL.union = yyLOCAL - case 1401: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9606 - { - var ifExists = yyDollar[3].boolValUnion() - var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - var accountName = tree.Identifier(yyDollar[6].cstrUnion().Compare()) - var pubName = tree.Identifier(yyDollar[8].cstrUnion().Compare()) - yyLOCAL = tree.NewDropSnapShot(ifExists, name, accountName, pubName) - } - yyVAL.union = yyLOCAL - case 1402: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9616 - { - var ifExists = yyDollar[3].boolValUnion() - var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - yyLOCAL = &tree.DropPitr{ - IfExists: ifExists, - Name: name, - Internal: yyDollar[5].boolValUnion(), - } - - } - yyVAL.union = yyLOCAL - case 1403: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:9629 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1404: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.AccountCommentOrAttribute -//line mysql_sql.y:9634 - { - var Exist = false - var IsComment bool - var Str string - yyLOCAL = *tree.NewAccountCommentOrAttribute( - Exist, - IsComment, - Str, - ) - - } - yyVAL.union = yyLOCAL - case 1405: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AccountCommentOrAttribute -//line mysql_sql.y:9646 - { - var Exist = true - var IsComment = true - var Str = yyDollar[2].str - yyLOCAL = *tree.NewAccountCommentOrAttribute( - Exist, - IsComment, - Str, - ) - } - yyVAL.union = yyLOCAL - case 1406: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.AccountCommentOrAttribute -//line mysql_sql.y:9657 - { - var Exist = true - var IsComment = false - var Str = yyDollar[2].str - yyLOCAL = *tree.NewAccountCommentOrAttribute( - Exist, - IsComment, - Str, - ) - } - yyVAL.union = yyLOCAL - case 1407: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.User -//line mysql_sql.y:9765 - { - yyLOCAL = []*tree.User{yyDollar[1].userUnion()} - } - yyVAL.union = yyLOCAL - case 1408: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.User -//line mysql_sql.y:9769 - { - yyLOCAL = append(yyDollar[1].usersUnion(), yyDollar[3].userUnion()) - } - yyVAL.union = yyLOCAL - case 1409: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.User -//line mysql_sql.y:9775 - { - var Username = yyDollar[1].usernameRecordUnion().Username - var Hostname = yyDollar[1].usernameRecordUnion().Hostname - var AuthOption = yyDollar[2].userIdentifiedUnion() - yyLOCAL = tree.NewUser( - Username, - Hostname, - AuthOption, - ) - } - yyVAL.union = yyLOCAL - case 1410: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.User -//line mysql_sql.y:9788 - { - yyLOCAL = []*tree.User{yyDollar[1].userUnion()} - } - yyVAL.union = yyLOCAL - case 1411: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.User -//line mysql_sql.y:9792 - { - yyLOCAL = append(yyDollar[1].usersUnion(), yyDollar[3].userUnion()) - } - yyVAL.union = yyLOCAL - case 1412: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.User -//line mysql_sql.y:9798 - { - var Username = yyDollar[1].usernameRecordUnion().Username - var Hostname = yyDollar[1].usernameRecordUnion().Hostname - var AuthOption = yyDollar[2].userIdentifiedUnion() - yyLOCAL = tree.NewUser( - Username, - Hostname, - AuthOption, - ) - } - yyVAL.union = yyLOCAL - case 1413: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.UsernameRecord -//line mysql_sql.y:9811 - { - yyLOCAL = &tree.UsernameRecord{Username: yyDollar[1].str, Hostname: "%"} - } - yyVAL.union = yyLOCAL - case 1414: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.UsernameRecord -//line mysql_sql.y:9815 - { - yyLOCAL = &tree.UsernameRecord{Username: yyDollar[1].str, Hostname: yyDollar[3].str} - } - yyVAL.union = yyLOCAL - case 1415: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.UsernameRecord -//line mysql_sql.y:9819 - { - yyLOCAL = &tree.UsernameRecord{Username: yyDollar[1].str, Hostname: yyDollar[2].str} - } - yyVAL.union = yyLOCAL - case 1416: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.AccountIdentified -//line mysql_sql.y:9824 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1417: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.AccountIdentified -//line mysql_sql.y:9828 - { - yyLOCAL = yyDollar[1].userIdentifiedUnion() - } - yyVAL.union = yyLOCAL - case 1418: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.AccountIdentified -//line mysql_sql.y:9834 - { - yyLOCAL = &tree.AccountIdentified{ - Typ: tree.AccountIdentifiedByPassword, - Str: tree.NewNumVal(yyDollar[3].str, yyDollar[3].str, false, tree.P_char), - } - } - yyVAL.union = yyLOCAL - case 1419: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.AccountIdentified -//line mysql_sql.y:9841 - { - yyLOCAL = &tree.AccountIdentified{ - Typ: tree.AccountIdentifiedByRandomPassword, - } - } - yyVAL.union = yyLOCAL - case 1420: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.AccountIdentified -//line mysql_sql.y:9847 - { - yyLOCAL = &tree.AccountIdentified{ - Typ: tree.AccountIdentifiedWithSSL, - Str: tree.NewNumVal(yyDollar[3].str, yyDollar[3].str, false, tree.P_char), - } - } - yyVAL.union = yyLOCAL - case 1421: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:9856 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1423: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9863 - { - var IfNotExists = yyDollar[3].ifNotExistsUnion() - var Roles = yyDollar[4].rolesUnion() - yyLOCAL = tree.NewCreateRole( - IfNotExists, - Roles, - ) - } - yyVAL.union = yyLOCAL - case 1424: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.Role -//line mysql_sql.y:9874 - { - yyLOCAL = []*tree.Role{yyDollar[1].roleUnion()} - } - yyVAL.union = yyLOCAL - case 1425: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.Role -//line mysql_sql.y:9878 - { - yyLOCAL = append(yyDollar[1].rolesUnion(), yyDollar[3].roleUnion()) - } - yyVAL.union = yyLOCAL - case 1426: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Role -//line mysql_sql.y:9884 - { - var UserName = yyDollar[1].cstrUnion().Compare() - yyLOCAL = tree.NewRole( - UserName, - ) - } - yyVAL.union = yyLOCAL - case 1427: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:9893 - { - yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) - } - yyVAL.union = yyLOCAL - case 1428: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:9897 - { - yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) - } - yyVAL.union = yyLOCAL - case 1429: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:9901 - { - yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) - } - yyVAL.union = yyLOCAL - case 1430: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:9905 - { - yyLOCAL = tree.NewCStr("lag", 1) - } - yyVAL.union = yyLOCAL - case 1431: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:9909 - { - yyLOCAL = tree.NewCStr("lead", 1) - } - yyVAL.union = yyLOCAL - case 1432: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:9913 - { - yyLOCAL = tree.NewCStr("first_value", 1) - } - yyVAL.union = yyLOCAL - case 1433: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:9917 - { - yyLOCAL = tree.NewCStr("last_value", 1) - } - yyVAL.union = yyLOCAL - case 1434: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:9921 - { - yyLOCAL = tree.NewCStr("nth_value", 1) - } - yyVAL.union = yyLOCAL - case 1435: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.IndexCategory -//line mysql_sql.y:9926 - { - yyLOCAL = tree.INDEX_CATEGORY_NONE - } - yyVAL.union = yyLOCAL - case 1436: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IndexCategory -//line mysql_sql.y:9930 - { - yyLOCAL = tree.INDEX_CATEGORY_FULLTEXT - } - yyVAL.union = yyLOCAL - case 1437: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IndexCategory -//line mysql_sql.y:9934 - { - yyLOCAL = tree.INDEX_CATEGORY_FULLTEXT2 - } - yyVAL.union = yyLOCAL - case 1438: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IndexCategory -//line mysql_sql.y:9938 - { - yyLOCAL = tree.INDEX_CATEGORY_SPATIAL - } - yyVAL.union = yyLOCAL - case 1439: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IndexCategory -//line mysql_sql.y:9942 - { - yyLOCAL = tree.INDEX_CATEGORY_UNIQUE - } - yyVAL.union = yyLOCAL - case 1440: - yyDollar = yyS[yypt-11 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:9948 - { - io := yyDollar[11].indexOptionUnion() - if io == nil { - io = tree.NewIndexOption() - } - // MySQL permits the index type before ON or after the key parts. - // When both forms are present, the trailing type takes precedence. - if io.IType == tree.INDEX_TYPE_INVALID { - io.IType = yyDollar[5].indexTypeUnion() - } - var Name = tree.Identifier(yyDollar[4].cstrUnion().Origin()) - var Table = yyDollar[7].tableNameUnion() - var ifNotExists = false - var IndexCat = yyDollar[2].indexCategoryUnion() - var KeyParts = yyDollar[9].keyPartsUnion() - var IndexOption = io - var MiscOption []tree.MiscOption - yyLOCAL = tree.NewCreateIndex( - Name, - Table, - ifNotExists, - IndexCat, - KeyParts, - IndexOption, - MiscOption, - ) - } - yyVAL.union = yyLOCAL - case 1441: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:9977 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1442: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:9981 - { - yyLOCAL = mergeIndexOption(yyDollar[1].indexOptionUnion(), yyDollar[2].indexOptionUnion()) - } - yyVAL.union = yyLOCAL - case 1443: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:9986 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1444: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:9990 - { - yyLOCAL = mergeIndexOption(yyDollar[1].indexOptionUnion(), yyDollar[2].indexOptionUnion()) - } - yyVAL.union = yyLOCAL - case 1445: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:9996 - { - yyLOCAL = yyDollar[1].indexOptionUnion() - } - yyVAL.union = yyLOCAL - case 1446: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10000 - { - io := tree.NewIndexOption() - io.IType = yyDollar[1].indexTypeUnion() - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1447: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10008 - { - io := tree.NewIndexOption() - io.KeyBlockSize = integralToUint64(yyDollar[3].item) - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1448: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10014 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("LISTS should be greater than 0") - return 1 - } - - io := tree.NewIndexOption() - io.AlgoParamList = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1449: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10027 - { - io := tree.NewIndexOption() - io.AlgoParamVectorOpType = yyDollar[2].str - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1450: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10033 - { - io := tree.NewIndexOption() - io.Comment = yyDollar[2].str - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1451: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10039 - { - io := tree.NewIndexOption() - io.ParserName = yyDollar[3].cstrUnion().Compare() - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1452: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10045 - { - io := tree.NewIndexOption() - io.Visible = tree.VISIBLE_TYPE_VISIBLE - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1453: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10051 - { - io := tree.NewIndexOption() - io.Visible = tree.VISIBLE_TYPE_INVISIBLE - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1454: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10057 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("M should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.AlgoParamM = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1455: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10069 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("EF_CONSTRUCTION should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.HnswEfConstruction = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1456: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10081 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("EF_SEARCH should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.HnswEfSearch = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1457: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10093 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("INTERMEDIATE_GRAPH_DEGREE should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.IntermediateGraphDegree = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1458: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10105 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("GRAPH_DEGREE should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.GraphDegree = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1459: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10117 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("GRAPH_DEGREE should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.ITopkSize = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1460: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10129 - { - io := tree.NewIndexOption() - io.IncludeColumns = yyDollar[3].unresolveNamesUnion() - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1461: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10135 - { - io := tree.NewIndexOption() - io.Quantization = yyDollar[2].str - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1462: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10141 - { - io := tree.NewIndexOption() - io.DistributionMode = yyDollar[2].str - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1463: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10147 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("M should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.BitsPerCode = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1464: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10159 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("KMEANS_TRAIN_PERCENT should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.KmeansTrainPercent = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1465: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10171 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("QUANTIZER_TRAIN_LIMIT should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.QuantizerTrainLimit = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1466: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10183 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("KMEANS_MAX_ITERATION should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.KmeansMaxIteration = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1467: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10195 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("MAX_INDEX_CAPACITY should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.MaxIndexCapacity = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1468: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10207 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val <= 0 { - yylex.Error("MAX_POSTINGS_CAPACITY should be greater than 0") - return 1 - } - io := tree.NewIndexOption() - io.MaxPostingsCapacity = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1469: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10219 - { - io := tree.NewIndexOption() - io.PositionFree = true - io.PositionFreeSet = true - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1470: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10226 - { - io := tree.NewIndexOption() - io.PositionFree = false - io.PositionFreeSet = true - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1471: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10233 - { - io := tree.NewIndexOption() - io.Async = true - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1472: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10239 - { - io := tree.NewIndexOption() - io.ForceSync = true - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1473: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10245 - { - io := tree.NewIndexOption() - io.Merge = true - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1474: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10251 - { - io := tree.NewIndexOption() - io.AutoUpdate = true - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1475: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10257 - { - io := tree.NewIndexOption() - io.AutoUpdate = false - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1476: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10263 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val < 0 { - yylex.Error("DAY should be greater than or equal to 0") - return 1 - } - io := tree.NewIndexOption() - io.Day = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1477: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10275 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val < 0 || val > 23 { - yylex.Error("HOUR should be between 0 and 23") - return 1 - } - io := tree.NewIndexOption() - io.Hour = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1478: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IndexOption -//line mysql_sql.y:10287 - { - val, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - if val < 0 { - yylex.Error("SECOND should be greater than or equal to 0") - return 1 - } - io := tree.NewIndexOption() - io.Second = val - yyLOCAL = io - } - yyVAL.union = yyLOCAL - case 1479: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.KeyPart -//line mysql_sql.y:10302 - { - yyLOCAL = []*tree.KeyPart{yyDollar[1].keyPartUnion()} - } - yyVAL.union = yyLOCAL - case 1480: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.KeyPart -//line mysql_sql.y:10306 - { - yyLOCAL = append(yyDollar[1].keyPartsUnion(), yyDollar[3].keyPartUnion()) - } - yyVAL.union = yyLOCAL - case 1481: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.KeyPart -//line mysql_sql.y:10312 - { - // Order is parsed but just ignored as MySQL dtree. - var ColName = yyDollar[1].unresolvedNameUnion() - var Length = int(yyDollar[2].lengthOptUnion()) - var Direction = yyDollar[3].directionUnion() - var Expr tree.Expr - yyLOCAL = tree.NewKeyPart( - ColName, - Length, - Direction, - Expr, - ) - } - yyVAL.union = yyLOCAL - case 1482: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.KeyPart -//line mysql_sql.y:10326 - { - var ColName *tree.UnresolvedName - var Length int - var Expr = yyDollar[2].exprUnion() - var Direction = yyDollar[4].directionUnion() - yyLOCAL = tree.NewKeyPart( - ColName, - Length, - Direction, - Expr, - ) - } - yyVAL.union = yyLOCAL - case 1483: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.IndexType -//line mysql_sql.y:10340 - { - yyLOCAL = tree.INDEX_TYPE_INVALID - } - yyVAL.union = yyLOCAL - case 1484: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IndexType -//line mysql_sql.y:10344 - { - yyLOCAL = yyDollar[1].indexTypeUnion() - } - yyVAL.union = yyLOCAL - case 1485: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexType -//line mysql_sql.y:10350 - { - yyLOCAL = tree.INDEX_TYPE_BTREE - } - yyVAL.union = yyLOCAL - case 1486: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexType -//line mysql_sql.y:10354 - { - yyLOCAL = tree.INDEX_TYPE_IVFFLAT - } - yyVAL.union = yyLOCAL - case 1487: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexType -//line mysql_sql.y:10358 - { - yyLOCAL = tree.INDEX_TYPE_HNSW - } - yyVAL.union = yyLOCAL - case 1488: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexType -//line mysql_sql.y:10362 - { - yyLOCAL = tree.INDEX_TYPE_IVFPQ - } - yyVAL.union = yyLOCAL - case 1489: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexType -//line mysql_sql.y:10366 - { - yyLOCAL = tree.INDEX_TYPE_CAGRA - } - yyVAL.union = yyLOCAL - case 1490: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexType -//line mysql_sql.y:10370 - { - yyLOCAL = tree.INDEX_TYPE_MASTER - } - yyVAL.union = yyLOCAL - case 1491: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexType -//line mysql_sql.y:10374 - { - yyLOCAL = tree.INDEX_TYPE_HASH - } - yyVAL.union = yyLOCAL - case 1492: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexType -//line mysql_sql.y:10378 - { - yyLOCAL = tree.INDEX_TYPE_RTREE - } - yyVAL.union = yyLOCAL - case 1493: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.IndexType -//line mysql_sql.y:10382 - { - yyLOCAL = tree.INDEX_TYPE_BSI - } - yyVAL.union = yyLOCAL - case 1494: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10388 - { - var IfNotExists = yyDollar[3].ifNotExistsUnion() - var Name = tree.Identifier(yyDollar[4].str) - var SubscriptionOption = yyDollar[5].subscriptionOptionUnion() - var CreateOptions = yyDollar[6].createOptionsUnion() - yyLOCAL = tree.NewCreateDatabase( - IfNotExists, - Name, - SubscriptionOption, - CreateOptions, - ) - } - yyVAL.union = yyLOCAL - case 1495: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10402 - { - var t = tree.NewCloneDatabase() - t.IfNotExists = yyDollar[3].ifNotExistsUnion() - t.DstDatabase = tree.Identifier(yyDollar[4].str) - t.SrcDatabase = tree.Identifier(yyDollar[6].str) - t.AtTsExpr = yyDollar[7].atTimeStampUnion() - t.ToAccountOpt = yyDollar[8].toAccountOptUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1496: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10412 - { - var DbName = tree.Identifier(yyDollar[4].str) - var FromUri = yyDollar[6].str - var SubscriptionAccountName = yyDollar[7].cstrUnion().Compare() - var PubName = tree.Identifier(yyDollar[9].cstrUnion().Compare()) - var SyncInterval = yyDollar[10].int64ValUnion() - yyLOCAL = tree.NewCreateSubscription( - true, // isDatabase - DbName, - "", - FromUri, - SubscriptionAccountName, - PubName, - SyncInterval, - ) - } - yyVAL.union = yyLOCAL - case 1497: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.SubscriptionOption -//line mysql_sql.y:10430 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1498: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.SubscriptionOption -//line mysql_sql.y:10434 - { - var From = tree.Identifier(yyDollar[2].str) - var Publication = tree.Identifier(yyDollar[4].cstrUnion().Compare()) - yyLOCAL = tree.NewSubscriptionOption(From, Publication) - } - yyVAL.union = yyLOCAL - case 1501: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:10445 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1502: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:10449 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1503: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:10453 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1504: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:10458 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1505: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:10462 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1506: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []tree.CreateOption -//line mysql_sql.y:10467 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1507: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.CreateOption -//line mysql_sql.y:10471 - { - yyLOCAL = yyDollar[1].createOptionsUnion() - } - yyVAL.union = yyLOCAL - case 1508: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.CreateOption -//line mysql_sql.y:10477 - { - yyLOCAL = []tree.CreateOption{yyDollar[1].createOptionUnion()} - } - yyVAL.union = yyLOCAL - case 1509: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []tree.CreateOption -//line mysql_sql.y:10481 - { - yyLOCAL = append(yyDollar[1].createOptionsUnion(), yyDollar[2].createOptionUnion()) - } - yyVAL.union = yyLOCAL - case 1510: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.CreateOption -//line mysql_sql.y:10487 - { - var IsDefault = yyDollar[1].defaultOptionalUnion() - var Charset = yyDollar[4].str - yyLOCAL = tree.NewCreateOptionCharset( - IsDefault, - Charset, - ) - } - yyVAL.union = yyLOCAL - case 1511: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.CreateOption -//line mysql_sql.y:10496 - { - var IsDefault = yyDollar[1].defaultOptionalUnion() - var Collate = yyDollar[4].str - yyLOCAL = tree.NewCreateOptionCollate( - IsDefault, - Collate, - ) - } - yyVAL.union = yyLOCAL - case 1512: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.CreateOption -//line mysql_sql.y:10505 - { - var Encrypt = yyDollar[4].str - yyLOCAL = tree.NewCreateOptionEncryption(Encrypt) - } - yyVAL.union = yyLOCAL - case 1513: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:10511 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1514: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:10515 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1515: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10521 - { - var taskID uint64 - switch v := yyDollar[4].item.(type) { - case uint64: - taskID = v - case int64: - taskID = uint64(v) - default: - yylex.Error("parse integral fail") - goto ret1 - } - yyLOCAL = &tree.PauseDaemonTask{ - TaskID: taskID, - } - } - yyVAL.union = yyLOCAL - case 1516: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10539 - { - var taskID uint64 - switch v := yyDollar[4].item.(type) { - case uint64: - taskID = v - case int64: - taskID = uint64(v) - default: - yylex.Error("parse integral fail") - goto ret1 - } - yyLOCAL = &tree.CancelDaemonTask{ - TaskID: taskID, - } - } - yyVAL.union = yyLOCAL - case 1517: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10557 - { - var taskID uint64 - switch v := yyDollar[4].item.(type) { - case uint64: - taskID = v - case int64: - taskID = uint64(v) - default: - yylex.Error("parse integral fail") - goto ret1 - } - yyLOCAL = &tree.ResumeDaemonTask{ - TaskID: taskID, - } - } - yyVAL.union = yyLOCAL - case 1518: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:10574 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1519: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:10578 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1520: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10584 - { - t := tree.NewDataBranchCreateTable() - t.CreateTable.Table = *yyDollar[5].tableNameUnion() - t.CreateTable.LikeTableName = *yyDollar[7].tableNameUnion() - t.CreateTable.IsAsLike = true - t.SrcTable = *yyDollar[7].tableNameUnion() - t.ToAccountOpt = yyDollar[8].toAccountOptUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1521: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10594 - { - t := tree.NewDataBranchCreateDatabase() - t.DstDatabase = tree.Identifier(yyDollar[5].str) - t.SrcDatabase = tree.Identifier(yyDollar[7].str) - t.AtTsExpr = yyDollar[8].atTimeStampUnion() - t.ToAccountOpt = yyDollar[9].toAccountOptUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1522: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10603 - { - t := tree.NewDataBranchDeleteTable() - t.TableName = *yyDollar[5].tableNameUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1523: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10609 - { - t := tree.NewDataBranchDeleteDatabase() - t.DatabaseName = tree.Identifier(yyDollar[5].str) - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1524: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10615 - { - t := tree.NewDataBranchDiff() - t.TargetTable = *yyDollar[4].tableNameUnion() - t.BaseTable = *yyDollar[6].tableNameUnion() - t.Columns = yyDollar[7].identifierListUnion() - t.OutputOpt = yyDollar[8].diffOutputOptUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1525: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10624 - { - t := tree.NewDataBranchMerge() - t.SrcTable = *yyDollar[4].tableNameUnion() - t.DstTable = *yyDollar[6].tableNameUnion() - t.ConflictOpt = yyDollar[7].conflictOptUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1526: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10632 - { - t := tree.NewDataBranchPick() - t.SrcTable = *yyDollar[4].tableNameUnion() - t.DstTable = *yyDollar[6].tableNameUnion() - t.Keys = yyDollar[7].pickKeysUnion() - t.ConflictOpt = yyDollar[8].conflictOptUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1527: - yyDollar = yyS[yypt-12 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10641 - { - t := tree.NewDataBranchPick() - t.SrcTable = *yyDollar[4].tableNameUnion() - t.DstTable = *yyDollar[6].tableNameUnion() - t.BetweenFrom = yylex.(*Lexer).GetDbOrTblName(yyDollar[9].cstrUnion().Origin()) - t.BetweenTo = yylex.(*Lexer).GetDbOrTblName(yyDollar[11].cstrUnion().Origin()) - t.ConflictOpt = yyDollar[12].conflictOptUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1528: - yyDollar = yyS[yypt-12 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10651 - { - t := tree.NewDataBranchPick() - t.SrcTable = *yyDollar[4].tableNameUnion() - t.DstTable = *yyDollar[6].tableNameUnion() - t.BetweenFrom = yyDollar[9].str - t.BetweenTo = yyDollar[11].str - t.ConflictOpt = yyDollar[12].conflictOptUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1529: - yyDollar = yyS[yypt-13 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10661 - { - t := tree.NewDataBranchPick() - t.SrcTable = *yyDollar[4].tableNameUnion() - t.DstTable = *yyDollar[6].tableNameUnion() - t.BetweenFrom = yylex.(*Lexer).GetDbOrTblName(yyDollar[9].cstrUnion().Origin()) - t.BetweenTo = yylex.(*Lexer).GetDbOrTblName(yyDollar[11].cstrUnion().Origin()) - t.Keys = yyDollar[12].pickKeysUnion() - t.ConflictOpt = yyDollar[13].conflictOptUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1530: - yyDollar = yyS[yypt-13 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10672 - { - t := tree.NewDataBranchPick() - t.SrcTable = *yyDollar[4].tableNameUnion() - t.DstTable = *yyDollar[6].tableNameUnion() - t.BetweenFrom = yyDollar[9].str - t.BetweenTo = yyDollar[11].str - t.Keys = yyDollar[12].pickKeysUnion() - t.ConflictOpt = yyDollar[13].conflictOptUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1531: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:10684 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1532: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.IdentifierList -//line mysql_sql.y:10688 - { - yyLOCAL = yyDollar[3].identifierListUnion() - } - yyVAL.union = yyLOCAL - case 1533: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.DiffOutputOpt -//line mysql_sql.y:10693 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1534: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.DiffOutputOpt -//line mysql_sql.y:10697 - { - yyLOCAL = &tree.DiffOutputOpt{ - As: *yyDollar[3].tableNameUnion(), - } - } - yyVAL.union = yyLOCAL - case 1535: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.DiffOutputOpt -//line mysql_sql.y:10703 - { - yyLOCAL = &tree.DiffOutputOpt{ - DirPath: yyDollar[3].str, - } - } - yyVAL.union = yyLOCAL - case 1536: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.DiffOutputOpt -//line mysql_sql.y:10709 - { - x, errStr := util.GetInt64(yyDollar[3].item) - if errStr != "" { - yylex.Error("OUTPUT LIMIT is out of range") - goto ret1 - } - yyLOCAL = &tree.DiffOutputOpt{ - Limit: &x, - } - } - yyVAL.union = yyLOCAL - case 1537: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.DiffOutputOpt -//line mysql_sql.y:10716 - { - yyLOCAL = &tree.DiffOutputOpt{ - Count: true, - } - } - yyVAL.union = yyLOCAL - case 1538: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.DiffOutputOpt -//line mysql_sql.y:10722 - { - yyLOCAL = &tree.DiffOutputOpt{ - Summary: true, - } - } - yyVAL.union = yyLOCAL - case 1539: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.ConflictOpt -//line mysql_sql.y:10730 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1540: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.ConflictOpt -//line mysql_sql.y:10734 - { - yyLOCAL = &tree.ConflictOpt{ - Opt: tree.CONFLICT_FAIL, - } - } - yyVAL.union = yyLOCAL - case 1541: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.ConflictOpt -//line mysql_sql.y:10740 - { - yyLOCAL = &tree.ConflictOpt{ - Opt: tree.CONFLICT_SKIP, - } - } - yyVAL.union = yyLOCAL - case 1542: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.ConflictOpt -//line mysql_sql.y:10746 - { - yyLOCAL = &tree.ConflictOpt{ - Opt: tree.CONFLICT_ACCEPT, - } - } - yyVAL.union = yyLOCAL - case 1543: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.PickKeys -//line mysql_sql.y:10754 - { - yyLOCAL = &tree.PickKeys{ - Type: tree.PickKeysValues, - KeyExprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 1544: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.PickKeys -//line mysql_sql.y:10761 - { - yyLOCAL = &tree.PickKeys{ - Type: tree.PickKeysSubquery, - Select: yyDollar[3].selectUnion(), - } - } - yyVAL.union = yyLOCAL - case 1545: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.ToAccountOpt -//line mysql_sql.y:10770 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1546: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.ToAccountOpt -//line mysql_sql.y:10774 - { - yyLOCAL = &tree.ToAccountOpt{ - AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - } - } - yyVAL.union = yyLOCAL - case 1547: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:10782 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1548: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:10786 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1549: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:10791 - { - yyVAL.str = "" - } - case 1550: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:10792 - { - yyVAL.str = "ignore" - } - case 1551: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:10793 - { - yyVAL.str = "replace" - } - case 1552: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:10796 - { - yyVAL.str = "ignore" - } - case 1553: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:10797 - { - yyVAL.str = "replace" - } - case 1554: - yyDollar = yyS[yypt-11 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10801 - { - t := tree.NewCreateTable() - t.Temporary = yyDollar[2].boolValUnion() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.Defs = yyDollar[7].tableDefsUnion() - t.Options = yyDollar[9].tableOptionsUnion() - t.PartitionOption = yyDollar[10].partitionOptionUnion() - t.ClusterByOption = yyDollar[11].clusterByOptionUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1555: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10813 - { - t := tree.NewCreateTable() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.Defs = yyDollar[7].tableDefsUnion() - t.Param = yyDollar[9].loadParamUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1556: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10822 - { - t := tree.NewCreateTable() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.Defs = yyDollar[7].tableDefsUnion() - t.IcebergParam = yyDollar[9].icebergTableParamUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1557: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10831 - { - t := tree.NewCreateTable() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.Defs = yyDollar[7].tableDefsUnion() - t.MongoDBParam = yyDollar[9].mongodbTableParamUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1558: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10840 - { - t := tree.NewCreateTable() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.Defs = yyDollar[7].tableDefsUnion() - t.DataStreamParam = yyDollar[9].datastreamTableParamUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1559: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10849 - { - t := tree.NewCreateTable() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.Defs = yyDollar[7].tableDefsUnion() - t.ForeignParam = yyDollar[9].foreignTableParamUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1560: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10858 - { - t := tree.NewCreateTable() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.Defs = yyDollar[7].tableDefsUnion() - t.KafkaParam = yyDollar[9].kafkaTableParamUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1561: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10867 - { - t := tree.NewCreateTable() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.IcebergParam = yyDollar[6].icebergTableParamUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1562: - yyDollar = yyS[yypt-11 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10875 - { - t := tree.NewCreateTable() - t.IsClusterTable = true - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.Defs = yyDollar[7].tableDefsUnion() - t.Options = yyDollar[9].tableOptionsUnion() - t.PartitionOption = yyDollar[10].partitionOptionUnion() - t.ClusterByOption = yyDollar[11].clusterByOptionUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1563: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10887 - { - if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[6].selectUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - t := tree.NewCreateTable() - t.IsAsSelect = true - t.Temporary = yyDollar[2].boolValUnion() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.AsSource = yyDollar[6].selectUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1564: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10901 - { - if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[9].selectUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - t := tree.NewCreateTable() - t.IsAsSelect = true - t.Temporary = yyDollar[2].boolValUnion() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.Defs = yyDollar[7].tableDefsUnion() - t.AsSource = yyDollar[9].selectUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1565: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10916 - { - if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[7].selectUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - t := tree.NewCreateTable() - t.IsAsSelect = true - t.Temporary = yyDollar[2].boolValUnion() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.CTASConflict = yyDollar[6].str - t.AsSource = yyDollar[7].selectUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1566: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10921 - { - if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[10].selectUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - t := tree.NewCreateTable() - t.IsAsSelect = true - t.Temporary = yyDollar[2].boolValUnion() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.Defs = yyDollar[7].tableDefsUnion() - t.CTASConflict = yyDollar[9].str - t.AsSource = yyDollar[10].selectUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1567: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10926 - { - if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[8].selectUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - t := tree.NewCreateTable() - t.IsAsSelect = true - t.Temporary = yyDollar[2].boolValUnion() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.CTASConflict = yyDollar[6].str - t.AsSource = yyDollar[8].selectUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1568: - yyDollar = yyS[yypt-11 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10931 - { - if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[11].selectUnion()); intoErr != "" { - yylex.Error(intoErr) - goto ret1 - } - t := tree.NewCreateTable() - t.IsAsSelect = true - t.Temporary = yyDollar[2].boolValUnion() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.Defs = yyDollar[7].tableDefsUnion() - t.CTASConflict = yyDollar[9].str - t.AsSource = yyDollar[11].selectUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1569: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10936 - { - t := tree.NewCreateTable() - t.IsAsLike = true - t.Temporary = yyDollar[2].boolValUnion() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.LikeTableName = *yyDollar[7].tableNameUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1570: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10946 - { - t := tree.NewCreateTable() - t.Temporary = yyDollar[2].boolValUnion() - t.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.Table = *yyDollar[5].tableNameUnion() - t.SubscriptionOption = yyDollar[6].subscriptionOptionUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1571: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10955 - { - t := tree.NewCloneTable() - t.CreateTable.Temporary = yyDollar[2].boolValUnion() - t.CreateTable.IfNotExists = yyDollar[4].ifNotExistsUnion() - t.CreateTable.Table = *yyDollar[5].tableNameUnion() - t.CreateTable.LikeTableName = *yyDollar[7].tableNameUnion() - t.CreateTable.IsAsLike = true - t.SrcTable = *yyDollar[7].tableNameUnion() - t.CopyGrants = yyDollar[8].boolValUnion() - t.ToAccountOpt = yyDollar[9].toAccountOptUnion() - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1572: - yyDollar = yyS[yypt-11 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:10968 - { - var TableName = yyDollar[5].tableNameUnion() - var FromUri = yyDollar[7].str - var SubscriptionAccountName = yyDollar[8].cstrUnion().Compare() - var PubName = tree.Identifier(yyDollar[10].cstrUnion().Compare()) - var SyncInterval = yyDollar[11].int64ValUnion() - var TableNameStr = string(TableName.ObjectName) - var DbName = tree.Identifier("") - // Extract database name from table name if explicitly specified - if TableName.ExplicitSchema { - DbName = TableName.SchemaName - } - yyLOCAL = tree.NewCreateSubscription( - false, // isDatabase - DbName, - TableNameStr, - FromUri, - SubscriptionAccountName, - PubName, - SyncInterval, - ) - } - yyVAL.union = yyLOCAL - case 1573: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.ExternParam -//line mysql_sql.y:10993 - { - yyLOCAL = yyDollar[1].loadParamUnion() - yyLOCAL.Tail = yyDollar[2].tailParamUnion() - } - yyVAL.union = yyLOCAL - case 1574: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.ExternParam -//line mysql_sql.y:11000 - { - yyLOCAL = &tree.ExternParam{ - ExParamConst: tree.ExParamConst{ - Filepath: yyDollar[2].str, - CompressType: tree.AUTO, - Format: tree.CSV, - }, - } - } - yyVAL.union = yyLOCAL - case 1575: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL *tree.ExternParam -//line mysql_sql.y:11010 - { - yyLOCAL = &tree.ExternParam{ - ExParamConst: tree.ExParamConst{ - ScanType: tree.INLINE, - Format: strings.ToLower(yyDollar[4].str), - Data: yyDollar[8].str, - }, - ExParam: tree.ExParam{ - JsonData: yyDollar[9].str, - }, - } - } - yyVAL.union = yyLOCAL - case 1576: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.ExternParam -//line mysql_sql.y:11023 - { - yyLOCAL = &tree.ExternParam{ - ExParamConst: tree.ExParamConst{ - Option: yyDollar[3].strsUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 1577: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.ExternParam -//line mysql_sql.y:11031 - { - yyLOCAL = &tree.ExternParam{ - ExParamConst: tree.ExParamConst{ - ScanType: tree.S3, - Option: yyDollar[4].strsUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 1578: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.ExternParam -//line mysql_sql.y:11040 - { - yyLOCAL = &tree.ExternParam{ - ExParamConst: tree.ExParamConst{ - StageName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), - }, - } - } - yyVAL.union = yyLOCAL - case 1579: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:11049 - { - yyVAL.str = "" - } - case 1580: - yyDollar = yyS[yypt-4 : yypt+1] -//line mysql_sql.y:11053 - { - yyVAL.str = yyDollar[4].str - } - case 1581: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:11059 - { - yyLOCAL = yyDollar[1].strsUnion() - } - yyVAL.union = yyLOCAL - case 1582: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:11063 - { - yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].strsUnion()...) - } - yyVAL.union = yyLOCAL - case 1583: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:11068 - { - yyLOCAL = []string{} - } - yyVAL.union = yyLOCAL - case 1584: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:11072 - { - yyLOCAL = append(yyLOCAL, yyDollar[1].str) - yyLOCAL = append(yyLOCAL, yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1585: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.TailParameter -//line mysql_sql.y:11079 - { - yyLOCAL = &tree.TailParameter{ - Charset: yyDollar[1].str, - Fields: yyDollar[2].fieldsUnion(), - Lines: yyDollar[3].linesUnion(), - IgnoredLines: uint64(yyDollar[4].int64ValUnion()), - ColumnList: yyDollar[5].loadColumnsUnion(), - Assignments: yyDollar[6].updateExprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 1586: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:11091 - { - yyVAL.str = "" - } - case 1587: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:11095 - { - yyVAL.str = yyDollar[2].str - } - case 1588: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:11101 - { - var Name = yyDollar[4].tableNameUnion() - var Type = yyDollar[5].columnTypeUnion() - var IfNotExists = yyDollar[3].ifNotExistsUnion() - var IncrementBy = yyDollar[6].incrementByOptionUnion() - var MinValue = yyDollar[7].minValueOptionUnion() - var MaxValue = yyDollar[8].maxValueOptionUnion() - var StartWith = yyDollar[9].startWithOptionUnion() - var Cycle = yyDollar[10].boolValUnion() - yyLOCAL = tree.NewCreateSequence( - Name, - Type, - IfNotExists, - IncrementBy, - MinValue, - MaxValue, - StartWith, - Cycle, - ) - } - yyVAL.union = yyLOCAL - case 1589: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:11122 - { - locale := "" - fstr := "bigint" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: fstr, - Width: 64, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_LONGLONG), - }, - } - } - yyVAL.union = yyLOCAL - case 1590: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:11136 - { - yyLOCAL = yyDollar[2].columnTypeUnion() - } - yyVAL.union = yyLOCAL - case 1591: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.TypeOption -//line mysql_sql.y:11140 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1592: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.TypeOption -//line mysql_sql.y:11144 - { - yyLOCAL = &tree.TypeOption{ - Type: yyDollar[2].columnTypeUnion(), - } - } - yyVAL.union = yyLOCAL - case 1593: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.IncrementByOption -//line mysql_sql.y:11150 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1594: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IncrementByOption -//line mysql_sql.y:11154 - { - yyLOCAL = &tree.IncrementByOption{ - Minus: false, - Num: yyDollar[3].item, - } - } - yyVAL.union = yyLOCAL - case 1595: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.IncrementByOption -//line mysql_sql.y:11161 - { - yyLOCAL = &tree.IncrementByOption{ - Minus: false, - Num: yyDollar[2].item, - } - } - yyVAL.union = yyLOCAL - case 1596: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.IncrementByOption -//line mysql_sql.y:11168 - { - yyLOCAL = &tree.IncrementByOption{ - Minus: true, - Num: yyDollar[4].item, - } - } - yyVAL.union = yyLOCAL - case 1597: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IncrementByOption -//line mysql_sql.y:11175 - { - yyLOCAL = &tree.IncrementByOption{ - Minus: true, - Num: yyDollar[3].item, - } - } - yyVAL.union = yyLOCAL - case 1598: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:11182 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1599: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:11186 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1600: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:11190 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1601: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.MinValueOption -//line mysql_sql.y:11194 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1602: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.MinValueOption -//line mysql_sql.y:11198 - { - yyLOCAL = &tree.MinValueOption{ - Minus: false, - Num: yyDollar[2].item, - } - } - yyVAL.union = yyLOCAL - case 1603: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.MinValueOption -//line mysql_sql.y:11205 - { - yyLOCAL = &tree.MinValueOption{ - Minus: true, - Num: yyDollar[3].item, - } - } - yyVAL.union = yyLOCAL - case 1604: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.MaxValueOption -//line mysql_sql.y:11212 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1605: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.MaxValueOption -//line mysql_sql.y:11216 - { - yyLOCAL = &tree.MaxValueOption{ - Minus: false, - Num: yyDollar[2].item, - } - } - yyVAL.union = yyLOCAL - case 1606: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.MaxValueOption -//line mysql_sql.y:11223 - { - yyLOCAL = &tree.MaxValueOption{ - Minus: true, - Num: yyDollar[3].item, - } - } - yyVAL.union = yyLOCAL - case 1607: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.CycleOption -//line mysql_sql.y:11230 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1608: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.CycleOption -//line mysql_sql.y:11234 - { - yyLOCAL = &tree.CycleOption{ - Cycle: false, - } - } - yyVAL.union = yyLOCAL - case 1609: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CycleOption -//line mysql_sql.y:11240 - { - yyLOCAL = &tree.CycleOption{ - Cycle: true, - } - } - yyVAL.union = yyLOCAL - case 1610: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.StartWithOption -//line mysql_sql.y:11246 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1611: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.StartWithOption -//line mysql_sql.y:11250 - { - yyLOCAL = &tree.StartWithOption{ - Minus: false, - Num: yyDollar[3].item, - } - } - yyVAL.union = yyLOCAL - case 1612: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.StartWithOption -//line mysql_sql.y:11257 - { - yyLOCAL = &tree.StartWithOption{ - Minus: false, - Num: yyDollar[2].item, - } - } - yyVAL.union = yyLOCAL - case 1613: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.StartWithOption -//line mysql_sql.y:11264 - { - yyLOCAL = &tree.StartWithOption{ - Minus: true, - Num: yyDollar[4].item, - } - } - yyVAL.union = yyLOCAL - case 1614: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.StartWithOption -//line mysql_sql.y:11271 - { - yyLOCAL = &tree.StartWithOption{ - Minus: true, - Num: yyDollar[3].item, - } - } - yyVAL.union = yyLOCAL - case 1615: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:11278 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1616: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:11282 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1617: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:11287 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1618: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:11291 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1619: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:11295 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1620: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.PartitionOption -//line mysql_sql.y:11300 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1621: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.PartitionOption -//line mysql_sql.y:11304 - { - yyDollar[3].partitionByUnion().Num = uint64(yyDollar[4].int64ValUnion()) - var PartBy = yyDollar[3].partitionByUnion() - var SubPartBy = yyDollar[5].partitionByUnion() - var Partitions = yyDollar[6].partitionsUnion() - yyLOCAL = tree.NewPartitionOption( - PartBy, - SubPartBy, - Partitions, - ) - } - yyVAL.union = yyLOCAL - case 1622: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.ClusterByOption -//line mysql_sql.y:11317 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1623: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.ClusterByOption -//line mysql_sql.y:11321 - { - var ColumnList = []*tree.UnresolvedName{yyDollar[3].unresolvedNameUnion()} - yyLOCAL = tree.NewClusterByOption( - ColumnList, - ) - - } - yyVAL.union = yyLOCAL - case 1624: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.ClusterByOption -//line mysql_sql.y:11329 - { - var ColumnList = yyDollar[4].unresolveNamesUnion() - yyLOCAL = tree.NewClusterByOption( - ColumnList, - ) - } - yyVAL.union = yyLOCAL - case 1625: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.PartitionBy -//line mysql_sql.y:11337 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1626: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.PartitionBy -//line mysql_sql.y:11341 - { - var IsSubPartition = true - var PType = yyDollar[3].partitionByUnion().PType - var Num = uint64(yyDollar[4].int64ValUnion()) - yyDollar[3].partitionByUnion().PType = nil - yyDollar[3].partitionByUnion().Free() - yyLOCAL = tree.NewPartitionBy2( - IsSubPartition, - PType, - Num, - ) - } - yyVAL.union = yyLOCAL - case 1627: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []*tree.Partition -//line mysql_sql.y:11355 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1628: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.Partition -//line mysql_sql.y:11359 - { - yyLOCAL = yyDollar[2].partitionsUnion() - } - yyVAL.union = yyLOCAL - case 1629: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.Partition -//line mysql_sql.y:11365 - { - yyLOCAL = []*tree.Partition{yyDollar[1].partitionUnion()} - } - yyVAL.union = yyLOCAL - case 1630: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.Partition -//line mysql_sql.y:11369 - { - yyLOCAL = append(yyDollar[1].partitionsUnion(), yyDollar[3].partitionUnion()) - } - yyVAL.union = yyLOCAL - case 1631: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.Partition -//line mysql_sql.y:11375 - { - var Name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) - var Values = yyDollar[3].valuesUnion() - var Options []tree.TableOption - var Subs = yyDollar[4].subPartitionsUnion() - yyLOCAL = tree.NewPartition( - Name, - Values, - Options, - Subs, - ) - } - yyVAL.union = yyLOCAL - case 1632: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.Partition -//line mysql_sql.y:11388 - { - var Name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) - var Values = yyDollar[3].valuesUnion() - var Options = yyDollar[4].tableOptionsUnion() - var Subs = yyDollar[5].subPartitionsUnion() - yyLOCAL = tree.NewPartition( - Name, - Values, - Options, - Subs, - ) - } - yyVAL.union = yyLOCAL - case 1633: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []*tree.SubPartition -//line mysql_sql.y:11402 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1634: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.SubPartition -//line mysql_sql.y:11406 - { - yyLOCAL = yyDollar[2].subPartitionsUnion() - } - yyVAL.union = yyLOCAL - case 1635: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.SubPartition -//line mysql_sql.y:11412 - { - yyLOCAL = []*tree.SubPartition{yyDollar[1].subPartitionUnion()} - } - yyVAL.union = yyLOCAL - case 1636: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.SubPartition -//line mysql_sql.y:11416 - { - yyLOCAL = append(yyDollar[1].subPartitionsUnion(), yyDollar[3].subPartitionUnion()) - } - yyVAL.union = yyLOCAL - case 1637: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.SubPartition -//line mysql_sql.y:11422 - { - var Name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) - var Options []tree.TableOption - yyLOCAL = tree.NewSubPartition( - Name, - Options, - ) - } - yyVAL.union = yyLOCAL - case 1638: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.SubPartition -//line mysql_sql.y:11431 - { - var Name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) - var Options = yyDollar[3].tableOptionsUnion() - yyLOCAL = tree.NewSubPartition( - Name, - Options, - ) - } - yyVAL.union = yyLOCAL - case 1639: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.TableOption -//line mysql_sql.y:11442 - { - yyLOCAL = []tree.TableOption{yyDollar[1].tableOptionUnion()} - } - yyVAL.union = yyLOCAL - case 1640: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []tree.TableOption -//line mysql_sql.y:11446 - { - yyLOCAL = append(yyDollar[1].tableOptionsUnion(), yyDollar[2].tableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 1641: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11452 - { - if option, ok := yyDollar[1].tableOptionUnion().(*tree.TableOptionAutoIDCache); ok { - option.Free() - yylex.Error("AUTO_ID_CACHE is a table option, not a partition or subpartition option") - goto ret1 - } - yyLOCAL = yyDollar[1].tableOptionUnion() - } - yyVAL.union = yyLOCAL - case 1642: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Values -//line mysql_sql.y:11462 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1643: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Values -//line mysql_sql.y:11466 - { - expr := tree.NewMaxValue() - var valueList = tree.Exprs{expr} - yyLOCAL = tree.NewValuesLessThan(valueList) - } - yyVAL.union = yyLOCAL - case 1644: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Values -//line mysql_sql.y:11472 - { - var valueList = yyDollar[5].exprsUnion() - yyLOCAL = tree.NewValuesLessThan(valueList) - } - yyVAL.union = yyLOCAL - case 1645: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Values -//line mysql_sql.y:11477 - { - var valueList = yyDollar[4].exprsUnion() - yyLOCAL = tree.NewValuesIn( - valueList, - ) - } - yyVAL.union = yyLOCAL - case 1646: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:11485 - { - yyLOCAL = 0 - } - yyVAL.union = yyLOCAL - case 1647: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:11489 - { - res, ok := signedIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - if res == 0 { - yylex.Error("partitions can not be 0") - goto ret1 - } - yyLOCAL = res - } - yyVAL.union = yyLOCAL - case 1648: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:11500 - { - yyLOCAL = 0 - } - yyVAL.union = yyLOCAL - case 1649: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:11504 - { - res, ok := signedIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - if res == 0 { - yylex.Error("partitions can not be 0") - goto ret1 - } - yyLOCAL = res - } - yyVAL.union = yyLOCAL - case 1650: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.PartitionBy -//line mysql_sql.y:11516 - { - rangeTyp := tree.NewRangeType() - rangeTyp.Expr = yyDollar[3].exprUnion() - yyLOCAL = tree.NewPartitionBy( - rangeTyp, - ) - } - yyVAL.union = yyLOCAL - case 1651: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.PartitionBy -//line mysql_sql.y:11524 - { - rangeTyp := tree.NewRangeType() - rangeTyp.ColumnList = yyDollar[4].unresolveNamesUnion() - yyLOCAL = tree.NewPartitionBy( - rangeTyp, - ) - } - yyVAL.union = yyLOCAL - case 1652: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.PartitionBy -//line mysql_sql.y:11532 - { - listTyp := tree.NewListType() - listTyp.Expr = yyDollar[3].exprUnion() - yyLOCAL = tree.NewPartitionBy( - listTyp, - ) - } - yyVAL.union = yyLOCAL - case 1653: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.PartitionBy -//line mysql_sql.y:11540 - { - listTyp := tree.NewListType() - listTyp.ColumnList = yyDollar[4].unresolveNamesUnion() - yyLOCAL = tree.NewPartitionBy( - listTyp, - ) - } - yyVAL.union = yyLOCAL - case 1655: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.PartitionBy -//line mysql_sql.y:11551 - { - keyTyp := tree.NewKeyType() - keyTyp.Linear = yyDollar[1].boolValUnion() - keyTyp.Algorithm = yyDollar[3].int64ValUnion() - yyLOCAL = tree.NewPartitionBy( - keyTyp, - ) - } - yyVAL.union = yyLOCAL - case 1656: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.PartitionBy -//line mysql_sql.y:11560 - { - keyTyp := tree.NewKeyType() - keyTyp.Linear = yyDollar[1].boolValUnion() - keyTyp.Algorithm = yyDollar[3].int64ValUnion() - keyTyp.ColumnList = yyDollar[5].unresolveNamesUnion() - yyLOCAL = tree.NewPartitionBy( - keyTyp, - ) - } - yyVAL.union = yyLOCAL - case 1657: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.PartitionBy -//line mysql_sql.y:11570 - { - Linear := yyDollar[1].boolValUnion() - Expr := yyDollar[4].exprUnion() - hashTyp := tree.NewHashType(Linear, Expr) - yyLOCAL = tree.NewPartitionBy( - hashTyp, - ) - } - yyVAL.union = yyLOCAL - case 1658: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:11580 - { - yyLOCAL = 2 - } - yyVAL.union = yyLOCAL - case 1659: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:11584 - { - value, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - yyLOCAL = value - } - yyVAL.union = yyLOCAL - case 1660: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:11591 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1661: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:11595 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1662: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.IcebergTableParam -//line mysql_sql.y:11601 - { - yyLOCAL = tree.NewIcebergTableParam(yyDollar[4].icebergOptionsUnion()) - } - yyVAL.union = yyLOCAL - case 1663: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.IcebergOptions -//line mysql_sql.y:11606 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1664: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.IcebergOptions -//line mysql_sql.y:11610 - { - yyLOCAL = yyDollar[3].icebergOptionsUnion() - } - yyVAL.union = yyLOCAL - case 1665: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.IcebergOptions -//line mysql_sql.y:11616 - { - yyLOCAL = tree.IcebergOptions{yyDollar[1].icebergOptionUnion()} - } - yyVAL.union = yyLOCAL - case 1666: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.IcebergOptions -//line mysql_sql.y:11620 - { - yyLOCAL = append(yyDollar[1].icebergOptionsUnion(), yyDollar[3].icebergOptionUnion()) - } - yyVAL.union = yyLOCAL - case 1667: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IcebergOption -//line mysql_sql.y:11626 - { - yyLOCAL = tree.NewIcebergOption(tree.Identifier(yyDollar[1].str), yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1668: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11632 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1669: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11636 - { - yyVAL.str = yyDollar[1].str - } - case 1670: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11642 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1671: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11646 - { - yyVAL.str = yyDollar[1].str - } - case 1672: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.MongoDBTableParam -//line mysql_sql.y:11652 - { - yyLOCAL = tree.NewMongoDBTableParam(yyDollar[4].mongodbOptionsUnion()) - } - yyVAL.union = yyLOCAL - case 1673: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.MongoDBOptions -//line mysql_sql.y:11657 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1674: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.MongoDBOptions -//line mysql_sql.y:11661 - { - yyLOCAL = yyDollar[3].mongodbOptionsUnion() - } - yyVAL.union = yyLOCAL - case 1675: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.MongoDBOptions -//line mysql_sql.y:11667 - { - yyLOCAL = tree.MongoDBOptions{yyDollar[1].mongodbOptionUnion()} - } - yyVAL.union = yyLOCAL - case 1676: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.MongoDBOptions -//line mysql_sql.y:11671 - { - yyLOCAL = append(yyDollar[1].mongodbOptionsUnion(), yyDollar[3].mongodbOptionUnion()) - } - yyVAL.union = yyLOCAL - case 1677: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.MongoDBOption -//line mysql_sql.y:11677 - { - yyLOCAL = tree.NewMongoDBOption(tree.Identifier(yyDollar[1].str), yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1678: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11683 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1679: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11687 - { - yyVAL.str = yyDollar[1].str - } - case 1680: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11693 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1681: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11697 - { - yyVAL.str = yyDollar[1].str - } - case 1682: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.DataStreamTableParam -//line mysql_sql.y:11703 - { - yyLOCAL = tree.NewDataStreamTableParam(yyDollar[4].datastreamOptionsUnion()) - } - yyVAL.union = yyLOCAL - case 1683: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.DataStreamOptions -//line mysql_sql.y:11708 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1684: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.DataStreamOptions -//line mysql_sql.y:11712 - { - yyLOCAL = yyDollar[3].datastreamOptionsUnion() - } - yyVAL.union = yyLOCAL - case 1685: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.DataStreamOptions -//line mysql_sql.y:11718 - { - yyLOCAL = tree.DataStreamOptions{yyDollar[1].datastreamOptionUnion()} - } - yyVAL.union = yyLOCAL - case 1686: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.DataStreamOptions -//line mysql_sql.y:11722 - { - yyLOCAL = append(yyDollar[1].datastreamOptionsUnion(), yyDollar[3].datastreamOptionUnion()) - } - yyVAL.union = yyLOCAL - case 1687: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.DataStreamOption -//line mysql_sql.y:11728 - { - yyLOCAL = tree.NewDataStreamOption(tree.Identifier(yyDollar[1].str), yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1688: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.ForeignTableParam -//line mysql_sql.y:11734 - { - yyLOCAL = tree.NewForeignTableParam(yyDollar[3].str, yyDollar[4].foreignTableOptionsUnion()) - } - yyVAL.union = yyLOCAL - case 1689: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.KafkaTableParam -//line mysql_sql.y:11740 - { - yyLOCAL = tree.NewKafkaTableParam(yyDollar[4].kafkaTableOptionsUnion()) - } - yyVAL.union = yyLOCAL - case 1690: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.KafkaTableOptions -//line mysql_sql.y:11745 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1691: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.KafkaTableOptions -//line mysql_sql.y:11749 - { - yyLOCAL = yyDollar[3].kafkaTableOptionsUnion() - } - yyVAL.union = yyLOCAL - case 1692: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.KafkaTableOptions -//line mysql_sql.y:11755 - { - yyLOCAL = tree.KafkaTableOptions{yyDollar[1].kafkaTableOptionUnion()} - } - yyVAL.union = yyLOCAL - case 1693: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.KafkaTableOptions -//line mysql_sql.y:11759 - { - yyLOCAL = append(yyDollar[1].kafkaTableOptionsUnion(), yyDollar[3].kafkaTableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 1694: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.KafkaTableOption -//line mysql_sql.y:11765 - { - yyLOCAL = tree.NewKafkaTableOption(tree.Identifier(yyDollar[1].str), yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1695: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11771 - { - yyVAL.str = "esql" - } - case 1696: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11775 - { - yyVAL.str = "sql" - } - case 1697: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.ForeignTableOptions -//line mysql_sql.y:11780 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1698: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.ForeignTableOptions -//line mysql_sql.y:11784 - { - yyLOCAL = yyDollar[3].foreignTableOptionsUnion() - } - yyVAL.union = yyLOCAL - case 1699: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ForeignTableOptions -//line mysql_sql.y:11790 - { - yyLOCAL = tree.ForeignTableOptions{yyDollar[1].foreignTableOptionUnion()} - } - yyVAL.union = yyLOCAL - case 1700: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.ForeignTableOptions -//line mysql_sql.y:11794 - { - yyLOCAL = append(yyDollar[1].foreignTableOptionsUnion(), yyDollar[3].foreignTableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 1701: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.ForeignTableOption -//line mysql_sql.y:11800 - { - yyLOCAL = tree.NewForeignTableOption(tree.Identifier(yyDollar[1].str), yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1702: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11806 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1703: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11810 - { - yyVAL.str = yyDollar[1].str - } - case 1704: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11816 - { - yyVAL.str = yyDollar[1].cstrUnion().Compare() - } - case 1705: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:11820 - { - yyVAL.str = yyDollar[1].str - } - case 1706: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []tree.TableOption -//line mysql_sql.y:11825 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1707: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.TableOption -//line mysql_sql.y:11829 - { - yyLOCAL = yyDollar[1].tableOptionsUnion() - } - yyVAL.union = yyLOCAL - case 1708: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.TableOption -//line mysql_sql.y:11835 - { - yyLOCAL = []tree.TableOption{yyDollar[1].tableOptionUnion()} - } - yyVAL.union = yyLOCAL - case 1709: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []tree.TableOption -//line mysql_sql.y:11839 - { - yyLOCAL = append(yyDollar[1].tableOptionsUnion(), yyDollar[3].tableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 1710: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []tree.TableOption -//line mysql_sql.y:11843 - { - yyLOCAL = append(yyDollar[1].tableOptionsUnion(), yyDollar[2].tableOptionUnion()) - } - yyVAL.union = yyLOCAL - case 1711: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11849 - { - yyLOCAL = tree.NewTableOptionAUTOEXTEND_SIZE(integralToUint64(yyDollar[3].item)) - } - yyVAL.union = yyLOCAL - case 1712: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11853 - { - yyLOCAL = tree.NewTableOptionAutoIncrement(integralToUint64(yyDollar[3].item)) - } - yyVAL.union = yyLOCAL - case 1713: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11857 - { - yyLOCAL = tree.NewTableOptionAutoIDCache(integralToUint64(yyDollar[3].item)) - } - yyVAL.union = yyLOCAL - case 1714: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11861 - { - yyLOCAL = tree.NewTableOptionAvgRowLength(integralToUint64(yyDollar[3].item)) - } - yyVAL.union = yyLOCAL - case 1715: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11865 - { - yyLOCAL = tree.NewTableOptionCharset(yyDollar[4].str) - } - yyVAL.union = yyLOCAL - case 1716: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11869 - { - yyLOCAL = tree.NewTableOptionCollate(yyDollar[4].str) - } - yyVAL.union = yyLOCAL - case 1717: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11873 - { - yyLOCAL = tree.NewTableOptionChecksum(integralToUint64(yyDollar[3].item)) - } - yyVAL.union = yyLOCAL - case 1718: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11877 - { - str := util.DealCommentString(yyDollar[3].str) - yyLOCAL = tree.NewTableOptionComment(str) - } - yyVAL.union = yyLOCAL - case 1719: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11882 - { - yyLOCAL = tree.NewTableOptionCompression(yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1720: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11886 - { - yyLOCAL = tree.NewTableOptionConnection(yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1721: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11890 - { - yyLOCAL = tree.NewTableOptionDataDirectory(yyDollar[4].str) - } - yyVAL.union = yyLOCAL - case 1722: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11894 - { - yyLOCAL = tree.NewTableOptionIndexDirectory(yyDollar[4].str) - } - yyVAL.union = yyLOCAL - case 1723: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11898 - { - yyLOCAL = tree.NewTableOptionDelayKeyWrite(integralToUint64(yyDollar[3].item)) - } - yyVAL.union = yyLOCAL - case 1724: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11902 - { - yyLOCAL = tree.NewTableOptionEncryption(yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1725: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11906 - { - yyLOCAL = tree.NewTableOptionEngine(yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1726: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11910 - { - yyLOCAL = tree.NewTableOptionEngineAttr(yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1727: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11914 - { - yyLOCAL = tree.NewTableOptionInsertMethod(yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1728: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11918 - { - yyLOCAL = tree.NewTableOptionKeyBlockSize(integralToUint64(yyDollar[3].item)) - } - yyVAL.union = yyLOCAL - case 1729: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11922 - { - yyLOCAL = tree.NewTableOptionMaxRows(integralToUint64(yyDollar[3].item)) - } - yyVAL.union = yyLOCAL - case 1730: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11926 - { - yyLOCAL = tree.NewTableOptionMinRows(integralToUint64(yyDollar[3].item)) - } - yyVAL.union = yyLOCAL - case 1731: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11930 - { - t := tree.NewTableOptionPackKeys() - value, ok := signedIntegral(yylex, yyDollar[3].item) - if !ok { - goto ret1 - } - t.Value = value - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1732: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11938 - { - t := tree.NewTableOptionPackKeys() - t.Default = true - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1733: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11944 - { - yyLOCAL = tree.NewTableOptionPassword(yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1734: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11948 - { - yyLOCAL = tree.NewTableOptionRowFormat(yyDollar[3].rowFormatTypeUnion()) - } - yyVAL.union = yyLOCAL - case 1735: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11952 - { - yyLOCAL = tree.NewTTableOptionStartTrans(true) - } - yyVAL.union = yyLOCAL - case 1736: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11956 - { - yyLOCAL = tree.NewTTableOptionSecondaryEngineAttr(yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 1737: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11960 - { - t := tree.NewTableOptionStatsAutoRecalc() - t.Value = integralToUint64(yyDollar[3].item) - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1738: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11966 - { - t := tree.NewTableOptionStatsAutoRecalc() - t.Default = true - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1739: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11972 - { - t := tree.NewTableOptionStatsPersistent() - t.Value = integralToUint64(yyDollar[3].item) - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1740: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11978 - { - t := tree.NewTableOptionStatsPersistent() - t.Default = true - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1741: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11984 - { - t := tree.NewTableOptionStatsSamplePages() - t.Value = integralToUint64(yyDollar[3].item) - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1742: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11990 - { - t := tree.NewTableOptionStatsSamplePages() - t.Default = true - yyLOCAL = t - } - yyVAL.union = yyLOCAL - case 1743: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:11996 - { - yyLOCAL = tree.NewTableOptionTablespace(yyDollar[3].cstrUnion().Compare(), "") - } - yyVAL.union = yyLOCAL - case 1744: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:12000 - { - yyLOCAL = tree.NewTableOptionTablespace("", yyDollar[1].str) - } - yyVAL.union = yyLOCAL - case 1745: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:12004 - { - yyLOCAL = tree.NewTableOptionUnion(yyDollar[4].tableNamesUnion()) - } - yyVAL.union = yyLOCAL - case 1746: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.TableOption -//line mysql_sql.y:12008 - { - var Preperties = yyDollar[3].propertiesUnion() - yyLOCAL = tree.NewTableOptionProperties(Preperties) - } - yyVAL.union = yyLOCAL - case 1747: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.Property -//line mysql_sql.y:12015 - { - yyLOCAL = []tree.Property{yyDollar[1].propertyUnion()} - } - yyVAL.union = yyLOCAL - case 1748: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []tree.Property -//line mysql_sql.y:12019 - { - yyLOCAL = append(yyDollar[1].propertiesUnion(), yyDollar[3].propertyUnion()) - } - yyVAL.union = yyLOCAL - case 1749: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Property -//line mysql_sql.y:12025 - { - var Key = yyDollar[1].str - var Value = yyDollar[3].str - yyLOCAL = *tree.NewProperty( - Key, - Value, - ) - } - yyVAL.union = yyLOCAL - case 1750: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:12036 - { - yyVAL.str = " " + yyDollar[1].str + " " + yyDollar[2].str - } - case 1751: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:12040 - { - yyVAL.str = " " + yyDollar[1].str + " " + yyDollar[2].str - } - case 1752: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.RowFormatType -//line mysql_sql.y:12046 - { - yyLOCAL = tree.ROW_FORMAT_DEFAULT - } - yyVAL.union = yyLOCAL - case 1753: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.RowFormatType -//line mysql_sql.y:12050 - { - yyLOCAL = tree.ROW_FORMAT_DYNAMIC - } - yyVAL.union = yyLOCAL - case 1754: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.RowFormatType -//line mysql_sql.y:12054 - { - yyLOCAL = tree.ROW_FORMAT_FIXED - } - yyVAL.union = yyLOCAL - case 1755: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.RowFormatType -//line mysql_sql.y:12058 - { - yyLOCAL = tree.ROW_FORMAT_COMPRESSED - } - yyVAL.union = yyLOCAL - case 1756: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.RowFormatType -//line mysql_sql.y:12062 - { - yyLOCAL = tree.ROW_FORMAT_REDUNDANT - } - yyVAL.union = yyLOCAL - case 1757: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.RowFormatType -//line mysql_sql.y:12066 - { - yyLOCAL = tree.ROW_FORMAT_COMPACT - } - yyVAL.union = yyLOCAL - case 1762: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableNames -//line mysql_sql.y:12080 - { - yyLOCAL = tree.TableNames{yyDollar[1].tableNameUnion()} - } - yyVAL.union = yyLOCAL - case 1763: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableNames -//line mysql_sql.y:12084 - { - yyLOCAL = append(yyDollar[1].tableNamesUnion(), yyDollar[3].tableNameUnion()) - } - yyVAL.union = yyLOCAL - case 1764: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.TableName -//line mysql_sql.y:12093 - { - tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - prefix := tree.ObjectNamePrefix{ExplicitSchema: false} - yyLOCAL = tree.NewTableName(tree.Identifier(tblName), prefix, yyDollar[2].atTimeStampUnion()) - yyLOCAL.IcebergRef = yyDollar[3].icebergRefSpecUnion() - } - yyVAL.union = yyLOCAL - case 1765: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.TableName -//line mysql_sql.y:12100 - { - dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) - tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[3].cstrUnion().Origin()) - prefix := tree.ObjectNamePrefix{SchemaName: tree.Identifier(dbName), ExplicitSchema: true} - yyLOCAL = tree.NewTableName(tree.Identifier(tblName), prefix, yyDollar[4].atTimeStampUnion()) - yyLOCAL.IcebergRef = yyDollar[5].icebergRefSpecUnion() - } - yyVAL.union = yyLOCAL - case 1766: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.IcebergRefSpec -//line mysql_sql.y:12109 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1767: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IcebergRefSpec -//line mysql_sql.y:12113 - { - raw := fmt.Sprintf("%v", yyDollar[3].item) - yyLOCAL = tree.NewIcebergSnapshotRef(tree.NewNumVal(raw, raw, false, tree.P_int64)) - } - yyVAL.union = yyLOCAL - case 1768: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IcebergRefSpec -//line mysql_sql.y:12118 - { - yyLOCAL = tree.NewIcebergSnapshotRef(tree.NewNumVal(yyDollar[3].str, yyDollar[3].str, false, tree.P_char)) - } - yyVAL.union = yyLOCAL - case 1769: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.IcebergRefSpec -//line mysql_sql.y:12122 - { - yyLOCAL = tree.NewIcebergTimestampRef(tree.NewNumVal(yyDollar[6].str, yyDollar[6].str, false, tree.P_char)) - } - yyVAL.union = yyLOCAL - case 1770: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.IcebergRefSpec -//line mysql_sql.y:12126 - { - yyLOCAL = tree.NewIcebergTimestampRef(tree.NewNumVal(yyDollar[5].str, yyDollar[5].str, false, tree.P_char)) - } - yyVAL.union = yyLOCAL - case 1771: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.IcebergRefSpec -//line mysql_sql.y:12130 - { - yyLOCAL = tree.NewIcebergNamedRef(tree.Identifier(yyDollar[3].str)) - } - yyVAL.union = yyLOCAL - case 1772: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:12136 - { - yyVAL.str = yyDollar[1].str - } - case 1773: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:12140 - { - yyVAL.str = yyDollar[1].str - } - case 1774: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:12144 - { - yyVAL.str = yyDollar[1].str - } - case 1775: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.AtTimeStamp -//line mysql_sql.y:12149 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1776: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.AtTimeStamp -//line mysql_sql.y:12153 - { - yyLOCAL = &tree.AtTimeStamp{ - Type: tree.ATTIMESTAMPTIME, - Expr: yyDollar[4].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 1777: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.AtTimeStamp -//line mysql_sql.y:12160 - { - var str = yyDollar[4].cstrUnion().Compare() - yyLOCAL = &tree.AtTimeStamp{ - Type: tree.ATTIMESTAMPSNAPSHOT, - SnapshotName: yylex.(*Lexer).GetDbOrTblName(yyDollar[4].cstrUnion().Origin()), - Expr: tree.NewNumVal(str, str, false, tree.P_char), - } - } - yyVAL.union = yyLOCAL - case 1778: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.AtTimeStamp -//line mysql_sql.y:12169 - { - yyLOCAL = &tree.AtTimeStamp{ - Type: tree.ATTIMESTAMPSNAPSHOT, - SnapshotName: yyDollar[4].str, - Expr: tree.NewNumVal(yyDollar[4].str, yyDollar[4].str, false, tree.P_char), - } - } - yyVAL.union = yyLOCAL - case 1779: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.AtTimeStamp -//line mysql_sql.y:12177 - { - yyLOCAL = &tree.AtTimeStamp{ - Type: tree.ATMOTIMESTAMP, - Expr: yyDollar[4].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 1780: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.AtTimeStamp -//line mysql_sql.y:12184 - { - yyLOCAL = &tree.AtTimeStamp{ - Type: tree.ASOFTIMESTAMP, - Expr: tree.NewNumVal(yyDollar[5].str, yyDollar[5].str, false, tree.P_char), - } - } - yyVAL.union = yyLOCAL - case 1781: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.TableDefs -//line mysql_sql.y:12192 - { - yyLOCAL = tree.TableDefs(nil) - } - yyVAL.union = yyLOCAL - case 1783: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableDefs -//line mysql_sql.y:12199 - { - yyLOCAL = tree.TableDefs{yyDollar[1].tableDefUnion()} - } - yyVAL.union = yyLOCAL - case 1784: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.TableDefs -//line mysql_sql.y:12203 - { - yyLOCAL = append(yyDollar[1].tableDefsUnion(), yyDollar[3].tableDefUnion()) - } - yyVAL.union = yyLOCAL - case 1785: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12209 - { - yyLOCAL = tree.TableDef(yyDollar[1].columnTableDefUnion()) - } - yyVAL.union = yyLOCAL - case 1786: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12213 - { - yyLOCAL = yyDollar[1].tableDefUnion() - } - yyVAL.union = yyLOCAL - case 1787: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12217 - { - yyLOCAL = yyDollar[1].tableDefUnion() - } - yyVAL.union = yyLOCAL - case 1788: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12223 - { - yyLOCAL = yyDollar[1].tableDefUnion() - } - yyVAL.union = yyLOCAL - case 1789: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12227 - { - yyLOCAL = yyDollar[1].tableDefUnion() - } - yyVAL.union = yyLOCAL - case 1790: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12233 - { - var KeyParts = yyDollar[5].keyPartsUnion() - var Name = yyDollar[3].str - var Empty = true - var IndexOption = yyDollar[7].indexOptionUnion() - yyLOCAL = tree.NewFullTextIndex( - KeyParts, - Name, - Empty, - IndexOption, - ) - } - yyVAL.union = yyLOCAL - case 1791: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12246 - { - var KeyParts = yyDollar[5].keyPartsUnion() - var Name = yyDollar[3].str - var Empty = true - var IndexOption = yyDollar[9].indexOptionUnion() - yyLOCAL = tree.NewFullTextIndex( - KeyParts, - Name, - Empty, - IndexOption, - ) - } - yyVAL.union = yyLOCAL - case 1792: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12259 - { - var KeyParts = yyDollar[5].keyPartsUnion() - var Name = yyDollar[3].str - var Empty = true - var IndexOption = yyDollar[7].indexOptionUnion() - fti := tree.NewFullTextIndex( - KeyParts, - Name, - Empty, - IndexOption, - ) - fti.IsV2 = true - yyLOCAL = fti - } - yyVAL.union = yyLOCAL - case 1793: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12274 - { - keyTyp := tree.INDEX_TYPE_INVALID - if yyDollar[3].strsUnion()[1] != "" { - t := strings.ToLower(yyDollar[3].strsUnion()[1]) - switch t { - case "btree": - keyTyp = tree.INDEX_TYPE_BTREE - case "ivfflat": - keyTyp = tree.INDEX_TYPE_IVFFLAT - case "master": - keyTyp = tree.INDEX_TYPE_MASTER - case "hash": - keyTyp = tree.INDEX_TYPE_HASH - case "rtree": - keyTyp = tree.INDEX_TYPE_RTREE - case "zonemap": - keyTyp = tree.INDEX_TYPE_ZONEMAP - case "bsi": - keyTyp = tree.INDEX_TYPE_BSI - case "hnsw": - keyTyp = tree.INDEX_TYPE_HNSW - case "cagra": - keyTyp = tree.INDEX_TYPE_CAGRA - case "ivfpq": - keyTyp = tree.INDEX_TYPE_IVFPQ - default: - yylex.Error("Invalid the type of index") - goto ret1 - } - } - - var IfNotExists = yyDollar[2].ifNotExistsUnion() - var KeyParts = yyDollar[5].keyPartsUnion() - var Name = yyDollar[3].strsUnion()[0] - var KeyType = keyTyp - var IndexOption = yyDollar[7].indexOptionUnion() - yyLOCAL = tree.NewIndex( - IfNotExists, - KeyParts, - Name, - KeyType, - IndexOption, - ) - } - yyVAL.union = yyLOCAL - case 1794: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12319 - { - keyTyp := tree.INDEX_TYPE_INVALID - if yyDollar[3].strsUnion()[1] != "" { - t := strings.ToLower(yyDollar[3].strsUnion()[1]) - switch t { - case "btree": - keyTyp = tree.INDEX_TYPE_BTREE - case "ivfflat": - keyTyp = tree.INDEX_TYPE_IVFFLAT - case "master": - keyTyp = tree.INDEX_TYPE_MASTER - case "hash": - keyTyp = tree.INDEX_TYPE_HASH - case "rtree": - keyTyp = tree.INDEX_TYPE_RTREE - case "zonemap": - keyTyp = tree.INDEX_TYPE_ZONEMAP - case "bsi": - keyTyp = tree.INDEX_TYPE_BSI - case "hnsw": - keyTyp = tree.INDEX_TYPE_HNSW - case "cagra": - keyTyp = tree.INDEX_TYPE_CAGRA - case "ivfpq": - keyTyp = tree.INDEX_TYPE_IVFPQ - default: - yylex.Error("Invalid type of index") - goto ret1 - } - } - var IfNotExists = yyDollar[2].ifNotExistsUnion() - var KeyParts = yyDollar[5].keyPartsUnion() - var Name = yyDollar[3].strsUnion()[0] - var KeyType = keyTyp - var IndexOption = yyDollar[9].indexOptionUnion() - yyLOCAL = tree.NewIndex( - IfNotExists, - KeyParts, - Name, - KeyType, - IndexOption, - ) - } - yyVAL.union = yyLOCAL - case 1795: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12364 - { - if yyDollar[1].str != "" { - switch v := yyDollar[2].tableDefUnion().(type) { - case *tree.PrimaryKeyIndex: - v.ConstraintSymbol = yyDollar[1].str - case *tree.ForeignKey: - v.ConstraintSymbol = yyDollar[1].str - case *tree.UniqueIndex: - v.ConstraintSymbol = yyDollar[1].str - case *tree.CheckIndex: - v.ConstraintSymbol = yyDollar[1].str - } - } - yyLOCAL = yyDollar[2].tableDefUnion() - } - yyVAL.union = yyLOCAL - case 1796: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12379 - { - yyLOCAL = yyDollar[1].tableDefUnion() - } - yyVAL.union = yyLOCAL - case 1797: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12385 - { - var KeyParts = yyDollar[5].keyPartsUnion() - var Name = yyDollar[3].strsUnion()[0] - var Empty = yyDollar[3].strsUnion()[1] == "" - var IndexOption = yyDollar[7].indexOptionUnion() - yyLOCAL = tree.NewPrimaryKeyIndex( - KeyParts, - Name, - Empty, - IndexOption, - ) - } - yyVAL.union = yyLOCAL - case 1798: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12398 - { - var KeyParts = yyDollar[5].keyPartsUnion() - var Name = yyDollar[3].strsUnion()[0] - var Empty = yyDollar[3].strsUnion()[1] == "" - var IndexOption = yyDollar[9].indexOptionUnion() - yyLOCAL = tree.NewPrimaryKeyIndex( - KeyParts, - Name, - Empty, - IndexOption, - ) - } - yyVAL.union = yyLOCAL - case 1799: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12411 - { - var KeyParts = yyDollar[5].keyPartsUnion() - var Name = yyDollar[3].strsUnion()[0] - var Empty = yyDollar[3].strsUnion()[1] == "" - var IndexOption = yyDollar[7].indexOptionUnion() - yyLOCAL = tree.NewUniqueIndex( - KeyParts, - Name, - Empty, - IndexOption, - ) - } - yyVAL.union = yyLOCAL - case 1800: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12424 - { - var KeyParts = yyDollar[5].keyPartsUnion() - var Name = yyDollar[3].strsUnion()[0] - var Empty = yyDollar[3].strsUnion()[1] == "" - var IndexOption = yyDollar[9].indexOptionUnion() - yyLOCAL = tree.NewUniqueIndex( - KeyParts, - Name, - Empty, - IndexOption, - ) - } - yyVAL.union = yyLOCAL - case 1801: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12437 - { - var IfNotExists = yyDollar[3].ifNotExistsUnion() - var KeyParts = yyDollar[6].keyPartsUnion() - var Name = tree.NewCStr(yyDollar[4].str, 1).Compare() - var Refer = yyDollar[8].attributeReferenceUnion() - var Empty = true - yyLOCAL = tree.NewForeignKey( - IfNotExists, - KeyParts, - Name, - Refer, - Empty, - ) - } - yyVAL.union = yyLOCAL - case 1802: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.TableDef -//line mysql_sql.y:12452 - { - var Expr = yyDollar[3].exprUnion() - var Enforced = yyDollar[5].boolValUnion() - yyLOCAL = tree.NewCheckIndex( - Expr, - Enforced, - ) - } - yyVAL.union = yyLOCAL - case 1803: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:12462 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1805: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:12468 - { - yyVAL.str = "" - } - case 1806: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:12472 - { - yyVAL.str = yyDollar[1].str - } - case 1809: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:12482 - { - yyLOCAL = make([]string, 2) - yyLOCAL[0] = yyDollar[1].str - yyLOCAL[1] = "" - } - yyVAL.union = yyLOCAL - case 1810: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:12488 - { - yyLOCAL = make([]string, 2) - yyLOCAL[0] = yyDollar[1].str - yyLOCAL[1] = yyDollar[3].str - } - yyVAL.union = yyLOCAL - case 1811: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:12494 - { - yyLOCAL = make([]string, 2) - yyLOCAL[0] = yyDollar[1].cstrUnion().Origin() - yyLOCAL[1] = yyDollar[3].str - } - yyVAL.union = yyLOCAL - case 1826: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:12519 - { - yyVAL.str = "" - } - case 1827: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:12523 - { - yyVAL.str = yyDollar[1].cstrUnion().Origin() - } - case 1828: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.ColumnTableDef -//line mysql_sql.y:12529 - { - yyLOCAL = tree.NewColumnTableDef(yyDollar[1].unresolvedNameUnion(), yyDollar[2].columnTypeUnion(), yyDollar[3].columnAttributesUnion()) - } - yyVAL.union = yyLOCAL - case 1829: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:12535 - { - yyLOCAL = tree.NewUnresolvedName(yyDollar[1].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 1830: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:12539 - { - tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedName(tblNameCStr, yyDollar[3].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 1831: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:12544 - { - dbNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) - tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[3].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedName(dbNameCStr, tblNameCStr, yyDollar[5].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 1832: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:12552 - { - if rejectSQLModeReservedFunctionName(yylex, yyDollar[1].str) { - goto ret1 - } - yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) - } - yyVAL.union = yyLOCAL - case 1833: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:12556 - { - yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) - } - yyVAL.union = yyLOCAL - case 1834: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:12560 - { - if rejectSQLModeReservedFunctionName(yylex, yyDollar[1].str) { - goto ret1 - } - yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) - } - yyVAL.union = yyLOCAL - case 1835: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:12564 - { - if rejectSQLModeReservedFunctionName(yylex, yyDollar[1].str) { - goto ret1 - } - yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) - } - yyVAL.union = yyLOCAL - case 1836: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:12570 - { - yyLOCAL = yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) - } - yyVAL.union = yyLOCAL - case 1837: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:12576 - { - yyLOCAL = tree.NewUnresolvedName(yyDollar[1].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 1838: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:12580 - { - tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedName(tblNameCStr, yyDollar[3].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 1839: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.UnresolvedName -//line mysql_sql.y:12585 - { - dbNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) - tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[3].cstrUnion().Origin()) - yyLOCAL = tree.NewUnresolvedName(dbNameCStr, tblNameCStr, yyDollar[5].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 1840: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []tree.ColumnAttribute -//line mysql_sql.y:12592 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1841: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.ColumnAttribute -//line mysql_sql.y:12596 - { - yyLOCAL = yyDollar[1].columnAttributesUnion() - } - yyVAL.union = yyLOCAL - case 1842: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []tree.ColumnAttribute -//line mysql_sql.y:12602 - { - yyLOCAL = []tree.ColumnAttribute{yyDollar[1].columnAttributeUnion()} - } - yyVAL.union = yyLOCAL - case 1843: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []tree.ColumnAttribute -//line mysql_sql.y:12606 - { - yyLOCAL = append(yyDollar[1].columnAttributesUnion(), yyDollar[2].columnAttributeUnion()) - } - yyVAL.union = yyLOCAL - case 1844: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12612 - { - yyLOCAL = tree.NewAttributeNull(true) - } - yyVAL.union = yyLOCAL - case 1845: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12616 - { - yyLOCAL = tree.NewAttributeNull(false) - } - yyVAL.union = yyLOCAL - case 1846: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12620 - { - yyLOCAL = tree.NewAttributeNull(false) - } - yyVAL.union = yyLOCAL - case 1847: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12624 - { - yyLOCAL = tree.NewAttributeDefault(yyDollar[2].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1848: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12628 - { - yyLOCAL = tree.NewAttributeAutoIncrement() - } - yyVAL.union = yyLOCAL - case 1849: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12632 - { - yyLOCAL = yyDollar[1].columnAttributeUnion() - } - yyVAL.union = yyLOCAL - case 1850: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12636 - { - str := util.DealCommentString(yyDollar[2].str) - yyLOCAL = tree.NewAttributeComment(tree.NewNumVal(str, str, false, tree.P_char)) - } - yyVAL.union = yyLOCAL - case 1851: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12641 - { - yyLOCAL = tree.NewAttributeMongoDBPath(yyDollar[2].str) - } - yyVAL.union = yyLOCAL - case 1852: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12645 - { - yyLOCAL = tree.NewAttributeMongoDBConvert(yyDollar[2].str) - } - yyVAL.union = yyLOCAL - case 1853: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12649 - { - yyLOCAL = tree.NewAttributeCollate(yyDollar[2].str) - } - yyVAL.union = yyLOCAL - case 1854: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12653 - { - yyLOCAL = tree.NewAttributeColumnFormat(yyDollar[2].str) - } - yyVAL.union = yyLOCAL - case 1855: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12657 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1856: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12661 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1857: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12665 - { - yyLOCAL = tree.NewAttributeStorage(yyDollar[2].str) - } - yyVAL.union = yyLOCAL - case 1858: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12669 - { - yyLOCAL = tree.NewAttributeAutoRandom(int(yyDollar[2].int64ValUnion())) - } - yyVAL.union = yyLOCAL - case 1859: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12673 - { - yyLOCAL = yyDollar[1].attributeReferenceUnion() - } - yyVAL.union = yyLOCAL - case 1860: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12677 - { - yyLOCAL = tree.NewAttributeCheckConstraint(yyDollar[4].exprUnion(), true, yyDollar[1].str) - } - yyVAL.union = yyLOCAL - case 1861: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12681 - { - yyLOCAL = tree.NewAttributeCheckConstraint(yyDollar[4].exprUnion(), yyDollar[6].boolValUnion(), yyDollar[1].str) - } - yyVAL.union = yyLOCAL - case 1862: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12685 - { - name := tree.NewUnresolvedColName(yyDollar[3].str) - var es tree.Exprs = nil - if yyDollar[4].exprUnion() != nil { - es = append(es, yyDollar[4].exprUnion()) - } - expr := &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[3].str, 1), - Exprs: es, - } - yyLOCAL = tree.NewAttributeOnUpdate(expr) - } - yyVAL.union = yyLOCAL - case 1863: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12699 - { - v, errStr := util.GetInt64(yyDollar[2].item) - if errStr != "" { - yylex.Error(errStr) - goto ret1 - } - if v < 0 || v > 4294967295 { - yylex.Error("SRID should be between 0 and 4294967295") - goto ret1 - } - yyLOCAL = tree.NewAttributeSRID(uint32(v)) - } - yyVAL.union = yyLOCAL - case 1864: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12712 - { - yyLOCAL = tree.NewAttributeLowCardinality() - } - yyVAL.union = yyLOCAL - case 1865: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12716 - { - yyLOCAL = tree.NewAttributeVisable(true) - } - yyVAL.union = yyLOCAL - case 1866: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12720 - { - yyLOCAL = tree.NewAttributeVisable(false) - } - yyVAL.union = yyLOCAL - case 1867: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12724 - { - yyLOCAL = tree.NewAttributeCharset(yyDollar[5].str) - } - yyVAL.union = yyLOCAL - case 1868: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12728 - { - yyLOCAL = tree.NewAttributeGeneratedAlways(yyDollar[5].exprUnion(), yyDollar[7].boolValUnion()) - } - yyVAL.union = yyLOCAL - case 1869: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:12732 - { - yyLOCAL = tree.NewAttributeGeneratedAlways(yyDollar[3].exprUnion(), yyDollar[5].boolValUnion()) - } - yyVAL.union = yyLOCAL - case 1870: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:12737 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1871: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:12741 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1872: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:12745 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1873: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:12751 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 1874: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:12755 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1875: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:12759 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 1876: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:12764 - { - yyVAL.str = "" - } - case 1877: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:12768 - { - yyVAL.str = yyDollar[1].str - } - case 1878: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:12774 - { - yyVAL.str = "" - } - case 1879: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:12778 - { - yyVAL.str = yyDollar[2].cstrUnion().Compare() - } - case 1880: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.AttributeReference -//line mysql_sql.y:12784 - { - var TableName = yyDollar[2].tableNameUnion() - var KeyParts = yyDollar[3].keyPartsUnion() - var Match = yyDollar[4].matchTypeUnion() - var OnDelete = yyDollar[5].referenceOnRecordUnion().OnDelete - var OnUpdate = yyDollar[5].referenceOnRecordUnion().OnUpdate - yyLOCAL = tree.NewAttributeReference( - TableName, - KeyParts, - Match, - OnDelete, - OnUpdate, - ) - } - yyVAL.union = yyLOCAL - case 1881: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.ReferenceOnRecord -//line mysql_sql.y:12801 - { - yyLOCAL = &tree.ReferenceOnRecord{ - OnDelete: tree.REFERENCE_OPTION_INVALID, - OnUpdate: tree.REFERENCE_OPTION_INVALID, - } - } - yyVAL.union = yyLOCAL - case 1882: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.ReferenceOnRecord -//line mysql_sql.y:12808 - { - yyLOCAL = &tree.ReferenceOnRecord{ - OnDelete: yyDollar[1].referenceOptionTypeUnion(), - OnUpdate: tree.REFERENCE_OPTION_INVALID, - } - } - yyVAL.union = yyLOCAL - case 1883: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.ReferenceOnRecord -//line mysql_sql.y:12815 - { - yyLOCAL = &tree.ReferenceOnRecord{ - OnDelete: tree.REFERENCE_OPTION_INVALID, - OnUpdate: yyDollar[1].referenceOptionTypeUnion(), - } - } - yyVAL.union = yyLOCAL - case 1884: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.ReferenceOnRecord -//line mysql_sql.y:12822 - { - yyLOCAL = &tree.ReferenceOnRecord{ - OnDelete: yyDollar[1].referenceOptionTypeUnion(), - OnUpdate: yyDollar[2].referenceOptionTypeUnion(), - } - } - yyVAL.union = yyLOCAL - case 1885: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.ReferenceOnRecord -//line mysql_sql.y:12829 - { - yyLOCAL = &tree.ReferenceOnRecord{ - OnDelete: yyDollar[2].referenceOptionTypeUnion(), - OnUpdate: yyDollar[1].referenceOptionTypeUnion(), - } - } - yyVAL.union = yyLOCAL - case 1886: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.ReferenceOptionType -//line mysql_sql.y:12838 - { - yyLOCAL = yyDollar[3].referenceOptionTypeUnion() - } - yyVAL.union = yyLOCAL - case 1887: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.ReferenceOptionType -//line mysql_sql.y:12844 - { - yyLOCAL = yyDollar[3].referenceOptionTypeUnion() - } - yyVAL.union = yyLOCAL - case 1888: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ReferenceOptionType -//line mysql_sql.y:12850 - { - yyLOCAL = tree.REFERENCE_OPTION_RESTRICT - } - yyVAL.union = yyLOCAL - case 1889: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ReferenceOptionType -//line mysql_sql.y:12854 - { - yyLOCAL = tree.REFERENCE_OPTION_CASCADE - } - yyVAL.union = yyLOCAL - case 1890: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ReferenceOptionType -//line mysql_sql.y:12858 - { - yyLOCAL = tree.REFERENCE_OPTION_SET_NULL - } - yyVAL.union = yyLOCAL - case 1891: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ReferenceOptionType -//line mysql_sql.y:12862 - { - yyLOCAL = tree.REFERENCE_OPTION_NO_ACTION - } - yyVAL.union = yyLOCAL - case 1892: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ReferenceOptionType -//line mysql_sql.y:12866 - { - yyLOCAL = tree.REFERENCE_OPTION_SET_DEFAULT - } - yyVAL.union = yyLOCAL - case 1893: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.MatchType -//line mysql_sql.y:12871 - { - yyLOCAL = tree.MATCH_INVALID - } - yyVAL.union = yyLOCAL - case 1895: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.MatchType -//line mysql_sql.y:12878 - { - yyLOCAL = tree.MATCH_FULL - } - yyVAL.union = yyLOCAL - case 1896: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.MatchType -//line mysql_sql.y:12882 - { - yyLOCAL = tree.MATCH_PARTIAL - } - yyVAL.union = yyLOCAL - case 1897: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.MatchType -//line mysql_sql.y:12886 - { - yyLOCAL = tree.MATCH_SIMPLE - } - yyVAL.union = yyLOCAL - case 1898: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.FullTextSearchType -//line mysql_sql.y:12891 - { - yyLOCAL = tree.FULLTEXT_DEFAULT - } - yyVAL.union = yyLOCAL - case 1899: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.FullTextSearchType -//line mysql_sql.y:12895 - { - yyLOCAL = tree.FULLTEXT_NL - } - yyVAL.union = yyLOCAL - case 1900: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.FullTextSearchType -//line mysql_sql.y:12899 - { - yyLOCAL = tree.FULLTEXT_NL_QUERY_EXPANSION - } - yyVAL.union = yyLOCAL - case 1901: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.FullTextSearchType -//line mysql_sql.y:12903 - { - yyLOCAL = tree.FULLTEXT_BOOLEAN - } - yyVAL.union = yyLOCAL - case 1902: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.FullTextSearchType -//line mysql_sql.y:12907 - { - yyLOCAL = tree.FULLTEXT_QUERY_EXPANSION - } - yyVAL.union = yyLOCAL - case 1903: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.FullTextSearchType -//line mysql_sql.y:12911 - { - yyLOCAL = tree.FULLTEXT_BM25 - } - yyVAL.union = yyLOCAL - case 1904: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL []*tree.KeyPart -//line mysql_sql.y:12916 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1905: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []*tree.KeyPart -//line mysql_sql.y:12920 - { - yyLOCAL = yyDollar[2].keyPartsUnion() - } - yyVAL.union = yyLOCAL - case 1906: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:12925 - { - yyLOCAL = -1 - } - yyVAL.union = yyLOCAL - case 1907: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL int64 -//line mysql_sql.y:12929 - { - value, ok := signedIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - yyLOCAL = value - } - yyVAL.union = yyLOCAL - case 1914: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.Subquery -//line mysql_sql.y:12947 - { - yyLOCAL = &tree.Subquery{Select: yyDollar[1].selectStatementUnion(), Exists: false} - } - yyVAL.union = yyLOCAL - case 1915: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12953 - { - yyLOCAL = tree.NewBinaryExpr(tree.BIT_AND, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1916: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12957 - { - yyLOCAL = tree.NewBinaryExpr(tree.BIT_OR, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1917: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12961 - { - yyLOCAL = tree.NewBinaryExpr(tree.BIT_XOR, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1918: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12965 - { - yyLOCAL = tree.NewBinaryExpr(tree.PLUS, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1919: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12969 - { - yyLOCAL = tree.NewBinaryExpr(tree.MINUS, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1920: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12973 - { - yyLOCAL = tree.NewBinaryExpr(tree.MULTI, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1921: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12977 - { - yyLOCAL = tree.NewBinaryExpr(tree.DIV, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1922: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12981 - { - yyLOCAL = tree.NewBinaryExpr(tree.INTEGER_DIV, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1923: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12985 - { - yyLOCAL = tree.NewBinaryExpr(tree.MOD, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1924: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12989 - { - yyLOCAL = tree.NewBinaryExpr(tree.MOD, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1925: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12993 - { - yyLOCAL = tree.NewBinaryExpr(tree.LEFT_SHIFT, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1926: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:12997 - { - yyLOCAL = tree.NewBinaryExpr(tree.RIGHT_SHIFT, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1927: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13001 - { - name := tree.NewUnresolvedColName("json_extract") - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr("json_extract", 1), - Exprs: tree.Exprs{yyDollar[1].exprUnion(), yyDollar[3].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 1928: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13010 - { - extractName := tree.NewUnresolvedColName("json_extract") - inner := &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(extractName), - FuncName: tree.NewCStr("json_extract", 1), - Exprs: tree.Exprs{yyDollar[1].exprUnion(), yyDollar[3].exprUnion()}, - } - unquoteName := tree.NewUnresolvedColName("json_unquote") - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(unquoteName), - FuncName: tree.NewCStr("json_unquote", 1), - Exprs: tree.Exprs{inner}, - } - } - yyVAL.union = yyLOCAL - case 1929: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13025 - { - yyLOCAL = yyDollar[1].exprUnion() - } - yyVAL.union = yyLOCAL - case 1930: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13031 - { - yyLOCAL = yyDollar[1].unresolvedNameUnion() - } - yyVAL.union = yyLOCAL - case 1931: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13035 - { - yyLOCAL = yyDollar[1].varExprUnion() - } - yyVAL.union = yyLOCAL - case 1932: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13039 - { - yyLOCAL = yyDollar[1].exprUnion() - } - yyVAL.union = yyLOCAL - case 1933: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13043 - { - name := tree.NewUnresolvedColName("concat") - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr("concat", 1), - Exprs: tree.Exprs{yyDollar[1].exprUnion(), yyDollar[3].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 1934: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13052 - { - yyLOCAL = tree.NewParentExpr(yyDollar[2].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1935: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13056 - { - yyLOCAL = tree.NewTuple(append(yyDollar[2].exprsUnion(), yyDollar[4].exprUnion())) - } - yyVAL.union = yyLOCAL - case 1936: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13060 - { - yyLOCAL = tree.NewUnaryExpr(tree.UNARY_PLUS, yyDollar[2].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1937: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13064 - { - yyLOCAL = tree.NewUnaryExpr(tree.UNARY_MINUS, yyDollar[2].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1938: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13068 - { - yyLOCAL = tree.NewUnaryExpr(tree.UNARY_TILDE, yyDollar[2].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1939: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13072 - { - yyLOCAL = tree.NewUnaryExpr(tree.UNARY_MARK, yyDollar[2].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1940: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13076 - { - yyLOCAL = tree.NewNotExpr(yyDollar[2].exprUnion()) - } - yyVAL.union = yyLOCAL - case 1941: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13080 - { - hint := strings.ToLower(yyDollar[2].cstrUnion().Compare()) - switch hint { - case "d": - locale := "" - t := &tree.T{ - InternalType: tree.InternalType{ - Family: tree.TimestampFamily, - FamilyString: "DATETIME", - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DATETIME), - }, - } - yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), t) - case "t": - locale := "" - t := &tree.T{ - InternalType: tree.InternalType{ - Family: tree.TimeFamily, - FamilyString: "TIME", - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TIME), - }, - } - yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), t) - case "ts": - locale := "" - t := &tree.T{ - InternalType: tree.InternalType{ - Family: tree.TimestampFamily, - FamilyString: "TIMESTAMP", - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TIMESTAMP), - }, - } - yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), t) - default: - yylex.Error("Invalid type") - return 1 - } - } - yyVAL.union = yyLOCAL - case 1942: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13122 - { - yyLOCAL = yyDollar[1].exprUnion() - } - yyVAL.union = yyLOCAL - case 1943: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13126 - { - yyLOCAL = yyDollar[1].subqueryUnion() - } - yyVAL.union = yyLOCAL - case 1944: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13130 - { - yyDollar[2].subqueryUnion().Exists = true - yyLOCAL = yyDollar[2].subqueryUnion() - } - yyVAL.union = yyLOCAL - case 1945: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13135 - { - yyLOCAL = &tree.CaseExpr{ - Expr: yyDollar[2].exprUnion(), - Whens: yyDollar[3].whenClauseListUnion(), - Else: yyDollar[4].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 1946: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13143 - { - yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), yyDollar[5].columnTypeUnion()) - } - yyVAL.union = yyLOCAL - case 1947: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13147 - { - yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), makeCharsetCastCharType(yyDollar[6].lengthOptUnion(), yyDollar[9].str)) - } - yyVAL.union = yyLOCAL - case 1948: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13151 - { - yyLOCAL = tree.NewSerialExtractExpr(yyDollar[3].exprUnion(), yyDollar[5].exprUnion(), yyDollar[7].columnTypeUnion()) - } - yyVAL.union = yyLOCAL - case 1949: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13155 - { - yyLOCAL = tree.NewBitCastExpr(yyDollar[3].exprUnion(), yyDollar[5].columnTypeUnion()) - } - yyVAL.union = yyLOCAL - case 1950: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13159 - { - yyLOCAL = tree.NewCastExpr(yyDollar[1].exprUnion(), yyDollar[3].columnTypeUnion()) - } - yyVAL.union = yyLOCAL - case 1951: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13163 - { - yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), yyDollar[5].columnTypeUnion()) - } - yyVAL.union = yyLOCAL - case 1952: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13167 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - es := tree.NewNumVal(yyDollar[5].str, yyDollar[5].str, false, tree.P_char) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion(), es}, - } - } - yyVAL.union = yyLOCAL - case 1953: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13177 - { - yyLOCAL = yyDollar[1].funcExprUnion() - } - yyVAL.union = yyLOCAL - case 1954: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13181 - { - yyLOCAL = yyDollar[1].funcExprUnion() - } - yyVAL.union = yyLOCAL - case 1955: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13185 - { - yyLOCAL = yyDollar[1].funcExprUnion() - } - yyVAL.union = yyLOCAL - case 1956: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13189 - { - yyLOCAL = yyDollar[1].funcExprUnion() - } - yyVAL.union = yyLOCAL - case 1957: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13193 - { - yyLOCAL = yyDollar[1].funcExprUnion() - } - yyVAL.union = yyLOCAL - case 1958: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13197 - { - yyLOCAL = yyDollar[1].exprUnion() - } - yyVAL.union = yyLOCAL - case 1959: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13201 - { - yyLOCAL = &tree.CollateExpr{Expr: yyDollar[1].exprUnion(), Collation: yyDollar[3].str} - } - yyVAL.union = yyLOCAL - case 1960: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13205 - { - val, err := tree.NewFullTextMatchFuncExpression(yyDollar[3].keyPartsUnion(), yyDollar[7].exprUnion(), yyDollar[8].fullTextSearchTypeUnion()) - if err != nil { - yylex.Error(err.Error()) - goto ret1 - } - yyLOCAL = val - } - yyVAL.union = yyLOCAL - case 1961: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13215 - { - yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_char) - } - yyVAL.union = yyLOCAL - case 1962: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13219 - { - yyLOCAL = tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()) - } - yyVAL.union = yyLOCAL - case 1963: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13223 - { - yyLOCAL = tree.NewUnresolvedName(yyDollar[1].cstrUnion()) - } - yyVAL.union = yyLOCAL - case 1964: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13229 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - WindowSpec: yyDollar[4].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1965: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13238 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - WindowSpec: yyDollar[4].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1966: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13247 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - WindowSpec: yyDollar[4].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1967: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13256 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - WindowSpec: yyDollar[4].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1968: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13265 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion()}, - WindowSpec: yyDollar[5].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1969: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13275 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - WindowSpec: yyDollar[4].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1970: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13284 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion()}, - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1971: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13294 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, - WindowSpec: yyDollar[8].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1972: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13304 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion(), yyDollar[7].exprUnion()}, - WindowSpec: yyDollar[10].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1973: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13314 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion()}, - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1974: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13324 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, - WindowSpec: yyDollar[8].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1975: - yyDollar = yyS[yypt-10 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13334 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion(), yyDollar[7].exprUnion()}, - WindowSpec: yyDollar[10].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1976: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13344 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion()}, - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1977: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13354 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion()}, - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1978: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13364 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, - WindowSpec: yyDollar[9].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 1979: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13376 - { - value, ok := signedIntegral(yylex, yyDollar[5].item) - if !ok { - goto ret1 - } - v := int(value) - val, err := tree.NewSampleRowsFuncExpression(v, true, nil, "block") - if err != nil { - yylex.Error(err.Error()) - goto ret1 - } - yyLOCAL = val - } - yyVAL.union = yyLOCAL - case 1980: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13388 - { - value, ok := signedIntegral(yylex, yyDollar[5].item) - if !ok { - goto ret1 - } - v := int(value) - val, err := tree.NewSampleRowsFuncExpression(v, true, nil, yyDollar[8].str) - if err != nil { - yylex.Error(err.Error()) - goto ret1 - } - yyLOCAL = val - } - yyVAL.union = yyLOCAL - case 1981: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13400 - { - value, ok := signedIntegral(yylex, yyDollar[5].item) - if !ok { - goto ret1 - } - val, err := tree.NewSamplePercentFuncExpression1(value, true, nil) - if err != nil { - yylex.Error(err.Error()) - goto ret1 - } - yyLOCAL = val - } - yyVAL.union = yyLOCAL - case 1982: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13411 - { - val, err := tree.NewSamplePercentFuncExpression2(yyDollar[5].item.(float64), true, nil) - if err != nil { - yylex.Error(err.Error()) - goto ret1 - } - yyLOCAL = val - } - yyVAL.union = yyLOCAL - case 1983: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13421 - { - value, ok := signedIntegral(yylex, yyDollar[5].item) - if !ok { - goto ret1 - } - v := int(value) - val, err := tree.NewSampleRowsFuncExpression(v, false, yyDollar[3].exprsUnion(), "block") - if err != nil { - yylex.Error(err.Error()) - goto ret1 - } - yyLOCAL = val - } - yyVAL.union = yyLOCAL - case 1984: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13433 - { - value, ok := signedIntegral(yylex, yyDollar[5].item) - if !ok { - goto ret1 - } - v := int(value) - val, err := tree.NewSampleRowsFuncExpression(v, false, yyDollar[3].exprsUnion(), yyDollar[8].str) - if err != nil { - yylex.Error(err.Error()) - goto ret1 - } - yyLOCAL = val - } - yyVAL.union = yyLOCAL - case 1985: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13445 - { - value, ok := signedIntegral(yylex, yyDollar[5].item) - if !ok { - goto ret1 - } - val, err := tree.NewSamplePercentFuncExpression1(value, false, yyDollar[3].exprsUnion()) - if err != nil { - yylex.Error(err.Error()) - goto ret1 - } - yyLOCAL = val - } - yyVAL.union = yyLOCAL - case 1986: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13456 - { - val, err := tree.NewSamplePercentFuncExpression2(yyDollar[5].item.(float64), false, yyDollar[3].exprsUnion()) - if err != nil { - yylex.Error(err.Error()) - goto ret1 - } - yyLOCAL = val - } - yyVAL.union = yyLOCAL - case 1987: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13466 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1988: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13470 - { - yyLOCAL = yyDollar[2].exprUnion() - } - yyVAL.union = yyLOCAL - case 1989: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13475 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 1990: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:13479 - { - yyLOCAL = yyDollar[1].exprUnion() - } - yyVAL.union = yyLOCAL - case 1991: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []*tree.When -//line mysql_sql.y:13485 - { - yyLOCAL = []*tree.When{yyDollar[1].whenClauseUnion()} - } - yyVAL.union = yyLOCAL - case 1992: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL []*tree.When -//line mysql_sql.y:13489 - { - yyLOCAL = append(yyDollar[1].whenClauseListUnion(), yyDollar[2].whenClauseUnion()) - } - yyVAL.union = yyLOCAL - case 1993: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.When -//line mysql_sql.y:13495 - { - yyLOCAL = &tree.When{ - Cond: yyDollar[2].exprUnion(), - Val: yyDollar[4].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 1994: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:13504 - { - t := yyVAL.columnTypeUnion() - str := strings.ToLower(t.InternalType.FamilyString) - if str == "binary" { - t.InternalType.Scale = -1 - } else if str == "char" { - if t.InternalType.DisplayWith == -1 { - t.InternalType.FamilyString = "varchar" - t.InternalType.Oid = uint32(defines.MYSQL_TYPE_VARCHAR) - } - } - } - case 1995: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13516 - { - name := yyDollar[1].str - if yyDollar[2].str != "" { - name = yyDollar[2].str - } - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: name, - Width: 64, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_LONGLONG), - }, - } - } - yyVAL.union = yyLOCAL - case 1996: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13533 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[2].str, - Width: 64, - Locale: &locale, - Unsigned: true, - Oid: uint32(defines.MYSQL_TYPE_LONGLONG), - }, - } - } - yyVAL.union = yyLOCAL - case 1998: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13550 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.JsonFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_JSON), - }, - } - } - yyVAL.union = yyLOCAL - case 1999: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13562 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.StringFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_VARCHAR), - DisplayWith: yyDollar[2].lengthOptUnion(), - Scale: -1, - }, - } - } - yyVAL.union = yyLOCAL - case 2000: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13576 - { - locale := "" - oid := uint32(defines.MYSQL_TYPE_STRING) - familyString := yyDollar[1].str - if yyDollar[2].lengthOptUnion() == -1 { - oid = uint32(defines.MYSQL_TYPE_VARCHAR) - familyString = "varchar" - } - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.StringFamily, - FamilyString: familyString, - Locale: &locale, - Oid: oid, - DisplayWith: yyDollar[2].lengthOptUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 2001: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13595 - { - yyLOCAL = makeCharsetCastCharType(yyDollar[2].lengthOptUnion(), yyDollar[5].str) - } - yyVAL.union = yyLOCAL - case 2002: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13599 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.DateFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DATE), - }, - } - } - yyVAL.union = yyLOCAL - case 2003: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13611 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - Width: 16, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_YEAR), - }, - } - } - yyVAL.union = yyLOCAL - case 2004: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13625 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.TimestampFamily, - Scale: yyDollar[2].lengthOptUnion(), - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - TimePrecisionIsSet: false, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DATETIME), - }, - } - } - yyVAL.union = yyLOCAL - case 2005: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13640 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.TimeFamily, - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - Scale: yyDollar[2].lengthOptUnion(), - TimePrecisionIsSet: false, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TIME), - }, - } - } - yyVAL.union = yyLOCAL - case 2006: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13655 - { - name := yyDollar[1].str - if yyDollar[2].str != "" { - name = yyDollar[2].str - } - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: name, - Width: 64, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_LONGLONG), - }, - } - } - yyVAL.union = yyLOCAL - case 2007: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:13672 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[2].str, - Width: 64, - Locale: &locale, - Unsigned: true, - Oid: uint32(defines.MYSQL_TYPE_LONGLONG), - }, - } - } - yyVAL.union = yyLOCAL - case 2008: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:13688 - { - yyVAL.str = "" - } - case 2012: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FrameBound -//line mysql_sql.y:13697 - { - yyLOCAL = &tree.FrameBound{Type: tree.Following, UnBounded: true} - } - yyVAL.union = yyLOCAL - case 2013: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FrameBound -//line mysql_sql.y:13701 - { - yyLOCAL = &tree.FrameBound{Type: tree.Following, Expr: yyDollar[1].exprUnion()} - } - yyVAL.union = yyLOCAL - case 2014: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FrameBound -//line mysql_sql.y:13705 - { - yyLOCAL = &tree.FrameBound{Type: tree.Following, Expr: tree.NewParamExpr(yylex.(*Lexer).GetParamIndex())} - } - yyVAL.union = yyLOCAL - case 2015: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FrameBound -//line mysql_sql.y:13709 - { - yyLOCAL = &tree.FrameBound{Type: tree.Following, Expr: yyDollar[1].exprUnion()} - } - yyVAL.union = yyLOCAL - case 2016: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FrameBound -//line mysql_sql.y:13715 - { - yyLOCAL = &tree.FrameBound{Type: tree.CurrentRow} - } - yyVAL.union = yyLOCAL - case 2017: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FrameBound -//line mysql_sql.y:13719 - { - yyLOCAL = &tree.FrameBound{Type: tree.Preceding, UnBounded: true} - } - yyVAL.union = yyLOCAL - case 2018: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FrameBound -//line mysql_sql.y:13723 - { - yyLOCAL = &tree.FrameBound{Type: tree.Preceding, Expr: yyDollar[1].exprUnion()} - } - yyVAL.union = yyLOCAL - case 2019: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FrameBound -//line mysql_sql.y:13727 - { - yyLOCAL = &tree.FrameBound{Type: tree.Preceding, Expr: tree.NewParamExpr(yylex.(*Lexer).GetParamIndex())} - } - yyVAL.union = yyLOCAL - case 2020: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FrameBound -//line mysql_sql.y:13731 - { - yyLOCAL = &tree.FrameBound{Type: tree.Preceding, Expr: yyDollar[1].exprUnion()} - } - yyVAL.union = yyLOCAL - case 2021: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FrameType -//line mysql_sql.y:13737 - { - yyLOCAL = tree.Rows - } - yyVAL.union = yyLOCAL - case 2022: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FrameType -//line mysql_sql.y:13741 - { - yyLOCAL = tree.Range - } - yyVAL.union = yyLOCAL - case 2023: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FrameType -//line mysql_sql.y:13745 - { - yyLOCAL = tree.Groups - } - yyVAL.union = yyLOCAL - case 2024: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FrameClause -//line mysql_sql.y:13751 - { - yyLOCAL = &tree.FrameClause{ - Type: yyDollar[1].frameTypeUnion(), - Start: yyDollar[2].frameBoundUnion(), - End: &tree.FrameBound{Type: tree.CurrentRow}, - } - } - yyVAL.union = yyLOCAL - case 2025: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.FrameClause -//line mysql_sql.y:13759 - { - yyLOCAL = &tree.FrameClause{ - Type: yyDollar[1].frameTypeUnion(), - HasEnd: true, - Start: yyDollar[3].frameBoundUnion(), - End: yyDollar[5].frameBoundUnion(), - } - } - yyVAL.union = yyLOCAL - case 2026: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.FrameClause -//line mysql_sql.y:13769 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 2027: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.FrameClause -//line mysql_sql.y:13773 - { - yyLOCAL = yyDollar[1].frameClauseUnion() - } - yyVAL.union = yyLOCAL - case 2028: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:13779 - { - yyLOCAL = yyDollar[3].exprsUnion() - } - yyVAL.union = yyLOCAL - case 2029: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:13784 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 2030: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:13788 - { - yyLOCAL = yyDollar[1].exprsUnion() - } - yyVAL.union = yyLOCAL - case 2031: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:13793 - { - yyVAL.str = "," - } - case 2032: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:13797 - { - yyVAL.str = yyDollar[2].str - } - case 2033: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:13802 - { - yyVAL.str = "1,vector_l2_ops,random,false" - } - case 2034: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:13806 - { - yyVAL.str = yyDollar[2].str - } - case 2035: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.WindowSpec -//line mysql_sql.y:13811 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 2037: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.WindowSpec -//line mysql_sql.y:13818 - { - yyLOCAL = makeWindowSpec(yyDollar[2].cstrUnion(), nil, nil, nil) - yyLOCAL.ReferencedOnly = true - } - yyVAL.union = yyLOCAL - case 2038: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.WindowSpec -//line mysql_sql.y:13823 - { - yyLOCAL = yyDollar[3].windowSpecUnion() - } - yyVAL.union = yyLOCAL - case 2039: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.WindowSpec -//line mysql_sql.y:13829 - { - yyLOCAL = makeWindowSpec(yyDollar[1].cstrUnion(), yyDollar[2].exprsUnion(), yyDollar[3].orderByUnion(), yyDollar[4].frameClauseUnion()) - } - yyVAL.union = yyLOCAL - case 2040: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:13838 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 2041: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.CStr -//line mysql_sql.y:13842 - { - yyLOCAL = yyDollar[1].cstrUnion() - } - yyVAL.union = yyLOCAL - case 2042: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.WindowDefinitions -//line mysql_sql.y:13847 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 2043: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.WindowDefinitions -//line mysql_sql.y:13851 - { - yyLOCAL = yyDollar[2].windowDefinitionsUnion() - } - yyVAL.union = yyLOCAL - case 2044: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.WindowDefinitions -//line mysql_sql.y:13857 - { - yyLOCAL = tree.WindowDefinitions{yyDollar[1].windowDefinitionUnion()} - } - yyVAL.union = yyLOCAL - case 2045: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.WindowDefinitions -//line mysql_sql.y:13861 - { - yyLOCAL = append(yyDollar[1].windowDefinitionsUnion(), yyDollar[3].windowDefinitionUnion()) - } - yyVAL.union = yyLOCAL - case 2046: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.WindowDefinition -//line mysql_sql.y:13867 - { - yyLOCAL = &tree.WindowDefinition{Name: yyDollar[1].cstrUnion(), Spec: yyDollar[4].windowSpecUnion()} - } - yyVAL.union = yyLOCAL - case 2047: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13873 - { - functionName := yyDollar[1].str - arguments := yyDollar[4].exprsUnion() - separator := tree.Expr(tree.NewNumVal(yyDollar[6].str, yyDollar[6].str, false, tree.P_char)) - if strings.EqualFold(functionName, "listagg") { - // LISTAGG is a compatibility surface over GROUP_CONCAT. Keep the - // spelling in FuncName for deparsing, but bind the canonical name. - functionName = "group_concat" - if len(arguments) < 1 || len(arguments) > 2 { - yylex.Error("listagg requires one value and an optional delimiter") - return 1 - } - if len(arguments) == 2 { - literal, ok := arguments[1].(*tree.NumVal) - if !ok || (literal.ValType != tree.P_char && literal.ValType != tree.P_null) { - yylex.Error("listagg delimiter must be a string literal or NULL") - return 1 - } - separator = arguments[1] - arguments = arguments[:1] - } - } - name := tree.NewUnresolvedColName(functionName) - if yyDollar[5].orderByUnion() != nil && yyDollar[8].orderByUnion() != nil { - yylex.Error(yyDollar[1].str + " cannot use both ORDER BY and WITHIN GROUP ORDER BY") - return 1 - } - orderBy := yyDollar[5].orderByUnion() - if yyDollar[8].orderByUnion() != nil { - orderBy = yyDollar[8].orderByUnion() - } - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: append(arguments, separator), - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[9].windowSpecUnion(), - OrderBy: orderBy, - WithinGroup: yyDollar[8].orderByUnion() != nil, - } - } - yyVAL.union = yyLOCAL - case 2048: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13915 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion()}, - WindowSpec: yyDollar[6].windowSpecUnion(), - OrderBy: yyDollar[5].orderByUnion(), - WithinGroup: yyDollar[5].orderByUnion() != nil, - } - } - yyVAL.union = yyLOCAL - case 2049: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13927 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion()}, - WindowSpec: yyDollar[6].windowSpecUnion(), - OrderBy: yyDollar[5].orderByUnion(), - WithinGroup: yyDollar[5].orderByUnion() != nil, - } - } - yyVAL.union = yyLOCAL - case 2050: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13939 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: append(yyDollar[4].exprsUnion(), tree.NewNumVal(yyDollar[6].str, yyDollar[6].str, false, tree.P_char)), - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[8].windowSpecUnion(), - OrderBy: yyDollar[5].orderByUnion(), - } - } - yyVAL.union = yyLOCAL - case 2051: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13951 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2052: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13962 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[4].exprsUnion(), - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2053: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13973 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - es := tree.NewNumVal("*", "*", false, tree.P_star) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{es}, - WindowSpec: yyDollar[5].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2054: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13984 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - WindowSpec: yyDollar[5].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2055: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:13994 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - OrderBy: yyDollar[5].orderByUnion(), - WithinGroup: yyDollar[5].orderByUnion() != nil, - } - } - yyVAL.union = yyLOCAL - case 2056: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14006 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2057: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14017 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2058: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14028 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2059: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14039 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[4].exprsUnion(), - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2060: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14050 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - es := tree.NewNumVal("*", "*", false, tree.P_star) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{es}, - WindowSpec: yyDollar[5].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2061: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14061 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2062: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14072 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2063: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14083 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2064: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14094 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2065: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14105 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2066: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14116 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2067: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14127 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2068: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14138 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2069: - yyDollar = yyS[yypt-9 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14149 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - OrderBy: yyDollar[7].orderByUnion(), - WithinGroup: true, - WindowSpec: yyDollar[9].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2070: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14160 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2071: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14171 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2072: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14182 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[4].exprsUnion(), - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2073: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14193 - { - functionName := yyDollar[1].str - if strings.EqualFold(functionName, "array_agg") { - // MatrixOne has no general SQL ARRAY value. ARRAY_AGG deliberately - // adopts JSON_ARRAYAGG's JSON return contract instead. - functionName = "json_arrayagg" - } - name := tree.NewUnresolvedColName(functionName) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2074: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14210 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion(), yyDollar[6].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[8].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2078: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14228 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - IsGeneric: isSQLModeSensitiveFunctionName(yyDollar[1].str), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2079: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14238 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - exprs := tree.Exprs{yyDollar[3].exprUnion()} - exprs = append(exprs, yyDollar[5].exprsUnion()...) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: exprs, - } - } - yyVAL.union = yyLOCAL - case 2080: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14249 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2081: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14258 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2082: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14267 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion(), yyDollar[7].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2083: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14276 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - str := strings.ToLower(yyDollar[3].str) - timeUinit := tree.NewTimeUnitExpr(str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{timeUinit, yyDollar[5].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2084: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14287 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2085: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14296 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2086: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14305 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[4].exprUnion()}, - Type: yyDollar[3].funcTypeUnion(), - WindowSpec: yyDollar[6].windowSpecUnion(), - } - } - yyVAL.union = yyLOCAL - case 2087: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14316 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2088: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14325 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2089: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14334 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2090: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14343 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: nil, - } - } - yyVAL.union = yyLOCAL - case 2091: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14352 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - arg0 := tree.NewNumVal(int64(0), "0", false, tree.P_int64) - arg1 := tree.NewNumVal("both", "both", false, tree.P_char) - arg2 := tree.NewNumVal(" ", " ", false, tree.P_char) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{arg0, arg1, arg2, yyDollar[3].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2092: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14364 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - arg0 := tree.NewNumVal(int64(1), "1", false, tree.P_int64) - arg1 := tree.NewNumVal("both", "both", false, tree.P_char) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{arg0, arg1, yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2093: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14375 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - arg0 := tree.NewNumVal(int64(2), "2", false, tree.P_int64) - str := strings.ToLower(yyDollar[3].str) - arg1 := tree.NewNumVal(str, str, false, tree.P_char) - arg2 := tree.NewNumVal(" ", " ", false, tree.P_char) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{arg0, arg1, arg2, yyDollar[5].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2094: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14388 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - arg0 := tree.NewNumVal(int64(3), "3", false, tree.P_int64) - str := strings.ToLower(yyDollar[3].str) - arg1 := tree.NewNumVal(str, str, false, tree.P_char) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{arg0, arg1, yyDollar[4].exprUnion(), yyDollar[6].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2095: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14400 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[3].unresolvedNameUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2102: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:14421 - { - yyVAL.str = yyDollar[1].str - } - case 2135: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14463 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - var es tree.Exprs = nil - if yyDollar[2].exprUnion() != nil { - es = append(es, yyDollar[2].exprUnion()) - } - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: es, - } - } - yyVAL.union = yyLOCAL - case 2136: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14476 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - var es tree.Exprs = nil - if yyDollar[2].exprUnion() != nil { - es = append(es, yyDollar[2].exprUnion()) - } - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: es, - } - } - yyVAL.union = yyLOCAL - case 2137: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14489 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - str := strings.ToLower(yyDollar[3].str) - arg1 := tree.NewTimeUnitExpr(str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{arg1, yyDollar[5].exprUnion(), yyDollar[7].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2138: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14500 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - str := strings.ToLower(yyDollar[3].str) - arg1 := tree.NewTimeUnitExpr(str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{arg1, yyDollar[5].exprUnion(), yyDollar[7].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2139: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14511 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - str := strings.ToUpper(yyDollar[3].str) - arg1 := tree.NewNumVal(str, str, false, tree.P_char) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{arg1, yyDollar[5].exprUnion()}, - } - } - yyVAL.union = yyLOCAL - case 2140: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14523 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2141: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14532 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - } - } - yyVAL.union = yyLOCAL - case 2142: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14540 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - } - } - yyVAL.union = yyLOCAL - case 2143: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14548 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - var es tree.Exprs = nil - if yyDollar[2].exprUnion() != nil { - es = append(es, yyDollar[2].exprUnion()) - } - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: es, - } - } - yyVAL.union = yyLOCAL - case 2144: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14561 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2145: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14570 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - exprs := make([]tree.Expr, 1) - exprs[0] = yyDollar[2].exprUnion() - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: exprs, - } - } - yyVAL.union = yyLOCAL - case 2146: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14581 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - exprs := make([]tree.Expr, 1) - exprs[0] = yyDollar[2].unresolvedNameUnion() - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: exprs, - } - } - yyVAL.union = yyLOCAL - case 2147: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14592 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2148: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14601 - { - charName := tree.NewUnresolvedColName(yyDollar[1].str) - charExpr := &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(charName), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - charset := tree.NewNumVal(yyDollar[5].str, yyDollar[5].str, false, tree.P_char) - name := tree.NewUnresolvedColName("convert") - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr("convert", 1), - Exprs: tree.Exprs{charExpr, charset}, - } - } - yyVAL.union = yyLOCAL - case 2149: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14617 - { - val := tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char) - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{val}, - } - } - yyVAL.union = yyLOCAL - case 2150: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14627 - { - val := tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char) - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{val}, - } - } - yyVAL.union = yyLOCAL - case 2151: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14637 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2152: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14646 - { - es := tree.Exprs{yyDollar[3].exprUnion()} - es = append(es, yyDollar[5].exprUnion()) - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: es, - } - } - yyVAL.union = yyLOCAL - case 2153: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14657 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2154: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14666 - { - val := tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char) - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{val}, - } - } - yyVAL.union = yyLOCAL - case 2155: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14676 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2156: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14685 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2157: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.FuncExpr -//line mysql_sql.y:14694 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: yyDollar[3].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2158: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14704 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 2159: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14708 - { - yyLOCAL = yyDollar[1].exprUnion() - } - yyVAL.union = yyLOCAL - case 2160: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14714 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 2161: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14718 - { - ival, errStr := util.GetInt64(yyDollar[2].item) - if errStr != "" { - yylex.Error(errStr) - goto ret1 - } - str := fmt.Sprintf("%v", yyDollar[2].item) - yyLOCAL = tree.NewNumVal(ival, str, false, tree.P_int64) - } - yyVAL.union = yyLOCAL - case 2168: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:14737 - { - } - case 2169: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:14739 - { - } - case 2206: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14783 - { - name := tree.NewUnresolvedColName(yyDollar[1].str) - str := strings.ToLower(yyDollar[3].str) - arg2 := tree.NewTimeUnitExpr(str) - yyLOCAL = &tree.FuncExpr{ - Func: tree.FuncName2ResolvableFunctionReference(name), - FuncName: tree.NewCStr(yyDollar[1].str, 1), - Exprs: tree.Exprs{yyDollar[2].exprUnion(), arg2}, - } - } - yyVAL.union = yyLOCAL - case 2207: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.FuncType -//line mysql_sql.y:14795 - { - yyLOCAL = tree.FUNC_TYPE_DEFAULT - } - yyVAL.union = yyLOCAL - case 2208: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FuncType -//line mysql_sql.y:14799 - { - yyLOCAL = tree.FUNC_TYPE_DISTINCT - } - yyVAL.union = yyLOCAL - case 2209: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.FuncType -//line mysql_sql.y:14803 - { - yyLOCAL = tree.FUNC_TYPE_ALL - } - yyVAL.union = yyLOCAL - case 2210: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.Tuple -//line mysql_sql.y:14809 - { - yyLOCAL = tree.NewTuple(yyDollar[2].exprsUnion()) - } - yyVAL.union = yyLOCAL - case 2211: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:14814 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 2212: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:14818 - { - yyLOCAL = yyDollar[1].exprsUnion() - } - yyVAL.union = yyLOCAL - case 2213: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:14824 - { - yyLOCAL = tree.Exprs{yyDollar[1].exprUnion()} - } - yyVAL.union = yyLOCAL - case 2214: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:14828 - { - yyLOCAL = append(yyDollar[1].exprsUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2215: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:14834 - { - yyLOCAL = tree.Exprs{yyDollar[1].exprUnion()} - } - yyVAL.union = yyLOCAL - case 2216: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Exprs -//line mysql_sql.y:14838 - { - yyLOCAL = append(yyDollar[1].exprsUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2217: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14845 - { - yyLOCAL = tree.NewAndExpr(yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2218: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14849 - { - yyLOCAL = tree.NewOrExpr(yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2219: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14853 - { - yyLOCAL = tree.NewXorExpr(yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2220: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14857 - { - yyLOCAL = tree.NewNotExpr(yyDollar[2].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2221: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14861 - { - yyLOCAL = yyDollar[1].exprUnion() - } - yyVAL.union = yyLOCAL - case 2222: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14866 - { - yyLOCAL = yyDollar[1].exprUnion() - } - yyVAL.union = yyLOCAL - case 2223: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14870 - { - yyLOCAL = tree.NewMaxValue() - } - yyVAL.union = yyLOCAL - case 2224: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14876 - { - yyLOCAL = tree.NewIsNullExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2225: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14880 - { - yyLOCAL = tree.NewIsNotNullExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2226: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14884 - { - yyLOCAL = tree.NewIsNotNullExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2227: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14888 - { - yyLOCAL = tree.NewIsUnknownExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2228: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14892 - { - yyLOCAL = tree.NewIsNotUnknownExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2229: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14896 - { - yyLOCAL = tree.NewIsNotUnknownExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2230: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14900 - { - yyLOCAL = tree.NewIsTrueExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2231: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14904 - { - yyLOCAL = tree.NewIsNotTrueExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2232: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14908 - { - yyLOCAL = tree.NewIsNotTrueExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2233: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14912 - { - yyLOCAL = tree.NewIsFalseExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2234: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14916 - { - yyLOCAL = tree.NewIsNotFalseExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2235: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14920 - { - yyLOCAL = tree.NewIsNotFalseExpr(yyDollar[1].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2236: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14924 - { - yyLOCAL = tree.NewComparisonExpr(yyDollar[2].comparisonOpUnion(), yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2237: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14928 - { - yyLOCAL = tree.NewSubqueryComparisonExpr(yyDollar[2].comparisonOpUnion(), yyDollar[3].comparisonOpUnion(), yyDollar[1].exprUnion(), yyDollar[4].subqueryUnion()) - yyLOCAL = tree.NewSubqueryComparisonExpr(yyDollar[2].comparisonOpUnion(), yyDollar[3].comparisonOpUnion(), yyDollar[1].exprUnion(), yyDollar[4].subqueryUnion()) - } - yyVAL.union = yyLOCAL - case 2239: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14936 - { - yyLOCAL = tree.NewComparisonExpr(tree.IN, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2240: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14940 - { - yyLOCAL = tree.NewComparisonExpr(tree.NOT_IN, yyDollar[1].exprUnion(), yyDollar[4].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2241: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14944 - { - yyLOCAL = tree.NewComparisonExpr(tree.NOT_IN, yyDollar[1].exprUnion(), yyDollar[4].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2242: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14948 - { - yyLOCAL = tree.NewComparisonExpr(tree.MEMBER_OF, yyDollar[1].exprUnion(), yyDollar[5].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2243: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14952 - { - yyLOCAL = tree.NewComparisonExprWithEscape(tree.LIKE, yyDollar[1].exprUnion(), yyDollar[3].exprUnion(), yyDollar[4].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2244: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14956 - { - yyLOCAL = tree.NewComparisonExprWithEscape(tree.NOT_LIKE, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[5].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2245: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14960 - { - yyLOCAL = tree.NewComparisonExprWithEscape(tree.NOT_LIKE, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[5].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2246: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14964 - { - yyLOCAL = tree.NewComparisonExprWithEscape(tree.ILIKE, yyDollar[1].exprUnion(), yyDollar[3].exprUnion(), yyDollar[4].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2247: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14968 - { - yyLOCAL = tree.NewComparisonExprWithEscape(tree.NOT_ILIKE, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[5].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2248: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14972 - { - yyLOCAL = tree.NewComparisonExprWithEscape(tree.NOT_ILIKE, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[5].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2249: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14976 - { - yyLOCAL = tree.NewComparisonExpr(tree.REG_MATCH, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2250: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14980 - { - yyLOCAL = tree.NewComparisonExpr(tree.NOT_REG_MATCH, yyDollar[1].exprUnion(), yyDollar[4].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2251: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14984 - { - yyLOCAL = tree.NewComparisonExpr(tree.NOT_REG_MATCH, yyDollar[1].exprUnion(), yyDollar[4].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2252: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14988 - { - yyLOCAL = tree.NewRangeCond(false, yyDollar[1].exprUnion(), yyDollar[3].exprUnion(), yyDollar[5].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2253: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14992 - { - yyLOCAL = tree.NewRangeCond(true, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[6].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2254: - yyDollar = yyS[yypt-6 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:14996 - { - yyLOCAL = tree.NewRangeCond(true, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[6].exprUnion()) - } - yyVAL.union = yyLOCAL - case 2256: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15002 - { - yyLOCAL = nil - } - yyVAL.union = yyLOCAL - case 2257: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15006 - { - yyLOCAL = yyDollar[2].exprUnion() - } - yyVAL.union = yyLOCAL - case 2260: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15016 - { - yyLOCAL = yyDollar[1].tupleUnion() - } - yyVAL.union = yyLOCAL - case 2261: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15020 - { - yyLOCAL = yyDollar[1].subqueryUnion() - } - yyVAL.union = yyLOCAL - case 2262: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ComparisonOp -//line mysql_sql.y:15027 - { - yyLOCAL = tree.ALL - } - yyVAL.union = yyLOCAL - case 2263: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ComparisonOp -//line mysql_sql.y:15031 - { - yyLOCAL = tree.ANY - } - yyVAL.union = yyLOCAL - case 2264: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ComparisonOp -//line mysql_sql.y:15035 - { - yyLOCAL = tree.SOME - } - yyVAL.union = yyLOCAL - case 2265: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ComparisonOp -//line mysql_sql.y:15041 - { - yyLOCAL = tree.EQUAL - } - yyVAL.union = yyLOCAL - case 2266: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ComparisonOp -//line mysql_sql.y:15045 - { - yyLOCAL = tree.LESS_THAN - } - yyVAL.union = yyLOCAL - case 2267: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ComparisonOp -//line mysql_sql.y:15049 - { - yyLOCAL = tree.GREAT_THAN - } - yyVAL.union = yyLOCAL - case 2268: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ComparisonOp -//line mysql_sql.y:15053 - { - yyLOCAL = tree.LESS_THAN_EQUAL - } - yyVAL.union = yyLOCAL - case 2269: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ComparisonOp -//line mysql_sql.y:15057 - { - yyLOCAL = tree.GREAT_THAN_EQUAL - } - yyVAL.union = yyLOCAL - case 2270: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ComparisonOp -//line mysql_sql.y:15061 - { - yyLOCAL = tree.NOT_EQUAL - } - yyVAL.union = yyLOCAL - case 2271: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ComparisonOp -//line mysql_sql.y:15065 - { - yyLOCAL = tree.NULL_SAFE_EQUAL - } - yyVAL.union = yyLOCAL - case 2272: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:15071 - { - yyLOCAL = tree.NewAttributePrimaryKey() - } - yyVAL.union = yyLOCAL - case 2273: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:15075 - { - yyLOCAL = tree.NewAttributeUniqueKey() - } - yyVAL.union = yyLOCAL - case 2274: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:15079 - { - yyLOCAL = tree.NewAttributeUnique() - } - yyVAL.union = yyLOCAL - case 2275: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.ColumnAttribute -//line mysql_sql.y:15083 - { - yyLOCAL = tree.NewAttributeKey() - } - yyVAL.union = yyLOCAL - case 2276: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15089 - { - str := fmt.Sprintf("%v", yyDollar[1].item) - switch v := yyDollar[1].item.(type) { - case uint64: - yyLOCAL = tree.NewNumVal(v, str, false, tree.P_uint64) - case int64: - yyLOCAL = tree.NewNumVal(v, str, false, tree.P_int64) - default: - yylex.Error("parse integral fail") - goto ret1 - } - } - yyVAL.union = yyLOCAL - case 2277: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15102 - { - fval := yyDollar[1].item.(float64) - yyLOCAL = tree.NewNumVal(fval, yylex.(*Lexer).scanner.LastToken, false, tree.P_float64) - } - yyVAL.union = yyLOCAL - case 2278: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15107 - { - yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_decimal) - } - yyVAL.union = yyLOCAL - case 2279: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15113 - { - yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_char) - } - yyVAL.union = yyLOCAL - case 2280: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15117 - { - str := fmt.Sprintf("%v", yyDollar[1].item) - switch v := yyDollar[1].item.(type) { - case uint64: - yyLOCAL = tree.NewNumVal(v, str, false, tree.P_uint64) - case int64: - yyLOCAL = tree.NewNumVal(v, str, false, tree.P_int64) - default: - yylex.Error("parse integral fail") - goto ret1 - } - } - yyVAL.union = yyLOCAL - case 2281: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15130 - { - fval := yyDollar[1].item.(float64) - yyLOCAL = tree.NewNumVal(fval, yylex.(*Lexer).scanner.LastToken, false, tree.P_float64) - } - yyVAL.union = yyLOCAL - case 2282: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15135 - { - yyLOCAL = tree.NewNumVal(true, "true", false, tree.P_bool) - } - yyVAL.union = yyLOCAL - case 2283: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15139 - { - yyLOCAL = tree.NewNumVal(false, "false", false, tree.P_bool) - } - yyVAL.union = yyLOCAL - case 2284: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15143 - { - yyLOCAL = tree.NewNumVal("null", "null", false, tree.P_null) - } - yyVAL.union = yyLOCAL - case 2285: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15147 - { - yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_hexnum) - } - yyVAL.union = yyLOCAL - case 2286: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15151 - { - yyLOCAL = tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_ScoreBinaryHexnum) - } - yyVAL.union = yyLOCAL - case 2287: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15155 - { - yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_decimal) - } - yyVAL.union = yyLOCAL - case 2288: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15159 - { - yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_bit) - } - yyVAL.union = yyLOCAL - case 2289: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15163 - { - yyLOCAL = tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()) - } - yyVAL.union = yyLOCAL - case 2290: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Expr -//line mysql_sql.y:15167 - { - yyLOCAL = tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_ScoreBinary) - } - yyVAL.union = yyLOCAL - case 2291: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15173 - { - yyLOCAL = yyDollar[1].columnTypeUnion() - yyLOCAL.InternalType.Unsigned = yyDollar[2].unsignedOptUnion() - yyLOCAL.InternalType.Zerofill = yyDollar[3].zeroFillOptUnion() - } - yyVAL.union = yyLOCAL - case 2295: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15182 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.ArrayFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TYPED_ARRAY), - ArrayContents: yyDollar[3].columnTypeUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 2296: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15197 - { - yyLOCAL = yyDollar[1].columnTypeUnion() - yyLOCAL.InternalType.DisplayWith = yyDollar[2].lengthOptUnion() - } - yyVAL.union = yyLOCAL - case 2297: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15202 - { - yyLOCAL = yyDollar[1].columnTypeUnion() - } - yyVAL.union = yyLOCAL - case 2298: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15208 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BitFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_BIT), - }, - } - } - yyVAL.union = yyLOCAL - case 2299: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15220 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BoolFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_BOOL), - }, - } - } - yyVAL.union = yyLOCAL - case 2300: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15232 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BoolFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_BOOL), - }, - } - } - yyVAL.union = yyLOCAL - case 2301: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15244 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - Width: 8, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TINY), - }, - } - } - yyVAL.union = yyLOCAL - case 2302: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15257 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - Width: 8, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TINY), - }, - } - } - yyVAL.union = yyLOCAL - case 2303: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15270 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - Width: 16, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_SHORT), - }, - } - } - yyVAL.union = yyLOCAL - case 2304: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15283 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - Width: 16, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_SHORT), - }, - } - } - yyVAL.union = yyLOCAL - case 2305: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15296 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - Width: 24, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_INT24), - }, - } - } - yyVAL.union = yyLOCAL - case 2306: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15309 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - Width: 24, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_INT24), - }, - } - } - yyVAL.union = yyLOCAL - case 2307: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15322 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - Width: 32, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_LONG), - }, - } - } - yyVAL.union = yyLOCAL - case 2308: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15335 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - Width: 32, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_LONG), - }, - } - } - yyVAL.union = yyLOCAL - case 2309: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15348 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - Width: 32, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_LONG), - }, - } - } - yyVAL.union = yyLOCAL - case 2310: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15361 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - Width: 64, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_LONGLONG), - }, - } - } - yyVAL.union = yyLOCAL - case 2311: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15374 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - Width: 64, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_LONGLONG), - }, - } - } - yyVAL.union = yyLOCAL - case 2312: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15389 - { - locale := "" - if yyDollar[2].lengthScaleOptUnion().DisplayWith > 255 { - yylex.Error("Display width for double out of range (max = 255)") - goto ret1 - } - if yyDollar[2].lengthScaleOptUnion().Scale > 30 { - yylex.Error("Display scale for double out of range (max = 30)") - goto ret1 - } - if yyDollar[2].lengthScaleOptUnion().Scale != tree.NotDefineDec && yyDollar[2].lengthScaleOptUnion().Scale > yyDollar[2].lengthScaleOptUnion().DisplayWith { - yylex.Error("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a'))") - goto ret1 - } - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.FloatFamily, - FamilyString: yyDollar[1].str, - Width: 64, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DOUBLE), - DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, - Scale: yyDollar[2].lengthScaleOptUnion().Scale, - }, - } - } - yyVAL.union = yyLOCAL - case 2313: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15416 - { - // DOUBLE PRECISION is the SQL-standard synonym for DOUBLE (float64). - locale := "" - if yyDollar[3].lengthScaleOptUnion().DisplayWith > 255 { - yylex.Error("Display width for double out of range (max = 255)") - goto ret1 - } - if yyDollar[3].lengthScaleOptUnion().Scale > 30 { - yylex.Error("Display scale for double out of range (max = 30)") - goto ret1 - } - if yyDollar[3].lengthScaleOptUnion().Scale != tree.NotDefineDec && yyDollar[3].lengthScaleOptUnion().Scale > yyDollar[3].lengthScaleOptUnion().DisplayWith { - yylex.Error("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a'))") - goto ret1 - } - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.FloatFamily, - FamilyString: yyDollar[1].str, - Width: 64, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DOUBLE), - DisplayWith: yyDollar[3].lengthScaleOptUnion().DisplayWith, - Scale: yyDollar[3].lengthScaleOptUnion().Scale, - }, - } - } - yyVAL.union = yyLOCAL - case 2314: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15444 - { - locale := "" - if yyDollar[2].lengthScaleOptUnion().DisplayWith > 255 { - yylex.Error("Display width for float out of range (max = 255)") - goto ret1 - } - if yyDollar[2].lengthScaleOptUnion().Scale > 30 { - yylex.Error("Display scale for float out of range (max = 30)") - goto ret1 - } - if yyDollar[2].lengthScaleOptUnion().Scale != tree.NotDefineDec && yyDollar[2].lengthScaleOptUnion().Scale > yyDollar[2].lengthScaleOptUnion().DisplayWith { - yylex.Error("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a'))") - goto ret1 - } - if yyDollar[2].lengthScaleOptUnion().Scale == tree.NotDefineDec && yyDollar[2].lengthScaleOptUnion().DisplayWith > 24 { - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.FloatFamily, - FamilyString: yyDollar[1].str, - Width: 64, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DOUBLE), - DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, - Scale: yyDollar[2].lengthScaleOptUnion().Scale, - }, - } - } else { - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.FloatFamily, - FamilyString: yyDollar[1].str, - Width: 32, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_FLOAT), - DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, - Scale: yyDollar[2].lengthScaleOptUnion().Scale, - }, - } - } - } - yyVAL.union = yyLOCAL - case 2315: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15486 - { - locale := "" - if yyDollar[2].lengthScaleOptUnion().Scale != tree.NotDefineDec && yyDollar[2].lengthScaleOptUnion().Scale > yyDollar[2].lengthScaleOptUnion().DisplayWith { - yylex.Error("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a'))") - goto ret1 - } - if yyDollar[2].lengthScaleOptUnion().DisplayWith > 65 || yyDollar[2].lengthScaleOptUnion().DisplayWith < 0 { - yylex.Error("For decimal(M), M must between 0 and 65.") - goto ret1 - } else if yyDollar[2].lengthScaleOptUnion().DisplayWith <= 16 { - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.FloatFamily, - FamilyString: yyDollar[1].str, - Width: 64, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DECIMAL), - DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, - Scale: yyDollar[2].lengthScaleOptUnion().Scale, - }, - } - } else if yyDollar[2].lengthScaleOptUnion().DisplayWith <= 38 { - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.FloatFamily, - FamilyString: yyDollar[1].str, - Width: 128, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DECIMAL), - DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, - Scale: yyDollar[2].lengthScaleOptUnion().Scale, - }, - } - } else { - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.FloatFamily, - FamilyString: yyDollar[1].str, - Width: 256, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DECIMAL), - DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, - Scale: yyDollar[2].lengthScaleOptUnion().Scale, - }, - } - } - } - yyVAL.union = yyLOCAL - case 2316: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15534 - { - locale := "" - if yyDollar[2].lengthScaleOptUnion().Scale != tree.NotDefineDec && yyDollar[2].lengthScaleOptUnion().Scale > yyDollar[2].lengthScaleOptUnion().DisplayWith { - yylex.Error("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a'))") - goto ret1 - } - if yyDollar[2].lengthScaleOptUnion().DisplayWith > 65 || yyDollar[2].lengthScaleOptUnion().DisplayWith < 0 { - yylex.Error("For decimal(M), M must between 0 and 65.") - goto ret1 - } else if yyDollar[2].lengthScaleOptUnion().DisplayWith <= 16 { - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.FloatFamily, - FamilyString: yyDollar[1].str, - Width: 64, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DECIMAL), - DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, - Scale: yyDollar[2].lengthScaleOptUnion().Scale, - }, - } - } else if yyDollar[2].lengthScaleOptUnion().DisplayWith <= 38 { - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.FloatFamily, - FamilyString: yyDollar[1].str, - Width: 128, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DECIMAL), - DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, - Scale: yyDollar[2].lengthScaleOptUnion().Scale, - }, - } - } else { - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.FloatFamily, - FamilyString: yyDollar[1].str, - Width: 256, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DECIMAL), - DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, - Scale: yyDollar[2].lengthScaleOptUnion().Scale, - }, - } - } - } - yyVAL.union = yyLOCAL - case 2317: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15582 - { - locale := "" - width := int32(64) - oid := uint32(defines.MYSQL_TYPE_DOUBLE) - if yylex.(*Lexer).HasSQLMode(SQLModeRealAsFloat) { - width = 32 - oid = uint32(defines.MYSQL_TYPE_FLOAT) - } - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.FloatFamily, - FamilyString: yyDollar[1].str, - Width: width, - Locale: &locale, - Oid: oid, - DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, - Scale: yyDollar[2].lengthScaleOptUnion().Scale, - }, - } - } - yyVAL.union = yyLOCAL - case 2318: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15605 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.DateFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DATE), - }, - } - } - yyVAL.union = yyLOCAL - case 2319: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15617 - { - locale := "" - if yyDollar[2].lengthOptUnion() < 0 || yyDollar[2].lengthOptUnion() > 6 { - yylex.Error("For Time(fsp), fsp must in [0, 6]") - goto ret1 - } else { - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.TimeFamily, - Scale: yyDollar[2].lengthOptUnion(), - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - TimePrecisionIsSet: true, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TIME), - }, - } - } - } - yyVAL.union = yyLOCAL - case 2320: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15637 - { - locale := "" - if yyDollar[2].lengthOptUnion() < 0 || yyDollar[2].lengthOptUnion() > 6 { - yylex.Error("For Timestamp(fsp), fsp must in [0, 6]") - goto ret1 - } else { - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.TimestampFamily, - Scale: yyDollar[2].lengthOptUnion(), - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - TimePrecisionIsSet: true, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TIMESTAMP), - }, - } - } - } - yyVAL.union = yyLOCAL - case 2321: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15657 - { - locale := "" - if yyDollar[2].lengthOptUnion() < 0 || yyDollar[2].lengthOptUnion() > 6 { - yylex.Error("For Datetime(fsp), fsp must in [0, 6]") - goto ret1 - } else { - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.TimestampFamily, - Scale: yyDollar[2].lengthOptUnion(), - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - TimePrecisionIsSet: true, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_DATETIME), - }, - } - } - } - yyVAL.union = yyLOCAL - case 2322: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15677 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.IntFamily, - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - Width: 16, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_YEAR), - }, - } - } - yyVAL.union = yyLOCAL - case 2323: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15693 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.StringFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_STRING), - DisplayWith: yyDollar[2].lengthOptUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 2324: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15706 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.StringFamily, - Locale: &locale, - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - Oid: uint32(defines.MYSQL_TYPE_VARCHAR), - }, - } - } - yyVAL.union = yyLOCAL - case 2325: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15719 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.StringFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_VARCHAR), - DisplayWith: yyDollar[2].lengthOptUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 2326: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15732 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.StringFamily, - Locale: &locale, - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - Oid: uint32(defines.MYSQL_TYPE_VARCHAR), - }, - } - } - yyVAL.union = yyLOCAL - case 2327: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15745 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BlobFamily, - FamilyString: "mediumtext", - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TEXT), - }, - } - } - yyVAL.union = yyLOCAL - case 2328: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15757 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BlobFamily, - FamilyString: "mediumblob", - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_MEDIUM_BLOB), - }, - } - } - yyVAL.union = yyLOCAL - case 2329: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15769 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BlobFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TEXT), - }, - } - } - yyVAL.union = yyLOCAL - case 2330: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15781 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BlobFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TEXT), - DisplayWith: yyDollar[2].lengthOptUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 2331: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15794 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BlobFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TEXT), - }, - } - } - yyVAL.union = yyLOCAL - case 2332: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15806 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BlobFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TEXT), - }, - } - } - yyVAL.union = yyLOCAL - case 2333: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15818 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BlobFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TEXT), - }, - } - } - yyVAL.union = yyLOCAL - case 2334: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15830 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BlobFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_BLOB), - DisplayWith: yyDollar[2].lengthOptUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 2335: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15843 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BlobFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_TINY_BLOB), - }, - } - } - yyVAL.union = yyLOCAL - case 2336: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15855 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BlobFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_MEDIUM_BLOB), - }, - } - } - yyVAL.union = yyLOCAL - case 2337: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15867 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.BlobFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_LONG_BLOB), - }, - } - } - yyVAL.union = yyLOCAL - case 2338: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15879 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.JsonFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_JSON), - }, - } - } - yyVAL.union = yyLOCAL - case 2339: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15891 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.ArrayFamily, - Locale: &locale, - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - Oid: uint32(defines.MYSQL_TYPE_VARCHAR), - }, - } - } - yyVAL.union = yyLOCAL - case 2340: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15904 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.ArrayFamily, - Locale: &locale, - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - Oid: uint32(defines.MYSQL_TYPE_VARCHAR), - }, - } - } - yyVAL.union = yyLOCAL - case 2341: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15917 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.ArrayFamily, - Locale: &locale, - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - Oid: uint32(defines.MYSQL_TYPE_VARCHAR), - }, - } - } - yyVAL.union = yyLOCAL - case 2342: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15930 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.ArrayFamily, - Locale: &locale, - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - Oid: uint32(defines.MYSQL_TYPE_VARCHAR), - }, - } - } - yyVAL.union = yyLOCAL - case 2343: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15943 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.ArrayFamily, - Locale: &locale, - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - Oid: uint32(defines.MYSQL_TYPE_VARCHAR), - }, - } - } - yyVAL.union = yyLOCAL - case 2344: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15956 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.ArrayFamily, - Locale: &locale, - FamilyString: yyDollar[1].str, - DisplayWith: yyDollar[2].lengthOptUnion(), - Oid: uint32(defines.MYSQL_TYPE_VARCHAR), - }, - } - } - yyVAL.union = yyLOCAL - case 2345: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15969 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.EnumFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_ENUM), - EnumValues: yyDollar[3].strsUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 2346: - yyDollar = yyS[yypt-4 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15982 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.SetFamily, - FamilyString: yyDollar[1].str, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_SET), - EnumValues: yyDollar[3].strsUnion(), - }, - } - } - yyVAL.union = yyLOCAL - case 2347: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:15995 - { - locale := "" - yyLOCAL = &tree.T{ - InternalType: tree.InternalType{ - Family: tree.UuidFamily, - FamilyString: yyDollar[1].str, - Width: 128, - Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_UUID), - }, - } - } - yyVAL.union = yyLOCAL - case 2348: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:16010 - { - yyLOCAL = &tree.Do{ - Exprs: yyDollar[2].exprsUnion(), - } - } - yyVAL.union = yyLOCAL - case 2349: - yyDollar = yyS[yypt-2 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:16018 - { - yyDollar[2].selectUnion().IsPerform = true - if intoErr := tree.ValidatePerformSelectIntoPlacement(yyDollar[2].selectUnion()); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - yyLOCAL = yyDollar[2].selectUnion() - } - yyVAL.union = yyLOCAL - case 2350: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:16029 - { - yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: yyDollar[6].selectIntoUnion().UserVars, SelectLockInfo: yyDollar[7].selectLockInfoUnion()} - if intoErr := tree.ValidatePerformSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 2351: - yyDollar = yyS[yypt-8 : yypt+1] - var yyLOCAL *tree.Select -//line mysql_sql.y:16037 - { - yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), TimeWindow: yyDollar[3].timeWindowUnion(), OrderBy: yyDollar[4].orderByUnion(), Limit: yyDollar[5].limitUnion(), RankOption: yyDollar[6].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[7].selectIntoUnion().Export), IntoVars: yyDollar[7].selectIntoUnion().UserVars, SelectLockInfo: yyDollar[8].selectLockInfoUnion(), With: yyDollar[1].withClauseUnion()} - if intoErr := tree.ValidatePerformSelectIntoPlacement(yyLOCAL); intoErr != "" { - yylex.Error(intoErr) - return 1 - } - } - yyVAL.union = yyLOCAL - case 2352: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:16047 - { - yyLOCAL = &tree.Declare{ - Variables: yyDollar[2].strsUnion(), - ColumnType: yyDollar[3].columnTypeUnion(), - DefaultVal: tree.NewNumVal("null", "null", false, tree.P_null), - } - } - yyVAL.union = yyLOCAL - case 2353: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.Statement -//line mysql_sql.y:16056 - { - yyLOCAL = &tree.Declare{ - Variables: yyDollar[2].strsUnion(), - ColumnType: yyDollar[3].columnTypeUnion(), - DefaultVal: yyDollar[5].exprUnion(), - } - } - yyVAL.union = yyLOCAL - case 2354: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL *tree.T -//line mysql_sql.y:16066 - { - yyLOCAL = tree.NewSpatialType(yyDollar[1].str) - } - yyVAL.union = yyLOCAL - case 2373: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:16094 - { - yyLOCAL = make([]string, 0, 4) - yyLOCAL = append(yyLOCAL, yyDollar[1].str) - } - yyVAL.union = yyLOCAL - case 2374: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL []string -//line mysql_sql.y:16099 - { - yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].str) - } - yyVAL.union = yyLOCAL - case 2375: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int32 -//line mysql_sql.y:16105 - { - yyLOCAL = 0 - } - yyVAL.union = yyLOCAL - case 2377: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int32 -//line mysql_sql.y:16112 - { - yyLOCAL = 0 - } - yyVAL.union = yyLOCAL - case 2378: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL int32 -//line mysql_sql.y:16116 - { - value, ok := typeLengthIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - yyLOCAL = value - } - yyVAL.union = yyLOCAL - case 2379: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL int32 -//line mysql_sql.y:16123 - { - yyLOCAL = int32(-1) - } - yyVAL.union = yyLOCAL - case 2380: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL int32 -//line mysql_sql.y:16127 - { - value, ok := typeLengthIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - yyLOCAL = value - } - yyVAL.union = yyLOCAL - case 2381: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL int32 -//line mysql_sql.y:16135 - { - value, ok := typeLengthIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - yyLOCAL = tree.GetDisplayWith(value) - } - yyVAL.union = yyLOCAL - case 2382: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.LengthScaleOpt -//line mysql_sql.y:16143 - { - yyLOCAL = tree.LengthScaleOpt{ - DisplayWith: tree.NotDefineDisplayWidth, - Scale: tree.NotDefineDec, - } - } - yyVAL.union = yyLOCAL - case 2383: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.LengthScaleOpt -//line mysql_sql.y:16150 - { - value, ok := typeLengthIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - yyLOCAL = tree.LengthScaleOpt{ - DisplayWith: tree.GetDisplayWith(value), - Scale: tree.NotDefineDec, - } - } - yyVAL.union = yyLOCAL - case 2384: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.LengthScaleOpt -//line mysql_sql.y:16159 - { - width, ok := typeLengthIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - scale, ok := typeLengthIntegral(yylex, yyDollar[4].item) - if !ok { - goto ret1 - } - yyLOCAL = tree.LengthScaleOpt{ - DisplayWith: tree.GetDisplayWith(width), - Scale: scale, - } - } - yyVAL.union = yyLOCAL - case 2385: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL tree.LengthScaleOpt -//line mysql_sql.y:16172 - { - yyLOCAL = tree.LengthScaleOpt{ - DisplayWith: 10, // MySQL default precision for DECIMAL/NUMERIC - Scale: 0, - } - } - yyVAL.union = yyLOCAL - case 2386: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.LengthScaleOpt -//line mysql_sql.y:16179 - { - value, ok := typeLengthIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - yyLOCAL = tree.LengthScaleOpt{ - DisplayWith: tree.GetDisplayWith(value), - Scale: 0, - } - } - yyVAL.union = yyLOCAL - case 2387: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.LengthScaleOpt -//line mysql_sql.y:16188 - { - width, ok := typeLengthIntegral(yylex, yyDollar[2].item) - if !ok { - goto ret1 - } - scale, ok := typeLengthIntegral(yylex, yyDollar[4].item) - if !ok { - goto ret1 - } - yyLOCAL = tree.LengthScaleOpt{ - DisplayWith: tree.GetDisplayWith(width), - Scale: scale, - } - } - yyVAL.union = yyLOCAL - case 2388: - yyDollar = yyS[yypt-0 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:16201 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 2389: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:16205 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 2390: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:16209 - { - yyLOCAL = false - } - yyVAL.union = yyLOCAL - case 2391: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:16215 - { - } - case 2392: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL bool -//line mysql_sql.y:16217 - { - yyLOCAL = true - } - yyVAL.union = yyLOCAL - case 2396: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:16227 - { - yyVAL.str = "" - } - case 2397: - yyDollar = yyS[yypt-1 : yypt+1] -//line mysql_sql.y:16231 - { - yyVAL.str = string(yyDollar[1].str) - } - case 2913: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:16950 - { - } - case 2914: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:16953 - { - } - case 2915: - yyDollar = yyS[yypt-0 : yypt+1] -//line mysql_sql.y:16957 - { - } - case 2916: - yyDollar = yyS[yypt-2 : yypt+1] -//line mysql_sql.y:16960 - { - } - case 2917: - yyDollar = yyS[yypt-5 : yypt+1] - var yyLOCAL tree.AlterTableOptions -//line mysql_sql.y:16970 - { - yyLOCAL = yyDollar[4].alterTableOptionsUnion() - } - yyVAL.union = yyLOCAL - case 2918: - yyDollar = yyS[yypt-7 : yypt+1] - var yyLOCAL tree.AlterTableOptions -//line mysql_sql.y:16974 - { - yyLOCAL = append(yyDollar[1].alterTableOptionsUnion(), yyDollar[6].alterTableOptionsUnion()...) - } - yyVAL.union = yyLOCAL - case 2919: - yyDollar = yyS[yypt-1 : yypt+1] - var yyLOCAL tree.AlterTableOptions -//line mysql_sql.y:16980 - { - position := tree.NewColumnPosition(tree.ColumnPositionNone, nil) - yyLOCAL = tree.AlterTableOptions{tree.NewAlterAddCol(yyDollar[1].columnTableDefUnion(), position)} - } - yyVAL.union = yyLOCAL - case 2920: - yyDollar = yyS[yypt-3 : yypt+1] - var yyLOCAL tree.AlterTableOptions -//line mysql_sql.y:16985 - { - position := tree.NewColumnPosition(tree.ColumnPositionNone, nil) - yyLOCAL = append(yyDollar[1].alterTableOptionsUnion(), tree.NewAlterAddCol(yyDollar[3].columnTableDefUnion(), position)) - } - yyVAL.union = yyLOCAL - } - goto yystack /* stack new state and value */ -} + "BIT_CAST \ No newline at end of file From 4b56d2cc690921cb2aadff7d56b395b2e37501d7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 8 Oct 2026 18:35:06 +0800 Subject: [PATCH 207/241] test(bootstrap): pin historical compensation fixtures --- pkg/bootstrap/service_statistics_upgrade_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/bootstrap/service_statistics_upgrade_test.go b/pkg/bootstrap/service_statistics_upgrade_test.go index 2569065d8a243..059916a457841 100644 --- a/pkg/bootstrap/service_statistics_upgrade_test.go +++ b/pkg/bootstrap/service_statistics_upgrade_test.go @@ -398,7 +398,7 @@ func TestStatisticsUpgradeCompensatesPostSnapshotTenantAfterRestart(t *testing.T } func TestMaybeUpgradeTenantDoesNotCacheUncommittedOrFailedChecks(t *testing.T) { - final := statisticsFinalUpgradeVersion() + final := v4_0_11.Handler.Metadata() for _, test := range []struct { name string version string @@ -483,7 +483,7 @@ func initStatisticsUpgradeThroughV4011(s *service) { func TestMaybeUpgradeTenantRechecksVersionUnderLock(t *testing.T) { runtime.RunTest("", func(runtime.Runtime) { - final := statisticsFinalUpgradeVersion() + final := v4_0_11.Handler.Metadata() reads := 0 exec := executor.NewMemExecutor(func(sql string) (executor.Result, error) { switch { @@ -513,7 +513,7 @@ func TestMaybeUpgradeTenantRechecksVersionUnderLock(t *testing.T) { func TestMaybeUpgradeTenantWaitHonorsCancellation(t *testing.T) { runtime.RunTest("", func(runtime.Runtime) { - final := statisticsFinalUpgradeVersion() + final := v4_0_11.Handler.Metadata() exec := executor.NewMemExecutor(func(sql string) (executor.Result, error) { switch { case sql == "select create_version from mo_account where account_id = 11": @@ -548,7 +548,7 @@ func TestMaybeUpgradeTenantRejectsConcurrentAccountDeletion(t *testing.T) { } t.Run(name, func(t *testing.T) { runtime.RunTest("", func(runtime.Runtime) { - final := statisticsFinalUpgradeVersion() + final := v4_0_11.Handler.Metadata() var authenticated, dropped bool exec := &statisticsTransactionTracker{SQLExecutor: executor.NewMemExecutor( func(sql string) (executor.Result, error) { From 78813e20a5588965188290770f6b86b55290af61 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 8 Oct 2026 18:38:06 +0800 Subject: [PATCH 208/241] test(udf): clean rebase upgrade imports --- pkg/cnservice/server_test.go | 2 +- pkg/tests/upgrade/upgrade_v4_0_8_statistics_test.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pkg/cnservice/server_test.go b/pkg/cnservice/server_test.go index 6b3be01f00b33..7384b011440ae 100644 --- a/pkg/cnservice/server_test.go +++ b/pkg/cnservice/server_test.go @@ -1367,7 +1367,7 @@ func TestHandleRequestPropagatesConfiguredRPCMaxMessageSize(t *testing.T) { _ lockservice.LockService, _ qclient.QueryClient, _ logservice.CNHAKeeperClient, - _ udf.Service, + _ udf.Runtime, _ client.TxnClient, _ *defines.AutoIncrCacheManager, _ func() morpc.Message, diff --git a/pkg/tests/upgrade/upgrade_v4_0_8_statistics_test.go b/pkg/tests/upgrade/upgrade_v4_0_8_statistics_test.go index 3708cc21f685d..cecdb06ace3e5 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_8_statistics_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_8_statistics_test.go @@ -25,7 +25,6 @@ import ( "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_8" "github.com/matrixorigin/matrixone/pkg/catalog" - "github.com/matrixorigin/matrixone/pkg/cnservice" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/embed" "github.com/matrixorigin/matrixone/pkg/frontend" From 5dd39d26860bfc0b81cfacb1653982dada551dc0 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 9 Oct 2026 02:00:49 +0800 Subject: [PATCH 209/241] fix(udf): preserve routine catalogs across restore --- docs/design/python_udf_current_stage.md | 14 +- .../python_udf_current_stage_approval.md | 6 +- pkg/bootstrap/versions/v4_0_12/upgrade.go | 20 +- .../versions/v4_0_12/upgrade_test.go | 306 +++++++----------- pkg/bootstrap/versions/v4_0_13/upgrade.go | 15 +- .../versions/v4_0_13/upgrade_test.go | 231 ++++++++++++- pkg/frontend/pitr.go | 5 +- pkg/frontend/snapshot.go | 5 +- pkg/frontend/snapshot_restore_with_ts.go | 5 +- ...est.go => upgrade_v4_0_13_routine_test.go} | 18 +- 10 files changed, 376 insertions(+), 249 deletions(-) rename pkg/tests/upgrade/{upgrade_v4_0_12_routine_test.go => upgrade_v4_0_13_routine_test.go} (95%) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 8a9b87ab1a768..26b50a21c6365 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r3-2026-10-05` | +| Design revision | `python-udf-current-stage-r4-2026-10-09` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `c65991043b10fb39988d45b72af1485560ac5433` (MORPC 106, catalog 4.0.11) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r3 repair adds catalog 4.0.12 and protocol 107 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `9df2c4006142a0593f9bb4c40019ee1a8cd2cde7` (MORPC 106, catalog 4.0.12) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r4 repair adds catalog 4.0.13 and protocol 107 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -87,9 +87,9 @@ demo's old execution behavior is not a compatibility promise. Upgrade `4.0.7` contains the original idempotent shared-function schema entries. Its historical protocol-61 requirement belongs to the already-shipped provenance contract; it does not prove Python revision capability. The registered repair -`4.0.12` (minimum direct source `4.0.11`) replays only the nine shared-function -entries. Upstream handlers `4.0.8` through `4.0.11` remain unchanged. Thus a tenant -already at upstream final `4.0.11`, including one lacking revision tables, still +`4.0.13` (minimum direct source `4.0.12`) replays only the nine shared-function +entries. Upstream handlers `4.0.8` through `4.0.12` remain unchanged. Thus a tenant +already at upstream final `4.0.12`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata requires protocol 107 before tenant tasks are created, and the repair handler @@ -245,7 +245,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-107 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_12/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases; real persisted-service upgrade and downgrade are not verified by those mocks. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-107 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_13/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases; real persisted-service upgrade and downgrade are not verified by those mocks. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index e2a00c26c01ca..27809fff7345d 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r3-2026-10-05`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r4-2026-10-09`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -77,3 +77,7 @@ historical approval only; they are not the current proposal's content identity. Architecture and SQL/Planner approval remain pending, as recorded in reviews 5302243148 and the exact-head review on 4ca229411166b9da09a702dbe1b799de43d8d694. Code review and passing tests do not substitute for those independent decisions. + +## r4 rebase maintenance addendum (2026-10-09) + +Against upstream `9df2c4006142a0593f9bb4c40019ee1a8cd2cde7`, the current repair catalog is 4.0.13 with minimum direct source 4.0.12. Upstream 4.0.12 owns the charset metadata refresh and remains unchanged. The shared-function repair replays its nine entries only in the new handler, so already-upgraded 4.0.12 tenants are scheduled. Protocol admission remains 107, immediate predecessor 106. This mechanical rebase correction and the historical-schema lookup correction for snapshot/TS/PITR restore remain within the existing development scope; independent approval remains pending. diff --git a/pkg/bootstrap/versions/v4_0_12/upgrade.go b/pkg/bootstrap/versions/v4_0_12/upgrade.go index ba48b616dcddc..d853f7a45c5fc 100644 --- a/pkg/bootstrap/versions/v4_0_12/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_12/upgrade.go @@ -19,7 +19,6 @@ import ( "time" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/catalog" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/runtime" @@ -28,19 +27,17 @@ import ( "go.uber.org/zap" ) -// 4.0.12 replays only the idempotent shared Python UDF catalog entries. -// An upstream-final 4.0.11 tenant may lack these entries; a strictly newer -// registered handler ensures the upgrade framework schedules their repair. -// Earlier tenants first traverse the unchanged upstream handlers through -// 4.0.11. Complete, partial and absent revision schemas converge on retry. +// Already-upgraded tenants must run the charset metadata refresh. An offset +// change is insufficient: old tenant workers compare only ToVersion. Keep the +// preceding semantic upgrade and its protocol floor; no new key format is enabled. var Handler = &versionHandle{ metadata: versions.Version{ Version: "4.0.12", MinUpgradeVersion: "4.0.11", UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, - VersionOffset: uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), - RequiredProtocolVersion: defines.MORPCVersion107, + VersionOffset: uint32(len(tenantUpgEntries)), + RequiredProtocolVersion: defines.MORPCVersion106, }, } @@ -58,13 +55,8 @@ func (v *versionHandle) Prepare(ctx context.Context, txn executor.TxnExecutor, f } func (v *versionHandle) HandleTenantUpgrade(ctx context.Context, tenantID int32, txn executor.TxnExecutor) error { - // Login compensation invokes this handler without the cluster-upgrade - // scheduler, so enforce the same floor before any catalog mutation. - if err := versions.CheckCommonProtocolVersion(txn, v.metadata.RequiredProtocolVersion); err != nil { - return err - } logger := runtime.ServiceRuntime(txn.Txn().TxnOptions().CN).Logger() - for _, entry := range v4_0_7.PythonRevisionUpgradeEntries() { + for _, entry := range tenantUpgEntries { start := time.Now() if err := entry.Upgrade(txn, uint32(tenantID)); err != nil { logger.Error("tenant upgrade entry execute error", diff --git a/pkg/bootstrap/versions/v4_0_12/upgrade_test.go b/pkg/bootstrap/versions/v4_0_12/upgrade_test.go index 185ba1ddb8d69..f213b055f08e2 100644 --- a/pkg/bootstrap/versions/v4_0_12/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_12/upgrade_test.go @@ -15,221 +15,143 @@ package v4_0_12 import ( - "context" - "fmt" - "strings" + "errors" "testing" "github.com/golang/mock/gomock" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/defines" mock_frontend "github.com/matrixorigin/matrixone/pkg/frontend/test" - "github.com/matrixorigin/matrixone/pkg/pb/txn" + pbtxn "github.com/matrixorigin/matrixone/pkg/pb/txn" "github.com/matrixorigin/matrixone/pkg/util/executor" + "github.com/matrixorigin/matrixone/pkg/util/sysview" "github.com/stretchr/testify/require" ) -func TestPythonRevisionRepairUpgradePath(t *testing.T) { - metadata := Handler.Metadata() - require.Equal(t, "4.0.12", metadata.Version) - require.Equal(t, "4.0.11", metadata.MinUpgradeVersion) - require.Equal(t, versions.No, metadata.UpgradeCluster) - require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(107), metadata.RequiredProtocolVersion) - require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) - require.True(t, metadata.CanDirectUpgrade("4.0.11")) - require.False(t, metadata.CanDirectUpgrade("4.0.7")) - require.Len(t, v4_0_7.PythonRevisionUpgradeEntries(), 9) +func TestCharacterSetsUpgradeMetadata(t *testing.T) { + m := Handler.Metadata() + require.Equal(t, "4.0.12", m.Version) + require.Equal(t, "4.0.11", m.MinUpgradeVersion) + require.Equal(t, versions.Yes, m.UpgradeTenant) + require.Equal(t, versions.No, m.UpgradeCluster) + require.Equal(t, defines.MORPCVersion106, m.RequiredProtocolVersion) + require.Equal(t, uint32(1), m.VersionOffset) + check := sysview.InformationSchemaCharacterSetsCheckSQL() + require.Contains(t, check, "(SELECT COUNT(*) FROM information_schema.CHARACTER_SETS) = 3") + require.Contains(t, check, "CHARACTER_SET_NAME = 'utf8' AND DEFAULT_COLLATE_NAME = 'utf8_general_ci' AND MAXLEN = 4") + require.NotContains(t, check, "MAXLEN = 3") } -func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { - for _, response := range []string{ - `{"result":"cn-a:106"}`, - `{"result":"cn-a:107,cn-b:106"}`, - `{"result":""}`, - `invalid`, - } { - t.Run(response, func(t *testing.T) { - var statements []string - txn := executor.NewMemTxnExecutor(func(statement string) (executor.Result, error) { - statements = append(statements, statement) - require.Equal(t, "SELECT mo_ctl('cn', 'GetProtocolVersion', '')", statement) - return repairStringResult(t, response), nil - }, nil) - err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 107") - require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) - }) +type scopedTxn struct { + executor.TxnExecutor + t *testing.T + accountID uint32 +} + +func (txn scopedTxn) Exec(sql string, options executor.StatementOption) (executor.Result, error) { + if sql != "SELECT mo_ctl('cn', 'GetProtocolVersion', '')" { + require.True(txn.t, options.HasAccountID()) + require.Equal(txn.t, txn.accountID, options.AccountID()) } + return txn.TxnExecutor.Exec(sql, options) } -func TestPythonRevisionRepairIsIdempotentForCatalogStates(t *testing.T) { - for _, test := range []struct { - name string - schemaOrigin string - columns []string - newIndex bool - legacyIndex bool - revisionTable bool - wantFirstDDL int +func TestCharacterSetsUpgradeAdmissionAndRetry(t *testing.T) { + entry := refreshInformationSchemaCharacterSets() + const protocolSQL = "SELECT mo_ctl('cn', 'GetProtocolVersion', '')" + checkSQL := sysview.InformationSchemaCharacterSetsCheckSQL() + injected := errors.New("injected charset metadata upgrade failure") + for _, tc := range []struct { + name string + ready bool + protocol string + failSQL string + wantErr bool + wantSQL []string }{ - { - name: "upstream_final_4.0.11_missed_catalog", - schemaOrigin: "4.0.11", - legacyIndex: true, - wantFirstDDL: 9, - }, - { - name: "partial_revision_catalog", - schemaOrigin: "4.0.8", - columns: []string{ - "active_revision", "namespace_version", "canonical_input_descriptor", - "return_descriptor", "signature_key_schema_version", "signature_fingerprint", - }, - legacyIndex: true, - wantFirstDDL: 3, - }, - { - name: "complete_revision_catalog", - schemaOrigin: "4.0.8", - columns: []string{ - "active_revision", "namespace_version", "canonical_input_descriptor", - "return_descriptor", "signature_key_schema_version", "signature_fingerprint", - }, - newIndex: true, - revisionTable: true, - wantFirstDDL: 0, - }, + {name: "legacy utf8 maxlen three", protocol: `{"result":"cn0:106,cn1:106"}`, + wantSQL: []string{checkSQL, protocolSQL, entry.PreSql, entry.UpgSql}}, + {name: "fresh canonical catalog", ready: true, wantSQL: []string{checkSQL}}, + {name: "failed check", failSQL: checkSQL, wantErr: true, wantSQL: []string{checkSQL}}, + {name: "mixed protocol", protocol: `{"result":"cn0:106,cn1:105"}`, wantErr: true, + wantSQL: []string{checkSQL, protocolSQL}}, + {name: "failed protocol", failSQL: protocolSQL, wantErr: true, + wantSQL: []string{checkSQL, protocolSQL}}, + {name: "failed delete", protocol: `{"result":"cn0:106"}`, failSQL: entry.PreSql, wantErr: true, + wantSQL: []string{checkSQL, protocolSQL, entry.PreSql}}, + {name: "failed insert", protocol: `{"result":"cn0:106"}`, failSQL: entry.UpgSql, wantErr: true, + wantSQL: []string{checkSQL, protocolSQL, entry.PreSql, entry.UpgSql}}, } { - t.Run(test.name, func(t *testing.T) { + t.Run(tc.name, func(t *testing.T) { runtime.RunTest("", func(runtime.Runtime) { - state := &pythonRevisionCatalogState{ - columns: make(map[string]bool), - newIndex: test.newIndex, - legacyIndex: test.legacyIndex, - revisionTable: test.revisionTable, + operator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) + operator.EXPECT().TxnOptions().Return(pbtxn.TxnOptions{}).AnyTimes() + mp := mpool.MustNewZero() + defer func() { + require.Zero(t, mp.CurrNB()) + mpool.DeleteMPool(mp) + }() + result := func(value string) executor.Result { + r := executor.NewMemResult([]types.Type{types.T_varchar.ToType()}, mp) + if value != "" { + r.NewBatchWithRowCount(1) + require.NoError(t, executor.AppendStringRows(r, 0, []string{value})) + } + return r.GetResult() + } + var calls []string + ready := tc.ready + failSQL := tc.failSQL + protocol := tc.protocol + txn := scopedTxn{t: t, accountID: 7, TxnExecutor: executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { + calls = append(calls, sql) + if sql == failSQL { + return executor.Result{}, injected + } + switch sql { + case checkSQL: + if ready { + return result("1"), nil + } + return result(""), nil + case protocolSQL: + return result(protocol), nil + case entry.PreSql: + ready = false + case entry.UpgSql: + ready = true + default: + t.Fatalf("unexpected SQL: %s", sql) + } + return executor.Result{}, nil + }, operator)} + require.NoError(t, Handler.Prepare(t.Context(), txn, true)) + require.NoError(t, Handler.HandleClusterUpgrade(t.Context(), txn)) + require.Error(t, Handler.HandleCreateFrameworkDeps(txn)) + err := Handler.HandleTenantUpgrade(t.Context(), 7, txn) + if tc.failSQL != "" { + require.ErrorIs(t, err, injected) + } else if tc.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) } - for _, column := range test.columns { - state.columns[column] = true + require.Equal(t, tc.wantSQL, calls) + if tc.wantErr { + // The owner transaction rolls back failed entries. On retry the + // handler must execute the repair, not treat MAXLEN=3 as ready. + ready, failSQL, protocol = false, "", `{"result":"cn0:106"}` + calls = nil + require.NoError(t, Handler.HandleTenantUpgrade(t.Context(), 7, txn)) + require.Equal(t, []string{checkSQL, protocolSQL, entry.PreSql, entry.UpgSql}, calls) } - txn := newRepairTxnExecutor(t, state) - require.NoError(t, Handler.Prepare(context.Background(), txn, true)) - require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) - require.Len(t, state.ddl, test.wantFirstDDL, - "repair of %s schema must apply only missing catalog objects", test.schemaOrigin) - firstDDL := append([]string(nil), state.ddl...) - require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) - require.Equal(t, firstDDL, state.ddl, - "a restart/retry of %s schema must not repeat DDL", test.schemaOrigin) + calls = nil + require.NoError(t, Handler.HandleTenantUpgrade(t.Context(), 7, txn)) + require.Equal(t, []string{checkSQL}, calls, "a completed refresh must be idempotent") }) }) } } - -type pythonRevisionCatalogState struct { - columns map[string]bool - newIndex bool - legacyIndex bool - revisionTable bool - ddl []string -} - -func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) executor.TxnExecutor { - t.Helper() - txnOperator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) - txnOperator.EXPECT().TxnOptions().Return(txn.TxnOptions{}).AnyTimes() - return executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { - lower := strings.ToLower(sql) - switch { - case strings.Contains(lower, "from mo_catalog.mo_columns"): - for column := range state.columns { - if strings.Contains(sql, fmt.Sprintf("attname = '%s'", column)) { - return repairColumnResult(t), nil - } - } - return executor.Result{}, nil - case strings.Contains(lower, "from `mo_catalog`.`mo_indexes`"): - if strings.Contains(sql, "name_db_arg_types_descriptor") && state.newIndex { - return repairStringResult(t, "name_db_arg_types_descriptor"), nil - } - if strings.Contains(sql, "name_db_arg_types'") && state.legacyIndex { - return repairStringResult(t, "name_db_arg_types"), nil - } - return executor.Result{}, nil - case strings.Contains(lower, "from mo_catalog.mo_tables"): - if state.revisionTable && strings.Contains(sql, "relname = 'mo_function_revisions'") { - return repairStringResult(t, "mo_function_revisions"), nil - } - return executor.Result{}, nil - case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:107"}`), nil - case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): - for column := range state.columns { - if strings.Contains(sql, "add column "+column+" ") { - return executor.Result{}, nil - } - } - for _, column := range []string{ - "active_revision", "namespace_version", "canonical_input_descriptor", - "return_descriptor", "signature_key_schema_version", "signature_fingerprint", - } { - if strings.Contains(sql, "add column "+column+" ") { - state.columns[column] = true - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - } - } - case strings.Contains(lower, "create unique index name_db_arg_types_descriptor"): - state.newIndex = true - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - case strings.Contains(lower, "drop index name_db_arg_types"): - state.legacyIndex = false - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - case strings.Contains(lower, "create table mo_catalog.mo_function_revisions"): - state.revisionTable = true - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - default: - return executor.Result{}, fmt.Errorf("unexpected repair SQL: %s", sql) - } - return executor.Result{}, nil - }, txnOperator) -} - -func repairStringResult(t *testing.T, value string) executor.Result { - t.Helper() - mp := mpool.MustNewZeroNoFixed() - t.Cleanup(func() { mpool.DeleteMPool(mp) }) - result := executor.NewMemResult([]types.Type{types.T_varchar.ToType()}, mp) - result.NewBatchWithRowCount(1) - require.NoError(t, executor.AppendStringRows(result, 0, []string{value})) - return result.GetResult() -} - -func repairColumnResult(t *testing.T) executor.Result { - t.Helper() - mp := mpool.MustNewZeroNoFixed() - t.Cleanup(func() { mpool.DeleteMPool(mp) }) - result := executor.NewMemResult([]types.Type{ - types.T_varchar.ToType(), types.T_varchar.ToType(), - types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), - types.T_int32.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), - }, mp) - result.NewBatchWithRowCount(1) - require.NoError(t, executor.AppendStringRows(result, 0, []string{"BIGINT UNSIGNED"})) - require.NoError(t, executor.AppendStringRows(result, 1, []string{"NO"})) - require.NoError(t, executor.AppendFixedRows(result, 2, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 3, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 4, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 5, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 6, []int32{1})) - require.NoError(t, executor.AppendStringRows(result, 7, []string{"0"})) - require.NoError(t, executor.AppendStringRows(result, 8, []string{""})) - require.NoError(t, executor.AppendStringRows(result, 9, []string{""})) - return result.GetResult() -} diff --git a/pkg/bootstrap/versions/v4_0_13/upgrade.go b/pkg/bootstrap/versions/v4_0_13/upgrade.go index ed5295b8638a3..139ab564ca495 100644 --- a/pkg/bootstrap/versions/v4_0_13/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_13/upgrade.go @@ -19,6 +19,7 @@ import ( "time" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/catalog" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/runtime" @@ -27,9 +28,10 @@ import ( "go.uber.org/zap" ) -// Use a new semantic version after the existing 4.0.11 CDC and 4.0.12 -// CHARACTER_SETS migrations. An old worker must not treat this STATISTICS -// refresh as already handled merely because it knows one of those versions. +// 4.0.13 replays the idempotent shared Python UDF catalog entries together +// with the statistics view refresh introduced by the preceding main revision. +// An upstream-final 4.0.12 tenant may lack either set of objects; the newer +// handler converges both sets on retry after all CNs support MORPC v108. var Handler = &versionHandle{ metadata: versions.Version{ Version: "4.0.13", @@ -37,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion107, + RequiredProtocolVersion: defines.MORPCVersion108, }, } @@ -55,6 +57,11 @@ func (v *versionHandle) Prepare(_ context.Context, txn executor.TxnExecutor, _ b } func (v *versionHandle) HandleTenantUpgrade(_ context.Context, tenantID int32, txn executor.TxnExecutor) error { + // Login compensation invokes this handler without the cluster-upgrade + // scheduler, so enforce the same floor before any catalog mutation. + if err := versions.CheckCommonProtocolVersion(txn, v.metadata.RequiredProtocolVersion); err != nil { + return err + } logger := runtime.ServiceRuntime(txn.Txn().TxnOptions().CN).Logger() for _, entry := range tenantUpgEntries { start := time.Now() diff --git a/pkg/bootstrap/versions/v4_0_13/upgrade_test.go b/pkg/bootstrap/versions/v4_0_13/upgrade_test.go index 2fad53a90628e..ec4e0a356a610 100644 --- a/pkg/bootstrap/versions/v4_0_13/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_13/upgrade_test.go @@ -17,11 +17,13 @@ package v4_0_13 import ( "context" "errors" + "fmt" "strings" "testing" "github.com/golang/mock/gomock" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/catalog" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/common/runtime" @@ -34,16 +36,209 @@ import ( "github.com/stretchr/testify/require" ) -func TestStatisticsUpgradeMetadata(t *testing.T) { - m := Handler.Metadata() - require.Equal(t, "4.0.13", m.Version) - require.Equal(t, "4.0.12", m.MinUpgradeVersion) - require.Equal(t, versions.Yes, m.UpgradeTenant) - require.Equal(t, versions.No, m.UpgradeCluster) - require.Equal(t, defines.MORPCVersion107, m.RequiredProtocolVersion) - require.Equal(t, uint32(1), m.VersionOffset) - require.Len(t, tenantUpgEntries, 1) - require.Equal(t, int64(defines.MORPCVersion107), tenantUpgEntries[0].RequiredProtocolVersion) +func TestPythonRevisionRepairUpgradePath(t *testing.T) { + metadata := Handler.Metadata() + require.Equal(t, "4.0.13", metadata.Version) + require.Equal(t, "4.0.12", metadata.MinUpgradeVersion) + require.Equal(t, versions.No, metadata.UpgradeCluster) + require.Equal(t, versions.Yes, metadata.UpgradeTenant) + require.Equal(t, int64(defines.MORPCVersion108), metadata.RequiredProtocolVersion) + require.Equal(t, uint32(len(tenantUpgEntries)), metadata.VersionOffset) + require.Len(t, tenantUpgEntries, len(v4_0_7.PythonRevisionUpgradeEntries())+1) + require.True(t, metadata.CanDirectUpgrade("4.0.12")) + require.False(t, metadata.CanDirectUpgrade("4.0.7")) + require.Len(t, v4_0_7.PythonRevisionUpgradeEntries(), 9) +} + +func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { + for _, response := range []string{ + `{"result":"cn-a:107"}`, + `{"result":"cn-a:108,cn-b:107"}`, + `{"result":""}`, + `invalid`, + } { + t.Run(response, func(t *testing.T) { + var statements []string + txn := executor.NewMemTxnExecutor(func(statement string) (executor.Result, error) { + statements = append(statements, statement) + require.Equal(t, "SELECT mo_ctl('cn', 'GetProtocolVersion', '')", statement) + return repairStringResult(t, response), nil + }, nil) + err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 108") + require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) + }) + } +} + +func TestPythonRevisionRepairIsIdempotentForCatalogStates(t *testing.T) { + for _, test := range []struct { + name string + schemaOrigin string + columns []string + newIndex bool + legacyIndex bool + revisionTable bool + wantFirstDDL int + }{ + { + name: "upstream_final_4.0.12_missed_catalog", + schemaOrigin: "4.0.12", + legacyIndex: true, + wantFirstDDL: 9, + }, + { + name: "partial_revision_catalog", + schemaOrigin: "4.0.8", + columns: []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + }, + legacyIndex: true, + wantFirstDDL: 3, + }, + { + name: "complete_revision_catalog", + schemaOrigin: "4.0.8", + columns: []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + }, + newIndex: true, + revisionTable: true, + wantFirstDDL: 0, + }, + } { + t.Run(test.name, func(t *testing.T) { + runtime.RunTest("", func(runtime.Runtime) { + state := &pythonRevisionCatalogState{ + columns: make(map[string]bool), + newIndex: test.newIndex, + legacyIndex: test.legacyIndex, + revisionTable: test.revisionTable, + } + for _, column := range test.columns { + state.columns[column] = true + } + txn := newRepairTxnExecutor(t, state) + require.NoError(t, Handler.Prepare(context.Background(), txn, true)) + require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) + require.Len(t, state.ddl, test.wantFirstDDL, + "repair of %s schema must apply only missing catalog objects", test.schemaOrigin) + firstDDL := append([]string(nil), state.ddl...) + require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) + require.Equal(t, firstDDL, state.ddl, + "a restart/retry of %s schema must not repeat DDL", test.schemaOrigin) + }) + }) + } +} + +type pythonRevisionCatalogState struct { + columns map[string]bool + newIndex bool + legacyIndex bool + revisionTable bool + ddl []string +} + +func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) executor.TxnExecutor { + t.Helper() + txnOperator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) + txnOperator.EXPECT().TxnOptions().Return(txn.TxnOptions{}).AnyTimes() + return executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { + lower := strings.ToLower(sql) + switch { + case strings.Contains(lower, "from mo_catalog.mo_columns"): + for column := range state.columns { + if strings.Contains(sql, fmt.Sprintf("attname = '%s'", column)) { + return repairColumnResult(t), nil + } + } + return executor.Result{}, nil + case strings.Contains(lower, "from `mo_catalog`.`mo_indexes`"): + if strings.Contains(sql, "name_db_arg_types_descriptor") && state.newIndex { + return repairStringResult(t, "name_db_arg_types_descriptor"), nil + } + if strings.Contains(sql, "name_db_arg_types'") && state.legacyIndex { + return repairStringResult(t, "name_db_arg_types"), nil + } + return executor.Result{}, nil + case strings.HasPrefix(sql, "SELECT tbl.rel_createsql"): + return repairStringResult(t, sysview.InformationSchemaStatisticsDDL), nil + case strings.Contains(lower, "from mo_catalog.mo_tables"): + if state.revisionTable && strings.Contains(sql, "relname = 'mo_function_revisions'") { + return repairStringResult(t, "mo_function_revisions"), nil + } + return executor.Result{}, nil + case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:108"}`), nil + case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): + for column := range state.columns { + if strings.Contains(sql, "add column "+column+" ") { + return executor.Result{}, nil + } + } + for _, column := range []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + } { + if strings.Contains(sql, "add column "+column+" ") { + state.columns[column] = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + } + } + case strings.Contains(lower, "create unique index name_db_arg_types_descriptor"): + state.newIndex = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + case strings.Contains(lower, "drop index name_db_arg_types"): + state.legacyIndex = false + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + case strings.Contains(lower, "create table mo_catalog.mo_function_revisions"): + state.revisionTable = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + default: + return executor.Result{}, fmt.Errorf("unexpected repair SQL: %s", sql) + } + return executor.Result{}, nil + }, txnOperator) +} + +func repairStringResult(t *testing.T, value string) executor.Result { + t.Helper() + mp := mpool.MustNewZeroNoFixed() + t.Cleanup(func() { mpool.DeleteMPool(mp) }) + result := executor.NewMemResult([]types.Type{types.T_varchar.ToType()}, mp) + result.NewBatchWithRowCount(1) + require.NoError(t, executor.AppendStringRows(result, 0, []string{value})) + return result.GetResult() +} + +func repairColumnResult(t *testing.T) executor.Result { + t.Helper() + mp := mpool.MustNewZeroNoFixed() + t.Cleanup(func() { mpool.DeleteMPool(mp) }) + result := executor.NewMemResult([]types.Type{ + types.T_varchar.ToType(), types.T_varchar.ToType(), + types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), + types.T_int32.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), + }, mp) + result.NewBatchWithRowCount(1) + require.NoError(t, executor.AppendStringRows(result, 0, []string{"BIGINT UNSIGNED"})) + require.NoError(t, executor.AppendStringRows(result, 1, []string{"NO"})) + require.NoError(t, executor.AppendFixedRows(result, 2, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 3, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 4, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 5, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 6, []int32{1})) + require.NoError(t, executor.AppendStringRows(result, 7, []string{"0"})) + require.NoError(t, executor.AppendStringRows(result, 8, []string{""})) + require.NoError(t, executor.AppendStringRows(result, 9, []string{""})) + return result.GetResult() } func TestStatisticsUpgradeLifecycle(t *testing.T) { @@ -52,12 +247,16 @@ func TestStatisticsUpgradeLifecycle(t *testing.T) { operator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) operator.EXPECT().TxnOptions().Return(pbtxn.TxnOptions{}).AnyTimes() txn := executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { - require.True(t, strings.HasPrefix(sql, "SELECT tbl.rel_createsql"), sql) - mp := mpool.MustNewZero() - r := executor.NewMemResult([]types.Type{types.T_varchar.ToType()}, mp) - r.NewBatchWithRowCount(1) - require.NoError(t, executor.AppendStringRows(r, 0, []string{sysview.InformationSchemaStatisticsDDL})) - return r.GetResult(), nil + switch { + case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:108"}`), nil + case strings.HasPrefix(sql, "SELECT tbl.rel_createsql"): + return repairStringResult(t, sysview.InformationSchemaStatisticsDDL), nil + default: + // The Python entries are independently covered above; allow their + // idempotent probes and DDLs to complete in this focused test. + return executor.Result{}, nil + } }, operator) require.NoError(t, Handler.Prepare(ctx, txn, true)) require.NoError(t, Handler.HandleTenantUpgrade(ctx, int32(catalog.System_Account), txn)) diff --git a/pkg/frontend/pitr.go b/pkg/frontend/pitr.go index 28b99c1f7c420..cf9738703ebe4 100644 --- a/pkg/frontend/pitr.go +++ b/pkg/frontend/pitr.go @@ -2075,8 +2075,9 @@ func restoreSystemDatabaseWithPitr( } getLogger(sid).Info(fmt.Sprintf("[%s] start to restore system table: %v.%v", pitrName, moCatalog, tblInfo.tblName)) - // Sequences use their CREATE definition; table schemas belong to CLONE. - if isSequence(tblInfo) { + // Sequences need their definition; routine catalogs need the source + // schema to preserve revision metadata. Other schemas belong to CLONE. + if isSequence(tblInfo) || isCurrentSchemaUserDefinedFunctionCatalog(tblInfo) || isCurrentFunctionRevisionCatalog(tblInfo) { tblInfo.createSql, err = getCreateTableSqlWithTs(ctx, bh, ts, dbName, tblInfo.tblName) if err != nil { return err diff --git a/pkg/frontend/snapshot.go b/pkg/frontend/snapshot.go index 1babc52d1ce32..8981f0c106200 100644 --- a/pkg/frontend/snapshot.go +++ b/pkg/frontend/snapshot.go @@ -1710,8 +1710,9 @@ func restoreSystemDatabase( } getLogger(sid).Debug(fmt.Sprintf("[%s] start to restore system table: %v.%v", snapshotName, moCatalog, tblInfo.tblName)) - // Sequences use their CREATE definition; table schemas belong to CLONE. - if isSequence(tblInfo) { + // Sequences need their definition; routine catalogs need the source + // schema to preserve revision metadata. Other schemas belong to CLONE. + if isSequence(tblInfo) || isCurrentSchemaUserDefinedFunctionCatalog(tblInfo) || isCurrentFunctionRevisionCatalog(tblInfo) { tblInfo.createSql, err = getCreateTableSql(ctx, bh, tempSnap, dbName, tblInfo.tblName) if err != nil { return err diff --git a/pkg/frontend/snapshot_restore_with_ts.go b/pkg/frontend/snapshot_restore_with_ts.go index f51504ccae5dc..37f355788bd67 100644 --- a/pkg/frontend/snapshot_restore_with_ts.go +++ b/pkg/frontend/snapshot_restore_with_ts.go @@ -666,8 +666,9 @@ func restoreSystemDatabaseFromTS( } getLogger(sid).Info(fmt.Sprintf("[%d:%d] start to restore system table: %v.%v", restoreAccount, snapshotTs, moCatalog, tblInfo.tblName)) - // Sequences use their CREATE definition; table schemas belong to CLONE. - if isSequence(tblInfo) { + // Sequences need their definition; routine catalogs need the source + // schema to preserve revision metadata. Other schemas belong to CLONE. + if isSequence(tblInfo) || isCurrentSchemaUserDefinedFunctionCatalog(tblInfo) || isCurrentFunctionRevisionCatalog(tblInfo) { tblInfo.createSql, err = getCreateTableSqlFromTS(ctx, bh, dbName, tblInfo.tblName, snapshotTs, restoreAccount, toAccountId) if err != nil { return err diff --git a/pkg/tests/upgrade/upgrade_v4_0_12_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_13_routine_test.go similarity index 95% rename from pkg/tests/upgrade/upgrade_v4_0_12_routine_test.go rename to pkg/tests/upgrade/upgrade_v4_0_13_routine_test.go index ea7b3db5d9952..1ff21a6362cb1 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_12_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_13_routine_test.go @@ -23,7 +23,7 @@ import ( "time" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_12" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_13" "github.com/matrixorigin/matrixone/pkg/catalog" moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -36,7 +36,7 @@ import ( // Reuse the upgrade package's single-CN fixture. A late tenant must be repaired // on its first real login, even when the cluster has already completed upgrade. -func TestV4012LoginRepairsLegacyRoutineCatalog(t *testing.T) { +func TestV4013LoginRepairsLegacyRoutineCatalog(t *testing.T) { embed.RunSingleCNBaseClusterTests(t, func(cluster embed.Cluster) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() @@ -46,7 +46,7 @@ func TestV4012LoginRepairsLegacyRoutineCatalog(t *testing.T) { systemDB, err := sql.Open("mysql", fmt.Sprintf("dump:111@tcp(127.0.0.1:%d)/", port)) require.NoError(t, err) defer systemDB.Close() - const account = "routine_repair_4012" + const account = "routine_repair_4013" _, err = systemDB.ExecContext(ctx, "create account "+account+" ADMIN_NAME 'root' IDENTIFIED BY '111'") require.NoError(t, err) defer func() { @@ -77,7 +77,7 @@ func TestV4012LoginRepairsLegacyRoutineCatalog(t *testing.T) { } res.Close() } - return versions.UpgradeTenantVersion(int32(accountID), "4.0.11", txn) + return versions.UpgradeTenantVersion(int32(accountID), "4.0.12", txn) }, executor.Options{}.WithDatabase(catalog.MO_CATALOG). WithAccountID(catalog.System_Account).WithWaitCommittedLogApplied())) var functionID uint64 @@ -112,7 +112,7 @@ func TestV4012LoginRepairsLegacyRoutineCatalog(t *testing.T) { return nil }, executor.Options{}.WithDatabase(catalog.MO_CATALOG).WithAccountID(catalog.System_Account))) } - checkCatalog("4.0.11", false) + checkCatalog("4.0.12", false) rt := moruntime.ServiceRuntime(cn.ServiceID()) original, present := rt.GetGlobalVariables(moruntime.MOProtocolVersion) require.True(t, present) @@ -127,7 +127,7 @@ func TestV4012LoginRepairsLegacyRoutineCatalog(t *testing.T) { defer db.Close() require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 107") }() - checkCatalog("4.0.11", false) + checkCatalog("4.0.12", false) tenantDB, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer tenantDB.Close() @@ -140,18 +140,18 @@ func TestV4012LoginRepairsLegacyRoutineCatalog(t *testing.T) { require.Equal(t, int64(12), result) } checkResult() - checkCatalog("4.0.12", true) + checkCatalog("4.0.13", true) // Explicit replay reaches the handler; a cached second login would not // prove that its DDL is idempotent against the persisted catalog. for range 2 { var mutations int require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { - return v4_0_12.Handler.HandleTenantUpgrade(ctx, int32(accountID), + return v4_0_13.Handler.HandleTenantUpgrade(ctx, int32(accountID), &routineRepairTxn{TxnExecutor: txn, mutations: &mutations}) }, executor.Options{}.WithDatabase(catalog.MO_CATALOG). WithAccountID(catalog.System_Account).WithWaitCommittedLogApplied())) require.Zero(t, mutations) - checkCatalog("4.0.12", true) + checkCatalog("4.0.13", true) checkResult() } }) From 36754a382e23d1cf1ef8fff73263cda9156b05cc Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 9 Oct 2026 02:52:07 +0800 Subject: [PATCH 210/241] test(frontend): mock routine catalog restore schema --- pkg/frontend/restore_clone_metadata_test.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pkg/frontend/restore_clone_metadata_test.go b/pkg/frontend/restore_clone_metadata_test.go index c9e29402a9d00..329030b4483dd 100644 --- a/pkg/frontend/restore_clone_metadata_test.go +++ b/pkg/frontend/restore_clone_metadata_test.go @@ -57,6 +57,15 @@ func TestCatalogRestoreMetadataOwnership(t *testing.T) { {"mo_user_defined_function", "BASE TABLE", catalog.SystemOrdinaryRel, ""}, {"mo_tables", "BASE TABLE", catalog.SystemOrdinaryRel, ""}, }) + // Routine-catalog restore obtains the source schema before copying + // rows. The three restore families use slightly different SHOW + // CREATE forms, so provide the historical DDL for each form. + sourceDDL := newMrsForRestoreStringRows([]string{"table", "create"}, [][]interface{}{ + {"mo_user_defined_function", MoCatalogMoUserDefinedFunctionDDL}, + }) + bh.sql2result[fmt.Sprintf("show create table %s.%s {MO_TS = 123}", + quoteIdentifierForSQL(moCatalog), quoteIdentifierForSQL("mo_user_defined_function"))] = sourceDDL + bh.sql2result[showCreateTableSQL(moCatalog, "mo_user_defined_function")+" {MO_TS = 123}"] = sourceDDL if scenario == "enumeration failure" { failure := moerr.NewInternalErrorNoCtx("catalog enumeration failed") bh.sql2err[list] = failure @@ -78,6 +87,12 @@ func TestCatalogRestoreMetadataOwnership(t *testing.T) { require.NoError(t, family.restore(ctx, bh)) require.Contains(t, bh.executedSQLs, clone) require.Contains(t, bh.executedSQLs, MoCatalogMoUserDefinedFunctionDDL) + sourceQuery := showCreateTableSQL(moCatalog, "mo_user_defined_function") + " {MO_TS = 123}" + if family.name == "snapshot" { + sourceQuery = fmt.Sprintf("show create table %s.%s {MO_TS = 123}", + quoteIdentifierForSQL(moCatalog), quoteIdentifierForSQL("mo_user_defined_function")) + } + require.Contains(t, bh.executedSQLs, sourceQuery) require.NotContains(t, bh.executedSQLs, restoreTableDataByTsSQL(moCatalog, "mo_tables", 123)) } else { failureSQL := clone @@ -93,7 +108,7 @@ func TestCatalogRestoreMetadataOwnership(t *testing.T) { require.Equal(t, []string{list, failureSQL}, bh.executedSQLs) } } - if scenario != "sequence read failure" { + if scenario != "sequence read failure" && scenario != "ordinary and UDF" { for _, sql := range bh.executedSQLs { require.NotContains(t, sql, "show create") } From 9ea0cd3b673b3012e0e1fcf9ab83b76a5a995f67 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 9 Oct 2026 14:29:54 +0800 Subject: [PATCH 211/241] docs(udf): clarify independent approval status --- docs/design/python_udf_current_stage.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 26b50a21c6365..1b4fbd95b74d9 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -255,6 +255,7 @@ test/development correctness and backpressure, not hostile-code containment. The reviewed change is not declared production-ready. Artifact GC/total-storage quota, cross-version migration rollback/restore, authenticated transport, and sandboxing remain explicit limits. The owner-approved acceptance is limited to -the test/development stage. This approval closes the current-stage design gate; -the reviewer must still complete the implementation/lifecycle review before the -PR review is complete. +the test/development stage. It closes the feature-owner scope record for that +limited stage; it does not close the independent Architecture or SQL/Planner +approval gate, which remains pending in the approval record. Implementation and +lifecycle review, as well as any broader enablement, remain separate decisions. From f9698ff7793978f0d430d3d32abf0d4e462b0ed7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 9 Oct 2026 16:37:35 +0800 Subject: [PATCH 212/241] fix(udf): assign fresh protocol after main rebase --- docs/design/python_udf_current_stage.md | 18 +++++++++--------- .../versions/v4_0_13/tenant_upgrade_list.go | 6 +++++- pkg/bootstrap/versions/v4_0_13/upgrade.go | 1 - pkg/bootstrap/versions/v4_0_13/upgrade_test.go | 2 +- pkg/frontend/python_udf_catalog_test.go | 6 +++--- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 ++-- .../compile/expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 10 +++++----- pkg/sql/compile/remoterun.go | 4 ++-- .../upgrade/upgrade_v4_0_13_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 13 files changed, 32 insertions(+), 29 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 1b4fbd95b74d9..ee523b58a9e60 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -5,7 +5,7 @@ | Design revision | `python-udf-current-stage-r4-2026-10-09` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | | Upstream repair baseline | `9df2c4006142a0593f9bb4c40019ee1a8cd2cde7` (MORPC 106, catalog 4.0.12) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r4 repair adds catalog 4.0.13 and protocol 107 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r4 repair adds catalog 4.0.13 and protocol 108 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -71,12 +71,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `107` (`latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `108` (`latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 107 and above, +revision that would become authoritative later. At protocol 108 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -87,25 +87,25 @@ demo's old execution behavior is not a compatibility promise. Upgrade `4.0.7` contains the original idempotent shared-function schema entries. Its historical protocol-61 requirement belongs to the already-shipped provenance contract; it does not prove Python revision capability. The registered repair -`4.0.13` (minimum direct source `4.0.12`) replays only the nine shared-function -entries. Upstream handlers `4.0.8` through `4.0.12` remain unchanged. Thus a tenant +`4.0.13` (minimum direct source `4.0.12`) replays the nine shared-function +entries together with the statistics view refresh. Upstream handlers `4.0.8` through `4.0.12` remain unchanged. Thus a tenant already at upstream final `4.0.12`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 107 before tenant tasks are created, and the repair handler +requires protocol 108 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -107. That value is rollout state in the service runtime, not a computed live +108. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 107. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 108. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -245,7 +245,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-107 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_13/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases; real persisted-service upgrade and downgrade are not verified by those mocks. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-108 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_13/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases; real persisted-service upgrade and downgrade are not verified by those mocks. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/pkg/bootstrap/versions/v4_0_13/tenant_upgrade_list.go b/pkg/bootstrap/versions/v4_0_13/tenant_upgrade_list.go index 79f4d70fbe209..ff46e38faddb2 100644 --- a/pkg/bootstrap/versions/v4_0_13/tenant_upgrade_list.go +++ b/pkg/bootstrap/versions/v4_0_13/tenant_upgrade_list.go @@ -18,12 +18,16 @@ import ( "fmt" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/defines" "github.com/matrixorigin/matrixone/pkg/util/executor" "github.com/matrixorigin/matrixone/pkg/util/sysview" ) -var tenantUpgEntries = []versions.UpgradeEntry{upgradeInformationSchemaStatistics()} +var tenantUpgEntries = append( + []versions.UpgradeEntry{upgradeInformationSchemaStatistics()}, + v4_0_7.PythonRevisionUpgradeEntries()..., +) func upgradeInformationSchemaStatistics() versions.UpgradeEntry { return versions.UpgradeEntry{ diff --git a/pkg/bootstrap/versions/v4_0_13/upgrade.go b/pkg/bootstrap/versions/v4_0_13/upgrade.go index 139ab564ca495..10e135a26bf17 100644 --- a/pkg/bootstrap/versions/v4_0_13/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_13/upgrade.go @@ -19,7 +19,6 @@ import ( "time" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/catalog" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/runtime" diff --git a/pkg/bootstrap/versions/v4_0_13/upgrade_test.go b/pkg/bootstrap/versions/v4_0_13/upgrade_test.go index ec4e0a356a610..692eb010f1c65 100644 --- a/pkg/bootstrap/versions/v4_0_13/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_13/upgrade_test.go @@ -145,7 +145,7 @@ type pythonRevisionCatalogState struct { func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) executor.TxnExecutor { t.Helper() txnOperator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) - txnOperator.EXPECT().TxnOptions().Return(txn.TxnOptions{}).AnyTimes() + txnOperator.EXPECT().TxnOptions().Return(pbtxn.TxnOptions{}).AnyTimes() return executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { lower := strings.ToLower(sql) switch { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index f4cfb37ad87fe..05961dce5cf96 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -561,7 +561,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 107"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 108"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -620,12 +620,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion106) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion107) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 107") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 108") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 1531a5423b027..b33ace364252c 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion107, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion108, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index f41319ffe15c0..faf629521f797 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,8 +37,8 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion107(t *testing.T) { - assert.Equal(t, defines.MORPCVersion107, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +func TestGetPythonUdfStatusRequiresProtocolVersion108(t *testing.T) { + assert.Equal(t, defines.MORPCVersion108, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 599f03a53168f..e4aaa12cd7f05 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion107, + {features.PythonRoutineContract, defines.MORPCVersion108, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index 3a5af414ddf6e..f2155b2f101c0 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion107) + required = max(required, defines.MORPCVersion108) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index e562574298057..4b7790f10264c 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -551,20 +551,20 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion107, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion108, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion106, defines.MORPCVersion107} { + for _, version := range []int64{defines.MORPCVersion107, defines.MORPCVersion108} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion107 { + if version < defines.MORPCVersion108 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion106) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion107) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion108) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 8958b4acb4dc8..9bfd20ad32f70 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion107) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 107") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion108) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 108") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_13_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_13_routine_test.go index 1ff21a6362cb1..adcf6618ec011 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_13_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_13_routine_test.go @@ -125,7 +125,7 @@ func TestV4013LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 107") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 108") }() checkCatalog("4.0.12", false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 1258d8b855fd1..05a4cee8ebcd2 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion107 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion108 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From 68bf72a50bd5384101cf14279e22a576ed8723bc Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 9 Oct 2026 17:51:45 +0800 Subject: [PATCH 213/241] fix(udf): preserve official catalog migrations and add v4.0.14 repair --- docs/design/python_udf_current_stage.md | 15 +- .../python_udf_current_stage_approval.md | 16 +- .../service_statistics_upgrade_test.go | 31 +-- .../versions/v4_0_13/tenant_upgrade_list.go | 6 +- pkg/bootstrap/versions/v4_0_13/upgrade.go | 14 +- .../versions/v4_0_13/upgrade_test.go | 231 ++---------------- .../versions/v4_0_14/tenant_upgrade_list.go | 42 +++- pkg/bootstrap/versions/v4_0_14/upgrade.go | 21 +- .../versions/v4_0_14/upgrade_test.go | 216 +++++++++++++++- pkg/frontend/authenticate_test.go | 2 +- .../upgrade/upgrade_v4_0_13_routine_test.go | 172 ------------- .../upgrade/upgrade_v4_0_14_routine_test.go | 176 +++++++++++++ 12 files changed, 496 insertions(+), 446 deletions(-) delete mode 100644 pkg/tests/upgrade/upgrade_v4_0_13_routine_test.go create mode 100644 pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index ee523b58a9e60..35b46294c6e54 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r4-2026-10-09` | +| Design revision | `python-udf-current-stage-r5-2026-10-09` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `9df2c4006142a0593f9bb4c40019ee1a8cd2cde7` (MORPC 106, catalog 4.0.12) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r4 repair adds catalog 4.0.13 and protocol 108 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `d7621ea017db4e43dbde9e5a855ba7b2ad920784` (MORPC 107, catalog 4.0.13) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r5 repair adds catalog 4.0.14 and protocol 108 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -87,9 +87,10 @@ demo's old execution behavior is not a compatibility promise. Upgrade `4.0.7` contains the original idempotent shared-function schema entries. Its historical protocol-61 requirement belongs to the already-shipped provenance contract; it does not prove Python revision capability. The registered repair -`4.0.13` (minimum direct source `4.0.12`) replays the nine shared-function -entries together with the statistics view refresh. Upstream handlers `4.0.8` through `4.0.12` remain unchanged. Thus a tenant -already at upstream final `4.0.12`, including one lacking revision tables, still +`4.0.14` (minimum direct source `4.0.13`) replays only the nine shared-function +entries. Upstream handlers `4.0.8` through `4.0.13`, including the protocol-107 +statistics view refresh, remain unchanged. Thus a tenant already at upstream +final `4.0.13`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata requires protocol 108 before tenant tasks are created, and the repair handler @@ -245,7 +246,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-108 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_13/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases; real persisted-service upgrade and downgrade are not verified by those mocks. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-108 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_14/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13, rejection at protocol 107 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 27809fff7345d..72f9d19d93920 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r4-2026-10-09`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r5-2026-10-09`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -81,3 +81,17 @@ Code review and passing tests do not substitute for those independent decisions. ## r4 rebase maintenance addendum (2026-10-09) Against upstream `9df2c4006142a0593f9bb4c40019ee1a8cd2cde7`, the current repair catalog is 4.0.13 with minimum direct source 4.0.12. Upstream 4.0.12 owns the charset metadata refresh and remains unchanged. The shared-function repair replays its nine entries only in the new handler, so already-upgraded 4.0.12 tenants are scheduled. Protocol admission remains 107, immediate predecessor 106. This mechanical rebase correction and the historical-schema lookup correction for snapshot/TS/PITR restore remain within the existing development scope; independent approval remains pending. + +## r5 rebase maintenance addendum (2026-10-09) + +Official main `d7621ea017db4e43dbde9e5a855ba7b2ad920784` has allocated +MORPC 107 and catalog 4.0.13 to functional-index metadata and its STATISTICS +refresh. This proposal uses the next MORPC 108 and a separate catalog 4.0.14 +repair (minimum direct source 4.0.13), preserving the upstream handler unchanged. +The nine idempotent shared-function entries are replayed only by the new handler; +already-upgraded 4.0.13 tenants remain eligible. Sender, receiver, prepared reuse, +physical execution and status RPC admission move together; protocol 107 is the +immediate predecessor rejection case. This is a mechanical compatibility +correction within the existing test/development scope. Independent Architecture +and SQL/Planner approval remains pending; no approval is inferred from this +addendum or validation. diff --git a/pkg/bootstrap/service_statistics_upgrade_test.go b/pkg/bootstrap/service_statistics_upgrade_test.go index 059916a457841..27d9fcfeac292 100644 --- a/pkg/bootstrap/service_statistics_upgrade_test.go +++ b/pkg/bootstrap/service_statistics_upgrade_test.go @@ -398,7 +398,7 @@ func TestStatisticsUpgradeCompensatesPostSnapshotTenantAfterRestart(t *testing.T } func TestMaybeUpgradeTenantDoesNotCacheUncommittedOrFailedChecks(t *testing.T) { - final := v4_0_11.Handler.Metadata() + final := statisticsFinalUpgradeVersion() for _, test := range []struct { name string version string @@ -439,7 +439,7 @@ func TestMaybeUpgradeTenantDoesNotCacheUncommittedOrFailedChecks(t *testing.T) { } }, txnOp) b := newServiceForTest("", &memLocker{}, clock.NewHLCClock(func() int64 { return 0 }, 0), - nil, exec, initStatisticsUpgradeThroughV4011) + nil, exec, func(s *service) { s.initUpgrade() }) defer b.stopper.Stop() for range 2 { var txnOp client.TxnOperator @@ -466,24 +466,9 @@ func TestMaybeUpgradeTenantDoesNotCacheUncommittedOrFailedChecks(t *testing.T) { } } -// These tests exercise the tenant-compensation state machine against the -// historical statistics-upgrade contract. Keep the synthetic service at the -// last pre-routine-catalog version so their SQL fixtures do not silently grow -// unrelated 4.0.12 catalog mutations. -func initStatisticsUpgradeThroughV4011(s *service) { - s.handles = append(s.handles, - v4_0_6.Handler, - v4_0_7.Handler, - v4_0_8.Handler, - v4_0_9.Handler, - v4_0_10.Handler, - v4_0_11.Handler, - ) -} - func TestMaybeUpgradeTenantRechecksVersionUnderLock(t *testing.T) { runtime.RunTest("", func(runtime.Runtime) { - final := v4_0_11.Handler.Metadata() + final := statisticsFinalUpgradeVersion() reads := 0 exec := executor.NewMemExecutor(func(sql string) (executor.Result, error) { switch { @@ -500,7 +485,7 @@ func TestMaybeUpgradeTenantRechecksVersionUnderLock(t *testing.T) { } }) b := newServiceForTest("", &memLocker{}, clock.NewHLCClock(func() int64 { return 0 }, 0), - nil, exec, initStatisticsUpgradeThroughV4011) + nil, exec, func(s *service) { s.initUpgrade() }) defer b.stopper.Stop() upgraded, err := b.MaybeUpgradeTenant(t.Context(), func() (int32, string, error) { return 11, final.Version, nil }, nil) @@ -513,7 +498,7 @@ func TestMaybeUpgradeTenantRechecksVersionUnderLock(t *testing.T) { func TestMaybeUpgradeTenantWaitHonorsCancellation(t *testing.T) { runtime.RunTest("", func(runtime.Runtime) { - final := v4_0_11.Handler.Metadata() + final := statisticsFinalUpgradeVersion() exec := executor.NewMemExecutor(func(sql string) (executor.Result, error) { switch { case sql == "select create_version from mo_account where account_id = 11": @@ -528,7 +513,7 @@ func TestMaybeUpgradeTenantWaitHonorsCancellation(t *testing.T) { } }) b := newServiceForTest("", &memLocker{}, clock.NewHLCClock(func() int64 { return 0 }, 0), - nil, exec, initStatisticsUpgradeThroughV4011) + nil, exec, func(s *service) { s.initUpgrade() }) defer b.stopper.Stop() ctx, cancel := context.WithCancel(t.Context()) cancel() @@ -548,7 +533,7 @@ func TestMaybeUpgradeTenantRejectsConcurrentAccountDeletion(t *testing.T) { } t.Run(name, func(t *testing.T) { runtime.RunTest("", func(runtime.Runtime) { - final := v4_0_11.Handler.Metadata() + final := statisticsFinalUpgradeVersion() var authenticated, dropped bool exec := &statisticsTransactionTracker{SQLExecutor: executor.NewMemExecutor( func(sql string) (executor.Result, error) { @@ -570,7 +555,7 @@ func TestMaybeUpgradeTenantRejectsConcurrentAccountDeletion(t *testing.T) { } })} b := newServiceForTest("", &memLocker{}, clock.NewHLCClock(func() int64 { return 0 }, 0), - nil, exec, initStatisticsUpgradeThroughV4011) + nil, exec, func(s *service) { s.initUpgrade() }) defer b.stopper.Stop() fetch := func() (int32, string, error) { authenticated = true diff --git a/pkg/bootstrap/versions/v4_0_13/tenant_upgrade_list.go b/pkg/bootstrap/versions/v4_0_13/tenant_upgrade_list.go index ff46e38faddb2..79f4d70fbe209 100644 --- a/pkg/bootstrap/versions/v4_0_13/tenant_upgrade_list.go +++ b/pkg/bootstrap/versions/v4_0_13/tenant_upgrade_list.go @@ -18,16 +18,12 @@ import ( "fmt" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/defines" "github.com/matrixorigin/matrixone/pkg/util/executor" "github.com/matrixorigin/matrixone/pkg/util/sysview" ) -var tenantUpgEntries = append( - []versions.UpgradeEntry{upgradeInformationSchemaStatistics()}, - v4_0_7.PythonRevisionUpgradeEntries()..., -) +var tenantUpgEntries = []versions.UpgradeEntry{upgradeInformationSchemaStatistics()} func upgradeInformationSchemaStatistics() versions.UpgradeEntry { return versions.UpgradeEntry{ diff --git a/pkg/bootstrap/versions/v4_0_13/upgrade.go b/pkg/bootstrap/versions/v4_0_13/upgrade.go index 10e135a26bf17..ed5295b8638a3 100644 --- a/pkg/bootstrap/versions/v4_0_13/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_13/upgrade.go @@ -27,10 +27,9 @@ import ( "go.uber.org/zap" ) -// 4.0.13 replays the idempotent shared Python UDF catalog entries together -// with the statistics view refresh introduced by the preceding main revision. -// An upstream-final 4.0.12 tenant may lack either set of objects; the newer -// handler converges both sets on retry after all CNs support MORPC v108. +// Use a new semantic version after the existing 4.0.11 CDC and 4.0.12 +// CHARACTER_SETS migrations. An old worker must not treat this STATISTICS +// refresh as already handled merely because it knows one of those versions. var Handler = &versionHandle{ metadata: versions.Version{ Version: "4.0.13", @@ -38,7 +37,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion108, + RequiredProtocolVersion: defines.MORPCVersion107, }, } @@ -56,11 +55,6 @@ func (v *versionHandle) Prepare(_ context.Context, txn executor.TxnExecutor, _ b } func (v *versionHandle) HandleTenantUpgrade(_ context.Context, tenantID int32, txn executor.TxnExecutor) error { - // Login compensation invokes this handler without the cluster-upgrade - // scheduler, so enforce the same floor before any catalog mutation. - if err := versions.CheckCommonProtocolVersion(txn, v.metadata.RequiredProtocolVersion); err != nil { - return err - } logger := runtime.ServiceRuntime(txn.Txn().TxnOptions().CN).Logger() for _, entry := range tenantUpgEntries { start := time.Now() diff --git a/pkg/bootstrap/versions/v4_0_13/upgrade_test.go b/pkg/bootstrap/versions/v4_0_13/upgrade_test.go index 692eb010f1c65..2fad53a90628e 100644 --- a/pkg/bootstrap/versions/v4_0_13/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_13/upgrade_test.go @@ -17,13 +17,11 @@ package v4_0_13 import ( "context" "errors" - "fmt" "strings" "testing" "github.com/golang/mock/gomock" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/catalog" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/common/runtime" @@ -36,209 +34,16 @@ import ( "github.com/stretchr/testify/require" ) -func TestPythonRevisionRepairUpgradePath(t *testing.T) { - metadata := Handler.Metadata() - require.Equal(t, "4.0.13", metadata.Version) - require.Equal(t, "4.0.12", metadata.MinUpgradeVersion) - require.Equal(t, versions.No, metadata.UpgradeCluster) - require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion108), metadata.RequiredProtocolVersion) - require.Equal(t, uint32(len(tenantUpgEntries)), metadata.VersionOffset) - require.Len(t, tenantUpgEntries, len(v4_0_7.PythonRevisionUpgradeEntries())+1) - require.True(t, metadata.CanDirectUpgrade("4.0.12")) - require.False(t, metadata.CanDirectUpgrade("4.0.7")) - require.Len(t, v4_0_7.PythonRevisionUpgradeEntries(), 9) -} - -func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { - for _, response := range []string{ - `{"result":"cn-a:107"}`, - `{"result":"cn-a:108,cn-b:107"}`, - `{"result":""}`, - `invalid`, - } { - t.Run(response, func(t *testing.T) { - var statements []string - txn := executor.NewMemTxnExecutor(func(statement string) (executor.Result, error) { - statements = append(statements, statement) - require.Equal(t, "SELECT mo_ctl('cn', 'GetProtocolVersion', '')", statement) - return repairStringResult(t, response), nil - }, nil) - err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 108") - require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) - }) - } -} - -func TestPythonRevisionRepairIsIdempotentForCatalogStates(t *testing.T) { - for _, test := range []struct { - name string - schemaOrigin string - columns []string - newIndex bool - legacyIndex bool - revisionTable bool - wantFirstDDL int - }{ - { - name: "upstream_final_4.0.12_missed_catalog", - schemaOrigin: "4.0.12", - legacyIndex: true, - wantFirstDDL: 9, - }, - { - name: "partial_revision_catalog", - schemaOrigin: "4.0.8", - columns: []string{ - "active_revision", "namespace_version", "canonical_input_descriptor", - "return_descriptor", "signature_key_schema_version", "signature_fingerprint", - }, - legacyIndex: true, - wantFirstDDL: 3, - }, - { - name: "complete_revision_catalog", - schemaOrigin: "4.0.8", - columns: []string{ - "active_revision", "namespace_version", "canonical_input_descriptor", - "return_descriptor", "signature_key_schema_version", "signature_fingerprint", - }, - newIndex: true, - revisionTable: true, - wantFirstDDL: 0, - }, - } { - t.Run(test.name, func(t *testing.T) { - runtime.RunTest("", func(runtime.Runtime) { - state := &pythonRevisionCatalogState{ - columns: make(map[string]bool), - newIndex: test.newIndex, - legacyIndex: test.legacyIndex, - revisionTable: test.revisionTable, - } - for _, column := range test.columns { - state.columns[column] = true - } - txn := newRepairTxnExecutor(t, state) - require.NoError(t, Handler.Prepare(context.Background(), txn, true)) - require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) - require.Len(t, state.ddl, test.wantFirstDDL, - "repair of %s schema must apply only missing catalog objects", test.schemaOrigin) - firstDDL := append([]string(nil), state.ddl...) - require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) - require.Equal(t, firstDDL, state.ddl, - "a restart/retry of %s schema must not repeat DDL", test.schemaOrigin) - }) - }) - } -} - -type pythonRevisionCatalogState struct { - columns map[string]bool - newIndex bool - legacyIndex bool - revisionTable bool - ddl []string -} - -func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) executor.TxnExecutor { - t.Helper() - txnOperator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) - txnOperator.EXPECT().TxnOptions().Return(pbtxn.TxnOptions{}).AnyTimes() - return executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { - lower := strings.ToLower(sql) - switch { - case strings.Contains(lower, "from mo_catalog.mo_columns"): - for column := range state.columns { - if strings.Contains(sql, fmt.Sprintf("attname = '%s'", column)) { - return repairColumnResult(t), nil - } - } - return executor.Result{}, nil - case strings.Contains(lower, "from `mo_catalog`.`mo_indexes`"): - if strings.Contains(sql, "name_db_arg_types_descriptor") && state.newIndex { - return repairStringResult(t, "name_db_arg_types_descriptor"), nil - } - if strings.Contains(sql, "name_db_arg_types'") && state.legacyIndex { - return repairStringResult(t, "name_db_arg_types"), nil - } - return executor.Result{}, nil - case strings.HasPrefix(sql, "SELECT tbl.rel_createsql"): - return repairStringResult(t, sysview.InformationSchemaStatisticsDDL), nil - case strings.Contains(lower, "from mo_catalog.mo_tables"): - if state.revisionTable && strings.Contains(sql, "relname = 'mo_function_revisions'") { - return repairStringResult(t, "mo_function_revisions"), nil - } - return executor.Result{}, nil - case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:108"}`), nil - case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): - for column := range state.columns { - if strings.Contains(sql, "add column "+column+" ") { - return executor.Result{}, nil - } - } - for _, column := range []string{ - "active_revision", "namespace_version", "canonical_input_descriptor", - "return_descriptor", "signature_key_schema_version", "signature_fingerprint", - } { - if strings.Contains(sql, "add column "+column+" ") { - state.columns[column] = true - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - } - } - case strings.Contains(lower, "create unique index name_db_arg_types_descriptor"): - state.newIndex = true - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - case strings.Contains(lower, "drop index name_db_arg_types"): - state.legacyIndex = false - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - case strings.Contains(lower, "create table mo_catalog.mo_function_revisions"): - state.revisionTable = true - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - default: - return executor.Result{}, fmt.Errorf("unexpected repair SQL: %s", sql) - } - return executor.Result{}, nil - }, txnOperator) -} - -func repairStringResult(t *testing.T, value string) executor.Result { - t.Helper() - mp := mpool.MustNewZeroNoFixed() - t.Cleanup(func() { mpool.DeleteMPool(mp) }) - result := executor.NewMemResult([]types.Type{types.T_varchar.ToType()}, mp) - result.NewBatchWithRowCount(1) - require.NoError(t, executor.AppendStringRows(result, 0, []string{value})) - return result.GetResult() -} - -func repairColumnResult(t *testing.T) executor.Result { - t.Helper() - mp := mpool.MustNewZeroNoFixed() - t.Cleanup(func() { mpool.DeleteMPool(mp) }) - result := executor.NewMemResult([]types.Type{ - types.T_varchar.ToType(), types.T_varchar.ToType(), - types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), - types.T_int32.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), - }, mp) - result.NewBatchWithRowCount(1) - require.NoError(t, executor.AppendStringRows(result, 0, []string{"BIGINT UNSIGNED"})) - require.NoError(t, executor.AppendStringRows(result, 1, []string{"NO"})) - require.NoError(t, executor.AppendFixedRows(result, 2, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 3, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 4, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 5, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 6, []int32{1})) - require.NoError(t, executor.AppendStringRows(result, 7, []string{"0"})) - require.NoError(t, executor.AppendStringRows(result, 8, []string{""})) - require.NoError(t, executor.AppendStringRows(result, 9, []string{""})) - return result.GetResult() +func TestStatisticsUpgradeMetadata(t *testing.T) { + m := Handler.Metadata() + require.Equal(t, "4.0.13", m.Version) + require.Equal(t, "4.0.12", m.MinUpgradeVersion) + require.Equal(t, versions.Yes, m.UpgradeTenant) + require.Equal(t, versions.No, m.UpgradeCluster) + require.Equal(t, defines.MORPCVersion107, m.RequiredProtocolVersion) + require.Equal(t, uint32(1), m.VersionOffset) + require.Len(t, tenantUpgEntries, 1) + require.Equal(t, int64(defines.MORPCVersion107), tenantUpgEntries[0].RequiredProtocolVersion) } func TestStatisticsUpgradeLifecycle(t *testing.T) { @@ -247,16 +52,12 @@ func TestStatisticsUpgradeLifecycle(t *testing.T) { operator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) operator.EXPECT().TxnOptions().Return(pbtxn.TxnOptions{}).AnyTimes() txn := executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { - switch { - case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:108"}`), nil - case strings.HasPrefix(sql, "SELECT tbl.rel_createsql"): - return repairStringResult(t, sysview.InformationSchemaStatisticsDDL), nil - default: - // The Python entries are independently covered above; allow their - // idempotent probes and DDLs to complete in this focused test. - return executor.Result{}, nil - } + require.True(t, strings.HasPrefix(sql, "SELECT tbl.rel_createsql"), sql) + mp := mpool.MustNewZero() + r := executor.NewMemResult([]types.Type{types.T_varchar.ToType()}, mp) + r.NewBatchWithRowCount(1) + require.NoError(t, executor.AppendStringRows(r, 0, []string{sysview.InformationSchemaStatisticsDDL})) + return r.GetResult(), nil }, operator) require.NoError(t, Handler.Prepare(ctx, txn, true)) require.NoError(t, Handler.HandleTenantUpgrade(ctx, int32(catalog.System_Account), txn)) diff --git a/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go b/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go index 6fba56b82c82b..ca18f683c9f5e 100644 --- a/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go +++ b/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go @@ -14,6 +14,44 @@ package v4_0_14 -import "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" +import ( + "fmt" -var tenantUpgEntries = []versions.UpgradeEntry{versions.InformationSchemaColumnsUpgradeEntry()} + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" + "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/util/executor" + "github.com/matrixorigin/matrixone/pkg/util/sysview" +) + +// The v4.0.14 repair replays both the native COLUMNS view migration introduced +// by the upstream branch and the idempotent Python UDF revision catalog repair. +// Keep these entries in one version so tenants that already recorded v4.0.13 +// receive either or both repairs on the same upgrade attempt. +var tenantUpgEntries = append( + []versions.UpgradeEntry{upgradeInformationSchemaColumns()}, + v4_0_7.PythonRevisionUpgradeEntries()..., +) + +// upgradeInformationSchemaColumns refreshes the persisted COLUMNS view for +// tenants that already passed the protocol-100 view migration. The current +// definition adds the native UCA 4.0.0 charset/collation identities (selector +// values 4 and 5); changing the old v4.0.10 entry would not reach tenants that +// have already recorded a later tenant version. +func upgradeInformationSchemaColumns() versions.UpgradeEntry { + return versions.UpgradeEntry{ + Schema: sysview.InformationDBConst, + TableName: "COLUMNS", + UpgType: versions.MODIFY_VIEW, + UpgSql: sysview.InformationSchemaColumnsDDL, + RequiredProtocolVersion: defines.MORPCVersion109, + CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { + exists, definition, err := versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "COLUMNS") + if err == nil && !exists { + exists, definition, err = versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "columns") + } + return exists && definition == sysview.InformationSchemaColumnsDDL, err + }, + PreSql: fmt.Sprintf("DROP VIEW IF EXISTS %s.COLUMNS;", sysview.InformationDBConst), + } +} diff --git a/pkg/bootstrap/versions/v4_0_14/upgrade.go b/pkg/bootstrap/versions/v4_0_14/upgrade.go index e2ecc58ba65f5..64d2947dad8a8 100644 --- a/pkg/bootstrap/versions/v4_0_14/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_14/upgrade.go @@ -27,6 +27,12 @@ import ( "go.uber.org/zap" ) +// 4.0.14 replays the idempotent shared Python UDF catalog entries together +// with the upstream COLUMNS view repair. An upstream-final 4.0.13 tenant may +// lack either repair; this newer registered handler ensures the upgrade +// framework schedules both repairs. Earlier tenants first traverse the +// unchanged upstream handlers through 4.0.13. Complete, partial and absent +// catalog states converge on retry. var Handler = &versionHandle{ metadata: versions.Version{ Version: "4.0.14", @@ -34,7 +40,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion109, + RequiredProtocolVersion: defines.MORPCVersion110, }, } @@ -46,12 +52,17 @@ func (v *versionHandle) Metadata() versions.Version { return v.metadata } -func (v *versionHandle) Prepare(_ context.Context, txn executor.TxnExecutor, _ bool) error { +func (v *versionHandle) Prepare(ctx context.Context, txn executor.TxnExecutor, final bool) error { txn.Use(catalog.MO_CATALOG) return nil } -func (v *versionHandle) HandleTenantUpgrade(_ context.Context, tenantID int32, txn executor.TxnExecutor) error { +func (v *versionHandle) HandleTenantUpgrade(ctx context.Context, tenantID int32, txn executor.TxnExecutor) error { + // Login compensation invokes this handler without the cluster-upgrade + // scheduler, so enforce the same floor before any catalog mutation. + if err := versions.CheckCommonProtocolVersion(txn, v.metadata.RequiredProtocolVersion); err != nil { + return err + } logger := runtime.ServiceRuntime(txn.Txn().TxnOptions().CN).Logger() for _, entry := range tenantUpgEntries { start := time.Now() @@ -72,10 +83,10 @@ func (v *versionHandle) HandleTenantUpgrade(_ context.Context, tenantID int32, t return nil } -func (v *versionHandle) HandleClusterUpgrade(_ context.Context, _ executor.TxnExecutor) error { +func (v *versionHandle) HandleClusterUpgrade(ctx context.Context, txn executor.TxnExecutor) error { return nil } -func (v *versionHandle) HandleCreateFrameworkDeps(_ executor.TxnExecutor) error { +func (v *versionHandle) HandleCreateFrameworkDeps(txn executor.TxnExecutor) error { return moerr.NewInternalErrorNoCtxf("Only v1.2.0 can initialize upgrade framework, current version is:%s", v.metadata.Version) } diff --git a/pkg/bootstrap/versions/v4_0_14/upgrade_test.go b/pkg/bootstrap/versions/v4_0_14/upgrade_test.go index 7febbbc93b6f0..058cc93d269f5 100644 --- a/pkg/bootstrap/versions/v4_0_14/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_14/upgrade_test.go @@ -17,11 +17,13 @@ package v4_0_14 import ( "context" "errors" + "fmt" "strings" "testing" "github.com/golang/mock/gomock" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/common/runtime" @@ -40,9 +42,9 @@ func TestColumnsUpgradeMetadata(t *testing.T) { require.Equal(t, "4.0.13", m.MinUpgradeVersion) require.Equal(t, versions.Yes, m.UpgradeTenant) require.Equal(t, versions.No, m.UpgradeCluster) - require.Equal(t, defines.MORPCVersion109, m.RequiredProtocolVersion) - require.Equal(t, uint32(1), m.VersionOffset) - require.Len(t, tenantUpgEntries, 1) + require.Equal(t, defines.MORPCVersion110, m.RequiredProtocolVersion) + require.Equal(t, uint32(1+len(v4_0_7.PythonRevisionUpgradeEntries())), m.VersionOffset) + require.Len(t, tenantUpgEntries, 1+len(v4_0_7.PythonRevisionUpgradeEntries())) require.Equal(t, int64(defines.MORPCVersion109), tenantUpgEntries[0].RequiredProtocolVersion) } @@ -142,11 +144,215 @@ func TestColumnsUpgradeLifecycle(t *testing.T) { return r.GetResult(), nil }, operator) require.NoError(t, Handler.Prepare(ctx, txn, true)) - require.NoError(t, Handler.HandleTenantUpgrade(ctx, 1, txn)) + require.NoError(t, upgradeInformationSchemaColumns().Upgrade(txn, 1)) require.Error(t, Handler.HandleCreateFrameworkDeps(txn)) injected := errors.New("injected") failed := executor.NewMemTxnExecutor(func(string) (executor.Result, error) { return executor.Result{}, injected }, operator) - require.ErrorIs(t, Handler.HandleTenantUpgrade(ctx, 7, failed), injected) + require.ErrorIs(t, upgradeInformationSchemaColumns().Upgrade(failed, 7), injected) }) } + +func TestPythonRevisionRepairUpgradePath(t *testing.T) { + metadata := Handler.Metadata() + require.Equal(t, "4.0.14", metadata.Version) + require.Equal(t, "4.0.13", metadata.MinUpgradeVersion) + require.Equal(t, versions.No, metadata.UpgradeCluster) + require.Equal(t, versions.Yes, metadata.UpgradeTenant) + require.Equal(t, int64(defines.MORPCVersion110), metadata.RequiredProtocolVersion) + require.Equal(t, uint32(1+len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) + require.True(t, metadata.CanDirectUpgrade("4.0.13")) + require.False(t, metadata.CanDirectUpgrade("4.0.7")) + require.Len(t, v4_0_7.PythonRevisionUpgradeEntries(), 9) +} + +func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { + for _, response := range []string{ + `{"result":"cn-a:109"}`, + `{"result":"cn-a:110,cn-b:109"}`, + `{"result":""}`, + `invalid`, + } { + t.Run(response, func(t *testing.T) { + var statements []string + txn := executor.NewMemTxnExecutor(func(statement string) (executor.Result, error) { + statements = append(statements, statement) + require.Equal(t, "SELECT mo_ctl('cn', 'GetProtocolVersion', '')", statement) + return repairStringResult(t, response), nil + }, nil) + err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 110") + require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) + }) + } +} + +func TestPythonRevisionRepairIsIdempotentForCatalogStates(t *testing.T) { + for _, test := range []struct { + name string + schemaOrigin string + columns []string + newIndex bool + legacyIndex bool + revisionTable bool + wantFirstDDL int + }{ + { + name: "upstream_final_4.0.13_missed_catalog", + schemaOrigin: "4.0.13", + legacyIndex: true, + wantFirstDDL: 9, + }, + { + name: "partial_revision_catalog", + schemaOrigin: "4.0.8", + columns: []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + }, + legacyIndex: true, + wantFirstDDL: 3, + }, + { + name: "complete_revision_catalog", + schemaOrigin: "4.0.8", + columns: []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + }, + newIndex: true, + revisionTable: true, + wantFirstDDL: 0, + }, + } { + t.Run(test.name, func(t *testing.T) { + runtime.RunTest("", func(runtime.Runtime) { + state := &pythonRevisionCatalogState{ + columns: make(map[string]bool), + newIndex: test.newIndex, + legacyIndex: test.legacyIndex, + revisionTable: test.revisionTable, + } + for _, column := range test.columns { + state.columns[column] = true + } + txn := newRepairTxnExecutor(t, state) + require.NoError(t, Handler.Prepare(context.Background(), txn, true)) + require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) + require.Len(t, state.ddl, test.wantFirstDDL, + "repair of %s schema must apply only missing catalog objects", test.schemaOrigin) + firstDDL := append([]string(nil), state.ddl...) + require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) + require.Equal(t, firstDDL, state.ddl, + "a restart/retry of %s schema must not repeat DDL", test.schemaOrigin) + }) + }) + } +} + +type pythonRevisionCatalogState struct { + columns map[string]bool + newIndex bool + legacyIndex bool + revisionTable bool + ddl []string +} + +func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) executor.TxnExecutor { + t.Helper() + txnOperator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) + txnOperator.EXPECT().TxnOptions().Return(pbtxn.TxnOptions{}).AnyTimes() + return executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { + lower := strings.ToLower(sql) + switch { + case strings.Contains(lower, "select tbl.rel_createsql"): + return repairStringResult(t, sysview.InformationSchemaColumnsDDL), nil + case strings.Contains(lower, "from mo_catalog.mo_columns"): + for column := range state.columns { + if strings.Contains(sql, fmt.Sprintf("attname = '%s'", column)) { + return repairColumnResult(t), nil + } + } + return executor.Result{}, nil + case strings.Contains(lower, "from `mo_catalog`.`mo_indexes`"): + if strings.Contains(sql, "name_db_arg_types_descriptor") && state.newIndex { + return repairStringResult(t, "name_db_arg_types_descriptor"), nil + } + if strings.Contains(sql, "name_db_arg_types'") && state.legacyIndex { + return repairStringResult(t, "name_db_arg_types"), nil + } + return executor.Result{}, nil + case strings.Contains(lower, "from mo_catalog.mo_tables"): + if state.revisionTable && strings.Contains(sql, "relname = 'mo_function_revisions'") { + return repairStringResult(t, "mo_function_revisions"), nil + } + return executor.Result{}, nil + case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:110"}`), nil + case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): + for column := range state.columns { + if strings.Contains(sql, "add column "+column+" ") { + return executor.Result{}, nil + } + } + for _, column := range []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + } { + if strings.Contains(sql, "add column "+column+" ") { + state.columns[column] = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + } + } + case strings.Contains(lower, "create unique index name_db_arg_types_descriptor"): + state.newIndex = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + case strings.Contains(lower, "drop index name_db_arg_types"): + state.legacyIndex = false + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + case strings.Contains(lower, "create table mo_catalog.mo_function_revisions"): + state.revisionTable = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + default: + return executor.Result{}, fmt.Errorf("unexpected repair SQL: %s", sql) + } + return executor.Result{}, nil + }, txnOperator) +} + +func repairStringResult(t *testing.T, value string) executor.Result { + t.Helper() + mp := mpool.MustNewZeroNoFixed() + t.Cleanup(func() { mpool.DeleteMPool(mp) }) + result := executor.NewMemResult([]types.Type{types.T_varchar.ToType()}, mp) + result.NewBatchWithRowCount(1) + require.NoError(t, executor.AppendStringRows(result, 0, []string{value})) + return result.GetResult() +} + +func repairColumnResult(t *testing.T) executor.Result { + t.Helper() + mp := mpool.MustNewZeroNoFixed() + t.Cleanup(func() { mpool.DeleteMPool(mp) }) + result := executor.NewMemResult([]types.Type{ + types.T_varchar.ToType(), types.T_varchar.ToType(), + types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), + types.T_int32.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), + }, mp) + result.NewBatchWithRowCount(1) + require.NoError(t, executor.AppendStringRows(result, 0, []string{"BIGINT UNSIGNED"})) + require.NoError(t, executor.AppendStringRows(result, 1, []string{"NO"})) + require.NoError(t, executor.AppendFixedRows(result, 2, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 3, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 4, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 5, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 6, []int32{1})) + require.NoError(t, executor.AppendStringRows(result, 7, []string{"0"})) + require.NoError(t, executor.AppendStringRows(result, 8, []string{""})) + require.NoError(t, executor.AppendStringRows(result, 9, []string{""})) + return result.GetResult() +} diff --git a/pkg/frontend/authenticate_test.go b/pkg/frontend/authenticate_test.go index c18bfa485f13d..85899c40c7dd0 100644 --- a/pkg/frontend/authenticate_test.go +++ b/pkg/frontend/authenticate_test.go @@ -1285,7 +1285,7 @@ func Test_initFunction(t *testing.T) { FamilyString: "INT", Width: 24, Locale: &locale, - Oid: uint32(defines.MYSQL_TYPE_INT24), + Oid: uint32(defines.MYSQL_TYPE_LONG), }, }), Body: "", diff --git a/pkg/tests/upgrade/upgrade_v4_0_13_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_13_routine_test.go deleted file mode 100644 index adcf6618ec011..0000000000000 --- a/pkg/tests/upgrade/upgrade_v4_0_13_routine_test.go +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2026 Matrix Origin -// -// 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 upgrade - -import ( - "context" - "database/sql" - "fmt" - "strings" - "testing" - "time" - - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_13" - "github.com/matrixorigin/matrixone/pkg/catalog" - moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime" - "github.com/matrixorigin/matrixone/pkg/container/vector" - "github.com/matrixorigin/matrixone/pkg/embed" - "github.com/matrixorigin/matrixone/pkg/tests/testutils" - "github.com/matrixorigin/matrixone/pkg/udf" - "github.com/matrixorigin/matrixone/pkg/util/executor" - "github.com/stretchr/testify/require" -) - -// Reuse the upgrade package's single-CN fixture. A late tenant must be repaired -// on its first real login, even when the cluster has already completed upgrade. -func TestV4013LoginRepairsLegacyRoutineCatalog(t *testing.T) { - embed.RunSingleCNBaseClusterTests(t, func(cluster embed.Cluster) { - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) - defer cancel() - cn, err := cluster.GetCNService(0) - require.NoError(t, err) - port := cn.GetServiceConfig().CN.Frontend.Port - systemDB, err := sql.Open("mysql", fmt.Sprintf("dump:111@tcp(127.0.0.1:%d)/", port)) - require.NoError(t, err) - defer systemDB.Close() - const account = "routine_repair_4013" - _, err = systemDB.ExecContext(ctx, "create account "+account+" ADMIN_NAME 'root' IDENTIFIED BY '111'") - require.NoError(t, err) - defer func() { - cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 30*time.Second) - defer cleanupCancel() - _, err := systemDB.ExecContext(cleanupCtx, "drop account "+account) - require.NoError(t, err) - var remaining int - require.NoError(t, systemDB.QueryRowContext(cleanupCtx, - "select count(*) from mo_catalog.mo_account where account_name = '"+account+"'").Scan(&remaining)) - require.Zero(t, remaining) - }() - var accountID uint32 - require.NoError(t, systemDB.QueryRowContext(ctx, - "select account_id from mo_catalog.mo_account where account_name = '"+account+"'").Scan(&accountID)) - sqlExecutor := testutils.GetSQLExecutor(cn) - // Model an old writer through a sys-owned transaction, without tenant - // authentication populating the bootstrap service's checked-tenant cache. - require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { - for _, statement := range []string{ - "create database routine_repair", - `insert into mo_catalog.mo_user_defined_function(name,owner,args,arg_types,rettype,body,language,db,definer,type,security_type) values ('legacy_plus_seven',2,'[{"name":"x","type":"bigint"}]','["bigint"]','bigint','$1 + 7','sql','routine_repair','root','SQL','INVOKER')`, - "drop table mo_catalog.mo_function_revisions", - } { - res, err := txn.Exec(statement, versions.UpgradeStatementOption(accountID)) - if err != nil { - return err - } - res.Close() - } - return versions.UpgradeTenantVersion(int32(accountID), "4.0.12", txn) - }, executor.Options{}.WithDatabase(catalog.MO_CATALOG). - WithAccountID(catalog.System_Account).WithWaitCommittedLogApplied())) - var functionID uint64 - checkCatalog := func(wantVersion string, wantTable bool) { - t.Helper() - var version string - require.NoError(t, systemDB.QueryRowContext(ctx, - fmt.Sprintf("select create_version from mo_catalog.mo_account where account_id = %d", accountID)).Scan(&version)) - require.Equal(t, wantVersion, version) - require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { - exists, err := versions.CheckTableDefinition(txn, accountID, catalog.MO_CATALOG, "mo_function_revisions") - if err != nil { - return err - } - require.Equal(t, wantTable, exists) - res, err := txn.Exec("select function_id,body,active_revision,namespace_version from mo_catalog.mo_user_defined_function where name = 'legacy_plus_seven'", versions.UpgradeStatementOption(accountID)) - if err != nil { - return err - } - defer res.Close() - require.Equal(t, 1, len(res.Batches)) - batch := res.Batches[0] - require.Equal(t, 1, batch.RowCount()) - id := uint64(vector.GetFixedAtWithTypeCheck[int32](batch.Vecs[0], 0)) - if functionID == 0 { - functionID = id - } - require.Equal(t, functionID, id) - require.Equal(t, "$1 + 7", batch.Vecs[1].GetStringAt(0)) - require.Equal(t, uint64(0), vector.GetFixedAtWithTypeCheck[uint64](batch.Vecs[2], 0)) - require.Equal(t, uint64(0), vector.GetFixedAtWithTypeCheck[uint64](batch.Vecs[3], 0)) - return nil - }, executor.Options{}.WithDatabase(catalog.MO_CATALOG).WithAccountID(catalog.System_Account))) - } - checkCatalog("4.0.12", false) - rt := moruntime.ServiceRuntime(cn.ServiceID()) - original, present := rt.GetGlobalVariables(moruntime.MOProtocolVersion) - require.True(t, present) - require.GreaterOrEqual(t, original.(int64), udf.SharedRoutineRevisionProtocolVersion) - defer rt.SetGlobalVariables(moruntime.MOProtocolVersion, original) - tenantDSN := fmt.Sprintf("%s#root#accountadmin:111@tcp(127.0.0.1:%d)/", account, port) - func() { - rt.SetGlobalVariables(moruntime.MOProtocolVersion, udf.SharedRoutineRevisionProtocolVersion-1) - defer rt.SetGlobalVariables(moruntime.MOProtocolVersion, original) - db, err := sql.Open("mysql", tenantDSN) - require.NoError(t, err) - defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 108") - }() - checkCatalog("4.0.12", false) - tenantDB, err := sql.Open("mysql", tenantDSN) - require.NoError(t, err) - defer tenantDB.Close() - checkResult := func() { - t.Helper() - _, err := tenantDB.ExecContext(ctx, "use routine_repair") - require.NoError(t, err) - var result int64 - require.NoError(t, tenantDB.QueryRowContext(ctx, "select legacy_plus_seven(5)").Scan(&result)) - require.Equal(t, int64(12), result) - } - checkResult() - checkCatalog("4.0.13", true) - // Explicit replay reaches the handler; a cached second login would not - // prove that its DDL is idempotent against the persisted catalog. - for range 2 { - var mutations int - require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { - return v4_0_13.Handler.HandleTenantUpgrade(ctx, int32(accountID), - &routineRepairTxn{TxnExecutor: txn, mutations: &mutations}) - }, executor.Options{}.WithDatabase(catalog.MO_CATALOG). - WithAccountID(catalog.System_Account).WithWaitCommittedLogApplied())) - require.Zero(t, mutations) - checkCatalog("4.0.13", true) - checkResult() - } - }) -} - -type routineRepairTxn struct { - executor.TxnExecutor - mutations *int -} - -func (txn *routineRepairTxn) Exec(statement string, opts executor.StatementOption) (executor.Result, error) { - res, err := txn.TxnExecutor.Exec(statement, opts) - lower := strings.ToLower(strings.TrimSpace(statement)) - if err == nil && (strings.HasPrefix(lower, "alter table") || strings.HasPrefix(lower, "create table") || strings.HasPrefix(lower, "create unique index")) { - (*txn.mutations)++ - } - return res, err -} diff --git a/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go new file mode 100644 index 0000000000000..f62a25a29014c --- /dev/null +++ b/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go @@ -0,0 +1,176 @@ +// Copyright 2026 Matrix Origin +// +// 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 upgrade + +import ( + "context" + "database/sql" + "fmt" + "strings" + "testing" + "time" + + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_14" + "github.com/matrixorigin/matrixone/pkg/catalog" + moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime" + "github.com/matrixorigin/matrixone/pkg/container/vector" + "github.com/matrixorigin/matrixone/pkg/embed" + "github.com/matrixorigin/matrixone/pkg/tests/testutils" + "github.com/matrixorigin/matrixone/pkg/udf" + "github.com/matrixorigin/matrixone/pkg/util/executor" + "github.com/stretchr/testify/require" +) + +// Reuse the upgrade package's single-CN fixture. A late tenant must be repaired +// on its first real login, even when the cluster has already completed upgrade. +func TestV4014LoginRepairsLegacyRoutineCatalog(t *testing.T) { + embed.RunSingleCNBaseClusterTests(t, func(cluster embed.Cluster) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) + defer cancel() + cn, err := cluster.GetCNService(0) + require.NoError(t, err) + port := cn.GetServiceConfig().CN.Frontend.Port + systemDB, err := sql.Open("mysql", fmt.Sprintf("dump:111@tcp(127.0.0.1:%d)/", port)) + require.NoError(t, err) + defer systemDB.Close() + for _, sourceVersion := range []string{"4.0.12", "4.0.13"} { + t.Run(sourceVersion, func(t *testing.T) { + account := "routine_repair_4014_" + strings.ReplaceAll(sourceVersion, ".", "") + _, err = systemDB.ExecContext(ctx, "create account "+account+" ADMIN_NAME 'root' IDENTIFIED BY '111'") + require.NoError(t, err) + defer func() { + cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cleanupCancel() + _, err := systemDB.ExecContext(cleanupCtx, "drop account "+account) + require.NoError(t, err) + var remaining int + require.NoError(t, systemDB.QueryRowContext(cleanupCtx, + "select count(*) from mo_catalog.mo_account where account_name = '"+account+"'").Scan(&remaining)) + require.Zero(t, remaining) + }() + var accountID uint32 + require.NoError(t, systemDB.QueryRowContext(ctx, + "select account_id from mo_catalog.mo_account where account_name = '"+account+"'").Scan(&accountID)) + sqlExecutor := testutils.GetSQLExecutor(cn) + // Model an old writer through a sys-owned transaction, without tenant + // authentication populating the bootstrap service's checked-tenant cache. + require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { + for _, statement := range []string{ + "create database routine_repair", + `insert into mo_catalog.mo_user_defined_function(name,owner,args,arg_types,rettype,body,language,db,definer,type,security_type) values ('legacy_plus_seven',2,'[{"name":"x","type":"bigint"}]','["bigint"]','bigint','$1 + 7','sql','routine_repair','root','SQL','INVOKER')`, + "drop table mo_catalog.mo_function_revisions", + } { + res, err := txn.Exec(statement, versions.UpgradeStatementOption(accountID)) + if err != nil { + return err + } + res.Close() + } + return versions.UpgradeTenantVersion(int32(accountID), sourceVersion, txn) + }, executor.Options{}.WithDatabase(catalog.MO_CATALOG). + WithAccountID(catalog.System_Account).WithWaitCommittedLogApplied())) + var functionID uint64 + checkCatalog := func(wantVersion string, wantTable bool) { + t.Helper() + var version string + require.NoError(t, systemDB.QueryRowContext(ctx, + fmt.Sprintf("select create_version from mo_catalog.mo_account where account_id = %d", accountID)).Scan(&version)) + require.Equal(t, wantVersion, version) + require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { + exists, err := versions.CheckTableDefinition(txn, accountID, catalog.MO_CATALOG, "mo_function_revisions") + if err != nil { + return err + } + require.Equal(t, wantTable, exists) + res, err := txn.Exec("select function_id,body,active_revision,namespace_version from mo_catalog.mo_user_defined_function where name = 'legacy_plus_seven'", versions.UpgradeStatementOption(accountID)) + if err != nil { + return err + } + defer res.Close() + require.Equal(t, 1, len(res.Batches)) + batch := res.Batches[0] + require.Equal(t, 1, batch.RowCount()) + id := uint64(vector.GetFixedAtWithTypeCheck[int32](batch.Vecs[0], 0)) + if functionID == 0 { + functionID = id + } + require.Equal(t, functionID, id) + require.Equal(t, "$1 + 7", batch.Vecs[1].GetStringAt(0)) + require.Equal(t, uint64(0), vector.GetFixedAtWithTypeCheck[uint64](batch.Vecs[2], 0)) + require.Equal(t, uint64(0), vector.GetFixedAtWithTypeCheck[uint64](batch.Vecs[3], 0)) + return nil + }, executor.Options{}.WithDatabase(catalog.MO_CATALOG).WithAccountID(catalog.System_Account))) + } + checkCatalog(sourceVersion, false) + rt := moruntime.ServiceRuntime(cn.ServiceID()) + original, present := rt.GetGlobalVariables(moruntime.MOProtocolVersion) + require.True(t, present) + require.GreaterOrEqual(t, original.(int64), udf.SharedRoutineRevisionProtocolVersion) + defer rt.SetGlobalVariables(moruntime.MOProtocolVersion, original) + tenantDSN := fmt.Sprintf("%s#root#accountadmin:111@tcp(127.0.0.1:%d)/", account, port) + func() { + rt.SetGlobalVariables(moruntime.MOProtocolVersion, udf.SharedRoutineRevisionProtocolVersion-1) + defer rt.SetGlobalVariables(moruntime.MOProtocolVersion, original) + db, err := sql.Open("mysql", tenantDSN) + require.NoError(t, err) + defer db.Close() + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 108") + }() + checkCatalog(sourceVersion, false) + tenantDB, err := sql.Open("mysql", tenantDSN) + require.NoError(t, err) + defer tenantDB.Close() + checkResult := func() { + t.Helper() + _, err := tenantDB.ExecContext(ctx, "use routine_repair") + require.NoError(t, err) + var result int64 + require.NoError(t, tenantDB.QueryRowContext(ctx, "select legacy_plus_seven(5)").Scan(&result)) + require.Equal(t, int64(12), result) + } + checkResult() + checkCatalog("4.0.14", true) + // Explicit replay reaches the handler; a cached second login would not + // prove that its DDL is idempotent against the persisted catalog. + for range 2 { + var mutations int + require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { + return v4_0_14.Handler.HandleTenantUpgrade(ctx, int32(accountID), + &routineRepairTxn{TxnExecutor: txn, mutations: &mutations}) + }, executor.Options{}.WithDatabase(catalog.MO_CATALOG). + WithAccountID(catalog.System_Account).WithWaitCommittedLogApplied())) + require.Zero(t, mutations) + checkCatalog("4.0.14", true) + checkResult() + } + }) + } + }) +} + +type routineRepairTxn struct { + executor.TxnExecutor + mutations *int +} + +func (txn *routineRepairTxn) Exec(statement string, opts executor.StatementOption) (executor.Result, error) { + res, err := txn.TxnExecutor.Exec(statement, opts) + lower := strings.ToLower(strings.TrimSpace(statement)) + if err == nil && (strings.HasPrefix(lower, "alter table") || strings.HasPrefix(lower, "create table") || strings.HasPrefix(lower, "create unique index")) { + (*txn.mutations)++ + } + return res, err +} From ec9d68dc852ea457b3b92dcc1781c68d613d2e15 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sat, 10 Oct 2026 01:07:13 +0800 Subject: [PATCH 214/241] fix(udf): allocate protocol after upstream rebase --- docs/design/python_udf_current_stage.md | 16 ++++++++-------- docs/design/python_udf_current_stage_approval.md | 8 ++++---- pkg/frontend/python_udf_catalog_test.go | 4 ++-- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 ++-- .../compile/expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 10 +++++----- pkg/sql/compile/remoterun.go | 4 ++-- .../upgrade/upgrade_v4_0_14_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 11 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 35b46294c6e54..cc1fdda064a36 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -4,8 +4,8 @@ | --- | --- | | Design revision | `python-udf-current-stage-r5-2026-10-09` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `d7621ea017db4e43dbde9e5a855ba7b2ad920784` (MORPC 107, catalog 4.0.13) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r5 repair adds catalog 4.0.14 and protocol 108 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `72d4a49db7d750520e1a1654cb6091fc7169882b` (MORPC 108, catalog 4.0.13) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r5 repair adds catalog 4.0.14 and protocol 109 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -71,12 +71,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `108` (`latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `109` (`latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 108 and above, +revision that would become authoritative later. At protocol 109 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -93,20 +93,20 @@ statistics view refresh, remain unchanged. Thus a tenant already at upstream final `4.0.13`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 108 before tenant tasks are created, and the repair handler +requires protocol 109 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -108. That value is rollout state in the service runtime, not a computed live +109. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 108. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 109. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -246,7 +246,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-108 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_14/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13, rejection at protocol 107 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-109 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_14/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13, rejection at protocol 108 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 72f9d19d93920..39c981ef2c28e 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -84,13 +84,13 @@ Against upstream `9df2c4006142a0593f9bb4c40019ee1a8cd2cde7`, the current repair ## r5 rebase maintenance addendum (2026-10-09) -Official main `d7621ea017db4e43dbde9e5a855ba7b2ad920784` has allocated -MORPC 107 and catalog 4.0.13 to functional-index metadata and its STATISTICS -refresh. This proposal uses the next MORPC 108 and a separate catalog 4.0.14 +Official main `72d4a49db7d750520e1a1654cb6091fc7169882b` has allocated +MORPC 108 to the user-variable NULL regexp migration contract while retaining +catalog 4.0.13. This proposal uses the next MORPC 109 and a separate catalog 4.0.14 repair (minimum direct source 4.0.13), preserving the upstream handler unchanged. The nine idempotent shared-function entries are replayed only by the new handler; already-upgraded 4.0.13 tenants remain eligible. Sender, receiver, prepared reuse, -physical execution and status RPC admission move together; protocol 107 is the +physical execution and status RPC admission move together; protocol 108 is the immediate predecessor rejection case. This is a mechanical compatibility correction within the existing test/development scope. Independent Architecture and SQL/Planner approval remains pending; no approval is inferred from this diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 05961dce5cf96..cb5ec5cc73103 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -561,7 +561,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 108"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 109"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -625,7 +625,7 @@ func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 108") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 109") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index b33ace364252c..c1b755d2d3044 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion108, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion109, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index faf629521f797..d8275c634b088 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,8 +37,8 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion108(t *testing.T) { - assert.Equal(t, defines.MORPCVersion108, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +func TestGetPythonUdfStatusRequiresProtocolVersion109(t *testing.T) { + assert.Equal(t, defines.MORPCVersion109, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index e4aaa12cd7f05..6239f8d60c1be 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion108, + {features.PythonRoutineContract, defines.MORPCVersion109, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index f2155b2f101c0..ac86ae9442053 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion108) + required = max(required, defines.MORPCVersion109) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 4b7790f10264c..67cf79edf4ff0 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -551,20 +551,20 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion108, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion109, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion107, defines.MORPCVersion108} { + for _, version := range []int64{defines.MORPCVersion108, defines.MORPCVersion109} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion108 { + if version < defines.MORPCVersion109 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion107) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion108) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion109) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 9bfd20ad32f70..4f57a9fffa5e9 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion108) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 108") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion109) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 109") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go index f62a25a29014c..90d57526d5ddd 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go @@ -127,7 +127,7 @@ func TestV4014LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 108") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 109") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 05a4cee8ebcd2..85fa8bd35c272 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion108 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion109 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From 09ec1a877f6f7068e4f793e7c335d43aa5b08044 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sat, 10 Oct 2026 12:57:11 +0800 Subject: [PATCH 215/241] optools: target embedded watchdog in stderr regression test --- optools/ut_embedded_schedule_test.go | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/optools/ut_embedded_schedule_test.go b/optools/ut_embedded_schedule_test.go index c5b36b8652d18..5d1f7a9e37b2f 100644 --- a/optools/ut_embedded_schedule_test.go +++ b/optools/ut_embedded_schedule_test.go @@ -1051,13 +1051,28 @@ func TestEmbeddedPrebuiltFailureKeepsReportJSONOnly(t *testing.T) { t.Run("parallel="+parallel, func(t *testing.T) { script := embeddedSetup + ` function logger() { printf '%s\n' "$*"; } - # Keep both active-package group-alive probes false, then force the real - # watchdog cleanup wait through its bounded force-stop branch. The diagnostic - # must remain in UT_STDERR; a missing redirection contaminates UT_REPORT. -force_group_probe_count=0 + # Keep the active test process groups false, then force only the first + # watchdog cleanup wait through its bounded force-stop branch. The + # diagnostic must remain in UT_STDERR; a missing redirection contaminates + # UT_REPORT. +first_group_pid="" +watchdog_group_pid="" +watchdog_probe_count=0 function ut_process_group_alive() { - force_group_probe_count=$((force_group_probe_count + 1)) - if (( force_group_probe_count >= 3 && force_group_probe_count <= 23 )); then return 0; fi + local pid=$1 + if [[ -z "$first_group_pid" ]]; then + first_group_pid=$pid + return 1 + fi + if [[ "$pid" == "$first_group_pid" ]]; then return 1; fi + if [[ -z "$watchdog_group_pid" ]]; then + watchdog_group_pid=$pid + fi + if [[ "$pid" == "$watchdog_group_pid" ]]; then + watchdog_probe_count=$((watchdog_probe_count + 1)) + if (( watchdog_probe_count <= 21 )); then return 0; fi + return 1 + fi return 1 } start_embedded_prebuild "$scope" 1 From 889317ca7da7b1c6aede570836d175b5977b1a5f Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 11 Oct 2026 00:05:09 +0800 Subject: [PATCH 216/241] fix(udf): allocate MORPC 110 after upstream rebase --- docs/design/python_udf_current_stage.md | 23 ++++++++++--------- .../python_udf_current_stage_approval.md | 16 ++++++------- .../versions/v4_0_14/upgrade_test.go | 5 ++-- pkg/frontend/python_udf_catalog_test.go | 6 ++--- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 ++-- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 10 ++++---- pkg/sql/compile/remoterun.go | 4 ++-- .../upgrade/upgrade_v4_0_14_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 12 files changed, 40 insertions(+), 38 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index cc1fdda064a36..9ac1931689fb3 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -4,8 +4,8 @@ | --- | --- | | Design revision | `python-udf-current-stage-r5-2026-10-09` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `72d4a49db7d750520e1a1654cb6091fc7169882b` (MORPC 108, catalog 4.0.13) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r5 repair adds catalog 4.0.14 and protocol 109 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `8cc9167cb0a04479cd4c2f083aece5130f8c1946` (MORPC 109, including the native COLUMNS repair in catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r5 repair preserves the upstream catalog 4.0.14 migration, adds the Python revision repair, and uses protocol 110 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -71,12 +71,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `109` (`latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `110` (`latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 109 and above, +revision that would become authoritative later. At protocol 110 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -87,26 +87,27 @@ demo's old execution behavior is not a compatibility promise. Upgrade `4.0.7` contains the original idempotent shared-function schema entries. Its historical protocol-61 requirement belongs to the already-shipped provenance contract; it does not prove Python revision capability. The registered repair -`4.0.14` (minimum direct source `4.0.13`) replays only the nine shared-function -entries. Upstream handlers `4.0.8` through `4.0.13`, including the protocol-107 -statistics view refresh, remain unchanged. Thus a tenant already at upstream +`4.0.14` (minimum direct source `4.0.13`) replays the nine shared-function +entries together with the preserved upstream COLUMNS refresh. Upstream handlers +`4.0.8` through `4.0.13`, including the protocol-107 statistics view refresh, +remain unchanged. Thus a tenant already at upstream final `4.0.13`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 109 before tenant tasks are created, and the repair handler +requires protocol 110 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -109. That value is rollout state in the service runtime, not a computed live +110. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 109. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 110. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -246,7 +247,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-109 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_14/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13, rejection at protocol 108 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-110 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_14/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13, rejection at protocol 109 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 39c981ef2c28e..a830edf44ddf2 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -84,14 +84,14 @@ Against upstream `9df2c4006142a0593f9bb4c40019ee1a8cd2cde7`, the current repair ## r5 rebase maintenance addendum (2026-10-09) -Official main `72d4a49db7d750520e1a1654cb6091fc7169882b` has allocated -MORPC 108 to the user-variable NULL regexp migration contract while retaining -catalog 4.0.13. This proposal uses the next MORPC 109 and a separate catalog 4.0.14 -repair (minimum direct source 4.0.13), preserving the upstream handler unchanged. -The nine idempotent shared-function entries are replayed only by the new handler; -already-upgraded 4.0.13 tenants remain eligible. Sender, receiver, prepared reuse, -physical execution and status RPC admission move together; protocol 108 is the -immediate predecessor rejection case. This is a mechanical compatibility +Official main `8cc9167cb0a04479cd4c2f083aece5130f8c1946` has allocated +MORPC 109 to the native Unicode COLUMNS migration in catalog 4.0.14. This +proposal uses the next MORPC 110 and preserves that upstream migration alongside +the Python revision repair (minimum direct source 4.0.13). The nine idempotent +shared-function entries remain replayed by the combined handler; already-upgraded +4.0.13 tenants remain eligible. Sender, receiver, prepared reuse, physical +execution and status RPC admission move together; protocol 109 is the immediate +predecessor rejection case. This is a mechanical compatibility correction within the existing test/development scope. Independent Architecture and SQL/Planner approval remains pending; no approval is inferred from this addendum or validation. diff --git a/pkg/bootstrap/versions/v4_0_14/upgrade_test.go b/pkg/bootstrap/versions/v4_0_14/upgrade_test.go index 058cc93d269f5..38cbcefa0b264 100644 --- a/pkg/bootstrap/versions/v4_0_14/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_14/upgrade_test.go @@ -143,13 +143,14 @@ func TestColumnsUpgradeLifecycle(t *testing.T) { require.NoError(t, executor.AppendStringRows(r, 0, []string{sysview.InformationSchemaColumnsDDL})) return r.GetResult(), nil }, operator) + entry := upgradeInformationSchemaColumns() require.NoError(t, Handler.Prepare(ctx, txn, true)) - require.NoError(t, upgradeInformationSchemaColumns().Upgrade(txn, 1)) + require.NoError(t, entry.Upgrade(txn, 1)) require.Error(t, Handler.HandleCreateFrameworkDeps(txn)) injected := errors.New("injected") failed := executor.NewMemTxnExecutor(func(string) (executor.Result, error) { return executor.Result{}, injected }, operator) - require.ErrorIs(t, upgradeInformationSchemaColumns().Upgrade(failed, 7), injected) + require.ErrorIs(t, entry.Upgrade(failed, 7), injected) }) } diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index cb5ec5cc73103..c3369c7467e67 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -561,7 +561,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 109"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 110"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -620,12 +620,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion107) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion109) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 109") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 110") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index c1b755d2d3044..5c45ed6f2584c 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion109, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion110, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index d8275c634b088..49147ddcc672e 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,8 +37,8 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion109(t *testing.T) { - assert.Equal(t, defines.MORPCVersion109, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +func TestGetPythonUdfStatusRequiresProtocolVersion110(t *testing.T) { + assert.Equal(t, defines.MORPCVersion110, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 6239f8d60c1be..b0734fe2f2c47 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion109, + {features.PythonRoutineContract, defines.MORPCVersion110, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index ac86ae9442053..b5ad4547928f0 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion109) + required = max(required, defines.MORPCVersion110) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 67cf79edf4ff0..3a17a6ebb70b0 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -551,20 +551,20 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion109, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion110, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion108, defines.MORPCVersion109} { + for _, version := range []int64{defines.MORPCVersion109, defines.MORPCVersion110} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion109 { + if version < defines.MORPCVersion110 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion108) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion109) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion110) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 4f57a9fffa5e9..4d6d04bba4b5d 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion109) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 109") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion110) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 110") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go index 90d57526d5ddd..43e15b0c75b87 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go @@ -127,7 +127,7 @@ func TestV4014LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 109") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 110") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 85fa8bd35c272..310fc7904a7f1 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion109 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion110 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From 709e1e1b8abe8e9424e99eda686fec690f51598b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 11 Oct 2026 00:17:09 +0800 Subject: [PATCH 217/241] test(optools): isolate embedded watchdog fixture by platform --- optools/ut_embedded_schedule_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/optools/ut_embedded_schedule_test.go b/optools/ut_embedded_schedule_test.go index 5d1f7a9e37b2f..ea66fb4cbcf39 100644 --- a/optools/ut_embedded_schedule_test.go +++ b/optools/ut_embedded_schedule_test.go @@ -18,6 +18,7 @@ import ( "encoding/json" "fmt" "os/exec" + "runtime" "strings" "testing" ) @@ -1046,6 +1047,9 @@ printf 'REVIEW signal=%s status=%s flag=%s retained=%s live_groups=%s later=%s\n } func TestEmbeddedPrebuiltFailureKeepsReportJSONOnly(t *testing.T) { + if runtime.GOOS != "linux" { + t.Skip("prebuilt watchdog force-stop fixture relies on Linux process-group semantics") + } t.Parallel() for _, parallel := range []string{"1", "2"} { t.Run("parallel="+parallel, func(t *testing.T) { @@ -1058,8 +1062,16 @@ function logger() { printf '%s\n' "$*"; } first_group_pid="" watchdog_group_pid="" watchdog_probe_count=0 +execution_started=0 function ut_process_group_alive() { local pid=$1 + if [[ ! -e "$CASE_DIR/execution-start" ]]; then return 1; fi + if (( execution_started == 0 )); then + first_group_pid="" + watchdog_group_pid="" + watchdog_probe_count=0 + execution_started=1 + fi if [[ -z "$first_group_pid" ]]; then first_group_pid=$pid return 1 @@ -1077,6 +1089,7 @@ function ut_process_group_alive() { } start_embedded_prebuild "$scope" 1 status=0 +touch "$CASE_DIR/execution-start" run_embedded_tests "$scope" 2 > "$CASE_DIR/outer-log" || status=$? [[ "$status" != 0 ]] || exit 90 cat "$UT_REPORT" From 1881c608388568120bc9bed3a541dd451afe2732 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sun, 11 Oct 2026 11:02:53 +0800 Subject: [PATCH 218/241] fix(udf): repair revision restore and preserve published upgrade handlers --- docs/design/python_udf_current_stage.md | 18 +- .../python_udf_current_stage_approval.md | 18 +- optools/ut_embedded_schedule_test.go | 61 ++--- .../versions/v4_0_14/tenant_upgrade_list.go | 10 +- pkg/bootstrap/versions/v4_0_14/upgrade.go | 21 +- .../versions/v4_0_14/upgrade_test.go | 217 +--------------- .../versions/v4_0_15/tenant_upgrade_list.go | 70 +----- pkg/bootstrap/versions/v4_0_15/upgrade.go | 22 +- .../versions/v4_0_15/upgrade_test.go | 236 ++++++++++++++++++ pkg/frontend/catalog_ddl_context_test.go | 26 +- pkg/frontend/snapshot_catalog_restore.go | 5 +- ...est.go => upgrade_v4_0_15_routine_test.go} | 14 +- 12 files changed, 353 insertions(+), 365 deletions(-) create mode 100644 pkg/bootstrap/versions/v4_0_15/upgrade_test.go rename pkg/tests/upgrade/{upgrade_v4_0_14_routine_test.go => upgrade_v4_0_15_routine_test.go} (95%) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 9ac1931689fb3..070244f70a443 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r5-2026-10-09` | +| Design revision | `python-udf-current-stage-r6-2026-10-11` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `8cc9167cb0a04479cd4c2f083aece5130f8c1946` (MORPC 109, including the native COLUMNS repair in catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r5 repair preserves the upstream catalog 4.0.14 migration, adds the Python revision repair, and uses protocol 110 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `4022729da24d71b082c22b52aaed3faba2b77ea5` (MORPC 109, including the native COLUMNS repair in catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r6 repair preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 110 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -87,11 +87,11 @@ demo's old execution behavior is not a compatibility promise. Upgrade `4.0.7` contains the original idempotent shared-function schema entries. Its historical protocol-61 requirement belongs to the already-shipped provenance contract; it does not prove Python revision capability. The registered repair -`4.0.14` (minimum direct source `4.0.13`) replays the nine shared-function -entries together with the preserved upstream COLUMNS refresh. Upstream handlers -`4.0.8` through `4.0.13`, including the protocol-107 statistics view refresh, -remain unchanged. Thus a tenant already at upstream -final `4.0.13`, including one lacking revision tables, still +`4.0.15` (minimum direct source `4.0.14`) replays the nine shared-function +entries. Upstream handlers `4.0.8` through `4.0.14`, including the protocol-107 +statistics view refresh and the protocol-109 COLUMNS refresh, remain unchanged. +Thus a tenant already at upstream final `4.0.14`, including one lacking revision +tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata requires protocol 110 before tenant tasks are created, and the repair handler @@ -247,7 +247,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-110 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_14/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13, rejection at protocol 109 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-110 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 109 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index a830edf44ddf2..3b091975dbaeb 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r5-2026-10-09`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r6-2026-10-11`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -95,3 +95,19 @@ predecessor rejection case. This is a mechanical compatibility correction within the existing test/development scope. Independent Architecture and SQL/Planner approval remains pending; no approval is inferred from this addendum or validation. + +## r6 maintenance addendum (2026-10-11) + +Against official main `4022729da24d71b082c22b52aaed3faba2b77ea5`, +MORPC remains 109, so this proposal retains capability 110 and immediate +predecessor 109. The r5 combined 4.0.14 handler above is superseded: a tenant +already at the official final 4.0.14 would not be scheduled by that version. +The r6 proposal preserves the upstream 4.0.14 handler exactly and registers +Python repair 4.0.15 with minimum direct source 4.0.14. It replays only the nine +idempotent shared-function entries, gates catalog access at protocol 110, and +covers real first-login repair from 4.0.12, 4.0.13 and 4.0.14. Revision-table +snapshot/PITR restore also uses the same trusted catalog DDL context as the +head-table restore; ordinary user DDL does not acquire that context. +This maintenance stays within the authorized test/development scope. +Independent Architecture and SQL/Planner approval remains pending; this +addendum records implementation changes and does not grant approval. diff --git a/optools/ut_embedded_schedule_test.go b/optools/ut_embedded_schedule_test.go index ea66fb4cbcf39..bdce22ba2169c 100644 --- a/optools/ut_embedded_schedule_test.go +++ b/optools/ut_embedded_schedule_test.go @@ -18,7 +18,6 @@ import ( "encoding/json" "fmt" "os/exec" - "runtime" "strings" "testing" ) @@ -1047,49 +1046,34 @@ printf 'REVIEW signal=%s status=%s flag=%s retained=%s live_groups=%s later=%s\n } func TestEmbeddedPrebuiltFailureKeepsReportJSONOnly(t *testing.T) { - if runtime.GOOS != "linux" { - t.Skip("prebuilt watchdog force-stop fixture relies on Linux process-group semantics") - } t.Parallel() for _, parallel := range []string{"1", "2"} { t.Run("parallel="+parallel, func(t *testing.T) { script := embeddedSetup + ` function logger() { printf '%s\n' "$*"; } - # Keep the active test process groups false, then force only the first - # watchdog cleanup wait through its bounded force-stop branch. The - # diagnostic must remain in UT_STDERR; a missing redirection contaminates - # UT_REPORT. -first_group_pid="" -watchdog_group_pid="" -watchdog_probe_count=0 -execution_started=0 +# Inject one live probe only at the explicitly selected watchdog cleanup. +# Prebuild children, test processes and parent joins keep their real probes. +# A zero grace period reaches force-stop without a wall-clock phase trigger. +eval "$(declare -f ut_process_group_alive | sed '1s/ut_process_group_alive/original_ut_process_group_alive/')" function ut_process_group_alive() { - local pid=$1 - if [[ ! -e "$CASE_DIR/execution-start" ]]; then return 1; fi - if (( execution_started == 0 )); then - first_group_pid="" - watchdog_group_pid="" - watchdog_probe_count=0 - execution_started=1 - fi - if [[ -z "$first_group_pid" ]]; then - first_group_pid=$pid - return 1 - fi - if [[ "$pid" == "$first_group_pid" ]]; then return 1; fi - if [[ -z "$watchdog_group_pid" ]]; then - watchdog_group_pid=$pid + if [[ "$1" == "${forced_watchdog_pid:-}" ]] && (( forced_watchdog_probes == 0 )); then + forced_watchdog_probes=1 + return 0 fi - if [[ "$pid" == "$watchdog_group_pid" ]]; then - watchdog_probe_count=$((watchdog_probe_count + 1)) - if (( watchdog_probe_count <= 21 )); then return 0; fi - return 1 + original_ut_process_group_alive "$@" +} +force_stop_injected=0 +function wait_for_fixture_watchdog() { + if (( force_stop_injected != 0 )); then + wait_for_ut_process_group "$@" + return $? fi - return 1 + force_stop_injected=1 + local forced_watchdog_pid=$1 forced_watchdog_probes=0 + wait_for_ut_process_group "$1" 0 } start_embedded_prebuild "$scope" 1 status=0 -touch "$CASE_DIR/execution-start" run_embedded_tests "$scope" 2 > "$CASE_DIR/outer-log" || status=$? [[ "$status" != 0 ]] || exit 90 cat "$UT_REPORT" @@ -1097,7 +1081,16 @@ cat "$UT_REPORT" grep -q 'prebuilt embedded package example/b failed' "$UT_STDERR" || exit 92 grep -q 'UT cancellation: force stopping process group' "$UT_STDERR" || exit 93 ` - out, err := scheduleHarnessWithMockTransform(t, script, embeddedGoMock, nil, + transform := func(text string) string { + const anchor = `wait_for_ut_process_group "${watchdog_pids[index]}" 20` + if strings.Count(text, anchor) != 1 { + t.Fatal("missing unique watchdog cleanup wait") + } + // Preserve the call's redirection: removing it must contaminate + // the real JSON report and fail the independent parser oracle. + return strings.Replace(text, anchor, `wait_for_fixture_watchdog "${watchdog_pids[index]}" 20`, 1) + } + out, err := scheduleHarnessWithMockTransform(t, script, embeddedGoMock, transform, "MODE=test-failure", "UT_PREBUILD_EMBEDDED=1", "UT_HARD_TIMEOUT=", "UT_EMBEDDED_PACKAGE_PARALLEL="+parallel) if err != nil { t.Fatalf("embedded failure JSON report: %v\n%s", err, out) diff --git a/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go b/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go index ca18f683c9f5e..124ff85ecaca6 100644 --- a/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go +++ b/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go @@ -18,20 +18,12 @@ import ( "fmt" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/defines" "github.com/matrixorigin/matrixone/pkg/util/executor" "github.com/matrixorigin/matrixone/pkg/util/sysview" ) -// The v4.0.14 repair replays both the native COLUMNS view migration introduced -// by the upstream branch and the idempotent Python UDF revision catalog repair. -// Keep these entries in one version so tenants that already recorded v4.0.13 -// receive either or both repairs on the same upgrade attempt. -var tenantUpgEntries = append( - []versions.UpgradeEntry{upgradeInformationSchemaColumns()}, - v4_0_7.PythonRevisionUpgradeEntries()..., -) +var tenantUpgEntries = []versions.UpgradeEntry{upgradeInformationSchemaColumns()} // upgradeInformationSchemaColumns refreshes the persisted COLUMNS view for // tenants that already passed the protocol-100 view migration. The current diff --git a/pkg/bootstrap/versions/v4_0_14/upgrade.go b/pkg/bootstrap/versions/v4_0_14/upgrade.go index 64d2947dad8a8..e2ecc58ba65f5 100644 --- a/pkg/bootstrap/versions/v4_0_14/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_14/upgrade.go @@ -27,12 +27,6 @@ import ( "go.uber.org/zap" ) -// 4.0.14 replays the idempotent shared Python UDF catalog entries together -// with the upstream COLUMNS view repair. An upstream-final 4.0.13 tenant may -// lack either repair; this newer registered handler ensures the upgrade -// framework schedules both repairs. Earlier tenants first traverse the -// unchanged upstream handlers through 4.0.13. Complete, partial and absent -// catalog states converge on retry. var Handler = &versionHandle{ metadata: versions.Version{ Version: "4.0.14", @@ -40,7 +34,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion110, + RequiredProtocolVersion: defines.MORPCVersion109, }, } @@ -52,17 +46,12 @@ func (v *versionHandle) Metadata() versions.Version { return v.metadata } -func (v *versionHandle) Prepare(ctx context.Context, txn executor.TxnExecutor, final bool) error { +func (v *versionHandle) Prepare(_ context.Context, txn executor.TxnExecutor, _ bool) error { txn.Use(catalog.MO_CATALOG) return nil } -func (v *versionHandle) HandleTenantUpgrade(ctx context.Context, tenantID int32, txn executor.TxnExecutor) error { - // Login compensation invokes this handler without the cluster-upgrade - // scheduler, so enforce the same floor before any catalog mutation. - if err := versions.CheckCommonProtocolVersion(txn, v.metadata.RequiredProtocolVersion); err != nil { - return err - } +func (v *versionHandle) HandleTenantUpgrade(_ context.Context, tenantID int32, txn executor.TxnExecutor) error { logger := runtime.ServiceRuntime(txn.Txn().TxnOptions().CN).Logger() for _, entry := range tenantUpgEntries { start := time.Now() @@ -83,10 +72,10 @@ func (v *versionHandle) HandleTenantUpgrade(ctx context.Context, tenantID int32, return nil } -func (v *versionHandle) HandleClusterUpgrade(ctx context.Context, txn executor.TxnExecutor) error { +func (v *versionHandle) HandleClusterUpgrade(_ context.Context, _ executor.TxnExecutor) error { return nil } -func (v *versionHandle) HandleCreateFrameworkDeps(txn executor.TxnExecutor) error { +func (v *versionHandle) HandleCreateFrameworkDeps(_ executor.TxnExecutor) error { return moerr.NewInternalErrorNoCtxf("Only v1.2.0 can initialize upgrade framework, current version is:%s", v.metadata.Version) } diff --git a/pkg/bootstrap/versions/v4_0_14/upgrade_test.go b/pkg/bootstrap/versions/v4_0_14/upgrade_test.go index 38cbcefa0b264..7febbbc93b6f0 100644 --- a/pkg/bootstrap/versions/v4_0_14/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_14/upgrade_test.go @@ -17,13 +17,11 @@ package v4_0_14 import ( "context" "errors" - "fmt" "strings" "testing" "github.com/golang/mock/gomock" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/mpool" "github.com/matrixorigin/matrixone/pkg/common/runtime" @@ -42,9 +40,9 @@ func TestColumnsUpgradeMetadata(t *testing.T) { require.Equal(t, "4.0.13", m.MinUpgradeVersion) require.Equal(t, versions.Yes, m.UpgradeTenant) require.Equal(t, versions.No, m.UpgradeCluster) - require.Equal(t, defines.MORPCVersion110, m.RequiredProtocolVersion) - require.Equal(t, uint32(1+len(v4_0_7.PythonRevisionUpgradeEntries())), m.VersionOffset) - require.Len(t, tenantUpgEntries, 1+len(v4_0_7.PythonRevisionUpgradeEntries())) + require.Equal(t, defines.MORPCVersion109, m.RequiredProtocolVersion) + require.Equal(t, uint32(1), m.VersionOffset) + require.Len(t, tenantUpgEntries, 1) require.Equal(t, int64(defines.MORPCVersion109), tenantUpgEntries[0].RequiredProtocolVersion) } @@ -143,217 +141,12 @@ func TestColumnsUpgradeLifecycle(t *testing.T) { require.NoError(t, executor.AppendStringRows(r, 0, []string{sysview.InformationSchemaColumnsDDL})) return r.GetResult(), nil }, operator) - entry := upgradeInformationSchemaColumns() require.NoError(t, Handler.Prepare(ctx, txn, true)) - require.NoError(t, entry.Upgrade(txn, 1)) + require.NoError(t, Handler.HandleTenantUpgrade(ctx, 1, txn)) require.Error(t, Handler.HandleCreateFrameworkDeps(txn)) injected := errors.New("injected") failed := executor.NewMemTxnExecutor(func(string) (executor.Result, error) { return executor.Result{}, injected }, operator) - require.ErrorIs(t, entry.Upgrade(failed, 7), injected) + require.ErrorIs(t, Handler.HandleTenantUpgrade(ctx, 7, failed), injected) }) } - -func TestPythonRevisionRepairUpgradePath(t *testing.T) { - metadata := Handler.Metadata() - require.Equal(t, "4.0.14", metadata.Version) - require.Equal(t, "4.0.13", metadata.MinUpgradeVersion) - require.Equal(t, versions.No, metadata.UpgradeCluster) - require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion110), metadata.RequiredProtocolVersion) - require.Equal(t, uint32(1+len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) - require.True(t, metadata.CanDirectUpgrade("4.0.13")) - require.False(t, metadata.CanDirectUpgrade("4.0.7")) - require.Len(t, v4_0_7.PythonRevisionUpgradeEntries(), 9) -} - -func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { - for _, response := range []string{ - `{"result":"cn-a:109"}`, - `{"result":"cn-a:110,cn-b:109"}`, - `{"result":""}`, - `invalid`, - } { - t.Run(response, func(t *testing.T) { - var statements []string - txn := executor.NewMemTxnExecutor(func(statement string) (executor.Result, error) { - statements = append(statements, statement) - require.Equal(t, "SELECT mo_ctl('cn', 'GetProtocolVersion', '')", statement) - return repairStringResult(t, response), nil - }, nil) - err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 110") - require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) - }) - } -} - -func TestPythonRevisionRepairIsIdempotentForCatalogStates(t *testing.T) { - for _, test := range []struct { - name string - schemaOrigin string - columns []string - newIndex bool - legacyIndex bool - revisionTable bool - wantFirstDDL int - }{ - { - name: "upstream_final_4.0.13_missed_catalog", - schemaOrigin: "4.0.13", - legacyIndex: true, - wantFirstDDL: 9, - }, - { - name: "partial_revision_catalog", - schemaOrigin: "4.0.8", - columns: []string{ - "active_revision", "namespace_version", "canonical_input_descriptor", - "return_descriptor", "signature_key_schema_version", "signature_fingerprint", - }, - legacyIndex: true, - wantFirstDDL: 3, - }, - { - name: "complete_revision_catalog", - schemaOrigin: "4.0.8", - columns: []string{ - "active_revision", "namespace_version", "canonical_input_descriptor", - "return_descriptor", "signature_key_schema_version", "signature_fingerprint", - }, - newIndex: true, - revisionTable: true, - wantFirstDDL: 0, - }, - } { - t.Run(test.name, func(t *testing.T) { - runtime.RunTest("", func(runtime.Runtime) { - state := &pythonRevisionCatalogState{ - columns: make(map[string]bool), - newIndex: test.newIndex, - legacyIndex: test.legacyIndex, - revisionTable: test.revisionTable, - } - for _, column := range test.columns { - state.columns[column] = true - } - txn := newRepairTxnExecutor(t, state) - require.NoError(t, Handler.Prepare(context.Background(), txn, true)) - require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) - require.Len(t, state.ddl, test.wantFirstDDL, - "repair of %s schema must apply only missing catalog objects", test.schemaOrigin) - firstDDL := append([]string(nil), state.ddl...) - require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) - require.Equal(t, firstDDL, state.ddl, - "a restart/retry of %s schema must not repeat DDL", test.schemaOrigin) - }) - }) - } -} - -type pythonRevisionCatalogState struct { - columns map[string]bool - newIndex bool - legacyIndex bool - revisionTable bool - ddl []string -} - -func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) executor.TxnExecutor { - t.Helper() - txnOperator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) - txnOperator.EXPECT().TxnOptions().Return(pbtxn.TxnOptions{}).AnyTimes() - return executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { - lower := strings.ToLower(sql) - switch { - case strings.Contains(lower, "select tbl.rel_createsql"): - return repairStringResult(t, sysview.InformationSchemaColumnsDDL), nil - case strings.Contains(lower, "from mo_catalog.mo_columns"): - for column := range state.columns { - if strings.Contains(sql, fmt.Sprintf("attname = '%s'", column)) { - return repairColumnResult(t), nil - } - } - return executor.Result{}, nil - case strings.Contains(lower, "from `mo_catalog`.`mo_indexes`"): - if strings.Contains(sql, "name_db_arg_types_descriptor") && state.newIndex { - return repairStringResult(t, "name_db_arg_types_descriptor"), nil - } - if strings.Contains(sql, "name_db_arg_types'") && state.legacyIndex { - return repairStringResult(t, "name_db_arg_types"), nil - } - return executor.Result{}, nil - case strings.Contains(lower, "from mo_catalog.mo_tables"): - if state.revisionTable && strings.Contains(sql, "relname = 'mo_function_revisions'") { - return repairStringResult(t, "mo_function_revisions"), nil - } - return executor.Result{}, nil - case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:110"}`), nil - case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): - for column := range state.columns { - if strings.Contains(sql, "add column "+column+" ") { - return executor.Result{}, nil - } - } - for _, column := range []string{ - "active_revision", "namespace_version", "canonical_input_descriptor", - "return_descriptor", "signature_key_schema_version", "signature_fingerprint", - } { - if strings.Contains(sql, "add column "+column+" ") { - state.columns[column] = true - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - } - } - case strings.Contains(lower, "create unique index name_db_arg_types_descriptor"): - state.newIndex = true - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - case strings.Contains(lower, "drop index name_db_arg_types"): - state.legacyIndex = false - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - case strings.Contains(lower, "create table mo_catalog.mo_function_revisions"): - state.revisionTable = true - state.ddl = append(state.ddl, sql) - return executor.Result{}, nil - default: - return executor.Result{}, fmt.Errorf("unexpected repair SQL: %s", sql) - } - return executor.Result{}, nil - }, txnOperator) -} - -func repairStringResult(t *testing.T, value string) executor.Result { - t.Helper() - mp := mpool.MustNewZeroNoFixed() - t.Cleanup(func() { mpool.DeleteMPool(mp) }) - result := executor.NewMemResult([]types.Type{types.T_varchar.ToType()}, mp) - result.NewBatchWithRowCount(1) - require.NoError(t, executor.AppendStringRows(result, 0, []string{value})) - return result.GetResult() -} - -func repairColumnResult(t *testing.T) executor.Result { - t.Helper() - mp := mpool.MustNewZeroNoFixed() - t.Cleanup(func() { mpool.DeleteMPool(mp) }) - result := executor.NewMemResult([]types.Type{ - types.T_varchar.ToType(), types.T_varchar.ToType(), - types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), - types.T_int32.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), - }, mp) - result.NewBatchWithRowCount(1) - require.NoError(t, executor.AppendStringRows(result, 0, []string{"BIGINT UNSIGNED"})) - require.NoError(t, executor.AppendStringRows(result, 1, []string{"NO"})) - require.NoError(t, executor.AppendFixedRows(result, 2, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 3, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 4, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 5, []int64{0})) - require.NoError(t, executor.AppendFixedRows(result, 6, []int32{1})) - require.NoError(t, executor.AppendStringRows(result, 7, []string{"0"})) - require.NoError(t, executor.AppendStringRows(result, 8, []string{""})) - require.NoError(t, executor.AppendStringRows(result, 9, []string{""})) - return result.GetResult() -} diff --git a/pkg/bootstrap/versions/v4_0_15/tenant_upgrade_list.go b/pkg/bootstrap/versions/v4_0_15/tenant_upgrade_list.go index 4d082e5c658d8..3188f09250a90 100644 --- a/pkg/bootstrap/versions/v4_0_15/tenant_upgrade_list.go +++ b/pkg/bootstrap/versions/v4_0_15/tenant_upgrade_list.go @@ -4,7 +4,7 @@ // 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 +// 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, @@ -14,68 +14,8 @@ package v4_0_15 -import ( - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/catalog" - "github.com/matrixorigin/matrixone/pkg/defines" - "github.com/matrixorigin/matrixone/pkg/util/executor" - "github.com/matrixorigin/matrixone/pkg/util/sysview" -) +import "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" -var tenantUpgEntries = []versions.UpgradeEntry{ - { - Schema: catalog.MO_CATALOG, - TableName: catalog.MODatabaseDefaults, - UpgType: versions.CREATE_NEW_TABLE, - UpgSql: catalog.MoDatabaseDefaultsDDL, - RequiredProtocolVersion: defines.MORPCVersion118, - CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { - return versions.CheckTableDefinition(txn, accountID, catalog.MO_CATALOG, catalog.MODatabaseDefaults) - }, - }, - { - Schema: sysview.InformationDBConst, - TableName: "SCHEMATA", - UpgType: versions.MODIFY_VIEW, - UpgSql: sysview.InformationSchemaSchemataDDL, - PreSql: "DROP VIEW IF EXISTS information_schema.SCHEMATA;", - RequiredProtocolVersion: defines.MORPCVersion118, - CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { - exists, definition, err := versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "SCHEMATA") - if err == nil && !exists { - exists, definition, err = versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "schemata") - } - return exists && definition == sysview.InformationSchemaSchemataDDL, err - }, - }, - { - Schema: sysview.InformationDBConst, - TableName: "COLUMNS", - UpgType: versions.MODIFY_VIEW, - UpgSql: sysview.InformationSchemaColumnsDDL, - PreSql: "DROP VIEW IF EXISTS information_schema.COLUMNS;", - RequiredProtocolVersion: defines.MORPCVersion118, - CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { - exists, definition, err := versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "COLUMNS") - if err == nil && !exists { - exists, definition, err = versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "columns") - } - return exists && definition == sysview.InformationSchemaColumnsDDL, err - }, - }, - { - Schema: sysview.InformationDBConst, - TableName: "TABLES", - UpgType: versions.MODIFY_VIEW, - UpgSql: sysview.InformationSchemaTablesV118DDL, - PreSql: "DROP VIEW IF EXISTS information_schema.TABLES;", - RequiredProtocolVersion: defines.MORPCVersion118, - CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { - exists, definition, err := versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "TABLES") - if err == nil && !exists { - exists, definition, err = versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "tables") - } - return exists && definition == sysview.InformationSchemaTablesV118DDL, err - }, - }, -} +// This repair is newer than every published upstream tenant version, so an +// already-upgraded tenant is scheduled even if it lacks the revision catalog. +var tenantUpgEntries = v4_0_7.PythonRevisionUpgradeEntries() diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade.go b/pkg/bootstrap/versions/v4_0_15/upgrade.go index 57a1c52ed8f33..ff633c2634a08 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade.go @@ -27,8 +27,11 @@ import ( "go.uber.org/zap" ) -// Database defaults have their own tenant migration after 4.0.14. An older -// worker must not treat the new catalog and SCHEMATA view as already upgraded. +// 4.0.15 replays the idempotent shared Python UDF catalog entries without +// changing the already-published upstream handlers. Tenants that completed +// upstream 4.0.14 may still lack this catalog; a new semantic version makes +// them eligible for both background upgrade and first-login compensation. +// Complete, partial and absent catalog states converge on retry. var Handler = &versionHandle{ metadata: versions.Version{ Version: "4.0.15", @@ -36,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion118, + RequiredProtocolVersion: defines.MORPCVersion110, }, } @@ -48,12 +51,17 @@ func (v *versionHandle) Metadata() versions.Version { return v.metadata } -func (v *versionHandle) Prepare(_ context.Context, txn executor.TxnExecutor, _ bool) error { +func (v *versionHandle) Prepare(ctx context.Context, txn executor.TxnExecutor, final bool) error { txn.Use(catalog.MO_CATALOG) return nil } -func (v *versionHandle) HandleTenantUpgrade(_ context.Context, tenantID int32, txn executor.TxnExecutor) error { +func (v *versionHandle) HandleTenantUpgrade(ctx context.Context, tenantID int32, txn executor.TxnExecutor) error { + // Login compensation invokes this handler without the cluster-upgrade + // scheduler, so enforce the same floor before any catalog mutation. + if err := versions.CheckCommonProtocolVersion(txn, v.metadata.RequiredProtocolVersion); err != nil { + return err + } logger := runtime.ServiceRuntime(txn.Txn().TxnOptions().CN).Logger() for _, entry := range tenantUpgEntries { start := time.Now() @@ -74,10 +82,10 @@ func (v *versionHandle) HandleTenantUpgrade(_ context.Context, tenantID int32, t return nil } -func (v *versionHandle) HandleClusterUpgrade(_ context.Context, _ executor.TxnExecutor) error { +func (v *versionHandle) HandleClusterUpgrade(ctx context.Context, txn executor.TxnExecutor) error { return nil } -func (v *versionHandle) HandleCreateFrameworkDeps(_ executor.TxnExecutor) error { +func (v *versionHandle) HandleCreateFrameworkDeps(txn executor.TxnExecutor) error { return moerr.NewInternalErrorNoCtxf("Only v1.2.0 can initialize upgrade framework, current version is:%s", v.metadata.Version) } diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go new file mode 100644 index 0000000000000..d57fd38c7a854 --- /dev/null +++ b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go @@ -0,0 +1,236 @@ +// Copyright 2026 Matrix Origin +// +// 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 v4_0_15 + +import ( + "context" + "fmt" + "strings" + "testing" + + "github.com/golang/mock/gomock" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" + "github.com/matrixorigin/matrixone/pkg/common/mpool" + "github.com/matrixorigin/matrixone/pkg/common/runtime" + "github.com/matrixorigin/matrixone/pkg/container/types" + "github.com/matrixorigin/matrixone/pkg/defines" + mock_frontend "github.com/matrixorigin/matrixone/pkg/frontend/test" + pbtxn "github.com/matrixorigin/matrixone/pkg/pb/txn" + "github.com/matrixorigin/matrixone/pkg/util/executor" + "github.com/stretchr/testify/require" +) + +func TestPythonRevisionRepairUpgradePath(t *testing.T) { + metadata := Handler.Metadata() + require.Equal(t, "4.0.15", metadata.Version) + require.Equal(t, "4.0.14", metadata.MinUpgradeVersion) + require.Equal(t, versions.No, metadata.UpgradeCluster) + require.Equal(t, versions.Yes, metadata.UpgradeTenant) + require.Equal(t, int64(defines.MORPCVersion110), metadata.RequiredProtocolVersion) + require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) + require.True(t, metadata.CanDirectUpgrade("4.0.14")) + require.False(t, metadata.CanDirectUpgrade("4.0.13")) + require.Len(t, v4_0_7.PythonRevisionUpgradeEntries(), 9) +} + +func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { + for _, response := range []string{ + `{"result":"cn-a:109"}`, + `{"result":"cn-a:110,cn-b:109"}`, + `{"result":""}`, + `invalid`, + } { + t.Run(response, func(t *testing.T) { + var statements []string + txn := executor.NewMemTxnExecutor(func(statement string) (executor.Result, error) { + statements = append(statements, statement) + require.Equal(t, "SELECT mo_ctl('cn', 'GetProtocolVersion', '')", statement) + return repairStringResult(t, response), nil + }, nil) + err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 110") + require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) + }) + } +} + +func TestPythonRevisionRepairIsIdempotentForCatalogStates(t *testing.T) { + for _, test := range []struct { + name string + schemaOrigin string + columns []string + newIndex bool + legacyIndex bool + revisionTable bool + wantFirstDDL int + }{ + { + name: "upstream_final_4.0.14_missed_catalog", + schemaOrigin: "4.0.14", + legacyIndex: true, + wantFirstDDL: 9, + }, + { + name: "partial_revision_catalog", + schemaOrigin: "4.0.8", + columns: []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + }, + legacyIndex: true, + wantFirstDDL: 3, + }, + { + name: "complete_revision_catalog", + schemaOrigin: "4.0.8", + columns: []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + }, + newIndex: true, + revisionTable: true, + wantFirstDDL: 0, + }, + } { + t.Run(test.name, func(t *testing.T) { + runtime.RunTest("", func(runtime.Runtime) { + state := &pythonRevisionCatalogState{ + columns: make(map[string]bool), + newIndex: test.newIndex, + legacyIndex: test.legacyIndex, + revisionTable: test.revisionTable, + } + for _, column := range test.columns { + state.columns[column] = true + } + txn := newRepairTxnExecutor(t, state) + require.NoError(t, Handler.Prepare(context.Background(), txn, true)) + require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) + require.Len(t, state.ddl, test.wantFirstDDL, + "repair of %s schema must apply only missing catalog objects", test.schemaOrigin) + firstDDL := append([]string(nil), state.ddl...) + require.NoError(t, Handler.HandleTenantUpgrade(context.Background(), 7, txn)) + require.Equal(t, firstDDL, state.ddl, + "a restart/retry of %s schema must not repeat DDL", test.schemaOrigin) + }) + }) + } +} + +type pythonRevisionCatalogState struct { + columns map[string]bool + newIndex bool + legacyIndex bool + revisionTable bool + ddl []string +} + +func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) executor.TxnExecutor { + t.Helper() + txnOperator := mock_frontend.NewMockTxnOperator(gomock.NewController(t)) + txnOperator.EXPECT().TxnOptions().Return(pbtxn.TxnOptions{}).AnyTimes() + return executor.NewMemTxnExecutor(func(sql string) (executor.Result, error) { + lower := strings.ToLower(sql) + switch { + case strings.Contains(lower, "from mo_catalog.mo_columns"): + for column := range state.columns { + if strings.Contains(sql, fmt.Sprintf("attname = '%s'", column)) { + return repairColumnResult(t), nil + } + } + return executor.Result{}, nil + case strings.Contains(lower, "from `mo_catalog`.`mo_indexes`"): + if strings.Contains(sql, "name_db_arg_types_descriptor") && state.newIndex { + return repairStringResult(t, "name_db_arg_types_descriptor"), nil + } + if strings.Contains(sql, "name_db_arg_types'") && state.legacyIndex { + return repairStringResult(t, "name_db_arg_types"), nil + } + return executor.Result{}, nil + case strings.Contains(lower, "from mo_catalog.mo_tables"): + if state.revisionTable && strings.Contains(sql, "relname = 'mo_function_revisions'") { + return repairStringResult(t, "mo_function_revisions"), nil + } + return executor.Result{}, nil + case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:110"}`), nil + case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): + for column := range state.columns { + if strings.Contains(sql, "add column "+column+" ") { + return executor.Result{}, nil + } + } + for _, column := range []string{ + "active_revision", "namespace_version", "canonical_input_descriptor", + "return_descriptor", "signature_key_schema_version", "signature_fingerprint", + } { + if strings.Contains(sql, "add column "+column+" ") { + state.columns[column] = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + } + } + case strings.Contains(lower, "create unique index name_db_arg_types_descriptor"): + state.newIndex = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + case strings.Contains(lower, "drop index name_db_arg_types"): + state.legacyIndex = false + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + case strings.Contains(lower, "create table mo_catalog.mo_function_revisions"): + state.revisionTable = true + state.ddl = append(state.ddl, sql) + return executor.Result{}, nil + default: + return executor.Result{}, fmt.Errorf("unexpected repair SQL: %s", sql) + } + return executor.Result{}, nil + }, txnOperator) +} + +func repairStringResult(t *testing.T, value string) executor.Result { + t.Helper() + mp := mpool.MustNewZeroNoFixed() + t.Cleanup(func() { mpool.DeleteMPool(mp) }) + result := executor.NewMemResult([]types.Type{types.T_varchar.ToType()}, mp) + result.NewBatchWithRowCount(1) + require.NoError(t, executor.AppendStringRows(result, 0, []string{value})) + return result.GetResult() +} + +func repairColumnResult(t *testing.T) executor.Result { + t.Helper() + mp := mpool.MustNewZeroNoFixed() + t.Cleanup(func() { mpool.DeleteMPool(mp) }) + result := executor.NewMemResult([]types.Type{ + types.T_varchar.ToType(), types.T_varchar.ToType(), + types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), types.T_int64.ToType(), + types.T_int32.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), types.T_varchar.ToType(), + }, mp) + result.NewBatchWithRowCount(1) + require.NoError(t, executor.AppendStringRows(result, 0, []string{"BIGINT UNSIGNED"})) + require.NoError(t, executor.AppendStringRows(result, 1, []string{"NO"})) + require.NoError(t, executor.AppendFixedRows(result, 2, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 3, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 4, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 5, []int64{0})) + require.NoError(t, executor.AppendFixedRows(result, 6, []int32{1})) + require.NoError(t, executor.AppendStringRows(result, 7, []string{"0"})) + require.NoError(t, executor.AppendStringRows(result, 8, []string{""})) + require.NoError(t, executor.AppendStringRows(result, 9, []string{""})) + return result.GetResult() +} diff --git a/pkg/frontend/catalog_ddl_context_test.go b/pkg/frontend/catalog_ddl_context_test.go index 7e3ee4ff29df9..c414779108001 100644 --- a/pkg/frontend/catalog_ddl_context_test.go +++ b/pkg/frontend/catalog_ddl_context_test.go @@ -45,12 +45,18 @@ func (e *catalogDDLContextExec) Exec(ctx context.Context, sql string) error { } func TestCatalogDDLOwnsInternalExecutionContext(t *testing.T) { - for _, scenario := range []string{"new account", "current-schema restore"} { + for _, scenario := range []string{"new account", "legacy head restore", "current head restore", "legacy revision restore", "current revision restore"} { t.Run(scenario, func(t *testing.T) { ctx := defines.AttachAccountId(t.Context(), 42) bh := &backgroundExecTest{} bh.init() + // Current revision restore validates its copied rows. Model an empty + // catalog explicitly so this admission test still traverses validation. + query := "select " + functionRevisionCatalogColumns + " from " + + qualifiedTableName(moCatalog, "mo_function_revisions") + " order by function_id, revision;" + bh.sql2result[query] = &MysqlResultSet{} capture := &catalogDDLContextExec{BackgroundExec: bh, t: t} + ddl := MoCatalogMoUserDefinedFunctionDDL if scenario == "new account" { pu := config.NewParameterUnit(&config.FrontendParameters{}, nil, nil, nil) pu.SV.SetDefaultValues() @@ -59,11 +65,23 @@ func TestCatalogDDLOwnsInternalExecutionContext(t *testing.T) { &createAccount{AdminName: "admin", IdentTyp: tree.AccountIdentifiedByPassword, IdentStr: "111"}, ctx, tenant, pu) require.NoError(t, err) + } else if strings.Contains(scenario, "head") { + sourceDDL := "create table mo_catalog.mo_user_defined_function (function_id int, args json)" + if scenario == "current head restore" { + sourceDDL = ddl + } + require.NoError(t, restoreUserDefinedFunctionCatalogWithCurrentSchema(ctx, capture, " {MO_TS = 123}", 42, 42, sourceDDL)) + require.Equal(t, []string{ddl}, capture.internal) } else { - require.NoError(t, restoreUserDefinedFunctionCatalogWithCurrentSchema(ctx, capture, " {MO_TS = 123}", 42, 42)) - require.Equal(t, []string{MoCatalogMoUserDefinedFunctionDDL}, capture.internal) + ddl = MoCatalogMoFunctionRevisionDDL + sourceDDL := "create table mo_catalog.mo_function_revisions (function_id bigint, revision bigint)" + if scenario == "current revision restore" { + sourceDDL = ddl + } + require.NoError(t, restoreFunctionRevisionCatalogWithCurrentSchema(ctx, capture, " {MO_TS = 123}", 42, 42, sourceDDL)) + require.Equal(t, []string{ddl}, capture.internal) } - require.Contains(t, capture.internal, MoCatalogMoUserDefinedFunctionDDL) + require.Contains(t, capture.internal, ddl) require.NotEmpty(t, capture.ordinary) for _, sql := range capture.internal { require.True(t, strings.HasPrefix(strings.ToLower(strings.TrimSpace(sql)), "create "), sql) diff --git a/pkg/frontend/snapshot_catalog_restore.go b/pkg/frontend/snapshot_catalog_restore.go index d8368bca6e449..fe75ff083baaa 100644 --- a/pkg/frontend/snapshot_catalog_restore.go +++ b/pkg/frontend/snapshot_catalog_restore.go @@ -418,7 +418,10 @@ func restoreFunctionRevisionCatalogWithCurrentSchema( if err := bh.Exec(targetCtx, dropTableIfExistsSQL(moCatalog, "mo_function_revisions")); err != nil { return err } - if err := bh.Exec(targetCtx, MoCatalogMoFunctionRevisionDDL); err != nil { + // This schema is owned by the running binary, just like the function head + // table. Its historical VARCHAR widths require trusted catalog DDL admission. + internalDDL := context.WithValue(targetCtx, defines.InternalExecutorKey{}, true) + if err := bh.Exec(internalDDL, MoCatalogMoFunctionRevisionDDL); err != nil { return err } diff --git a/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go similarity index 95% rename from pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go rename to pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go index 43e15b0c75b87..1723c2b50470f 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_14_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go @@ -23,7 +23,7 @@ import ( "time" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_14" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_15" "github.com/matrixorigin/matrixone/pkg/catalog" moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -36,7 +36,7 @@ import ( // Reuse the upgrade package's single-CN fixture. A late tenant must be repaired // on its first real login, even when the cluster has already completed upgrade. -func TestV4014LoginRepairsLegacyRoutineCatalog(t *testing.T) { +func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { embed.RunSingleCNBaseClusterTests(t, func(cluster embed.Cluster) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() @@ -46,9 +46,9 @@ func TestV4014LoginRepairsLegacyRoutineCatalog(t *testing.T) { systemDB, err := sql.Open("mysql", fmt.Sprintf("dump:111@tcp(127.0.0.1:%d)/", port)) require.NoError(t, err) defer systemDB.Close() - for _, sourceVersion := range []string{"4.0.12", "4.0.13"} { + for _, sourceVersion := range []string{"4.0.12", "4.0.13", "4.0.14"} { t.Run(sourceVersion, func(t *testing.T) { - account := "routine_repair_4014_" + strings.ReplaceAll(sourceVersion, ".", "") + account := "routine_repair_4015_" + strings.ReplaceAll(sourceVersion, ".", "") _, err = systemDB.ExecContext(ctx, "create account "+account+" ADMIN_NAME 'root' IDENTIFIED BY '111'") require.NoError(t, err) defer func() { @@ -142,18 +142,18 @@ func TestV4014LoginRepairsLegacyRoutineCatalog(t *testing.T) { require.Equal(t, int64(12), result) } checkResult() - checkCatalog("4.0.14", true) + checkCatalog("4.0.15", true) // Explicit replay reaches the handler; a cached second login would not // prove that its DDL is idempotent against the persisted catalog. for range 2 { var mutations int require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { - return v4_0_14.Handler.HandleTenantUpgrade(ctx, int32(accountID), + return v4_0_15.Handler.HandleTenantUpgrade(ctx, int32(accountID), &routineRepairTxn{TxnExecutor: txn, mutations: &mutations}) }, executor.Options{}.WithDatabase(catalog.MO_CATALOG). WithAccountID(catalog.System_Account).WithWaitCommittedLogApplied())) require.Zero(t, mutations) - checkCatalog("4.0.14", true) + checkCatalog("4.0.15", true) checkResult() } }) From 8bda9e1548d6eed6faf02cfc1d3d42e181c62ca5 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 12 Oct 2026 19:52:16 +0800 Subject: [PATCH 219/241] fix(udf): preserve protocol and integer contracts after rebase --- docs/design/python_udf_current_stage.md | 24 ++++++++------ .../python_udf_current_stage_approval.md | 25 ++++++++++++++- pkg/bootstrap/versions/v4_0_15/upgrade.go | 2 +- .../versions/v4_0_15/upgrade_test.go | 10 +++--- pkg/frontend/python_udf_catalog_test.go | 32 ++++++++++++++++--- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 +-- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 10 +++--- pkg/sql/compile/remoterun.go | 4 +-- .../upgrade/upgrade_v4_0_15_routine_test.go | 2 +- pkg/udf/python/arrow.go | 6 ++++ pkg/udf/python/arrow_test.go | 15 +++++++++ pkg/udf/python_contract.go | 2 +- 15 files changed, 107 insertions(+), 35 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 070244f70a443..3bf115794de54 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r6-2026-10-11` | +| Design revision | `python-udf-current-stage-r7-2026-10-12` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `4022729da24d71b082c22b52aaed3faba2b77ea5` (MORPC 109, including the native COLUMNS repair in catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r6 repair preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 110 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `11914526ba0cd40d471299d8e5e2929909b9e09c` (MORPC 110 for MEDIUMINT; the native COLUMNS repair remains catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r7 repair preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 111 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -51,6 +51,12 @@ code or install packages. The environment digest includes the current runtime environment, including tzdata. An environment mismatch fails closed; definitions must be explicitly recreated for a changed contract. +MEDIUMINT, signed or unsigned, is unsupported by the current Python ABI. Its +24-bit SQL value domain must not be normalized into an ordinary 32-bit integer +descriptor. Python argument and return declarations reject it before artifact, +worker, or catalog publication; physical input validation also rejects it. +Ordinary INT and INT UNSIGNED retain their existing 32-bit contract. + The current mappings encode JSON as `canonical_text` and DATE/DATETIME/TIMESTAMP with `sql_zero_struct`; SQL zero temporal values remain explicit values and are never rewritten as NULL. SCALAR handlers receive `(ctx, scalar...)`; VECTOR @@ -71,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `110` (`latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `111` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 110 and above, +revision that would become authoritative later. At protocol 111 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -94,20 +100,20 @@ Thus a tenant already at upstream final `4.0.14`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 110 before tenant tasks are created, and the repair handler +requires protocol 111 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -110. That value is rollout state in the service runtime, not a computed live +111. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 110. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 111. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -247,7 +253,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-110 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 109 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-111 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 110 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 3b091975dbaeb..81a306643a1aa 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r6-2026-10-11`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r7-2026-10-12`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -111,3 +111,26 @@ head-table restore; ordinary user DDL does not acquire that context. This maintenance stays within the authorized test/development scope. Independent Architecture and SQL/Planner approval remains pending; this addendum records implementation changes and does not grant approval. + +## r7 rebase maintenance addendum (2026-10-12) + +Official main `11914526ba0cd40d471299d8e5e2929909b9e09c` has allocated +MORPC 110 to MEDIUMINT assignment bounds. The Python capability therefore moves +to the next version, 111, with 110 as its immediate predecessor rejection case. +The published 4.0.14 handler remains unchanged; the separate 4.0.15 repair still +replays the same nine idempotent shared-function entries. Catalog publication, +reads, prepared reuse, physical execution, remote sender/receiver admission, +repair scheduling and direct replay, and the status RPC share the new floor. +Tests reject predecessor-only and mixed 111/110 CNs before catalog mutation, +and retain MEDIUMINT's independent version-110 admission. + +The new upstream MEDIUMINT uses a 24-bit logical domain in INT32 storage. The +current Python ABI rejects signed/unsigned MEDIUMINT declarations and inputs +before normalization could widen that domain; ordinary 32-bit INT is unchanged. +Typed descriptor and parsed CREATE FUNCTION cases cover this fail-closed boundary. + +This supersedes r6's candidate protocol allocation and records the new upstream +type boundary. It preserves the existing opt-in, unisolated test/development +scope and catalog repair contract. +Independent Architecture and SQL/Planner approval remains pending. Neither this +mechanical rebase nor its validation grants approval or extends production scope. diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade.go b/pkg/bootstrap/versions/v4_0_15/upgrade.go index ff633c2634a08..1e2fcabf2e27d 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion110, + RequiredProtocolVersion: defines.MORPCVersion111, }, } diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go index d57fd38c7a854..91347f90e3880 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.14", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion110), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion111), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.14")) require.False(t, metadata.CanDirectUpgrade("4.0.13")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:109"}`, - `{"result":"cn-a:110,cn-b:109"}`, + `{"result":"cn-a:110"}`, + `{"result":"cn-a:111,cn-b:110"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 110") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 111") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:110"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:111"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index c3369c7467e67..bb6252ea305eb 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -137,6 +137,28 @@ func TestInitPythonFunctionValidatesArtifactBeforeCatalogReadiness(t *testing.T) tenant := &TenantInfo{User: "root", TenantID: 27, DefaultRoleID: accountAdminRoleID} session := &Session{feSessionImpl: feSessionImpl{service: service, tenant: tenant}} + for _, test := range []struct { + name, argument, result string + }{ + {"signed_argument", "mediumint", "bigint"}, + {"unsigned_argument", "mediumint unsigned", "bigint"}, + {"signed_result", "bigint", "mediumint"}, + {"unsigned_result", "bigint", "mediumint unsigned"}, + } { + t.Run(test.name, func(t *testing.T) { + statement, err := parsers.ParseOne(ctx, dialect.MYSQL, fmt.Sprintf( + "create function app.py_echo(value %s) returns %s language python as 'def py_echo(ctx, value): return value' handler 'py_echo'", + test.argument, test.result), 1) + require.NoError(t, err) + defer statement.Free() + runtime.definition = nil + background.executedSqls = nil + err = InitFunction(session, &ExecCtx{reqCtx: ctx}, tenant, statement.(*tree.CreateFunction)) + require.ErrorContains(t, err, "python udf does not support MEDIUMINT") + require.Nil(t, runtime.definition, "unsupported types must fail before worker validation") + require.Empty(t, background.executedSqls, "unsupported types must fail before catalog access") + }) + } err = InitFunction(session, &ExecCtx{reqCtx: ctx}, tenant, createFunction) require.ErrorContains(t, err, "Python UDF catalog contract is not ready") require.ErrorContains(t, err, missingRevisionCatalog.Error()) @@ -537,7 +559,7 @@ func setSharedRoutineRevisionProtocolForTest(t *testing.T, version int64) { } func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion106) + setSharedRoutineRevisionProtocolForTest(t, sharedRoutineRevisionProtocolVersion-1) create := &backgroundExecTestWithHistory{} create.init() @@ -561,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 110"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 111"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -607,7 +629,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T } func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion106) + setSharedRoutineRevisionProtocolForTest(t, sharedRoutineRevisionProtocolVersion-1) background := &backgroundExecTestWithHistory{} background.init() @@ -620,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion109) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion110) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 110") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 111") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 5c45ed6f2584c..960927c28466f 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion110, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion111, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 49147ddcc672e..6e0e43b797f09 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,8 +37,8 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion110(t *testing.T) { - assert.Equal(t, defines.MORPCVersion110, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +func TestGetPythonUdfStatusRequiresProtocolVersion111(t *testing.T) { + assert.Equal(t, defines.MORPCVersion111, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index b0734fe2f2c47..d5864206d37c7 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion110, + {features.PythonRoutineContract, defines.MORPCVersion111, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index b5ad4547928f0..ae7a5f0d54ac3 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion110) + required = max(required, defines.MORPCVersion111) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 3a17a6ebb70b0..e105403819891 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -551,20 +551,20 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion110, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion111, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion109, defines.MORPCVersion110} { + for _, version := range []int64{defines.MORPCVersion110, defines.MORPCVersion111} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion110 { + if version < defines.MORPCVersion111 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion109) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion110) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion111) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 4d6d04bba4b5d..19a79b3f5360f 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion110) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 110") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion111) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 111") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go index 1723c2b50470f..054bfc5f1a404 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go @@ -127,7 +127,7 @@ func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 110") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 111") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python/arrow.go b/pkg/udf/python/arrow.go index a129311757350..1e02a6292e50a 100644 --- a/pkg/udf/python/arrow.go +++ b/pkg/udf/python/arrow.go @@ -67,6 +67,12 @@ type TypeDescriptor struct { } func NewTypeDescriptor(typ types.Type) (TypeDescriptor, error) { + // MEDIUMINT uses INT32 storage, but Width=24 is a value-domain contract, + // not display metadata. The current Python ABI has no 24-bit integer + // descriptor, so reject it before normalization can widen the domain. + if typ.IsMediumInt() { + return TypeDescriptor{}, udferr.Newf("python udf does not support MEDIUMINT") + } // Planner types use scale=-1 as the sentinel for types whose SQL // definition has no scale (for example INT and BINARY). That sentinel is // an internal planner representation and cannot cross the Python ABI: diff --git a/pkg/udf/python/arrow_test.go b/pkg/udf/python/arrow_test.go index 515206c9564fe..45551bd1a2fba 100644 --- a/pkg/udf/python/arrow_test.go +++ b/pkg/udf/python/arrow_test.go @@ -728,6 +728,21 @@ func TestNewTypeDescriptorNormalizesPlannerOnlySentinels(t *testing.T) { require.Equal(t, int32(0), descriptor.Scale) } +func TestNewTypeDescriptorRejectsMediumInt(t *testing.T) { + for _, oid := range []types.T{types.T_int32, types.T_uint32} { + t.Run(oid.String(), func(t *testing.T) { + _, err := NewTypeDescriptor(types.New(oid, 24, 0)) + require.ErrorContains(t, err, "python udf does not support MEDIUMINT") + + // The ordinary 32-bit domain still admits planner display metadata. + descriptor, err := NewTypeDescriptor(types.New(oid, 32, -1)) + require.NoError(t, err) + require.Equal(t, int32(0), descriptor.Width) + require.Equal(t, int32(0), descriptor.Scale) + }) + } +} + func TestBuildInputRecordCanonicalizesJSONText(t *testing.T) { mp := mpool.MustNewZeroNoFixed() input := vector.NewVec(types.T_json.ToType()) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 310fc7904a7f1..362946a9b18f6 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion110 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion111 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From c778420615734c980743c88a2cb58c5df743faf1 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 12 Oct 2026 22:34:12 +0800 Subject: [PATCH 220/241] docs(udf): record r8 contract after upstream rebase --- docs/design/python_udf_current_stage.md | 6 +++--- docs/design/python_udf_current_stage_approval.md | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 3bf115794de54..1178446a108c9 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r7-2026-10-12` | +| Design revision | `python-udf-current-stage-r8-2026-10-12` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `11914526ba0cd40d471299d8e5e2929909b9e09c` (MORPC 110 for MEDIUMINT; the native COLUMNS repair remains catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r7 repair preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 111 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `b09f2c6fc54eb159f549f69db2636fd5fb6e5125` (MORPC 110 for MEDIUMINT; the native COLUMNS repair remains catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r8 repair preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 111 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 81a306643a1aa..f5a4294b1f09a 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r7-2026-10-12`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r8-2026-10-12`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -134,3 +134,17 @@ type boundary. It preserves the existing opt-in, unisolated test/development scope and catalog repair contract. Independent Architecture and SQL/Planner approval remains pending. Neither this mechanical rebase nor its validation grants approval or extends production scope. + +## r8 rebase maintenance addendum (2026-10-12) + +Official main is now b09f2c6fc54eb159f549f69db2636fd5fb6e5125. Its MORPC +latest remains 110, so Python capability 111 and immediate predecessor 110 +remain unchanged. The published catalog 4.0.14 handler and separate 4.0.15 +Python revision repair retain the r7 contract, including signed/unsigned +MEDIUMINT rejection before descriptor normalization. This rebase incorporates +upstream decimal-tail validation, the lock-timeout compatibility alias, and +batched catalog ID lookup for table statistics without adding Python ABI or +rollout scope. The immutable r7 maintenance record above remains historical; +this addendum records the new implementation baseline only. Independent +Architecture and SQL/Planner approval remains pending, and validation does not +supply that approval. From fb6ed5aef8b056c090f8aeeccb4dd71890921d49 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 13 Oct 2026 00:34:48 +0800 Subject: [PATCH 221/241] fix(udf): reconcile Python protocol with index search scans --- docs/design/python_udf_current_stage.md | 14 ++--- .../python_udf_current_stage_approval.md | 20 +++++- pkg/bootstrap/versions/v4_0_15/upgrade.go | 2 +- .../versions/v4_0_15/upgrade_test.go | 10 +-- pkg/frontend/python_udf_catalog_test.go | 6 +- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 +- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 61 +++++++++++++++++-- pkg/sql/compile/remoterun.go | 4 +- .../upgrade/upgrade_v4_0_15_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 13 files changed, 100 insertions(+), 31 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 1178446a108c9..2de60a299beed 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r8-2026-10-12` | +| Design revision | `python-udf-current-stage-r9-2026-10-13` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `b09f2c6fc54eb159f549f69db2636fd5fb6e5125` (MORPC 110 for MEDIUMINT; the native COLUMNS repair remains catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r8 repair preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 111 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `0a4db0e6a6517e489a333ad9073dfcdc5d26aff4` (MORPC 111 for IndexSearchScan; the native COLUMNS repair remains catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r9 repair preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 112 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `111` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `112` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 111 and above, +revision that would become authoritative later. At protocol 112 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -100,7 +100,7 @@ Thus a tenant already at upstream final `4.0.14`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 111 before tenant tasks are created, and the repair handler +requires protocol 112 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. @@ -253,7 +253,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-111 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 110 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-112 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 111 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index f5a4294b1f09a..50d9dcd979c4f 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r8-2026-10-12`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r9-2026-10-13`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -148,3 +148,21 @@ rollout scope. The immutable r7 maintenance record above remains historical; this addendum records the new implementation baseline only. Independent Architecture and SQL/Planner approval remains pending, and validation does not supply that approval. + +## r9 rebase maintenance addendum (2026-10-13) + +Official main `0a4db0e6a6517e489a333ad9073dfcdc5d26aff4` allocates +MORPC 111 to IndexSearchScan. Python's single new capability moves to 112, +with 111 as its immediate predecessor rejection case. The main IndexSearchScan +plan and pipeline contract remains at 111; MEDIUMINT remains at 110. The merged +plan protobuf retains both IndexSearchScan and typed routine metadata, including +routine dependency envelopes and deep-copy ownership. Python catalog reads, +publication, Prepare reuse, physical/remote execution, repair scheduling/direct +replay, and status RPC admission all use the new Python floor. Tests reject +predecessor-only and mixed 112/111 CNs before catalog mutation. + +The published catalog 4.0.14 handler remains unchanged, and the separate 4.0.15 +repair retains the nine idempotent shared-function entries. The current Python +ABI and opt-in, unisolated test/development scope are unchanged. Historical r8 +records remain immutable. Independent Architecture and SQL/Planner approval of +this current revision remains pending; rebase and validation do not supply it. diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade.go b/pkg/bootstrap/versions/v4_0_15/upgrade.go index 1e2fcabf2e27d..a0143f60a4cd7 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion111, + RequiredProtocolVersion: defines.MORPCVersion112, }, } diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go index 91347f90e3880..437ee44479903 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.14", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion111), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion112), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.14")) require.False(t, metadata.CanDirectUpgrade("4.0.13")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:110"}`, - `{"result":"cn-a:111,cn-b:110"}`, + `{"result":"cn-a:111"}`, + `{"result":"cn-a:112,cn-b:111"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 111") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 112") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:111"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:112"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index bb6252ea305eb..ad58ecb2f59a7 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 111"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 112"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion110) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion111) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 111") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 112") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 960927c28466f..48af6eb8302c0 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion111, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion112, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 6e0e43b797f09..1f81666a2073e 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,8 +37,8 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion111(t *testing.T) { - assert.Equal(t, defines.MORPCVersion111, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +func TestGetPythonUdfStatusRequiresProtocolVersion112(t *testing.T) { + assert.Equal(t, defines.MORPCVersion112, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index d5864206d37c7..c03fc0b579052 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion111, + {features.PythonRoutineContract, defines.MORPCVersion112, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index ae7a5f0d54ac3..a742ee54e2148 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion111) + required = max(required, defines.MORPCVersion112) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index e105403819891..e31ad8cb0a150 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -20,6 +20,7 @@ import ( "testing" "time" + "github.com/gogo/protobuf/proto" moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/defines" @@ -551,20 +552,70 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion111, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion112, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion110, defines.MORPCVersion111} { + for _, version := range []int64{defines.MORPCVersion111, defines.MORPCVersion112} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion111 { + if version < defines.MORPCVersion112 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion110) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion111) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion112) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } + +func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { + for _, field := range []string{"query_payload", "algo_expr"} { + t.Run(field, func(t *testing.T) { + c, client := expressionProtocolTestCompile(t) + call := &planpb.RoutineCall{FunctionRef: &planpb.FunctionRef{FunctionId: 7, Revision: 3}, Language: "python"} + expr := &planpb.Expr{Expr: &planpb.Expr_F{F: &planpb.Function{RoutineCall: call}}} + scan := &planpb.IndexSearchScan{AlgoOptions: []byte(`{}`)} + if field == "query_payload" { + scan.QueryPayload = expr + } else { + scan.AlgoExprs = []*planpb.Expr{expr} + scan.AlgoExprNames = []string{"first_round_limit"} + } + cloned := plan2.DeepCopyNode(&planpb.Node{NodeType: planpb.Node_INDEX_SEARCH_SCAN, IndexSearchScan: scan}) + require.True(t, proto.Equal(scan, cloned.IndexSearchScan)) + var clonedExpr *planpb.Expr + if field == "query_payload" { + clonedExpr = cloned.IndexSearchScan.QueryPayload + } else { + clonedExpr = cloned.IndexSearchScan.AlgoExprs[0] + } + require.NotSame(t, call, clonedExpr.GetF().RoutineCall) + require.NotSame(t, call.FunctionRef, clonedExpr.GetF().RoutineCall.FunctionRef) + p := &pipeline.Pipeline{ + Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, + DataSource: &pipeline.Source{Node: cloned}, + } + data, err := p.Marshal() + require.NoError(t, err) + var received pipeline.Pipeline + require.NoError(t, received.Unmarshal(data)) + require.True(t, proto.Equal(scan, received.DataSource.Node.IndexSearchScan)) + features, err := planpb.RequiredRemoteExpressionFeatures(&received) + require.NoError(t, err) + require.True(t, features.PythonRoutineContract) + require.Equal(t, defines.MORPCVersion112, remoteExpressionProtocolVersion(features)) + rt := moruntime.ServiceRuntime(c.proc.GetService()) + client.version = defines.MORPCVersion111 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion111) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion112 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion112) + require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) + require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) + require.Equal(t, client.calls, client.releases) + }) + } +} diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 19a79b3f5360f..2d08a0160df3a 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion111) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 111") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion112) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 112") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go index 054bfc5f1a404..35e78baf62a19 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go @@ -127,7 +127,7 @@ func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 111") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 112") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 362946a9b18f6..433ffcff29975 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion111 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion112 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From 8b0252374015ef08caa7b2a461e84e1c1220f4e7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 13 Oct 2026 03:48:01 +0800 Subject: [PATCH 222/241] docs(udf): align active protocol references with MORPC 112 --- docs/design/python_udf_current_stage.md | 8 ++++---- docs/design/python_udf_current_stage_approval.md | 13 ++++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 2de60a299beed..495ac811caae0 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r9-2026-10-13` | +| Design revision | `python-udf-current-stage-r10-2026-10-13` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | | Upstream repair baseline | `0a4db0e6a6517e489a333ad9073dfcdc5d26aff4` (MORPC 111 for IndexSearchScan; the native COLUMNS repair remains catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r9 repair preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 112 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r10 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 112 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -106,14 +106,14 @@ rechecks every CN before catalog access on login compensation or direct replay; Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -111. That value is rollout state in the service runtime, not a computed live +112. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 111. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 112. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 50d9dcd979c4f..d46c3d9045373 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r9-2026-10-13`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r10-2026-10-13`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -166,3 +166,14 @@ repair retains the nine idempotent shared-function entries. The current Python ABI and opt-in, unisolated test/development scope are unchanged. Historical r8 records remain immutable. Independent Architecture and SQL/Planner approval of this current revision remains pending; rebase and validation do not supply it. + +## r10 documentation errata (2026-10-13) + +This revision corrects two stale r9 prose references: shared revision +publication/Python reads and `GetPythonUdfStatus` both require MORPC 112, +as implemented at `5daca2160a95495ef343a4c13ebdc8337309dab5`. Protocol 111 +remains the official IndexSearchScan capability and Python's immediate +predecessor rejection case. The implementation, ABI, catalog repair, and +test/development scope are unchanged. The r9 maintenance record above is +retained. Independent Architecture and SQL/Planner approval of the current +revision remains pending; this documentation correction does not grant it. From 49676c261a62073a191d96872f91efe20434aa6f Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 13 Oct 2026 05:28:16 +0800 Subject: [PATCH 223/241] test: isolate embedded admission release channels after main rebase --- docs/design/python_udf_current_stage.md | 6 ++--- .../python_udf_current_stage_approval.md | 18 ++++++++++++++- optools/ut_embedded_schedule_test.go | 23 ++++++++++++++----- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 495ac811caae0..2e32bbe00c53d 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r10-2026-10-13` | +| Design revision | `python-udf-current-stage-r11-2026-10-13` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `0a4db0e6a6517e489a333ad9073dfcdc5d26aff4` (MORPC 111 for IndexSearchScan; the native COLUMNS repair remains catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r10 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 112 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `fa7cc1d9b38e3324572a4efc5617033522de0cbf` (MORPC 111 for IndexSearchScan; the native COLUMNS repair remains catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r11 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 112 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index d46c3d9045373..bd4bb3ca53d0f 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r10-2026-10-13`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r11-2026-10-13`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -177,3 +177,19 @@ predecessor rejection case. The implementation, ABI, catalog repair, and test/development scope are unchanged. The r9 maintenance record above is retained. Independent Architecture and SQL/Planner approval of the current revision remains pending; this documentation correction does not grant it. + +## r11 rebase maintenance addendum (2026-10-13) + +Official main is now `fa7cc1d9b38e3324572a4efc5617033522de0cbf`. +Its MORPC latest remains 111, so Python capability 112 and immediate +predecessor 111 remain unchanged. The published catalog 4.0.14 handler and +separate 4.0.15 Python revision repair retain the r10 contract. The rebase +incorporates upstream prepared COALESCE typing, integer common-type precision, +OR normalization, Unicode collation metadata, performance-schema formatters, +buffered TLS handshakes, and bounded gossip fixtures without changing Python +ABI or rollout scope. The embedded admission test now releases concurrent +light packages through distinct FIFO channels and checks each package's token; +its admission, exclusion, failure, and cleanup assertions remain in force. + +Historical r10 records remain immutable. Independent Architecture and +SQL/Planner approval remains pending; rebase and validation do not supply it. diff --git a/optools/ut_embedded_schedule_test.go b/optools/ut_embedded_schedule_test.go index bdce22ba2169c..77eb8d5063779 100644 --- a/optools/ut_embedded_schedule_test.go +++ b/optools/ut_embedded_schedule_test.go @@ -333,9 +333,11 @@ func TestEmbeddedPrebuiltAdmission(t *testing.T) { t.Run(tc.name, func(t *testing.T) { script := embeddedSetup + ` scope=$'github.com/matrixorigin/matrixone/pkg/bootstrap\ngithub.com/matrixorigin/matrixone/pkg/embed\ngithub.com/matrixorigin/matrixone/pkg/tests/arrowload\ngithub.com/matrixorigin/matrixone/pkg/tests/sqlintegration\ngithub.com/matrixorigin/matrixone/pkg/tests/dml' -mkfifo "$CASE_DIR/release-heavy" "$CASE_DIR/release-light" -exec 10<>"$CASE_DIR/release-heavy" 11<>"$CASE_DIR/release-light" -release_children() { printf 'release\nrelease\nrelease\n' >&10; printf 'release\nrelease\n' >&11; } +# Concurrent Bash readers do not consume FIFO lines atomically. Give each +# light package its own release channel; heavy packages execute exclusively. +mkfifo "$CASE_DIR/release-heavy" "$CASE_DIR/release-arrowload" "$CASE_DIR/release-dml" +exec 10<>"$CASE_DIR/release-heavy" 11<>"$CASE_DIR/release-arrowload" 12<>"$CASE_DIR/release-dml" +release_children() { printf 'release\nrelease\nrelease\n' >&10; printf 'arrowload\n' >&11; printf 'dml\n' >&12; } driver_pid="" cleanup_driver() { release_children @@ -359,7 +361,8 @@ artifact_dir=$CLUSTER_PREBUILD_DIR [[ "$first $second" == 'arrowload dml' || "$first $second" == 'dml arrowload' ]] || exit 105 [[ "$first_pid" != "$second_pid" ]] || exit 106 kill -0 "$first_pid" && kill -0 "$second_pid" || exit 107 - printf 'release\nrelease\n' >&11 + printf 'arrowload\n' >&11 + printf 'dml\n' >&12 read -r -t 5 leaf pid <&8 || exit 108 [[ "$leaf" == sqlintegration ]] || exit 109 printf 'release\n' >&10 @@ -367,7 +370,11 @@ artifact_dir=$CLUSTER_PREBUILD_DIR for next in arrowload sqlintegration dml; do read -r -t 5 leaf pid <&8 || exit 110 [[ "$leaf" == "$next" ]] || exit 111 - if [[ "$leaf" == sqlintegration ]]; then printf 'release\n' >&10; else printf 'release\n' >&11; fi + case "$leaf" in + arrowload) printf 'arrowload\n' >&11 ;; + dml) printf 'dml\n' >&12 ;; + sqlintegration) printf 'release\n' >&10 ;; + esac done fi ) & @@ -423,7 +430,11 @@ if [[ "$1" == tool && "$2" == test2json ]]; then [[ " $* " == *' -test.run=.* '* || "${!#}" == '-test.run=.*' ]] || exit 123 mkdir "$CASE_DIR/executed-$leaf" || exit 124 printf '%s %s\n' "$leaf" "$$" >&8 - case "$leaf" in arrowload|dml) read -r _ <&11 ;; *) read -r _ <&10 ;; esac + case "$leaf" in + arrowload) read -r released <&11; [[ "$released" == "$leaf" ]] || exit 126 ;; + dml) read -r released <&12; [[ "$released" == "$leaf" ]] || exit 126 ;; + *) read -r _ <&10 ;; + esac if [[ "$MODE" == heavy-failure && "$leaf" == embed ]]; then printf '{"Action":"fail","Package":"%s"}\n' "$package" exit 7 From 48e3b70bb4023a5a068c51a3fc5131b2a9fee74e Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 14 Oct 2026 03:17:20 +0800 Subject: [PATCH 224/241] fix(udf): advance Python protocol admission after calendar contracts --- docs/design/python_udf_current_stage.md | 14 ++++++------- .../python_udf_current_stage_approval.md | 18 +++++++++++++++++ pkg/bootstrap/versions/v4_0_15/upgrade.go | 2 +- .../versions/v4_0_15/upgrade_test.go | 10 +++++----- pkg/frontend/python_udf_catalog_test.go | 6 +++--- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 ++-- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 20 +++++++++---------- pkg/sql/compile/remoterun.go | 4 ++-- .../upgrade/upgrade_v4_0_15_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 13 files changed, 53 insertions(+), 35 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 2e32bbe00c53d..92c6291babc31 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r11-2026-10-13` | +| Design revision | `python-udf-current-stage-r12-2026-10-14` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `fa7cc1d9b38e3324572a4efc5617033522de0cbf` (MORPC 111 for IndexSearchScan; the native COLUMNS repair remains catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r11 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 112 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `1b66ff135c64ef1c642a297105bf599cd3173dee` (MORPC 112 for signed WEEK/DAYOFYEAR results; the native COLUMNS repair remains catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r12 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 113 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -82,7 +82,7 @@ binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 112 and above, +revision that would become authoritative later. At protocol 113 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -100,7 +100,7 @@ Thus a tenant already at upstream final `4.0.14`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 112 before tenant tasks are created, and the repair handler +requires protocol 113 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. @@ -113,7 +113,7 @@ Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 112. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 113. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -253,7 +253,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-112 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 111 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-113 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 112 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index bd4bb3ca53d0f..4a75fca67a88a 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -193,3 +193,21 @@ its admission, exclusion, failure, and cleanup assertions remain in force. Historical r10 records remain immutable. Independent Architecture and SQL/Planner approval remains pending; rebase and validation do not supply it. + +## r12 protocol allocation addendum (2026-10-14) + +Official main `1b66ff135c64ef1c642a297105bf599cd3173dee` assigns +MORPC 112 to signed INT WEEK/DAYOFYEAR result vectors. The current +`python-udf-current-stage-r12-2026-10-14` contract moves Python's single new +capability to 113, with 112 as the immediate predecessor rejection case. +The signed date result capability remains at 112 and IndexSearchScan remains +at 111. Shared catalog publication and reads, prepared reuse, physical +execution, remote placement/send/receive admission, the 4.0.15 repair, and +`GetPythonUdfStatus` all use the Python 113 floor. Predecessor-only and mixed +113/112 CNs are rejected before catalog mutation; legacy SQL fallback is +retained. Catalog versions, Python ABI, and the test/development scope are +unchanged. + +Historical r11 and earlier artifacts above remain immutable. Independent +Architecture and SQL/Planner approval of r12 remains pending; mechanical +rebase and validation do not supply an approval decision. diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade.go b/pkg/bootstrap/versions/v4_0_15/upgrade.go index a0143f60a4cd7..04e7036c57762 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion112, + RequiredProtocolVersion: defines.MORPCVersion113, }, } diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go index 437ee44479903..44301ead38677 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.14", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion112), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion113), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.14")) require.False(t, metadata.CanDirectUpgrade("4.0.13")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:111"}`, - `{"result":"cn-a:112,cn-b:111"}`, + `{"result":"cn-a:112"}`, + `{"result":"cn-a:113,cn-b:112"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 112") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 113") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:112"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:113"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index ad58ecb2f59a7..722612d70d1ab 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 112"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 113"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion111) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion112) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 112") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 113") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 48af6eb8302c0..4612ec558a7c4 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion112, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion113, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 1f81666a2073e..185459cb1a988 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,8 +37,8 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion112(t *testing.T) { - assert.Equal(t, defines.MORPCVersion112, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +func TestGetPythonUdfStatusRequiresProtocolVersion113(t *testing.T) { + assert.Equal(t, defines.MORPCVersion113, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index c03fc0b579052..1cd95e781c77a 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion112, + {features.PythonRoutineContract, defines.MORPCVersion113, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index a742ee54e2148..a2487f8973e2e 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion112) + required = max(required, defines.MORPCVersion113) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index e31ad8cb0a150..8fed61b9d6eba 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -552,20 +552,20 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion112, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion113, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion111, defines.MORPCVersion112} { + for _, version := range []int64{defines.MORPCVersion112, defines.MORPCVersion113} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion112 { + if version < defines.MORPCVersion113 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion111) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion112) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion113) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } @@ -605,14 +605,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion112, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion113, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion111 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion111) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion112 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion112) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion113 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion113) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 2d08a0160df3a..f5eda2661c973 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion112) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 112") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion113) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 113") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go index 35e78baf62a19..d698e6638fe35 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go @@ -127,7 +127,7 @@ func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 112") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 113") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 433ffcff29975..7fec67f820336 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion112 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion113 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From 5bb31ea41aa965d36aa5d5b52078bfaa7287a65b Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 15 Oct 2026 07:52:51 +0800 Subject: [PATCH 225/241] fix(udf): allocate MORPC 114 after main rebase --- docs/design/python_udf_current_stage.md | 18 +++++++-------- .../python_udf_current_stage_approval.md | 22 ++++++++++++++++++- pkg/bootstrap/versions/v4_0_15/upgrade.go | 2 +- .../versions/v4_0_15/upgrade_test.go | 10 ++++----- pkg/frontend/python_udf_catalog_test.go | 6 ++--- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 ++-- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 20 ++++++++--------- pkg/sql/compile/remoterun.go | 4 ++-- .../upgrade/upgrade_v4_0_15_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 13 files changed, 58 insertions(+), 38 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 92c6291babc31..43f73b3bdb28a 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r12-2026-10-14` | +| Design revision | `python-udf-current-stage-r13-2026-10-15` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `1b66ff135c64ef1c642a297105bf599cd3173dee` (MORPC 112 for signed WEEK/DAYOFYEAR results; the native COLUMNS repair remains catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r12 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 113 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `8c8f829f9d3e9576d3b7371333e0eb1147a008e4` (MORPC 113 for DECIMAL variance/stddev DOUBLE results; the native COLUMNS repair remains catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r13 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 114 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `112` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `114` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 113 and above, +revision that would become authoritative later. At protocol 114 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -100,20 +100,20 @@ Thus a tenant already at upstream final `4.0.14`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 113 before tenant tasks are created, and the repair handler +requires protocol 114 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -112. That value is rollout state in the service runtime, not a computed live +114. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 113. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 114. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -253,7 +253,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-113 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 112 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-114 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 113 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 4a75fca67a88a..8849cffe65876 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r11-2026-10-13`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r13-2026-10-15`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -211,3 +211,23 @@ unchanged. Historical r11 and earlier artifacts above remain immutable. Independent Architecture and SQL/Planner approval of r12 remains pending; mechanical rebase and validation do not supply an approval decision. + +## r13 protocol allocation addendum (2026-10-15) + +Official main `8c8f829f9d3e9576d3b7371333e0eb1147a008e4` assigns +MORPC 113 to DECIMAL variance/stddev DOUBLE result contracts. The governing +`python-udf-current-stage-r13-2026-10-15` revision moves Python's single new +capability to 114, with 113 as the immediate predecessor rejection case. +The upstream statistical result contract remains at 113; signed date results +remain at 112 and IndexSearchScan remains at 111. + +Shared revision publication and reads, cached/prepared/evaluator checks, +actual remote-destination admission, receiver validation, catalog repair +metadata and login compensation, and `GetPythonUdfStatus` all require Python +capability 114. Predecessor-only and mixed 114/113 CNs are rejected before +catalog mutation. Ordinary SQL UDFs retain their pre-floor legacy fallback. +The nine idempotent shared-function entries and catalog repair 4.0.15 are +unchanged; this revision adds no execution, production or security scope. + +Independent Architecture and SQL/Planner approval of r13 remains pending. +Mechanical rebase, protocol allocation and validation do not supply it. diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade.go b/pkg/bootstrap/versions/v4_0_15/upgrade.go index 04e7036c57762..462a9b8b68106 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion113, + RequiredProtocolVersion: defines.MORPCVersion114, }, } diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go index 44301ead38677..ce2ab0f92beec 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.14", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion113), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion114), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.14")) require.False(t, metadata.CanDirectUpgrade("4.0.13")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:112"}`, - `{"result":"cn-a:113,cn-b:112"}`, + `{"result":"cn-a:113"}`, + `{"result":"cn-a:114,cn-b:113"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 113") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 114") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:113"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:114"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 722612d70d1ab..ec6daefb45009 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 113"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 114"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion112) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion113) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 113") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 114") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 4612ec558a7c4..1926d12662f6a 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion113, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion114, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 185459cb1a988..ecb484b79f54d 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,8 +37,8 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion113(t *testing.T) { - assert.Equal(t, defines.MORPCVersion113, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +func TestGetPythonUdfStatusRequiresProtocolVersion114(t *testing.T) { + assert.Equal(t, defines.MORPCVersion114, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 1cd95e781c77a..9092ef743c822 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion113, + {features.PythonRoutineContract, defines.MORPCVersion114, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index a2487f8973e2e..de094dd52f936 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion113) + required = max(required, defines.MORPCVersion114) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 8fed61b9d6eba..7741161766c86 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -552,20 +552,20 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion113, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion114, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion112, defines.MORPCVersion113} { + for _, version := range []int64{defines.MORPCVersion113, defines.MORPCVersion114} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion113 { + if version < defines.MORPCVersion114 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion112) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion113) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion114) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } @@ -605,14 +605,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion113, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion114, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion112 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion112) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion113 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion113) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion114 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion114) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index f5eda2661c973..1ca48098f917c 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion113) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 113") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion114) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 114") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go index d698e6638fe35..a1dbefebc12b7 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go @@ -127,7 +127,7 @@ func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 113") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 114") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 7fec67f820336..7f8754e88efaf 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion113 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion114 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From f27b171c5ad83b0b02ae4f2cdc5fcae12f391adf Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Thu, 15 Oct 2026 23:00:30 +0800 Subject: [PATCH 226/241] fix(udf): allocate MORPC 115 and refresh planner fixtures --- docs/design/python_udf_current_stage.md | 18 +++--- .../python_udf_current_stage_approval.md | 22 +++++++- pkg/bootstrap/versions/v4_0_15/upgrade.go | 2 +- .../versions/v4_0_15/upgrade_test.go | 10 ++-- pkg/frontend/python_udf_catalog_test.go | 6 +- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 +- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 20 +++---- pkg/sql/compile/remoterun.go | 4 +- .../plan/apply_indices_fulltext_order_test.go | 56 +++++++++++++++++-- .../upgrade/upgrade_v4_0_15_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 14 files changed, 108 insertions(+), 44 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 43f73b3bdb28a..77aa97559f668 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r13-2026-10-15` | +| Design revision | `python-udf-current-stage-r14-2026-10-15` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `8c8f829f9d3e9576d3b7371333e0eb1147a008e4` (MORPC 113 for DECIMAL variance/stddev DOUBLE results; the native COLUMNS repair remains catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r13 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 114 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `493d8b8181b7d74bed91e360874a3dd35223f276` (MORPC 114 for native Unicode UNIQUE key format and duplicate admission; the native COLUMNS repair remains catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r14 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 115 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `114` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `115` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 114 and above, +revision that would become authoritative later. At protocol 115 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -100,20 +100,20 @@ Thus a tenant already at upstream final `4.0.14`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 114 before tenant tasks are created, and the repair handler +requires protocol 115 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -114. That value is rollout state in the service runtime, not a computed live +115. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 114. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 115. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -253,7 +253,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-114 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 113 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-115 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 114 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 8849cffe65876..43699a6bad652 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r13-2026-10-15`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r14-2026-10-15`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -231,3 +231,23 @@ unchanged; this revision adds no execution, production or security scope. Independent Architecture and SQL/Planner approval of r13 remains pending. Mechanical rebase, protocol allocation and validation do not supply it. + +## r14 protocol allocation addendum (2026-10-15) + +Official main `493d8b8181b7d74bed91e360874a3dd35223f276` assigns +MORPC 114 to native Unicode UNIQUE key format and duplicate-admission semantics. +The governing `python-udf-current-stage-r14-2026-10-15` revision moves Python's +single new capability to 115, with 114 as the immediate predecessor rejection +case. The upstream Unicode contract remains at 114, DECIMAL statistical results +at 113, signed date results at 112 and IndexSearchScan at 111. + +Shared revision publication and reads, cached/prepared/evaluator checks, +actual remote-destination admission, receiver validation, catalog repair +metadata and login compensation, and `GetPythonUdfStatus` all require Python +capability 115. Predecessor-only and mixed 115/114 CNs are rejected before +catalog mutation. Ordinary SQL UDFs retain their pre-floor legacy fallback. +The nine idempotent shared-function entries and catalog repair 4.0.15 are +unchanged; this revision adds no execution, production or security scope. + +Independent Architecture and SQL/Planner approval of r14 remains pending. +Mechanical rebase, protocol allocation and validation do not supply it. diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade.go b/pkg/bootstrap/versions/v4_0_15/upgrade.go index 462a9b8b68106..fd9bfb49400e5 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion114, + RequiredProtocolVersion: defines.MORPCVersion115, }, } diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go index ce2ab0f92beec..2ac25c3a7757d 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.14", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion114), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion115), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.14")) require.False(t, metadata.CanDirectUpgrade("4.0.13")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:113"}`, - `{"result":"cn-a:114,cn-b:113"}`, + `{"result":"cn-a:114"}`, + `{"result":"cn-a:115,cn-b:114"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 114") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 115") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:114"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:115"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index ec6daefb45009..9948f3546a385 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 114"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 115"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion113) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion114) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 114") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 115") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 1926d12662f6a..7f4c775a5683a 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion114, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion115, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index ecb484b79f54d..06a5417273cf2 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,8 +37,8 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion114(t *testing.T) { - assert.Equal(t, defines.MORPCVersion114, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +func TestGetPythonUdfStatusRequiresProtocolVersion115(t *testing.T) { + assert.Equal(t, defines.MORPCVersion115, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 9092ef743c822..6880be550a066 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion114, + {features.PythonRoutineContract, defines.MORPCVersion115, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index de094dd52f936..c985058157b36 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion114) + required = max(required, defines.MORPCVersion115) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 7741161766c86..277d4d4f02a00 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -552,20 +552,20 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion114, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion115, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion113, defines.MORPCVersion114} { + for _, version := range []int64{defines.MORPCVersion114, defines.MORPCVersion115} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion114 { + if version < defines.MORPCVersion115 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion113) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion114) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion115) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } @@ -605,14 +605,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion114, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion115, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion113 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion113) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion114 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion114) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion115 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion115) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 1ca48098f917c..41040a99ca245 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion114) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 114") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion115) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 115") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/sql/plan/apply_indices_fulltext_order_test.go b/pkg/sql/plan/apply_indices_fulltext_order_test.go index 974677a644ae7..71a80c6eaed5a 100644 --- a/pkg/sql/plan/apply_indices_fulltext_order_test.go +++ b/pkg/sql/plan/apply_indices_fulltext_order_test.go @@ -16,6 +16,7 @@ package plan import ( "context" + "encoding/json" "testing" "github.com/matrixorigin/matrixone/pkg/container/types" @@ -23,6 +24,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql" "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + "github.com/matrixorigin/matrixone/pkg/udf" "github.com/stretchr/testify/require" ) @@ -161,12 +163,49 @@ func (c *fullTextOrderPythonUdfContext) ResolveUdf(name string, args []*planpb.E if name != "py_tick" { return c.fullTextJoinMockCompilerContext.ResolveUdf(name, args) } - return &function.Udf{ - Language: string(tree.PYTHON), - RetType: "bigint", - Args: []*function.Arg{{Name: "x", Type: "bigint"}}, - ArgsType: []types.Type{types.T_int64.ToType()}, - }, nil + // Bind a current catalog revision so this oracle reaches the fulltext + // ordering decision through the real typed Python routine path. + descriptor, err := function.NewPythonTypeDescriptor(types.T_int64.ToType()) + if err != nil { + return nil, err + } + environment, err := udf.PythonEnvironmentDigest() + if err != nil { + return nil, err + } + const source = "def py_tick(ctx, x): return x" + body, err := json.Marshal(function.PythonRoutineBody{ + DefinitionSchemaVersion: udf.PythonDefinitionSchemaVersion, + Handler: name, + Source: source, + Mode: "SCALAR", + NullPolicy: udf.NullCallHandler, + ABIContract: udf.PythonABIContract, + AdapterVersion: udf.PythonAdapterVersion, + SDKVersion: udf.PythonSDKVersion, + ArtifactDigest: udf.PythonInlineArtifactDigest(name, source), + EnvironmentDigest: environment, + ArgTypes: []function.PythonTypeDescriptor{descriptor}, + ReturnType: &descriptor, + }) + if err != nil { + return nil, err + } + routine := &function.Udf{ + FunctionID: 1, + DatabaseID: 1, + Revision: 1, + NamespaceVersion: 1, + Language: string(tree.PYTHON), + Body: string(body), + RetType: "bigint", + Args: []*function.Arg{{Name: "x", Type: "bigint"}}, + ArgsType: []types.Type{types.T_int64.ToType()}, + } + if err := routine.LoadPythonTypeContract(); err != nil { + return nil, err + } + return routine, routine.ValidatePythonCatalogSignature() } // Parse/bind/optimize the public SQL shape as a separate reachability oracle. @@ -211,6 +250,11 @@ func TestFullTextImplicitOrderSQLReachability(t *testing.T) { require.NoError(t, err) query := p.GetQuery() require.NotNil(t, query) + if tc.name == "python udf alias" || tc.name == "nested python udf alias" { + require.Len(t, query.RoutineDependencies, 1) + require.Equal(t, int32(udf.PythonPlanContractVersion), query.RoutineDependencies[0].ContractVersion) + require.NotEmpty(t, query.RoutineDependencies[0].DefinitionFingerprint) + } require.Len(t, query.Steps, 1) planned := &QueryBuilder{qry: query} require.Equal(t, tc.wantSorts, reachableFullTextOrderSorts(planned, query.Steps[0])) diff --git a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go index a1dbefebc12b7..ae0f7745fffa2 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go @@ -127,7 +127,7 @@ func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 114") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 115") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 7f8754e88efaf..632b9e2315bf3 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion114 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion115 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From fd0c691ea27b8d62b8f5f62ad6489e8cfa0f0cc7 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 16 Oct 2026 03:45:38 +0800 Subject: [PATCH 227/241] fix(udf): allocate MORPC 116 after upstream rebase --- docs/design/python_udf_current_stage.md | 18 +++++++------- .../python_udf_current_stage_approval.md | 23 +++++++++++++++++- pkg/bootstrap/versions/v4_0_15/upgrade.go | 2 +- .../versions/v4_0_15/upgrade_test.go | 10 ++++---- pkg/frontend/python_udf_catalog_test.go | 6 ++--- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 ++-- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 24 ++++++++++--------- pkg/sql/compile/remoterun.go | 4 ++-- .../upgrade/upgrade_v4_0_15_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 13 files changed, 62 insertions(+), 39 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 77aa97559f668..ae6211f106043 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r14-2026-10-15` | +| Design revision | `python-udf-current-stage-r15-2026-10-16` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `493d8b8181b7d74bed91e360874a3dd35223f276` (MORPC 114 for native Unicode UNIQUE key format and duplicate admission; the native COLUMNS repair remains catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r14 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 115 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `99f52528308289e08ab6f07f87b0a54719b877a3` (MORPC 115 for type-sensitive calendar DAY and truncating SECOND intervals; the native COLUMNS repair remains catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r15 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 116 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `115` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `116` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 115 and above, +revision that would become authoritative later. At protocol 116 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -100,20 +100,20 @@ Thus a tenant already at upstream final `4.0.14`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 115 before tenant tasks are created, and the repair handler +requires protocol 116 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -115. That value is rollout state in the service runtime, not a computed live +116. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 115. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 116. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -253,7 +253,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-115 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 114 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-116 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 115 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 43699a6bad652..0eb1457454717 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r14-2026-10-15`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r15-2026-10-16`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -251,3 +251,24 @@ unchanged; this revision adds no execution, production or security scope. Independent Architecture and SQL/Planner approval of r14 remains pending. Mechanical rebase, protocol allocation and validation do not supply it. + +## r15 protocol allocation addendum (2026-10-16) + +Official main `99f52528308289e08ab6f07f87b0a54719b877a3` assigns MORPC 115 +to type-sensitive calendar DAY and truncating SECOND intervals. The governing +`python-udf-current-stage-r15-2026-10-16` revision moves Python's single new +capability to 116, with 115 as the immediate predecessor rejection case. +Calendar normalization remains at 115 and native Unicode UNIQUE semantics at 114. +Both remote-expression feature detectors and their distinct admission floors +are retained after rebase. + +Shared revision publication and reads, cached/prepared/evaluator checks, +actual remote-destination admission, receiver validation, catalog repair +metadata and login compensation, and `GetPythonUdfStatus` all require Python +capability 116. Predecessor-only and mixed 116/115 CNs are rejected before +catalog mutation. Ordinary SQL UDFs retain their pre-floor legacy fallback. +The nine idempotent shared-function entries and catalog repair 4.0.15 are +unchanged; this revision adds no execution, production or security scope. + +Independent Architecture and SQL/Planner approval of r15 remains pending. +Mechanical rebase, protocol allocation and validation do not supply it. diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade.go b/pkg/bootstrap/versions/v4_0_15/upgrade.go index fd9bfb49400e5..dbd3076e215ea 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion115, + RequiredProtocolVersion: defines.MORPCVersion116, }, } diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go index 2ac25c3a7757d..5df2a88b5eede 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.14", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion115), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion116), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.14")) require.False(t, metadata.CanDirectUpgrade("4.0.13")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:114"}`, - `{"result":"cn-a:115,cn-b:114"}`, + `{"result":"cn-a:115"}`, + `{"result":"cn-a:116,cn-b:115"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 115") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 116") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:115"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:116"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 9948f3546a385..f71325e53460b 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 115"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 116"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion114) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion115) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 115") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 116") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 7f4c775a5683a..6b1af8e2646e3 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion115, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion116, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 06a5417273cf2..1bb80e7f69c59 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,8 +37,8 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion115(t *testing.T) { - assert.Equal(t, defines.MORPCVersion115, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +func TestGetPythonUdfStatusRequiresProtocolVersion116(t *testing.T) { + assert.Equal(t, defines.MORPCVersion116, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 6880be550a066..0cff7575b9320 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion115, + {features.PythonRoutineContract, defines.MORPCVersion116, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index c985058157b36..288dd3cc61143 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion115) + required = max(required, defines.MORPCVersion116) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 277d4d4f02a00..357cee0e2f3cd 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -548,24 +548,26 @@ func TestRemoteExpressionDestinationUnknownEvidence(t *testing.T) { func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { c, client := expressionProtocolTestCompile(t) expr := &planpb.Expr{Expr: &planpb.Expr_F{F: &planpb.Function{RoutineCall: &planpb.RoutineCall{}}}} - p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr}}}} + calendar := &planpb.Expr{Expr: &planpb.Expr_F{F: &planpb.Function{Func: &planpb.ObjectRef{Obj: function.EncodeOverloadID(function.TO_CALENDAR_INTERVAL, 0)}}}} + p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar}}}} features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion115, remoteExpressionProtocolVersion(features)) + require.True(t, features.CalendarIntervalNormalization) + require.Equal(t, defines.MORPCVersion116, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion114, defines.MORPCVersion115} { + for _, version := range []int64{defines.MORPCVersion115, defines.MORPCVersion116} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion115 { + if version < defines.MORPCVersion116 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion114) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion115) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion116) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } @@ -605,14 +607,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion115, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion116, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion114 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion114) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion115 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion115) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion116 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion116) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 41040a99ca245..00b65e231ed7f 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion115) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 115") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 116") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go index ae0f7745fffa2..4a21f38992ccc 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go @@ -127,7 +127,7 @@ func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 115") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 116") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 632b9e2315bf3..26cadbe34d318 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion115 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion116 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From f0ea1f05530a6a143c9364f2fa284f45b0cf639c Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 16 Oct 2026 11:48:02 +0800 Subject: [PATCH 228/241] fix(udf): allocate MORPC 117 after upstream rebase --- docs/design/python_udf_current_stage.md | 18 +++++----- .../python_udf_current_stage_approval.md | 23 +++++++++++- pkg/bootstrap/versions/v4_0_15/upgrade.go | 2 +- .../versions/v4_0_15/upgrade_test.go | 10 +++--- pkg/frontend/python_udf_catalog_test.go | 6 ++-- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 +-- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 35 +++++++++++++------ pkg/sql/compile/remoterun.go | 4 +-- .../upgrade/upgrade_v4_0_15_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 13 files changed, 73 insertions(+), 39 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index ae6211f106043..abe214d094191 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r15-2026-10-16` | +| Design revision | `python-udf-current-stage-r16-2026-10-16` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `99f52528308289e08ab6f07f87b0a54719b877a3` (MORPC 115 for type-sensitive calendar DAY and truncating SECOND intervals; the native COLUMNS repair remains catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r15 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 116 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `76deafc8062f9a7e33a31a4df858ebcdb9477cb5` (MORPC 116 for SELECT scalar division warning diagnostics; the native COLUMNS repair remains catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r16 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 117 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `116` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `117` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 116 and above, +revision that would become authoritative later. At protocol 117 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -100,20 +100,20 @@ Thus a tenant already at upstream final `4.0.14`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 116 before tenant tasks are created, and the repair handler +requires protocol 117 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -116. That value is rollout state in the service runtime, not a computed live +117. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 116. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 117. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -253,7 +253,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-116 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 115 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-117 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 116 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 0eb1457454717..f98c398157c44 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r15-2026-10-16`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r16-2026-10-16`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -272,3 +272,24 @@ unchanged; this revision adds no execution, production or security scope. Independent Architecture and SQL/Planner approval of r15 remains pending. Mechanical rebase, protocol allocation and validation do not supply it. + +## r16 protocol allocation addendum (2026-10-16) + +Official main `76deafc8062f9a7e33a31a4df858ebcdb9477cb5` assigns MORPC 116 +to SELECT scalar division warning diagnostics. The governing +`python-udf-current-stage-r16-2026-10-16` revision moves Python's single new +capability to 117, with 116 as the immediate predecessor rejection case. +Division diagnostics retain their execution-only 116 floor and statement-policy +check; calendar normalization remains at 115. The receiver and actual remote +endpoint retain both independent admission checks after rebase. + +Shared revision publication and reads, cached/prepared/evaluator checks, +actual remote-destination admission, receiver validation, catalog repair +metadata and login compensation, and `GetPythonUdfStatus` all require Python +capability 117. Predecessor-only and mixed 117/116 CNs are rejected before +catalog mutation. Ordinary SQL UDFs retain their pre-floor legacy fallback. +The nine idempotent shared-function entries and catalog repair 4.0.15 are +unchanged; this revision adds no execution, production or security scope. + +Independent Architecture and SQL/Planner approval of r16 remains pending. +Mechanical rebase, protocol allocation and validation do not supply it. diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade.go b/pkg/bootstrap/versions/v4_0_15/upgrade.go index dbd3076e215ea..2d64ac18da76a 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion116, + RequiredProtocolVersion: defines.MORPCVersion117, }, } diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go index 5df2a88b5eede..6e2dbdfc98842 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.14", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion116), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion117), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.14")) require.False(t, metadata.CanDirectUpgrade("4.0.13")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:115"}`, - `{"result":"cn-a:116,cn-b:115"}`, + `{"result":"cn-a:116"}`, + `{"result":"cn-a:117,cn-b:116"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 116") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 117") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:116"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:117"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index f71325e53460b..1e2b2d6b5b2ee 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 116"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 117"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion115) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion116) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 116") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 117") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 6b1af8e2646e3..b3c2a217d7cb7 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion116, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion117, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 1bb80e7f69c59..635cae06802b3 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,8 +37,8 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion116(t *testing.T) { - assert.Equal(t, defines.MORPCVersion116, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +func TestGetPythonUdfStatusRequiresProtocolVersion117(t *testing.T) { + assert.Equal(t, defines.MORPCVersion117, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 0cff7575b9320..594a6e22bddea 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion116, + {features.PythonRoutineContract, defines.MORPCVersion117, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index 288dd3cc61143..cf04b6566eec4 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion116) + required = max(required, defines.MORPCVersion117) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 357cee0e2f3cd..ce2eae79f7e72 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -32,6 +32,7 @@ import ( plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" "github.com/matrixorigin/matrixone/pkg/sql/plan/function" "github.com/matrixorigin/matrixone/pkg/vm/engine" + "github.com/matrixorigin/matrixone/pkg/vm/process" "github.com/stretchr/testify/require" ) @@ -547,27 +548,39 @@ func TestRemoteExpressionDestinationUnknownEvidence(t *testing.T) { func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { c, client := expressionProtocolTestCompile(t) + c.proc.SetStmtProfile(&process.StmtProfile{}) + c.proc.GetStmtProfile().SetStatementRuntimeProfile("Select", "DQL", false) + c.proc.GetSessionInfo().SqlMode = "ERROR_FOR_DIVISION_BY_ZERO" + c.proc.SetResolveVariableFunc(nil) + require.True(t, c.proc.DivisionByZeroWarningsEnabled()) expr := &planpb.Expr{Expr: &planpb.Expr_F{F: &planpb.Function{RoutineCall: &planpb.RoutineCall{}}}} calendar := &planpb.Expr{Expr: &planpb.Expr_F{F: &planpb.Function{Func: &planpb.ObjectRef{Obj: function.EncodeOverloadID(function.TO_CALENDAR_INTERVAL, 0)}}}} - p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar}}}} + division, err := plan2.BindFuncExprImplByPlanExpr(c.proc.Ctx, "div", []*planpb.Expr{ + {Typ: types.T_int64.ToType().PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 0}}}, + plan2.MakePlan2Int64ConstExprWithType(0), + }) + require.NoError(t, err) + p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division}}}} features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) require.True(t, features.CalendarIntervalNormalization) - require.Equal(t, defines.MORPCVersion116, remoteExpressionProtocolVersion(features)) + require.True(t, features.ScalarDivision) + require.Equal(t, defines.MORPCVersion117, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion117, executionRemoteExpressionProtocolVersion(c.proc, features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion115, defines.MORPCVersion116} { + for _, version := range []int64{defines.MORPCVersion116, defines.MORPCVersion117} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion116 { + if version < defines.MORPCVersion117 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion115) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion116) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion117) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } @@ -607,14 +620,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion116, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion117, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion115 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion115) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion116 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion116) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion117 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion117) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 00b65e231ed7f..f74901519c314 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 116") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion117) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 117") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go index 4a21f38992ccc..7c8495c57afc1 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go @@ -127,7 +127,7 @@ func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 116") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 117") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 26cadbe34d318..3cd0c69065a4b 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion116 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion117 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From b7dfd755d2c15e123dec4a7d6086d1484744e385 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Fri, 16 Oct 2026 17:39:40 +0800 Subject: [PATCH 229/241] fix(udf): allocate MORPC 118 and isolate Python test helpers --- docs/design/python_udf_current_stage.md | 18 +++++------ .../python_udf_current_stage_approval.md | 25 ++++++++++++++- optools/ut_holder_test.go | 15 +++++++-- pkg/bootstrap/versions/v4_0_15/upgrade.go | 2 +- .../versions/v4_0_15/upgrade_test.go | 10 +++--- pkg/frontend/python_udf_catalog_test.go | 6 ++-- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 4 +-- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 32 ++++++++++++------- pkg/sql/compile/remoterun.go | 4 +-- .../upgrade/upgrade_v4_0_15_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 14 files changed, 83 insertions(+), 43 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index abe214d094191..6eb160e78ffaa 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r16-2026-10-16` | +| Design revision | `python-udf-current-stage-r17-2026-10-16` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `76deafc8062f9a7e33a31a4df858ebcdb9477cb5` (MORPC 116 for SELECT scalar division warning diagnostics; the native COLUMNS repair remains catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r16 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 117 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `14a8d854b0f9346065ff8432eb979e35f32f50d8` (MORPC 117 for collation-aware LEAST/GREATEST ordering; the native COLUMNS repair remains catalog 4.0.14) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r17 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 118 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `117` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `118` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 117 and above, +revision that would become authoritative later. At protocol 118 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -100,20 +100,20 @@ Thus a tenant already at upstream final `4.0.14`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 117 before tenant tasks are created, and the repair handler +requires protocol 118 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -117. That value is rollout state in the service runtime, not a computed live +118. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 117. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 118. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -253,7 +253,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-117 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 116 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-118 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 117 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index f98c398157c44..b64dedd8bab2c 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r16-2026-10-16`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r17-2026-10-16`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -293,3 +293,26 @@ unchanged; this revision adds no execution, production or security scope. Independent Architecture and SQL/Planner approval of r16 remains pending. Mechanical rebase, protocol allocation and validation do not supply it. + +## r17 protocol allocation addendum (2026-10-16) + +Official main `14a8d854b0f9346065ff8432eb979e35f32f50d8` assigns MORPC 117 +to collation-aware LEAST/GREATEST ordering. The governing +`python-udf-current-stage-r17-2026-10-16` revision moves Python's single new +capability to 118, with 117 as the immediate predecessor rejection case. +LEAST/GREATEST retains its independent 117 floor; SELECT division diagnostics +remain at the execution-only 116 floor and calendar normalization at 115. +The sender, actual endpoint and receiver preserve all independent checks. + +Shared revision publication and reads, cached/prepared/evaluator checks, +remote-destination and receiver admission, catalog repair metadata and login +compensation, and `GetPythonUdfStatus` all require Python capability 118. +Predecessor-only and mixed 118/117 CNs are rejected before catalog mutation. +Ordinary SQL UDFs retain their pre-floor legacy fallback. The nine idempotent +shared-function entries and catalog repair 4.0.15 are unchanged. The rebase also +preserves upstream SQL UDF subquery admission and COLLATE expression binding; +it does not restore the removed Sirius Flight transport or add execution, +production or security scope to Python UDFs. + +Independent Architecture and SQL/Planner approval of r17 remains pending. +Mechanical rebase, protocol allocation and validation do not supply it. diff --git a/optools/ut_holder_test.go b/optools/ut_holder_test.go index a6b9bc5f00f6b..2824067fb06e6 100644 --- a/optools/ut_holder_test.go +++ b/optools/ut_holder_test.go @@ -60,6 +60,8 @@ func TestUTAdmissionHolderEvidence(t *testing.T) { func TestPythonStdlibEnvironmentUsesConfiguredRuntimeLibraryPath(t *testing.T) { t.Setenv("pythonLocation", "/python/toolcache") t.Setenv("LD_LIBRARY_PATH", "/matrixone/cgo") + t.Setenv("DYLD_LIBRARY_PATH", "/matrixone/cgo") + t.Setenv("DYLD_FALLBACK_LIBRARY_PATH", "/matrixone/thirdparties/lib") t.Setenv("PYTHONPATH", "/matrixone/python") t.Setenv("PYTHONHOME", "/matrixone/python-home") t.Setenv("PYTHONUSERBASE", "/matrixone/user-site") @@ -83,6 +85,7 @@ func TestPythonStdlibEnvironmentUsesConfiguredRuntimeLibraryPath(t *testing.T) { t.Fatalf("Python runtime loader path = %q, want %q", got, want) } for _, forbidden := range []string{ + "DYLD_LIBRARY_PATH", "DYLD_FALLBACK_LIBRARY_PATH", "PYTHONPATH", "PYTHONHOME", "PYTHONUSERBASE", "PYTHONSTARTUP", "PYTHONINSPECT", } { if _, ok := values[forbidden]; ok { @@ -94,8 +97,14 @@ func TestPythonStdlibEnvironmentUsesConfiguredRuntimeLibraryPath(t *testing.T) { func TestPythonStdlibEnvironmentDropsNativeLoaderPathWithoutPythonLocation(t *testing.T) { t.Setenv("pythonLocation", "") t.Setenv("LD_LIBRARY_PATH", "/matrixone/cgo") - if got := pythonStdlibEnvironment(); strings.Contains(strings.Join(got, "\n"), "LD_LIBRARY_PATH=") { - t.Fatalf("Python stdlib helper inherited MatrixOne loader path: %q", got) + t.Setenv("DYLD_LIBRARY_PATH", "/matrixone/cgo") + t.Setenv("DYLD_FALLBACK_LIBRARY_PATH", "/matrixone/thirdparties/lib") + for _, entry := range pythonStdlibEnvironment() { + key, _, _ := strings.Cut(entry, "=") + switch key { + case "LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH", "DYLD_FALLBACK_LIBRARY_PATH": + t.Fatalf("Python stdlib helper inherited native loader variable %q", key) + } } } @@ -107,7 +116,7 @@ func pythonStdlibEnvironment() []string { for _, entry := range os.Environ() { key, _, _ := strings.Cut(entry, "=") switch key { - case "LD_LIBRARY_PATH", "PYTHONHOME", "PYTHONPATH", "PYTHONUSERBASE", "PYTHONSTARTUP", "PYTHONINSPECT": + case "LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH", "DYLD_FALLBACK_LIBRARY_PATH", "PYTHONHOME", "PYTHONPATH", "PYTHONUSERBASE", "PYTHONSTARTUP", "PYTHONINSPECT": continue default: env = append(env, entry) diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade.go b/pkg/bootstrap/versions/v4_0_15/upgrade.go index 2d64ac18da76a..bbf3d93a3e113 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion117, + RequiredProtocolVersion: defines.MORPCVersion118, }, } diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go index 6e2dbdfc98842..ed934b9b6a0b1 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.14", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion117), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion118), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.14")) require.False(t, metadata.CanDirectUpgrade("4.0.13")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:116"}`, - `{"result":"cn-a:117,cn-b:116"}`, + `{"result":"cn-a:117"}`, + `{"result":"cn-a:118,cn-b:117"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 117") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 118") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:117"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:118"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 1e2b2d6b5b2ee..8caef4912d65e 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 117"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 118"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion116) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion117) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 117") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 118") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index b3c2a217d7cb7..d672b28f6a507 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion117, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion118, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 635cae06802b3..7c14b2485b9c9 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -37,8 +37,8 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion117(t *testing.T) { - assert.Equal(t, defines.MORPCVersion117, methodVersions[query.CmdMethod_GetPythonUdfStatus]) +func TestGetPythonUdfStatusRequiresProtocolVersion118(t *testing.T) { + assert.Equal(t, defines.MORPCVersion118, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 594a6e22bddea..06a5bf2141e57 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion117, + {features.PythonRoutineContract, defines.MORPCVersion118, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index cf04b6566eec4..dd48525671a90 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion117) + required = max(required, defines.MORPCVersion118) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index ce2eae79f7e72..8b6637bb8ad43 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -560,27 +560,35 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { plan2.MakePlan2Int64ConstExprWithType(0), }) require.NoError(t, err) - p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division}}}} + stringType := types.NewWithCharset(types.T_varchar, 20, 0, types.CharsetUTF8MB4UnicodeCI) + stringType.CollationVersion = 1 + least, err := plan2.BindFuncExprImplByPlanExpr(c.proc.Ctx, "least", []*planpb.Expr{ + {Typ: stringType.PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 1}}}, + {Typ: stringType.PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 2}}}, + }) + require.NoError(t, err) + p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least}}}} features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) require.True(t, features.CalendarIntervalNormalization) require.True(t, features.ScalarDivision) - require.Equal(t, defines.MORPCVersion117, remoteExpressionProtocolVersion(features)) - require.Equal(t, defines.MORPCVersion117, executionRemoteExpressionProtocolVersion(c.proc, features)) + require.True(t, features.LeastGreatestCollationSemantics) + require.Equal(t, defines.MORPCVersion118, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion118, executionRemoteExpressionProtocolVersion(c.proc, features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion116, defines.MORPCVersion117} { + for _, version := range []int64{defines.MORPCVersion117, defines.MORPCVersion118} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion117 { + if version < defines.MORPCVersion118 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion116) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion117) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion118) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } @@ -620,14 +628,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion117, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion118, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion116 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion116) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion117 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion117) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion118 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion118) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index f74901519c314..8d67ae7dcefd5 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion117) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 117") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion118) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 118") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go index 7c8495c57afc1..d381aca51c817 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go @@ -127,7 +127,7 @@ func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 117") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 118") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 3cd0c69065a4b..f8fff0123fcda 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion117 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion118 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From 6be0d5fe53b31eccd91264ac336dcc7010784ac1 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Sat, 17 Oct 2026 23:07:33 +0800 Subject: [PATCH 230/241] fix(udf): preserve catalog 4.0.17 and add 4.0.18 repair Keep the published COLUMNS migration and historical handlers intact. Register the shared Python revision repair at 4.0.18 with minimum source 4.0.17; retain protocol 120 admission and predecessor rejection. Preserve both shared Query descriptors and the official protocol 119 contract. Cover the new scheduler hop and real first-login repair from 4.0.12 through 4.0.17, with SQL UDF compatibility and idempotent replay. Keep the COLUMNS fixture's failure/retry boundary at its published version. Update the governing r21 design and immutable allocation record while retaining pending independent Architecture and SQL/Planner approval. --- docs/design/python_udf_current_stage.md | 36 +- .../python_udf_current_stage_approval.md | 106 +- pkg/bootstrap/columns_upgrade_test.go | 9 +- .../service_statistics_upgrade_test.go | 5 + pkg/bootstrap/upgrade.go | 2 + .../versions/v4_0_14/tenant_upgrade_list.go | 34 +- .../versions/v4_0_15/tenant_upgrade_list.go | 70 +- pkg/bootstrap/versions/v4_0_15/upgrade.go | 20 +- .../versions/v4_0_18/tenant_upgrade_list.go | 21 + pkg/bootstrap/versions/v4_0_18/upgrade.go | 91 + .../{v4_0_15 => v4_0_18}/upgrade_test.go | 24 +- pkg/defines/const.go | 3 +- pkg/frontend/python_udf_catalog_test.go | 6 +- pkg/pb/plan/correlation_test.go | 9 + pkg/pb/plan/merged_descriptor_test.go | 2 +- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 2 +- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 29 +- pkg/sql/compile/remoterun.go | 4 +- pkg/sql/parsers/dialect/mysql/mysql_sql.go | 35102 +++++++++++++++- pkg/sql/plan/deepcopy_test.go | 9 + ...est.go => upgrade_v4_0_18_routine_test.go} | 30 +- pkg/udf/python_contract.go | 2 +- .../cases/dml/show/database_statistics.result | 4 +- test/distributed/cases/dml/show/show.result | 2 +- 27 files changed, 35381 insertions(+), 247 deletions(-) create mode 100644 pkg/bootstrap/versions/v4_0_18/tenant_upgrade_list.go create mode 100644 pkg/bootstrap/versions/v4_0_18/upgrade.go rename pkg/bootstrap/versions/{v4_0_15 => v4_0_18}/upgrade_test.go (94%) rename pkg/tests/upgrade/{upgrade_v4_0_15_routine_test.go => upgrade_v4_0_18_routine_test.go} (88%) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 6eb160e78ffaa..cb79e972298f8 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r17-2026-10-16` | +| Design revision | `python-udf-current-stage-r21-2026-10-19` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `14a8d854b0f9346065ff8432eb979e35f32f50d8` (MORPC 117 for collation-aware LEAST/GREATEST ordering; the native COLUMNS repair remains catalog 4.0.14) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r17 contract preserves the upstream catalog 4.0.14 handler unchanged, adds a separate Python revision repair in catalog 4.0.15, and uses protocol 118 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `def799e1260dd547cae2e0e54323ea20ec1b7685` (MORPC 119 for coordinator-owned parameterized subquery programs; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r21 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 120 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `118` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `120` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 118 and above, +revision that would become authoritative later. At protocol 120 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -93,27 +93,35 @@ demo's old execution behavior is not a compatibility promise. Upgrade `4.0.7` contains the original idempotent shared-function schema entries. Its historical protocol-61 requirement belongs to the already-shipped provenance contract; it does not prove Python revision capability. The registered repair -`4.0.15` (minimum direct source `4.0.14`) replays the nine shared-function -entries. Upstream handlers `4.0.8` through `4.0.14`, including the protocol-107 -statistics view refresh and the protocol-109 COLUMNS refresh, remain unchanged. -Thus a tenant already at upstream final `4.0.14`, including one lacking revision +`4.0.18` (minimum direct source `4.0.17`) replays the nine shared-function +entries. Upstream handlers `4.0.8` through `4.0.17`, including the protocol-107 +statistics view refresh, the protocol-109 COLUMNS refresh, and the protocol-118 +database-defaults/table-collation upgrade, persisted COLLATIONS refresh, and +4.0.17 COLUMNS MEDIUMINT refresh, remain unchanged. +Thus a tenant already at upstream final `4.0.17`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 118 before tenant tasks are created, and the repair handler +requires protocol 120 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -118. That value is rollout state in the service runtime, not a computed live +120. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy row. Sender admission also probes the actual remote CN endpoint, and the receiver checks its own active protocol; coordinator state alone cannot admit an old -receiver. Missing or malformed protocol state fails closed. The read-only -`GetPythonUdfStatus` method uses wire capability 118. Worker capability negotiation +receiver. Missing or malformed protocol state fails closed. + +The shared `Query` protobuf preserves official `correlation = 19`; this PR +uses `routine_dependencies = 20`. Both fields survive serialization, generated +descriptor lookup, and deep-copy without aliasing. Python-bearing plans require +protocol 120 before Prepare, publication, send, or execution; main-only dependent +programs retain their independent protocol-119 admission. The read-only +`GetPythonUdfStatus` method uses wire capability 120. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -253,7 +261,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-118 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_15/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14, rejection at protocol 117 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-120 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 119 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index b64dedd8bab2c..97593f2dd2ad3 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r17-2026-10-16`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r18-2026-10-17`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -316,3 +316,107 @@ production or security scope to Python UDFs. Independent Architecture and SQL/Planner approval of r17 remains pending. Mechanical rebase, protocol allocation and validation do not supply it. + +## r18 protocol and catalog allocation addendum (2026-10-17) + +Official main `b111224b0c624773389b390cd3cf1223126b6ee2` owns MORPC 118 +for transactional database defaults and table charset alteration, including +its catalog 4.0.15 migration. The governing +`python-udf-current-stage-r18-2026-10-17` revision preserves that handler and +all earlier published handlers unchanged. Python's single new capability is +119; its nine idempotent shared-function entries move to catalog 4.0.16, +whose minimum direct source is 4.0.15. The historical 4.0.7 entries keep their +original provenance and are not treated as current Python admission. + +Shared revision publication/read, cached/prepared/evaluator checks, +remote destination/send/receive admission, repair metadata, login compensation +and `GetPythonUdfStatus` require capability 119. Immediate predecessor 118 +and mixed 119/118 CNs are rejected before shared-function mutation. The +independent table-collation/defaults contract remains at 118; LEAST/GREATEST +remains at 117. Ordinary SQL UDFs retain their pre-floor legacy fallback. +The real login-repair regression covers tenant versions 4.0.12 through +4.0.15, rejection at 118, preserved legacy SQL results, and idempotent replay. + +Generated plan bindings combine the upstream database-defaults message with +Python routine identities; the merged parser retains both charset DDL and +Python function syntax. This mechanical rebase adds no Python execution, +production or security scope. The earlier addenda describe their historical +allocations, not the governing r18 admission floor. + +Independent Architecture and SQL/Planner approval of r18 remains pending. +Rebase, allocation and validation do not provide independent approval. + +## r19 catalog allocation addendum (2026-10-18) + +Official main `a8be04735bcf6d2a7aa48d464f76c0b13c691ef5` publishes +catalog 4.0.16 to refresh persisted COLLATIONS metadata. The governing +`python-udf-current-stage-r19-2026-10-18` proposal preserves that handler, +its protocol-118 admission and all earlier published handlers unchanged. +Python's nine idempotent shared-function entries move to catalog 4.0.17, +whose minimum direct source is 4.0.16. Official MORPC latest remains 118, +so the single Python capability remains 119; immediate predecessor 118 and +mixed 119/118 admission checks are unchanged. + +The upgrade registry and scheduling oracle retain the explicit 4.0.15, +4.0.16 and 4.0.17 hops. Real first-login repair covers tenant versions +4.0.12 through 4.0.16, rejection at protocol 118 before mutation, preserved +legacy SQL results and two mutation-free replays. Upstream row-scoped scalar +warning diagnostics and test-harness cleanup ownership remain intact. + +This allocation update adds no Python execution, production or security +scope. Earlier addenda record historical allocations. Independent Architecture +and SQL/Planner approval of r19 remains pending; rebase and validation do not +provide that approval. + + +## r20 protocol and shared-plan allocation addendum (2026-10-19) + +Official main `75d16a2b875905ffa4121783dcda4f538d3c05f7` owns protocol 119 +for coordinator-owned parameterized subquery programs and `Query.correlation` +field 19. The current `python-udf-current-stage-r20-2026-10-19` proposal preserves +both official allocations. Its single Python capability moves to 120, and +`Query.routine_dependencies` uses field 20. The merged protobuf descriptor, +marshal/unmarshal and deep-copy must preserve both contracts independently. + +Catalog versions and entries are unchanged: all published handlers through +4.0.16 remain intact; the separate Python repair is 4.0.17 with minimum direct +source 4.0.16. Catalog repair, SQL revision read/write, prepared-plan reuse, +Python evaluator Prepare, remote sender/receiver and `GetPythonUdfStatus` use +capability 120. Immediate predecessor 119 and mixed 120/119 workers fail closed +before shared catalog mutation or Python execution. The main dependent-program +contract stays at 119 and the independent table/defaults contract stays at 118. + +The acceptance evidence includes merged descriptor and mixed Query round-trip / +deep-copy checks, both compiler gates, predecessor rejection, and real login +repair from tenant versions 4.0.12 through 4.0.16 with legacy SQL UDF results and +idempotent replay. These tests do not establish cross-binary downgrade or +independent architecture approval. No new Python production, security or runtime +scope is added. Independent Architecture and SQL/Planner approval of r20 remains +pending; this allocation and rebase do not provide that approval. + + +## r21 catalog allocation addendum (2026-10-19) + +Official main `def799e1260dd547cae2e0e54323ea20ec1b7685` publishes catalog +4.0.17 for the persisted COLUMNS MEDIUMINT metadata refresh. The governing +`python-udf-current-stage-r21-2026-10-19` proposal preserves that handler and +its entries byte-for-byte, including its protocol-118 admission metadata. +The shared COLUMNS entry used by 4.0.14 also retains the official implementation. +Python's nine idempotent shared-function entries move to catalog 4.0.18, +whose minimum direct source is 4.0.17. The registry retains both distinct hops; +no published handler is replaced by the Python repair. + +Official MORPC latest remains 119, so the single Python capability remains 120. +Catalog repair, revision publication/read, Prepare, prepared reuse, remote +sender/receiver and status admission continue to reject predecessor 119 and +mixed 120/119 workers before Python catalog mutation or execution. Query fields +19 (correlation) and 20 (routine dependencies) remain unchanged. + +Scheduling covers the 4.0.17 to 4.0.18 transition. The existing real first-login +fixture now includes tenant versions 4.0.12 through 4.0.17, predecessor rejection, +legacy SQL UDF and nested correlated results, and two mutation-free repair +replays. The COLUMNS fixture independently retains its published 4.0.17 boundary. +These tests do not establish cross-binary downgrade or independent approval. +No new Python runtime, production or security scope is added. Independent +Architecture and SQL/Planner approval of r21 remains pending; rebase and +validation do not provide that approval. diff --git a/pkg/bootstrap/columns_upgrade_test.go b/pkg/bootstrap/columns_upgrade_test.go index 78fd928893a9b..c1452919dbd5c 100644 --- a/pkg/bootstrap/columns_upgrade_test.go +++ b/pkg/bootstrap/columns_upgrade_test.go @@ -22,6 +22,8 @@ import ( "github.com/golang/mock/gomock" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_16" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_17" "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/matrixorigin/matrixone/pkg/defines" mock_frontend "github.com/matrixorigin/matrixone/pkg/frontend/test" @@ -86,7 +88,12 @@ func TestColumnsUpgradeReachesExistingTenants(t *testing.T) { return executor.Result{}, nil }, op) s := newServiceForTest("", &memLocker{}, clock.NewHLCClock(func() int64 { return 0 }, 0), nil, exec, - func(s *service) { s.initUpgrade() }) + func(s *service) { + // This fixture proves the published COLUMNS repair at 4.0.17. + // The scheduling and real-login tests cover the full registry + // including the separate Python revision repair. + s.handles = []VersionHandle{v4_0_16.Handler, v4_0_17.Handler} + }) t.Cleanup(s.stopper.Stop) final := s.getFinalVersionHandle().Metadata() require.NoError(t, s.doCheckUpgrade(t.Context())) diff --git a/pkg/bootstrap/service_statistics_upgrade_test.go b/pkg/bootstrap/service_statistics_upgrade_test.go index 27d9fcfeac292..2dcb0535ac4f2 100644 --- a/pkg/bootstrap/service_statistics_upgrade_test.go +++ b/pkg/bootstrap/service_statistics_upgrade_test.go @@ -29,6 +29,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_14" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_15" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_16" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_17" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_6" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_8" @@ -82,6 +83,7 @@ func TestDoCheckUpgradeQueuesStatisticsRefresh(t *testing.T) { {name: "current_4.0.14", version: "4.0.14", offset: v4_0_14.Handler.Metadata().VersionOffset, upgrade: true}, {name: "current_4.0.15", version: "4.0.15", offset: v4_0_15.Handler.Metadata().VersionOffset, upgrade: true}, {name: "current_4.0.16", version: "4.0.16", offset: v4_0_16.Handler.Metadata().VersionOffset, upgrade: true}, + {name: "current_4.0.17", version: "4.0.17", offset: v4_0_17.Handler.Metadata().VersionOffset, upgrade: true}, {name: "current", version: final.Version, offset: final.VersionOffset}, } { t.Run(test.name, func(t *testing.T) { @@ -117,6 +119,9 @@ func TestDoCheckUpgradeQueuesStatisticsRefresh(t *testing.T) { require.NoError(t, b.doCheckUpgrade(context.Background())) if test.upgrade { hops := []versions.Version{final} + if versions.Compare(test.version, "4.0.17") < 0 { + hops = append([]versions.Version{v4_0_17.Handler.Metadata()}, hops...) + } if versions.Compare(test.version, "4.0.16") < 0 { hops = append([]versions.Version{v4_0_16.Handler.Metadata()}, hops...) } diff --git a/pkg/bootstrap/upgrade.go b/pkg/bootstrap/upgrade.go index fd5b118047547..ff004169ece01 100644 --- a/pkg/bootstrap/upgrade.go +++ b/pkg/bootstrap/upgrade.go @@ -36,6 +36,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_15" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_16" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_17" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_18" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_2" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_3" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_4" @@ -81,6 +82,7 @@ func (s *service) initUpgrade() { s.handles = append(s.handles, v4_0_15.Handler) s.handles = append(s.handles, v4_0_16.Handler) s.handles = append(s.handles, v4_0_17.Handler) + s.handles = append(s.handles, v4_0_18.Handler) } func (s *service) getFinalVersionHandle() VersionHandle { diff --git a/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go b/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go index 124ff85ecaca6..6fba56b82c82b 100644 --- a/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go +++ b/pkg/bootstrap/versions/v4_0_14/tenant_upgrade_list.go @@ -14,36 +14,6 @@ package v4_0_14 -import ( - "fmt" +import "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/defines" - "github.com/matrixorigin/matrixone/pkg/util/executor" - "github.com/matrixorigin/matrixone/pkg/util/sysview" -) - -var tenantUpgEntries = []versions.UpgradeEntry{upgradeInformationSchemaColumns()} - -// upgradeInformationSchemaColumns refreshes the persisted COLUMNS view for -// tenants that already passed the protocol-100 view migration. The current -// definition adds the native UCA 4.0.0 charset/collation identities (selector -// values 4 and 5); changing the old v4.0.10 entry would not reach tenants that -// have already recorded a later tenant version. -func upgradeInformationSchemaColumns() versions.UpgradeEntry { - return versions.UpgradeEntry{ - Schema: sysview.InformationDBConst, - TableName: "COLUMNS", - UpgType: versions.MODIFY_VIEW, - UpgSql: sysview.InformationSchemaColumnsDDL, - RequiredProtocolVersion: defines.MORPCVersion109, - CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { - exists, definition, err := versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "COLUMNS") - if err == nil && !exists { - exists, definition, err = versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "columns") - } - return exists && definition == sysview.InformationSchemaColumnsDDL, err - }, - PreSql: fmt.Sprintf("DROP VIEW IF EXISTS %s.COLUMNS;", sysview.InformationDBConst), - } -} +var tenantUpgEntries = []versions.UpgradeEntry{versions.InformationSchemaColumnsUpgradeEntry()} diff --git a/pkg/bootstrap/versions/v4_0_15/tenant_upgrade_list.go b/pkg/bootstrap/versions/v4_0_15/tenant_upgrade_list.go index 3188f09250a90..4d082e5c658d8 100644 --- a/pkg/bootstrap/versions/v4_0_15/tenant_upgrade_list.go +++ b/pkg/bootstrap/versions/v4_0_15/tenant_upgrade_list.go @@ -4,7 +4,7 @@ // 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 +// 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, @@ -14,8 +14,68 @@ package v4_0_15 -import "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" +import ( + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/catalog" + "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/util/executor" + "github.com/matrixorigin/matrixone/pkg/util/sysview" +) -// This repair is newer than every published upstream tenant version, so an -// already-upgraded tenant is scheduled even if it lacks the revision catalog. -var tenantUpgEntries = v4_0_7.PythonRevisionUpgradeEntries() +var tenantUpgEntries = []versions.UpgradeEntry{ + { + Schema: catalog.MO_CATALOG, + TableName: catalog.MODatabaseDefaults, + UpgType: versions.CREATE_NEW_TABLE, + UpgSql: catalog.MoDatabaseDefaultsDDL, + RequiredProtocolVersion: defines.MORPCVersion118, + CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { + return versions.CheckTableDefinition(txn, accountID, catalog.MO_CATALOG, catalog.MODatabaseDefaults) + }, + }, + { + Schema: sysview.InformationDBConst, + TableName: "SCHEMATA", + UpgType: versions.MODIFY_VIEW, + UpgSql: sysview.InformationSchemaSchemataDDL, + PreSql: "DROP VIEW IF EXISTS information_schema.SCHEMATA;", + RequiredProtocolVersion: defines.MORPCVersion118, + CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { + exists, definition, err := versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "SCHEMATA") + if err == nil && !exists { + exists, definition, err = versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "schemata") + } + return exists && definition == sysview.InformationSchemaSchemataDDL, err + }, + }, + { + Schema: sysview.InformationDBConst, + TableName: "COLUMNS", + UpgType: versions.MODIFY_VIEW, + UpgSql: sysview.InformationSchemaColumnsDDL, + PreSql: "DROP VIEW IF EXISTS information_schema.COLUMNS;", + RequiredProtocolVersion: defines.MORPCVersion118, + CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { + exists, definition, err := versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "COLUMNS") + if err == nil && !exists { + exists, definition, err = versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "columns") + } + return exists && definition == sysview.InformationSchemaColumnsDDL, err + }, + }, + { + Schema: sysview.InformationDBConst, + TableName: "TABLES", + UpgType: versions.MODIFY_VIEW, + UpgSql: sysview.InformationSchemaTablesV118DDL, + PreSql: "DROP VIEW IF EXISTS information_schema.TABLES;", + RequiredProtocolVersion: defines.MORPCVersion118, + CheckFunc: func(txn executor.TxnExecutor, accountID uint32) (bool, error) { + exists, definition, err := versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "TABLES") + if err == nil && !exists { + exists, definition, err = versions.CheckViewDefinition(txn, accountID, sysview.InformationDBConst, "tables") + } + return exists && definition == sysview.InformationSchemaTablesV118DDL, err + }, + }, +} diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade.go b/pkg/bootstrap/versions/v4_0_15/upgrade.go index bbf3d93a3e113..57a1c52ed8f33 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_15/upgrade.go @@ -27,11 +27,8 @@ import ( "go.uber.org/zap" ) -// 4.0.15 replays the idempotent shared Python UDF catalog entries without -// changing the already-published upstream handlers. Tenants that completed -// upstream 4.0.14 may still lack this catalog; a new semantic version makes -// them eligible for both background upgrade and first-login compensation. -// Complete, partial and absent catalog states converge on retry. +// Database defaults have their own tenant migration after 4.0.14. An older +// worker must not treat the new catalog and SCHEMATA view as already upgraded. var Handler = &versionHandle{ metadata: versions.Version{ Version: "4.0.15", @@ -51,17 +48,12 @@ func (v *versionHandle) Metadata() versions.Version { return v.metadata } -func (v *versionHandle) Prepare(ctx context.Context, txn executor.TxnExecutor, final bool) error { +func (v *versionHandle) Prepare(_ context.Context, txn executor.TxnExecutor, _ bool) error { txn.Use(catalog.MO_CATALOG) return nil } -func (v *versionHandle) HandleTenantUpgrade(ctx context.Context, tenantID int32, txn executor.TxnExecutor) error { - // Login compensation invokes this handler without the cluster-upgrade - // scheduler, so enforce the same floor before any catalog mutation. - if err := versions.CheckCommonProtocolVersion(txn, v.metadata.RequiredProtocolVersion); err != nil { - return err - } +func (v *versionHandle) HandleTenantUpgrade(_ context.Context, tenantID int32, txn executor.TxnExecutor) error { logger := runtime.ServiceRuntime(txn.Txn().TxnOptions().CN).Logger() for _, entry := range tenantUpgEntries { start := time.Now() @@ -82,10 +74,10 @@ func (v *versionHandle) HandleTenantUpgrade(ctx context.Context, tenantID int32, return nil } -func (v *versionHandle) HandleClusterUpgrade(ctx context.Context, txn executor.TxnExecutor) error { +func (v *versionHandle) HandleClusterUpgrade(_ context.Context, _ executor.TxnExecutor) error { return nil } -func (v *versionHandle) HandleCreateFrameworkDeps(txn executor.TxnExecutor) error { +func (v *versionHandle) HandleCreateFrameworkDeps(_ executor.TxnExecutor) error { return moerr.NewInternalErrorNoCtxf("Only v1.2.0 can initialize upgrade framework, current version is:%s", v.metadata.Version) } diff --git a/pkg/bootstrap/versions/v4_0_18/tenant_upgrade_list.go b/pkg/bootstrap/versions/v4_0_18/tenant_upgrade_list.go new file mode 100644 index 0000000000000..0250b4ff50ef6 --- /dev/null +++ b/pkg/bootstrap/versions/v4_0_18/tenant_upgrade_list.go @@ -0,0 +1,21 @@ +// Copyright 2026 Matrix Origin +// +// 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 v4_0_18 + +import "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_7" + +// This repair is newer than every published upstream tenant version, so an +// already-upgraded tenant is scheduled even if it lacks the revision catalog. +var tenantUpgEntries = v4_0_7.PythonRevisionUpgradeEntries() diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade.go b/pkg/bootstrap/versions/v4_0_18/upgrade.go new file mode 100644 index 0000000000000..e3ad29c17acce --- /dev/null +++ b/pkg/bootstrap/versions/v4_0_18/upgrade.go @@ -0,0 +1,91 @@ +// Copyright 2026 Matrix Origin +// +// 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 v4_0_18 + +import ( + "context" + "time" + + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" + "github.com/matrixorigin/matrixone/pkg/catalog" + "github.com/matrixorigin/matrixone/pkg/common/moerr" + "github.com/matrixorigin/matrixone/pkg/common/runtime" + "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/util/executor" + "go.uber.org/zap" +) + +// 4.0.18 replays the idempotent shared Python UDF catalog entries without +// changing the already-published upstream handlers. Tenants that completed +// upstream 4.0.17 may still lack this catalog; a new semantic version makes +// them eligible for both background upgrade and first-login compensation. +// Complete, partial and absent catalog states converge on retry. +var Handler = &versionHandle{ + metadata: versions.Version{ + Version: "4.0.18", + MinUpgradeVersion: "4.0.17", + UpgradeCluster: versions.No, + UpgradeTenant: versions.Yes, + VersionOffset: uint32(len(tenantUpgEntries)), + RequiredProtocolVersion: defines.MORPCVersion120, + }, +} + +type versionHandle struct { + metadata versions.Version +} + +func (v *versionHandle) Metadata() versions.Version { + return v.metadata +} + +func (v *versionHandle) Prepare(ctx context.Context, txn executor.TxnExecutor, final bool) error { + txn.Use(catalog.MO_CATALOG) + return nil +} + +func (v *versionHandle) HandleTenantUpgrade(ctx context.Context, tenantID int32, txn executor.TxnExecutor) error { + // Login compensation invokes this handler without the cluster-upgrade + // scheduler, so enforce the same floor before any catalog mutation. + if err := versions.CheckCommonProtocolVersion(txn, v.metadata.RequiredProtocolVersion); err != nil { + return err + } + logger := runtime.ServiceRuntime(txn.Txn().TxnOptions().CN).Logger() + for _, entry := range tenantUpgEntries { + start := time.Now() + if err := entry.Upgrade(txn, uint32(tenantID)); err != nil { + logger.Error("tenant upgrade entry execute error", + zap.Error(err), + zap.Int32("tenantId", tenantID), + zap.String("version", v.metadata.Version), + zap.String("upgrade entry", entry.String())) + return err + } + logger.Info("tenant upgrade entry complete", + zap.Int32("tenantId", tenantID), + zap.String("upgrade entry", entry.String()), + zap.Int64("time cost(ms)", time.Since(start).Milliseconds()), + zap.String("toVersion", v.metadata.Version)) + } + return nil +} + +func (v *versionHandle) HandleClusterUpgrade(ctx context.Context, txn executor.TxnExecutor) error { + return nil +} + +func (v *versionHandle) HandleCreateFrameworkDeps(txn executor.TxnExecutor) error { + return moerr.NewInternalErrorNoCtxf("Only v1.2.0 can initialize upgrade framework, current version is:%s", v.metadata.Version) +} diff --git a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go similarity index 94% rename from pkg/bootstrap/versions/v4_0_15/upgrade_test.go rename to pkg/bootstrap/versions/v4_0_18/upgrade_test.go index ed934b9b6a0b1..82b58c13430f1 100644 --- a/pkg/bootstrap/versions/v4_0_15/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package v4_0_15 +package v4_0_18 import ( "context" @@ -35,21 +35,21 @@ import ( func TestPythonRevisionRepairUpgradePath(t *testing.T) { metadata := Handler.Metadata() - require.Equal(t, "4.0.15", metadata.Version) - require.Equal(t, "4.0.14", metadata.MinUpgradeVersion) + require.Equal(t, "4.0.18", metadata.Version) + require.Equal(t, "4.0.17", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion118), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion120), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) - require.True(t, metadata.CanDirectUpgrade("4.0.14")) - require.False(t, metadata.CanDirectUpgrade("4.0.13")) + require.True(t, metadata.CanDirectUpgrade("4.0.17")) + require.False(t, metadata.CanDirectUpgrade("4.0.16")) require.Len(t, v4_0_7.PythonRevisionUpgradeEntries(), 9) } func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:117"}`, - `{"result":"cn-a:118,cn-b:117"}`, + `{"result":"cn-a:119"}`, + `{"result":"cn-a:120,cn-b:119"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 118") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 120") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -78,8 +78,8 @@ func TestPythonRevisionRepairIsIdempotentForCatalogStates(t *testing.T) { wantFirstDDL int }{ { - name: "upstream_final_4.0.14_missed_catalog", - schemaOrigin: "4.0.14", + name: "upstream_final_4.0.17_missed_catalog", + schemaOrigin: "4.0.17", legacyIndex: true, wantFirstDDL: 9, }, @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:118"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:120"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/defines/const.go b/pkg/defines/const.go index 97439489fd538..8a8fc5c279455 100644 --- a/pkg/defines/const.go +++ b/pkg/defines/const.go @@ -162,7 +162,8 @@ const ( MORPCVersion124 int64 = 124 // exact fractional TIMESTAMPADD SECOND intervals MORPCVersion125 int64 = 125 // LOAD IGNORE foreign-key row rejection diagnostics MORPCVersion126 int64 = 126 // parser-derived information_schema.VIEWS definitions - MORPCLatestVersion = MORPCVersion126 + MORPCVersion127 int64 = 127 // shared Python UDF revision catalog and remote execution contract + MORPCLatestVersion = MORPCVersion127 ) // DefaultLockWaitTimeoutSeconds is shared by the frontend default and by diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 8caef4912d65e..895501d56199a 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 118"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 120"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion117) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion119) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 118") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 120") require.Empty(t, background.executedSqls) } diff --git a/pkg/pb/plan/correlation_test.go b/pkg/pb/plan/correlation_test.go index 394013e0b5d61..c5e83a8ddb008 100644 --- a/pkg/pb/plan/correlation_test.go +++ b/pkg/pb/plan/correlation_test.go @@ -50,6 +50,10 @@ func correlationTestQuery() *Query { func TestCorrelationPlanRoundTrip(t *testing.T) { q := correlationTestQuery() + q.RoutineDependencies = []*RoutinePlanDependency{{ + FunctionRef: &FunctionRef{FunctionId: 11, Revision: 3}, + Language: "python", + }} require.NoError(t, q.ValidateCorrelation()) data, err := q.Marshal() require.NoError(t, err) @@ -57,6 +61,11 @@ func TestCorrelationPlanRoundTrip(t *testing.T) { require.NoError(t, decoded.Unmarshal(data)) require.NoError(t, decoded.ValidateCorrelation()) require.True(t, proto.Equal(q, decoded)) + require.Equal(t, uint64(3), decoded.RoutineDependencies[0].FunctionRef.Revision) + features, err := RequiredRemoteExpressionFeatures(decoded) + require.NoError(t, err) + require.True(t, features.DependentPrograms) + require.True(t, features.Any()) require.Equal(t, int32(0), decoded.MainOutputStep()) require.Equal(t, int32(1), (&Query{Steps: []int32{0, 1}}).MainOutputStep()) require.Equal(t, int32(-1), (*Query)(nil).MainOutputStep()) diff --git a/pkg/pb/plan/merged_descriptor_test.go b/pkg/pb/plan/merged_descriptor_test.go index 09737c46be787..0d066f3ee51fa 100644 --- a/pkg/pb/plan/merged_descriptor_test.go +++ b/pkg/pb/plan/merged_descriptor_test.go @@ -25,7 +25,7 @@ func TestPlanDescriptorMergedContracts(t *testing.T) { // The compressed descriptor must agree with both generated Go contracts. // Resolving a descriptor-only conflict by choosing either side loses one. want := map[string]map[string]int32{ - "Query": {"correlation": 19}, + "Query": {"correlation": 19, "routine_dependencies": 20}, "CreateDatabase": {"defaults": 5}, "AlterDatabase": {"defaults": 3}, "CreateTable": {"database_defaults": 18, "ctas_execution_protocol_version": 19}, diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index d672b28f6a507..9f190a3591d83 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion118, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion119, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 7c14b2485b9c9..a08130a34123e 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -38,7 +38,7 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { } func TestGetPythonUdfStatusRequiresProtocolVersion118(t *testing.T) { - assert.Equal(t, defines.MORPCVersion118, methodVersions[query.CmdMethod_GetPythonUdfStatus]) + assert.Equal(t, defines.MORPCVersion119, methodVersions[query.CmdMethod_GetPythonUdfStatus]) } // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 06a5bf2141e57..c0ad8b5e5ad37 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion118, + {features.PythonRoutineContract, defines.MORPCVersion120, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index dd48525671a90..2c67fb27c46e2 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion118) + required = max(required, defines.MORPCVersion120) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 8b6637bb8ad43..34089fff5990b 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -567,28 +567,33 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { {Typ: stringType.PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 2}}}, }) require.NoError(t, err) - p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least}}}} + tableCollation, err := plan2.BindFuncExprImplByPlanExpr(c.proc.Ctx, "internal_table_collation", []*planpb.Expr{ + {Typ: types.T_varchar.ToType().PlanType(), Expr: &planpb.Expr_Lit{Lit: &planpb.Literal{Value: &planpb.Literal_Sval{Sval: ""}}}}, + }) + require.NoError(t, err) + p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least, tableCollation}}}} features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) require.True(t, features.CalendarIntervalNormalization) require.True(t, features.ScalarDivision) require.True(t, features.LeastGreatestCollationSemantics) - require.Equal(t, defines.MORPCVersion118, remoteExpressionProtocolVersion(features)) - require.Equal(t, defines.MORPCVersion118, executionRemoteExpressionProtocolVersion(c.proc, features)) + require.True(t, features.TableCollationFunction) + require.Equal(t, defines.MORPCVersion120, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion120, executionRemoteExpressionProtocolVersion(c.proc, features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion117, defines.MORPCVersion118} { + for _, version := range []int64{defines.MORPCVersion119, defines.MORPCVersion120} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion118 { + if version < defines.MORPCVersion120 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion117) + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion119) require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion118) + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion120) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } @@ -628,14 +633,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion118, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion120, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion117 + client.version = defines.MORPCVersion119 require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion117) + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion119) require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") - client.version = defines.MORPCVersion118 - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion118) + client.version = defines.MORPCVersion120 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion120) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 8d67ae7dcefd5..63478e13dff79 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion118) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 118") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion120) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 120") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/sql/parsers/dialect/mysql/mysql_sql.go b/pkg/sql/parsers/dialect/mysql/mysql_sql.go index fe1f30f9b0d60..75cb0d54c0cd2 100644 --- a/pkg/sql/parsers/dialect/mysql/mysql_sql.go +++ b/pkg/sql/parsers/dialect/mysql/mysql_sql.go @@ -2,65 +2,67 @@ //line mysql_sql.y:16 package mysql + import ( -__yyfmt__ "fmt" -__yyunsafe__ "unsafe" + __yyfmt__ "fmt" + __yyunsafe__ "unsafe" ) + //line mysql_sql.y:16 - + import ( - "fmt" - "strings" + "fmt" + "strings" - "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" - "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" - "github.com/matrixorigin/matrixone/pkg/sql/parsers/util" - "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" + "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" + "github.com/matrixorigin/matrixone/pkg/sql/parsers/util" ) func sqlTaskNodeString(node tree.NodeFormatter) string { - if node == nil { - return "" - } - return tree.StringWithOpts(node, dialect.MYSQL, tree.WithQuoteIdentifier(), tree.WithSingleQuoteString()) + if node == nil { + return "" + } + return tree.StringWithOpts(node, dialect.MYSQL, tree.WithQuoteIdentifier(), tree.WithSingleQuoteString()) } // makeSelectStarFromTable builds the `SELECT * FROM tbl` clause used to desugar // MySQL TABLE query terms and their REPLACE source form. func makeSelectStarFromTable(tbl tree.TableExpr) *tree.SelectClause { - return &tree.SelectClause{ - Exprs: tree.SelectExprs{tree.SelectExpr{Expr: tree.StarExpr()}}, - From: &tree.From{ - Tables: tree.TableExprs{&tree.AliasedTableExpr{Expr: tbl}}, - }, - } + return &tree.SelectClause{ + Exprs: tree.SelectExprs{tree.SelectExpr{Expr: tree.StarExpr()}}, + From: &tree.From{ + Tables: tree.TableExprs{&tree.AliasedTableExpr{Expr: tbl}}, + }, + } } func sqlTaskBodyString(stmt tree.Statement) string { - compound, ok := stmt.(*tree.CompoundStmt) - if !ok || compound == nil { - return "" - } - parts := make([]string, 0, len(compound.Stmts)) - for _, s := range compound.Stmts { - if s != nil { - parts = append(parts, tree.StringWithOpts(s, dialect.MYSQL, tree.WithQuoteIdentifier(), tree.WithSingleQuoteString())) - } - } - return strings.Join(parts, "; ") + compound, ok := stmt.(*tree.CompoundStmt) + if !ok || compound == nil { + return "" + } + parts := make([]string, 0, len(compound.Stmts)) + for _, s := range compound.Stmts { + if s != nil { + parts = append(parts, tree.StringWithOpts(s, dialect.MYSQL, tree.WithQuoteIdentifier(), tree.WithSingleQuoteString())) + } + } + return strings.Join(parts, "; ") } func sqlTaskInt64(v any) int64 { - switch value := v.(type) { - case int: - return int64(value) - case int64: - return value - case uint64: - return int64(value) - default: - panic(fmt.Sprintf("unexpected integral type %T", v)) - } + switch value := v.(type) { + case int: + return int64(value) + case int64: + return value + case uint64: + return int64(value) + default: + panic(fmt.Sprintf("unexpected integral type %T", v)) + } } const restoreSnapshotFromSyntaxHint = `FROM SNAPSHOT is not supported; use RESTORE DATABASE [account.]database{snapshot="snapshot_name"}` @@ -76,107 +78,108 @@ func makeCharsetCastCharType(width int32, charsetName string) *tree.T { oid = uint32(defines.MYSQL_TYPE_VARCHAR) } return &tree.T{InternalType: tree.InternalType{ - Family: tree.StringFamily, - FamilyString: familyString, - DisplayWith: width, - Locale: &locale, - Oid: oid, + Family: tree.StringFamily, + FamilyString: familyString, + DisplayWith: width, + Locale: &locale, + Oid: oid, CastCharsetSpecified: true, - CastCharsetName: charsetName, + CastCharsetName: charsetName, }} } func mergeIndexOption(left, right *tree.IndexOption) *tree.IndexOption { - if left == nil { - return right - } - if right == nil { - return left - } - if right.IType != tree.INDEX_TYPE_INVALID { - left.IType = right.IType - } else if len(right.Comment) > 0 { - left.Comment = right.Comment - } else if right.KeyBlockSize > 0 { - left.KeyBlockSize = right.KeyBlockSize - } else if len(right.ParserName) > 0 { - left.ParserName = right.ParserName - } else if right.Visible != tree.VISIBLE_TYPE_INVALID { - left.Visible = right.Visible - } else if right.AlgoParamList > 0 { - left.AlgoParamList = right.AlgoParamList - } else if len(right.AlgoParamVectorOpType) > 0 { - left.AlgoParamVectorOpType = right.AlgoParamVectorOpType - } else if right.AlgoParamM > 0 { - left.AlgoParamM = right.AlgoParamM - } else if right.HnswEfConstruction > 0 { - left.HnswEfConstruction = right.HnswEfConstruction - } else if right.HnswEfSearch > 0 { - left.HnswEfSearch = right.HnswEfSearch - } else if right.Async { - left.Async = right.Async - } else if right.ForceSync { - left.ForceSync = right.ForceSync - } else if right.Merge { - left.Merge = right.Merge - } else if right.AutoUpdate { - left.AutoUpdate = right.AutoUpdate - } else if right.Day > 0 { - left.Day = right.Day - } else if right.Hour > 0 { - left.Hour = right.Hour - } else if right.Second > 0 { - left.Second = right.Second - } else if right.IntermediateGraphDegree > 0 { - left.IntermediateGraphDegree = right.IntermediateGraphDegree - } else if right.GraphDegree > 0 { - left.GraphDegree = right.GraphDegree - } else if right.BitsPerCode > 0 { - left.BitsPerCode = right.BitsPerCode - } else if len(right.Quantization) > 0 { - left.Quantization = right.Quantization - } else if len(right.DistributionMode) > 0 { - left.DistributionMode = right.DistributionMode - } else if right.ITopkSize > 0 { - left.ITopkSize = right.ITopkSize - } else if right.KmeansTrainPercent > 0 { - left.KmeansTrainPercent = right.KmeansTrainPercent - } else if right.KmeansMaxIteration > 0 { - left.KmeansMaxIteration = right.KmeansMaxIteration - } else if right.MaxIndexCapacity > 0 { - left.MaxIndexCapacity = right.MaxIndexCapacity - } else if right.MaxPostingsCapacity > 0 { - left.MaxPostingsCapacity = right.MaxPostingsCapacity - } else if right.QuantizerTrainLimit > 0 { - left.QuantizerTrainLimit = right.QuantizerTrainLimit - } else if right.PositionFreeSet { - left.PositionFree = right.PositionFree - left.PositionFreeSet = true - } else if len(right.IncludeColumns) > 0 { - left.IncludeColumns = right.IncludeColumns - } - return left + if left == nil { + return right + } + if right == nil { + return left + } + if right.IType != tree.INDEX_TYPE_INVALID { + left.IType = right.IType + } else if len(right.Comment) > 0 { + left.Comment = right.Comment + } else if right.KeyBlockSize > 0 { + left.KeyBlockSize = right.KeyBlockSize + } else if len(right.ParserName) > 0 { + left.ParserName = right.ParserName + } else if right.Visible != tree.VISIBLE_TYPE_INVALID { + left.Visible = right.Visible + } else if right.AlgoParamList > 0 { + left.AlgoParamList = right.AlgoParamList + } else if len(right.AlgoParamVectorOpType) > 0 { + left.AlgoParamVectorOpType = right.AlgoParamVectorOpType + } else if right.AlgoParamM > 0 { + left.AlgoParamM = right.AlgoParamM + } else if right.HnswEfConstruction > 0 { + left.HnswEfConstruction = right.HnswEfConstruction + } else if right.HnswEfSearch > 0 { + left.HnswEfSearch = right.HnswEfSearch + } else if right.Async { + left.Async = right.Async + } else if right.ForceSync { + left.ForceSync = right.ForceSync + } else if right.Merge { + left.Merge = right.Merge + } else if right.AutoUpdate { + left.AutoUpdate = right.AutoUpdate + } else if right.Day > 0 { + left.Day = right.Day + } else if right.Hour > 0 { + left.Hour = right.Hour + } else if right.Second > 0 { + left.Second = right.Second + } else if right.IntermediateGraphDegree > 0 { + left.IntermediateGraphDegree = right.IntermediateGraphDegree + } else if right.GraphDegree > 0 { + left.GraphDegree = right.GraphDegree + } else if right.BitsPerCode > 0 { + left.BitsPerCode = right.BitsPerCode + } else if len(right.Quantization) > 0 { + left.Quantization = right.Quantization + } else if len(right.DistributionMode) > 0 { + left.DistributionMode = right.DistributionMode + } else if right.ITopkSize > 0 { + left.ITopkSize = right.ITopkSize + } else if right.KmeansTrainPercent > 0 { + left.KmeansTrainPercent = right.KmeansTrainPercent + } else if right.KmeansMaxIteration > 0 { + left.KmeansMaxIteration = right.KmeansMaxIteration + } else if right.MaxIndexCapacity > 0 { + left.MaxIndexCapacity = right.MaxIndexCapacity + } else if right.MaxPostingsCapacity > 0 { + left.MaxPostingsCapacity = right.MaxPostingsCapacity + } else if right.QuantizerTrainLimit > 0 { + left.QuantizerTrainLimit = right.QuantizerTrainLimit + } else if right.PositionFreeSet { + left.PositionFree = right.PositionFree + left.PositionFreeSet = true + } else if len(right.IncludeColumns) > 0 { + left.IncludeColumns = right.IncludeColumns + } + return left } func makeWindowSpec(refName *tree.CStr, partitionBy tree.Exprs, orderBy tree.OrderBy, frame *tree.FrameClause) *tree.WindowSpec { - hasFrame := frame != nil - if frame == nil { - frame = &tree.FrameClause{Type: tree.Range} - frame.Start = &tree.FrameBound{Type: tree.Preceding, UnBounded: true} - if orderBy == nil { - frame.End = &tree.FrameBound{Type: tree.Following, UnBounded: true} - } else { - frame.End = &tree.FrameBound{Type: tree.CurrentRow} - } - } - return &tree.WindowSpec{ - RefName: refName, - PartitionBy: partitionBy, - OrderBy: orderBy, - Frame: frame, - HasFrame: hasFrame, - } + hasFrame := frame != nil + if frame == nil { + frame = &tree.FrameClause{Type: tree.Range} + frame.Start = &tree.FrameBound{Type: tree.Preceding, UnBounded: true} + if orderBy == nil { + frame.End = &tree.FrameBound{Type: tree.Following, UnBounded: true} + } else { + frame.End = &tree.FrameBound{Type: tree.CurrentRow} + } + } + return &tree.WindowSpec{ + RefName: refName, + PartitionBy: partitionBy, + OrderBy: orderBy, + Frame: frame, + HasFrame: hasFrame, + } } + const LEX_ERROR = 57346 const JSON_TABLE = 57347 const JSON_TABLE_PATH = 57348 @@ -1635,4 +1638,34837 @@ var yyToknames = [...]string{ "ROW_NUMBER", "DENSE_RANK", "CUME_DIST", - "BIT_CAST \ No newline at end of file + "BIT_CAST", + "LAG", + "LEAD", + "FIRST_VALUE", + "LAST_VALUE", + "NTH_VALUE", + "NTILE", + "PERCENT_RANK", + "BITMAP_BIT_POSITION", + "BITMAP_BUCKET_NUMBER", + "BITMAP_COUNT", + "BITMAP_CONSTRUCT_AGG", + "BITMAP_OR_AGG", + "JSON_ARRAYAGG", + "JSON_OBJECTAGG", + "GET_FORMAT", + "SRID", + "NEXTVAL", + "SETVAL", + "CURRVAL", + "LASTVAL", + "ROW", + "OUTFILE", + "HEADER", + "MAX_FILE_SIZE", + "FORCE_QUOTE", + "PARALLEL", + "STRICT", + "SPLITSIZE", + "UNUSED", + "BINDINGS", + "GENERATED", + "ALWAYS", + "STORED", + "VIRTUAL", + "DO", + "PERFORM", + "DECLARE", + "LOOP", + "WHILE", + "LEAVE", + "ITERATE", + "UNTIL", + "CALL", + "PREV", + "SLIDING", + "FILL", + "GAPFILL", + "SPBEGIN", + "BACKEND", + "SERVERS", + "HANDLER", + "PERCENT", + "SAMPLE", + "MO_TS", + "PITR", + "RECOVERY_WINDOW", + "INTERNAL", + "CDC_TASK_NAME", + "CDC", + "ICEBERG", + "CATALOG", + "CATALOGS", + "NAMESPACE", + "NAMESPACES", + "REF", + "FOR_ICEBERG", + "MONGODB", + "MONGODB_PATH", + "MONGODB_CONVERT", + "CONNECTIONS", + "DATASTREAM", + "ESQL", + "KAFKA", + "GROUPING", + "SETS", + "CUBE", + "ROLLUP", + "LOGSERVICE", + "REPLICAS", + "STORES", + "SETTINGS", + "DUMP", + "METADATA", + "KILL", + "BACKUP", + "FILESYSTEM", + "PARALLELISM", + "RESTORE", + "QUERY_RESULT", + "RETURNING", + "ARRAY", + "WITHIN", + "PERCENTILE_CONT", + "PERCENTILE_DISC", + "ASOF", + "TOLERANCE", + "WINDOW", + "WINDOW_NAME_EMPTY", + "RESPECT", + "MEMBER", + "AUTO_ID_CACHE", + "';'", + "'{'", + "'}'", + "':'", + "'@'", +} + +var yyStatenames = [...]string{} + +const yyEofCode = 1 +const yyErrCode = 2 +const yyInitialStackSize = 16 + +//line mysql_sql.y:17042 + +//line yacctab:1 +var yyExca = [...]int{ + -1, 1, + 1, -1, + -2, 0, + -1, 153, + 52, 765, + 286, 765, + 313, 772, + 314, 772, + 558, 765, + -2, 805, + -1, 173, + 17, 1016, + 30, 1016, + -2, 1002, + -1, 199, + 284, 1624, + 286, 1444, + -2, 1527, + -1, 276, + 793, 2618, + -2, 638, + -1, 670, + 793, 2747, + -2, 465, + -1, 730, + 793, 2808, + -2, 463, + -1, 731, + 793, 2809, + -2, 464, + -1, 732, + 793, 2810, + -2, 466, + -1, 886, + 553, 805, + 554, 805, + -2, 766, + -1, 958, + 365, 217, + 530, 217, + 531, 217, + -2, 2459, + -1, 1028, + 96, 2187, + -2, 2681, + -1, 1029, + 96, 2208, + -2, 2649, + -1, 1033, + 96, 2209, + -2, 2680, + -1, 1081, + 96, 2108, + -2, 2902, + -1, 1082, + 96, 2109, + -2, 2901, + -1, 1083, + 96, 2110, + -2, 2891, + -1, 1084, + 96, 2862, + -2, 2882, + -1, 1085, + 96, 2863, + -2, 2883, + -1, 1086, + 96, 2864, + -2, 2893, + -1, 1087, + 96, 2865, + -2, 2871, + -1, 1088, + 96, 2866, + -2, 2880, + -1, 1089, + 96, 2867, + -2, 2895, + -1, 1090, + 96, 2868, + -2, 2900, + -1, 1091, + 96, 2869, + -2, 2905, + -1, 1092, + 96, 2870, + -2, 2906, + -1, 1093, + 96, 2183, + -2, 2720, + -1, 1094, + 96, 2184, + -2, 2442, + -1, 1095, + 96, 2185, + -2, 2730, + -1, 1096, + 96, 2186, + -2, 2453, + -1, 1098, + 96, 2189, + -2, 2461, + -1, 1100, + 96, 2191, + -2, 2755, + -1, 1102, + 96, 2193, + -2, 2485, + -1, 1103, + 96, 2194, + -2, 2411, + -1, 1105, + 96, 2196, + -2, 2767, + -1, 1106, + 96, 2197, + -2, 2766, + -1, 1107, + 96, 2198, + -2, 2572, + -1, 1108, + 96, 2199, + -2, 2676, + -1, 1109, + 96, 2200, + -2, 2592, + -1, 1112, + 96, 2203, + -2, 2778, + -1, 1113, + 96, 2204, + -2, 2617, + -1, 1115, + 96, 2206, + -2, 2781, + -1, 1116, + 96, 2207, + -2, 2783, + -1, 1117, + 96, 2210, + -2, 2790, + -1, 1118, + 96, 2211, + -2, 2658, + -1, 1119, + 96, 2212, + -2, 2707, + -1, 1120, + 96, 2213, + -2, 2670, + -1, 1121, + 96, 2214, + -2, 2696, + -1, 1132, + 96, 2084, + -2, 2896, + -1, 1133, + 96, 2085, + -2, 2897, + -1, 1134, + 96, 2086, + -2, 2898, + -1, 1263, + 138, 2442, + 149, 2442, + 182, 2442, + -2, 2402, + -1, 1412, + 30, 1051, + -2, 978, + -1, 1617, + 17, 1016, + 30, 1016, + -2, 1923, + -1, 1719, + 30, 1051, + -2, 978, + -1, 2056, + 52, 765, + 286, 765, + 313, 772, + 314, 772, + 558, 765, + -2, 805, + -1, 2166, + 96, 2272, + -2, 2678, + -1, 2167, + 96, 2273, + -2, 2679, + -1, 2476, + 17, 1016, + 30, 1016, + -2, 1197, + -1, 2967, + 97, 1291, + -2, 1297, + -1, 2985, + 121, 1522, + 169, 1522, + 217, 1522, + 220, 1522, + 326, 1522, + -2, 1515, + -1, 2988, + 44, 1558, + -2, 1506, + -1, 3501, + 97, 2388, + 183, 2388, + -2, 2660, + -1, 3502, + 97, 2388, + 183, 2388, + -2, 2659, + -1, 3504, + 97, 2384, + 183, 2384, + -2, 2646, + -1, 3505, + 97, 2340, + 183, 2340, + -2, 2651, + -1, 3506, + 97, 2341, + 183, 2341, + -2, 2558, + -1, 3507, + 97, 2342, + 183, 2342, + -2, 2551, + -1, 3508, + 97, 2384, + 183, 2384, + -2, 2426, + -1, 3509, + 97, 2344, + 183, 2344, + -2, 2648, + -1, 3510, + 97, 2345, + 183, 2345, + -2, 2556, + -1, 3511, + 97, 2346, + 183, 2346, + -2, 2550, + -1, 3512, + 97, 2347, + 183, 2347, + -2, 2526, + -1, 3513, + 97, 2388, + 183, 2388, + -2, 2527, + -1, 3514, + 97, 2388, + 183, 2388, + -2, 2528, + -1, 3515, + 97, 2388, + 183, 2388, + -2, 2529, + -1, 3516, + 97, 2388, + 183, 2388, + -2, 2530, + -1, 3517, + 97, 2388, + 183, 2388, + -2, 2531, + -1, 3518, + 97, 2388, + 183, 2388, + -2, 2532, + -1, 3520, + 97, 2356, + 183, 2356, + -2, 2696, + -1, 3521, + 97, 2327, + 183, 2327, + -2, 2681, + -1, 3522, + 97, 2386, + 183, 2386, + -2, 2649, + -1, 3523, + 97, 2386, + 183, 2386, + -2, 2680, + -1, 3524, + 97, 2386, + 183, 2386, + -2, 2462, + -1, 3525, + 97, 2384, + 183, 2384, + -2, 2670, + -1, 3526, + 96, 2307, + 97, 2307, + 172, 2307, + 173, 2307, + 175, 2307, + 183, 2307, + -2, 2425, + -1, 3527, + 96, 2308, + 97, 2308, + 172, 2308, + 173, 2308, + 175, 2308, + 183, 2308, + -2, 2427, + -1, 3528, + 96, 2309, + 97, 2309, + 172, 2309, + 173, 2309, + 175, 2309, + 183, 2309, + -2, 2726, + -1, 3529, + 96, 2311, + 97, 2311, + 172, 2311, + 173, 2311, + 175, 2311, + 183, 2311, + -2, 2650, + -1, 3530, + 96, 2313, + 97, 2313, + 172, 2313, + 173, 2313, + 175, 2313, + 183, 2313, + -2, 2628, + -1, 3531, + 96, 2315, + 97, 2315, + 172, 2315, + 173, 2315, + 175, 2315, + 183, 2315, + -2, 2557, + -1, 3532, + 96, 2317, + 97, 2317, + 172, 2317, + 173, 2317, + 175, 2317, + 183, 2317, + -2, 2512, + -1, 3533, + 96, 2318, + 97, 2318, + 172, 2318, + 173, 2318, + 175, 2318, + 183, 2318, + -2, 2513, + -1, 3534, + 96, 2320, + 97, 2320, + 172, 2320, + 173, 2320, + 175, 2320, + 183, 2320, + -2, 2424, + -1, 3535, + 97, 2391, + 172, 2391, + 173, 2391, + 175, 2391, + 183, 2391, + -2, 2469, + -1, 3536, + 97, 2391, + 172, 2391, + 173, 2391, + 175, 2391, + 183, 2391, + -2, 2486, + -1, 3537, + 97, 2394, + 172, 2394, + 173, 2394, + 175, 2394, + 183, 2394, + -2, 2463, + -1, 3538, + 97, 2394, + 172, 2394, + 173, 2394, + 175, 2394, + 183, 2394, + -2, 2577, + -1, 3539, + 97, 2391, + 172, 2391, + 173, 2391, + 175, 2391, + 183, 2391, + -2, 2608, + -1, 3540, + 97, 2364, + 183, 2364, + -2, 2490, + -1, 3541, + 97, 2365, + 183, 2365, + -2, 2592, + -1, 3542, + 97, 2366, + 183, 2366, + -2, 2547, + -1, 3543, + 97, 2367, + 183, 2367, + -2, 2593, + -1, 3544, + 97, 2368, + 183, 2368, + -2, 2491, + -1, 3545, + 97, 2369, + 183, 2369, + -2, 2564, + -1, 3546, + 97, 2370, + 183, 2370, + -2, 2563, + -1, 3547, + 97, 2371, + 183, 2371, + -2, 2565, + -1, 3548, + 97, 2372, + 183, 2372, + -2, 2493, + -1, 3549, + 97, 2373, + 183, 2373, + -2, 2492, + -1, 3550, + 97, 2374, + 183, 2374, + -2, 2494, + -1, 3551, + 97, 2375, + 183, 2375, + -2, 2495, + -1, 3552, + 97, 2376, + 183, 2376, + -2, 2496, + -1, 3553, + 97, 2377, + 183, 2377, + -2, 2497, + -1, 3554, + 97, 2378, + 183, 2378, + -2, 2498, + -1, 3555, + 97, 2379, + 183, 2379, + -2, 2499, + -1, 3556, + 97, 2380, + 183, 2380, + -2, 2500, + -1, 3557, + 97, 2381, + 183, 2381, + -2, 2501, + -1, 3593, + 121, 1522, + 169, 1522, + 217, 1522, + 220, 1522, + 326, 1522, + -2, 1516, + -1, 3609, + 44, 1559, + -2, 1561, + -1, 3610, + 44, 1560, + -2, 1562, + -1, 3643, + 93, 871, + 183, 871, + -2, 1784, + -1, 4169, + 220, 1522, + 350, 1885, + -2, 1849, + -1, 4225, + 17, 1016, + 30, 1016, + -2, 1923, + -1, 4417, + 44, 1558, + 121, 1522, + 169, 1522, + 217, 1522, + 220, 1522, + -2, 1715, + -1, 4426, + 121, 1522, + 169, 1522, + 217, 1522, + 220, 1522, + -2, 1715, + -1, 4444, + 93, 871, + 183, 871, + -2, 1784, + -1, 4477, + 220, 1522, + 350, 1885, + -2, 1850, + -1, 4688, + 121, 1522, + 169, 1522, + 217, 1522, + 220, 1522, + -2, 1716, + -1, 4732, + 97, 1642, + 183, 1642, + -2, 1522, + -1, 4953, + 102, 1206, + -2, 2409, + -1, 4959, + 97, 1642, + 183, 1642, + -2, 1522, + -1, 5244, + 97, 1646, + 183, 1646, + -2, 1522, + -1, 5316, + 97, 1647, + 183, 1647, + -2, 1522, +} + +const yyPrivate = 57344 + +const yyLast = 89784 + +var yyAct = [...]int{ + 994, 5373, 5430, 5400, 5437, 969, 5358, 5392, 5365, 996, + 264, 5341, 1996, 5362, 4950, 5357, 5415, 3694, 5382, 5254, + 5248, 4961, 3827, 1995, 2145, 4518, 979, 5192, 4528, 3974, + 5258, 5247, 5259, 4199, 4959, 4180, 4026, 5116, 4582, 5023, + 4845, 1882, 3210, 4272, 4767, 3698, 5181, 4494, 4951, 3480, + 3264, 3709, 4794, 2983, 4892, 4028, 785, 5040, 4577, 4273, + 1656, 2204, 4958, 4944, 5082, 4677, 3600, 1501, 4962, 5193, + 4270, 1899, 2220, 3712, 807, 5195, 1025, 4721, 4922, 1262, + 4406, 4400, 4392, 4590, 1936, 3864, 824, 834, 1508, 844, + 251, 5, 844, 4690, 3420, 4478, 4167, 3395, 4706, 3476, + 4162, 1472, 4684, 3078, 4449, 2207, 4352, 1269, 3478, 3646, + 4097, 4078, 3612, 971, 2148, 4660, 4096, 2447, 1271, 3002, + 3828, 3388, 3601, 3257, 1898, 3602, 4253, 2603, 840, 44, + 3826, 3793, 4082, 2477, 3725, 4390, 1900, 1455, 44, 4164, + 4195, 4174, 4427, 3683, 3677, 3303, 3823, 2470, 3496, 3488, + 4222, 1418, 838, 16, 921, 3681, 912, 3675, 2652, 3447, + 4342, 3579, 16, 2203, 916, 1875, 2774, 4047, 961, 4060, + 2226, 830, 4058, 3205, 4173, 4099, 4098, 4109, 3092, 2006, + 2341, 962, 1804, 3008, 3023, 1179, 1884, 3011, 1912, 2098, + 3003, 3814, 1984, 1277, 77, 3594, 2927, 1988, 238, 1964, + 249, 824, 1223, 77, 4094, 4006, 2817, 2926, 3302, 3237, + 2600, 3494, 966, 2657, 3216, 1969, 2596, 2617, 3180, 3567, + 2471, 3561, 2770, 2769, 3082, 3700, 2491, 3615, 2479, 171, + 1721, 1979, 3057, 896, 3079, 785, 3650, 2478, 3727, 2001, + 3022, 4, 839, 32, 1802, 3649, 3000, 1256, 824, 3006, + 2985, 1335, 32, 2410, 1816, 2221, 260, 7, 2140, 2771, + 2744, 259, 6, 970, 264, 2009, 264, 2813, 1325, 1326, + 3010, 1891, 1860, 3013, 1854, 1821, 824, 1937, 1846, 2975, + 841, 2453, 960, 2929, 2214, 2978, 806, 2182, 1453, 1653, + 2097, 962, 2437, 1253, 980, 1436, 2131, 835, 17, 1490, + 2674, 2019, 1944, 784, 909, 2401, 2405, 17, 2139, 1856, + 1143, 1255, 1458, 26, 1859, 2409, 1144, 1844, 1222, 2227, + 245, 1140, 1142, 1511, 1278, 1809, 1747, 5342, 1486, 918, + 1805, 825, 2431, 86, 250, 919, 1145, 843, 3181, 5, + 244, 1220, 1304, 1803, 237, 1202, 915, 1215, 54, 1657, + 78, 837, 15, 154, 42, 881, 29, 87, 27, 1139, + 5067, 15, 81, 1137, 28, 80, 76, 1580, 2369, 1581, + 1579, 19, 2749, 4918, 3444, 3444, 10, 44, 1322, 3444, + 1512, 2483, 4447, 4286, 4017, 4134, 836, 38, 4016, 3879, + 3878, 2786, 44, 1419, 44, 1580, 38, 1581, 1579, 1748, + 4640, 16, 4409, 2458, 2462, 2463, 2464, 2459, 2469, 2460, + 2466, 1420, 4265, 2461, 2144, 2467, 16, 1580, 16, 1581, + 1579, 3336, 816, 3240, 1749, 2358, 3243, 3241, 814, 848, + 1318, 810, 3238, 1947, 1317, 248, 3182, 3421, 1275, 4837, + 811, 1951, 77, 812, 813, 4143, 2458, 2462, 2463, 2464, + 2459, 2469, 2460, 2466, 3389, 2890, 2461, 77, 2467, 77, + 3648, 4450, 3001, 3265, 1321, 809, 1323, 1419, 3256, 1273, + 2925, 1742, 1858, 1137, 2458, 2462, 2463, 2464, 2459, 2469, + 2460, 2466, 5170, 1318, 2461, 1699, 2467, 1468, 1469, 1470, + 1316, 32, 2458, 2462, 2463, 2464, 2459, 2469, 2460, 2466, + 1467, 1318, 2461, 2010, 2467, 7, 32, 2450, 32, 1476, + 6, 2699, 3394, 2737, 1136, 2738, 967, 4291, 5094, 2458, + 2462, 2463, 2464, 2459, 2469, 2460, 2466, 2733, 1358, 2461, + 1916, 2467, 2700, 1832, 1776, 1166, 1163, 4425, 3211, 4624, + 4018, 2931, 4014, 2941, 2365, 1751, 17, 3992, 3989, 5353, + 1528, 9, 1466, 2352, 1268, 3990, 3987, 2921, 1730, 4575, + 1266, 17, 1949, 17, 3859, 3857, 3999, 3997, 1580, 2662, + 1581, 1579, 5256, 5255, 1267, 1270, 1580, 4759, 1581, 1579, + 2539, 4279, 5035, 4853, 4846, 4578, 4271, 5198, 201, 246, + 1080, 3005, 1141, 1651, 2349, 3952, 4045, 2681, 2726, 3156, + 15, 3121, 5397, 5050, 2015, 5349, 4864, 2071, 5047, 4904, + 4861, 4001, 4381, 3369, 4629, 15, 2948, 15, 2541, 5128, + 2591, 1913, 950, 1757, 1136, 952, 1755, 1754, 4627, 1459, + 951, 4376, 4048, 1167, 2965, 38, 1164, 2552, 1280, 3608, + 914, 3947, 1798, 2784, 3821, 2979, 3201, 2378, 1154, 1576, + 38, 1127, 38, 1126, 1128, 1129, 4906, 1130, 1131, 1524, + 2205, 2206, 1525, 2376, 239, 1376, 1377, 1338, 3863, 3188, + 3832, 2089, 3187, 2579, 2516, 3189, 3833, 3834, 950, 3202, + 1161, 952, 2580, 2581, 2383, 2384, 951, 1772, 1366, 1370, + 1372, 1374, 1379, 3162, 1384, 1380, 1381, 1382, 1383, 2613, + 3475, 1361, 1362, 1363, 1364, 1336, 1337, 1367, 3471, 1339, + 3161, 1340, 1342, 1343, 1344, 1345, 1341, 1346, 1347, 1348, + 1349, 1350, 1357, 1359, 1351, 1352, 1353, 1354, 1355, 1356, + 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1394, 1393, + 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1369, 1371, + 1373, 1375, 1378, 2013, 1464, 2532, 1465, 3991, 3988, 950, + 1155, 1764, 952, 1527, 5314, 1167, 1164, 951, 1607, 1861, + 1613, 1863, 1463, 4459, 2012, 3473, 1498, 3315, 3314, 1509, + 1510, 4025, 3258, 3468, 905, 2147, 1610, 1612, 1606, 1360, + 1611, 1593, 1592, 1602, 1603, 1604, 1605, 1595, 1596, 1597, + 1598, 1599, 1600, 1601, 1594, 2068, 1507, 1608, 1569, 824, + 1506, 1509, 1510, 1839, 2113, 3563, 1574, 2567, 3044, 824, + 2463, 2464, 2262, 2837, 824, 3564, 1422, 2087, 4184, 1950, + 1948, 4182, 1265, 201, 246, 4872, 1264, 2897, 3606, 201, + 246, 200, 233, 202, 5202, 1328, 844, 844, 1450, 4002, + 824, 824, 247, 5201, 2520, 5200, 3472, 3609, 5202, 5298, + 5199, 5262, 5263, 5292, 3469, 2526, 201, 246, 200, 233, + 202, 1421, 5201, 5297, 5038, 3562, 2465, 201, 246, 200, + 233, 202, 5200, 5296, 3608, 2514, 2548, 1165, 1162, 2515, + 2517, 2519, 3865, 2521, 2522, 2523, 2527, 2528, 2529, 2531, + 2534, 2535, 2536, 5199, 5295, 5214, 1428, 5183, 4703, 3599, + 2524, 2533, 2525, 5344, 5345, 239, 3866, 5186, 3867, 2465, + 5041, 5042, 5043, 5044, 4274, 1413, 4274, 1556, 5183, 4849, + 1557, 2368, 3287, 833, 4863, 2151, 1412, 1917, 1833, 1158, + 1777, 2597, 832, 1423, 3870, 2788, 2151, 2465, 1505, 2785, + 1502, 2379, 1502, 239, 1414, 5078, 2066, 4398, 1559, 3603, + 824, 4295, 1475, 1526, 2540, 2465, 3747, 2377, 4631, 5066, + 1484, 2587, 4391, 1842, 3175, 2088, 2127, 1494, 2780, 1626, + 1741, 3815, 4917, 4298, 3909, 1619, 1514, 1515, 3443, 1517, + 1518, 1420, 2465, 1520, 1420, 3164, 2973, 821, 3570, 4074, + 1426, 1430, 1420, 1433, 3474, 2611, 2612, 4908, 4909, 4000, + 1496, 3905, 3470, 5478, 1159, 4669, 5431, 5432, 1607, 5471, + 1613, 4871, 841, 841, 3485, 841, 4507, 1422, 5402, 4873, + 3328, 1275, 1572, 1573, 2537, 3880, 1610, 1612, 1606, 5216, + 1611, 1593, 1592, 1602, 1603, 1604, 1605, 1595, 1596, 1597, + 1598, 1599, 1600, 1601, 1594, 4072, 2512, 1608, 230, 5399, + 2511, 4628, 1273, 3877, 5261, 3903, 2748, 1318, 1567, 1568, + 3437, 2701, 1661, 1571, 3119, 1544, 1420, 4576, 1536, 3858, + 2787, 1318, 1318, 1554, 2530, 2822, 1318, 3806, 1318, 1318, + 4019, 2932, 2550, 2518, 2590, 1160, 3155, 247, 3158, 2247, + 2150, 2149, 3609, 247, 3167, 3168, 4914, 4719, 2468, 3157, + 3166, 2150, 2149, 4069, 4070, 4666, 2066, 4146, 2132, 1439, + 1442, 2136, 1783, 1368, 4625, 828, 829, 4080, 4079, 4071, + 247, 3446, 3178, 1268, 1749, 1566, 1432, 805, 4537, 1411, + 1660, 247, 4992, 2062, 1519, 2135, 1781, 1444, 3265, 1555, + 4393, 2468, 5027, 1267, 2796, 2798, 2799, 4186, 1744, 1746, + 4862, 1750, 4533, 3610, 1932, 1749, 1415, 3239, 1522, 1523, + 4907, 1275, 1756, 1492, 1493, 1952, 4068, 1768, 1753, 2468, + 5070, 1771, 4895, 1448, 1449, 3605, 816, 4694, 1780, 4641, + 1443, 4415, 814, 4197, 4198, 810, 4259, 2468, 4425, 4196, + 2687, 4110, 1273, 4093, 811, 5089, 1141, 812, 813, 5090, + 5093, 5092, 953, 954, 955, 956, 957, 824, 824, 824, + 1460, 3566, 1223, 4955, 2468, 2551, 3998, 1529, 1530, 5401, + 1831, 1558, 4630, 5112, 4934, 824, 5096, 1838, 3616, 1513, + 1845, 4356, 1516, 1157, 824, 4358, 1533, 1716, 785, 785, + 1720, 1168, 1487, 1491, 1491, 1491, 4513, 846, 785, 785, + 1535, 1719, 1886, 1886, 845, 824, 5402, 1333, 953, 954, + 955, 956, 957, 2987, 2137, 3819, 1627, 1759, 2981, 1487, + 1487, 1723, 1497, 5056, 4080, 1509, 1510, 4007, 1509, 1510, + 5083, 2465, 5058, 4519, 5059, 844, 5141, 807, 2134, 1782, + 5117, 4181, 2014, 1940, 1888, 3710, 3711, 4066, 3714, 3714, + 5052, 4526, 968, 2792, 2794, 2795, 1485, 1761, 1763, 264, + 3085, 3088, 2960, 2067, 4901, 4649, 2243, 4367, 785, 4633, + 4634, 4635, 4038, 2240, 4370, 3154, 4539, 2242, 2239, 2241, + 2245, 2246, 1425, 1427, 4538, 2244, 5077, 4755, 842, 953, + 954, 955, 956, 957, 5425, 2598, 3611, 2513, 4744, 2066, + 3132, 4453, 4593, 1441, 1440, 3174, 2157, 2161, 2162, 2720, + 2721, 3816, 1478, 4080, 1893, 842, 1561, 2158, 3131, 1562, + 1429, 1431, 1446, 1909, 1910, 3576, 842, 1672, 1673, 3569, + 4075, 5060, 1840, 201, 246, 200, 233, 202, 2063, 4910, + 5215, 2082, 4369, 3906, 1992, 4201, 1871, 1564, 3610, 1997, + 1870, 1143, 4750, 4956, 79, 5385, 2159, 3152, 3153, 1534, + 2011, 1483, 2133, 1482, 4935, 1880, 1881, 1481, 1609, 1843, + 2780, 3748, 5118, 3749, 3750, 4187, 4188, 4923, 4189, 4191, + 4190, 79, 1500, 1499, 4202, 2588, 2037, 44, 3573, 3574, + 2128, 2797, 79, 1268, 4964, 4163, 5246, 2040, 1820, 1714, + 1434, 2069, 4321, 3572, 3085, 4670, 1726, 5401, 4192, 239, + 1727, 16, 2007, 1267, 3439, 1752, 3122, 1810, 4428, 3077, + 3102, 1886, 1715, 4573, 3089, 2004, 1724, 1845, 1787, 3084, + 3077, 3083, 834, 3080, 3086, 1865, 1867, 2250, 2251, 2252, + 2253, 2254, 2255, 2248, 2249, 1878, 1879, 1773, 914, 3094, + 4197, 4198, 77, 2112, 5180, 3077, 3096, 1857, 4436, 2000, + 1845, 3217, 3218, 4353, 1541, 2121, 2121, 1758, 1845, 2070, + 1845, 1845, 1560, 1502, 1614, 1785, 1962, 1792, 1965, 1966, + 4226, 1886, 4206, 1886, 1422, 3324, 3059, 3061, 3087, 2002, + 1959, 1971, 1972, 1973, 1974, 1975, 1976, 1211, 1808, 1212, + 3193, 32, 1970, 1815, 1811, 1812, 2074, 2077, 2078, 2081, + 4067, 5386, 1565, 3095, 1987, 1953, 2054, 1991, 1616, 1615, + 1983, 1990, 3160, 1929, 2095, 2096, 1869, 3613, 1896, 2146, + 3094, 1903, 1897, 3117, 1981, 1982, 3077, 3096, 1563, 2023, + 2045, 2105, 2106, 2027, 2028, 2116, 2930, 2777, 1894, 2586, + 2793, 1902, 1270, 1911, 2574, 4963, 17, 1886, 1998, 1770, + 2986, 841, 816, 2118, 3457, 841, 841, 4551, 4200, 1540, + 1760, 1762, 1927, 3084, 3081, 1422, 2224, 4242, 3086, 4228, + 3091, 841, 2961, 4746, 3800, 2005, 1941, 4745, 3088, 3908, + 1923, 1619, 2275, 1942, 3095, 1796, 3777, 247, 1795, 2265, + 2266, 2267, 1794, 2160, 2256, 2257, 5245, 2093, 2261, 808, + 15, 1243, 2281, 850, 849, 2282, 2276, 4384, 1609, 5053, + 2222, 4751, 4752, 5054, 2293, 2295, 2294, 4758, 4193, 2283, + 2049, 2285, 3087, 2286, 2287, 2288, 2303, 2304, 201, 246, + 200, 233, 202, 1224, 2360, 38, 2566, 2556, 2554, 2117, + 2708, 2814, 2555, 1197, 819, 2060, 820, 2124, 2789, 2790, + 5383, 5384, 1967, 4301, 3101, 1968, 2336, 2093, 3099, 2093, + 1226, 1227, 1228, 201, 246, 200, 233, 202, 1196, 2035, + 1422, 4299, 2025, 3745, 4343, 2046, 4285, 3285, 2029, 3060, + 1819, 3465, 2370, 1773, 1143, 2952, 2373, 2565, 2954, 2953, + 1767, 824, 824, 824, 2386, 2143, 1765, 1766, 2387, 1180, + 2388, 2390, 2292, 2391, 239, 2394, 2395, 5196, 1784, 2398, + 1986, 2055, 807, 2402, 4437, 2354, 5058, 2406, 5059, 1886, + 2412, 2413, 2347, 2415, 1845, 2104, 2053, 2163, 824, 2044, + 2024, 1886, 2051, 2208, 2052, 2043, 2048, 824, 2110, 239, + 2094, 3089, 2042, 2259, 2099, 1223, 2101, 2102, 2448, 2047, + 2125, 2126, 2337, 2100, 2041, 4360, 2473, 2473, 1831, 2473, + 1173, 2109, 4013, 2484, 2485, 824, 824, 1275, 2549, 1848, + 2951, 2339, 2406, 2560, 2366, 1210, 2342, 2385, 1169, 2036, + 906, 1886, 2571, 2572, 3144, 4453, 2346, 1831, 4284, 785, + 1170, 2361, 1487, 2120, 2122, 2033, 2034, 3884, 1273, 2138, + 1774, 1775, 4707, 785, 1778, 1886, 1491, 2142, 1786, 1788, + 1789, 1790, 1791, 3458, 1793, 5060, 4665, 5427, 1797, 1491, + 201, 246, 2715, 4249, 1177, 2090, 1985, 906, 4089, 1175, + 1174, 2184, 842, 1477, 906, 2501, 3583, 3589, 3590, 3591, + 3584, 3588, 3585, 3587, 3586, 2629, 2631, 246, 1806, 824, + 2406, 1886, 5190, 2638, 4194, 824, 912, 912, 5168, 2402, + 2503, 2429, 2645, 5485, 2647, 2648, 2649, 1244, 2439, 2651, + 2653, 3778, 3780, 3781, 3782, 3779, 908, 264, 5474, 907, + 264, 264, 3116, 264, 2350, 2141, 2414, 1290, 1849, 2345, + 1272, 2348, 247, 2362, 201, 246, 239, 1279, 79, 3491, + 1239, 2021, 4453, 2558, 2475, 2093, 2481, 201, 246, 2274, + 2020, 1578, 2083, 2416, 2441, 2430, 3623, 2093, 2977, 2021, + 2576, 1176, 239, 908, 2289, 2290, 907, 247, 2020, 5026, + 908, 2066, 4244, 907, 2103, 3492, 3493, 201, 246, 1847, + 5484, 201, 246, 2689, 2021, 2438, 1171, 2707, 2614, 1578, + 2671, 2111, 2776, 2020, 2114, 2115, 1275, 2696, 3608, 3768, + 3769, 2583, 1268, 2585, 2619, 2620, 2592, 2093, 2338, 2340, + 2440, 4248, 1477, 2712, 2604, 2605, 201, 246, 200, 233, + 202, 785, 1267, 239, 1541, 4090, 2634, 1273, 2693, 5466, + 3052, 2093, 2640, 824, 2914, 2448, 2018, 824, 2400, 4418, + 2359, 5464, 2363, 4339, 2730, 44, 2732, 2367, 44, 44, + 2736, 44, 4133, 2695, 2003, 2575, 2637, 239, 2741, 2742, + 2743, 2606, 2607, 2747, 2615, 1845, 1578, 2599, 4297, 16, + 1173, 5452, 16, 16, 2858, 16, 2577, 2093, 2857, 2168, + 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, + 2179, 2976, 239, 2563, 1845, 2685, 1717, 5446, 2449, 2200, + 2201, 1886, 2773, 2445, 2432, 2694, 896, 2443, 2444, 2432, + 77, 2436, 1477, 77, 77, 1578, 77, 2661, 2557, 2562, + 2664, 2665, 5448, 2667, 247, 2225, 2776, 1578, 5017, 1848, + 2260, 2561, 1578, 2702, 1172, 2021, 2569, 201, 246, 1175, + 1174, 3767, 3645, 5053, 2020, 1272, 2650, 5194, 2678, 2582, + 247, 2584, 2724, 2284, 2593, 1541, 2776, 5107, 2021, 32, + 2709, 2710, 32, 32, 1578, 32, 3052, 2020, 2801, 4249, + 1178, 3323, 2716, 2411, 1473, 3183, 3644, 842, 1474, 5444, + 2130, 2759, 841, 841, 2123, 2425, 201, 246, 4281, 2651, + 1148, 1149, 1150, 1151, 841, 5412, 2635, 2628, 247, 2636, + 2641, 2642, 2624, 2686, 2643, 2690, 2623, 2740, 5445, 1146, + 3300, 247, 842, 239, 17, 2691, 2658, 17, 17, 841, + 17, 2129, 2622, 4768, 4769, 4770, 4774, 4772, 4773, 4775, + 4776, 4777, 4778, 4771, 3982, 2570, 2762, 4120, 246, 201, + 246, 247, 2764, 79, 2766, 247, 1538, 4209, 1849, 2676, + 4207, 201, 246, 4155, 5409, 5406, 1621, 1622, 1623, 1624, + 1625, 1580, 239, 1581, 1579, 5445, 3979, 5404, 15, 4249, + 5394, 15, 15, 4152, 15, 1908, 5379, 5333, 79, 2868, + 247, 5413, 2871, 2767, 2873, 5318, 5278, 2093, 1905, 3323, + 1279, 2880, 2831, 1580, 2711, 1581, 1579, 2717, 2714, 1847, + 4831, 2905, 1279, 38, 2893, 2141, 38, 38, 2713, 38, + 4054, 1578, 1539, 239, 2719, 239, 4051, 4005, 3052, 2775, + 3983, 2723, 3629, 1580, 5277, 1581, 1579, 239, 1580, 5276, + 1581, 1579, 2933, 2934, 3645, 2936, 2937, 1539, 1541, 2940, + 5410, 5407, 3440, 3085, 3088, 5271, 1872, 824, 1845, 824, + 1845, 2746, 3980, 2782, 1275, 2750, 5395, 3262, 2775, 1152, + 2955, 2670, 5319, 5334, 3204, 1717, 2578, 2962, 2963, 5264, + 961, 5319, 5279, 5242, 824, 824, 2903, 3071, 2924, 2974, + 2911, 2910, 2830, 2820, 2867, 1273, 2763, 2906, 824, 824, + 824, 2866, 2896, 2898, 2899, 2900, 2768, 2902, 2753, 2865, + 2779, 247, 4447, 1580, 2760, 1581, 1579, 2761, 2834, 5142, + 1578, 3009, 3009, 3015, 5139, 1578, 2913, 2722, 5106, 5100, + 3024, 1831, 1831, 1831, 1831, 1831, 1831, 1831, 1831, 2800, + 2609, 2782, 2912, 4983, 2396, 2397, 2757, 2815, 4982, 2573, + 4979, 2403, 2404, 2473, 2802, 1148, 1149, 1150, 1151, 2807, + 247, 2184, 2417, 2418, 2419, 2832, 2184, 1814, 2211, 5243, + 4978, 4397, 2904, 1580, 1146, 1581, 1579, 1491, 2824, 4977, + 2296, 3108, 4440, 2299, 2300, 2301, 4976, 3063, 2305, 2306, + 2307, 2308, 2310, 2311, 2312, 2313, 2314, 2315, 2316, 2317, + 2319, 2320, 2321, 2322, 2323, 2782, 4975, 3940, 1439, 1442, + 2832, 247, 3849, 247, 5107, 1578, 4957, 3089, 3647, 3628, + 3453, 3326, 3084, 3077, 3083, 247, 3080, 3086, 1580, 2782, + 1581, 1579, 3944, 4138, 2782, 842, 2832, 4920, 3072, 1580, + 2993, 1581, 1579, 4889, 4886, 2998, 3325, 2945, 1886, 2947, + 3286, 2969, 2439, 2439, 824, 2121, 2832, 2916, 2917, 1580, + 4726, 1581, 1579, 3115, 2731, 2832, 4725, 2734, 2735, 2853, + 2919, 2739, 2832, 2836, 4651, 785, 785, 1549, 4650, 1443, + 1551, 3087, 2765, 1422, 2718, 2751, 2752, 3943, 4546, 1886, + 824, 4829, 2832, 1143, 4474, 2754, 2755, 4470, 2756, 2656, + 2364, 79, 4475, 4464, 1580, 3012, 1581, 1579, 1552, 2016, + 1635, 2069, 4461, 3212, 3213, 4434, 4332, 4328, 3673, 1275, + 824, 1445, 4544, 2832, 1152, 807, 1408, 2935, 1661, 1578, + 3020, 2939, 1940, 1403, 4217, 3228, 1580, 3230, 1581, 1579, + 264, 1580, 2608, 1581, 1579, 4115, 4727, 1594, 3076, 3075, + 1273, 3074, 3020, 3172, 3931, 3097, 3098, 3900, 2994, 3025, + 4155, 3875, 2966, 3416, 4152, 3873, 2108, 3081, 1148, 1149, + 1150, 1151, 3223, 3051, 2066, 3633, 3009, 3009, 3271, 3631, + 4475, 2819, 2818, 4471, 3625, 3282, 2805, 2806, 3159, 4155, + 4568, 2810, 2811, 1957, 1956, 2909, 1660, 3414, 4152, 3292, + 2828, 1578, 4333, 4329, 3401, 3050, 3238, 3026, 3027, 3028, + 3029, 3030, 3031, 3032, 3298, 3393, 3016, 3017, 3301, 3304, + 4218, 3338, 3070, 3184, 3306, 3295, 5428, 4936, 3045, 1886, + 3253, 3626, 5414, 1545, 2208, 3251, 1616, 1615, 3249, 5411, + 1578, 3247, 4599, 3365, 3366, 4263, 3320, 3632, 5097, 2773, + 3359, 3626, 1441, 1440, 5408, 3053, 1886, 3215, 1886, 1547, + 3019, 3634, 2915, 1422, 2876, 3632, 2084, 2085, 44, 2875, + 3626, 3337, 1550, 1553, 3190, 3199, 3191, 1384, 1380, 1381, + 1382, 1383, 2856, 1578, 3364, 2847, 3363, 3362, 3360, 2846, + 1578, 2845, 16, 3266, 5098, 3196, 3197, 2833, 2781, 1546, + 1614, 1578, 5348, 2079, 3358, 2030, 2568, 1578, 3332, 1521, + 2392, 3020, 1886, 1422, 3297, 1876, 3254, 3372, 3299, 4937, + 2563, 3252, 1865, 1867, 3248, 3203, 1877, 3248, 3179, 3173, + 3373, 3185, 3310, 77, 3381, 2264, 2263, 1152, 1488, 1886, + 3233, 3052, 3317, 3318, 1616, 1615, 3020, 4708, 2914, 2393, + 1578, 2264, 2263, 3367, 4431, 1578, 4111, 1874, 2222, 5068, + 3012, 3200, 4429, 3288, 3289, 4938, 3290, 3291, 1578, 5009, + 4598, 1578, 3361, 1433, 1275, 1578, 5008, 1578, 3417, 963, + 3382, 1548, 32, 2832, 2782, 841, 841, 4919, 841, 841, + 3307, 2031, 3914, 4709, 4857, 841, 3259, 2180, 2181, 3321, + 4432, 4827, 4792, 2198, 2199, 1273, 3260, 2202, 4430, 3227, + 3263, 3220, 3448, 3450, 1473, 3309, 2195, 1473, 1474, 3455, + 1614, 1474, 3459, 4748, 1473, 3267, 2080, 4747, 1474, 824, + 824, 824, 2192, 2194, 2191, 4673, 2193, 17, 4441, 4112, + 2075, 4408, 2093, 1580, 2093, 1581, 1579, 3269, 3280, 1422, + 3558, 3270, 4250, 2309, 4266, 4240, 3387, 1886, 4231, 3391, + 1845, 1489, 4219, 1873, 1616, 1615, 3294, 1845, 2560, 2302, + 4157, 3352, 3390, 3355, 3349, 3334, 4154, 3009, 3397, 3419, + 3423, 3329, 3425, 3426, 4084, 4113, 3809, 3308, 3370, 3808, + 3635, 15, 3630, 3581, 3499, 1597, 1598, 1599, 1600, 1601, + 1594, 3640, 3643, 2190, 1312, 1313, 1314, 3445, 3322, 3347, + 3498, 1473, 3335, 3891, 3327, 1474, 3293, 3195, 3433, 2187, + 2189, 2186, 3434, 2188, 2938, 1580, 38, 1581, 1579, 2705, + 3621, 2704, 2703, 1831, 3617, 1831, 3242, 2026, 2022, 1311, + 1800, 1799, 1308, 1424, 3232, 3679, 3685, 3636, 3637, 4027, + 2659, 3339, 3340, 5235, 5234, 1422, 3342, 3343, 2215, 3595, + 2825, 1473, 3357, 2076, 3704, 1474, 5102, 3319, 3368, 1945, + 3483, 2659, 3715, 1422, 4030, 3717, 3718, 3719, 1422, 1422, + 1422, 2121, 2215, 1807, 1422, 3730, 3850, 3731, 3732, 5, + 3733, 4030, 3735, 3736, 1807, 5294, 2433, 3607, 3598, 1580, + 1806, 1581, 1579, 3730, 1580, 4945, 1581, 1579, 4264, 1581, + 1579, 3688, 1580, 3351, 1581, 1579, 2473, 4888, 3716, 4887, + 2501, 3234, 3933, 3432, 3721, 3722, 2849, 44, 1579, 3726, + 3790, 1580, 4762, 1581, 1579, 4761, 3435, 3436, 4116, 3737, + 2997, 1319, 1320, 2093, 3734, 2503, 1324, 785, 3707, 3577, + 1886, 16, 1886, 3705, 4027, 5472, 3596, 2430, 1580, 2560, + 1581, 1579, 5459, 1422, 1422, 3696, 5435, 1946, 4737, 4029, + 2141, 5161, 5162, 4736, 1886, 1595, 1596, 1597, 1598, 1599, + 1600, 1601, 1594, 3274, 1807, 5283, 3830, 3932, 3720, 5159, + 5160, 3810, 77, 3273, 1580, 824, 1581, 1579, 2848, 5270, + 1422, 5424, 4450, 3846, 5230, 3559, 3560, 1831, 3829, 3829, + 3575, 5013, 5014, 3580, 1580, 264, 1581, 1579, 5165, 3604, + 264, 1580, 3620, 1581, 1579, 1580, 3619, 1581, 1579, 1945, + 1305, 1306, 1307, 1310, 3795, 1309, 1580, 5164, 1581, 1579, + 3639, 32, 3642, 3311, 3638, 3499, 1940, 3655, 3656, 3316, + 5321, 5163, 3871, 3653, 3654, 7, 5158, 3812, 4674, 4675, + 6, 3498, 3918, 3666, 3670, 3671, 3672, 3882, 5423, 3667, + 3665, 3206, 3207, 2829, 2279, 1637, 3687, 1580, 3690, 1581, + 1579, 3304, 3428, 5157, 3429, 3701, 3701, 3702, 1636, 2280, + 3701, 3706, 4667, 3699, 5156, 3801, 17, 5155, 5154, 3723, + 3114, 4395, 5153, 5151, 1886, 5150, 3120, 3902, 3789, 3123, + 3124, 3125, 3126, 3127, 3128, 3129, 3130, 3787, 5375, 3133, + 3134, 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, 3143, + 3872, 3145, 3146, 3147, 3148, 3149, 3764, 3150, 2208, 3376, + 3848, 3751, 1580, 44, 1581, 1579, 5149, 3817, 44, 1580, + 15, 1581, 1579, 1580, 4668, 1581, 1579, 3383, 5376, 5251, + 2093, 5148, 3169, 4396, 3171, 3804, 5125, 16, 3396, 5147, + 3788, 2411, 16, 3813, 3402, 3831, 4880, 5146, 3785, 3786, + 3886, 2008, 3774, 3889, 3890, 38, 1580, 4613, 1581, 1579, + 5144, 4401, 3838, 1580, 3807, 1581, 1579, 3835, 5143, 3976, + 5099, 3896, 3840, 1580, 3477, 1581, 1579, 4986, 77, 4967, + 3844, 3845, 4939, 77, 1580, 3851, 1581, 1579, 4913, 4885, + 3855, 4847, 4757, 3839, 4711, 5374, 3853, 4011, 4710, 3852, + 3995, 4611, 4520, 4433, 4015, 4394, 4602, 4377, 4073, 4020, + 3784, 824, 1845, 1241, 3773, 4601, 4407, 4059, 3893, 3380, + 4032, 4034, 4035, 4037, 3883, 4039, 4040, 32, 1580, 3862, + 1581, 1579, 32, 1580, 4600, 1581, 1579, 3861, 3798, 3899, + 4517, 1422, 1580, 3772, 1581, 1579, 3904, 3771, 4317, 3868, + 2803, 2804, 3770, 3762, 4307, 2808, 2809, 3756, 3755, 3888, + 2093, 1580, 3986, 1581, 1579, 3754, 3753, 1580, 3977, 1581, + 1579, 3981, 3945, 3984, 3985, 1580, 3752, 1581, 1579, 3441, + 3296, 1580, 17, 1581, 1579, 3938, 4052, 17, 3255, 1580, + 2827, 1581, 1579, 3192, 3911, 3930, 3898, 2923, 2727, 1580, + 5421, 1581, 1579, 3917, 3912, 3937, 5403, 3913, 2680, 3921, + 3922, 4055, 1580, 3934, 1581, 1579, 4062, 4064, 1580, 2679, + 1581, 1579, 3926, 3927, 2677, 2673, 2672, 4077, 3923, 2626, + 3925, 2375, 1580, 824, 1581, 1579, 15, 3415, 2372, 2017, + 1580, 15, 1581, 1579, 1740, 3924, 4911, 4912, 4092, 5396, + 1422, 3054, 3277, 5377, 824, 3279, 824, 2560, 1406, 4583, + 3278, 4004, 1422, 5346, 1580, 1422, 1581, 1579, 5312, 5302, + 1580, 38, 1581, 1579, 2840, 5241, 38, 3009, 5211, 4124, + 3009, 4114, 5209, 4127, 4893, 4128, 5178, 5080, 1208, 1234, + 1232, 4009, 1233, 4678, 3413, 1831, 3024, 5074, 4137, 4008, + 5065, 4023, 1602, 1603, 1604, 1605, 1595, 1596, 1597, 1598, + 1599, 1600, 1601, 1594, 3994, 5063, 3412, 5045, 4100, 1405, + 1237, 1580, 3993, 1581, 1579, 4088, 5036, 3679, 5001, 5000, + 4991, 3410, 4990, 3685, 4966, 4965, 1868, 3595, 4916, 4130, + 4081, 4900, 4898, 1580, 3108, 1581, 1579, 4884, 1422, 4848, + 4741, 4171, 1966, 4171, 4175, 4740, 4175, 4175, 1580, 4739, + 1581, 1579, 4682, 1971, 1972, 1973, 1974, 1975, 1976, 4671, + 4656, 4655, 1422, 1580, 1970, 1581, 1579, 4653, 4646, 1987, + 3607, 4644, 1991, 4623, 3847, 4210, 1990, 3598, 4622, 4621, + 4617, 1983, 3409, 1242, 1886, 1886, 3408, 4123, 4091, 4616, + 1828, 1080, 2342, 4203, 4121, 1981, 1982, 4587, 4126, 4065, + 4169, 4585, 4581, 4579, 4557, 4554, 4548, 997, 1007, 1580, + 3703, 1581, 1579, 1580, 3794, 1581, 1579, 998, 4135, 999, + 1003, 1006, 1002, 1000, 1001, 4211, 4212, 4389, 4379, 4087, + 4362, 3565, 824, 4344, 4315, 1238, 4312, 4105, 1275, 4183, + 4185, 4280, 4238, 2430, 4237, 4119, 4062, 3885, 4168, 3887, + 4122, 4234, 1886, 3012, 4117, 4233, 4106, 4125, 4159, 4108, + 3892, 4132, 1845, 4220, 4215, 2560, 2560, 3894, 3895, 1273, + 4136, 4214, 4205, 4151, 4153, 4085, 822, 4049, 4156, 4041, + 4031, 4021, 4170, 4012, 4172, 1004, 4010, 2928, 3407, 3910, + 3372, 3907, 3881, 4235, 3860, 5453, 3406, 3837, 4267, 3802, + 4204, 1240, 3799, 3796, 1582, 4158, 3783, 3076, 3075, 3775, + 4160, 3765, 1618, 3763, 3759, 1580, 1005, 1581, 1579, 3758, + 4176, 4177, 1629, 1580, 3757, 1581, 1579, 3659, 3484, 3466, + 3936, 1585, 1586, 1587, 1588, 1589, 1590, 1591, 1583, 3454, + 4208, 3948, 3442, 3950, 3272, 3953, 3954, 3261, 1639, 824, + 3955, 3956, 3957, 3958, 3959, 3405, 3960, 3961, 3962, 3963, + 3964, 3965, 3966, 3967, 3221, 3969, 3970, 3971, 3972, 4216, + 4305, 3404, 2956, 3743, 3744, 2943, 3403, 1080, 1079, 5390, + 3400, 4308, 1580, 1207, 1581, 1579, 2942, 2791, 2684, 3760, + 3761, 1219, 2683, 2675, 3399, 2408, 2374, 2371, 1580, 5388, + 1581, 1579, 3398, 1580, 4221, 1581, 1579, 1580, 2357, 1581, + 1579, 4245, 4246, 4232, 3392, 4230, 2356, 4229, 2119, 3377, + 4239, 1580, 3805, 1581, 1579, 1668, 1664, 1236, 3811, 1580, + 4288, 1581, 1579, 1663, 4283, 4277, 1410, 1156, 1315, 201, + 246, 1580, 4282, 1581, 1579, 4236, 1580, 5371, 1581, 1579, + 3371, 4243, 2264, 2263, 3448, 4347, 5236, 5120, 3348, 3448, + 4349, 5046, 2653, 2908, 5369, 4890, 822, 4224, 4879, 4878, + 2907, 4866, 5370, 5475, 4363, 4860, 4365, 1580, 4654, 1581, + 1579, 4371, 2901, 3679, 3685, 1580, 1728, 1581, 1579, 5368, + 1580, 4620, 1581, 1579, 4606, 1422, 2709, 1580, 4595, 1581, + 1579, 2870, 4293, 4549, 4438, 4359, 4294, 4426, 2318, 1580, + 4424, 1581, 1579, 4417, 4322, 239, 5473, 4324, 841, 2869, + 824, 2560, 4300, 4340, 4372, 4338, 4335, 4316, 1580, 4334, + 1581, 1579, 2210, 4331, 4416, 4330, 4318, 4314, 1235, 4311, + 3499, 4269, 4268, 1230, 4258, 4422, 1580, 4252, 1581, 1579, + 1231, 4144, 4131, 4053, 4383, 4050, 3498, 4003, 3941, 1580, + 4336, 1581, 1579, 4387, 4388, 3345, 3928, 3346, 3920, 246, + 200, 233, 202, 2473, 1831, 4444, 4366, 3919, 4368, 3916, + 3674, 3250, 2448, 3246, 3245, 3244, 3209, 3208, 4455, 246, + 200, 233, 202, 3679, 2881, 3304, 3685, 2995, 4466, 2874, + 2864, 1422, 2863, 4405, 4472, 2862, 2861, 1422, 4419, 4345, + 4452, 2859, 203, 4346, 2855, 4354, 4341, 2854, 4348, 4171, + 4351, 2852, 2996, 246, 2843, 3607, 3607, 2839, 2838, 2758, + 2682, 2329, 2327, 2326, 2325, 2324, 2278, 4378, 4414, 4374, + 4373, 4382, 1939, 4385, 239, 5477, 2277, 1422, 1422, 2268, + 4543, 1907, 4473, 4423, 1886, 5419, 5417, 4402, 4529, 4530, + 4531, 4532, 3695, 5389, 239, 5378, 5308, 4404, 5307, 4552, + 3607, 5306, 5282, 5275, 4337, 5273, 5171, 5124, 1658, 5119, + 4439, 5030, 5029, 824, 5028, 2560, 4999, 4446, 5476, 1831, + 1422, 4974, 4541, 3726, 4968, 4545, 4791, 4782, 239, 4451, + 4569, 4760, 4754, 4501, 4728, 264, 4712, 4443, 4527, 4524, + 4522, 3696, 4515, 4508, 4514, 4511, 4224, 4510, 4509, 4410, + 4442, 913, 4361, 4357, 4313, 4147, 4141, 1986, 1989, 1961, + 1980, 1977, 4589, 1963, 1958, 3829, 4046, 4460, 4043, 4463, + 4462, 4468, 4565, 1593, 1592, 1602, 1603, 1604, 1605, 1595, + 1596, 1597, 1598, 1599, 1600, 1601, 1594, 4042, 3968, 3929, + 4516, 3797, 3791, 4558, 3708, 3624, 3618, 3614, 1817, 3438, + 3219, 3194, 3151, 3037, 4534, 2860, 3018, 4247, 2968, 2967, + 4251, 2922, 4542, 2812, 2185, 4540, 239, 1654, 2697, 2482, + 4547, 2442, 2353, 2064, 1978, 4561, 1739, 1718, 2448, 1713, + 1712, 4636, 1143, 1711, 1710, 4642, 4553, 1709, 1708, 1707, + 4563, 4648, 4556, 1706, 4638, 4560, 4592, 2086, 4564, 1705, + 4559, 4550, 4562, 1704, 1703, 1702, 1701, 1700, 1699, 1698, + 1697, 1696, 1695, 44, 1694, 4178, 4287, 1693, 1692, 4289, + 4290, 4586, 4584, 2107, 1691, 1690, 4292, 1689, 1688, 1687, + 1686, 1422, 1886, 1886, 1685, 1684, 4683, 16, 1683, 1422, + 4610, 4614, 4612, 1682, 1681, 1680, 1679, 4608, 1678, 1677, + 1676, 4107, 4604, 4603, 1675, 1674, 1671, 1422, 1670, 1669, + 1667, 4714, 1666, 4555, 1665, 1662, 4658, 1655, 1652, 1651, + 1650, 4724, 1649, 4680, 1648, 1647, 2222, 1646, 77, 4713, + 1645, 4626, 1644, 1643, 4618, 4574, 1642, 4645, 1641, 4647, + 1422, 1640, 1634, 1633, 1632, 4632, 1422, 1631, 2153, 2154, + 2155, 2156, 3829, 4679, 4685, 1630, 4689, 1543, 1504, 1886, + 1407, 3651, 3652, 5138, 5136, 4689, 4718, 5134, 5131, 4512, + 4659, 2745, 2984, 1451, 4662, 5460, 5434, 32, 824, 5420, + 1422, 1422, 1422, 5325, 4672, 1422, 1422, 5323, 4681, 5260, + 4227, 3803, 3582, 1422, 3214, 1422, 2212, 4692, 3001, 4705, + 2216, 2217, 2218, 2219, 4704, 4691, 4785, 4697, 1618, 4702, + 4686, 2258, 1542, 4687, 1471, 3049, 3607, 4788, 4695, 4790, + 2269, 4784, 4830, 4720, 4446, 2222, 2222, 2222, 4779, 1409, + 2222, 2222, 17, 4145, 3035, 4826, 4730, 4729, 2146, 1219, + 2146, 4501, 4731, 4735, 1417, 3034, 4843, 4844, 2297, 2298, + 4168, 4508, 4764, 4765, 4766, 4839, 4734, 4780, 4781, 3662, + 3047, 4639, 3048, 1886, 4742, 1886, 2702, 1886, 3663, 2208, + 1454, 1456, 3042, 3664, 3661, 3660, 2328, 3043, 2330, 2331, + 2332, 2333, 2334, 3657, 3040, 3038, 15, 4149, 2343, 3041, + 3039, 3046, 4874, 3033, 82, 4881, 4882, 4150, 824, 4833, + 5433, 5191, 5049, 1502, 4856, 5048, 4858, 4832, 4859, 5021, + 4835, 4566, 4894, 5465, 4896, 4445, 5461, 4733, 4435, 3874, + 3627, 38, 1801, 2427, 2428, 2422, 2423, 2424, 3739, 4083, + 3065, 4421, 3118, 4615, 1009, 173, 3740, 3741, 3742, 4165, + 4850, 4166, 3978, 4535, 173, 2208, 4256, 4257, 4148, 3842, + 4855, 3067, 3066, 4386, 4254, 2541, 1954, 4897, 3622, 4899, + 2003, 4851, 4567, 1806, 1146, 4929, 3206, 3207, 5239, 4521, + 2958, 4523, 815, 4255, 3333, 2950, 4875, 2435, 4876, 2949, + 1577, 2003, 4877, 1999, 1229, 2957, 2644, 2553, 1537, 5169, + 1940, 4971, 4925, 4724, 4724, 4940, 4652, 4101, 4948, 4952, + 4057, 4056, 3689, 3275, 3069, 2992, 5338, 5240, 2446, 2399, + 2264, 2263, 817, 4903, 1737, 1738, 1735, 1736, 5309, 4902, + 4970, 173, 4596, 4924, 4915, 1733, 1734, 4927, 1731, 1732, + 4594, 4213, 3176, 3170, 3165, 3064, 4921, 2564, 4942, 1532, + 4928, 1531, 4693, 1570, 3876, 2343, 2706, 2197, 1503, 1146, + 2343, 2343, 4592, 1422, 4932, 3669, 4930, 2959, 1148, 1149, + 1150, 1151, 1422, 1272, 2073, 1480, 1479, 1462, 4588, 1146, + 4946, 4947, 1503, 4664, 4943, 3331, 2618, 1146, 2729, 5289, + 5287, 5220, 4663, 5188, 3330, 3607, 4985, 5187, 5185, 5084, + 5031, 4786, 4609, 4580, 4941, 4572, 4458, 4605, 2222, 1886, + 4607, 4457, 5018, 4969, 1138, 4276, 4275, 2146, 5024, 1722, + 3103, 3090, 1906, 4571, 4261, 2660, 3949, 3411, 2663, 1477, + 4643, 2666, 5327, 5326, 2668, 4980, 5232, 5233, 5327, 4364, + 4981, 4350, 4327, 3897, 3461, 3460, 3452, 3451, 3226, 3222, + 5015, 1592, 1602, 1603, 1604, 1605, 1595, 1596, 1597, 1598, + 1599, 1600, 1601, 1594, 5019, 5020, 2841, 2152, 5064, 1447, + 1416, 5326, 4756, 5311, 5310, 5293, 5069, 5057, 1148, 1149, + 1150, 1151, 5229, 1272, 1274, 5076, 4411, 4412, 4413, 5227, + 5225, 3481, 3479, 173, 4661, 2918, 1994, 1148, 1149, 1150, + 1151, 5032, 5482, 1272, 5450, 5451, 5483, 5238, 173, 5313, + 173, 5111, 2196, 4326, 818, 1495, 91, 2, 5351, 5352, + 5051, 5071, 1, 5072, 1138, 3996, 5055, 2920, 2351, 1729, + 1147, 1862, 4716, 4717, 3186, 2610, 1890, 2355, 1153, 3055, + 3056, 3668, 3058, 2627, 1457, 3467, 2778, 1219, 1219, 1813, + 3818, 3163, 2972, 5061, 5062, 1422, 4076, 1818, 1225, 2270, + 1438, 5114, 2032, 1437, 5079, 1836, 1435, 2213, 2291, 1011, + 3004, 3792, 5085, 5145, 1855, 5086, 3766, 5095, 4454, 4738, + 1422, 5073, 5337, 5391, 5130, 5132, 5133, 5135, 5137, 5101, + 5104, 5105, 5088, 1502, 5109, 1892, 5281, 1886, 5167, 5340, + 2222, 2688, 5113, 2059, 5152, 995, 5179, 4278, 3869, 5037, + 5122, 5175, 5285, 5039, 4854, 2783, 1575, 4118, 876, 1057, + 1023, 5172, 5173, 2692, 4793, 2146, 3951, 5129, 3946, 1022, + 4825, 4399, 3571, 5025, 3607, 4933, 877, 2669, 5166, 5034, + 4852, 1955, 1960, 3068, 4954, 5115, 4732, 4161, 3713, 1299, + 5176, 5210, 4834, 1993, 5140, 4525, 4870, 4868, 4869, 5197, + 3975, 5022, 4836, 920, 2589, 783, 4783, 2999, 1886, 5217, + 5081, 5177, 4973, 1195, 4380, 2982, 1188, 5184, 5182, 3593, + 3592, 5203, 5205, 2164, 1584, 2183, 4319, 4320, 4952, 5207, + 1628, 2821, 965, 2823, 3568, 2826, 4865, 5212, 5244, 4867, + 5204, 5206, 5208, 2835, 1886, 4495, 3836, 90, 89, 5222, + 88, 272, 1014, 271, 5218, 5219, 5221, 4891, 4676, 5223, + 5174, 992, 991, 990, 989, 988, 987, 2456, 2455, 2457, + 2454, 2452, 5231, 2451, 1300, 1825, 5237, 1824, 4260, 4570, + 3224, 3225, 2844, 3729, 4536, 5252, 3724, 2493, 2489, 5024, + 2851, 1853, 2490, 3093, 3105, 2488, 5265, 5257, 4302, 5266, + 4597, 5267, 5126, 5268, 5127, 4753, 3776, 5269, 4591, 2421, + 3100, 2509, 3746, 2506, 2505, 3738, 4749, 4743, 2538, 5091, + 2872, 5361, 5226, 5364, 5228, 2877, 2878, 2879, 5272, 4701, + 2882, 2883, 2884, 2885, 2886, 2887, 2888, 2889, 5280, 2891, + 2892, 1422, 2894, 2895, 5288, 5284, 5290, 5291, 4700, 5286, + 5356, 5224, 4699, 4465, 3684, 4698, 4688, 4476, 4477, 4484, + 1365, 5299, 2991, 5300, 1293, 1334, 1285, 1289, 1291, 1329, + 1331, 1332, 1330, 3356, 5301, 4241, 3073, 5305, 4095, 3490, + 3489, 3487, 3486, 5398, 1779, 5075, 5303, 5213, 4657, 3497, + 3495, 1461, 1296, 2065, 3976, 2061, 1288, 1452, 5317, 5316, + 5336, 5315, 1404, 2275, 3014, 5320, 4024, 1745, 1743, 3658, + 5324, 5322, 5343, 3036, 5328, 5329, 5330, 5331, 2247, 5335, + 2616, 3841, 1826, 5332, 1823, 1422, 4142, 5359, 5359, 5359, + 1422, 1822, 1303, 1302, 5363, 5366, 2621, 1276, 240, 1901, + 241, 5197, 5350, 172, 1135, 4355, 4420, 1294, 5347, 5354, + 3820, 5355, 5367, 3177, 3276, 3678, 4905, 2426, 5114, 1189, + 5380, 5381, 2980, 126, 5393, 48, 5387, 145, 125, 1297, + 2146, 219, 69, 218, 68, 3829, 1298, 20, 143, 217, + 67, 5033, 4828, 53, 52, 215, 121, 120, 119, 5416, + 118, 5416, 142, 5405, 214, 66, 256, 255, 258, 4952, + 257, 254, 3062, 3235, 3236, 253, 1943, 5418, 252, 5189, + 4696, 5274, 51, 5422, 50, 220, 2275, 49, 127, 70, + 47, 1286, 46, 2728, 4044, 5343, 2072, 5429, 5359, 5438, + 4375, 5359, 5438, 5426, 5359, 5438, 5441, 5363, 3482, 5443, + 5366, 2964, 5442, 5436, 5440, 1295, 45, 40, 14, 12, + 5447, 43, 5449, 5393, 5457, 5454, 5458, 41, 25, 24, + 1209, 2038, 23, 31, 30, 13, 5462, 5463, 39, 37, + 36, 164, 5468, 5470, 163, 35, 162, 161, 160, 159, + 158, 157, 156, 34, 22, 61, 60, 1287, 59, 58, + 57, 56, 8, 4448, 139, 5480, 149, 148, 150, 146, + 141, 138, 33, 2343, 140, 2343, 5479, 136, 5481, 137, + 130, 129, 128, 173, 173, 122, 173, 1274, 102, 101, + 100, 115, 114, 113, 2343, 2343, 817, 112, 111, 110, + 108, 2380, 2381, 2382, 1834, 1835, 109, 1837, 875, 99, + 1841, 4931, 1850, 1851, 1852, 2243, 98, 97, 96, 95, + 135, 134, 2240, 131, 117, 124, 2242, 2239, 2241, 2245, + 2246, 123, 106, 116, 2244, 107, 105, 104, 2420, 1292, + 103, 1939, 94, 93, 92, 133, 132, 2434, 147, 221, + 71, 198, 197, 1914, 1915, 196, 195, 1918, 1919, 1920, + 1921, 1922, 194, 1924, 1925, 1926, 192, 1928, 193, 1931, + 191, 1933, 1934, 1935, 190, 2486, 2487, 189, 188, 187, + 186, 62, 63, 1282, 64, 65, 210, 209, 211, 223, + 222, 213, 216, 3281, 212, 3284, 207, 205, 208, 206, + 204, 83, 11, 4988, 4989, 144, 21, 18, 3, 5110, + 4993, 4994, 4995, 4996, 4997, 4998, 5467, 5469, 5372, 5002, + 5003, 5004, 5005, 5006, 5007, 0, 0, 1617, 0, 0, + 5010, 5011, 5012, 0, 0, 0, 0, 5016, 0, 0, + 0, 201, 246, 200, 233, 202, 3312, 3313, 1358, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1456, + 0, 2050, 0, 0, 0, 1456, 0, 0, 226, 0, + 0, 0, 0, 0, 0, 2228, 2229, 2230, 2231, 2232, + 2233, 2234, 2235, 2236, 2237, 2238, 2250, 2251, 2252, 2253, + 2254, 2255, 2248, 2249, 1301, 0, 0, 0, 1281, 1283, + 0, 0, 0, 0, 4987, 0, 1284, 0, 0, 0, + 0, 0, 0, 0, 0, 3350, 0, 239, 3354, 0, + 0, 1080, 0, 2039, 0, 0, 0, 0, 0, 0, + 3374, 3375, 0, 0, 0, 0, 5087, 0, 2842, 3378, + 3379, 1593, 1592, 1602, 1603, 1604, 1605, 1595, 1596, 1597, + 1598, 1599, 1600, 1601, 1594, 3384, 3385, 3386, 1593, 1592, + 1602, 1603, 1604, 1605, 1595, 1596, 1597, 1598, 1599, 1600, + 1601, 1594, 0, 0, 0, 0, 0, 0, 5123, 0, + 2205, 2206, 0, 5108, 0, 1376, 1377, 1338, 0, 0, + 0, 1358, 1138, 0, 3422, 0, 3424, 0, 0, 3427, + 1725, 2153, 0, 1454, 2343, 0, 0, 2725, 1366, 1370, + 1372, 1374, 1379, 0, 1384, 1380, 1381, 1382, 1383, 0, + 0, 1361, 1362, 1363, 1364, 3353, 1337, 1367, 0, 1339, + 0, 1340, 1342, 1343, 1344, 1345, 1341, 1346, 1347, 1348, + 1349, 1350, 1357, 1359, 1351, 1352, 1353, 1354, 1355, 1356, + 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1394, 1393, + 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1369, 1371, + 1373, 1375, 1378, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1829, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 199, 231, 243, 232, 0, + 151, 0, 0, 0, 0, 247, 0, 0, 0, 1360, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2056, + 225, 224, 1895, 0, 0, 1904, 0, 0, 1376, 1377, + 1338, 0, 817, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, + 0, 1366, 1370, 1372, 1374, 1379, 0, 1384, 1380, 1381, + 1382, 1383, 4789, 0, 1361, 1362, 1363, 1364, 1336, 1337, + 1367, 0, 1339, 173, 1340, 1342, 1343, 1344, 1345, 1341, + 1346, 1347, 1348, 1349, 1350, 1357, 1359, 1351, 1352, 1353, + 1354, 1355, 1356, 1385, 1386, 1387, 1388, 1389, 1390, 1391, + 1392, 1394, 1393, 1395, 1396, 1397, 1398, 1399, 1400, 1401, + 1402, 1369, 1371, 1373, 1375, 1378, 1593, 1592, 1602, 1603, + 1604, 1605, 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1594, + 1593, 1592, 1602, 1603, 1604, 1605, 1595, 1596, 1597, 1598, + 1599, 1600, 1601, 1594, 0, 0, 0, 0, 932, 931, + 938, 928, 1360, 0, 0, 0, 0, 0, 0, 0, + 0, 935, 936, 0, 937, 941, 0, 0, 922, 0, + 0, 0, 0, 0, 2343, 0, 0, 0, 946, 0, + 0, 0, 173, 0, 0, 0, 173, 173, 0, 0, + 0, 0, 0, 0, 2618, 0, 0, 0, 0, 0, + 0, 0, 173, 0, 0, 0, 0, 4787, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2944, 0, 2946, + 0, 0, 0, 0, 0, 0, 0, 0, 3854, 0, + 3856, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2970, 2971, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1939, 0, 0, 2988, 2989, + 2990, 1593, 1592, 1602, 1603, 1604, 1605, 1595, 1596, 1597, + 1598, 1599, 1600, 1601, 1594, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2632, 2633, + 0, 0, 0, 3344, 4503, 2639, 0, 0, 0, 0, + 4482, 0, 0, 0, 2646, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1358, 79, 1593, 1592, 1602, + 1603, 1604, 1605, 1595, 1596, 1597, 1598, 1599, 1600, 1601, + 1594, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3915, 4496, 1368, 0, 0, 0, 2057, 242, 2058, + 0, 0, 0, 0, 0, 0, 4485, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4479, 0, 0, + 3939, 0, 4505, 4506, 0, 0, 0, 0, 4480, 0, + 2698, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1617, 0, 0, 0, 0, 0, 0, + 0, 923, 925, 924, 0, 3942, 3973, 0, 0, 0, + 0, 0, 0, 930, 1855, 0, 0, 4481, 0, 4488, + 0, 0, 0, 0, 0, 934, 0, 0, 0, 0, + 0, 0, 949, 0, 0, 0, 0, 0, 0, 927, + 0, 0, 0, 0, 0, 169, 0, 0, 0, 0, + 1892, 0, 1376, 1377, 1338, 0, 0, 0, 1327, 1593, + 1592, 1602, 1603, 1604, 1605, 1595, 1596, 1597, 1598, 1599, + 1600, 1601, 1594, 0, 0, 1366, 1370, 1372, 1374, 1379, + 1456, 1384, 1380, 1381, 1382, 1383, 1368, 1333, 1361, 1362, + 1363, 1364, 1336, 1337, 1367, 0, 1339, 0, 1340, 1342, + 1343, 1344, 1345, 1341, 1346, 1347, 1348, 1349, 1350, 1357, + 1359, 1351, 1352, 1353, 1354, 1355, 1356, 1385, 1386, 1387, + 1388, 1389, 1390, 1391, 1392, 1394, 1393, 1395, 1396, 1397, + 1398, 1399, 1400, 1401, 1402, 1369, 1371, 1373, 1375, 1378, + 0, 4504, 0, 3083, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 173, 0, 0, + 0, 0, 0, 0, 173, 0, 0, 0, 4492, 0, + 0, 0, 0, 0, 0, 0, 1360, 0, 0, 0, + 0, 0, 2476, 0, 0, 0, 0, 0, 0, 0, + 4489, 4493, 4491, 4490, 929, 933, 939, 0, 940, 942, + 0, 0, 943, 944, 945, 0, 0, 0, 947, 948, + 0, 1829, 0, 0, 2343, 0, 0, 0, 0, 0, + 2343, 0, 0, 0, 0, 4129, 0, 0, 0, 0, + 1333, 0, 0, 0, 0, 0, 0, 0, 4139, 0, + 0, 4140, 0, 0, 0, 0, 0, 0, 4499, 4500, + 0, 0, 0, 0, 932, 931, 938, 928, 0, 0, + 1580, 0, 1581, 1579, 0, 0, 2625, 935, 936, 0, + 937, 941, 0, 0, 922, 0, 0, 0, 0, 0, + 1358, 0, 0, 0, 946, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 4179, 0, + 0, 173, 0, 0, 173, 173, 0, 173, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4507, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 950, 0, 0, 952, 0, 0, 4483, 3935, + 951, 4498, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2247, 0, 0, 0, 0, 0, 0, 0, + 0, 173, 0, 0, 0, 0, 0, 0, 926, 0, + 0, 0, 0, 173, 173, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 173, 0, 4223, 0, 3462, + 3463, 3464, 0, 1593, 1592, 1602, 1603, 1604, 1605, 1595, + 1596, 1597, 1598, 1599, 1600, 1601, 1594, 0, 0, 0, + 173, 0, 0, 0, 0, 0, 0, 1376, 1377, 1338, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1366, 1370, 1372, 1374, 1379, 0, 1384, 1380, 1381, 1382, + 1383, 0, 0, 1361, 1362, 1363, 1364, 1336, 1337, 1367, + 0, 1339, 3641, 1340, 1342, 1343, 1344, 1345, 1341, 1346, + 1347, 1348, 1349, 1350, 1357, 1359, 1351, 1352, 1353, 1354, + 1355, 1356, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, + 1394, 1393, 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, + 1369, 1371, 1373, 1375, 1378, 0, 0, 923, 925, 924, + 1368, 0, 0, 0, 0, 0, 0, 0, 0, 930, + 0, 0, 0, 4306, 0, 0, 0, 0, 0, 0, + 0, 934, 0, 4309, 4310, 0, 0, 0, 949, 0, + 1617, 1360, 0, 0, 0, 927, 0, 0, 0, 917, + 2539, 0, 0, 0, 4497, 2499, 0, 0, 2547, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4502, + 4323, 0, 0, 4325, 0, 0, 0, 0, 0, 2243, + 0, 0, 0, 0, 3341, 0, 2240, 0, 2541, 2508, + 2242, 2239, 2241, 2245, 2246, 0, 0, 0, 2244, 2542, + 2543, 0, 0, 0, 0, 0, 4486, 4487, 1593, 1592, + 1602, 1603, 1604, 1605, 1595, 1596, 1597, 1598, 1599, 1600, + 1601, 1594, 0, 0, 0, 2507, 0, 0, 0, 0, + 0, 0, 2816, 0, 0, 0, 4223, 0, 0, 0, + 0, 0, 0, 2539, 2516, 0, 0, 0, 2499, 0, + 0, 2547, 0, 0, 1333, 3843, 1593, 1592, 1602, 1603, + 1604, 1605, 1595, 1596, 1597, 1598, 1599, 1600, 1601, 1594, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2541, 2508, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2542, 2543, 0, 0, 0, 0, 0, 0, + 929, 933, 939, 0, 940, 942, 0, 0, 943, 944, + 945, 0, 0, 0, 947, 948, 0, 0, 2507, 0, + 0, 0, 0, 0, 0, 2532, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2516, 0, 2228, + 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, + 2250, 2251, 2252, 2253, 2254, 2255, 2248, 2249, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 173, 0, 0, 0, + 0, 173, 0, 0, 0, 1274, 0, 0, 173, 173, + 0, 0, 0, 0, 0, 1829, 1829, 1829, 1829, 1829, + 1829, 1829, 1829, 2495, 2500, 2498, 0, 0, 2532, 2492, + 0, 0, 2343, 0, 2520, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2526, 0, 0, 0, 0, + 2343, 0, 0, 2510, 0, 2494, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2514, 2548, 0, 0, 2515, + 2517, 2519, 0, 2521, 2522, 2523, 2527, 2528, 2529, 2531, + 2534, 2535, 2536, 0, 926, 1368, 0, 0, 0, 0, + 2524, 2533, 2525, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2502, 0, 0, 0, 0, 0, 0, 0, + 0, 4022, 0, 0, 0, 0, 3692, 3693, 2498, 0, + 0, 0, 3691, 0, 0, 0, 0, 2520, 0, 0, + 0, 0, 953, 954, 955, 956, 957, 0, 2526, 4619, + 0, 0, 0, 0, 2540, 0, 0, 0, 0, 0, + 0, 2539, 0, 0, 0, 0, 0, 0, 2514, 2548, + 0, 0, 2515, 2517, 2519, 0, 2521, 2522, 2523, 2527, + 2528, 2529, 2531, 2534, 2535, 2536, 0, 0, 0, 0, + 0, 0, 0, 2524, 2533, 2525, 0, 0, 0, 2541, + 0, 0, 0, 0, 0, 2502, 2496, 2497, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2537, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 173, 0, 0, 0, 0, 1333, + 0, 0, 0, 4086, 0, 4960, 2512, 2540, 0, 0, + 2511, 4715, 0, 0, 0, 2516, 0, 201, 246, 200, + 233, 202, 0, 1639, 4102, 0, 4103, 0, 0, 0, + 1274, 0, 0, 0, 2530, 0, 0, 234, 0, 0, + 0, 0, 0, 2518, 226, 0, 173, 173, 235, 173, + 173, 0, 0, 0, 0, 0, 173, 2545, 2544, 2496, + 2497, 203, 0, 0, 0, 0, 0, 0, 170, 0, + 0, 0, 0, 0, 0, 0, 0, 2537, 0, 0, + 0, 0, 0, 155, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 239, 0, 0, 2532, 0, 0, 2512, + 0, 0, 0, 2511, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2504, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2530, 0, 0, + 0, 0, 0, 0, 0, 0, 2518, 0, 0, 0, + 0, 4838, 0, 0, 0, 0, 0, 0, 0, 0, + 2545, 2544, 0, 0, 0, 0, 0, 2546, 0, 0, + 0, 0, 0, 2539, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 180, 181, 0, 182, 183, 0, 0, + 0, 184, 0, 0, 185, 2520, 0, 0, 0, 0, + 0, 2541, 0, 0, 0, 0, 2526, 2504, 0, 0, + 0, 0, 1456, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2514, 2548, 0, 0, + 2515, 2517, 2519, 0, 2521, 2522, 2523, 2527, 2528, 2529, + 2531, 2534, 2535, 2536, 0, 0, 0, 0, 0, 0, + 2546, 2524, 2533, 2525, 0, 0, 0, 2516, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 199, 231, 243, 232, 84, 151, 0, 0, 0, + 2539, 247, 0, 0, 0, 0, 0, 0, 0, 1939, + 0, 0, 0, 0, 0, 153, 225, 224, 0, 0, + 0, 0, 85, 0, 0, 2540, 0, 2513, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2541, 0, + 179, 0, 0, 173, 0, 0, 0, 0, 0, 4296, + 4972, 0, 0, 864, 4926, 0, 0, 0, 2532, 0, + 0, 0, 0, 0, 0, 0, 0, 152, 0, 0, + 0, 0, 0, 173, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 227, 228, 229, 0, 0, 0, 0, + 0, 0, 0, 0, 2516, 2537, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1829, 0, 1829, + 0, 0, 0, 0, 0, 0, 0, 2512, 0, 0, + 2513, 2511, 0, 0, 0, 0, 0, 860, 861, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 906, 0, + 0, 0, 0, 0, 0, 2530, 0, 0, 0, 0, + 0, 0, 0, 0, 2518, 0, 0, 2520, 0, 236, + 0, 0, 0, 0, 0, 0, 0, 0, 2526, 0, + 0, 0, 0, 0, 0, 2532, 0, 0, 0, 0, + 165, 0, 0, 0, 230, 0, 166, 0, 2514, 2548, + 0, 0, 2515, 2517, 2519, 0, 2521, 2522, 2523, 2527, + 2528, 2529, 2531, 2534, 2535, 2536, 0, 0, 0, 0, + 0, 0, 0, 2524, 2533, 2525, 0, 0, 0, 0, + 1456, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 908, 5103, 0, 907, 0, 0, + 0, 0, 0, 0, 0, 0, 167, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5121, 75, + 0, 0, 0, 0, 0, 0, 0, 2540, 0, 0, + 0, 0, 0, 0, 2520, 0, 864, 0, 0, 0, + 0, 1829, 0, 0, 0, 2526, 0, 0, 0, 173, + 0, 893, 0, 0, 173, 0, 0, 0, 0, 0, + 0, 865, 0, 0, 0, 2514, 2548, 0, 0, 2515, + 2517, 2519, 79, 2521, 2522, 2523, 2527, 2528, 2529, 2531, + 2534, 2535, 2536, 0, 0, 0, 0, 0, 867, 0, + 2524, 2533, 2525, 0, 0, 0, 0, 2537, 0, 0, + 0, 0, 0, 177, 242, 178, 0, 0, 0, 0, + 860, 861, 0, 0, 0, 0, 0, 0, 72, 2512, + 0, 906, 0, 2511, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1456, 2540, 0, 0, 2530, 0, 0, + 0, 0, 0, 0, 0, 0, 2518, 0, 0, 0, + 0, 0, 0, 0, 0, 889, 0, 891, 888, 5249, + 0, 0, 892, 0, 5253, 0, 0, 0, 2513, 932, + 931, 938, 928, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 935, 936, 0, 937, 941, 0, 0, 922, + 168, 169, 55, 0, 0, 0, 0, 0, 73, 946, + 0, 0, 0, 9, 2537, 0, 0, 908, 887, 0, + 907, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 859, 0, 0, 0, 0, 0, 2512, 0, 0, 0, + 2511, 866, 901, 0, 0, 0, 0, 74, 0, 174, + 175, 0, 0, 176, 0, 0, 0, 950, 0, 0, + 952, 0, 0, 0, 2530, 951, 0, 897, 0, 0, + 0, 0, 0, 2518, 893, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 865, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5249, 0, 0, 0, + 0, 0, 0, 898, 902, 852, 0, 0, 0, 0, + 0, 867, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 884, 0, 882, 886, 905, 0, + 0, 0, 883, 880, 878, 0, 885, 869, 870, 868, + 0, 858, 871, 872, 873, 874, 853, 0, 0, 903, + 0, 904, 0, 0, 1211, 0, 1212, 0, 0, 0, + 0, 0, 899, 900, 0, 0, 0, 0, 0, 5249, + 0, 0, 0, 0, 0, 4799, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 889, 0, + 891, 888, 0, 0, 0, 892, 1193, 0, 0, 0, + 895, 0, 0, 0, 0, 0, 0, 0, 4763, 854, + 1206, 0, 1201, 0, 1274, 0, 173, 0, 890, 4820, + 2513, 0, 0, 4799, 0, 879, 0, 0, 0, 0, + 0, 0, 923, 925, 924, 0, 0, 0, 0, 0, + 173, 887, 0, 0, 930, 0, 0, 0, 2984, 0, + 0, 0, 0, 859, 0, 0, 934, 0, 0, 1829, + 0, 4798, 0, 949, 866, 901, 0, 4820, 0, 0, + 927, 0, 0, 0, 0, 0, 0, 0, 5456, 0, + 0, 1182, 0, 0, 0, 0, 0, 0, 0, 0, + 897, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 173, 0, 0, 0, 0, 4798, + 0, 0, 0, 0, 894, 0, 0, 0, 0, 0, + 862, 863, 0, 0, 851, 855, 898, 902, 4883, 0, + 0, 0, 856, 0, 0, 0, 0, 2513, 0, 0, + 0, 0, 0, 857, 0, 0, 0, 884, 0, 882, + 886, 905, 0, 0, 0, 883, 880, 878, 0, 885, + 869, 870, 868, 0, 858, 871, 872, 873, 874, 853, + 0, 1208, 903, 1200, 904, 0, 0, 0, 0, 0, + 0, 0, 1205, 1203, 0, 899, 900, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1194, 0, 0, 0, 0, 0, 0, + 0, 0, 4225, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 895, 0, 929, 933, 939, 0, 940, + 942, 0, 854, 943, 944, 945, 0, 0, 0, 947, + 948, 890, 1210, 0, 0, 0, 0, 1199, 879, 0, + 0, 1198, 4795, 0, 0, 0, 0, 1187, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1192, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 173, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, + 4795, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1204, 0, 0, 0, 1190, 0, + 0, 0, 0, 0, 0, 0, 0, 894, 0, 0, + 0, 0, 0, 862, 863, 0, 0, 851, 855, 0, + 0, 0, 0, 4800, 4801, 856, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 857, 1209, 0, 0, + 4796, 4797, 0, 4804, 4803, 4802, 4818, 4819, 4821, 4805, + 4806, 4809, 4811, 4810, 4807, 4808, 4812, 4814, 4815, 4816, + 4813, 0, 4817, 0, 1191, 0, 0, 0, 4822, 926, + 0, 4800, 4801, 0, 0, 4824, 0, 0, 0, 4823, + 0, 0, 0, 0, 0, 0, 0, 0, 4796, 4797, + 0, 4804, 4803, 4802, 4818, 4819, 4821, 4805, 4806, 4809, + 4811, 4810, 4807, 4808, 4812, 4814, 4815, 4816, 4813, 0, + 4817, 0, 0, 0, 0, 0, 4822, 953, 954, 955, + 956, 957, 0, 4824, 0, 0, 0, 4823, 0, 0, + 0, 4225, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 173, 173, 0, 0, 0, 1207, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 173, 0, 0, 0, + 1186, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1829, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1183, 0, 0, 0, 1181, 1184, 0, 0, 0, + 0, 0, 0, 1185, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1829, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 341, 342, 343, 1103, 345, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 201, 246, 1030, + 0, 0, 0, 0, 0, 0, 0, 0, 508, 0, + 0, 654, 688, 677, 766, 641, 4225, 0, 0, 0, + 0, 0, 981, 0, 0, 0, 401, 0, 0, 471, + 692, 673, 684, 674, 514, 659, 660, 661, 668, 413, + 662, 798, 664, 633, 665, 634, 666, 667, 1620, 691, + 640, 551, 490, 0, 708, 0, 0, 1104, 1114, 0, + 0, 0, 0, 0, 0, 0, 0, 1099, 0, 0, + 0, 0, 173, 972, 0, 0, 1010, 1080, 1079, 997, + 1007, 0, 0, 372, 270, 635, 762, 637, 636, 998, + 0, 999, 1003, 1006, 1002, 1000, 1001, 0, 1094, 0, + 0, 0, 0, 0, 0, 964, 976, 0, 982, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 973, 974, 0, 0, 0, 0, + 1031, 0, 975, 0, 977, 0, 0, 0, 0, 552, + 580, 0, 594, 0, 440, 441, 1026, 1004, 1008, 0, + 0, 0, 0, 356, 559, 577, 373, 546, 592, 378, + 554, 570, 368, 507, 542, 0, 0, 358, 575, 553, + 485, 357, 0, 535, 398, 415, 395, 505, 1005, 0, + 1029, 1033, 394, 1120, 1027, 585, 360, 0, 584, 504, + 477, 571, 576, 486, 479, 0, 359, 573, 484, 478, + 454, 405, 1121, 455, 456, 457, 458, 459, 460, 419, + 1109, 475, 521, 420, 492, 491, 493, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 430, 0, 0, 0, + 0, 0, 616, 617, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 754, + 1024, 247, 759, 0, 588, 0, 0, 1101, 0, 0, + 0, 557, 0, 0, 461, 0, 0, 0, 1028, 0, + 538, 510, 1117, 0, 0, 536, 473, 572, 522, 578, + 560, 586, 529, 523, 350, 561, 397, 487, 369, 371, + 787, 399, 402, 406, 407, 498, 499, 516, 545, 564, + 565, 566, 396, 383, 537, 384, 416, 385, 351, 388, + 387, 389, 547, 390, 353, 517, 569, 0, 412, 533, + 482, 354, 481, 518, 568, 567, 370, 596, 603, 604, + 696, 173, 609, 801, 802, 803, 618, 0, 524, 366, + 363, 0, 0, 0, 392, 519, 379, 381, 382, 380, + 513, 515, 623, 624, 625, 627, 628, 629, 630, 0, + 0, 0, 0, 631, 697, 715, 681, 650, 611, 705, + 647, 651, 652, 433, 434, 435, 436, 718, 0, 0, + 0, 602, 462, 463, 0, 404, 403, 483, 355, 0, + 0, 451, 432, 525, 361, 400, 453, 438, 464, 465, + 466, 467, 468, 0, 469, 470, 410, 340, 346, 795, + 1098, 506, 720, 757, 758, 642, 0, 1116, 1093, 1095, + 1096, 1100, 1105, 1106, 1107, 1108, 1110, 1112, 1115, 1119, + 794, 0, 698, 712, 799, 711, 791, 512, 0, 544, + 709, 656, 0, 702, 675, 676, 0, 703, 671, 707, + 362, 439, 530, 587, 0, 644, 0, 612, 615, 646, + 733, 734, 735, 352, 614, 737, 738, 739, 740, 741, + 742, 743, 736, 1118, 679, 655, 682, 593, 658, 657, + 0, 0, 693, 1032, 694, 695, 494, 495, 496, 497, + 1102, 721, 377, 613, 527, 528, 0, 680, 0, 0, + 0, 0, 0, 0, 0, 0, 685, 686, 683, 804, + 0, 744, 745, 0, 0, 607, 608, 409, 0, 626, + 417, 376, 511, 411, 591, 442, 0, 619, 687, 620, + 531, 532, 748, 753, 749, 750, 752, 773, 501, 431, + 437, 548, 452, 474, 534, 590, 509, 539, 374, 579, + 550, 480, 672, 700, 1127, 1097, 1126, 1128, 1129, 1125, + 1130, 1131, 1111, 986, 0, 1039, 1040, 1123, 1122, 1124, + 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 729, 728, 727, 726, 725, 724, 723, 722, 0, + 0, 669, 391, 792, 786, 793, 774, 777, 776, 751, + 993, 347, 649, 472, 526, 408, 716, 717, 0, 772, + 1087, 1050, 1051, 1052, 983, 1053, 1047, 1048, 984, 1049, + 1088, 1037, 1084, 1085, 1012, 1042, 1054, 1083, 1055, 1086, + 1013, 1089, 1132, 1133, 1061, 1045, 303, 1134, 1058, 1090, + 1082, 1081, 1056, 1038, 1091, 1092, 1020, 1015, 1059, 1060, + 1046, 1067, 1068, 1069, 1072, 985, 1073, 1074, 1075, 1076, + 1077, 1071, 1070, 1034, 1035, 1036, 1062, 1063, 1065, 1066, + 1041, 558, 1016, 1017, 1018, 1019, 0, 0, 597, 598, + 599, 622, 0, 600, 581, 648, 418, 348, 562, 589, + 789, 790, 0, 0, 0, 0, 0, 0, 0, 699, + 710, 746, 747, 0, 760, 761, 763, 765, 1078, 767, + 555, 556, 775, 0, 0, 443, 364, 365, 502, 503, + 541, 0, 444, 445, 446, 450, 447, 448, 449, 1064, + 770, 771, 768, 476, 540, 563, 549, 788, 489, 0, + 796, 638, 639, 797, 756, 755, 349, 0, 1043, 1044, + 713, 714, 0, 0, 1113, 488, 645, 0, 978, 341, + 342, 343, 1103, 345, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1030, 0, 0, 0, 0, + 0, 0, 0, 0, 508, 0, 0, 654, 688, 677, + 766, 641, 0, 0, 0, 0, 0, 0, 981, 0, + 0, 0, 401, 0, 0, 471, 692, 673, 684, 674, + 514, 659, 660, 661, 668, 413, 662, 798, 664, 633, + 665, 634, 666, 667, 1021, 691, 640, 551, 490, 0, + 708, 0, 0, 1104, 1114, 0, 0, 0, 0, 0, + 0, 0, 0, 1099, 0, 0, 0, 0, 0, 972, + 0, 0, 1010, 1080, 1079, 997, 1007, 0, 0, 372, + 270, 635, 762, 637, 636, 998, 0, 999, 1003, 1006, + 1002, 1000, 1001, 0, 1094, 0, 0, 0, 0, 0, + 0, 964, 976, 0, 982, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 973, 974, 0, 0, 0, 0, 1031, 0, 975, 0, + 977, 0, 0, 0, 0, 552, 580, 0, 594, 0, + 440, 441, 1026, 1004, 1008, 0, 0, 0, 0, 356, + 559, 577, 373, 546, 592, 378, 554, 570, 368, 507, + 542, 0, 0, 358, 575, 553, 485, 357, 0, 535, + 398, 415, 395, 505, 1005, 0, 1029, 1033, 394, 1120, + 1027, 585, 360, 0, 584, 504, 477, 571, 576, 486, + 479, 0, 359, 573, 484, 478, 454, 405, 1121, 455, + 456, 457, 458, 459, 460, 419, 1109, 475, 521, 420, + 492, 491, 493, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 430, 0, 0, 0, 0, 0, 616, 617, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 754, 1024, 0, 759, 0, + 588, 0, 0, 1101, 0, 0, 0, 557, 0, 0, + 461, 0, 0, 0, 1028, 0, 538, 510, 1117, 0, + 0, 536, 473, 572, 522, 578, 560, 586, 529, 523, + 350, 561, 397, 487, 369, 371, 787, 399, 402, 406, + 407, 498, 499, 516, 545, 564, 565, 566, 396, 383, + 537, 384, 416, 385, 351, 388, 387, 389, 547, 390, + 353, 517, 569, 0, 412, 533, 482, 354, 481, 518, + 568, 567, 370, 596, 603, 604, 696, 0, 609, 801, + 802, 803, 618, 0, 524, 366, 363, 0, 0, 0, + 392, 519, 379, 381, 382, 380, 513, 515, 623, 624, + 625, 627, 628, 629, 630, 0, 0, 0, 0, 631, + 697, 715, 681, 650, 611, 705, 647, 651, 652, 433, + 434, 435, 436, 718, 2272, 2271, 2273, 602, 462, 463, + 0, 404, 403, 483, 355, 0, 0, 451, 432, 525, + 361, 400, 453, 438, 464, 465, 466, 467, 468, 0, + 469, 470, 410, 340, 346, 795, 1098, 506, 720, 757, + 758, 642, 0, 1116, 1093, 1095, 1096, 1100, 1105, 1106, + 1107, 1108, 1110, 1112, 1115, 1119, 794, 0, 698, 712, + 799, 711, 791, 512, 0, 544, 709, 656, 0, 702, + 675, 676, 0, 703, 671, 707, 362, 439, 530, 587, + 0, 644, 0, 612, 615, 646, 733, 734, 735, 352, + 614, 737, 738, 739, 740, 741, 742, 743, 736, 1118, + 679, 655, 682, 593, 658, 657, 0, 0, 693, 1032, + 694, 695, 494, 495, 496, 497, 1102, 721, 377, 613, + 527, 528, 0, 680, 0, 0, 0, 0, 0, 0, + 0, 0, 685, 686, 683, 804, 0, 744, 745, 0, + 0, 607, 608, 409, 0, 626, 417, 376, 511, 411, + 591, 442, 0, 619, 687, 620, 531, 532, 748, 753, + 749, 750, 752, 773, 501, 431, 437, 548, 452, 474, + 534, 590, 509, 539, 374, 579, 550, 480, 672, 700, + 1127, 1097, 1126, 1128, 1129, 1125, 1130, 1131, 1111, 986, + 0, 1039, 1040, 1123, 1122, 1124, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 729, 728, 727, + 726, 725, 724, 723, 722, 0, 0, 669, 391, 792, + 786, 793, 774, 777, 776, 751, 993, 347, 649, 472, + 526, 408, 716, 717, 0, 772, 1087, 1050, 1051, 1052, + 983, 1053, 1047, 1048, 984, 1049, 1088, 1037, 1084, 1085, + 1012, 1042, 1054, 1083, 1055, 1086, 1013, 1089, 1132, 1133, + 1061, 1045, 303, 1134, 1058, 1090, 1082, 1081, 1056, 1038, + 1091, 1092, 1020, 1015, 1059, 1060, 1046, 1067, 1068, 1069, + 1072, 985, 1073, 1074, 1075, 1076, 1077, 1071, 1070, 1034, + 1035, 1036, 1062, 1063, 1065, 1066, 1041, 558, 1016, 1017, + 1018, 1019, 0, 0, 597, 598, 599, 622, 0, 600, + 581, 648, 418, 348, 562, 589, 789, 790, 0, 0, + 0, 0, 0, 0, 0, 699, 710, 746, 747, 0, + 760, 761, 763, 765, 1078, 767, 555, 556, 775, 0, + 0, 443, 364, 365, 502, 503, 541, 0, 444, 445, + 446, 450, 447, 448, 449, 1064, 770, 771, 768, 476, + 540, 563, 549, 788, 489, 0, 796, 638, 639, 797, + 756, 755, 349, 0, 1043, 1044, 713, 714, 0, 0, + 1113, 488, 645, 0, 978, 341, 342, 343, 1103, 345, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, + 246, 1030, 0, 0, 0, 0, 0, 0, 0, 0, + 508, 0, 0, 654, 688, 677, 766, 641, 0, 0, + 0, 0, 0, 0, 981, 0, 0, 0, 401, 0, + 0, 471, 692, 673, 684, 674, 514, 659, 660, 661, + 668, 413, 662, 798, 664, 633, 665, 634, 666, 667, + 1021, 691, 640, 551, 490, 0, 708, 0, 0, 1104, + 1114, 0, 0, 0, 0, 0, 0, 0, 0, 1099, + 0, 0, 0, 0, 0, 972, 0, 0, 1010, 1080, + 1079, 997, 1007, 0, 0, 372, 270, 635, 762, 637, + 636, 998, 0, 999, 1003, 1006, 1002, 1000, 1001, 0, + 1094, 0, 0, 0, 0, 0, 0, 964, 976, 0, + 982, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 973, 974, 0, 0, + 0, 0, 1031, 0, 975, 0, 977, 0, 0, 0, + 0, 552, 580, 0, 594, 0, 440, 441, 1026, 1004, + 1008, 0, 0, 0, 0, 356, 559, 577, 373, 546, + 592, 378, 554, 570, 368, 507, 542, 0, 0, 358, + 575, 553, 485, 357, 0, 535, 398, 415, 395, 505, + 1005, 0, 1029, 1033, 394, 1120, 1027, 585, 360, 0, + 584, 504, 477, 571, 576, 486, 479, 0, 359, 573, + 484, 478, 454, 405, 1121, 455, 456, 457, 458, 459, + 460, 419, 1109, 475, 521, 420, 492, 491, 493, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 430, 0, + 0, 0, 0, 0, 616, 617, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 754, 1024, 0, 759, 0, 588, 0, 0, 1101, + 0, 0, 0, 557, 0, 0, 461, 0, 0, 0, + 1028, 0, 538, 510, 1117, 0, 0, 536, 473, 572, + 522, 578, 560, 586, 529, 523, 350, 561, 397, 487, + 369, 371, 787, 399, 402, 406, 407, 498, 499, 516, + 545, 564, 565, 566, 396, 383, 537, 384, 416, 385, + 351, 388, 387, 389, 547, 390, 353, 517, 569, 0, + 412, 533, 482, 354, 481, 518, 568, 567, 370, 596, + 603, 604, 696, 0, 609, 801, 802, 803, 618, 0, + 524, 366, 363, 0, 0, 0, 392, 519, 379, 381, + 382, 380, 513, 515, 623, 624, 625, 627, 628, 629, + 630, 0, 0, 0, 0, 631, 697, 715, 681, 650, + 611, 705, 647, 651, 652, 433, 434, 435, 436, 718, + 0, 0, 0, 602, 462, 463, 0, 404, 403, 483, + 355, 0, 0, 451, 432, 525, 361, 400, 453, 438, + 464, 465, 466, 467, 468, 0, 469, 470, 410, 340, + 346, 795, 1098, 506, 720, 757, 758, 642, 0, 1116, + 1093, 1095, 1096, 1100, 1105, 1106, 1107, 1108, 1110, 1112, + 1115, 1119, 794, 0, 698, 712, 799, 711, 791, 512, + 0, 544, 709, 656, 0, 702, 675, 676, 0, 703, + 671, 707, 362, 439, 530, 587, 0, 644, 0, 612, + 615, 646, 733, 734, 735, 352, 614, 737, 738, 739, + 740, 741, 742, 743, 736, 1118, 679, 655, 682, 593, + 658, 657, 0, 0, 693, 1032, 694, 695, 494, 495, + 496, 497, 1102, 721, 377, 613, 527, 528, 0, 680, + 0, 0, 0, 0, 0, 0, 0, 0, 685, 686, + 683, 804, 0, 744, 745, 0, 0, 607, 608, 409, + 0, 626, 417, 376, 511, 411, 591, 442, 0, 619, + 687, 620, 531, 532, 748, 753, 749, 750, 752, 773, + 501, 431, 437, 548, 452, 474, 534, 590, 509, 539, + 374, 579, 550, 480, 672, 700, 1127, 1097, 1126, 1128, + 1129, 1125, 1130, 1131, 1111, 986, 0, 1039, 1040, 1123, + 1122, 1124, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 729, 728, 727, 726, 725, 724, 723, + 722, 0, 0, 669, 391, 792, 786, 793, 774, 777, + 776, 751, 993, 347, 649, 472, 526, 408, 716, 717, + 0, 772, 1087, 1050, 1051, 1052, 983, 1053, 1047, 1048, + 984, 1049, 1088, 1037, 1084, 1085, 1012, 1042, 1054, 1083, + 1055, 1086, 1013, 1089, 1132, 1133, 1061, 1045, 303, 1134, + 1058, 1090, 1082, 1081, 1056, 1038, 1091, 1092, 1020, 1015, + 1059, 1060, 1046, 1067, 1068, 1069, 1072, 985, 1073, 1074, + 1075, 1076, 1077, 1071, 1070, 1034, 1035, 1036, 1062, 1063, + 1065, 1066, 1041, 558, 1016, 1017, 1018, 1019, 0, 0, + 597, 598, 599, 622, 0, 600, 581, 648, 418, 348, + 562, 589, 789, 790, 0, 0, 0, 0, 0, 0, + 0, 699, 710, 746, 747, 0, 760, 761, 763, 765, + 1078, 767, 555, 556, 775, 0, 0, 443, 364, 365, + 502, 503, 541, 0, 444, 445, 446, 450, 447, 448, + 449, 1064, 770, 771, 768, 476, 540, 563, 549, 788, + 489, 0, 796, 638, 639, 797, 756, 755, 349, 0, + 1043, 1044, 713, 714, 0, 0, 1113, 488, 645, 0, + 978, 341, 342, 343, 1103, 345, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1030, 0, 0, + 0, 0, 0, 0, 0, 0, 508, 0, 0, 654, + 688, 677, 766, 641, 0, 0, 0, 0, 0, 0, + 981, 0, 0, 0, 401, 2344, 0, 471, 692, 673, + 684, 674, 514, 659, 660, 661, 668, 413, 662, 798, + 664, 633, 665, 634, 666, 667, 1021, 691, 640, 551, + 490, 0, 708, 0, 0, 1104, 1114, 0, 0, 0, + 0, 0, 0, 0, 0, 1099, 0, 2601, 0, 0, + 0, 972, 0, 0, 1010, 1080, 1079, 997, 1007, 0, + 0, 372, 270, 635, 762, 637, 636, 998, 0, 999, + 1003, 1006, 1002, 1000, 1001, 0, 1094, 0, 0, 0, + 0, 0, 0, 964, 976, 0, 982, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 973, 974, 0, 0, 0, 0, 1031, 0, + 975, 0, 977, 0, 0, 0, 0, 552, 580, 0, + 594, 0, 440, 441, 2602, 1004, 1008, 0, 0, 0, + 0, 356, 559, 577, 373, 546, 592, 378, 554, 570, + 368, 507, 542, 0, 0, 358, 575, 553, 485, 357, + 0, 535, 398, 415, 395, 505, 1005, 0, 1029, 1033, + 394, 1120, 1027, 585, 360, 0, 584, 504, 477, 571, + 576, 486, 479, 0, 359, 573, 484, 478, 454, 405, + 1121, 455, 456, 457, 458, 459, 460, 419, 1109, 475, + 521, 420, 492, 491, 493, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 430, 0, 0, 0, 0, 0, + 616, 617, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 754, 1024, 0, + 759, 0, 588, 0, 0, 1101, 0, 0, 0, 557, + 0, 0, 461, 0, 0, 0, 1028, 0, 538, 510, + 1117, 0, 0, 536, 473, 572, 522, 578, 560, 586, + 529, 523, 350, 561, 397, 487, 369, 371, 787, 399, + 402, 406, 407, 498, 499, 516, 545, 564, 565, 566, + 396, 383, 537, 384, 416, 385, 351, 388, 387, 389, + 547, 390, 353, 517, 569, 0, 412, 533, 482, 354, + 481, 518, 568, 567, 370, 596, 603, 604, 696, 0, + 609, 801, 802, 803, 618, 0, 524, 366, 363, 0, + 0, 0, 392, 519, 379, 381, 382, 380, 513, 515, + 623, 624, 625, 627, 628, 629, 630, 0, 0, 0, + 0, 631, 697, 715, 681, 650, 611, 705, 647, 651, + 652, 433, 434, 435, 436, 718, 0, 0, 0, 602, + 462, 463, 0, 404, 403, 483, 355, 0, 0, 451, + 432, 525, 361, 400, 453, 438, 464, 465, 466, 467, + 468, 0, 469, 470, 410, 340, 346, 795, 1098, 506, + 720, 757, 758, 642, 0, 1116, 1093, 1095, 1096, 1100, + 1105, 1106, 1107, 1108, 1110, 1112, 1115, 1119, 794, 0, + 698, 712, 799, 711, 791, 512, 0, 544, 709, 656, + 0, 702, 675, 676, 0, 703, 671, 707, 362, 439, + 530, 587, 0, 644, 0, 612, 615, 646, 733, 734, + 735, 352, 614, 737, 738, 739, 740, 741, 742, 743, + 736, 1118, 679, 655, 682, 593, 658, 657, 0, 0, + 693, 1032, 694, 695, 494, 495, 496, 497, 1102, 721, + 377, 613, 527, 528, 0, 680, 0, 0, 0, 0, + 0, 0, 0, 0, 685, 686, 683, 804, 0, 744, + 745, 0, 0, 607, 608, 409, 0, 626, 417, 376, + 511, 411, 591, 442, 0, 619, 687, 620, 531, 532, + 748, 753, 749, 750, 752, 773, 501, 431, 437, 548, + 452, 474, 534, 590, 509, 539, 374, 579, 550, 480, + 672, 700, 1127, 1097, 1126, 1128, 1129, 1125, 1130, 1131, + 1111, 986, 0, 1039, 1040, 1123, 1122, 1124, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 729, + 728, 727, 726, 725, 724, 723, 722, 0, 0, 669, + 391, 792, 786, 793, 774, 777, 776, 751, 993, 347, + 649, 472, 526, 408, 716, 717, 0, 772, 1087, 1050, + 1051, 1052, 983, 1053, 1047, 1048, 984, 1049, 1088, 1037, + 1084, 1085, 1012, 1042, 1054, 1083, 1055, 1086, 1013, 1089, + 1132, 1133, 1061, 1045, 303, 1134, 1058, 1090, 1082, 1081, + 1056, 1038, 1091, 1092, 1020, 1015, 1059, 1060, 1046, 1067, + 1068, 1069, 1072, 985, 1073, 1074, 1075, 1076, 1077, 1071, + 1070, 1034, 1035, 1036, 1062, 1063, 1065, 1066, 1041, 558, + 1016, 1017, 1018, 1019, 0, 0, 597, 598, 599, 622, + 0, 600, 581, 648, 418, 348, 562, 589, 789, 790, + 0, 0, 0, 0, 0, 0, 0, 699, 710, 746, + 747, 0, 760, 761, 763, 765, 1078, 767, 555, 556, + 775, 0, 0, 443, 364, 365, 502, 503, 541, 0, + 444, 445, 446, 450, 447, 448, 449, 1064, 770, 771, + 768, 476, 540, 563, 549, 788, 489, 0, 796, 638, + 639, 797, 756, 755, 349, 0, 1043, 1044, 713, 714, + 0, 0, 1113, 488, 645, 0, 978, 341, 342, 343, + 1103, 345, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1030, 0, 0, 0, 0, 0, 0, + 0, 0, 508, 0, 0, 654, 688, 677, 766, 641, + 0, 0, 0, 0, 0, 0, 981, 0, 0, 0, + 401, 5455, 0, 471, 692, 673, 684, 674, 514, 659, + 660, 661, 668, 413, 662, 798, 664, 633, 665, 634, + 666, 667, 1021, 691, 640, 551, 490, 0, 708, 0, + 0, 1104, 1114, 0, 0, 0, 0, 0, 0, 0, + 0, 1099, 0, 0, 0, 0, 0, 972, 0, 0, + 1010, 1080, 1079, 997, 1007, 0, 0, 372, 270, 635, + 762, 637, 636, 998, 0, 999, 1003, 1006, 1002, 1000, + 1001, 0, 1094, 0, 0, 0, 0, 0, 0, 964, + 976, 0, 982, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 973, 974, + 0, 0, 0, 0, 1031, 0, 975, 0, 977, 0, + 0, 0, 0, 552, 580, 0, 594, 0, 440, 441, + 1026, 1004, 1008, 0, 0, 0, 0, 356, 559, 577, + 373, 546, 592, 378, 554, 570, 368, 507, 542, 0, + 0, 358, 575, 553, 485, 357, 0, 535, 398, 415, + 395, 505, 1005, 0, 1029, 1033, 394, 1120, 1027, 585, + 360, 0, 584, 504, 477, 571, 576, 486, 479, 0, + 359, 573, 484, 478, 454, 405, 1121, 455, 456, 457, + 458, 459, 460, 419, 1109, 475, 521, 420, 492, 491, + 493, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 430, 0, 0, 0, 0, 0, 616, 617, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 754, 1024, 0, 759, 0, 588, 0, + 0, 1101, 0, 0, 0, 557, 0, 0, 461, 0, + 0, 0, 1028, 0, 538, 510, 1117, 0, 0, 536, + 473, 572, 522, 578, 560, 586, 529, 523, 350, 561, + 397, 487, 369, 371, 787, 399, 402, 406, 407, 498, + 499, 516, 545, 564, 565, 566, 396, 383, 537, 384, + 416, 385, 351, 388, 387, 389, 547, 390, 353, 517, + 569, 0, 412, 533, 482, 354, 481, 518, 568, 567, + 370, 596, 603, 604, 696, 0, 609, 801, 802, 803, + 618, 0, 524, 366, 363, 0, 0, 0, 392, 519, + 379, 381, 382, 380, 513, 515, 623, 624, 625, 627, + 628, 629, 630, 0, 0, 0, 0, 631, 697, 715, + 681, 650, 611, 705, 647, 651, 652, 433, 434, 435, + 436, 718, 0, 0, 0, 602, 462, 463, 0, 404, + 403, 483, 355, 0, 0, 451, 432, 525, 361, 400, + 453, 438, 464, 465, 466, 467, 468, 0, 469, 470, + 410, 340, 346, 795, 1098, 506, 720, 757, 758, 642, + 0, 1116, 1093, 1095, 1096, 1100, 1105, 1106, 1107, 1108, + 1110, 1112, 1115, 1119, 794, 0, 698, 712, 799, 711, + 791, 512, 0, 544, 709, 656, 0, 702, 675, 676, + 0, 703, 671, 707, 362, 439, 530, 587, 0, 644, + 0, 612, 615, 646, 733, 734, 735, 352, 614, 737, + 738, 739, 740, 741, 742, 743, 736, 1118, 679, 655, + 682, 593, 658, 657, 0, 0, 693, 1032, 694, 695, + 494, 495, 496, 497, 1102, 721, 377, 613, 527, 528, + 0, 680, 0, 0, 0, 0, 0, 0, 0, 0, + 685, 686, 683, 804, 0, 744, 745, 0, 0, 607, + 608, 409, 0, 626, 417, 376, 511, 411, 591, 442, + 0, 619, 687, 620, 531, 532, 748, 753, 749, 750, + 752, 773, 501, 431, 437, 548, 452, 474, 534, 590, + 509, 539, 374, 579, 550, 480, 672, 700, 1127, 1097, + 1126, 1128, 1129, 1125, 1130, 1131, 1111, 986, 0, 1039, + 1040, 1123, 1122, 1124, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 729, 728, 727, 726, 725, + 724, 723, 722, 0, 0, 669, 391, 792, 786, 793, + 774, 777, 776, 751, 993, 347, 649, 472, 526, 408, + 716, 717, 0, 772, 1087, 1050, 1051, 1052, 983, 1053, + 1047, 1048, 984, 1049, 1088, 1037, 1084, 1085, 1012, 1042, + 1054, 1083, 1055, 1086, 1013, 1089, 1132, 1133, 1061, 1045, + 303, 1134, 1058, 1090, 1082, 1081, 1056, 1038, 1091, 1092, + 1020, 1015, 1059, 1060, 1046, 1067, 1068, 1069, 1072, 985, + 1073, 1074, 1075, 1076, 1077, 1071, 1070, 1034, 1035, 1036, + 1062, 1063, 1065, 1066, 1041, 558, 1016, 1017, 1018, 1019, + 0, 0, 597, 598, 599, 622, 0, 600, 581, 648, + 418, 348, 562, 589, 789, 790, 0, 0, 0, 0, + 0, 0, 0, 699, 710, 746, 747, 0, 760, 761, + 763, 765, 1078, 767, 555, 556, 775, 0, 0, 443, + 364, 365, 502, 503, 541, 0, 444, 445, 446, 450, + 447, 448, 449, 1064, 770, 771, 768, 476, 540, 563, + 549, 788, 489, 0, 796, 638, 639, 797, 756, 755, + 349, 0, 1043, 1044, 713, 714, 0, 0, 1113, 488, + 645, 0, 978, 341, 342, 343, 1103, 345, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1030, + 0, 0, 0, 0, 0, 0, 0, 0, 508, 0, + 0, 654, 688, 677, 766, 641, 0, 0, 0, 0, + 0, 0, 981, 0, 0, 0, 401, 0, 0, 471, + 692, 673, 684, 674, 514, 659, 660, 661, 668, 413, + 662, 798, 664, 633, 665, 634, 666, 667, 1021, 691, + 640, 551, 490, 0, 708, 0, 0, 1104, 1114, 0, + 0, 0, 0, 0, 0, 0, 0, 1099, 0, 0, + 0, 0, 0, 972, 0, 0, 1010, 1080, 1079, 997, + 1007, 0, 0, 372, 270, 635, 762, 637, 636, 998, + 0, 999, 1003, 1006, 1002, 1000, 1001, 0, 1094, 0, + 0, 0, 0, 0, 0, 964, 976, 0, 982, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 973, 974, 0, 0, 0, 0, + 1031, 0, 975, 0, 977, 0, 0, 0, 0, 552, + 580, 0, 594, 0, 440, 441, 1026, 1004, 1008, 0, + 0, 0, 0, 356, 559, 577, 373, 546, 592, 378, + 554, 570, 368, 507, 542, 0, 0, 358, 575, 553, + 485, 357, 0, 535, 398, 415, 395, 505, 1005, 0, + 1029, 1033, 394, 1120, 1027, 585, 360, 0, 584, 504, + 477, 571, 576, 486, 479, 0, 359, 573, 484, 478, + 454, 405, 1121, 455, 456, 457, 458, 459, 460, 419, + 1109, 475, 521, 420, 492, 491, 493, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 430, 0, 0, 0, + 0, 0, 616, 617, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 754, + 1024, 0, 759, 0, 588, 0, 0, 1101, 0, 0, + 0, 557, 0, 0, 461, 0, 0, 0, 1028, 0, + 538, 510, 1117, 5250, 0, 536, 473, 572, 522, 578, + 560, 586, 529, 523, 350, 561, 397, 487, 369, 371, + 787, 399, 402, 406, 407, 498, 499, 516, 545, 564, + 565, 566, 396, 383, 537, 384, 416, 385, 351, 388, + 387, 389, 547, 390, 353, 517, 569, 0, 412, 533, + 482, 354, 481, 518, 568, 567, 370, 596, 603, 604, + 696, 0, 609, 801, 802, 803, 618, 0, 524, 366, + 363, 0, 0, 0, 392, 519, 379, 381, 382, 380, + 513, 515, 623, 624, 625, 627, 628, 629, 630, 0, + 0, 0, 0, 631, 697, 715, 681, 650, 611, 705, + 647, 651, 652, 433, 434, 435, 436, 718, 0, 0, + 0, 602, 462, 463, 0, 404, 403, 483, 355, 0, + 0, 451, 432, 525, 361, 400, 453, 438, 464, 465, + 466, 467, 468, 0, 469, 470, 410, 340, 346, 795, + 1098, 506, 720, 757, 758, 642, 0, 1116, 1093, 1095, + 1096, 1100, 1105, 1106, 1107, 1108, 1110, 1112, 1115, 1119, + 794, 0, 698, 712, 799, 711, 791, 512, 0, 544, + 709, 656, 0, 702, 675, 676, 0, 703, 671, 707, + 362, 439, 530, 587, 0, 644, 0, 612, 615, 646, + 733, 734, 735, 352, 614, 737, 738, 739, 740, 741, + 742, 743, 736, 1118, 679, 655, 682, 593, 658, 657, + 0, 0, 693, 1032, 694, 695, 494, 495, 496, 497, + 1102, 721, 377, 613, 527, 528, 0, 680, 0, 0, + 0, 0, 0, 0, 0, 0, 685, 686, 683, 804, + 0, 744, 745, 0, 0, 607, 608, 409, 0, 626, + 417, 376, 511, 411, 591, 442, 0, 619, 687, 620, + 531, 532, 748, 753, 749, 750, 752, 773, 501, 431, + 437, 548, 452, 474, 534, 590, 509, 539, 374, 579, + 550, 480, 672, 700, 1127, 1097, 1126, 1128, 1129, 1125, + 1130, 1131, 1111, 986, 0, 1039, 1040, 1123, 1122, 1124, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 729, 728, 727, 726, 725, 724, 723, 722, 0, + 0, 669, 391, 792, 786, 793, 774, 777, 776, 751, + 993, 347, 649, 472, 526, 408, 716, 717, 0, 772, + 1087, 1050, 1051, 1052, 983, 1053, 1047, 1048, 984, 1049, + 1088, 1037, 1084, 1085, 1012, 1042, 1054, 1083, 1055, 1086, + 1013, 1089, 1132, 1133, 1061, 1045, 303, 1134, 1058, 1090, + 1082, 1081, 1056, 1038, 1091, 1092, 1020, 1015, 1059, 1060, + 1046, 1067, 1068, 1069, 1072, 985, 1073, 1074, 1075, 1076, + 1077, 1071, 1070, 1034, 1035, 1036, 1062, 1063, 1065, 1066, + 1041, 558, 1016, 1017, 1018, 1019, 0, 0, 597, 598, + 599, 622, 0, 600, 581, 648, 418, 348, 562, 589, + 789, 790, 0, 0, 0, 0, 0, 0, 0, 699, + 710, 746, 747, 0, 760, 761, 763, 765, 1078, 767, + 555, 556, 775, 0, 0, 443, 364, 365, 502, 503, + 541, 0, 444, 445, 446, 450, 447, 448, 449, 1064, + 770, 771, 768, 476, 540, 563, 549, 788, 489, 0, + 796, 638, 639, 797, 756, 755, 349, 0, 1043, 1044, + 713, 714, 0, 0, 1113, 488, 645, 0, 978, 341, + 342, 343, 1103, 345, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1030, 0, 0, 0, 0, + 0, 0, 0, 0, 508, 0, 0, 654, 688, 677, + 766, 641, 0, 0, 0, 0, 0, 0, 981, 0, + 0, 0, 401, 0, 0, 471, 692, 673, 684, 674, + 514, 659, 660, 661, 668, 413, 662, 798, 664, 633, + 665, 634, 666, 667, 1021, 691, 640, 551, 490, 0, + 708, 0, 0, 1104, 1114, 0, 0, 0, 0, 0, + 0, 0, 0, 1099, 0, 0, 0, 0, 0, 972, + 0, 0, 1010, 1080, 1079, 997, 1007, 0, 0, 372, + 270, 635, 762, 637, 636, 998, 0, 999, 1003, 1006, + 1002, 1000, 1001, 0, 1094, 0, 0, 0, 0, 0, + 0, 964, 976, 0, 982, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 973, 974, 1938, 0, 0, 0, 1031, 0, 975, 0, + 977, 0, 0, 0, 0, 552, 580, 0, 594, 0, + 440, 441, 1026, 1004, 1008, 0, 0, 0, 0, 356, + 559, 577, 373, 546, 592, 378, 554, 570, 368, 507, + 542, 0, 0, 358, 575, 553, 485, 357, 0, 535, + 398, 415, 395, 505, 1005, 0, 1029, 1033, 394, 1120, + 1027, 585, 360, 0, 584, 504, 477, 571, 576, 486, + 479, 0, 359, 573, 484, 478, 454, 405, 1121, 455, + 456, 457, 458, 459, 460, 419, 1109, 475, 521, 420, + 492, 491, 493, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 430, 0, 0, 0, 0, 0, 616, 617, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 754, 1024, 0, 759, 0, + 588, 0, 0, 1101, 0, 0, 0, 557, 0, 0, + 461, 0, 0, 0, 1028, 0, 538, 510, 1117, 0, + 0, 536, 473, 572, 522, 578, 560, 586, 529, 523, + 350, 561, 397, 487, 369, 371, 787, 399, 402, 406, + 407, 498, 499, 516, 545, 564, 565, 566, 396, 383, + 537, 384, 416, 385, 351, 388, 387, 389, 547, 390, + 353, 517, 569, 0, 412, 533, 482, 354, 481, 518, + 568, 567, 370, 596, 603, 604, 696, 0, 609, 801, + 802, 803, 618, 0, 524, 366, 363, 0, 0, 0, + 392, 519, 379, 381, 382, 380, 513, 515, 623, 624, + 625, 627, 628, 629, 630, 0, 0, 0, 0, 631, + 697, 715, 681, 650, 611, 705, 647, 651, 652, 433, + 434, 435, 436, 718, 0, 0, 0, 602, 462, 463, + 0, 404, 403, 483, 355, 0, 0, 451, 432, 525, + 361, 400, 453, 438, 464, 465, 466, 467, 468, 0, + 469, 470, 410, 340, 346, 795, 1098, 506, 720, 757, + 758, 642, 0, 1116, 1093, 1095, 1096, 1100, 1105, 1106, + 1107, 1108, 1110, 1112, 1115, 1119, 794, 0, 698, 712, + 799, 711, 791, 512, 0, 544, 709, 656, 0, 702, + 675, 676, 0, 703, 671, 707, 362, 439, 530, 587, + 0, 644, 0, 612, 615, 646, 733, 734, 735, 352, + 614, 737, 738, 739, 740, 741, 742, 743, 736, 1118, + 679, 655, 682, 593, 658, 657, 0, 0, 693, 1032, + 694, 695, 494, 495, 496, 497, 1102, 721, 377, 613, + 527, 528, 0, 680, 0, 0, 0, 0, 0, 0, + 0, 0, 685, 686, 683, 804, 0, 744, 745, 0, + 0, 607, 608, 409, 0, 626, 417, 376, 511, 411, + 591, 442, 0, 619, 687, 620, 531, 532, 748, 753, + 749, 750, 752, 773, 501, 431, 437, 548, 452, 474, + 534, 590, 509, 539, 374, 579, 550, 480, 672, 700, + 1127, 1097, 1126, 1128, 1129, 1125, 1130, 1131, 1111, 986, + 0, 1039, 1040, 1123, 1122, 1124, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 729, 728, 727, + 726, 725, 724, 723, 722, 0, 0, 669, 391, 792, + 786, 793, 774, 777, 776, 751, 993, 347, 649, 472, + 526, 408, 716, 717, 0, 772, 1087, 1050, 1051, 1052, + 983, 1053, 1047, 1048, 984, 1049, 1088, 1037, 1084, 1085, + 1012, 1042, 1054, 1083, 1055, 1086, 1013, 1089, 1132, 1133, + 1061, 1045, 303, 1134, 1058, 1090, 1082, 1081, 1056, 1038, + 1091, 1092, 1020, 1015, 1059, 1060, 1046, 1067, 1068, 1069, + 1072, 985, 1073, 1074, 1075, 1076, 1077, 1071, 1070, 1034, + 1035, 1036, 1062, 1063, 1065, 1066, 1041, 558, 1016, 1017, + 1018, 1019, 0, 0, 597, 598, 599, 622, 0, 600, + 581, 648, 418, 348, 562, 589, 789, 790, 0, 0, + 0, 0, 0, 0, 0, 699, 710, 746, 747, 0, + 760, 761, 763, 765, 1078, 767, 555, 556, 775, 0, + 0, 443, 364, 365, 502, 503, 541, 0, 444, 445, + 446, 450, 447, 448, 449, 1064, 770, 771, 768, 476, + 540, 563, 549, 788, 489, 0, 796, 638, 639, 797, + 756, 755, 349, 0, 1043, 1044, 713, 714, 0, 0, + 1113, 488, 645, 0, 978, 341, 342, 343, 1103, 345, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1030, 0, 0, 0, 0, 0, 0, 0, 0, + 508, 0, 0, 654, 688, 677, 766, 641, 0, 0, + 0, 0, 0, 0, 981, 0, 0, 0, 401, 2344, + 0, 471, 692, 673, 684, 674, 514, 659, 660, 661, + 668, 413, 662, 798, 664, 633, 665, 634, 666, 667, + 1021, 691, 640, 551, 490, 0, 708, 0, 0, 1104, + 1114, 0, 0, 0, 0, 0, 0, 0, 0, 1099, + 0, 0, 0, 0, 0, 972, 0, 0, 1010, 1080, + 1079, 997, 1007, 0, 0, 372, 270, 635, 762, 637, + 636, 998, 0, 999, 1003, 1006, 1002, 1000, 1001, 0, + 1094, 0, 0, 0, 0, 0, 0, 964, 976, 0, + 982, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 973, 974, 0, 0, + 0, 0, 1031, 0, 975, 0, 977, 0, 0, 0, + 0, 552, 580, 0, 594, 0, 440, 441, 1026, 1004, + 1008, 0, 0, 0, 0, 356, 559, 577, 373, 546, + 592, 378, 554, 570, 368, 507, 542, 0, 0, 358, + 575, 553, 485, 357, 0, 535, 398, 415, 395, 505, + 1005, 0, 1029, 1033, 394, 1120, 1027, 585, 360, 0, + 584, 504, 477, 571, 576, 486, 479, 0, 359, 573, + 484, 478, 454, 405, 1121, 455, 456, 457, 458, 459, + 460, 419, 1109, 475, 521, 420, 492, 491, 493, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 430, 0, + 0, 0, 0, 0, 616, 617, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 754, 1024, 0, 759, 0, 588, 0, 0, 1101, + 0, 0, 0, 557, 0, 0, 461, 0, 0, 0, + 1028, 0, 538, 510, 1117, 0, 0, 536, 473, 572, + 522, 578, 560, 586, 529, 523, 350, 561, 397, 487, + 369, 371, 787, 399, 402, 406, 407, 498, 499, 516, + 545, 564, 565, 566, 396, 383, 537, 384, 416, 385, + 351, 388, 387, 389, 547, 390, 353, 517, 569, 0, + 412, 533, 482, 354, 481, 518, 568, 567, 370, 596, + 603, 604, 696, 0, 609, 801, 802, 803, 618, 0, + 524, 366, 363, 0, 0, 0, 392, 519, 379, 381, + 382, 380, 513, 515, 623, 624, 625, 627, 628, 629, + 630, 0, 0, 0, 0, 631, 697, 715, 681, 650, + 611, 705, 647, 651, 652, 433, 434, 435, 436, 718, + 0, 0, 0, 602, 462, 463, 0, 404, 403, 483, + 355, 0, 0, 451, 432, 525, 361, 400, 453, 438, + 464, 465, 466, 467, 468, 0, 469, 470, 410, 340, + 346, 795, 1098, 506, 720, 757, 758, 642, 0, 1116, + 1093, 1095, 1096, 1100, 1105, 1106, 1107, 1108, 1110, 1112, + 1115, 1119, 794, 0, 698, 712, 799, 711, 791, 512, + 0, 544, 709, 656, 0, 702, 675, 676, 0, 703, + 671, 707, 362, 439, 530, 587, 0, 644, 0, 612, + 615, 646, 733, 734, 735, 352, 614, 737, 738, 739, + 740, 741, 742, 743, 736, 1118, 679, 655, 682, 593, + 658, 657, 0, 0, 693, 1032, 694, 695, 494, 495, + 496, 497, 1102, 721, 377, 613, 527, 528, 0, 680, + 0, 0, 0, 0, 0, 0, 0, 0, 685, 686, + 683, 804, 0, 744, 745, 0, 0, 607, 608, 409, + 0, 626, 417, 376, 511, 411, 591, 442, 0, 619, + 687, 620, 531, 532, 748, 753, 749, 750, 752, 773, + 501, 431, 437, 548, 452, 474, 534, 590, 509, 539, + 374, 579, 550, 480, 672, 700, 1127, 1097, 1126, 1128, + 1129, 1125, 1130, 1131, 1111, 986, 0, 1039, 1040, 1123, + 1122, 1124, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 729, 728, 727, 726, 725, 724, 723, + 722, 0, 0, 669, 391, 792, 786, 793, 774, 777, + 776, 751, 993, 347, 649, 472, 526, 408, 716, 717, + 0, 772, 1087, 1050, 1051, 1052, 983, 1053, 1047, 1048, + 984, 1049, 1088, 1037, 1084, 1085, 1012, 1042, 1054, 1083, + 1055, 1086, 1013, 1089, 1132, 1133, 1061, 1045, 303, 1134, + 1058, 1090, 1082, 1081, 1056, 1038, 1091, 1092, 1020, 1015, + 1059, 1060, 1046, 1067, 1068, 1069, 1072, 985, 1073, 1074, + 1075, 1076, 1077, 1071, 1070, 1034, 1035, 1036, 1062, 1063, + 1065, 1066, 1041, 558, 1016, 1017, 1018, 1019, 0, 0, + 597, 598, 599, 622, 0, 600, 581, 648, 418, 348, + 562, 589, 789, 790, 0, 0, 0, 0, 0, 0, + 0, 699, 710, 746, 747, 0, 760, 761, 763, 765, + 1078, 767, 555, 556, 775, 0, 0, 443, 364, 365, + 502, 503, 541, 0, 444, 445, 446, 450, 447, 448, + 449, 1064, 770, 771, 768, 476, 540, 563, 549, 788, + 489, 0, 796, 638, 639, 797, 756, 755, 349, 0, + 1043, 1044, 713, 714, 0, 0, 1113, 488, 645, 0, + 978, 341, 342, 343, 1103, 345, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1030, 0, 0, + 2850, 0, 0, 0, 0, 0, 508, 0, 0, 654, + 688, 677, 766, 641, 0, 0, 0, 0, 0, 0, + 981, 0, 0, 0, 401, 0, 0, 471, 692, 673, + 684, 674, 514, 659, 660, 661, 668, 413, 662, 798, + 664, 633, 665, 634, 666, 667, 1021, 691, 640, 551, + 490, 0, 708, 0, 0, 1104, 1114, 0, 0, 0, + 0, 0, 0, 0, 0, 1099, 0, 0, 0, 0, + 0, 972, 0, 0, 1010, 1080, 1079, 997, 1007, 0, + 0, 372, 270, 635, 762, 637, 636, 998, 0, 999, + 1003, 1006, 1002, 1000, 1001, 0, 1094, 0, 0, 0, + 0, 0, 0, 964, 976, 0, 982, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 973, 974, 0, 0, 0, 0, 1031, 0, + 975, 0, 977, 0, 0, 0, 0, 552, 580, 0, + 594, 0, 440, 441, 1026, 1004, 1008, 0, 0, 0, + 0, 356, 559, 577, 373, 546, 592, 378, 554, 570, + 368, 507, 542, 0, 0, 358, 575, 553, 485, 357, + 0, 535, 398, 415, 395, 505, 1005, 0, 1029, 1033, + 394, 1120, 1027, 585, 360, 0, 584, 504, 477, 571, + 576, 486, 479, 0, 359, 573, 484, 478, 454, 405, + 1121, 455, 456, 457, 458, 459, 460, 419, 1109, 475, + 521, 420, 492, 491, 493, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 430, 0, 0, 0, 0, 0, + 616, 617, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 754, 1024, 0, + 759, 0, 588, 0, 0, 1101, 0, 0, 0, 557, + 0, 0, 461, 0, 0, 0, 1028, 0, 538, 510, + 1117, 0, 0, 536, 473, 572, 522, 578, 560, 586, + 529, 523, 350, 561, 397, 487, 369, 371, 787, 399, + 402, 406, 407, 498, 499, 516, 545, 564, 565, 566, + 396, 383, 537, 384, 416, 385, 351, 388, 387, 389, + 547, 390, 353, 517, 569, 0, 412, 533, 482, 354, + 481, 518, 568, 567, 370, 596, 603, 604, 696, 0, + 609, 801, 802, 803, 618, 0, 524, 366, 363, 0, + 0, 0, 392, 519, 379, 381, 382, 380, 513, 515, + 623, 624, 625, 627, 628, 629, 630, 0, 0, 0, + 0, 631, 697, 715, 681, 650, 611, 705, 647, 651, + 652, 433, 434, 435, 436, 718, 0, 0, 0, 602, + 462, 463, 0, 404, 403, 483, 355, 0, 0, 451, + 432, 525, 361, 400, 453, 438, 464, 465, 466, 467, + 468, 0, 469, 470, 410, 340, 346, 795, 1098, 506, + 720, 757, 758, 642, 0, 1116, 1093, 1095, 1096, 1100, + 1105, 1106, 1107, 1108, 1110, 1112, 1115, 1119, 794, 0, + 698, 712, 799, 711, 791, 512, 0, 544, 709, 656, + 0, 702, 675, 676, 0, 703, 671, 707, 362, 439, + 530, 587, 0, 644, 0, 612, 615, 646, 733, 734, + 735, 352, 614, 737, 738, 739, 740, 741, 742, 743, + 736, 1118, 679, 655, 682, 593, 658, 657, 0, 0, + 693, 1032, 694, 695, 494, 495, 496, 497, 1102, 721, + 377, 613, 527, 528, 0, 680, 0, 0, 0, 0, + 0, 0, 0, 0, 685, 686, 683, 804, 0, 744, + 745, 0, 0, 607, 608, 409, 0, 626, 417, 376, + 511, 411, 591, 442, 0, 619, 687, 620, 531, 532, + 748, 753, 749, 750, 752, 773, 501, 431, 437, 548, + 452, 474, 534, 590, 509, 539, 374, 579, 550, 480, + 672, 700, 1127, 1097, 1126, 1128, 1129, 1125, 1130, 1131, + 1111, 986, 0, 1039, 1040, 1123, 1122, 1124, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 729, + 728, 727, 726, 725, 724, 723, 722, 0, 0, 669, + 391, 792, 786, 793, 774, 777, 776, 751, 993, 347, + 649, 472, 526, 408, 716, 717, 0, 772, 1087, 1050, + 1051, 1052, 983, 1053, 1047, 1048, 984, 1049, 1088, 1037, + 1084, 1085, 1012, 1042, 1054, 1083, 1055, 1086, 1013, 1089, + 1132, 1133, 1061, 1045, 303, 1134, 1058, 1090, 1082, 1081, + 1056, 1038, 1091, 1092, 1020, 1015, 1059, 1060, 1046, 1067, + 1068, 1069, 1072, 985, 1073, 1074, 1075, 1076, 1077, 1071, + 1070, 1034, 1035, 1036, 1062, 1063, 1065, 1066, 1041, 558, + 1016, 1017, 1018, 1019, 0, 0, 597, 598, 599, 622, + 0, 600, 581, 648, 418, 348, 562, 589, 789, 790, + 0, 0, 0, 0, 0, 0, 0, 699, 710, 746, + 747, 0, 760, 761, 763, 765, 1078, 767, 555, 556, + 775, 0, 0, 443, 364, 365, 502, 503, 541, 0, + 444, 445, 446, 450, 447, 448, 449, 1064, 770, 771, + 768, 476, 540, 563, 549, 788, 489, 0, 796, 638, + 639, 797, 756, 755, 349, 0, 1043, 1044, 713, 714, + 0, 0, 1113, 488, 645, 0, 978, 341, 342, 343, + 1103, 345, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1030, 0, 0, 0, 0, 0, 0, + 0, 0, 508, 0, 0, 654, 688, 677, 766, 641, + 0, 0, 0, 0, 0, 0, 981, 0, 0, 0, + 401, 0, 0, 471, 692, 673, 684, 674, 514, 659, + 660, 661, 668, 413, 662, 798, 664, 633, 665, 634, + 666, 667, 1021, 691, 640, 551, 490, 0, 708, 0, + 0, 1104, 1114, 0, 0, 0, 0, 0, 0, 0, + 0, 1099, 0, 0, 0, 0, 0, 972, 0, 0, + 1010, 1080, 1079, 997, 1007, 0, 0, 372, 270, 635, + 762, 637, 636, 998, 0, 999, 1003, 1006, 1002, 1000, + 1001, 0, 1094, 0, 0, 0, 0, 0, 0, 964, + 976, 0, 982, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 973, 974, + 2335, 0, 0, 0, 1031, 0, 975, 0, 977, 0, + 0, 0, 0, 552, 580, 0, 594, 0, 440, 441, + 1026, 1004, 1008, 0, 0, 0, 0, 356, 559, 577, + 373, 546, 592, 378, 554, 570, 368, 507, 542, 0, + 0, 358, 575, 553, 485, 357, 0, 535, 398, 415, + 395, 505, 1005, 0, 1029, 1033, 394, 1120, 1027, 585, + 360, 0, 584, 504, 477, 571, 576, 486, 479, 0, + 359, 573, 484, 478, 454, 405, 1121, 455, 456, 457, + 458, 459, 460, 419, 1109, 475, 521, 420, 492, 491, + 493, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 430, 0, 0, 0, 0, 0, 616, 617, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 754, 1024, 0, 759, 0, 588, 0, + 0, 1101, 0, 0, 0, 557, 0, 0, 461, 0, + 0, 0, 1028, 0, 538, 510, 1117, 0, 0, 536, + 473, 572, 522, 578, 560, 586, 529, 523, 350, 561, + 397, 487, 369, 371, 787, 399, 402, 406, 407, 498, + 499, 516, 545, 564, 565, 566, 396, 383, 537, 384, + 416, 385, 351, 388, 387, 389, 547, 390, 353, 517, + 569, 0, 412, 533, 482, 354, 481, 518, 568, 567, + 370, 596, 603, 604, 696, 0, 609, 801, 802, 803, + 618, 0, 524, 366, 363, 0, 0, 0, 392, 519, + 379, 381, 382, 380, 513, 515, 623, 624, 625, 627, + 628, 629, 630, 0, 0, 0, 0, 631, 697, 715, + 681, 650, 611, 705, 647, 651, 652, 433, 434, 435, + 436, 718, 0, 0, 0, 602, 462, 463, 0, 404, + 403, 483, 355, 0, 0, 451, 432, 525, 361, 400, + 453, 438, 464, 465, 466, 467, 468, 0, 469, 470, + 410, 340, 346, 795, 1098, 506, 720, 757, 758, 642, + 0, 1116, 1093, 1095, 1096, 1100, 1105, 1106, 1107, 1108, + 1110, 1112, 1115, 1119, 794, 0, 698, 712, 799, 711, + 791, 512, 0, 544, 709, 656, 0, 702, 675, 676, + 0, 703, 671, 707, 362, 439, 530, 587, 0, 644, + 0, 612, 615, 646, 733, 734, 735, 352, 614, 737, + 738, 739, 740, 741, 742, 743, 736, 1118, 679, 655, + 682, 593, 658, 657, 0, 0, 693, 1032, 694, 695, + 494, 495, 496, 497, 1102, 721, 377, 613, 527, 528, + 0, 680, 0, 0, 0, 0, 0, 0, 0, 0, + 685, 686, 683, 804, 0, 744, 745, 0, 0, 607, + 608, 409, 0, 626, 417, 376, 511, 411, 591, 442, + 0, 619, 687, 620, 531, 532, 748, 753, 749, 750, + 752, 773, 501, 431, 437, 548, 452, 474, 534, 590, + 509, 539, 374, 579, 550, 480, 672, 700, 1127, 1097, + 1126, 1128, 1129, 1125, 1130, 1131, 1111, 986, 0, 1039, + 1040, 1123, 1122, 1124, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 729, 728, 727, 726, 725, + 724, 723, 722, 0, 0, 669, 391, 792, 786, 793, + 774, 777, 776, 751, 993, 347, 649, 472, 526, 408, + 716, 717, 0, 772, 1087, 1050, 1051, 1052, 983, 1053, + 1047, 1048, 984, 1049, 1088, 1037, 1084, 1085, 1012, 1042, + 1054, 1083, 1055, 1086, 1013, 1089, 1132, 1133, 1061, 1045, + 303, 1134, 1058, 1090, 1082, 1081, 1056, 1038, 1091, 1092, + 1020, 1015, 1059, 1060, 1046, 1067, 1068, 1069, 1072, 985, + 1073, 1074, 1075, 1076, 1077, 1071, 1070, 1034, 1035, 1036, + 1062, 1063, 1065, 1066, 1041, 558, 1016, 1017, 1018, 1019, + 0, 0, 597, 598, 599, 622, 0, 600, 581, 648, + 418, 348, 562, 589, 789, 790, 0, 0, 0, 0, + 0, 0, 0, 699, 710, 746, 747, 0, 760, 761, + 763, 765, 1078, 767, 555, 556, 775, 0, 0, 443, + 364, 365, 502, 503, 541, 0, 444, 445, 446, 450, + 447, 448, 449, 1064, 770, 771, 768, 476, 540, 563, + 549, 788, 489, 0, 796, 638, 639, 797, 756, 755, + 349, 0, 1043, 1044, 713, 714, 0, 0, 1113, 488, + 645, 0, 978, 341, 342, 343, 1103, 345, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1030, + 0, 0, 0, 0, 0, 0, 0, 0, 508, 0, + 0, 654, 688, 677, 766, 641, 0, 0, 0, 0, + 0, 0, 981, 0, 0, 0, 401, 0, 0, 471, + 692, 673, 684, 674, 514, 659, 660, 661, 668, 413, + 662, 798, 664, 633, 665, 634, 666, 667, 1021, 691, + 640, 551, 490, 0, 708, 0, 0, 1104, 1114, 0, + 0, 0, 0, 0, 0, 0, 0, 1099, 0, 0, + 0, 0, 0, 972, 0, 0, 1010, 1080, 1079, 997, + 1007, 0, 0, 372, 270, 635, 762, 637, 636, 998, + 0, 999, 1003, 1006, 1002, 1000, 1001, 0, 1094, 0, + 0, 0, 0, 0, 0, 964, 976, 0, 982, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 973, 974, 0, 0, 0, 0, + 1031, 0, 975, 0, 977, 0, 0, 0, 0, 552, + 580, 0, 594, 0, 440, 441, 1026, 1004, 1008, 0, + 0, 0, 0, 356, 559, 577, 373, 546, 592, 378, + 554, 570, 368, 507, 542, 0, 0, 358, 575, 553, + 485, 357, 0, 535, 398, 415, 395, 505, 1005, 0, + 1029, 1033, 394, 1120, 1027, 585, 360, 0, 584, 504, + 477, 571, 576, 486, 479, 0, 359, 573, 484, 478, + 454, 405, 1121, 455, 456, 457, 458, 459, 460, 419, + 1109, 475, 521, 420, 492, 491, 493, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 430, 0, 0, 0, + 0, 0, 616, 617, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 754, + 1024, 0, 759, 0, 588, 0, 0, 1101, 0, 0, + 0, 557, 0, 0, 461, 0, 0, 0, 1028, 0, + 538, 510, 1117, 0, 0, 536, 473, 572, 522, 578, + 560, 586, 529, 523, 350, 561, 397, 487, 369, 371, + 787, 399, 402, 406, 407, 498, 499, 516, 545, 564, + 565, 566, 396, 383, 537, 384, 416, 385, 351, 388, + 387, 389, 547, 390, 353, 517, 569, 0, 412, 533, + 482, 354, 481, 518, 568, 567, 370, 596, 603, 604, + 696, 0, 609, 801, 802, 803, 618, 0, 524, 366, + 363, 0, 0, 0, 392, 519, 379, 381, 382, 380, + 513, 515, 623, 624, 625, 627, 628, 629, 630, 0, + 0, 0, 0, 631, 697, 715, 681, 650, 611, 705, + 647, 651, 652, 433, 434, 435, 436, 718, 0, 0, + 0, 602, 462, 463, 0, 404, 403, 483, 355, 0, + 0, 451, 432, 525, 361, 400, 453, 438, 464, 465, + 466, 467, 468, 0, 469, 470, 410, 340, 346, 795, + 1098, 506, 720, 757, 758, 642, 0, 1116, 1093, 1095, + 1096, 1100, 1105, 1106, 1107, 1108, 1110, 1112, 1115, 1119, + 794, 0, 698, 712, 799, 711, 791, 512, 0, 544, + 709, 656, 0, 702, 675, 676, 0, 703, 671, 707, + 362, 439, 530, 587, 0, 644, 0, 612, 615, 646, + 733, 734, 735, 352, 614, 737, 738, 739, 740, 741, + 742, 743, 736, 1118, 679, 655, 682, 593, 658, 657, + 0, 0, 693, 1032, 694, 695, 494, 495, 496, 497, + 1102, 721, 377, 613, 527, 528, 0, 680, 0, 0, + 0, 0, 0, 0, 0, 0, 685, 686, 683, 804, + 0, 744, 745, 0, 0, 607, 608, 409, 0, 626, + 417, 376, 511, 411, 591, 442, 0, 619, 687, 620, + 531, 532, 748, 753, 749, 750, 752, 773, 501, 431, + 437, 548, 452, 474, 534, 590, 509, 539, 374, 579, + 550, 480, 672, 700, 1127, 1097, 1126, 1128, 1129, 1125, + 1130, 1131, 1111, 986, 0, 1039, 1040, 1123, 1122, 1124, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 729, 728, 727, 726, 725, 724, 723, 722, 0, + 0, 669, 391, 792, 786, 793, 774, 777, 776, 751, + 993, 347, 649, 472, 526, 408, 716, 717, 0, 772, + 1087, 1050, 1051, 1052, 983, 1053, 1047, 1048, 984, 1049, + 1088, 1037, 1084, 1085, 1012, 1042, 1054, 1083, 1055, 1086, + 1013, 1089, 1132, 1133, 1061, 1045, 303, 1134, 1058, 1090, + 1082, 1081, 1056, 1038, 1091, 1092, 1020, 1015, 1059, 1060, + 1046, 1067, 1068, 1069, 1072, 985, 1073, 1074, 1075, 1076, + 1077, 1071, 1070, 1034, 1035, 1036, 1062, 1063, 1065, 1066, + 1041, 558, 1016, 1017, 1018, 1019, 0, 0, 597, 598, + 599, 622, 0, 600, 581, 648, 418, 348, 562, 589, + 789, 790, 0, 0, 0, 0, 0, 0, 0, 699, + 710, 746, 747, 0, 760, 761, 763, 765, 1078, 767, + 555, 556, 775, 0, 0, 443, 364, 365, 502, 503, + 541, 0, 444, 445, 446, 450, 447, 448, 449, 1064, + 770, 771, 768, 476, 540, 563, 549, 788, 489, 0, + 796, 638, 639, 797, 756, 755, 349, 0, 1043, 1044, + 713, 714, 0, 0, 1113, 488, 645, 0, 978, 341, + 342, 343, 1103, 345, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1030, 0, 0, 0, 0, + 0, 0, 0, 0, 508, 0, 0, 654, 688, 677, + 766, 641, 0, 0, 0, 0, 0, 0, 981, 0, + 0, 0, 401, 0, 0, 471, 692, 673, 684, 674, + 514, 659, 660, 661, 668, 413, 662, 798, 664, 633, + 665, 634, 666, 667, 1021, 691, 640, 551, 490, 0, + 708, 0, 0, 1104, 1114, 0, 0, 0, 0, 0, + 0, 0, 0, 1099, 0, 0, 0, 0, 0, 972, + 0, 0, 1010, 1080, 1079, 997, 1007, 0, 0, 372, + 270, 635, 762, 637, 636, 998, 0, 999, 1003, 1006, + 1002, 1000, 1001, 0, 1094, 0, 0, 0, 0, 0, + 0, 964, 976, 0, 982, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 973, 974, 0, 0, 0, 0, 1031, 0, 975, 0, + 977, 0, 0, 0, 0, 552, 580, 0, 594, 0, + 440, 441, 1026, 1004, 1008, 0, 0, 0, 0, 356, + 559, 577, 373, 546, 592, 378, 554, 570, 368, 507, + 542, 0, 0, 358, 575, 553, 485, 357, 0, 535, + 398, 415, 395, 505, 1005, 0, 1029, 1033, 394, 1120, + 1027, 585, 360, 0, 584, 504, 477, 571, 576, 486, + 479, 0, 359, 573, 484, 478, 454, 405, 1121, 455, + 456, 457, 458, 459, 460, 419, 1109, 475, 521, 420, + 492, 491, 493, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 430, 0, 0, 0, 0, 0, 616, 617, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 754, 1024, 0, 759, 0, + 588, 0, 0, 1101, 0, 0, 0, 557, 0, 0, + 461, 0, 0, 0, 1028, 0, 538, 510, 1117, 0, + 0, 536, 473, 572, 522, 578, 560, 586, 529, 523, + 350, 561, 397, 487, 369, 371, 787, 399, 402, 406, + 407, 498, 499, 516, 545, 564, 565, 566, 396, 383, + 537, 384, 416, 385, 351, 388, 387, 389, 547, 390, + 353, 517, 569, 0, 412, 533, 482, 354, 481, 518, + 568, 567, 370, 596, 603, 604, 696, 0, 609, 801, + 802, 803, 618, 0, 524, 366, 363, 0, 0, 0, + 392, 519, 379, 381, 382, 380, 513, 515, 623, 624, + 625, 627, 628, 629, 630, 0, 0, 0, 0, 631, + 697, 715, 681, 650, 611, 705, 647, 651, 652, 433, + 434, 435, 436, 718, 0, 0, 0, 602, 462, 463, + 0, 404, 403, 483, 355, 0, 0, 451, 432, 525, + 361, 400, 453, 438, 464, 465, 466, 467, 468, 0, + 469, 470, 410, 340, 346, 795, 1098, 506, 720, 757, + 758, 642, 0, 1116, 1093, 1095, 1096, 1100, 1105, 1106, + 1107, 1108, 1110, 1112, 1115, 1119, 794, 0, 698, 712, + 799, 711, 791, 512, 0, 544, 709, 656, 0, 702, + 675, 676, 0, 703, 671, 707, 362, 439, 530, 587, + 0, 644, 0, 612, 615, 646, 733, 734, 735, 352, + 614, 737, 738, 739, 740, 741, 742, 743, 736, 1118, + 679, 655, 682, 593, 658, 657, 0, 0, 693, 1032, + 694, 695, 494, 495, 496, 497, 1102, 721, 377, 613, + 527, 528, 0, 680, 0, 0, 0, 0, 0, 0, + 0, 0, 685, 686, 683, 804, 0, 744, 745, 0, + 0, 607, 608, 409, 0, 626, 417, 376, 511, 411, + 591, 442, 0, 619, 687, 620, 531, 532, 748, 753, + 749, 750, 752, 773, 501, 431, 437, 548, 452, 474, + 534, 590, 509, 539, 374, 579, 550, 480, 672, 700, + 1127, 1097, 1126, 1128, 1129, 1125, 1130, 1131, 1111, 986, + 0, 1039, 1040, 1123, 1122, 1124, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 729, 728, 727, + 726, 725, 724, 723, 722, 0, 0, 669, 391, 792, + 786, 793, 774, 777, 776, 751, 993, 347, 649, 472, + 526, 408, 716, 717, 0, 772, 1087, 1050, 1051, 1052, + 983, 1053, 1047, 1048, 984, 1049, 1088, 1037, 1084, 1085, + 1012, 1042, 1054, 1083, 1055, 1086, 1013, 1089, 1132, 1133, + 1061, 1045, 303, 1134, 1058, 1090, 1082, 1081, 1056, 1038, + 1091, 1092, 1020, 1015, 1059, 1060, 1046, 1067, 1068, 1069, + 1072, 985, 1073, 1074, 1075, 1076, 1077, 1071, 1070, 1034, + 1035, 1036, 1062, 1063, 1065, 1066, 1041, 558, 1016, 1017, + 1018, 1019, 0, 0, 597, 598, 599, 622, 0, 600, + 581, 648, 418, 348, 562, 589, 789, 790, 0, 0, + 0, 0, 0, 0, 0, 699, 710, 746, 747, 0, + 760, 761, 763, 765, 1078, 767, 555, 556, 775, 0, + 0, 443, 364, 365, 502, 503, 541, 0, 444, 445, + 446, 450, 447, 448, 449, 4840, 770, 4841, 4842, 476, + 540, 563, 549, 788, 489, 0, 796, 638, 639, 797, + 756, 755, 349, 0, 1043, 1044, 713, 714, 0, 0, + 1113, 488, 645, 0, 978, 341, 342, 343, 1103, 345, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1030, 0, 0, 0, 0, 0, 0, 0, 0, + 508, 0, 0, 654, 688, 677, 766, 641, 0, 0, + 0, 0, 0, 0, 981, 0, 0, 0, 401, 0, + 0, 471, 692, 673, 684, 674, 514, 659, 660, 661, + 668, 413, 662, 798, 664, 633, 665, 634, 666, 667, + 1021, 691, 640, 551, 490, 0, 708, 0, 0, 1104, + 1114, 0, 0, 0, 0, 0, 0, 0, 0, 1099, + 0, 0, 0, 0, 0, 972, 0, 0, 1010, 1080, + 1079, 997, 1007, 0, 0, 372, 270, 635, 762, 637, + 636, 3430, 0, 3431, 1003, 1006, 1002, 1000, 1001, 0, + 1094, 0, 0, 0, 0, 0, 0, 964, 976, 0, + 982, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 973, 974, 0, 0, + 0, 0, 1031, 0, 975, 0, 977, 0, 0, 0, + 0, 552, 580, 0, 594, 0, 440, 441, 1026, 1004, + 1008, 0, 0, 0, 0, 356, 559, 577, 373, 546, + 592, 378, 554, 570, 368, 507, 542, 0, 0, 358, + 575, 553, 485, 357, 0, 535, 398, 415, 395, 505, + 1005, 0, 1029, 1033, 394, 1120, 1027, 585, 360, 0, + 584, 504, 477, 571, 576, 486, 479, 0, 359, 573, + 484, 478, 454, 405, 1121, 455, 456, 457, 458, 459, + 460, 419, 1109, 475, 521, 420, 492, 491, 493, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 430, 0, + 0, 0, 0, 0, 616, 617, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 754, 1024, 0, 759, 0, 588, 0, 0, 1101, + 0, 0, 0, 557, 0, 0, 461, 0, 0, 0, + 1028, 0, 538, 510, 1117, 0, 0, 536, 473, 572, + 522, 578, 560, 586, 529, 523, 350, 561, 397, 487, + 369, 371, 787, 399, 402, 406, 407, 498, 499, 516, + 545, 564, 565, 566, 396, 383, 537, 384, 416, 385, + 351, 388, 387, 389, 547, 390, 353, 517, 569, 0, + 412, 533, 482, 354, 481, 518, 568, 567, 370, 596, + 603, 604, 696, 0, 609, 801, 802, 803, 618, 0, + 524, 366, 363, 0, 0, 0, 392, 519, 379, 381, + 382, 380, 513, 515, 623, 624, 625, 627, 628, 629, + 630, 0, 0, 0, 0, 631, 697, 715, 681, 650, + 611, 705, 647, 651, 652, 433, 434, 435, 436, 718, + 0, 0, 0, 602, 462, 463, 0, 404, 403, 483, + 355, 0, 0, 451, 432, 525, 361, 400, 453, 438, + 464, 465, 466, 467, 468, 0, 469, 470, 410, 340, + 346, 795, 1098, 506, 720, 757, 758, 642, 0, 1116, + 1093, 1095, 1096, 1100, 1105, 1106, 1107, 1108, 1110, 1112, + 1115, 1119, 794, 0, 698, 712, 799, 711, 791, 512, + 0, 544, 709, 656, 0, 702, 675, 676, 0, 703, + 671, 707, 362, 439, 530, 587, 0, 644, 0, 612, + 615, 646, 733, 734, 735, 352, 614, 737, 738, 739, + 740, 741, 742, 743, 736, 1118, 679, 655, 682, 593, + 658, 657, 0, 0, 693, 1032, 694, 695, 494, 495, + 496, 497, 1102, 721, 377, 613, 527, 528, 0, 680, + 0, 0, 0, 0, 0, 0, 0, 0, 685, 686, + 683, 804, 0, 744, 745, 0, 0, 607, 608, 409, + 0, 626, 417, 376, 511, 411, 591, 442, 0, 619, + 687, 620, 531, 532, 748, 753, 749, 750, 752, 773, + 501, 431, 437, 548, 452, 474, 534, 590, 509, 539, + 374, 579, 550, 480, 672, 700, 1127, 1097, 1126, 1128, + 1129, 1125, 1130, 1131, 1111, 986, 0, 1039, 1040, 1123, + 1122, 1124, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 729, 728, 727, 726, 725, 724, 723, + 722, 0, 0, 669, 391, 792, 786, 793, 774, 777, + 776, 751, 993, 347, 649, 472, 526, 408, 716, 717, + 0, 772, 1087, 1050, 1051, 1052, 983, 1053, 1047, 1048, + 984, 1049, 1088, 1037, 1084, 1085, 1012, 1042, 1054, 1083, + 1055, 1086, 1013, 1089, 1132, 1133, 1061, 1045, 303, 1134, + 1058, 1090, 1082, 1081, 1056, 1038, 1091, 1092, 1020, 1015, + 1059, 1060, 1046, 1067, 1068, 1069, 1072, 985, 1073, 1074, + 1075, 1076, 1077, 1071, 1070, 1034, 1035, 1036, 1062, 1063, + 1065, 1066, 1041, 558, 1016, 1017, 1018, 1019, 0, 0, + 597, 598, 599, 622, 0, 600, 581, 648, 418, 348, + 562, 589, 789, 790, 0, 0, 0, 0, 0, 0, + 0, 699, 710, 746, 747, 0, 760, 761, 763, 765, + 1078, 767, 555, 556, 775, 0, 0, 443, 364, 365, + 502, 503, 541, 0, 444, 445, 446, 450, 447, 448, + 449, 1064, 770, 771, 768, 476, 540, 563, 549, 788, + 489, 0, 796, 638, 639, 797, 756, 755, 349, 0, + 1043, 1044, 713, 714, 0, 0, 1113, 488, 645, 0, + 978, 341, 342, 343, 1103, 345, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1030, 0, 0, + 0, 0, 0, 0, 0, 0, 508, 0, 0, 654, + 688, 677, 766, 641, 0, 0, 2165, 0, 0, 0, + 981, 0, 0, 0, 401, 0, 0, 471, 692, 673, + 684, 674, 514, 659, 660, 661, 668, 413, 662, 798, + 664, 633, 665, 634, 666, 667, 1021, 691, 640, 551, + 490, 0, 708, 0, 0, 1104, 1114, 0, 0, 0, + 0, 0, 0, 0, 0, 1099, 0, 0, 0, 0, + 0, 972, 0, 0, 1010, 1080, 1079, 997, 1007, 0, + 0, 372, 270, 635, 762, 637, 636, 998, 0, 999, + 1003, 1006, 1002, 1000, 1001, 0, 1094, 0, 0, 0, + 0, 0, 0, 0, 976, 0, 982, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 973, 974, 0, 0, 0, 0, 1031, 0, + 975, 0, 977, 0, 0, 0, 0, 552, 580, 0, + 594, 0, 440, 441, 1026, 1004, 1008, 0, 0, 0, + 0, 356, 559, 577, 373, 546, 592, 378, 554, 570, + 368, 507, 542, 0, 0, 358, 575, 553, 485, 357, + 0, 535, 398, 415, 395, 505, 1005, 0, 1029, 1033, + 394, 1120, 1027, 585, 360, 0, 584, 504, 477, 571, + 576, 486, 479, 0, 359, 573, 484, 478, 454, 405, + 1121, 455, 456, 457, 458, 459, 460, 419, 1109, 475, + 521, 420, 492, 491, 493, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 430, 0, 0, 0, 0, 0, + 616, 617, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 754, 1024, 0, + 759, 0, 588, 0, 0, 1101, 0, 0, 0, 557, + 0, 0, 461, 0, 0, 0, 1028, 0, 538, 510, + 1117, 0, 0, 536, 473, 572, 522, 578, 560, 586, + 529, 523, 350, 561, 397, 487, 369, 371, 787, 399, + 402, 406, 407, 498, 499, 516, 545, 564, 565, 566, + 396, 383, 537, 384, 416, 385, 351, 388, 387, 389, + 547, 390, 353, 517, 569, 0, 412, 533, 482, 354, + 481, 518, 568, 567, 370, 596, 2166, 2167, 696, 0, + 609, 801, 802, 803, 618, 0, 524, 366, 363, 0, + 0, 0, 392, 519, 379, 381, 382, 380, 513, 515, + 623, 624, 625, 627, 628, 629, 630, 0, 0, 0, + 0, 631, 697, 715, 681, 650, 611, 705, 647, 651, + 652, 433, 434, 435, 436, 718, 0, 0, 0, 602, + 462, 463, 0, 404, 403, 483, 355, 0, 0, 451, + 432, 525, 361, 400, 453, 438, 464, 465, 466, 467, + 468, 0, 469, 470, 410, 340, 346, 795, 1098, 506, + 720, 757, 758, 642, 0, 1116, 1093, 1095, 1096, 1100, + 1105, 1106, 1107, 1108, 1110, 1112, 1115, 1119, 794, 0, + 698, 712, 799, 711, 791, 512, 0, 544, 709, 656, + 0, 702, 675, 676, 0, 703, 671, 707, 362, 439, + 530, 587, 0, 644, 0, 612, 615, 646, 733, 734, + 735, 352, 614, 737, 738, 739, 740, 741, 742, 743, + 736, 1118, 679, 655, 682, 593, 658, 657, 0, 0, + 693, 1032, 694, 695, 494, 495, 496, 497, 1102, 721, + 377, 613, 527, 528, 0, 680, 0, 0, 0, 0, + 0, 0, 0, 0, 685, 686, 683, 804, 0, 744, + 745, 0, 0, 607, 608, 409, 0, 626, 417, 376, + 511, 411, 591, 442, 0, 619, 687, 620, 531, 532, + 748, 753, 749, 750, 752, 773, 501, 431, 437, 548, + 452, 474, 534, 590, 509, 539, 374, 579, 550, 480, + 672, 700, 1127, 1097, 1126, 1128, 1129, 1125, 1130, 1131, + 1111, 986, 0, 1039, 1040, 1123, 1122, 1124, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 729, + 728, 727, 726, 725, 724, 723, 722, 0, 0, 669, + 391, 792, 786, 793, 774, 777, 776, 751, 993, 347, + 649, 472, 526, 408, 716, 717, 0, 772, 1087, 1050, + 1051, 1052, 983, 1053, 1047, 1048, 984, 1049, 1088, 1037, + 1084, 1085, 1012, 1042, 1054, 1083, 1055, 1086, 1013, 1089, + 1132, 1133, 1061, 1045, 303, 1134, 1058, 1090, 1082, 1081, + 1056, 1038, 1091, 1092, 1020, 1015, 1059, 1060, 1046, 1067, + 1068, 1069, 1072, 985, 1073, 1074, 1075, 1076, 1077, 1071, + 1070, 1034, 1035, 1036, 1062, 1063, 1065, 1066, 1041, 558, + 1016, 1017, 1018, 1019, 0, 0, 597, 598, 599, 622, + 0, 600, 581, 648, 418, 348, 562, 589, 789, 790, + 0, 0, 0, 0, 0, 0, 0, 699, 710, 746, + 747, 0, 760, 761, 763, 765, 1078, 767, 555, 556, + 775, 0, 0, 443, 364, 365, 502, 503, 541, 0, + 444, 445, 446, 450, 447, 448, 449, 1064, 770, 771, + 768, 476, 540, 563, 549, 788, 489, 0, 796, 638, + 639, 797, 756, 755, 349, 0, 1043, 1044, 713, 714, + 0, 0, 1113, 488, 645, 0, 978, 341, 342, 343, + 1103, 345, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1030, 0, 0, 0, 0, 0, 0, + 0, 0, 508, 0, 0, 654, 688, 677, 766, 641, + 0, 0, 0, 0, 0, 0, 981, 0, 0, 0, + 401, 0, 0, 471, 692, 673, 684, 674, 514, 659, + 660, 661, 668, 413, 662, 798, 664, 633, 665, 634, + 666, 667, 1021, 691, 640, 551, 490, 0, 708, 0, + 0, 1104, 1114, 0, 0, 0, 0, 0, 0, 0, + 0, 1099, 0, 0, 0, 0, 0, 1638, 0, 0, + 1010, 1080, 1079, 997, 1007, 0, 0, 372, 270, 635, + 762, 637, 636, 998, 0, 999, 1003, 1006, 1002, 1000, + 1001, 0, 1094, 0, 0, 0, 0, 0, 0, 964, + 976, 0, 982, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 973, 974, + 0, 0, 0, 0, 1031, 0, 975, 0, 977, 0, + 0, 0, 0, 552, 580, 0, 594, 0, 440, 441, + 1026, 1004, 1008, 0, 0, 0, 0, 356, 559, 577, + 373, 546, 592, 378, 554, 570, 368, 507, 542, 0, + 0, 358, 575, 553, 485, 357, 0, 535, 398, 415, + 395, 505, 1005, 0, 1029, 1033, 394, 1120, 1027, 585, + 360, 0, 584, 504, 477, 571, 576, 486, 479, 0, + 359, 573, 484, 478, 454, 405, 1121, 455, 456, 457, + 458, 459, 460, 419, 1109, 475, 521, 420, 492, 491, + 493, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 430, 0, 0, 0, 0, 0, 616, 617, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 754, 1024, 0, 759, 0, 588, 0, + 0, 1101, 0, 0, 0, 557, 0, 0, 461, 0, + 0, 0, 1028, 0, 538, 510, 1117, 0, 0, 536, + 473, 572, 522, 578, 560, 586, 529, 523, 350, 561, + 397, 487, 369, 371, 787, 399, 402, 406, 407, 498, + 499, 516, 545, 564, 565, 566, 396, 383, 537, 384, + 416, 385, 351, 388, 387, 389, 547, 390, 353, 517, + 569, 0, 412, 533, 482, 354, 481, 518, 568, 567, + 370, 596, 603, 604, 696, 0, 609, 801, 802, 803, + 618, 0, 524, 366, 363, 0, 0, 0, 392, 519, + 379, 381, 382, 380, 513, 515, 623, 624, 625, 627, + 628, 629, 630, 0, 0, 0, 0, 631, 697, 715, + 681, 650, 611, 705, 647, 651, 652, 433, 434, 435, + 436, 718, 0, 0, 0, 602, 462, 463, 0, 404, + 403, 483, 355, 0, 0, 451, 432, 525, 361, 400, + 453, 438, 464, 465, 466, 467, 468, 0, 469, 470, + 410, 340, 346, 795, 1098, 506, 720, 757, 758, 642, + 0, 1116, 1093, 1095, 1096, 1100, 1105, 1106, 1107, 1108, + 1110, 1112, 1115, 1119, 794, 0, 698, 712, 799, 711, + 791, 512, 0, 544, 709, 656, 0, 702, 675, 676, + 0, 703, 671, 707, 362, 439, 530, 587, 0, 644, + 0, 612, 615, 646, 733, 734, 735, 352, 614, 737, + 738, 739, 740, 741, 742, 743, 736, 1118, 679, 655, + 682, 593, 658, 657, 0, 0, 693, 1032, 694, 695, + 494, 495, 496, 497, 1102, 721, 377, 613, 527, 528, + 0, 680, 0, 0, 0, 0, 0, 0, 0, 0, + 685, 686, 683, 804, 0, 744, 745, 0, 0, 607, + 608, 409, 0, 626, 417, 376, 511, 411, 591, 442, + 0, 619, 687, 620, 531, 532, 748, 753, 749, 750, + 752, 773, 501, 431, 437, 548, 452, 474, 534, 590, + 509, 539, 374, 579, 550, 480, 672, 700, 1127, 1097, + 1126, 1128, 1129, 1125, 1130, 1131, 1111, 986, 0, 1039, + 1040, 1123, 1122, 1124, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 729, 728, 727, 726, 725, + 724, 723, 722, 0, 0, 669, 391, 792, 786, 793, + 774, 777, 776, 751, 993, 347, 649, 472, 526, 408, + 716, 717, 0, 772, 1087, 1050, 1051, 1052, 983, 1053, + 1047, 1048, 984, 1049, 1088, 1037, 1084, 1085, 1012, 1042, + 1054, 1083, 1055, 1086, 1013, 1089, 1132, 1133, 1061, 1045, + 303, 1134, 1058, 1090, 1082, 1081, 1056, 1038, 1091, 1092, + 1020, 1015, 1059, 1060, 1046, 1067, 1068, 1069, 1072, 985, + 1073, 1074, 1075, 1076, 1077, 1071, 1070, 1034, 1035, 1036, + 1062, 1063, 1065, 1066, 1041, 558, 1016, 1017, 1018, 1019, + 0, 0, 597, 598, 599, 622, 0, 600, 581, 648, + 418, 348, 562, 589, 789, 790, 0, 0, 0, 0, + 0, 0, 0, 699, 710, 746, 747, 0, 760, 761, + 763, 765, 1078, 767, 555, 556, 775, 0, 0, 443, + 364, 365, 502, 503, 541, 0, 444, 445, 446, 450, + 447, 448, 449, 1064, 770, 771, 768, 476, 540, 563, + 549, 788, 489, 0, 796, 638, 639, 797, 756, 755, + 349, 0, 1043, 1044, 713, 714, 0, 0, 1113, 488, + 645, 0, 978, 341, 342, 343, 1103, 345, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1030, + 0, 0, 0, 0, 0, 0, 0, 0, 508, 0, + 0, 654, 688, 677, 766, 641, 0, 0, 0, 0, + 0, 0, 981, 0, 0, 0, 401, 0, 0, 471, + 692, 673, 684, 674, 514, 659, 660, 661, 668, 413, + 662, 798, 664, 633, 665, 634, 666, 667, 1021, 691, + 640, 551, 490, 0, 708, 0, 0, 1104, 1114, 0, + 0, 0, 0, 0, 0, 0, 0, 1099, 0, 0, + 0, 0, 0, 972, 0, 0, 1010, 1080, 1079, 997, + 1007, 0, 0, 372, 270, 635, 762, 637, 636, 998, + 0, 999, 1003, 1006, 1002, 1000, 1001, 0, 1094, 0, + 0, 0, 0, 0, 0, 0, 976, 0, 982, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 973, 974, 0, 0, 0, 0, + 1031, 0, 975, 0, 977, 0, 0, 0, 0, 552, + 580, 0, 594, 0, 440, 441, 1026, 1004, 1008, 0, + 0, 0, 0, 356, 559, 577, 373, 546, 592, 378, + 554, 570, 368, 507, 542, 0, 0, 358, 575, 553, + 485, 357, 0, 535, 398, 415, 395, 505, 1005, 0, + 1029, 1033, 394, 1120, 1027, 585, 360, 0, 584, 504, + 477, 571, 576, 486, 479, 0, 359, 573, 484, 478, + 454, 405, 1121, 455, 456, 457, 458, 459, 460, 419, + 1109, 475, 521, 420, 492, 491, 493, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 430, 0, 0, 0, + 0, 0, 616, 617, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 754, + 1024, 0, 759, 0, 588, 0, 0, 1101, 0, 0, + 0, 557, 0, 0, 461, 0, 0, 0, 1028, 0, + 538, 510, 1117, 0, 0, 536, 473, 572, 522, 578, + 560, 586, 529, 523, 350, 561, 397, 487, 369, 371, + 787, 399, 402, 406, 407, 498, 499, 516, 545, 564, + 565, 566, 396, 383, 537, 384, 416, 385, 351, 388, + 387, 389, 547, 390, 353, 517, 569, 0, 412, 533, + 482, 354, 481, 518, 568, 567, 370, 596, 603, 604, + 696, 0, 609, 801, 802, 803, 618, 0, 524, 366, + 363, 0, 0, 0, 392, 519, 379, 381, 382, 380, + 513, 515, 623, 624, 625, 627, 628, 629, 630, 0, + 0, 0, 0, 631, 697, 715, 681, 650, 611, 705, + 647, 651, 652, 433, 434, 435, 436, 718, 0, 0, + 0, 602, 462, 463, 0, 404, 403, 483, 355, 0, + 0, 451, 432, 525, 361, 400, 453, 438, 464, 465, + 466, 467, 468, 0, 469, 470, 410, 340, 346, 795, + 1098, 506, 720, 757, 758, 642, 0, 1116, 1093, 1095, + 1096, 1100, 1105, 1106, 1107, 1108, 1110, 1112, 1115, 1119, + 794, 0, 698, 712, 799, 711, 791, 512, 0, 544, + 709, 656, 0, 702, 675, 676, 0, 703, 671, 707, + 362, 439, 530, 587, 0, 644, 0, 612, 615, 646, + 733, 734, 735, 352, 614, 737, 738, 739, 740, 741, + 742, 743, 736, 1118, 679, 655, 682, 593, 658, 657, + 0, 0, 693, 1032, 694, 695, 494, 495, 496, 497, + 1102, 721, 377, 613, 527, 528, 0, 680, 0, 0, + 0, 0, 0, 0, 0, 0, 685, 686, 683, 804, + 0, 744, 745, 0, 0, 607, 608, 409, 0, 626, + 417, 376, 511, 411, 591, 442, 0, 619, 687, 620, + 531, 532, 748, 753, 749, 750, 752, 773, 501, 431, + 437, 548, 452, 474, 534, 590, 509, 539, 374, 579, + 550, 480, 672, 700, 1127, 1097, 1126, 1128, 1129, 1125, + 1130, 1131, 1111, 986, 0, 1039, 1040, 1123, 1122, 1124, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 729, 728, 727, 726, 725, 724, 723, 722, 0, + 0, 669, 391, 792, 786, 793, 774, 777, 776, 751, + 993, 347, 649, 472, 526, 408, 716, 717, 0, 772, + 1087, 1050, 1051, 1052, 983, 1053, 1047, 1048, 984, 1049, + 1088, 1037, 1084, 1085, 1012, 1042, 1054, 1083, 1055, 1086, + 1013, 1089, 1132, 1133, 1061, 1045, 303, 1134, 1058, 1090, + 1082, 1081, 1056, 1038, 1091, 1092, 1020, 1015, 1059, 1060, + 1046, 1067, 1068, 1069, 1072, 985, 1073, 1074, 1075, 1076, + 1077, 1071, 1070, 1034, 1035, 1036, 1062, 1063, 1065, 1066, + 1041, 558, 1016, 1017, 1018, 1019, 0, 0, 597, 598, + 599, 622, 0, 600, 581, 648, 418, 348, 562, 589, + 789, 790, 0, 0, 0, 0, 0, 0, 0, 699, + 710, 746, 747, 0, 760, 761, 763, 765, 1078, 767, + 555, 556, 775, 0, 0, 443, 364, 365, 502, 503, + 541, 0, 444, 445, 446, 450, 447, 448, 449, 1064, + 770, 771, 768, 476, 540, 563, 549, 788, 489, 0, + 796, 638, 639, 797, 756, 755, 349, 0, 1043, 1044, + 713, 714, 0, 0, 1113, 488, 645, 0, 978, 341, + 342, 343, 344, 345, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 201, 246, 200, 233, 202, 0, 0, + 0, 0, 0, 0, 508, 0, 0, 654, 688, 677, + 766, 641, 0, 234, 0, 0, 0, 0, 0, 0, + 226, 0, 401, 0, 235, 471, 692, 673, 684, 674, + 514, 659, 660, 661, 668, 413, 662, 663, 664, 633, + 665, 634, 666, 667, 170, 691, 640, 551, 490, 0, + 708, 0, 0, 0, 0, 0, 0, 0, 0, 155, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, + 0, 0, 269, 0, 0, 0, 0, 0, 0, 372, + 270, 635, 762, 637, 636, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 375, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 261, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 552, 580, 0, 594, 0, + 440, 441, 0, 0, 0, 0, 0, 0, 0, 356, + 559, 577, 373, 546, 592, 378, 554, 570, 368, 507, + 542, 0, 0, 358, 575, 553, 485, 357, 0, 535, + 398, 415, 395, 505, 0, 0, 574, 605, 394, 595, + 0, 585, 360, 0, 584, 504, 477, 571, 576, 486, + 479, 0, 359, 573, 484, 478, 454, 405, 621, 455, + 456, 457, 458, 459, 460, 419, 520, 475, 521, 420, + 492, 491, 493, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 430, 0, 0, 0, 0, 0, 616, 617, + 0, 0, 0, 0, 0, 0, 0, 199, 231, 243, + 232, 84, 151, 0, 0, 754, 0, 247, 759, 0, + 588, 0, 0, 262, 0, 0, 0, 557, 0, 0, + 461, 153, 225, 224, 606, 0, 538, 510, 275, 0, + 0, 536, 473, 572, 522, 578, 560, 586, 529, 523, + 350, 561, 397, 487, 369, 371, 284, 399, 402, 406, + 407, 498, 499, 516, 545, 564, 565, 566, 396, 383, + 537, 384, 416, 385, 351, 388, 387, 389, 547, 390, + 353, 517, 569, 152, 412, 533, 482, 354, 481, 518, + 568, 567, 370, 596, 603, 604, 696, 0, 609, 730, + 731, 732, 618, 0, 524, 366, 363, 0, 0, 0, + 392, 519, 379, 381, 382, 380, 513, 515, 623, 624, + 625, 627, 628, 629, 630, 0, 0, 0, 0, 631, + 697, 715, 681, 650, 611, 705, 647, 651, 652, 433, + 434, 435, 436, 718, 0, 0, 0, 602, 462, 463, + 0, 404, 403, 483, 355, 0, 0, 451, 432, 525, + 361, 400, 453, 438, 464, 465, 466, 467, 468, 0, + 469, 470, 410, 340, 346, 582, 393, 506, 720, 757, + 758, 642, 0, 706, 643, 653, 386, 678, 690, 689, + 500, 601, 265, 701, 704, 632, 276, 0, 698, 712, + 670, 711, 277, 512, 0, 544, 709, 656, 0, 702, + 675, 676, 0, 703, 671, 707, 362, 439, 530, 587, + 0, 644, 0, 612, 615, 646, 733, 734, 735, 352, + 614, 737, 738, 739, 740, 741, 742, 743, 736, 583, + 679, 655, 682, 593, 658, 657, 0, 0, 693, 610, + 694, 695, 494, 495, 496, 497, 414, 721, 377, 613, + 527, 528, 167, 680, 0, 0, 0, 0, 0, 0, + 0, 0, 685, 686, 683, 274, 0, 744, 745, 0, + 0, 607, 608, 409, 0, 626, 417, 376, 511, 411, + 591, 442, 0, 619, 687, 620, 531, 532, 748, 753, + 749, 750, 752, 773, 501, 431, 437, 548, 452, 474, + 534, 590, 509, 539, 374, 579, 550, 480, 672, 700, + 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, + 0, 326, 327, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 729, 728, 727, + 726, 725, 724, 723, 722, 0, 0, 669, 391, 282, + 367, 283, 774, 777, 776, 751, 0, 347, 649, 472, + 526, 408, 716, 717, 72, 772, 285, 286, 287, 288, + 289, 290, 291, 292, 333, 293, 294, 295, 296, 297, + 298, 299, 304, 305, 306, 307, 308, 309, 310, 311, + 719, 302, 303, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 325, 0, 0, 0, + 0, 334, 778, 779, 780, 781, 782, 0, 0, 335, + 336, 337, 0, 0, 300, 301, 328, 558, 329, 330, + 331, 332, 0, 0, 597, 598, 599, 622, 0, 600, + 581, 648, 418, 348, 562, 589, 278, 279, 55, 263, + 266, 268, 267, 0, 73, 699, 710, 746, 747, 9, + 760, 761, 763, 765, 764, 767, 555, 556, 775, 0, + 0, 443, 364, 365, 502, 503, 541, 0, 444, 445, + 446, 450, 447, 448, 449, 769, 770, 771, 768, 476, + 540, 563, 549, 273, 489, 174, 280, 638, 639, 281, + 756, 755, 349, 0, 338, 339, 713, 714, 0, 0, + 543, 488, 645, 341, 342, 343, 344, 345, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 201, 246, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 508, 0, + 0, 654, 688, 677, 766, 641, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 401, 0, 0, 471, + 692, 673, 684, 674, 514, 659, 660, 661, 668, 413, + 662, 798, 664, 633, 665, 634, 666, 667, 1279, 691, + 640, 551, 490, 0, 708, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 239, 0, 0, 269, 0, 0, 0, + 0, 0, 0, 372, 270, 635, 762, 637, 636, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 375, 3085, + 3088, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 552, + 580, 0, 594, 0, 440, 441, 0, 0, 0, 0, + 0, 0, 0, 356, 559, 577, 373, 546, 592, 378, + 554, 570, 368, 507, 542, 0, 0, 358, 575, 553, + 485, 357, 0, 535, 398, 415, 395, 505, 0, 0, + 574, 605, 394, 595, 0, 585, 360, 0, 584, 504, + 477, 571, 576, 486, 479, 0, 359, 573, 484, 478, + 454, 405, 621, 455, 456, 457, 458, 459, 460, 419, + 520, 475, 521, 420, 492, 491, 493, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 430, 0, 0, 0, + 0, 0, 616, 617, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 754, + 0, 247, 759, 3089, 588, 0, 0, 0, 3084, 0, + 3083, 557, 3080, 3086, 461, 0, 0, 0, 606, 0, + 538, 510, 800, 0, 0, 536, 473, 572, 522, 578, + 560, 586, 529, 523, 350, 561, 397, 487, 369, 371, + 787, 399, 402, 406, 407, 498, 499, 516, 545, 564, + 565, 566, 396, 383, 537, 384, 416, 385, 351, 388, + 387, 389, 547, 390, 353, 517, 569, 3087, 412, 533, + 482, 354, 481, 518, 568, 567, 370, 596, 603, 604, + 696, 0, 609, 801, 802, 803, 618, 0, 524, 366, + 363, 0, 0, 0, 392, 519, 379, 381, 382, 380, + 513, 515, 623, 624, 625, 627, 628, 629, 630, 0, + 0, 0, 0, 631, 697, 715, 681, 650, 611, 705, + 647, 651, 652, 433, 434, 435, 436, 718, 0, 0, + 0, 602, 462, 463, 0, 404, 403, 483, 355, 0, + 0, 451, 432, 525, 361, 400, 453, 438, 464, 465, + 466, 467, 468, 3081, 469, 470, 410, 340, 346, 795, + 393, 506, 720, 757, 758, 642, 0, 706, 643, 653, + 386, 678, 690, 689, 500, 601, 0, 701, 704, 632, + 794, 0, 698, 712, 799, 711, 791, 512, 0, 544, + 709, 656, 0, 702, 675, 676, 0, 703, 671, 707, + 362, 439, 530, 587, 0, 644, 0, 612, 615, 646, + 733, 734, 735, 352, 614, 737, 738, 739, 740, 741, + 742, 743, 736, 583, 679, 655, 682, 593, 658, 657, + 0, 0, 693, 610, 694, 695, 494, 495, 496, 497, + 414, 721, 377, 613, 527, 528, 0, 680, 0, 0, + 0, 0, 0, 0, 0, 0, 685, 686, 683, 804, + 0, 744, 745, 0, 0, 607, 608, 409, 0, 626, + 417, 376, 511, 411, 591, 442, 0, 619, 687, 620, + 531, 532, 748, 753, 749, 750, 752, 773, 501, 431, + 437, 548, 452, 474, 534, 590, 509, 539, 374, 579, + 550, 480, 672, 700, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 326, 327, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 729, 728, 727, 726, 725, 724, 723, 722, 0, + 0, 669, 391, 792, 786, 793, 774, 777, 776, 751, + 0, 347, 649, 472, 526, 408, 716, 717, 0, 772, + 285, 286, 287, 288, 289, 290, 291, 292, 333, 293, + 294, 295, 296, 297, 298, 299, 304, 305, 306, 307, + 308, 309, 310, 311, 719, 302, 303, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 0, 0, 0, 0, 334, 778, 779, 780, 781, + 782, 0, 0, 335, 336, 337, 0, 0, 300, 301, + 328, 558, 329, 330, 331, 332, 0, 0, 597, 598, + 599, 622, 0, 600, 581, 648, 418, 348, 562, 589, + 789, 790, 0, 0, 0, 0, 0, 0, 0, 699, + 710, 746, 747, 0, 760, 761, 763, 765, 764, 767, + 555, 556, 775, 0, 0, 443, 364, 365, 502, 503, + 541, 0, 444, 445, 446, 450, 447, 448, 449, 769, + 770, 771, 768, 476, 540, 563, 549, 788, 489, 0, + 796, 638, 639, 797, 756, 755, 349, 0, 338, 339, + 713, 714, 0, 0, 543, 488, 645, 341, 342, 343, + 344, 345, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 201, 246, 200, 233, 202, 0, 0, 0, 0, + 0, 0, 508, 826, 0, 654, 688, 677, 766, 641, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 401, 0, 0, 471, 692, 673, 684, 674, 514, 659, + 660, 661, 668, 413, 662, 798, 664, 633, 665, 634, + 666, 667, 0, 691, 640, 551, 490, 0, 708, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 833, 0, + 0, 0, 0, 0, 0, 0, 0, 832, 0, 0, + 269, 0, 0, 0, 0, 0, 0, 372, 270, 635, + 762, 637, 636, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 375, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 552, 580, 0, 594, 0, 440, 441, + 0, 0, 0, 0, 0, 0, 0, 356, 559, 577, + 373, 546, 592, 378, 554, 570, 368, 507, 542, 0, + 0, 358, 575, 553, 485, 357, 0, 535, 398, 415, + 395, 505, 0, 0, 574, 605, 394, 595, 0, 585, + 360, 0, 584, 504, 477, 571, 576, 486, 479, 0, + 359, 573, 484, 478, 454, 405, 621, 455, 456, 457, + 458, 459, 460, 419, 520, 475, 521, 420, 492, 491, + 493, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 430, 0, 0, 0, 0, 0, 616, 617, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 828, 829, 0, 754, 0, 247, 759, 0, 588, 0, + 0, 0, 0, 0, 0, 557, 0, 0, 461, 0, + 0, 0, 606, 0, 538, 510, 800, 0, 0, 536, + 473, 572, 522, 578, 560, 586, 529, 523, 350, 561, + 397, 487, 369, 371, 787, 399, 402, 406, 407, 498, + 499, 516, 545, 564, 565, 566, 396, 383, 537, 384, + 416, 385, 351, 388, 387, 389, 547, 390, 353, 517, + 569, 0, 412, 533, 482, 354, 481, 518, 568, 567, + 370, 596, 603, 604, 696, 0, 609, 801, 802, 803, + 618, 0, 524, 366, 363, 0, 0, 0, 392, 519, + 379, 381, 382, 380, 513, 515, 623, 624, 625, 627, + 628, 629, 630, 0, 0, 0, 0, 631, 697, 715, + 681, 650, 611, 705, 647, 651, 652, 433, 434, 435, + 436, 718, 0, 0, 0, 602, 462, 463, 0, 404, + 403, 483, 355, 0, 0, 451, 432, 525, 361, 400, + 453, 438, 464, 465, 466, 467, 468, 0, 469, 470, + 410, 340, 346, 795, 393, 506, 720, 757, 758, 642, + 0, 706, 643, 653, 386, 678, 690, 689, 500, 601, + 0, 701, 704, 632, 794, 0, 698, 712, 799, 711, + 791, 512, 0, 544, 709, 656, 0, 702, 675, 676, + 0, 703, 671, 707, 362, 439, 530, 587, 0, 644, + 0, 612, 615, 646, 733, 734, 735, 352, 614, 737, + 738, 739, 740, 741, 742, 743, 736, 583, 679, 655, + 682, 593, 658, 657, 0, 0, 693, 610, 694, 695, + 494, 495, 496, 497, 827, 831, 377, 613, 527, 528, + 842, 680, 0, 0, 0, 0, 0, 0, 0, 0, + 685, 686, 683, 804, 0, 744, 745, 0, 0, 607, + 608, 409, 0, 626, 417, 376, 511, 411, 591, 442, + 0, 619, 687, 620, 531, 532, 748, 753, 749, 750, + 752, 773, 501, 431, 437, 548, 452, 474, 534, 590, + 509, 539, 374, 579, 550, 480, 672, 700, 0, 0, + 0, 0, 0, 0, 0, 0, 79, 0, 0, 326, + 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 729, 728, 727, 726, 725, + 724, 723, 722, 0, 0, 669, 391, 792, 786, 793, + 774, 777, 776, 751, 0, 347, 649, 472, 526, 408, + 716, 717, 0, 772, 285, 286, 287, 288, 289, 290, + 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, + 304, 305, 306, 307, 308, 309, 310, 311, 719, 302, + 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, + 778, 779, 780, 781, 782, 0, 0, 335, 336, 337, + 0, 0, 300, 301, 328, 558, 329, 330, 331, 332, + 0, 0, 597, 598, 599, 622, 0, 600, 581, 648, + 418, 348, 562, 589, 789, 790, 0, 0, 0, 0, + 0, 0, 0, 699, 710, 746, 747, 0, 760, 761, + 763, 765, 764, 767, 555, 556, 775, 0, 0, 443, + 364, 365, 502, 503, 541, 0, 444, 445, 446, 450, + 447, 448, 449, 769, 770, 771, 768, 476, 540, 563, + 549, 788, 489, 0, 796, 638, 639, 797, 756, 755, + 349, 0, 338, 339, 713, 714, 0, 0, 543, 488, + 645, 341, 342, 343, 344, 345, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 508, 0, 0, 654, + 688, 677, 766, 641, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 401, 0, 0, 471, 692, 673, + 684, 674, 514, 659, 660, 661, 668, 413, 662, 798, + 664, 633, 665, 634, 666, 667, 0, 691, 640, 551, + 490, 0, 708, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1659, 0, 0, 269, 0, 0, 997, 1007, 0, + 0, 372, 270, 635, 762, 637, 636, 998, 0, 999, + 1003, 1006, 1002, 1000, 1001, 0, 375, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 552, 580, 0, + 594, 0, 440, 441, 0, 1004, 0, 0, 0, 0, + 0, 356, 559, 577, 373, 546, 592, 378, 554, 570, + 368, 507, 542, 0, 0, 358, 575, 553, 485, 357, + 0, 535, 398, 415, 395, 505, 1005, 0, 574, 605, + 394, 595, 0, 585, 360, 0, 584, 504, 477, 571, + 576, 486, 479, 0, 359, 573, 484, 478, 454, 405, + 621, 455, 456, 457, 458, 459, 460, 419, 520, 475, + 521, 420, 492, 491, 493, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 430, 0, 0, 0, 0, 0, + 616, 617, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 754, 0, 0, + 759, 0, 588, 0, 0, 0, 0, 0, 0, 557, + 0, 0, 461, 0, 0, 0, 606, 0, 538, 510, + 800, 0, 0, 536, 473, 572, 522, 578, 560, 586, + 529, 523, 350, 561, 397, 487, 369, 371, 787, 399, + 402, 406, 407, 498, 499, 516, 545, 564, 565, 566, + 396, 383, 537, 384, 416, 385, 351, 388, 387, 389, + 547, 390, 353, 517, 569, 0, 412, 533, 482, 354, + 481, 518, 568, 567, 370, 596, 603, 604, 696, 0, + 609, 801, 802, 803, 618, 0, 524, 366, 363, 0, + 0, 0, 392, 519, 379, 381, 382, 380, 513, 515, + 623, 624, 625, 627, 628, 629, 630, 0, 0, 0, + 0, 631, 697, 715, 681, 650, 611, 705, 647, 651, + 652, 433, 434, 435, 436, 718, 0, 0, 0, 602, + 462, 463, 0, 404, 403, 483, 355, 0, 0, 451, + 432, 525, 361, 400, 453, 438, 464, 465, 466, 467, + 468, 0, 469, 470, 410, 340, 346, 795, 393, 506, + 720, 757, 758, 642, 0, 706, 643, 653, 386, 678, + 690, 689, 500, 601, 0, 701, 704, 632, 794, 0, + 698, 712, 799, 711, 791, 512, 0, 544, 709, 656, + 0, 702, 675, 676, 0, 703, 671, 707, 362, 439, + 530, 587, 0, 644, 0, 612, 615, 646, 733, 734, + 735, 352, 614, 737, 738, 739, 740, 741, 742, 743, + 736, 583, 679, 655, 682, 593, 658, 657, 0, 0, + 693, 610, 694, 695, 494, 495, 496, 497, 414, 721, + 377, 613, 527, 528, 0, 680, 0, 0, 0, 0, + 0, 0, 0, 0, 685, 686, 683, 804, 0, 744, + 745, 0, 0, 607, 608, 409, 0, 626, 417, 376, + 511, 411, 591, 442, 0, 619, 687, 620, 531, 532, + 748, 753, 749, 750, 752, 773, 501, 431, 437, 548, + 452, 474, 534, 590, 509, 539, 374, 579, 550, 480, + 672, 700, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 326, 327, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 729, + 728, 727, 726, 725, 724, 723, 722, 0, 0, 669, + 391, 792, 786, 793, 774, 777, 776, 751, 0, 347, + 649, 472, 526, 408, 716, 717, 0, 772, 285, 286, + 287, 288, 289, 290, 291, 292, 333, 293, 294, 295, + 296, 297, 298, 299, 304, 305, 306, 307, 308, 309, + 310, 311, 719, 302, 303, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 323, 324, 325, 0, + 0, 0, 0, 334, 778, 779, 780, 781, 782, 0, + 0, 335, 336, 337, 0, 0, 300, 301, 328, 558, + 329, 330, 331, 332, 0, 0, 597, 598, 599, 622, + 0, 600, 581, 648, 418, 348, 562, 589, 789, 790, + 0, 0, 0, 0, 0, 0, 0, 699, 710, 746, + 747, 0, 760, 761, 763, 765, 764, 767, 555, 556, + 775, 0, 0, 443, 364, 365, 502, 503, 541, 0, + 444, 445, 446, 450, 447, 448, 449, 769, 770, 771, + 768, 476, 540, 563, 549, 788, 489, 0, 796, 638, + 639, 797, 756, 755, 349, 0, 338, 339, 713, 714, + 0, 0, 543, 488, 645, 341, 342, 343, 344, 345, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 508, 0, 0, 654, 688, 677, 766, 641, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 401, 0, + 0, 471, 692, 673, 684, 674, 514, 659, 660, 661, + 668, 413, 662, 798, 664, 633, 665, 634, 666, 667, + 0, 691, 640, 551, 490, 0, 708, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 269, 0, + 0, 0, 0, 0, 0, 372, 270, 635, 762, 637, + 636, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 375, 3085, 3088, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 552, 580, 0, 594, 0, 440, 441, 0, 0, + 0, 0, 0, 0, 0, 356, 559, 577, 373, 546, + 592, 378, 554, 570, 368, 507, 542, 0, 0, 358, + 575, 553, 485, 357, 0, 535, 398, 415, 395, 505, + 0, 0, 574, 605, 394, 595, 0, 585, 360, 0, + 584, 504, 477, 571, 576, 486, 479, 0, 359, 573, + 484, 478, 454, 405, 621, 455, 456, 457, 458, 459, + 460, 419, 520, 475, 521, 420, 492, 491, 493, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 430, 0, + 0, 0, 0, 0, 616, 617, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 754, 0, 0, 759, 3089, 588, 0, 0, 0, + 3084, 0, 3083, 557, 3080, 3086, 461, 0, 0, 0, + 606, 0, 538, 510, 800, 0, 0, 536, 473, 572, + 522, 578, 560, 586, 529, 523, 350, 561, 397, 487, + 369, 371, 787, 399, 402, 406, 407, 498, 499, 516, + 545, 564, 565, 566, 396, 383, 537, 384, 416, 385, + 351, 388, 387, 389, 547, 390, 353, 517, 569, 3087, + 412, 533, 482, 354, 481, 518, 568, 567, 370, 596, + 603, 604, 696, 0, 609, 801, 802, 803, 618, 0, + 524, 366, 363, 0, 0, 0, 392, 519, 379, 381, + 382, 380, 513, 515, 623, 624, 625, 627, 628, 629, + 630, 0, 0, 0, 0, 631, 697, 715, 681, 650, + 611, 705, 647, 651, 652, 433, 434, 435, 436, 718, + 0, 0, 0, 602, 462, 463, 0, 404, 403, 483, + 355, 0, 0, 451, 432, 525, 361, 400, 453, 438, + 464, 465, 466, 467, 468, 3081, 469, 470, 410, 340, + 346, 795, 393, 506, 720, 757, 758, 642, 0, 706, + 643, 653, 386, 678, 690, 689, 500, 601, 0, 701, + 704, 632, 794, 0, 698, 712, 799, 711, 791, 512, + 0, 544, 709, 656, 0, 702, 675, 676, 0, 703, + 671, 707, 362, 439, 530, 587, 0, 644, 0, 612, + 615, 646, 733, 734, 735, 352, 614, 737, 738, 739, + 740, 741, 742, 743, 736, 583, 679, 655, 682, 593, + 658, 657, 0, 0, 693, 610, 694, 695, 494, 495, + 496, 497, 414, 721, 377, 613, 527, 528, 0, 680, + 0, 0, 0, 0, 0, 0, 0, 0, 685, 686, + 683, 804, 0, 744, 745, 0, 0, 607, 608, 409, + 0, 626, 417, 376, 511, 411, 591, 442, 0, 619, + 687, 620, 531, 532, 748, 753, 749, 750, 752, 773, + 501, 431, 437, 548, 452, 474, 534, 590, 509, 539, + 374, 579, 550, 480, 672, 700, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 326, 327, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 729, 728, 727, 726, 725, 724, 723, + 722, 0, 0, 669, 391, 792, 786, 793, 774, 777, + 776, 751, 0, 347, 649, 472, 526, 408, 716, 717, + 0, 772, 285, 286, 287, 288, 289, 290, 291, 292, + 333, 293, 294, 295, 296, 297, 298, 299, 304, 305, + 306, 307, 308, 309, 310, 311, 719, 302, 303, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 323, 324, 325, 0, 0, 0, 0, 334, 778, 779, + 780, 781, 782, 0, 0, 335, 336, 337, 0, 0, + 300, 301, 328, 558, 329, 330, 331, 332, 0, 0, + 597, 598, 599, 622, 0, 600, 581, 648, 418, 348, + 562, 589, 789, 790, 0, 0, 0, 0, 0, 0, + 0, 699, 710, 746, 747, 0, 760, 761, 763, 765, + 764, 767, 555, 556, 775, 0, 0, 443, 364, 365, + 502, 503, 541, 0, 444, 445, 446, 450, 447, 448, + 449, 769, 770, 771, 768, 476, 540, 563, 549, 788, + 489, 0, 796, 638, 639, 797, 756, 755, 349, 0, + 338, 339, 713, 714, 0, 0, 543, 488, 645, 341, + 342, 343, 344, 345, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 508, 0, 0, 654, 688, 677, + 766, 641, 0, 1358, 0, 0, 0, 0, 0, 0, + 0, 0, 401, 0, 0, 471, 692, 673, 684, 674, + 514, 659, 660, 661, 668, 413, 662, 798, 664, 633, + 665, 634, 666, 667, 0, 691, 640, 551, 490, 0, + 708, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 269, 0, 0, 0, 0, 0, 0, 372, + 270, 635, 762, 637, 636, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 375, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 552, 580, 0, 594, 0, + 3532, 3533, 1338, 0, 0, 0, 0, 0, 0, 356, + 559, 577, 373, 546, 592, 378, 554, 570, 368, 507, + 542, 0, 0, 3526, 3529, 3530, 3531, 3534, 0, 3539, + 3535, 3536, 3537, 3538, 0, 0, 3522, 3523, 3524, 3525, + 1336, 3501, 3527, 0, 3502, 504, 3503, 3504, 3505, 3506, + 3507, 1341, 3508, 3509, 3510, 3511, 3512, 3519, 3520, 3513, + 3514, 3515, 3516, 3517, 3518, 3540, 3541, 3542, 3543, 3544, + 3545, 3546, 3547, 3549, 3548, 3550, 3551, 3552, 3553, 3554, + 3555, 3556, 3557, 1369, 1371, 1373, 1375, 1378, 616, 617, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 754, 0, 0, 759, 0, + 588, 0, 0, 0, 0, 0, 0, 557, 0, 0, + 461, 0, 0, 0, 3521, 0, 538, 510, 800, 0, + 0, 536, 473, 572, 522, 578, 560, 586, 529, 523, + 350, 561, 397, 487, 369, 371, 787, 399, 402, 406, + 407, 498, 499, 516, 545, 564, 565, 566, 396, 383, + 537, 384, 416, 385, 351, 388, 387, 389, 547, 390, + 353, 517, 569, 0, 412, 533, 482, 354, 481, 518, + 568, 567, 370, 596, 603, 604, 696, 0, 609, 801, + 802, 803, 618, 0, 524, 366, 363, 0, 0, 0, + 392, 519, 379, 381, 382, 380, 513, 515, 623, 624, + 625, 627, 628, 629, 630, 0, 0, 0, 0, 631, + 697, 715, 681, 650, 611, 705, 647, 651, 652, 433, + 434, 435, 436, 718, 0, 0, 0, 602, 462, 463, + 0, 404, 403, 483, 355, 0, 0, 451, 432, 525, + 361, 400, 453, 438, 464, 465, 466, 467, 468, 0, + 469, 470, 410, 340, 346, 795, 393, 506, 720, 757, + 758, 642, 0, 706, 643, 653, 386, 678, 690, 689, + 500, 601, 0, 701, 704, 632, 794, 0, 698, 712, + 799, 711, 791, 512, 0, 544, 709, 656, 0, 702, + 675, 676, 0, 703, 671, 707, 362, 439, 530, 587, + 0, 644, 0, 612, 615, 646, 733, 734, 735, 352, + 614, 737, 738, 739, 740, 741, 742, 743, 736, 583, + 679, 655, 682, 593, 658, 657, 0, 0, 693, 610, + 694, 695, 494, 495, 496, 497, 414, 721, 377, 613, + 527, 528, 0, 680, 0, 0, 0, 0, 0, 0, + 0, 0, 685, 686, 683, 804, 0, 744, 745, 0, + 0, 607, 608, 409, 0, 626, 417, 376, 511, 411, + 591, 442, 0, 619, 687, 620, 531, 532, 748, 753, + 749, 750, 752, 773, 501, 431, 437, 548, 452, 474, + 534, 590, 509, 539, 374, 579, 550, 480, 672, 700, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 326, 327, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 729, 728, 727, + 726, 725, 724, 723, 722, 0, 0, 669, 391, 792, + 786, 793, 774, 777, 776, 751, 0, 347, 3528, 472, + 526, 408, 716, 717, 0, 772, 285, 286, 287, 288, + 289, 290, 291, 292, 333, 293, 294, 295, 296, 297, + 298, 299, 304, 305, 306, 307, 308, 309, 310, 311, + 719, 302, 303, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 325, 0, 0, 0, + 0, 334, 778, 779, 780, 781, 782, 0, 0, 335, + 336, 337, 0, 0, 300, 301, 328, 558, 329, 330, + 331, 332, 0, 0, 597, 598, 599, 622, 0, 600, + 581, 648, 418, 348, 562, 589, 789, 790, 0, 0, + 0, 0, 0, 0, 0, 699, 710, 746, 747, 0, + 760, 761, 763, 765, 764, 767, 555, 556, 775, 0, + 0, 443, 364, 365, 502, 503, 541, 0, 444, 445, + 446, 450, 447, 448, 449, 769, 770, 771, 768, 476, + 540, 563, 549, 788, 489, 0, 796, 638, 639, 797, + 756, 755, 3500, 0, 338, 339, 713, 714, 0, 0, + 543, 488, 645, 1830, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 201, 246, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 1279, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1827, 0, 0, 269, 0, 0, + 0, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 247, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 0, 2480, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 3107, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 3106, 588, 0, 0, 0, 3113, 3109, 3111, 557, 0, + 3110, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 3104, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 3112, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, + 0, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 3107, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 0, 759, 3106, 588, 0, 0, 0, 3113, + 3109, 3111, 557, 0, 3110, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 3112, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 201, 246, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 508, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 1279, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 239, 3268, + 0, 269, 0, 0, 0, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 247, 759, 0, 588, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 529, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 743, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 0, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 751, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 755, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 201, 246, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 1279, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 239, 3007, 0, 269, 0, 0, 0, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 247, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 1830, 341, 342, 343, + 344, 345, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 508, 0, 0, 654, 688, 677, 766, 641, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 401, 0, 0, 471, 692, 673, 684, 674, 514, 659, + 660, 661, 668, 413, 662, 798, 664, 633, 665, 634, + 666, 667, 0, 691, 640, 551, 490, 0, 708, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1827, 0, 0, + 269, 0, 0, 0, 0, 0, 0, 372, 270, 635, + 762, 637, 636, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 375, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 552, 580, 0, 594, 0, 440, 441, + 0, 0, 0, 0, 0, 0, 0, 356, 559, 577, + 373, 546, 592, 378, 554, 570, 368, 507, 542, 0, + 0, 358, 575, 553, 485, 357, 0, 535, 398, 415, + 395, 505, 0, 0, 574, 605, 394, 595, 0, 585, + 360, 0, 584, 504, 477, 571, 576, 486, 479, 0, + 359, 573, 484, 478, 454, 405, 621, 455, 456, 457, + 458, 459, 460, 419, 520, 475, 521, 420, 492, 491, + 493, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 430, 0, 0, 0, 0, 0, 616, 617, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 754, 0, 0, 759, 0, 588, 0, + 0, 0, 0, 0, 0, 557, 0, 0, 461, 0, + 0, 0, 606, 0, 538, 510, 800, 0, 0, 536, + 473, 572, 522, 578, 560, 586, 529, 523, 350, 561, + 397, 487, 369, 371, 787, 399, 402, 406, 407, 498, + 499, 516, 545, 564, 565, 566, 396, 383, 537, 384, + 416, 385, 351, 388, 387, 389, 547, 390, 353, 517, + 569, 0, 412, 533, 482, 354, 481, 518, 568, 567, + 370, 596, 603, 604, 696, 0, 609, 801, 802, 803, + 618, 0, 524, 366, 363, 0, 0, 0, 392, 519, + 379, 381, 382, 380, 513, 515, 623, 624, 625, 627, + 628, 629, 630, 0, 0, 0, 0, 631, 697, 715, + 681, 650, 611, 705, 647, 651, 652, 433, 434, 435, + 436, 718, 0, 0, 0, 602, 462, 463, 0, 404, + 403, 483, 355, 0, 0, 451, 432, 525, 361, 400, + 453, 438, 464, 465, 466, 467, 468, 0, 469, 470, + 410, 340, 346, 795, 393, 506, 720, 757, 758, 642, + 0, 706, 643, 653, 386, 678, 690, 689, 500, 601, + 0, 701, 704, 632, 794, 0, 698, 712, 799, 711, + 791, 512, 0, 544, 709, 656, 0, 702, 675, 676, + 0, 703, 671, 707, 362, 439, 530, 587, 0, 644, + 0, 612, 615, 646, 733, 734, 735, 352, 614, 737, + 738, 739, 740, 741, 742, 743, 736, 583, 679, 655, + 682, 593, 658, 657, 0, 0, 693, 610, 694, 695, + 494, 495, 496, 497, 414, 721, 377, 613, 527, 528, + 0, 680, 0, 0, 0, 0, 0, 0, 0, 0, + 685, 686, 683, 804, 0, 744, 745, 0, 0, 607, + 608, 409, 0, 626, 417, 376, 511, 411, 591, 442, + 0, 619, 687, 620, 531, 532, 748, 753, 749, 750, + 752, 773, 501, 431, 437, 548, 452, 474, 534, 590, + 509, 539, 374, 579, 550, 480, 672, 700, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, + 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 729, 728, 727, 726, 725, + 724, 723, 722, 0, 0, 669, 391, 792, 786, 793, + 774, 777, 776, 751, 0, 347, 649, 472, 526, 408, + 716, 717, 0, 772, 285, 286, 287, 288, 289, 290, + 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, + 304, 305, 306, 307, 308, 309, 310, 311, 719, 302, + 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, + 778, 779, 780, 781, 782, 0, 0, 335, 336, 337, + 0, 0, 300, 301, 328, 558, 329, 330, 331, 332, + 0, 0, 597, 598, 599, 622, 0, 600, 581, 648, + 418, 348, 562, 589, 789, 790, 0, 0, 0, 0, + 0, 0, 0, 699, 710, 746, 747, 0, 760, 761, + 763, 765, 764, 767, 555, 556, 775, 0, 0, 443, + 364, 365, 502, 503, 541, 0, 444, 445, 446, 450, + 447, 448, 449, 769, 770, 771, 768, 476, 540, 563, + 549, 788, 489, 0, 796, 638, 639, 797, 756, 755, + 349, 0, 338, 339, 713, 714, 0, 0, 543, 488, + 645, 0, 2480, 341, 342, 343, 344, 345, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 508, 0, + 0, 654, 688, 677, 766, 641, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 401, 1252, 0, 471, + 692, 673, 684, 674, 514, 659, 660, 661, 668, 413, + 662, 798, 664, 633, 665, 634, 666, 667, 0, 691, + 640, 551, 490, 0, 708, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 269, 1259, 1260, 0, + 0, 0, 0, 372, 270, 635, 762, 637, 636, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1263, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 552, + 580, 0, 594, 0, 440, 441, 0, 0, 0, 0, + 0, 0, 0, 356, 559, 1246, 373, 546, 592, 378, + 554, 570, 368, 507, 542, 0, 0, 358, 575, 553, + 485, 357, 0, 535, 398, 415, 395, 505, 0, 0, + 574, 605, 394, 595, 908, 585, 360, 907, 584, 504, + 477, 571, 576, 486, 479, 0, 359, 573, 484, 478, + 454, 405, 621, 455, 456, 457, 458, 459, 460, 419, + 520, 475, 521, 420, 492, 491, 493, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 430, 0, 0, 0, + 0, 0, 616, 617, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 754, + 0, 0, 759, 0, 588, 0, 0, 0, 0, 0, + 0, 557, 0, 0, 461, 0, 0, 0, 606, 0, + 538, 510, 800, 0, 0, 536, 473, 572, 522, 578, + 560, 586, 1250, 523, 350, 561, 397, 487, 369, 371, + 787, 399, 402, 406, 407, 498, 499, 516, 545, 564, + 565, 566, 396, 383, 537, 384, 416, 385, 351, 388, + 387, 389, 547, 390, 353, 517, 569, 0, 412, 533, + 482, 354, 481, 518, 568, 567, 370, 596, 603, 604, + 696, 0, 609, 801, 802, 803, 618, 0, 524, 366, + 363, 0, 0, 0, 392, 519, 379, 381, 382, 380, + 513, 515, 623, 624, 625, 627, 628, 629, 630, 0, + 0, 0, 0, 631, 697, 715, 681, 650, 611, 705, + 647, 651, 652, 433, 434, 435, 436, 718, 0, 0, + 0, 602, 462, 463, 0, 404, 403, 483, 355, 0, + 0, 451, 432, 525, 361, 400, 453, 438, 464, 465, + 466, 467, 468, 0, 469, 470, 410, 340, 346, 795, + 393, 506, 720, 757, 758, 642, 0, 706, 643, 653, + 386, 678, 690, 689, 500, 601, 0, 701, 704, 632, + 794, 0, 698, 712, 799, 711, 791, 512, 0, 544, + 709, 656, 0, 702, 675, 676, 0, 703, 671, 707, + 362, 439, 530, 587, 0, 644, 0, 612, 615, 646, + 733, 734, 735, 352, 614, 737, 738, 739, 740, 741, + 742, 1251, 736, 583, 679, 655, 682, 593, 658, 657, + 0, 0, 693, 1254, 694, 695, 494, 495, 496, 497, + 414, 721, 1249, 613, 527, 528, 0, 680, 0, 0, + 0, 0, 0, 0, 0, 0, 685, 686, 683, 804, + 0, 744, 745, 0, 0, 607, 608, 409, 0, 626, + 417, 376, 511, 411, 591, 442, 0, 619, 687, 620, + 531, 532, 748, 753, 749, 750, 752, 773, 1261, 1247, + 1257, 1248, 452, 474, 534, 590, 509, 539, 374, 579, + 550, 1258, 672, 700, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 326, 327, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 729, 728, 727, 726, 725, 724, 723, 722, 0, + 0, 669, 391, 792, 786, 793, 774, 777, 776, 751, + 0, 347, 649, 472, 526, 408, 716, 717, 0, 772, + 285, 286, 287, 288, 289, 290, 291, 292, 333, 293, + 294, 295, 296, 297, 298, 299, 304, 305, 306, 307, + 308, 309, 310, 311, 719, 302, 303, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 0, 0, 0, 0, 334, 778, 779, 780, 781, + 782, 0, 0, 335, 336, 337, 0, 0, 300, 301, + 328, 558, 329, 330, 331, 332, 0, 0, 597, 598, + 599, 622, 0, 600, 581, 648, 418, 348, 562, 589, + 789, 790, 0, 0, 0, 0, 0, 0, 0, 699, + 710, 746, 747, 0, 760, 761, 763, 765, 764, 767, + 555, 556, 775, 0, 0, 443, 364, 365, 502, 503, + 541, 0, 444, 445, 446, 450, 447, 448, 449, 769, + 770, 771, 768, 1245, 540, 563, 549, 788, 489, 0, + 796, 638, 639, 797, 756, 755, 349, 0, 338, 339, + 713, 714, 0, 0, 543, 488, 645, 341, 342, 343, + 344, 345, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 508, 0, 0, 654, 688, 677, 766, 641, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 401, 0, 0, 471, 692, 673, 684, 674, 514, 659, + 660, 661, 668, 413, 662, 798, 664, 633, 665, 634, + 666, 667, 0, 691, 640, 551, 490, 0, 708, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 269, 1259, 1260, 0, 0, 0, 0, 372, 270, 635, + 762, 637, 636, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1263, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 552, 580, 0, 594, 0, 440, 441, + 0, 0, 0, 0, 0, 0, 0, 356, 559, 577, + 373, 546, 592, 378, 554, 570, 368, 507, 542, 0, + 0, 358, 575, 553, 485, 357, 0, 535, 398, 415, + 395, 505, 0, 0, 574, 605, 394, 595, 908, 585, + 360, 907, 584, 504, 477, 571, 576, 486, 479, 0, + 359, 573, 484, 478, 454, 405, 621, 455, 456, 457, + 458, 459, 460, 419, 520, 475, 521, 420, 492, 491, + 493, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 430, 0, 0, 0, 0, 0, 616, 617, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 754, 0, 0, 759, 0, 588, 0, + 0, 0, 0, 0, 0, 557, 0, 0, 461, 0, + 0, 0, 606, 0, 538, 510, 800, 0, 0, 536, + 473, 572, 522, 578, 560, 586, 529, 523, 350, 561, + 397, 487, 369, 371, 787, 399, 402, 406, 407, 498, + 499, 516, 545, 564, 565, 566, 396, 383, 537, 384, + 416, 385, 351, 388, 387, 389, 547, 390, 353, 517, + 569, 0, 412, 533, 482, 354, 481, 518, 568, 567, + 370, 596, 603, 604, 696, 0, 609, 801, 802, 803, + 618, 0, 524, 366, 363, 0, 0, 0, 392, 519, + 379, 381, 382, 380, 513, 515, 623, 624, 625, 627, + 628, 629, 630, 0, 0, 0, 0, 631, 697, 715, + 681, 650, 611, 705, 647, 651, 652, 433, 434, 435, + 436, 718, 0, 0, 0, 602, 462, 463, 0, 404, + 403, 483, 355, 0, 0, 451, 432, 525, 361, 400, + 453, 438, 464, 465, 466, 467, 468, 0, 469, 470, + 410, 340, 346, 795, 393, 506, 720, 757, 758, 642, + 0, 706, 643, 653, 386, 678, 690, 689, 500, 601, + 0, 701, 704, 632, 794, 0, 698, 712, 799, 711, + 791, 512, 0, 544, 709, 656, 0, 702, 675, 676, + 0, 703, 671, 707, 362, 439, 530, 587, 0, 644, + 0, 612, 615, 646, 733, 734, 735, 352, 614, 737, + 738, 739, 740, 741, 742, 743, 736, 583, 679, 655, + 682, 593, 658, 657, 0, 0, 693, 610, 694, 695, + 494, 495, 496, 497, 414, 721, 377, 613, 527, 528, + 0, 680, 0, 0, 0, 0, 0, 0, 0, 0, + 685, 686, 683, 804, 0, 744, 745, 0, 0, 607, + 608, 409, 0, 626, 417, 376, 511, 411, 591, 442, + 0, 619, 687, 620, 531, 532, 748, 753, 749, 750, + 752, 773, 1261, 2594, 1257, 2595, 452, 474, 534, 590, + 509, 539, 374, 579, 550, 1258, 672, 700, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, + 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 729, 728, 727, 726, 725, + 724, 723, 722, 0, 0, 669, 391, 792, 786, 793, + 774, 777, 776, 751, 0, 347, 649, 472, 526, 408, + 716, 717, 0, 772, 285, 286, 287, 288, 289, 290, + 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, + 304, 305, 306, 307, 308, 309, 310, 311, 719, 302, + 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, + 778, 779, 780, 781, 782, 0, 0, 335, 336, 337, + 0, 0, 300, 301, 328, 558, 329, 330, 331, 332, + 0, 0, 597, 598, 599, 622, 0, 600, 581, 648, + 418, 348, 562, 589, 789, 790, 0, 0, 0, 0, + 0, 0, 0, 699, 710, 746, 747, 0, 760, 761, + 763, 765, 764, 767, 555, 556, 775, 0, 0, 443, + 364, 365, 502, 503, 541, 0, 444, 445, 446, 450, + 447, 448, 449, 769, 770, 771, 768, 476, 540, 563, + 549, 788, 489, 0, 796, 638, 639, 797, 756, 755, + 349, 0, 338, 339, 713, 714, 0, 0, 543, 488, + 645, 341, 342, 343, 344, 345, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 508, 0, 0, 654, + 688, 677, 766, 641, 0, 0, 3822, 0, 0, 0, + 0, 0, 0, 0, 401, 0, 0, 471, 692, 673, + 684, 674, 514, 659, 660, 661, 668, 413, 662, 798, + 664, 633, 665, 634, 666, 667, 0, 691, 640, 551, + 490, 0, 708, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, + 0, 372, 270, 635, 762, 637, 636, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 375, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 552, 580, 0, + 594, 0, 440, 441, 0, 0, 0, 0, 0, 0, + 0, 356, 559, 577, 373, 546, 592, 378, 554, 570, + 368, 507, 542, 0, 0, 358, 575, 553, 485, 357, + 0, 535, 398, 415, 395, 505, 0, 0, 574, 605, + 394, 595, 0, 585, 360, 0, 584, 504, 477, 571, + 576, 486, 479, 0, 359, 573, 484, 478, 454, 405, + 621, 455, 456, 457, 458, 459, 460, 419, 520, 475, + 521, 420, 492, 491, 493, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 430, 0, 0, 0, 0, 0, + 616, 617, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3825, 0, 0, 0, 0, 3824, 754, 0, 0, + 759, 0, 588, 0, 0, 0, 0, 0, 0, 557, + 0, 0, 461, 0, 0, 0, 606, 0, 538, 510, + 800, 0, 0, 536, 473, 572, 522, 578, 560, 586, + 529, 523, 350, 561, 397, 487, 369, 371, 787, 399, + 402, 406, 407, 498, 499, 516, 545, 564, 565, 566, + 396, 383, 537, 384, 416, 385, 351, 388, 387, 389, + 547, 390, 353, 517, 569, 0, 412, 533, 482, 354, + 481, 518, 568, 567, 370, 596, 603, 604, 696, 0, + 609, 801, 802, 803, 618, 0, 524, 366, 363, 0, + 0, 0, 392, 519, 379, 381, 382, 380, 513, 515, + 623, 624, 625, 627, 628, 629, 630, 0, 0, 0, + 0, 631, 697, 715, 681, 650, 611, 705, 647, 651, + 652, 433, 434, 435, 436, 718, 0, 0, 0, 602, + 462, 463, 0, 404, 403, 483, 355, 0, 0, 451, + 432, 525, 361, 400, 453, 438, 464, 465, 466, 467, + 468, 0, 469, 470, 410, 340, 346, 795, 393, 506, + 720, 757, 758, 642, 0, 706, 643, 653, 386, 678, + 690, 689, 500, 601, 0, 701, 704, 632, 794, 0, + 698, 712, 799, 711, 791, 512, 0, 544, 709, 656, + 0, 702, 675, 676, 0, 703, 671, 707, 362, 439, + 530, 587, 0, 644, 0, 612, 615, 646, 733, 734, + 735, 352, 614, 737, 738, 739, 740, 741, 742, 743, + 736, 583, 679, 655, 682, 593, 658, 657, 0, 0, + 693, 610, 694, 695, 494, 495, 496, 497, 414, 721, + 377, 613, 527, 528, 0, 680, 0, 0, 0, 0, + 0, 0, 0, 0, 685, 686, 683, 804, 0, 744, + 745, 0, 0, 607, 608, 409, 0, 626, 417, 376, + 511, 411, 591, 442, 0, 619, 687, 620, 531, 532, + 748, 753, 749, 750, 752, 773, 501, 431, 437, 548, + 452, 474, 534, 590, 509, 539, 374, 579, 550, 480, + 672, 700, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 326, 327, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 729, + 728, 727, 726, 725, 724, 723, 722, 0, 0, 669, + 391, 792, 786, 793, 774, 777, 776, 751, 0, 347, + 649, 472, 526, 408, 716, 717, 0, 772, 285, 286, + 287, 288, 289, 290, 291, 292, 333, 293, 294, 295, + 296, 297, 298, 299, 304, 305, 306, 307, 308, 309, + 310, 311, 719, 302, 303, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 323, 324, 325, 0, + 0, 0, 0, 334, 778, 779, 780, 781, 782, 0, + 0, 335, 336, 337, 0, 0, 300, 301, 328, 558, + 329, 330, 331, 332, 0, 0, 597, 598, 599, 622, + 0, 600, 581, 648, 418, 348, 562, 589, 789, 790, + 0, 0, 0, 0, 0, 0, 0, 699, 710, 746, + 747, 0, 760, 761, 763, 765, 764, 767, 555, 556, + 775, 0, 0, 443, 364, 365, 502, 503, 541, 0, + 444, 445, 446, 450, 447, 448, 449, 769, 770, 771, + 768, 476, 540, 563, 549, 788, 489, 0, 796, 638, + 639, 797, 756, 755, 349, 0, 338, 339, 713, 714, + 0, 0, 543, 488, 645, 341, 342, 343, 344, 345, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 654, 688, 677, 766, 641, 0, 0, + 0, 0, 0, 2654, 0, 0, 0, 0, 401, 0, + 0, 471, 692, 673, 684, 674, 514, 659, 660, 661, + 668, 413, 662, 798, 664, 633, 665, 634, 666, 667, + 0, 691, 640, 551, 490, 0, 708, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 269, 0, + 0, 2655, 0, 0, 0, 372, 270, 635, 762, 637, + 636, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 375, 0, 0, 1580, 0, 1581, 1579, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 552, 580, 0, 594, 0, 440, 441, 0, 0, + 0, 0, 0, 0, 0, 356, 559, 577, 373, 546, + 592, 378, 554, 570, 368, 507, 542, 0, 0, 358, + 575, 553, 485, 357, 0, 535, 398, 415, 395, 505, + 0, 0, 574, 605, 394, 595, 0, 585, 360, 0, + 584, 504, 477, 571, 576, 486, 479, 0, 359, 573, + 484, 478, 454, 405, 621, 455, 456, 457, 458, 459, + 460, 419, 520, 475, 521, 420, 492, 491, 493, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 430, 0, + 0, 0, 0, 0, 616, 617, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 754, 0, 0, 759, 0, 588, 0, 0, 0, + 0, 0, 0, 557, 0, 0, 461, 0, 0, 0, + 606, 0, 538, 510, 800, 0, 0, 536, 473, 572, + 522, 578, 560, 586, 529, 523, 350, 561, 397, 487, + 369, 371, 787, 399, 402, 406, 407, 498, 499, 516, + 545, 564, 565, 566, 396, 383, 537, 384, 416, 385, + 351, 388, 387, 389, 547, 390, 353, 517, 569, 0, + 412, 533, 482, 354, 481, 518, 568, 567, 370, 596, + 603, 604, 696, 0, 609, 801, 802, 803, 618, 0, + 524, 366, 363, 0, 0, 0, 392, 519, 379, 381, + 382, 380, 513, 515, 623, 624, 625, 627, 628, 629, + 630, 0, 0, 0, 0, 631, 697, 715, 681, 650, + 611, 705, 647, 651, 652, 433, 434, 435, 436, 718, + 0, 0, 0, 602, 462, 463, 0, 404, 403, 483, + 355, 0, 0, 451, 432, 525, 361, 400, 453, 438, + 464, 465, 466, 467, 468, 0, 469, 470, 410, 340, + 346, 795, 393, 506, 720, 757, 758, 642, 0, 706, + 643, 653, 386, 678, 690, 689, 500, 601, 0, 701, + 704, 632, 794, 0, 698, 712, 799, 711, 791, 512, + 0, 544, 709, 656, 0, 702, 675, 676, 0, 703, + 671, 707, 362, 439, 530, 587, 0, 644, 0, 612, + 615, 646, 733, 734, 735, 352, 614, 737, 738, 739, + 740, 741, 742, 743, 736, 583, 679, 655, 682, 593, + 658, 657, 0, 0, 693, 610, 694, 695, 494, 495, + 496, 497, 414, 721, 377, 613, 527, 528, 0, 680, + 0, 0, 0, 0, 0, 0, 0, 0, 685, 686, + 683, 804, 0, 744, 745, 0, 0, 607, 608, 409, + 0, 626, 417, 376, 511, 411, 591, 442, 0, 619, + 687, 620, 531, 532, 748, 753, 749, 750, 752, 773, + 501, 431, 437, 548, 452, 474, 534, 590, 509, 539, + 374, 579, 550, 480, 672, 700, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 326, 327, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 729, 728, 727, 726, 725, 724, 723, + 722, 0, 0, 669, 391, 792, 786, 793, 774, 777, + 776, 751, 0, 347, 649, 472, 526, 408, 716, 717, + 0, 772, 285, 286, 287, 288, 289, 290, 291, 292, + 333, 293, 294, 295, 296, 297, 298, 299, 304, 305, + 306, 307, 308, 309, 310, 311, 719, 302, 303, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 323, 324, 325, 0, 0, 0, 0, 334, 778, 779, + 780, 781, 782, 0, 0, 335, 336, 337, 0, 0, + 300, 301, 328, 558, 329, 330, 331, 332, 0, 0, + 597, 598, 599, 622, 0, 600, 581, 648, 418, 348, + 562, 589, 789, 790, 0, 0, 0, 0, 0, 0, + 0, 699, 710, 746, 747, 0, 760, 761, 763, 765, + 764, 767, 555, 556, 775, 0, 0, 443, 364, 365, + 502, 503, 541, 0, 444, 445, 446, 450, 447, 448, + 449, 769, 770, 771, 768, 476, 540, 563, 549, 788, + 489, 0, 796, 638, 639, 797, 756, 0, 349, 0, + 338, 339, 713, 714, 0, 0, 543, 488, 645, 341, + 342, 343, 344, 345, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 508, 0, 0, 654, 688, 677, + 766, 641, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 401, 1889, 0, 471, 692, 673, 684, 674, + 514, 659, 660, 661, 668, 413, 662, 798, 664, 633, + 665, 634, 666, 667, 0, 691, 640, 551, 490, 0, + 708, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 269, 0, 0, 1887, 0, 0, 0, 372, + 270, 635, 762, 637, 636, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 375, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 552, 580, 0, 594, 0, + 440, 441, 1885, 0, 0, 0, 0, 0, 0, 356, + 559, 577, 373, 546, 592, 378, 554, 570, 368, 507, + 542, 0, 0, 358, 575, 553, 485, 357, 0, 535, + 398, 415, 395, 505, 0, 0, 574, 605, 394, 595, + 0, 585, 360, 0, 584, 504, 477, 571, 576, 486, + 479, 0, 359, 573, 484, 478, 454, 405, 621, 455, + 456, 457, 458, 459, 460, 419, 520, 475, 521, 420, + 492, 491, 493, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 430, 0, 0, 0, 0, 0, 616, 617, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 754, 0, 0, 759, 0, + 588, 0, 0, 0, 0, 0, 0, 557, 0, 0, + 461, 0, 0, 0, 606, 0, 538, 510, 800, 0, + 0, 536, 473, 572, 522, 578, 560, 586, 529, 523, + 350, 561, 397, 487, 369, 371, 787, 399, 402, 406, + 407, 498, 499, 516, 545, 564, 565, 566, 396, 383, + 537, 384, 416, 385, 351, 388, 387, 389, 547, 390, + 353, 517, 569, 0, 412, 533, 482, 354, 481, 518, + 568, 567, 370, 596, 603, 604, 696, 0, 609, 801, + 802, 803, 618, 0, 524, 366, 363, 0, 0, 0, + 392, 519, 379, 381, 382, 380, 513, 515, 623, 624, + 625, 627, 628, 629, 630, 0, 0, 0, 0, 631, + 697, 715, 681, 650, 611, 705, 647, 651, 652, 433, + 434, 435, 436, 718, 0, 0, 0, 602, 462, 463, + 0, 404, 403, 483, 355, 0, 0, 451, 432, 525, + 361, 400, 453, 438, 464, 465, 466, 467, 468, 0, + 469, 470, 410, 340, 346, 795, 393, 506, 720, 757, + 758, 642, 0, 706, 643, 653, 386, 678, 690, 689, + 500, 601, 0, 701, 704, 632, 794, 0, 698, 712, + 799, 711, 791, 512, 0, 544, 709, 656, 0, 702, + 675, 676, 0, 703, 671, 707, 362, 439, 530, 587, + 0, 644, 0, 612, 615, 646, 733, 734, 735, 352, + 614, 737, 738, 739, 740, 741, 742, 743, 736, 583, + 679, 655, 682, 593, 658, 657, 0, 0, 693, 610, + 694, 695, 494, 495, 496, 497, 414, 721, 377, 613, + 527, 528, 0, 680, 0, 0, 0, 0, 0, 0, + 0, 0, 685, 686, 683, 804, 0, 744, 745, 0, + 0, 607, 608, 409, 0, 626, 417, 376, 511, 411, + 591, 442, 0, 619, 687, 620, 531, 532, 748, 753, + 749, 750, 752, 773, 501, 431, 437, 548, 452, 474, + 534, 590, 509, 539, 374, 579, 550, 480, 672, 700, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 326, 327, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 729, 728, 727, + 726, 725, 724, 723, 722, 0, 0, 669, 391, 792, + 786, 793, 774, 777, 776, 751, 0, 347, 649, 472, + 526, 408, 716, 717, 0, 772, 285, 286, 287, 288, + 289, 290, 291, 292, 333, 293, 294, 295, 296, 297, + 298, 299, 304, 305, 306, 307, 308, 309, 310, 311, + 719, 302, 303, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 325, 0, 0, 0, + 0, 334, 778, 779, 780, 781, 782, 0, 0, 335, + 336, 337, 0, 0, 300, 301, 328, 558, 329, 330, + 331, 332, 0, 0, 597, 598, 599, 622, 0, 600, + 581, 648, 418, 348, 562, 589, 789, 790, 0, 0, + 0, 0, 0, 0, 0, 699, 710, 746, 747, 0, + 760, 761, 763, 765, 764, 767, 555, 556, 775, 0, + 0, 443, 364, 365, 502, 503, 541, 0, 444, 445, + 446, 450, 447, 448, 449, 769, 770, 771, 768, 476, + 540, 563, 549, 788, 489, 0, 796, 638, 639, 797, + 756, 755, 349, 0, 338, 339, 713, 714, 0, 0, + 543, 488, 645, 341, 342, 343, 344, 345, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 508, 0, + 0, 654, 688, 677, 766, 641, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 401, 1883, 0, 471, + 692, 673, 684, 674, 514, 659, 660, 661, 668, 413, + 662, 798, 664, 633, 665, 634, 666, 667, 0, 691, + 640, 551, 490, 0, 708, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 269, 0, 0, 1887, + 0, 0, 0, 372, 270, 635, 762, 637, 636, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 375, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 552, + 580, 0, 594, 0, 440, 441, 1885, 0, 0, 0, + 0, 0, 0, 356, 559, 577, 373, 546, 592, 378, + 554, 570, 368, 507, 542, 0, 0, 358, 575, 553, + 485, 357, 0, 535, 398, 415, 395, 505, 0, 0, + 574, 605, 394, 595, 0, 585, 360, 0, 584, 504, + 477, 571, 576, 486, 479, 0, 359, 573, 484, 478, + 454, 405, 621, 455, 456, 457, 458, 459, 460, 419, + 520, 475, 521, 420, 492, 491, 493, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 430, 0, 0, 0, + 0, 0, 616, 617, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 754, + 0, 0, 759, 0, 588, 0, 0, 0, 0, 0, + 0, 557, 0, 0, 461, 0, 0, 0, 606, 0, + 538, 510, 800, 0, 0, 536, 473, 572, 522, 578, + 560, 586, 529, 523, 350, 561, 397, 487, 369, 371, + 787, 399, 402, 406, 407, 498, 499, 516, 545, 564, + 565, 566, 396, 383, 537, 384, 416, 385, 351, 388, + 387, 389, 547, 390, 353, 517, 569, 0, 412, 533, + 482, 354, 481, 518, 568, 567, 370, 596, 603, 604, + 696, 0, 609, 801, 802, 803, 618, 0, 524, 366, + 363, 0, 0, 0, 392, 519, 379, 381, 382, 380, + 513, 515, 623, 624, 625, 627, 628, 629, 630, 0, + 0, 0, 0, 631, 697, 715, 681, 650, 611, 705, + 647, 651, 652, 433, 434, 435, 436, 718, 0, 0, + 0, 602, 462, 463, 0, 404, 403, 483, 355, 0, + 0, 451, 432, 525, 361, 400, 453, 438, 464, 465, + 466, 467, 468, 0, 469, 470, 410, 340, 346, 795, + 393, 506, 720, 757, 758, 642, 0, 706, 643, 653, + 386, 678, 690, 689, 500, 601, 0, 701, 704, 632, + 794, 0, 698, 712, 799, 711, 791, 512, 0, 544, + 709, 656, 0, 702, 675, 676, 0, 703, 671, 707, + 362, 439, 530, 587, 0, 644, 0, 612, 615, 646, + 733, 734, 735, 352, 614, 737, 738, 739, 740, 741, + 742, 743, 736, 583, 679, 655, 682, 593, 658, 657, + 0, 0, 693, 610, 694, 695, 494, 495, 496, 497, + 414, 721, 377, 613, 527, 528, 0, 680, 0, 0, + 0, 0, 0, 0, 0, 0, 685, 686, 683, 804, + 0, 744, 745, 0, 0, 607, 608, 409, 0, 626, + 417, 376, 511, 411, 591, 442, 0, 619, 687, 620, + 531, 532, 748, 753, 749, 750, 752, 773, 501, 431, + 437, 548, 452, 474, 534, 590, 509, 539, 374, 579, + 550, 480, 672, 700, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 326, 327, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 729, 728, 727, 726, 725, 724, 723, 722, 0, + 0, 669, 391, 792, 786, 793, 774, 777, 776, 751, + 0, 347, 649, 472, 526, 408, 716, 717, 0, 772, + 285, 286, 287, 288, 289, 290, 291, 292, 333, 293, + 294, 295, 296, 297, 298, 299, 304, 305, 306, 307, + 308, 309, 310, 311, 719, 302, 303, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 0, 0, 0, 0, 334, 778, 779, 780, 781, + 782, 0, 0, 335, 336, 337, 0, 0, 300, 301, + 328, 558, 329, 330, 331, 332, 0, 0, 597, 598, + 599, 622, 0, 600, 581, 648, 418, 348, 562, 589, + 789, 790, 0, 0, 0, 0, 0, 0, 0, 699, + 710, 746, 747, 0, 760, 761, 763, 765, 764, 767, + 555, 556, 775, 0, 0, 443, 364, 365, 502, 503, + 541, 0, 444, 445, 446, 450, 447, 448, 449, 769, + 770, 771, 768, 476, 540, 563, 549, 788, 489, 0, + 796, 638, 639, 797, 756, 755, 349, 0, 338, 339, + 713, 714, 0, 0, 543, 488, 645, 341, 342, 343, + 344, 345, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 508, 0, 0, 654, 688, 677, 766, 641, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 401, 1848, 0, 471, 692, 673, 684, 674, 514, 659, + 660, 661, 668, 413, 662, 798, 664, 633, 665, 634, + 666, 667, 0, 691, 640, 551, 490, 0, 708, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 269, 0, 0, 0, 0, 0, 0, 372, 270, 635, + 762, 637, 636, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 375, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1849, 0, 0, 552, 580, 0, 594, 0, 440, 441, + 0, 0, 0, 0, 0, 0, 0, 356, 559, 577, + 373, 546, 592, 378, 554, 570, 368, 507, 542, 0, + 0, 358, 575, 553, 485, 357, 0, 535, 398, 415, + 395, 505, 0, 0, 574, 605, 394, 595, 0, 585, + 360, 1847, 584, 504, 477, 571, 576, 486, 479, 0, + 359, 573, 484, 478, 454, 405, 621, 455, 456, 457, + 458, 459, 460, 419, 520, 475, 521, 420, 492, 491, + 493, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 430, 0, 0, 0, 0, 0, 616, 617, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 754, 0, 0, 759, 0, 588, 0, + 0, 0, 0, 0, 0, 557, 0, 0, 461, 0, + 0, 0, 606, 0, 538, 510, 800, 0, 0, 536, + 473, 572, 522, 578, 560, 586, 529, 523, 350, 561, + 397, 487, 369, 371, 787, 399, 402, 406, 407, 498, + 499, 516, 545, 564, 565, 566, 396, 383, 537, 384, + 416, 385, 351, 388, 387, 389, 547, 390, 353, 517, + 569, 0, 412, 533, 482, 354, 481, 518, 568, 567, + 370, 596, 603, 604, 696, 0, 609, 801, 802, 803, + 618, 0, 524, 366, 363, 0, 0, 0, 392, 519, + 379, 381, 382, 380, 513, 515, 623, 624, 625, 627, + 628, 629, 630, 0, 0, 0, 0, 631, 697, 715, + 681, 650, 611, 705, 647, 651, 652, 433, 434, 435, + 436, 718, 0, 0, 0, 602, 462, 463, 0, 404, + 403, 483, 355, 0, 0, 451, 432, 525, 361, 400, + 453, 438, 464, 465, 466, 467, 468, 0, 469, 470, + 410, 340, 346, 795, 393, 506, 720, 757, 758, 642, + 0, 706, 643, 653, 386, 678, 690, 689, 500, 601, + 0, 701, 704, 632, 794, 0, 698, 712, 799, 711, + 791, 512, 0, 544, 709, 656, 0, 702, 675, 676, + 0, 703, 671, 707, 362, 439, 530, 587, 0, 644, + 0, 612, 615, 646, 733, 734, 735, 352, 614, 737, + 738, 739, 740, 741, 742, 743, 736, 583, 679, 655, + 682, 593, 658, 657, 0, 0, 693, 610, 694, 695, + 494, 495, 496, 497, 414, 721, 377, 613, 527, 528, + 0, 680, 0, 0, 0, 0, 0, 0, 0, 0, + 685, 686, 683, 804, 0, 744, 745, 0, 0, 607, + 608, 409, 0, 626, 417, 376, 511, 411, 591, 442, + 0, 619, 687, 620, 531, 532, 748, 753, 749, 750, + 752, 773, 501, 431, 437, 548, 452, 474, 534, 590, + 509, 539, 374, 579, 550, 480, 672, 700, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, + 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 729, 728, 727, 726, 725, + 724, 723, 722, 0, 0, 669, 391, 792, 786, 793, + 774, 777, 776, 751, 0, 347, 649, 472, 526, 408, + 716, 717, 0, 772, 285, 286, 287, 288, 289, 290, + 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, + 304, 305, 306, 307, 308, 309, 310, 311, 719, 302, + 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, + 778, 779, 780, 781, 782, 0, 0, 335, 336, 337, + 0, 0, 300, 301, 328, 558, 329, 330, 331, 332, + 0, 0, 597, 598, 599, 622, 0, 600, 581, 648, + 418, 348, 562, 589, 789, 790, 0, 0, 0, 0, + 0, 0, 0, 699, 710, 746, 747, 0, 760, 761, + 763, 765, 764, 767, 555, 556, 775, 0, 0, 443, + 364, 365, 502, 503, 541, 0, 444, 445, 446, 450, + 447, 448, 449, 769, 770, 771, 768, 476, 540, 563, + 549, 788, 489, 0, 796, 638, 639, 797, 756, 755, + 349, 0, 338, 339, 713, 714, 0, 0, 543, 488, + 645, 341, 342, 343, 344, 345, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 508, 0, 0, 654, + 688, 677, 766, 641, 0, 0, 1213, 0, 0, 0, + 0, 0, 0, 1218, 401, 0, 0, 471, 692, 1214, + 684, 674, 1216, 659, 660, 661, 668, 413, 662, 798, + 664, 633, 665, 634, 666, 667, 0, 691, 640, 551, + 490, 0, 708, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, + 0, 372, 270, 635, 762, 637, 636, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 375, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 552, 580, 0, + 594, 0, 440, 441, 0, 0, 0, 0, 0, 0, + 0, 356, 559, 577, 373, 546, 592, 378, 554, 570, + 368, 507, 542, 0, 0, 358, 575, 553, 485, 357, + 0, 535, 398, 415, 395, 505, 0, 0, 574, 605, + 394, 595, 0, 585, 360, 0, 584, 504, 477, 571, + 576, 486, 479, 0, 359, 573, 484, 478, 454, 405, + 621, 455, 456, 457, 458, 459, 460, 419, 520, 475, + 521, 420, 492, 491, 493, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 430, 0, 0, 0, 0, 0, + 616, 617, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 754, 0, 0, + 759, 0, 588, 0, 1217, 0, 0, 0, 0, 557, + 0, 0, 461, 0, 0, 0, 606, 0, 538, 510, + 800, 0, 0, 536, 473, 572, 522, 578, 560, 586, + 529, 523, 350, 561, 397, 487, 369, 371, 787, 399, + 402, 406, 407, 498, 499, 516, 545, 564, 565, 566, + 396, 383, 537, 384, 416, 385, 351, 388, 387, 389, + 547, 390, 353, 517, 569, 0, 412, 533, 482, 354, + 481, 518, 568, 567, 370, 596, 603, 604, 696, 0, + 609, 801, 802, 803, 618, 0, 524, 366, 363, 0, + 0, 0, 392, 519, 379, 381, 382, 380, 513, 515, + 623, 624, 625, 627, 628, 629, 630, 0, 0, 0, + 0, 631, 697, 715, 681, 650, 611, 705, 647, 651, + 652, 433, 434, 435, 436, 718, 0, 0, 0, 602, + 462, 463, 0, 404, 403, 483, 355, 0, 0, 451, + 432, 525, 361, 400, 453, 438, 464, 465, 466, 467, + 468, 0, 469, 470, 410, 340, 346, 795, 393, 506, + 720, 757, 758, 642, 0, 706, 643, 653, 386, 678, + 690, 689, 500, 601, 0, 701, 704, 632, 794, 0, + 698, 712, 799, 711, 791, 512, 0, 544, 709, 656, + 0, 702, 675, 676, 0, 703, 671, 707, 362, 439, + 530, 587, 0, 644, 0, 612, 615, 646, 733, 734, + 735, 352, 614, 737, 738, 739, 740, 741, 742, 743, + 736, 583, 679, 655, 682, 593, 658, 657, 0, 0, + 693, 610, 694, 695, 494, 495, 496, 497, 414, 721, + 377, 613, 527, 528, 0, 680, 0, 0, 0, 0, + 0, 0, 0, 0, 685, 686, 683, 804, 0, 744, + 745, 0, 0, 607, 608, 409, 0, 626, 417, 376, + 511, 411, 591, 442, 0, 619, 687, 620, 531, 532, + 748, 753, 749, 750, 752, 773, 501, 431, 437, 548, + 452, 474, 534, 590, 509, 539, 374, 579, 550, 480, + 672, 700, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 326, 327, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 729, + 728, 727, 726, 725, 724, 723, 722, 0, 0, 669, + 391, 792, 786, 793, 774, 777, 776, 751, 0, 347, + 649, 472, 526, 408, 716, 717, 0, 772, 285, 286, + 287, 288, 289, 290, 291, 292, 333, 293, 294, 295, + 296, 297, 298, 299, 304, 305, 306, 307, 308, 309, + 310, 311, 719, 302, 303, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 323, 324, 325, 0, + 0, 0, 0, 334, 778, 779, 780, 781, 782, 0, + 0, 335, 336, 337, 0, 0, 300, 301, 328, 558, + 329, 330, 331, 332, 0, 0, 597, 598, 599, 622, + 0, 600, 581, 648, 418, 348, 562, 589, 789, 790, + 0, 0, 0, 0, 0, 0, 0, 699, 710, 746, + 747, 0, 760, 761, 763, 765, 764, 767, 555, 556, + 775, 0, 0, 443, 364, 365, 502, 503, 541, 0, + 444, 445, 446, 450, 447, 448, 449, 769, 770, 771, + 768, 476, 540, 563, 549, 788, 489, 0, 796, 638, + 639, 797, 756, 755, 349, 0, 338, 339, 713, 714, + 0, 0, 543, 488, 645, 341, 342, 343, 344, 345, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 508, 0, 0, 654, 688, 677, 766, 641, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 401, 0, + 0, 471, 692, 673, 684, 674, 514, 659, 660, 661, + 668, 413, 662, 798, 664, 633, 665, 634, 666, 667, + 0, 691, 640, 551, 490, 0, 708, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5339, 0, 269, 1080, + 0, 0, 0, 0, 0, 372, 270, 635, 762, 637, + 636, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 375, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 552, 580, 0, 594, 0, 440, 441, 0, 0, + 0, 0, 0, 0, 0, 356, 559, 577, 373, 546, + 592, 378, 554, 570, 368, 507, 542, 0, 0, 358, + 575, 553, 485, 357, 0, 535, 398, 415, 395, 505, + 0, 0, 574, 605, 394, 595, 0, 585, 360, 0, + 584, 504, 477, 571, 576, 486, 479, 0, 359, 573, + 484, 478, 454, 405, 621, 455, 456, 457, 458, 459, + 460, 419, 520, 475, 521, 420, 492, 491, 493, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 430, 0, + 0, 0, 0, 0, 616, 617, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 754, 0, 0, 759, 0, 588, 0, 0, 0, + 0, 0, 0, 557, 0, 0, 461, 0, 0, 0, + 606, 0, 538, 510, 800, 0, 0, 536, 473, 572, + 522, 578, 560, 586, 529, 523, 350, 561, 397, 487, + 369, 371, 787, 399, 402, 406, 407, 498, 499, 516, + 545, 564, 565, 566, 396, 383, 537, 384, 416, 385, + 351, 388, 387, 389, 547, 390, 353, 517, 569, 0, + 412, 533, 482, 354, 481, 518, 568, 567, 370, 596, + 603, 604, 696, 0, 609, 801, 802, 803, 618, 0, + 524, 366, 363, 0, 0, 0, 392, 519, 379, 381, + 382, 380, 513, 515, 623, 624, 625, 627, 628, 629, + 630, 0, 0, 0, 0, 631, 697, 715, 681, 650, + 611, 705, 647, 651, 652, 433, 434, 435, 436, 718, + 0, 0, 0, 602, 462, 463, 0, 404, 403, 483, + 355, 0, 0, 451, 432, 525, 361, 400, 453, 438, + 464, 465, 466, 467, 468, 0, 469, 470, 410, 340, + 346, 795, 393, 506, 720, 757, 758, 642, 0, 706, + 643, 653, 386, 678, 690, 689, 500, 601, 0, 701, + 704, 632, 794, 0, 698, 712, 799, 711, 791, 512, + 0, 544, 709, 656, 0, 702, 675, 676, 0, 703, + 671, 707, 362, 439, 530, 587, 0, 644, 0, 612, + 615, 646, 733, 734, 735, 352, 614, 737, 738, 739, + 740, 741, 742, 743, 736, 583, 679, 655, 682, 593, + 658, 657, 0, 0, 693, 610, 694, 695, 494, 495, + 496, 497, 414, 721, 377, 613, 527, 528, 0, 680, + 0, 0, 0, 0, 0, 0, 0, 0, 685, 686, + 683, 804, 0, 744, 745, 0, 0, 607, 608, 409, + 0, 626, 417, 376, 511, 411, 591, 442, 0, 619, + 687, 620, 531, 532, 748, 753, 749, 750, 752, 773, + 501, 431, 437, 548, 452, 474, 534, 590, 509, 539, + 374, 579, 550, 480, 672, 700, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 326, 327, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 729, 728, 727, 726, 725, 724, 723, + 722, 0, 0, 669, 391, 792, 786, 793, 774, 777, + 776, 751, 0, 347, 649, 472, 526, 408, 716, 717, + 0, 772, 285, 286, 287, 288, 289, 290, 291, 292, + 333, 293, 294, 295, 296, 297, 298, 299, 304, 305, + 306, 307, 308, 309, 310, 311, 719, 302, 303, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 323, 324, 325, 0, 0, 0, 0, 334, 778, 779, + 780, 781, 782, 0, 0, 335, 336, 337, 0, 0, + 300, 301, 328, 558, 329, 330, 331, 332, 0, 0, + 597, 598, 599, 622, 0, 600, 581, 648, 418, 348, + 562, 589, 789, 790, 0, 0, 0, 0, 0, 0, + 0, 699, 710, 746, 747, 0, 760, 761, 763, 765, + 764, 767, 555, 556, 775, 0, 0, 443, 364, 365, + 502, 503, 541, 0, 444, 445, 446, 450, 447, 448, + 449, 769, 770, 771, 768, 476, 540, 563, 549, 788, + 489, 0, 796, 638, 639, 797, 756, 755, 349, 0, + 338, 339, 713, 714, 0, 0, 543, 488, 645, 341, + 342, 343, 344, 345, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 508, 0, 0, 654, 688, 677, + 766, 641, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 401, 0, 0, 471, 692, 673, 684, 674, + 514, 659, 660, 661, 668, 413, 662, 798, 664, 633, + 665, 634, 666, 667, 0, 691, 640, 551, 490, 0, + 708, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 269, 0, 0, 1887, 0, 0, 0, 372, + 270, 635, 762, 637, 636, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 375, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 552, 580, 0, 594, 0, + 440, 441, 1885, 0, 0, 0, 0, 0, 0, 356, + 559, 577, 373, 546, 592, 378, 554, 570, 368, 507, + 542, 0, 0, 358, 575, 553, 485, 357, 0, 535, + 398, 415, 395, 505, 0, 0, 574, 605, 394, 595, + 0, 585, 360, 0, 584, 504, 477, 571, 576, 486, + 479, 0, 359, 573, 484, 478, 454, 405, 621, 455, + 456, 457, 458, 459, 460, 419, 520, 475, 521, 420, + 492, 491, 493, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 430, 0, 0, 0, 0, 0, 616, 617, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 754, 0, 0, 759, 0, + 588, 0, 0, 0, 0, 0, 0, 557, 0, 0, + 461, 0, 0, 0, 606, 0, 538, 510, 800, 0, + 0, 536, 473, 572, 522, 578, 560, 586, 529, 523, + 350, 561, 397, 487, 369, 371, 787, 399, 402, 406, + 407, 498, 499, 516, 545, 564, 565, 566, 396, 383, + 537, 384, 416, 385, 351, 388, 387, 389, 547, 390, + 353, 517, 569, 0, 412, 533, 482, 354, 481, 518, + 568, 567, 370, 596, 603, 604, 696, 0, 609, 801, + 802, 803, 618, 0, 524, 366, 363, 0, 0, 0, + 392, 519, 379, 381, 382, 380, 513, 515, 623, 624, + 625, 627, 628, 629, 630, 0, 0, 0, 0, 631, + 697, 715, 681, 650, 611, 705, 647, 651, 652, 433, + 434, 435, 436, 718, 0, 0, 0, 602, 462, 463, + 0, 404, 403, 483, 355, 0, 0, 451, 432, 525, + 361, 400, 453, 438, 464, 465, 466, 467, 468, 0, + 469, 470, 410, 340, 346, 795, 393, 506, 720, 757, + 758, 642, 0, 706, 643, 653, 386, 678, 690, 689, + 500, 601, 0, 701, 704, 632, 794, 0, 698, 712, + 799, 711, 791, 512, 0, 544, 709, 656, 0, 702, + 675, 676, 0, 703, 671, 707, 362, 439, 530, 587, + 0, 644, 0, 612, 615, 646, 733, 734, 735, 352, + 614, 737, 738, 739, 740, 741, 742, 743, 736, 583, + 679, 655, 682, 593, 658, 657, 0, 0, 693, 610, + 694, 695, 494, 495, 496, 497, 414, 721, 377, 613, + 527, 528, 0, 680, 0, 0, 0, 0, 0, 0, + 0, 0, 685, 686, 683, 804, 0, 744, 745, 0, + 0, 607, 608, 409, 0, 626, 417, 376, 511, 411, + 591, 442, 0, 619, 687, 620, 531, 532, 748, 753, + 749, 750, 752, 773, 501, 431, 437, 548, 452, 474, + 534, 590, 509, 539, 374, 579, 550, 480, 672, 700, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 326, 327, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 729, 728, 727, + 726, 725, 724, 723, 722, 0, 0, 669, 391, 792, + 786, 793, 774, 777, 776, 751, 0, 347, 649, 472, + 526, 408, 716, 717, 0, 772, 285, 286, 287, 288, + 289, 290, 291, 292, 333, 293, 294, 295, 296, 297, + 298, 299, 304, 305, 306, 307, 308, 309, 310, 311, + 719, 302, 303, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 325, 0, 0, 0, + 0, 334, 778, 779, 780, 781, 782, 0, 0, 335, + 336, 337, 0, 0, 300, 301, 328, 558, 329, 330, + 331, 332, 0, 0, 597, 598, 599, 622, 0, 600, + 581, 648, 418, 348, 562, 589, 789, 790, 0, 0, + 0, 0, 0, 0, 0, 699, 710, 746, 747, 0, + 760, 761, 763, 765, 764, 767, 555, 556, 775, 0, + 0, 443, 364, 365, 502, 503, 541, 0, 444, 445, + 446, 450, 447, 448, 449, 769, 770, 771, 768, 476, + 540, 563, 549, 788, 489, 0, 796, 638, 639, 797, + 756, 755, 349, 0, 338, 339, 713, 714, 0, 0, + 543, 488, 645, 341, 342, 343, 344, 345, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 508, 0, + 0, 654, 688, 677, 766, 641, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 401, 0, 0, 471, + 692, 673, 684, 674, 514, 659, 660, 661, 668, 413, + 662, 798, 664, 633, 665, 634, 666, 667, 0, 691, + 640, 551, 490, 0, 708, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 269, 0, 0, 1887, + 0, 0, 0, 372, 270, 635, 762, 637, 636, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 375, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 552, + 580, 0, 594, 0, 440, 441, 2209, 0, 0, 0, + 0, 0, 0, 356, 559, 577, 373, 546, 592, 378, + 554, 570, 368, 507, 542, 0, 0, 358, 575, 553, + 485, 357, 0, 535, 398, 415, 395, 505, 0, 0, + 574, 605, 394, 595, 0, 585, 360, 0, 584, 504, + 477, 571, 576, 486, 479, 0, 359, 573, 484, 478, + 454, 405, 621, 455, 456, 457, 458, 459, 460, 419, + 520, 475, 521, 420, 492, 491, 493, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 430, 0, 0, 0, + 0, 0, 616, 617, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 754, + 0, 0, 759, 0, 588, 0, 0, 0, 0, 0, + 0, 557, 0, 0, 461, 0, 0, 0, 606, 0, + 538, 510, 800, 0, 0, 536, 473, 572, 522, 578, + 560, 586, 529, 523, 350, 561, 397, 487, 369, 371, + 787, 399, 402, 406, 407, 498, 499, 516, 545, 564, + 565, 566, 396, 383, 537, 384, 416, 385, 351, 388, + 387, 389, 547, 390, 353, 517, 569, 0, 412, 533, + 482, 354, 481, 518, 568, 567, 370, 596, 603, 604, + 696, 0, 609, 801, 802, 803, 618, 0, 524, 366, + 363, 0, 0, 0, 392, 519, 379, 381, 382, 380, + 513, 515, 623, 624, 625, 627, 628, 629, 630, 0, + 0, 0, 0, 631, 697, 715, 681, 650, 611, 705, + 647, 651, 652, 433, 434, 435, 436, 718, 0, 0, + 0, 602, 462, 463, 0, 404, 403, 483, 355, 0, + 0, 451, 432, 525, 361, 400, 453, 438, 464, 465, + 466, 467, 468, 0, 469, 470, 410, 340, 346, 795, + 393, 506, 720, 757, 758, 642, 0, 706, 643, 653, + 386, 678, 690, 689, 500, 601, 0, 701, 704, 632, + 794, 0, 698, 712, 799, 711, 791, 512, 0, 544, + 709, 656, 0, 702, 675, 676, 0, 703, 671, 707, + 362, 439, 530, 587, 0, 644, 0, 612, 615, 646, + 733, 734, 735, 352, 614, 737, 738, 739, 740, 741, + 742, 743, 736, 583, 679, 655, 682, 593, 658, 657, + 0, 0, 693, 610, 694, 695, 494, 495, 496, 497, + 414, 721, 377, 613, 527, 528, 0, 680, 0, 0, + 0, 0, 0, 0, 0, 0, 685, 686, 683, 804, + 0, 744, 745, 0, 0, 607, 608, 409, 0, 626, + 417, 376, 511, 411, 591, 442, 0, 619, 687, 620, + 531, 532, 748, 753, 749, 750, 752, 773, 501, 431, + 437, 548, 452, 474, 534, 590, 509, 539, 374, 579, + 550, 480, 672, 700, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 326, 327, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 729, 728, 727, 726, 725, 724, 723, 722, 0, + 0, 669, 391, 792, 786, 793, 774, 777, 776, 751, + 0, 347, 649, 472, 526, 408, 716, 717, 0, 772, + 285, 286, 287, 288, 289, 290, 291, 292, 333, 293, + 294, 295, 296, 297, 298, 299, 304, 305, 306, 307, + 308, 309, 310, 311, 719, 302, 303, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 0, 0, 0, 0, 334, 778, 779, 780, 781, + 782, 0, 0, 335, 336, 337, 0, 0, 300, 301, + 328, 558, 329, 330, 331, 332, 0, 0, 597, 598, + 599, 622, 0, 600, 581, 648, 418, 348, 562, 589, + 789, 790, 0, 0, 0, 0, 0, 0, 0, 699, + 710, 746, 747, 0, 760, 761, 763, 765, 764, 767, + 555, 556, 775, 0, 0, 443, 364, 365, 502, 503, + 541, 0, 444, 445, 446, 450, 447, 448, 449, 769, + 770, 771, 768, 476, 540, 563, 549, 788, 489, 0, + 796, 638, 639, 797, 756, 755, 349, 0, 338, 339, + 713, 714, 0, 0, 543, 488, 645, 341, 342, 343, + 344, 345, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 508, 0, 0, 654, 688, 677, 766, 641, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 401, 0, 0, 471, 692, 673, 684, 674, 514, 659, + 660, 661, 668, 413, 662, 798, 664, 633, 665, 634, + 666, 667, 0, 691, 640, 551, 490, 0, 708, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 269, 0, 0, 0, 0, 0, 0, 372, 270, 635, + 762, 637, 636, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 375, 0, 0, 0, 0, 0, 0, 4722, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 4723, 0, + 0, 0, 0, 552, 580, 0, 594, 0, 440, 441, + 0, 0, 0, 0, 0, 0, 0, 356, 559, 577, + 373, 546, 592, 378, 554, 570, 368, 507, 542, 0, + 0, 358, 575, 553, 485, 357, 0, 535, 398, 415, + 395, 505, 0, 0, 574, 605, 394, 595, 0, 585, + 360, 0, 584, 504, 477, 571, 576, 486, 479, 0, + 359, 573, 484, 478, 454, 405, 621, 455, 456, 457, + 458, 459, 460, 419, 520, 475, 521, 420, 492, 491, + 493, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 430, 0, 0, 0, 0, 0, 616, 617, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 754, 0, 0, 759, 0, 588, 0, + 0, 0, 0, 0, 0, 557, 0, 0, 461, 0, + 0, 0, 606, 0, 538, 510, 800, 0, 0, 536, + 473, 572, 522, 578, 560, 586, 529, 523, 350, 561, + 397, 487, 369, 371, 787, 399, 402, 406, 407, 498, + 499, 516, 545, 564, 565, 566, 396, 383, 537, 384, + 416, 385, 351, 388, 387, 389, 547, 390, 353, 517, + 569, 0, 412, 533, 482, 354, 481, 518, 568, 567, + 370, 596, 603, 604, 696, 0, 609, 801, 802, 803, + 618, 0, 524, 366, 363, 0, 0, 0, 392, 519, + 379, 381, 382, 380, 513, 515, 623, 624, 625, 627, + 628, 629, 630, 0, 0, 0, 0, 631, 697, 715, + 681, 650, 611, 705, 647, 651, 652, 433, 434, 435, + 436, 718, 0, 0, 0, 602, 462, 463, 0, 404, + 403, 483, 355, 0, 0, 451, 432, 525, 361, 400, + 453, 438, 464, 465, 466, 467, 468, 0, 469, 470, + 410, 340, 346, 795, 393, 506, 720, 757, 758, 642, + 0, 706, 643, 653, 386, 678, 690, 689, 500, 601, + 0, 701, 704, 632, 794, 0, 698, 712, 799, 711, + 791, 512, 0, 544, 709, 656, 0, 702, 675, 676, + 0, 703, 671, 707, 362, 439, 530, 587, 0, 644, + 0, 612, 615, 646, 733, 734, 735, 352, 614, 737, + 738, 739, 740, 741, 742, 743, 736, 583, 679, 655, + 682, 593, 658, 657, 0, 0, 693, 610, 694, 695, + 494, 495, 496, 497, 414, 721, 377, 613, 527, 528, + 0, 680, 0, 0, 0, 0, 0, 0, 0, 0, + 685, 686, 683, 804, 0, 744, 745, 0, 0, 607, + 608, 409, 0, 626, 417, 376, 511, 411, 591, 442, + 0, 619, 687, 620, 531, 532, 748, 753, 749, 750, + 752, 773, 501, 431, 437, 548, 452, 474, 534, 590, + 509, 539, 374, 579, 550, 480, 672, 700, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, + 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 729, 728, 727, 726, 725, + 724, 723, 722, 0, 0, 669, 391, 792, 786, 793, + 774, 777, 776, 751, 0, 347, 649, 472, 526, 408, + 716, 717, 0, 772, 285, 286, 287, 288, 289, 290, + 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, + 304, 305, 306, 307, 308, 309, 310, 311, 719, 302, + 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, + 778, 779, 780, 781, 782, 0, 0, 335, 336, 337, + 0, 0, 300, 301, 328, 558, 329, 330, 331, 332, + 0, 0, 597, 598, 599, 622, 0, 600, 581, 648, + 418, 348, 562, 589, 789, 790, 0, 0, 0, 0, + 0, 0, 0, 699, 710, 746, 747, 0, 760, 761, + 763, 765, 764, 767, 555, 556, 775, 0, 0, 443, + 364, 365, 502, 503, 541, 0, 444, 445, 446, 450, + 447, 448, 449, 769, 770, 771, 768, 476, 540, 563, + 549, 788, 489, 0, 796, 638, 639, 797, 756, 755, + 349, 0, 338, 339, 713, 714, 0, 0, 543, 488, + 645, 341, 342, 343, 344, 345, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 508, 0, 0, 654, + 688, 677, 766, 641, 0, 0, 0, 0, 0, 2654, + 0, 0, 0, 0, 401, 0, 0, 471, 692, 673, + 684, 674, 514, 659, 660, 661, 668, 413, 662, 798, + 664, 633, 665, 634, 666, 667, 0, 691, 640, 551, + 490, 0, 708, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 269, 0, 0, 2655, 0, 0, + 0, 372, 270, 635, 762, 637, 636, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 375, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 552, 580, 0, + 594, 0, 440, 441, 0, 0, 0, 0, 0, 0, + 0, 356, 559, 577, 373, 546, 592, 378, 554, 570, + 368, 507, 542, 0, 0, 358, 575, 553, 485, 357, + 0, 535, 398, 415, 395, 505, 0, 0, 574, 605, + 394, 595, 0, 585, 360, 0, 584, 504, 477, 571, + 576, 486, 479, 0, 359, 573, 484, 478, 454, 405, + 621, 455, 456, 457, 458, 459, 460, 419, 520, 475, + 521, 420, 492, 491, 493, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 430, 0, 0, 0, 0, 0, + 616, 617, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 754, 0, 0, + 759, 0, 588, 0, 0, 0, 0, 0, 0, 557, + 0, 0, 461, 0, 0, 0, 606, 0, 538, 510, + 800, 0, 0, 536, 473, 572, 522, 578, 560, 586, + 529, 523, 350, 561, 397, 487, 369, 371, 787, 399, + 402, 406, 407, 498, 499, 516, 545, 564, 565, 566, + 396, 383, 537, 384, 416, 385, 351, 388, 387, 389, + 547, 390, 353, 517, 569, 0, 412, 533, 482, 354, + 481, 518, 568, 567, 370, 596, 603, 604, 696, 0, + 609, 801, 802, 803, 618, 0, 524, 366, 363, 0, + 0, 0, 392, 519, 379, 381, 382, 380, 513, 515, + 623, 624, 625, 627, 628, 629, 630, 0, 0, 0, + 0, 631, 697, 715, 681, 650, 611, 705, 647, 651, + 652, 433, 434, 435, 436, 718, 0, 0, 0, 602, + 462, 463, 0, 404, 403, 483, 355, 0, 0, 451, + 432, 525, 361, 400, 453, 438, 464, 465, 466, 467, + 468, 0, 469, 470, 410, 340, 346, 795, 393, 506, + 720, 757, 758, 642, 0, 706, 643, 653, 386, 678, + 690, 689, 500, 601, 0, 701, 704, 632, 794, 0, + 698, 712, 799, 711, 791, 512, 0, 544, 709, 656, + 0, 702, 675, 676, 0, 703, 671, 707, 362, 439, + 530, 587, 0, 644, 0, 612, 615, 646, 733, 734, + 735, 352, 614, 737, 738, 739, 740, 741, 742, 743, + 736, 583, 679, 655, 682, 593, 658, 657, 0, 0, + 693, 610, 694, 695, 494, 495, 496, 497, 414, 721, + 377, 613, 527, 528, 0, 680, 0, 0, 0, 0, + 0, 0, 0, 0, 685, 686, 683, 804, 0, 744, + 745, 0, 0, 607, 608, 409, 0, 626, 417, 376, + 511, 411, 591, 442, 0, 619, 687, 620, 531, 532, + 748, 753, 749, 750, 752, 773, 501, 431, 437, 548, + 452, 474, 534, 590, 509, 539, 374, 579, 550, 480, + 672, 700, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 326, 327, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 729, + 728, 727, 726, 725, 724, 723, 722, 0, 0, 669, + 391, 792, 786, 793, 774, 777, 776, 751, 0, 347, + 649, 472, 526, 408, 716, 717, 0, 772, 285, 286, + 287, 288, 289, 290, 291, 292, 333, 293, 294, 295, + 296, 297, 298, 299, 304, 305, 306, 307, 308, 309, + 310, 311, 719, 302, 303, 312, 313, 314, 315, 316, + 317, 318, 319, 320, 321, 322, 323, 324, 325, 0, + 0, 0, 0, 334, 778, 779, 780, 781, 782, 0, + 0, 335, 336, 337, 0, 0, 300, 301, 328, 558, + 329, 330, 331, 332, 0, 0, 597, 598, 599, 622, + 0, 600, 581, 648, 418, 348, 562, 589, 789, 790, + 0, 0, 0, 0, 0, 0, 0, 699, 710, 746, + 747, 0, 760, 761, 763, 765, 764, 767, 555, 556, + 775, 0, 0, 443, 364, 365, 502, 503, 541, 0, + 444, 445, 446, 450, 447, 448, 449, 769, 770, 771, + 768, 476, 540, 563, 549, 788, 489, 0, 796, 638, + 639, 797, 756, 755, 349, 0, 338, 339, 713, 714, + 0, 0, 543, 488, 645, 341, 342, 343, 344, 345, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 508, 0, 0, 654, 688, 677, 766, 641, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 401, 0, + 0, 471, 692, 673, 684, 674, 514, 659, 660, 661, + 668, 413, 662, 798, 664, 633, 665, 634, 666, 667, + 0, 691, 640, 551, 490, 0, 708, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 269, 0, + 0, 4303, 4304, 0, 0, 372, 270, 635, 762, 637, + 636, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 375, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 552, 580, 0, 594, 0, 440, 441, 0, 0, + 0, 0, 0, 0, 0, 356, 559, 577, 373, 546, + 592, 378, 554, 570, 368, 507, 542, 0, 0, 358, + 575, 553, 485, 357, 0, 535, 398, 415, 395, 505, + 0, 0, 574, 605, 394, 595, 0, 585, 360, 0, + 584, 504, 477, 571, 576, 486, 479, 0, 359, 573, + 484, 478, 454, 405, 621, 455, 456, 457, 458, 459, + 460, 419, 520, 475, 521, 420, 492, 491, 493, 421, + 422, 423, 424, 425, 426, 427, 428, 429, 430, 0, + 0, 0, 0, 0, 616, 617, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 754, 0, 0, 759, 0, 588, 0, 0, 0, + 0, 0, 0, 557, 0, 0, 461, 0, 0, 0, + 606, 0, 538, 510, 800, 0, 0, 536, 473, 572, + 522, 578, 560, 586, 529, 523, 350, 561, 397, 487, + 369, 371, 787, 399, 402, 406, 407, 498, 499, 516, + 545, 564, 565, 566, 396, 383, 537, 384, 416, 385, + 351, 388, 387, 389, 547, 390, 353, 517, 569, 0, + 412, 533, 482, 354, 481, 518, 568, 567, 370, 596, + 603, 604, 696, 0, 609, 801, 802, 803, 618, 0, + 524, 366, 363, 0, 0, 0, 392, 519, 379, 381, + 382, 380, 513, 515, 623, 624, 625, 627, 628, 629, + 630, 0, 0, 0, 0, 631, 697, 715, 681, 650, + 611, 705, 647, 651, 652, 433, 434, 435, 436, 718, + 0, 0, 0, 602, 462, 463, 0, 404, 403, 483, + 355, 0, 0, 451, 432, 525, 361, 400, 453, 438, + 464, 465, 466, 467, 468, 0, 469, 470, 410, 340, + 346, 795, 393, 506, 720, 757, 758, 642, 0, 706, + 643, 653, 386, 678, 690, 689, 500, 601, 0, 701, + 704, 632, 794, 0, 698, 712, 799, 711, 791, 512, + 0, 544, 709, 656, 0, 702, 675, 676, 0, 703, + 671, 707, 362, 439, 530, 587, 0, 644, 0, 612, + 615, 646, 733, 734, 735, 352, 614, 737, 738, 739, + 740, 741, 742, 743, 736, 583, 679, 655, 682, 593, + 658, 657, 0, 0, 693, 610, 694, 695, 494, 495, + 496, 497, 414, 721, 377, 613, 527, 528, 0, 680, + 0, 0, 0, 0, 0, 0, 0, 0, 685, 686, + 683, 804, 0, 744, 745, 0, 0, 607, 608, 409, + 0, 626, 417, 376, 511, 411, 591, 442, 0, 619, + 687, 620, 531, 532, 748, 753, 749, 750, 752, 773, + 501, 431, 437, 548, 452, 474, 534, 590, 509, 539, + 374, 579, 550, 480, 672, 700, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 326, 327, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 729, 728, 727, 726, 725, 724, 723, + 722, 0, 0, 669, 391, 792, 786, 793, 774, 777, + 776, 751, 0, 347, 649, 472, 526, 408, 716, 717, + 0, 772, 285, 286, 287, 288, 289, 290, 291, 292, + 333, 293, 294, 295, 296, 297, 298, 299, 304, 305, + 306, 307, 308, 309, 310, 311, 719, 302, 303, 312, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, + 323, 324, 325, 0, 0, 0, 0, 334, 778, 779, + 780, 781, 782, 0, 0, 335, 336, 337, 0, 0, + 300, 301, 328, 558, 329, 330, 331, 332, 0, 0, + 597, 598, 599, 622, 0, 600, 581, 648, 418, 348, + 562, 589, 789, 790, 0, 0, 0, 0, 0, 0, + 0, 699, 710, 746, 747, 0, 760, 761, 763, 765, + 764, 767, 555, 556, 775, 0, 0, 443, 364, 365, + 502, 503, 541, 0, 444, 445, 446, 450, 447, 448, + 449, 769, 770, 771, 768, 476, 540, 563, 549, 788, + 489, 0, 796, 638, 639, 797, 756, 755, 349, 0, + 338, 339, 713, 714, 0, 0, 543, 488, 645, 341, + 342, 343, 344, 345, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 508, 0, 0, 654, 688, 677, + 766, 641, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 401, 0, 0, 471, 692, 673, 684, 674, + 514, 659, 660, 661, 668, 413, 662, 798, 664, 633, + 665, 634, 666, 667, 0, 691, 640, 551, 490, 0, + 708, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 269, 0, 0, 4061, 4063, 0, 0, 372, + 270, 635, 762, 637, 636, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 375, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 552, 580, 0, 594, 0, + 440, 441, 0, 0, 0, 0, 0, 0, 0, 356, + 559, 577, 373, 546, 592, 378, 554, 570, 368, 507, + 542, 0, 0, 358, 575, 553, 485, 357, 0, 535, + 398, 415, 395, 505, 0, 0, 574, 605, 394, 595, + 0, 585, 360, 0, 584, 504, 477, 571, 576, 486, + 479, 0, 359, 573, 484, 478, 454, 405, 621, 455, + 456, 457, 458, 459, 460, 419, 520, 475, 521, 420, + 492, 491, 493, 421, 422, 423, 424, 425, 426, 427, + 428, 429, 430, 0, 0, 0, 0, 0, 616, 617, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 754, 0, 0, 759, 0, + 588, 0, 0, 0, 0, 0, 0, 557, 0, 0, + 461, 0, 0, 0, 606, 0, 538, 510, 800, 0, + 0, 536, 473, 572, 522, 578, 560, 586, 529, 523, + 350, 561, 397, 487, 369, 371, 787, 399, 402, 406, + 407, 498, 499, 516, 545, 564, 565, 566, 396, 383, + 537, 384, 416, 385, 351, 388, 387, 389, 547, 390, + 353, 517, 569, 0, 412, 533, 482, 354, 481, 518, + 568, 567, 370, 596, 603, 604, 696, 0, 609, 801, + 802, 803, 618, 0, 524, 366, 363, 0, 0, 0, + 392, 519, 379, 381, 382, 380, 513, 515, 623, 624, + 625, 627, 628, 629, 630, 0, 0, 0, 0, 631, + 697, 715, 681, 650, 611, 705, 647, 651, 652, 433, + 434, 435, 436, 718, 0, 0, 0, 602, 462, 463, + 0, 404, 403, 483, 355, 0, 0, 451, 432, 525, + 361, 400, 453, 438, 464, 465, 466, 467, 468, 0, + 469, 470, 410, 340, 346, 795, 393, 506, 720, 757, + 758, 642, 0, 706, 643, 653, 386, 678, 690, 689, + 500, 601, 0, 701, 704, 632, 794, 0, 698, 712, + 799, 711, 791, 512, 0, 544, 709, 656, 0, 702, + 675, 676, 0, 703, 671, 707, 362, 439, 530, 587, + 0, 644, 0, 612, 615, 646, 733, 734, 735, 352, + 614, 737, 738, 739, 740, 741, 742, 743, 736, 583, + 679, 655, 682, 593, 658, 657, 0, 0, 693, 610, + 694, 695, 494, 495, 496, 497, 414, 721, 377, 613, + 527, 528, 0, 680, 0, 0, 0, 0, 0, 0, + 0, 0, 685, 686, 683, 804, 0, 744, 745, 0, + 0, 607, 608, 409, 0, 626, 417, 376, 511, 411, + 591, 442, 0, 619, 687, 620, 531, 532, 748, 753, + 749, 750, 752, 773, 501, 431, 437, 548, 452, 474, + 534, 590, 509, 539, 374, 579, 550, 480, 672, 700, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 326, 327, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 729, 728, 727, + 726, 725, 724, 723, 722, 0, 0, 669, 391, 792, + 786, 793, 774, 777, 776, 751, 0, 347, 649, 472, + 526, 408, 716, 717, 0, 772, 285, 286, 287, 288, + 289, 290, 291, 292, 333, 293, 294, 295, 296, 297, + 298, 299, 304, 305, 306, 307, 308, 309, 310, 311, + 719, 302, 303, 312, 313, 314, 315, 316, 317, 318, + 319, 320, 321, 322, 323, 324, 325, 0, 0, 0, + 0, 334, 778, 779, 780, 781, 782, 0, 0, 335, + 336, 337, 0, 0, 300, 301, 328, 558, 329, 330, + 331, 332, 0, 0, 597, 598, 599, 622, 0, 600, + 581, 648, 418, 348, 562, 589, 789, 790, 0, 0, + 0, 0, 0, 0, 0, 699, 710, 746, 747, 0, + 760, 761, 763, 765, 764, 767, 555, 556, 775, 0, + 0, 443, 364, 365, 502, 503, 541, 0, 444, 445, + 446, 450, 447, 448, 449, 769, 770, 771, 768, 476, + 540, 563, 549, 788, 489, 0, 796, 638, 639, 797, + 756, 755, 349, 0, 338, 339, 713, 714, 0, 0, + 543, 488, 645, 341, 342, 343, 344, 345, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 508, 0, + 0, 654, 688, 677, 766, 641, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 401, 0, 0, 471, + 692, 673, 684, 674, 514, 659, 660, 661, 668, 413, + 662, 798, 664, 633, 665, 634, 666, 667, 0, 691, + 640, 551, 490, 0, 708, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3682, 0, 0, 269, 0, 0, 3686, + 0, 0, 0, 372, 270, 635, 762, 637, 636, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 375, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 552, + 580, 0, 594, 0, 440, 441, 0, 0, 0, 0, + 0, 0, 0, 356, 559, 577, 373, 546, 592, 378, + 554, 570, 368, 507, 542, 0, 0, 358, 575, 553, + 485, 357, 0, 535, 398, 415, 395, 505, 0, 0, + 574, 605, 394, 595, 0, 585, 360, 0, 584, 504, + 477, 571, 576, 486, 479, 0, 359, 573, 484, 478, + 454, 405, 621, 455, 456, 457, 458, 459, 460, 419, + 520, 475, 521, 420, 492, 491, 493, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 430, 0, 0, 0, + 0, 0, 616, 617, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 754, + 0, 0, 759, 0, 588, 0, 0, 0, 0, 0, + 0, 557, 0, 0, 461, 0, 0, 0, 606, 0, + 538, 510, 800, 0, 0, 536, 473, 572, 522, 578, + 560, 586, 529, 523, 350, 561, 397, 487, 369, 371, + 787, 399, 402, 406, 407, 498, 499, 516, 545, 564, + 565, 566, 396, 383, 537, 384, 416, 385, 351, 388, + 387, 389, 547, 390, 353, 517, 569, 0, 412, 533, + 482, 354, 481, 518, 568, 567, 370, 596, 603, 604, + 696, 0, 609, 801, 802, 803, 618, 0, 524, 366, + 363, 0, 0, 0, 392, 519, 379, 381, 382, 380, + 513, 515, 623, 624, 625, 627, 628, 629, 630, 0, + 0, 0, 0, 631, 697, 715, 681, 650, 611, 705, + 647, 651, 652, 433, 434, 435, 436, 718, 0, 0, + 0, 602, 462, 463, 0, 404, 403, 483, 355, 0, + 0, 451, 432, 525, 361, 400, 453, 438, 464, 465, + 466, 467, 468, 0, 469, 470, 410, 340, 346, 795, + 393, 506, 720, 757, 758, 642, 0, 706, 643, 653, + 386, 678, 690, 689, 500, 601, 0, 701, 704, 632, + 794, 0, 698, 712, 799, 711, 791, 512, 0, 544, + 709, 656, 0, 702, 675, 676, 0, 703, 671, 707, + 362, 439, 530, 587, 0, 644, 0, 612, 615, 646, + 733, 734, 735, 352, 614, 737, 738, 739, 740, 741, + 742, 743, 736, 583, 679, 655, 682, 593, 658, 657, + 0, 0, 693, 610, 694, 695, 494, 495, 496, 497, + 414, 721, 377, 613, 527, 528, 0, 680, 0, 0, + 0, 0, 0, 0, 0, 0, 685, 686, 683, 804, + 0, 744, 745, 0, 0, 607, 608, 409, 0, 626, + 417, 376, 511, 411, 591, 442, 0, 619, 687, 620, + 531, 532, 748, 753, 749, 750, 752, 773, 501, 431, + 437, 548, 452, 474, 534, 590, 509, 539, 374, 579, + 550, 480, 672, 700, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 326, 327, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 729, 728, 727, 726, 725, 724, 723, 722, 0, + 0, 669, 391, 792, 786, 793, 774, 777, 776, 751, + 0, 347, 649, 472, 526, 408, 716, 717, 0, 772, + 285, 286, 287, 288, 289, 290, 291, 292, 333, 293, + 294, 295, 296, 297, 298, 299, 304, 305, 306, 307, + 308, 309, 310, 311, 719, 302, 303, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, + 325, 0, 0, 0, 0, 334, 778, 779, 780, 781, + 782, 0, 0, 335, 336, 337, 0, 0, 300, 301, + 328, 558, 329, 330, 331, 332, 0, 0, 597, 598, + 599, 622, 0, 600, 581, 648, 418, 348, 562, 589, + 789, 790, 0, 0, 0, 0, 0, 0, 0, 699, + 710, 746, 747, 0, 760, 761, 763, 765, 764, 767, + 555, 556, 775, 0, 0, 443, 364, 365, 502, 503, + 541, 0, 444, 445, 446, 450, 447, 448, 449, 769, + 770, 771, 768, 476, 540, 563, 549, 788, 489, 0, + 796, 638, 639, 797, 756, 755, 349, 0, 338, 339, + 713, 714, 0, 0, 543, 488, 645, 341, 342, 343, + 344, 345, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 508, 0, 0, 654, 688, 677, 766, 641, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 401, 0, 0, 471, 692, 673, 684, 674, 514, 659, + 660, 661, 668, 413, 662, 798, 664, 633, 665, 634, + 666, 667, 0, 691, 640, 551, 490, 0, 708, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 3676, 0, 0, + 269, 0, 0, 3680, 0, 0, 0, 372, 270, 635, + 762, 637, 636, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 375, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 552, 580, 0, 594, 0, 440, 441, + 0, 0, 0, 0, 0, 0, 0, 356, 559, 577, + 373, 546, 592, 378, 554, 570, 368, 507, 542, 0, + 0, 358, 575, 553, 485, 357, 0, 535, 398, 415, + 395, 505, 0, 0, 574, 605, 394, 595, 0, 585, + 360, 0, 584, 504, 477, 571, 576, 486, 479, 0, + 359, 573, 484, 478, 454, 405, 621, 455, 456, 457, + 458, 459, 460, 419, 520, 475, 521, 420, 492, 491, + 493, 421, 422, 423, 424, 425, 426, 427, 428, 429, + 430, 0, 0, 0, 0, 0, 616, 617, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 754, 0, 0, 759, 0, 588, 0, + 0, 0, 0, 0, 0, 557, 0, 0, 461, 0, + 0, 0, 606, 0, 538, 510, 800, 0, 0, 536, + 473, 572, 522, 578, 560, 586, 529, 523, 350, 561, + 397, 487, 369, 371, 787, 399, 402, 406, 407, 498, + 499, 516, 545, 564, 565, 566, 396, 383, 537, 384, + 416, 385, 351, 388, 387, 389, 547, 390, 353, 517, + 569, 0, 412, 533, 482, 354, 481, 518, 568, 567, + 370, 596, 603, 604, 696, 0, 609, 801, 802, 803, + 618, 0, 524, 366, 363, 0, 0, 0, 392, 519, + 379, 381, 382, 380, 513, 515, 623, 624, 625, 627, + 628, 629, 630, 0, 0, 0, 0, 631, 697, 715, + 681, 650, 611, 705, 647, 651, 652, 433, 434, 435, + 436, 718, 0, 0, 0, 602, 462, 463, 0, 404, + 403, 483, 355, 0, 0, 451, 432, 525, 361, 400, + 453, 438, 464, 465, 466, 467, 468, 0, 469, 470, + 410, 340, 346, 795, 393, 506, 720, 757, 758, 642, + 0, 706, 643, 653, 386, 678, 690, 689, 500, 601, + 0, 701, 704, 632, 794, 0, 698, 712, 799, 711, + 791, 512, 0, 544, 709, 656, 0, 702, 675, 676, + 0, 703, 671, 707, 362, 439, 530, 587, 0, 644, + 0, 612, 615, 646, 733, 734, 735, 352, 614, 737, + 738, 739, 740, 741, 742, 743, 736, 583, 679, 655, + 682, 593, 658, 657, 0, 0, 693, 610, 694, 695, + 494, 495, 496, 497, 414, 721, 377, 613, 527, 528, + 0, 680, 0, 0, 0, 0, 0, 0, 0, 0, + 685, 686, 683, 804, 0, 744, 745, 0, 0, 607, + 608, 409, 0, 626, 417, 376, 511, 411, 591, 442, + 0, 619, 687, 620, 531, 532, 748, 753, 749, 750, + 752, 773, 501, 431, 437, 548, 452, 474, 534, 590, + 509, 539, 374, 579, 550, 480, 672, 700, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 326, + 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 729, 728, 727, 726, 725, + 724, 723, 722, 0, 0, 669, 391, 792, 786, 793, + 774, 777, 776, 751, 0, 347, 649, 472, 526, 408, + 716, 717, 0, 772, 285, 286, 287, 288, 289, 290, + 291, 292, 333, 293, 294, 295, 296, 297, 298, 299, + 304, 305, 306, 307, 308, 309, 310, 311, 719, 302, + 303, 312, 313, 314, 315, 316, 317, 318, 319, 320, + 321, 322, 323, 324, 325, 0, 0, 0, 0, 334, + 778, 779, 780, 781, 782, 0, 0, 335, 336, 337, + 0, 0, 300, 301, 328, 558, 329, 330, 331, 332, + 0, 0, 597, 598, 599, 622, 0, 600, 581, 648, + 418, 348, 562, 589, 789, 790, 0, 0, 0, 0, + 0, 0, 0, 699, 710, 746, 747, 0, 760, 761, + 763, 765, 764, 767, 555, 556, 775, 0, 0, 443, + 364, 365, 502, 503, 541, 0, 444, 445, 446, 450, + 447, 448, 449, 769, 770, 771, 768, 476, 540, 563, + 549, 788, 489, 0, 796, 638, 639, 797, 756, 755, + 349, 0, 338, 339, 713, 714, 0, 0, 543, 488, + 645, 1830, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1827, 0, 0, 269, 0, 0, 0, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 3198, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 269, + 0, 0, 1887, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 577, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 0, 0, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 533, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 0, 0, 1887, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 2092, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 2091, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, + 5439, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 0, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 508, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 0, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 269, 0, 0, 5360, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 0, 759, 0, 588, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 529, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 743, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 0, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 751, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 755, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 1080, 0, 0, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 0, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5304, 0, 0, 269, + 0, 0, 0, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 577, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 0, 0, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 533, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2223, 0, 0, 269, 0, 0, 0, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4984, 0, 269, 0, 0, + 0, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 0, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 508, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 0, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 269, 0, 0, 0, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 0, 759, 0, 588, + 0, 0, 0, 4949, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 529, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 743, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 0, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 751, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 755, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 4637, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 0, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4469, 0, 0, 269, + 0, 0, 0, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 577, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 0, 0, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 533, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 0, 0, 4467, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, + 3686, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 0, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 508, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 0, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 269, 0, 0, 3305, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 0, 759, 0, 588, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 529, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 743, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 0, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 751, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 755, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 3680, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 0, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 269, + 0, 0, 0, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 577, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 0, 4456, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 533, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4138, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 2472, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, + 2474, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 0, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 0, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 508, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 4403, 0, 0, 0, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 0, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 269, 0, 0, 0, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 0, 759, 0, 588, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 529, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 743, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 0, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 751, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 755, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 3449, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 0, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 269, + 0, 0, 0, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4262, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 577, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 0, 0, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 533, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 0, 0, 4104, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 4033, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, + 0, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 0, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 508, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 0, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 269, 0, 0, 0, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3901, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 0, 759, 0, 588, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 529, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 743, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 0, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 751, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 755, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 1887, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 0, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 269, + 0, 0, 2474, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 577, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 0, 0, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 533, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 3728, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3697, 0, 0, 269, 0, 0, + 0, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 0, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 508, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 0, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 269, 0, 0, 3597, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 0, 759, 0, 588, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 529, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 743, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 0, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 751, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 755, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 0, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3578, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 0, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 269, + 0, 0, 3456, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 577, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 0, 0, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 533, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3418, 0, 0, 269, 0, 0, 0, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, + 0, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2772, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 0, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 508, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 0, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 269, 0, 0, 3283, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 0, 759, 0, 588, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 529, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 743, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 0, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 751, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 755, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 0, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3231, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 0, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 269, + 0, 0, 3229, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 577, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 0, 0, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 533, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3021, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, + 0, 2407, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 0, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 508, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 1459, 0, 0, 0, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 0, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 269, 0, 0, 0, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 0, 759, 0, 588, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 529, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 743, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 0, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 2630, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 755, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 2559, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 0, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 0, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 269, + 0, 0, 0, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 577, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 1930, 0, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 533, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1218, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, + 0, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 823, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 508, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 0, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 269, 0, 0, 0, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 0, 759, 0, 588, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 529, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 743, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 1221, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 751, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 755, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 0, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 959, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 958, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 0, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 269, + 0, 0, 0, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 577, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 0, 0, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 533, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 4953, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, + 0, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 570, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 0, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 4036, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 0, 0, 0, 2472, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 0, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 269, 0, 0, 2474, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 0, 759, 0, 588, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 529, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 743, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 0, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 751, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 0, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 0, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 2389, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 751, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 0, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 269, + 0, 0, 0, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 1866, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 0, 0, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 533, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 1864, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 755, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, 341, 342, 343, 344, 345, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 508, + 0, 0, 654, 688, 677, 766, 641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 401, 0, 0, + 471, 692, 673, 684, 674, 514, 659, 660, 661, 668, + 413, 662, 798, 664, 633, 665, 634, 666, 667, 0, + 691, 640, 551, 490, 0, 708, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, + 0, 0, 0, 0, 372, 270, 635, 762, 637, 636, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 552, 580, 0, 594, 0, 440, 441, 0, 0, 0, + 0, 0, 0, 0, 356, 559, 577, 373, 546, 592, + 378, 554, 1769, 368, 507, 542, 0, 0, 358, 575, + 553, 485, 357, 0, 535, 398, 415, 395, 505, 0, + 0, 574, 605, 394, 595, 0, 585, 360, 0, 584, + 504, 477, 571, 576, 486, 479, 0, 359, 573, 484, + 478, 454, 405, 621, 455, 456, 457, 458, 459, 460, + 419, 520, 475, 521, 420, 492, 491, 493, 421, 422, + 423, 424, 425, 426, 427, 428, 429, 430, 0, 0, + 0, 0, 0, 616, 617, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 754, 0, 0, 759, 0, 588, 0, 0, 0, 0, + 0, 0, 557, 0, 0, 461, 0, 0, 0, 606, + 0, 538, 510, 800, 0, 0, 536, 473, 572, 522, + 578, 560, 586, 529, 523, 350, 561, 397, 487, 369, + 371, 787, 399, 402, 406, 407, 498, 499, 516, 545, + 564, 565, 566, 396, 383, 537, 384, 416, 385, 351, + 388, 387, 389, 547, 390, 353, 517, 569, 0, 412, + 533, 482, 354, 481, 518, 568, 567, 370, 596, 603, + 604, 696, 0, 609, 801, 802, 803, 618, 0, 524, + 366, 363, 0, 0, 0, 392, 519, 379, 381, 382, + 380, 513, 515, 623, 624, 625, 627, 628, 629, 630, + 0, 0, 0, 0, 631, 697, 715, 681, 650, 611, + 705, 647, 651, 652, 433, 434, 435, 436, 718, 0, + 0, 0, 602, 462, 463, 0, 404, 403, 483, 355, + 0, 0, 451, 432, 525, 361, 400, 453, 438, 464, + 465, 466, 467, 468, 0, 469, 470, 410, 340, 346, + 795, 393, 506, 720, 757, 758, 642, 0, 706, 643, + 653, 386, 678, 690, 689, 500, 601, 0, 701, 704, + 632, 794, 0, 698, 712, 799, 711, 791, 512, 0, + 544, 709, 656, 0, 702, 675, 676, 0, 703, 671, + 707, 362, 439, 530, 587, 0, 644, 0, 612, 615, + 646, 733, 734, 735, 352, 614, 737, 738, 739, 740, + 741, 742, 743, 736, 583, 679, 655, 682, 593, 658, + 657, 0, 0, 693, 610, 694, 695, 494, 495, 496, + 497, 414, 721, 377, 613, 527, 528, 0, 680, 0, + 0, 0, 0, 0, 0, 0, 0, 685, 686, 683, + 804, 0, 744, 745, 0, 0, 607, 608, 409, 0, + 626, 417, 376, 511, 411, 591, 442, 0, 619, 687, + 620, 531, 532, 748, 753, 749, 750, 752, 773, 501, + 431, 437, 548, 452, 474, 534, 590, 509, 539, 374, + 579, 550, 480, 672, 700, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 729, 728, 727, 726, 725, 724, 723, 722, + 0, 0, 669, 391, 792, 786, 793, 774, 777, 776, + 751, 0, 347, 649, 472, 526, 408, 716, 717, 0, + 772, 285, 286, 287, 288, 289, 290, 291, 292, 333, + 293, 294, 295, 296, 297, 298, 299, 304, 305, 306, + 307, 308, 309, 310, 311, 719, 302, 303, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 0, 0, 0, 0, 334, 778, 779, 780, + 781, 782, 0, 0, 335, 336, 337, 0, 0, 300, + 301, 328, 558, 329, 330, 331, 332, 0, 0, 597, + 598, 599, 622, 0, 600, 581, 648, 418, 348, 562, + 589, 789, 790, 0, 0, 0, 0, 0, 0, 0, + 699, 710, 746, 747, 0, 760, 761, 763, 765, 764, + 767, 555, 556, 775, 0, 0, 443, 364, 365, 502, + 503, 541, 0, 444, 445, 446, 450, 447, 448, 449, + 769, 770, 771, 768, 476, 540, 563, 549, 788, 489, + 0, 796, 638, 639, 797, 756, 755, 349, 0, 338, + 339, 713, 714, 0, 0, 543, 488, 645, 341, 342, + 343, 344, 345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 508, 0, 0, 654, 688, 677, 766, + 641, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 401, 0, 0, 471, 692, 673, 684, 674, 514, + 659, 660, 661, 668, 413, 662, 798, 664, 633, 665, + 634, 666, 667, 0, 691, 640, 551, 490, 0, 708, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 269, 0, 0, 0, 0, 0, 0, 372, 270, + 635, 762, 637, 636, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 375, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 552, 580, 0, 594, 0, 440, + 441, 0, 0, 0, 0, 0, 0, 0, 356, 559, + 577, 373, 546, 592, 378, 554, 570, 368, 507, 542, + 0, 0, 358, 575, 553, 485, 357, 0, 535, 398, + 415, 395, 505, 0, 0, 574, 605, 394, 595, 0, + 585, 360, 0, 584, 504, 477, 571, 576, 486, 479, + 0, 359, 573, 484, 478, 454, 405, 621, 455, 456, + 457, 458, 459, 460, 419, 520, 475, 521, 420, 492, + 491, 493, 421, 422, 423, 424, 425, 426, 427, 428, + 429, 430, 0, 0, 0, 0, 0, 616, 617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 754, 0, 0, 759, 0, 588, + 0, 0, 0, 0, 0, 0, 557, 0, 0, 461, + 0, 0, 0, 606, 0, 538, 510, 800, 0, 0, + 536, 473, 572, 522, 578, 560, 586, 910, 523, 350, + 561, 397, 487, 369, 371, 787, 399, 402, 406, 407, + 498, 499, 516, 545, 564, 565, 566, 396, 383, 537, + 384, 416, 385, 351, 388, 387, 389, 547, 390, 353, + 517, 569, 0, 412, 533, 482, 354, 481, 518, 568, + 567, 370, 596, 603, 604, 696, 0, 609, 801, 802, + 803, 618, 0, 524, 366, 363, 0, 0, 0, 392, + 519, 379, 381, 382, 380, 513, 515, 623, 624, 625, + 627, 628, 629, 630, 0, 0, 0, 0, 631, 697, + 715, 681, 650, 611, 705, 647, 651, 652, 433, 434, + 435, 436, 718, 0, 0, 0, 602, 462, 463, 0, + 404, 403, 483, 355, 0, 0, 451, 432, 525, 361, + 400, 453, 438, 464, 465, 466, 467, 468, 0, 469, + 470, 410, 340, 346, 795, 393, 506, 720, 757, 758, + 642, 0, 706, 643, 653, 386, 678, 690, 689, 500, + 601, 0, 701, 704, 632, 794, 0, 698, 712, 799, + 711, 791, 512, 0, 544, 709, 656, 0, 702, 675, + 676, 0, 703, 671, 707, 362, 439, 530, 587, 0, + 644, 0, 612, 615, 646, 733, 734, 735, 352, 614, + 737, 738, 739, 740, 741, 742, 911, 736, 583, 679, + 655, 682, 593, 658, 657, 0, 0, 693, 610, 694, + 695, 494, 495, 496, 497, 414, 721, 377, 613, 527, + 528, 0, 680, 0, 0, 0, 0, 0, 0, 0, + 0, 685, 686, 683, 804, 0, 744, 745, 0, 0, + 607, 608, 409, 0, 626, 417, 376, 511, 411, 591, + 442, 0, 619, 687, 620, 531, 532, 748, 753, 749, + 750, 752, 773, 501, 431, 437, 548, 452, 474, 534, + 590, 509, 539, 374, 579, 550, 480, 672, 700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 326, 327, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 729, 728, 727, 726, + 725, 724, 723, 722, 0, 0, 669, 391, 792, 786, + 793, 774, 777, 776, 751, 0, 347, 649, 472, 526, + 408, 716, 717, 0, 772, 285, 286, 287, 288, 289, + 290, 291, 292, 333, 293, 294, 295, 296, 297, 298, + 299, 304, 305, 306, 307, 308, 309, 310, 311, 719, + 302, 303, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 0, 0, 0, 0, + 334, 778, 779, 780, 781, 782, 0, 0, 335, 336, + 337, 0, 0, 300, 301, 328, 558, 329, 330, 331, + 332, 0, 0, 597, 598, 599, 622, 0, 600, 581, + 648, 418, 348, 562, 589, 789, 790, 0, 0, 0, + 0, 0, 0, 0, 699, 710, 746, 747, 0, 760, + 761, 763, 765, 764, 767, 555, 556, 775, 0, 0, + 443, 364, 365, 502, 503, 541, 0, 444, 445, 446, + 450, 447, 448, 449, 769, 770, 771, 768, 476, 540, + 563, 549, 788, 489, 0, 796, 638, 639, 797, 756, + 755, 349, 0, 338, 339, 713, 714, 0, 0, 543, + 488, 645, 341, 342, 343, 344, 345, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 508, 0, 0, + 654, 688, 677, 766, 641, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 401, 0, 0, 471, 692, + 673, 684, 674, 514, 659, 660, 661, 668, 413, 662, + 798, 664, 633, 665, 634, 666, 667, 0, 691, 640, + 551, 490, 0, 708, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 0, 0, + 0, 0, 372, 270, 635, 762, 637, 636, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 552, 580, + 0, 594, 0, 440, 441, 0, 0, 0, 0, 0, + 0, 0, 356, 559, 577, 373, 546, 592, 378, 554, + 570, 368, 507, 542, 0, 0, 358, 575, 553, 485, + 357, 0, 535, 398, 415, 395, 505, 0, 0, 574, + 605, 394, 595, 0, 585, 360, 0, 584, 504, 477, + 571, 576, 486, 479, 0, 359, 573, 484, 478, 454, + 405, 621, 455, 456, 457, 458, 459, 460, 419, 520, + 475, 521, 420, 492, 491, 493, 421, 422, 423, 424, + 425, 426, 427, 428, 429, 430, 0, 0, 0, 0, + 0, 616, 617, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 754, 0, + 0, 759, 0, 588, 0, 0, 0, 0, 0, 0, + 557, 0, 0, 461, 0, 0, 0, 606, 0, 538, + 510, 800, 0, 0, 536, 473, 572, 522, 578, 560, + 586, 529, 523, 350, 561, 397, 487, 369, 371, 787, + 399, 402, 406, 407, 498, 499, 516, 545, 564, 565, + 566, 396, 383, 537, 384, 416, 385, 351, 388, 387, + 389, 547, 390, 353, 517, 569, 0, 412, 533, 482, + 354, 481, 518, 568, 567, 370, 596, 603, 604, 696, + 0, 609, 801, 802, 803, 618, 0, 524, 366, 363, + 0, 0, 0, 392, 519, 379, 381, 382, 380, 513, + 515, 623, 624, 625, 627, 628, 629, 630, 0, 0, + 0, 0, 631, 697, 715, 681, 650, 611, 705, 647, + 651, 652, 433, 434, 435, 436, 718, 0, 0, 0, + 602, 462, 463, 0, 404, 403, 483, 355, 0, 0, + 451, 432, 525, 361, 400, 453, 438, 464, 465, 466, + 467, 468, 0, 469, 470, 410, 340, 346, 795, 393, + 506, 720, 757, 758, 642, 0, 706, 643, 653, 386, + 678, 690, 689, 500, 601, 0, 701, 704, 632, 794, + 0, 698, 712, 799, 711, 791, 512, 0, 544, 709, + 656, 0, 702, 675, 676, 0, 703, 671, 707, 362, + 439, 530, 587, 0, 644, 0, 612, 615, 646, 733, + 734, 735, 352, 614, 737, 738, 739, 740, 741, 742, + 743, 736, 583, 679, 655, 682, 593, 658, 657, 0, + 0, 693, 610, 694, 695, 494, 495, 496, 497, 414, + 721, 377, 613, 527, 528, 0, 680, 0, 0, 0, + 0, 0, 0, 0, 0, 685, 686, 683, 804, 0, + 744, 745, 0, 0, 607, 608, 409, 0, 626, 417, + 376, 511, 411, 591, 442, 0, 619, 687, 620, 531, + 532, 748, 753, 749, 750, 752, 773, 501, 431, 437, + 548, 452, 474, 534, 590, 509, 539, 374, 579, 550, + 480, 672, 700, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 326, 327, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 729, 728, 727, 726, 725, 724, 723, 722, 0, 0, + 669, 391, 792, 786, 793, 774, 777, 776, 847, 0, + 347, 649, 472, 526, 408, 716, 717, 0, 772, 285, + 286, 287, 288, 289, 290, 291, 292, 333, 293, 294, + 295, 296, 297, 298, 299, 304, 305, 306, 307, 308, + 309, 310, 311, 719, 302, 303, 312, 313, 314, 315, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 0, 0, 0, 0, 334, 778, 779, 780, 781, 782, + 0, 0, 335, 336, 337, 0, 0, 300, 301, 328, + 558, 329, 330, 331, 332, 0, 0, 597, 598, 599, + 622, 0, 600, 581, 648, 418, 348, 562, 589, 789, + 790, 0, 0, 0, 0, 0, 0, 0, 699, 710, + 746, 747, 0, 760, 761, 763, 765, 764, 767, 555, + 556, 775, 0, 0, 443, 364, 365, 502, 503, 541, + 0, 444, 445, 446, 450, 447, 448, 449, 769, 770, + 771, 768, 476, 540, 563, 549, 788, 489, 0, 796, + 638, 639, 797, 756, 755, 349, 0, 338, 339, 713, + 714, 0, 0, 543, 488, 645, 341, 342, 343, 344, + 345, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 508, 0, 0, 654, 688, 677, 766, 641, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 401, + 0, 0, 471, 692, 673, 684, 674, 514, 659, 660, + 661, 668, 413, 662, 798, 664, 633, 665, 634, 666, + 667, 0, 691, 640, 551, 490, 0, 708, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 269, + 0, 0, 0, 0, 0, 0, 372, 270, 635, 762, + 637, 636, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 552, 580, 0, 594, 0, 440, 441, 0, + 0, 0, 0, 0, 0, 0, 356, 559, 577, 373, + 546, 592, 378, 554, 570, 368, 507, 542, 0, 0, + 358, 575, 553, 485, 357, 0, 535, 398, 415, 395, + 505, 0, 0, 574, 605, 394, 595, 0, 585, 360, + 0, 584, 504, 477, 571, 576, 486, 479, 0, 359, + 573, 484, 478, 454, 405, 621, 455, 456, 457, 458, + 459, 460, 419, 520, 475, 521, 420, 492, 491, 493, + 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, + 0, 0, 0, 0, 0, 616, 617, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 754, 0, 0, 759, 0, 588, 0, 0, + 0, 0, 0, 0, 557, 0, 0, 461, 0, 0, + 0, 606, 0, 538, 510, 800, 0, 0, 536, 473, + 572, 522, 578, 560, 586, 529, 523, 350, 561, 397, + 487, 369, 371, 787, 399, 402, 406, 407, 498, 499, + 516, 545, 564, 565, 566, 396, 383, 537, 384, 416, + 385, 351, 388, 387, 389, 547, 390, 353, 517, 569, + 0, 412, 0, 482, 354, 481, 518, 568, 567, 370, + 596, 603, 604, 696, 0, 609, 801, 802, 803, 618, + 0, 524, 366, 363, 0, 0, 0, 392, 519, 379, + 381, 382, 380, 513, 515, 623, 624, 625, 627, 628, + 629, 630, 0, 0, 0, 0, 631, 697, 715, 681, + 650, 611, 705, 647, 651, 652, 433, 434, 435, 436, + 718, 0, 0, 0, 602, 462, 463, 0, 404, 403, + 483, 355, 0, 0, 451, 432, 525, 361, 400, 453, + 438, 464, 465, 466, 467, 468, 0, 469, 470, 410, + 340, 346, 795, 393, 506, 720, 757, 758, 642, 0, + 706, 643, 653, 386, 678, 690, 689, 500, 601, 0, + 701, 704, 632, 794, 0, 698, 712, 799, 711, 791, + 512, 0, 544, 709, 656, 0, 702, 675, 676, 0, + 703, 671, 707, 362, 439, 530, 587, 0, 644, 0, + 612, 615, 646, 733, 734, 735, 352, 614, 737, 738, + 739, 740, 741, 742, 743, 736, 583, 679, 655, 682, + 593, 658, 657, 0, 0, 693, 610, 694, 695, 494, + 495, 496, 497, 414, 721, 377, 613, 527, 528, 0, + 680, 0, 0, 0, 0, 0, 0, 0, 0, 685, + 686, 683, 804, 0, 744, 745, 0, 0, 607, 608, + 409, 0, 626, 417, 376, 511, 411, 591, 442, 0, + 619, 687, 620, 531, 532, 748, 753, 749, 750, 752, + 773, 501, 431, 437, 548, 452, 474, 534, 590, 509, + 539, 374, 579, 550, 480, 672, 700, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 326, 327, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 729, 728, 727, 726, 725, 724, + 723, 722, 0, 0, 669, 391, 792, 786, 793, 774, + 777, 776, 751, 0, 347, 649, 472, 526, 408, 716, + 717, 0, 772, 285, 286, 287, 288, 289, 290, 291, + 292, 333, 293, 294, 295, 296, 297, 298, 299, 304, + 305, 306, 307, 308, 309, 310, 311, 719, 302, 303, + 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 325, 0, 0, 0, 0, 334, 778, + 779, 780, 781, 782, 0, 0, 335, 336, 337, 0, + 0, 300, 301, 328, 558, 329, 330, 331, 332, 0, + 0, 597, 598, 599, 622, 0, 600, 581, 648, 418, + 348, 562, 589, 789, 790, 0, 0, 0, 0, 0, + 0, 0, 699, 710, 746, 747, 0, 760, 761, 763, + 765, 764, 767, 555, 556, 775, 0, 0, 443, 364, + 365, 502, 503, 541, 0, 444, 445, 446, 450, 447, + 448, 449, 769, 770, 771, 768, 476, 540, 563, 549, + 788, 489, 0, 796, 638, 639, 797, 756, 755, 349, + 0, 338, 339, 713, 714, 0, 0, 543, 488, 645, + 341, 342, 343, 344, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 508, 0, 0, 654, 688, + 677, 766, 641, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 401, 0, 0, 471, 692, 673, 684, + 674, 514, 659, 660, 661, 668, 413, 662, 798, 664, + 633, 665, 634, 666, 667, 0, 691, 640, 551, 490, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, + 372, 270, 635, 762, 637, 636, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 552, 580, 0, 594, + 0, 440, 441, 0, 0, 0, 0, 0, 0, 0, + 356, 559, 577, 373, 546, 592, 378, 554, 570, 368, + 507, 542, 0, 0, 358, 575, 553, 485, 357, 0, + 535, 398, 415, 395, 505, 0, 0, 574, 605, 394, + 595, 0, 585, 360, 0, 584, 504, 477, 571, 576, + 486, 479, 0, 359, 573, 484, 478, 454, 405, 621, + 455, 456, 457, 458, 459, 460, 419, 520, 475, 521, + 420, 492, 491, 493, 421, 422, 423, 424, 425, 426, + 427, 428, 429, 430, 0, 0, 0, 0, 0, 616, + 617, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 754, 0, 0, 759, + 0, 588, 0, 0, 0, 0, 0, 0, 557, 0, + 0, 461, 0, 0, 0, 606, 0, 538, 510, 800, + 0, 0, 536, 473, 572, 522, 578, 560, 586, 529, + 523, 350, 561, 397, 487, 369, 371, 787, 399, 402, + 406, 407, 498, 499, 516, 545, 564, 565, 566, 396, + 383, 537, 384, 416, 385, 351, 388, 387, 389, 547, + 390, 353, 517, 569, 0, 412, 533, 482, 354, 481, + 518, 568, 567, 370, 596, 603, 604, 696, 0, 609, + 801, 802, 803, 618, 0, 524, 366, 363, 0, 0, + 0, 392, 519, 379, 381, 382, 380, 513, 515, 623, + 624, 625, 627, 628, 629, 630, 0, 0, 0, 0, + 631, 697, 715, 681, 650, 611, 705, 647, 651, 652, + 433, 434, 435, 436, 718, 0, 0, 0, 602, 462, + 463, 0, 404, 403, 483, 355, 0, 0, 451, 432, + 525, 361, 400, 453, 438, 464, 465, 466, 467, 468, + 0, 469, 470, 410, 340, 346, 795, 393, 506, 720, + 757, 758, 642, 0, 706, 643, 653, 386, 678, 690, + 689, 500, 601, 0, 701, 704, 632, 794, 0, 698, + 712, 799, 711, 791, 512, 0, 544, 709, 656, 0, + 702, 675, 676, 0, 703, 671, 707, 362, 439, 530, + 587, 0, 644, 0, 612, 615, 646, 733, 734, 735, + 352, 614, 737, 738, 739, 740, 741, 742, 743, 736, + 583, 679, 655, 682, 593, 658, 657, 0, 0, 693, + 610, 694, 695, 494, 495, 496, 497, 414, 721, 377, + 613, 527, 528, 0, 680, 0, 0, 0, 0, 0, + 0, 0, 0, 685, 686, 683, 804, 0, 744, 745, + 0, 0, 607, 608, 409, 0, 626, 417, 376, 511, + 411, 591, 442, 0, 619, 687, 620, 531, 532, 748, + 753, 749, 750, 752, 773, 501, 431, 437, 548, 452, + 474, 534, 590, 509, 539, 374, 579, 550, 480, 672, + 700, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 326, 327, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 729, 728, + 727, 726, 725, 724, 723, 722, 0, 0, 669, 391, + 792, 786, 793, 774, 777, 776, 751, 0, 347, 649, + 472, 526, 408, 716, 717, 0, 772, 285, 286, 287, + 288, 289, 290, 291, 292, 333, 293, 294, 295, 296, + 297, 298, 299, 304, 305, 306, 307, 308, 309, 310, + 311, 719, 302, 303, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 325, 0, 0, + 0, 0, 334, 778, 779, 780, 781, 782, 0, 0, + 335, 336, 337, 0, 0, 300, 301, 328, 558, 329, + 330, 331, 332, 0, 0, 597, 598, 599, 622, 0, + 600, 581, 648, 418, 348, 562, 589, 789, 790, 0, + 0, 0, 0, 0, 0, 0, 699, 710, 746, 747, + 0, 760, 761, 763, 765, 764, 767, 555, 556, 775, + 0, 0, 443, 364, 365, 502, 503, 541, 0, 444, + 445, 446, 450, 447, 448, 449, 769, 770, 771, 768, + 476, 540, 563, 549, 788, 489, 0, 796, 638, 639, + 797, 756, 0, 349, 0, 338, 339, 713, 714, 0, + 0, 543, 488, 645, +} + +var yyPact = [...]int{ + 7327, -1000, -1000, -355, -1000, -1000, -1000, -1000, -1000, 21563, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 80370, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 697, 80370, 1385, -312, -1000, 4108, -1000, 1443, + -1000, -1000, -1000, -1000, 519, 78018, 23131, -1000, 80370, 898, + 891, 87426, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 1390, 1389, 7627, -1000, 86642, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 1218, 6543, 79586, 16847, 3979, + -117, -1000, -1000, 2463, 123, 3895, 655, 141, 140, 878, + 1657, 1672, 1973, 1703, 80370, 1575, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 8138, + 36465, 78802, 1459, 4666, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 3355, 1387, 1459, 30977, 288, 284, 2676, 4886, 2261, + -1000, -1000, 13, 4961, -1000, -1000, 2983, 80370, 7327, 299, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 16847, 16847, 21563, -415, 21563, 16847, 80370, 80370, -1000, + -1000, -1000, -1000, 1385, -312, 78018, 1218, 6543, 16847, 3979, + 3895, 655, 141, 140, 878, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 13, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 284, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 4666, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 6185, -1000, 2471, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 3567, 4394, 2464, 80370, 3894, + -1000, -1000, -1000, -1000, -1000, -1000, 2676, 4776, 77234, -1000, + -1000, 4865, -1000, 80370, 211, 80370, 418, 2925, 819, 857, + -1000, 1373, 2249, 591, 2459, -1000, -1000, -1000, -1000, -1000, + -1000, 4128, 1059, 4864, -1000, 80370, 80370, 80370, 4410, 80370, + 80370, 588, 4765, -1000, 202, 4, -258, -280, 4452, 2791, + 2791, 4823, 4823, 4764, 4763, 1114, 1110, 1108, 2791, 963, + -1000, 2833, 2833, 2833, 2833, 2791, 724, 1129, 4772, 4392, + 4772, 258, 2833, 233, 2791, 2791, 233, 2791, 2791, 750, + -1000, 2788, 779, 375, -188, -1000, -1000, -1000, 2833, 2833, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 4731, 4729, -1000, + 660, 1104, -1000, 8008, 4673, 2184, 1341, 4450, -1000, -1000, + 4391, -1000, 610, 2313, 643, 1092, 695, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 521, -1000, 4737, -1000, -1000, 603, + -1000, -1000, 559, -1000, -1000, -1000, 268, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 65, 80370, + -1000, -1000, 1798, 3132, 16847, 3753, -1000, 890, 2695, -1000, + -1000, -1000, 8987, 20777, 20777, 20777, 20777, 20777, 80370, -1000, + -1000, 4250, 16847, 4389, 4381, 4378, 4377, -1000, -1000, -1000, + -1000, -1000, -1000, 4376, 2448, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 3193, -1000, -1000, -1000, 19991, -1000, + 4375, 4372, 4370, 4367, 4366, 4364, 4361, 4359, 4358, 4356, + 4354, 4353, 4352, 4251, 4351, 4142, 23915, 4349, 3891, 3884, + 4348, 4346, 4344, 3883, 4343, 4342, 4340, 4142, 4142, 4339, + 4338, 4334, 4333, 4332, 4330, 4329, 4328, 4327, 4322, 4319, + 4318, 4314, 4313, 4312, 4311, 4309, 4308, 4302, 4301, 4298, + 4296, 4295, 4294, 4293, 4292, 4291, 4290, 4289, 4288, 4287, + 4283, 4277, 4273, 4272, 4271, 4268, 4267, 4264, 4263, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 2676, 4162, 4905, 1943, + -1000, 4261, 4906, 4810, 4768, 1896, 16847, -175, 4717, 4714, + 4705, 4703, 4260, 3482, -1000, -1000, 206, 80370, 80370, 374, + 80370, -198, 588, 789, -5, -6, 783, -9, 1253, -1000, + 741, -1000, -1000, 1571, -1000, 1563, 85858, 1331, -1000, -1000, + 80370, 1217, 1217, 1217, -215, 415, 1217, 80370, 835, 1491, + 1463, 1217, 1217, 1217, 1217, 1251, 1217, 1378, 1374, 1371, + 1217, 47, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 2923, 2922, 4583, 3072, 2971, 1170, 77234, 77234, 80370, -1000, + 2304, 80370, -1000, 4232, 1551, -1000, -1000, -1000, -1000, 44306, + -216, 413, 1218, 1218, 80370, 1218, 80370, 523, 350, 35681, + 1218, 1218, 1218, 80370, 1228, -297, 194, 85074, 84290, 3587, + 660, 1095, 1091, 2193, 2845, -1000, 2697, 80370, 80370, 2697, + 2697, 34897, 34113, -1000, 80370, -1000, 4906, 1896, -1000, 4748, + 2247, -1000, 4813, 4114, 2208, 4886, 4886, 4162, -1000, -117, + -11, 1218, 1218, -219, 412, 1218, 1218, 1218, 1218, 1218, + 1366, 1218, 1218, 1218, 80370, 1218, 76450, 1218, 775, 1218, + 1218, 1218, 13703, 2983, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 21563, 3117, + 3054, 298, 103, -289, 452, -1000, -1000, 80370, 4636, 2541, + -1000, -1000, -1000, 4198, 4193, -1000, 4197, 4197, 4197, 4197, + 1504, -1000, 4193, -1000, -1000, -1000, 4193, -1000, -1000, -1000, + -1000, 4197, 4197, 4197, 4197, 4197, 4197, 4195, 4258, -1000, + -1000, 4194, 4194, 4194, 4193, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 1684, 4191, 4192, 4192, 4191, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 80370, 4896, -1000, -1000, 16847, 80370, 1330, + 4665, 4906, 4663, 4772, 4810, 1165, 3293, -1000, -251, 80370, + 560, -1000, 2447, 3477, 1964, 2920, -1000, 1713, 591, 2919, + -1000, 2026, 2026, -1000, 591, 2728, -1000, 1747, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 80370, 65, 5631, -1000, -1000, + -1000, 3837, 960, -1000, 4257, 773, -1000, -1000, -1000, -1000, + 80370, 4772, -30, 4762, 2791, 2935, 2798, 2791, -1000, -1000, + -1000, 1086, 4823, 20777, 20777, -1000, -1000, 16847, -1000, 387, + 45874, 2833, 2791, 2791, -1000, -1000, 80370, -1000, -1000, -1000, + 2833, 80370, 2833, 2833, 4823, 2833, -1000, -1000, -1000, 2791, + 2791, -1000, -1000, 16847, 2527, -1000, -1000, 2833, 2833, -1000, + -1000, 4823, 80370, 266, 4823, 4823, 226, -1000, -1000, 80370, + -1000, 2791, 3876, -1000, 80370, 80370, 1217, 80370, -1000, 80370, + 80370, -1000, -1000, -1000, 935, 2159, 2185, -1000, 834, 6037, + 63906, 660, 63906, 80370, -1000, -1000, -1000, -1000, -1000, -1000, + 237, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 570, -1000, 4862, 16847, 16847, + 16847, 16847, -1000, 1249, 19205, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 20777, 20777, 20777, 20777, 20777, 20777, 20777, 20777, + 20777, 20777, 20777, 20777, 20777, 20777, 4248, 2893, 2806, 4744, + 20777, 20777, 20777, 20777, 20777, 488, 38817, 2208, 3995, 2305, + 497, 2587, 2587, 2587, 2587, 2587, 16847, -1000, 2970, 3132, + 16847, 16847, 16847, 16847, 49794, 80370, -1000, -1000, 8987, 6446, + 16847, 16847, 5082, 20777, 16847, 4699, 16847, 16847, 16847, 4112, + 9773, 80370, 16847, -1000, 4109, 4099, -1000, -1000, 3197, 16847, + -1000, -1000, 16847, -1000, -1000, 16847, 20777, 16847, -1000, 16847, + 16847, 16847, -1000, -1000, 883, 883, 1471, 4699, 16847, 16847, + 4699, 4699, 2830, 16847, 16847, 4699, 4699, 4699, 2814, 4699, + 4699, 4699, 4699, 4699, 4699, 4699, 3971, 4699, 4699, 4699, + 4699, 4699, 4098, 4097, 4096, 4095, 16847, 4094, 16847, 16847, + 16847, 16847, 16847, 16061, 4906, 2676, 4748, -117, 14489, 4663, + 4772, 4642, -90, 4810, -1000, -1000, -1000, -1000, 3132, -182, + 4256, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 80370, + 3874, 3866, -366, -367, 1679, -367, 2438, -1000, -199, 1651, + 343, 80370, -1000, 3855, 3476, 80370, 3854, 3469, 379, 363, + 80370, 80370, 80370, 106, 1655, 1568, 1573, -1000, -1000, 80370, + 83506, -1000, 80370, 2702, 80370, 80370, 1217, 1217, 80370, 4695, + -1000, 80370, 80370, 1217, 1217, -1000, 74098, 3853, 63906, 80370, + 80370, 660, 80370, 80370, 1217, 1217, 1217, 80370, -1000, 4592, + 63906, 4587, 1870, 2982, -1000, -1000, 80370, 16847, 2982, 1944, + 4255, 1170, 1170, -1000, 80370, 2304, 4694, 80370, 1228, -1000, + 414, -1000, -1000, -1000, -1000, 82722, 82722, 26268, 82722, -1000, + 4253, 285, 80370, 80370, 80370, 80370, 6848, 80370, 597, 4672, + 1431, 74098, 75666, 2109, 1789, -1000, -1000, 4727, 1537, 2688, + 63906, 80370, 80370, 2286, -1000, 1326, 30191, -1000, 80370, 2213, + -1000, 97, -1000, 104, 194, 2697, 194, 2697, 1321, -1000, + 930, 579, 31761, 839, 63906, 11345, -1000, -1000, 2697, 2697, + 11345, 11345, 2493, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 2277, -1000, 428, 4748, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -117, 16847, -1000, -1000, 4748, + 4748, 1896, 2212, 3467, 74882, 80370, 1218, 1218, 80370, 74098, + 63906, 660, 80370, 1218, 80370, 80370, 80370, -1000, 80370, -1000, + 4671, 80370, 1218, 80370, 80370, 80370, 2036, -1000, -1000, 33329, + 2437, -1000, -1000, 2957, -1000, 16847, 21563, -157, 16847, 21563, + 21563, 16847, 21563, -1000, 16847, 2216, -1000, -1000, 6550, -1000, + -1000, 3464, -1000, 3463, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 3851, 3851, -1000, + 3462, -1000, -1000, -1000, -1000, 4191, 3457, -1000, -1000, 3446, + -1000, -1000, -1000, -1000, -45, 4093, 1798, -1000, 3850, 3846, + 4748, -1000, 4810, 490, 4810, 4642, 1987, 4252, 1218, -1000, + 318, -380, 2914, 2913, 2911, 4743, 80370, -1000, 1678, 2026, + -1000, -1000, 1941, -1000, 591, -1000, 1790, -1000, -1000, -1000, + 2026, 840, -1000, -1000, -1000, -1000, -1000, 2422, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 31761, -1000, -1000, -1000, -1000, 846, 7850, 11, 8, 2264, + -1000, -1000, 80370, -1000, 80370, -1000, 80370, -1000, -43, -1000, + -1000, 3436, 4778, 80370, 4823, 80370, -222, 4823, 4823, 80370, + -236, 4823, 660, -1000, 2695, 2695, 3132, 80370, 80370, 80370, + 4408, 4251, 80370, 272, 80370, 4823, 4823, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 2833, 4823, 4823, 2435, 4092, 2791, + 2833, -1000, -1000, 2833, -380, -1000, 2833, -1000, -1000, -1000, + -380, 2420, -380, 80370, -1000, -1000, -1000, -1000, -1000, 834, + 63906, 70178, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 2166, + -1000, -1000, -1000, 1319, 471, 2721, -1000, -1000, 354, 289, + 422, 1453, 3845, 3132, -1000, 3003, 3021, -1000, 1196, 1037, + -1000, -1000, -1000, -1000, 4250, -1000, -1000, -1000, 3499, 4719, + -1000, 2856, 2856, 2503, 2503, 2503, 2503, 2503, 3038, 3038, + 2695, 2695, -1000, -1000, -1000, 8987, 4248, 20777, 20777, 20777, + 20777, 4248, 20777, 20777, 20777, 20777, 4247, -1000, 1409, 1409, + 5889, 6815, 2587, -1000, -1000, 2524, 2524, -1000, -1000, -1000, + -1000, 16847, 293, 2946, -1000, 16847, 3496, 2537, 3249, 2229, + 2720, -1000, 4193, 16847, 2411, 640, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 4091, 4090, 3599, 4861, + 5600, 4087, 16847, -1000, -1000, 2714, 2712, 2708, -1000, 3121, + 15275, -1000, -1000, -1000, 4084, 2407, 4080, -1000, -1000, -1000, + 4077, 2705, 2011, 4074, 4152, 4069, 4068, 4065, 4063, 2246, + 2238, 2231, -1000, -1000, -1000, -1000, 16847, 3982, 3964, 16847, + 16847, 16847, 4062, 2692, 2687, 16847, 16847, 16847, 16847, 4057, + 16847, 16847, 16847, 16847, 16847, 16847, 16847, 16847, -325, 16847, + 16847, 16847, 16847, 16847, 294, 294, 294, 294, 3945, 294, + 2309, 2234, 3933, 3926, 2532, 2228, 2227, 4748, 4906, -1000, + -1000, 2685, -1000, 3132, -1000, -1000, 4810, 4810, -1000, 4895, + 4642, -177, 4245, 3435, 2225, -1000, -1000, -305, 3745, 1318, + 348, 80370, 80370, 1318, 80370, 80370, 2906, 1318, 80370, -200, + 3844, -1000, -1000, 3833, -1000, -1000, 80370, 80370, 80370, 80370, + -18, 4661, 4657, -1000, -1000, 1647, 1558, 1562, -1000, 80370, + -1000, 3830, 4670, 4655, 4755, 1290, 80370, 80370, 5, 80370, + 4243, 4242, 2389, 80370, 80370, 503, -1000, -1000, 80370, 1938, + -1000, 471, 57, 913, 1871, 4409, 1248, 80370, 80370, 80370, + 4691, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 1991, -1000, 4645, 4086, 3027, 1991, 4436, -118, -1000, + 29406, 88994, 80370, 1944, 1944, -1000, 4240, 2683, -1000, 73314, + 44306, 44306, 44306, 44306, 44306, 44306, 44306, 44306, -1000, 4545, + 4486, 4237, -1000, 4537, 4536, 4524, 740, 4543, 4512, 4456, + 4232, -1000, 64690, -1000, -1000, -1000, 2208, 2678, -1000, 441, + 3502, 1460, 16847, 16847, 4725, 4620, 4690, 4232, 2224, -1000, + -1000, -1000, 2251, -1000, 4812, 1223, 1187, 1187, 1436, 4811, + 27054, -1000, 2688, 1783, 1305, 4610, 608, -1000, 2688, -39, + 1169, 2688, 2688, 2688, 2688, 2688, 2688, 2688, 2688, 1054, + 1036, 2688, 2688, 2688, 2688, 2688, 2688, 2688, 2688, 2688, + 2688, 2688, 1666, 2688, 2688, 2688, 2688, 2688, -1000, 2688, + 4236, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1098, 983, + -1000, -1000, 467, 660, 1294, 147, 130, 502, 4724, 664, + -1000, 1789, 658, -1000, 2688, 4723, 2688, 38817, -1000, 1938, + 923, 4722, 692, 80370, 80370, 396, 2165, 2697, 194, 92, + -1000, -1000, 2213, 11345, 2213, 11345, 3431, -1000, -1000, 1272, + -1000, -1000, 1871, -1000, 80370, 80370, -1000, -1000, 4235, 2899, + -1000, -1000, 23915, -1000, 11345, 11345, -1000, -1000, 45090, 80370, + -1000, 62, -1000, 101, 4810, 2212, 2211, -1000, 3245, 4050, + 4049, -1000, -1000, -1000, -1000, -1000, -1000, -207, -1000, -1000, + 80370, -1000, 80370, 80370, 1818, -1000, 2205, 1871, 4432, 80370, + 1176, -1000, -1000, 4234, 80370, -1000, 3822, -1000, 4844, -207, + 4843, 13703, -1000, -1000, 72530, -1000, 71746, 2929, -1000, 21563, + 3008, 296, -1000, 444, -307, 292, 2921, 291, 3132, -1000, + -1000, 4048, 4047, 4046, 2664, -1000, 2661, 4044, -1000, 2658, + 2653, 3426, -1000, -303, 229, 4810, 4642, 3805, 2204, -1000, + 4642, -1000, -315, -118, -1000, 28622, 88994, 80370, 3802, 3101, + 4689, 3503, -251, 16847, 70962, 16847, 1533, 2388, 407, -1000, + -1000, 2026, 2026, -1000, 2026, 2026, -1000, -1000, 80370, 2193, + 2898, 1373, 3837, -1000, 2648, -1000, -1000, -1000, -1000, 3418, + -1000, -1000, 2791, 80370, -1000, -1000, 2058, 80370, 55282, -1000, + -1000, -1000, -1000, 80370, -1000, 660, 4408, -1000, 63906, -1000, + 2791, -1000, -1000, 4823, -1000, -1000, 16847, 16847, 221, 4823, + 2791, 2791, -1000, 2833, -1000, 80370, -1000, -380, 70178, 2018, + -1000, 1257, 2384, 2359, -1000, 63906, 561, 63906, -1000, -1000, + 4785, -1000, 80370, 4656, -1000, -1000, -1000, 3745, 2894, -370, + 80370, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 2644, -1000, 1409, 1409, 5889, 6767, -1000, 1409, 1409, + 5889, 6076, 20777, -1000, 20777, -1000, 20777, -1000, -1000, -1000, + -1000, 3921, -1000, 2859, -1000, 16847, 3000, 5618, 16847, 488, + 2591, 38033, 49794, -21, 4650, 3913, 80370, 16847, -1000, -1000, + 16847, 16847, 20777, -1000, 3882, -1000, -1000, -1000, -1000, 16847, + 16847, 3444, -1000, 80370, -1000, -1000, -1000, -1000, 38033, -1000, + 20777, -1000, -1000, -1000, -1000, 16847, 16847, 16847, 2158, -326, + -326, 2158, 3877, 2638, 294, 294, -326, 3865, 3857, 3843, + 2627, 294, 3839, 3834, 3818, 3759, 3751, 3649, 3645, 3584, + 4820, 3569, 3547, 2620, 3490, 2500, -1000, 69394, -1000, -1000, + -1000, 294, -1000, -350, 16847, -350, 16847, -350, -350, 16847, + 3190, 18419, 4810, 4748, 14489, -1000, 4642, 4642, 600, -1000, + -1000, 4233, 1167, 2189, 3417, 3800, 196, -1000, 2889, -1000, + 691, 59986, 80370, 4842, 4841, -1000, 2358, 3797, 68610, -1000, + 1599, 80370, -1000, -1000, 4840, 4839, -1000, -1000, 80370, 80370, + 80370, -1000, -1000, -1000, 1554, -1000, 3787, -1000, -1000, 424, + 416, 3312, 4892, 4891, 2958, 3786, 547, 1821, 25483, 80370, + 4232, 4232, 320, 2688, 833, 947, 63906, 1070, -1000, 67826, + 3124, 2875, 4430, -1000, 1506, 4635, 80370, 67042, 813, 1260, + 4231, 853, 6550, -1000, 4645, 4230, 80370, 4645, -1000, -315, + -1000, 4639, 1803, -1000, 4229, -1000, 2607, 4579, -1000, 2357, + 2169, -1000, 2874, 2602, 2598, 2872, -315, 370, 7327, -1000, + 80370, 80370, 2181, -1000, 2356, 368, 4399, 4399, 4399, -1000, + 4399, 4399, -1000, -1000, -1000, -1000, 4535, 3785, -1000, 4527, + -1000, 4526, -1000, 4511, -1000, -1000, -1000, -1000, 4520, -1000, + -1000, -1000, 30191, -1000, 44306, -1000, 1460, -1000, 4753, 1525, + 1525, 1525, 2455, 4043, 43521, 42737, -1000, -1000, 853, 6550, + 4688, 6941, 4126, -1000, 66258, -1000, -1000, -1000, 1342, -1000, + 1525, 1525, 1217, 80370, 3050, 1525, 3045, 4228, -1000, -1000, + 953, 80370, 80370, -1000, 80370, 80370, 80370, 80370, 80370, 80370, + 80370, -1000, -1000, 80370, 65474, -1000, 80370, 80370, -1000, 80370, + 3041, 80370, 80370, 3036, 4608, 2688, 2688, 1523, -1000, -1000, + 916, -1000, 65474, 3414, 3404, 3403, 3396, 3395, 3782, 3777, + 3772, 2688, 2688, 3391, 3771, 64690, 3769, 1975, 3390, 3385, + 3381, 3352, 3767, 1606, -1000, 3764, 3348, 3287, 3278, 80370, + 4226, 3672, -1000, -1000, 3312, 3761, 4225, 3376, 3760, 1367, + 660, 3757, 4429, 320, 2688, 641, 80370, 2871, 2868, 38033, + 2688, 38817, -1000, 947, 875, 875, 910, 56, 32545, -1000, + -1000, -1000, 80370, 80370, 11345, -1000, -1000, 93, 95, -1000, + -1000, -1000, -1000, 63906, 3755, 839, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 4642, 16847, 4626, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 80370, 1176, -1000, -1000, -1000, 25483, + -1000, -1000, 80370, -1000, 4823, -1000, 30191, -1000, -1000, -1000, + 2350, -1000, 2975, -360, 21563, 2936, 2590, -1000, 16847, 21563, + 16847, -161, 620, -163, -1000, -1000, -1000, -1000, 3752, -1000, + -1000, -1000, 3375, -1000, 3367, -1000, 89, 355, 384, 4642, + -1000, 421, 3651, -1000, -1000, 13703, 1803, 2588, 4578, 2169, + 2584, -1000, -1000, -1000, -1000, 4741, -1000, -1000, -1000, -1000, + -1000, 271, -402, -403, 243, 3750, 80370, 3362, -1000, -1000, + -1000, -1000, -1000, 1765, -1000, -1000, -1000, 4823, 2791, 4823, + 55282, 2791, 2885, -1000, -1000, -1000, -1000, 1871, -1000, -1000, + 4823, -1000, 3132, 3132, -1000, -1000, -380, 4823, 4823, 2791, + -1000, -1000, 4838, 63906, 660, 2518, 63122, -1000, 595, 2136, + 909, 3749, -1000, 1365, 192, 3747, 3745, -1000, -1000, -1000, + -1000, 20777, -1000, -1000, 20777, 2815, 2695, -1000, -1000, -1000, + 3132, 16847, 4042, 4197, 3238, 4040, 4031, -1000, -1000, 4197, + 4197, -1000, 4193, 4194, 4193, 2524, 2524, 4029, -1000, 4223, + -1000, 4650, -1000, 2577, 3110, 3466, 6552, 294, 3458, 3438, + 16847, 2345, 4021, 6218, 2424, 2369, 3425, 44, 294, 4819, + 294, -74, 294, 294, -1000, -1000, -1000, 294, 294, 294, + 294, 294, -1000, 294, 294, 294, 294, 294, 294, 294, + 294, 4222, 294, 294, 294, 294, 16847, -1000, 88210, -1000, + 294, 4619, 2199, 294, 2167, 294, 294, 3415, 18, -192, + 17, -193, 4642, 4810, -1000, -1000, -1000, 16847, 494, 4020, + 5082, 2164, 927, 927, 3745, 3744, 80370, -1000, -1000, -1000, + 3741, 1639, -201, 80370, -1000, -404, -408, 347, 80370, 3739, + 80370, 80370, 227, 2937, 3059, -1000, 3738, -1000, -1000, 62338, + 80370, 80370, 81938, 980, 80370, 80370, 3737, -1000, -1000, 4221, + -1000, 4202, -46, 4200, 2, 3735, 4018, 2163, -1000, -1000, + 80370, -1000, -1000, -1000, 4016, 2157, -1000, -1000, -1000, 6550, + 4198, 4197, 4197, 1504, 4193, -1000, -1000, -1000, 4193, -1000, + -1000, -1000, -1000, 4197, 4197, 4197, 4197, 4197, 4197, 4195, + -1000, -1000, 4194, 4194, 4194, 4193, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 1684, 4191, 4192, 4192, 4191, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 4687, + 4686, 3361, -1000, -1000, -1000, 41953, 80370, 875, -1000, -1000, + -1000, 1126, 616, 3346, 887, -1000, 80370, 844, 687, 4597, + 2866, 3733, 80370, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 4635, -1000, 1729, -380, 80370, 815, 22347, + -1000, 1957, 4683, 80370, -1000, 80370, 61554, -1000, -117, -1000, + -1000, 24699, -1000, 2688, 24699, 814, 2847, -1000, 16847, 2568, + 4645, -1000, 3035, -118, 14489, 2196, 80370, -118, 80370, 80370, + 14489, -1000, 80370, -1000, 80370, 16847, -1000, -1000, -315, 4015, + -1000, 1165, 1989, 203, 30191, 80370, -1000, 57634, 16847, -1000, + -1000, 16847, 4190, -1000, -1000, -1000, -339, -1000, 4014, -1000, + -1000, -1000, -1000, -1000, 4485, -1000, 325, -1000, 4189, 4600, + -1000, -1000, -1000, 3731, -1000, 2120, 56066, -1000, 2858, -1000, + -1000, 2100, 54498, -1000, 2852, -1000, -1000, 814, -1000, 1991, + -1000, 1198, 1304, 27838, -1000, 1148, 4615, 80370, 6550, -1000, + 80370, -1000, 80370, 80370, -1000, 80370, 80370, 1217, 16847, 945, + 735, 732, -1000, 1034, -1000, 1032, 1648, 795, 1277, 1277, + 4615, 80370, 1254, -1000, 2097, -1000, 4650, -1000, -1000, 2094, + -1000, -1000, -1000, -1000, 80370, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 38033, 38033, 4721, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 3729, 3722, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 80370, 2557, -1000, 2844, 3721, 2, 10559, -1000, -1000, + 1252, -1000, 4428, 1355, 3361, 41953, 2840, 2697, 3713, 3709, + -1000, 38033, -1000, 875, -1000, 3702, 3700, -1000, 3124, 2837, + 1353, 80370, -1000, 1819, 80370, 80370, -1000, 2016, -1000, 2834, + 2116, -1000, -1000, -1000, -1000, 2018, 4010, -1000, -1000, 4652, + -1000, -1000, 4622, -1000, -1000, 4007, 808, 4817, 2013, 60770, + -1000, -360, 2630, -1000, 2995, 277, 2839, 80370, -1000, -1000, + -1000, 4005, 4004, -1000, -125, 394, 4807, 4806, 4652, -135, + 3699, -1000, 1756, 2147, -118, -1000, 1644, -1000, -1000, -1000, + -1000, -409, -1000, -1000, 2026, -1000, 4823, -1000, 2791, 4823, + 4823, -232, -1000, -1000, -1000, -1000, 4823, 660, -1000, 2002, + -1000, -1000, -1000, -1000, -1000, -1000, 445, -1000, 80370, -1000, + 1915, 191, -1000, -1000, -1000, 3132, -1000, 1521, 488, -1000, + -1000, -1000, 1503, -1000, -1000, -1000, -1000, -1000, -1000, 41169, + -1000, -1000, -1000, 16847, -1000, -1000, -1000, -1000, -1000, 3407, + 80370, -1000, -1000, 16847, 16847, -1000, 4002, 3694, -1000, 4188, + -1000, 4000, 3692, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 4906, -1000, + -1000, -1000, -1000, 3401, 3999, 1155, -1000, -1000, -1000, -350, + 16847, -1000, -350, 16847, -1000, -1000, 4837, 2540, 3998, 3996, + 2539, 3992, 3989, 4652, 4642, 1798, 3988, 1890, -1000, -1000, + -1000, -1000, -1000, -1000, 3986, 5082, 1530, 3691, 1530, -1000, + -1000, -1000, -1000, 59986, 80370, -1000, -1000, -1000, 59986, 80370, + 4836, 40385, 1235, -380, 858, 4187, -1000, 866, 2937, 1632, + 4186, 3688, -1000, 80370, 4834, 80370, 3312, 975, 3312, 1050, + 80370, -207, 56066, 54498, 0, 3345, 10559, -1000, 3686, -1000, + -24, 1821, 6550, 1395, 25483, 4633, 1957, 1957, -1000, 3685, + 465, -1000, -1000, -1000, 757, -1000, 3343, -1000, -1000, 3271, + 2310, 458, -1000, -1000, -1000, -1000, -1000, -1000, 3305, 80370, + 59202, 3305, 3360, 2823, -389, -1000, 4183, -1000, 2688, 2688, + 2688, 1235, 803, 80370, 3976, 1886, -1000, -1000, -1000, -1000, + -1000, 1957, -1000, 4601, 80370, 1943, 3973, -211, 3970, 1172, + 2770, 2762, -1000, 3341, 2538, 4577, 1495, -1000, 3967, 1881, + -118, -1000, -1000, 1803, 2320, -1000, -1000, -1000, 2820, 3132, + -1000, -1000, 58418, 30191, 57634, 1877, -1000, 2250, -1000, 3090, + 3132, 80370, -1000, 1791, -1000, -1000, -1000, 56850, -1000, 4802, + 4797, 219, 56066, 2535, 55282, 54498, 2526, 53714, 1172, -1000, + 52930, 2520, -1000, 80370, -1000, -1000, 80370, 2517, -1000, 6160, + 4182, -1000, 4181, 4179, 4406, 896, 4178, 4176, 80370, 3393, + 936, 3340, 20777, 4174, 20777, 4173, 957, 4172, -1000, -1000, + -1000, -1000, -1000, 1112, 4623, -1000, 715, -1000, -1000, -1000, + -1000, 993, 985, -1000, -1000, 4615, 80370, 80370, -1000, 80370, + -1000, 2473, -1000, 38033, -1000, -1000, 2511, -1000, 3672, 3664, + -1000, -1000, 3966, 3132, -1000, 2463, 660, 1343, 80370, -1000, + 465, 3663, 11345, -1000, -1000, -1000, -1000, -1000, -1000, 4597, + 3662, 3305, 80370, -1000, 80370, 1819, 1819, 4906, 30191, 80370, + 14489, -315, -1000, -1000, 4618, 2562, -1000, -1000, -1000, 80370, + 4815, 4796, -1000, 1193, 21563, -168, 618, -1000, -1000, -1000, + -127, 3661, -1000, -1000, 4794, 3660, 3507, -1000, 229, 3659, + -1000, -118, -1000, 1803, 3655, -1000, -1000, -1000, 4823, -1000, + -1000, 80370, -1000, 1871, -1000, -1000, 1776, 1039, -1000, 4720, + 3961, 4712, 2742, -1000, -1000, -1000, 3387, -1000, -1000, 3368, + 3359, -326, -1000, 4906, 294, -1000, 3957, 294, -1000, 4906, + -1000, 4793, 294, 3354, 294, 3310, -350, 4609, -1000, 3647, + -1000, -1000, -1000, 3638, -1000, -1000, -1000, 4652, -1000, 16847, + -1000, 3954, -1000, 3637, -1000, -1000, -1000, 3636, -1000, 3631, + -204, -1000, -1000, 684, 1235, -1000, 584, 80370, 949, -1000, + 52146, 10559, -391, 801, 80370, 4825, 3629, 3312, 3626, 3312, + 80370, 973, -1000, 2501, 2497, 4682, 3625, -1000, 3941, -1000, + 3619, 3618, -1000, -1000, 6550, -1000, 3665, 4894, 4894, -1000, + -1000, 4783, -1000, 1705, 672, -1000, -1000, 3262, 965, -1000, + -1000, 3617, 933, -1000, 1819, -1000, -1000, 2817, 3160, 3541, + 49794, 38033, 38817, 3610, -1000, 80370, -1000, 568, 24699, -1000, + 1235, 4736, 799, 4748, 581, 4892, 7598, 1685, 2755, -1000, + 3336, -1000, 3332, -1000, -1000, 4170, 80370, -1000, -1000, 1803, + 80370, 16847, 4823, 1877, 200, -315, -1000, 2394, 329, -1000, + 39601, 2489, -1000, 16847, 2483, -1000, -1000, -1000, -1000, 4168, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 1685, 80370, + -1000, 1148, 4576, -1000, -1000, 80370, -1000, 6160, -1000, -1000, + 3076, 3071, 20777, -1000, -1000, 3607, 3603, 3598, 38817, 1308, + 2809, 2805, 1362, 4166, -1000, 997, 4869, 3330, -1000, -1000, + -1000, 1467, -143, 4165, 3032, 3029, -1000, 80370, -1000, 49794, + 49794, 49794, 1853, 1853, 49794, 49794, 4161, 1277, 4126, 4792, + -1000, 6020, 80370, 5875, 80370, 4160, 2784, 20777, 8253, 8253, + 8253, 8253, 8253, 20777, -1000, -1000, -1000, 2783, -1000, -1000, + -1000, -1000, -1000, -1000, 2688, 2442, -1000, -1000, -1000, -1000, + -1000, 80370, 2148, -1000, -1000, -1000, 3360, -1000, -1000, 1818, + -1000, 4772, 1877, -1000, -1000, -1000, -1000, -1000, 4566, -1000, + -346, 16847, 17633, -1000, -360, 80370, 80370, -129, 3329, -1000, + 3597, 395, -1000, -1000, 355, -1000, 1803, -1000, -1000, 2791, + -131, 226, 38033, 2776, 38033, -1000, 38033, 3938, 525, -31, + -1000, -1000, -1000, 294, 3934, -1000, 294, -1000, 483, 16847, + -1000, -350, -1000, -350, 294, -1000, 3932, 3931, -1000, 3299, + -1000, -1000, -1000, -1000, 80370, 80370, -1000, 80370, 3595, 3327, + -1000, -1000, 2467, -1000, -1000, -1000, 3012, 3010, 2466, 3928, + 3532, 80370, 794, 80370, -207, 3590, -207, 3589, 972, 3312, + -1000, -1000, -185, -1000, -1000, -1000, -1000, -27, -1000, -1000, + -1000, 586, -1000, 905, 3494, 3326, -1000, -1000, 663, -1000, + -1000, -1000, 3305, 3586, -1000, -1000, 190, -1000, 2769, 2460, + -1000, -1000, -1000, 757, 1130, -1000, 1957, 4678, 7481, -1000, + 1783, -1000, -1000, -1000, 80370, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 1776, 2688, -1000, 1130, 1038, 2727, -1000, 3320, + -1000, -1000, 16847, 1710, -1000, 3132, 4906, -315, -1000, 13703, + -1000, 2998, 80370, 80370, -1000, -1000, -1000, 51362, 81154, 1027, + 2439, -1000, 7239, 1306, -1000, -1000, -1000, -1000, 5889, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 3583, 3582, -1000, + -1000, -1000, -1000, -1000, 3317, 4158, 64, -1000, 4710, 4677, + 16847, -1000, -1000, 4155, 2429, 2409, 2402, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 2393, 2373, 49794, -1000, -1000, -1000, 954, -1000, 2371, -1000, + 2366, 50578, 3315, 5617, -1000, 2688, 2688, 3580, 3578, 745, + -1000, -1000, 2688, 2688, 2688, 2688, 2688, 2688, 4150, 3577, + 3576, 2688, 2688, 2688, 2688, 2688, 2688, 2758, -1000, -1000, + -1000, 2751, 2688, 2688, 2688, 5889, 8253, 3113, 38033, 2688, + 1976, 80370, -1000, -315, -315, 4564, -1000, 80370, 3132, 1979, + 389, 4148, 4146, -1000, -1000, -1000, 4145, -1000, -1000, 4791, + -125, 4823, -133, 3574, 337, 388, -1000, 3565, 3924, -1000, + -1000, -28, 4560, 4557, -35, -1000, -1000, -1000, -1000, -1000, + 1180, -1000, -1000, -1000, 1798, 294, 294, -1000, -1000, -1000, + -1000, 3563, -1000, -1000, -1000, -1000, -1000, 80370, 3548, -1000, + -1000, 177, -1000, 2741, -1000, 80370, 792, -1000, -207, -1000, + -207, 3312, 3545, -1000, 80370, 996, -1000, -1000, -1000, -1000, + 439, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 3541, 3535, + -1000, -1000, 931, 4790, -1000, 1957, 7598, -1000, 2688, 757, + -1000, 450, 931, -1000, 850, -1000, 2656, -1000, 3308, -1000, + 2352, 4772, -1000, 1756, 2953, 16847, 2998, 2998, -1000, -1000, + 2351, -1000, 5761, 4925, -1000, 847, -1000, -1000, -1000, 7239, + 943, -1000, -1000, 1122, 4143, -1000, -1000, 3920, 16847, 4142, + 2688, 4141, 3289, -14, 49794, 4405, -1000, 4404, 4401, 4400, + 2347, 938, -1000, -1000, -1000, 2342, -1000, -1000, 3306, 3298, + -1000, -1000, 80370, 3285, 3277, 3269, 3254, 3213, 3211, 80370, + -1000, -1000, 3210, 3206, 3205, 3202, 3191, 3164, 3091, 3073, + 3159, 3145, 3126, -1000, -1000, -1000, 38033, 80370, -1000, -1000, + -1000, -1000, 1745, -1000, 4675, -1000, -283, 4140, 16847, 16847, + 80370, 3507, -127, -1000, -1000, 3534, -1000, 1225, 392, 388, + -1000, 4789, 383, 4788, 4784, 1739, -1000, 4556, -1000, -1000, + -1000, -1000, 1674, -122, 316, 311, 309, 300, -1000, -1000, + -1000, -1000, -1000, -1000, 3042, 3042, -207, 3532, 3530, -1000, + 80370, -1000, -1000, 3526, -207, 861, -1000, 569, -1000, -1000, + -1000, 8205, -1000, 4782, 953, -1000, -1000, 38033, -1000, 4891, + 4890, 4889, 4882, -1000, -1000, -1000, -1000, -1000, 3112, -1000, + -1000, -315, 4833, 3132, 2941, 2940, 3919, 81154, 4919, 4692, + 3523, -1000, -1000, -1000, -1000, 2306, -1000, 80370, 1360, 12917, + -1000, 3282, -1000, 38033, 16847, -149, 4427, -1000, 513, 2302, + 8253, 1853, 8253, 8253, 1853, 8253, 1853, 8253, 1853, 555, + -1000, 3107, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 2278, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 80370, 4139, + -1000, 4137, 2262, 2257, 2219, -1000, -1000, -129, -1000, 4136, + 3093, 394, 371, 4781, -1000, 3507, 4780, 3507, 3507, -1000, + 322, 4875, 2988, -1000, 359, 338, 328, 314, -1000, -1000, + -1000, -1000, -1000, -1000, 2937, -1000, 2937, -1000, -1000, -1000, + -1000, -207, -1000, 3517, -1000, -1000, -1000, -1000, -1000, -1000, + 49010, 945, -1000, -1000, -1000, 4135, -1000, 4132, -1000, 4130, + -1000, -1000, 4708, -1000, 4872, 4871, -1000, -1000, -1000, 3516, + 4923, 210, -1000, 943, 7598, -1000, 12917, 2218, -1000, 3132, + -1000, 1277, -1000, 3173, -1000, -1000, -1000, -1000, 4425, 4421, + 4829, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 88210, 2210, 16847, -1000, -1000, -1000, 80370, + -1000, 4696, 37249, 376, -1000, -1000, -1000, 3511, -1000, 3507, + -1000, -1000, 2684, -32, 1674, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -190, -1000, 80370, 936, 47442, 47442, 47442, 80370, + 3953, 3936, 3328, 3501, 4129, -1000, 7598, 2209, -1000, 12917, + -1000, -149, -1000, 4835, -1000, 4867, 1375, 1375, 8253, 8253, + 8253, 8253, 3862, -1000, 4127, 3842, -1000, -1000, 80370, -1000, + 2203, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 3497, -36, + -1000, 984, -1000, 3454, 2200, 4126, 2188, -1000, 2636, -1000, + -1000, 2187, -1000, 2621, 2128, -1000, 2614, 1710, 80370, 4120, + 80370, 4119, -1000, 4417, -1000, -1000, 3448, -1000, 81154, -1000, + -1000, -1000, -1000, -1000, -1000, 3171, 1007, -1000, -1000, 16847, + -1000, 1704, -1000, 2608, -1000, 48226, -1000, -1000, -1000, 531, + 4555, 4414, 3069, -1000, -1000, -1000, -1000, 47442, 46658, -1000, + 47442, 46658, -1000, 47442, 46658, 2112, 1945, 16847, 2055, 16847, + 4915, -1000, 2004, -1000, -1000, -1000, 3758, 80370, 12131, -1000, + 746, -1000, -1000, 531, 3065, 4413, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 4575, 80370, 80370, 1974, 4572, 1962, + 3328, 3328, -1000, -1000, -1000, -1000, 3132, -1000, -1000, 535, + 3058, 3980, 1766, -1000, -1000, 3937, -1000, -1000, 4156, -1000, + 4113, -1000, 529, 16847, 80370, 16847, 4912, 4917, -1000, 1913, + -1000, 1836, -1000, -1000, -1000, -1000, +} + +var yyPgo = [...]int{ + 0, 48, 5628, 14, 1, 5627, 5626, 5619, 241, 90, + 334, 261, 5618, 200, 376, 351, 366, 297, 5617, 371, + 364, 5616, 5615, 5612, 365, 362, 5611, 5610, 5609, 5608, + 5607, 5606, 5604, 5602, 5601, 5600, 5599, 5598, 5597, 5596, + 5595, 5594, 5592, 5591, 5590, 5589, 5588, 5587, 5584, 5580, + 5578, 5576, 5572, 5566, 5565, 5562, 5561, 5560, 5559, 5558, + 5556, 5555, 358, 5554, 5553, 5552, 5550, 5547, 5546, 5545, + 5543, 5542, 5541, 5535, 5534, 5533, 5531, 5530, 5529, 5528, + 5527, 5526, 5519, 5518, 5516, 5510, 5509, 5508, 5507, 5503, + 5502, 5501, 5500, 5499, 5498, 5495, 5492, 5491, 5490, 5489, + 5487, 5484, 242, 5482, 353, 5481, 5480, 5479, 5478, 5477, + 5476, 5474, 4624, 5473, 104, 63, 77, 5472, 5471, 5470, + 5469, 5468, 5466, 5465, 5464, 357, 171, 5463, 5462, 5461, + 5460, 5459, 5458, 5457, 5456, 5455, 5454, 5451, 5450, 5449, + 386, 5448, 5445, 356, 5444, 5443, 5442, 5441, 5439, 313, + 5438, 152, 5437, 354, 256, 5431, 5429, 5428, 5427, 5426, + 5421, 5418, 150, 167, 5410, 5406, 5404, 5403, 5402, 5400, + 5399, 5398, 5397, 5395, 5394, 5392, 188, 5391, 321, 239, + 114, 5390, 83, 5389, 326, 159, 283, 5388, 302, 5386, + 213, 5385, 209, 5384, 5383, 5381, 5380, 5378, 5377, 5376, + 5375, 5374, 5372, 5370, 5368, 5367, 5366, 5365, 5364, 5363, + 5360, 5359, 5358, 5357, 5354, 5353, 5352, 5351, 5348, 5347, + 5345, 5343, 5342, 81, 5339, 345, 5337, 115, 5336, 125, + 122, 208, 5335, 145, 5334, 250, 5333, 111, 5330, 348, + 106, 5326, 36, 55, 5325, 128, 66, 229, 5324, 5323, + 344, 4664, 340, 5320, 198, 5319, 320, 5318, 5317, 5316, + 324, 84, 50, 277, 5313, 5312, 342, 240, 5311, 5306, + 5304, 347, 5302, 275, 228, 237, 133, 173, 5301, 217, + 5300, 118, 107, 121, 67, 71, 124, 136, 230, 183, + 5293, 5289, 117, 254, 179, 273, 146, 5288, 5287, 5286, + 16, 249, 325, 5284, 236, 245, 126, 5282, 5277, 288, + 5275, 5273, 5271, 305, 211, 5270, 148, 5269, 5268, 5267, + 42, 5265, 5264, 282, 3, 2, 5263, 286, 5262, 5261, + 149, 5260, 5259, 151, 265, 204, 5258, 116, 176, 234, + 175, 5256, 3750, 184, 137, 5255, 110, 163, 5253, 61, + 5252, 5251, 5250, 5249, 251, 5245, 5242, 206, 5240, 95, + 5239, 5238, 5237, 102, 5236, 112, 108, 157, 144, 5235, + 49, 155, 143, 5234, 5233, 5232, 5231, 5230, 15, 6, + 4, 5228, 5209, 5204, 5203, 8, 5202, 5201, 13, 5199, + 41, 5198, 105, 5197, 5196, 5195, 5194, 5193, 5192, 5191, + 5190, 5189, 5188, 5186, 5185, 58, 5184, 5182, 5180, 5178, + 18, 30, 32, 5177, 47, 5175, 226, 5174, 5173, 218, + 5172, 5171, 274, 5168, 5167, 139, 134, 5166, 140, 5164, + 238, 5163, 68, 5161, 5160, 509, 5159, 5158, 5157, 336, + 5155, 5153, 5151, 281, 5150, 5149, 5148, 5147, 822, 5146, + 5145, 5144, 5143, 5142, 5141, 45, 327, 5, 300, 40, + 5140, 196, 207, 5138, 65, 54, 5137, 79, 189, 290, + 205, 160, 5133, 5132, 5131, 817, 178, 147, 186, 0, + 158, 304, 220, 333, 5130, 5128, 337, 5127, 331, 299, + 338, 101, 355, 323, 5126, 5125, 103, 5114, 219, 113, + 75, 212, 516, 26, 1312, 5113, 2899, 20, 267, 5112, + 287, 5110, 23, 31, 12, 190, 5107, 5106, 60, 349, + 5105, 5104, 5103, 195, 278, 5100, 5099, 317, 687, 93, + 5096, 1738, 5095, 53, 5094, 5093, 72, 5092, 255, 28, + 52, 5090, 5089, 164, 260, 335, 154, 414, 222, 258, + 253, 223, 308, 315, 120, 22, 246, 5087, 2016, 216, + 166, 33, 5086, 19, 311, 293, 247, 165, 5085, 210, + 5084, 329, 346, 296, 5083, 259, 24, 78, 64, 51, + 73, 25, 512, 97, 29, 39, 5082, 5081, 5080, 5078, + 5077, 27, 69, 5076, 88, 5075, 35, 5074, 5073, 99, + 82, 5068, 100, 17, 5067, 5066, 34, 21, 37, 5065, + 62, 294, 227, 177, 142, 98, 5064, 5063, 215, 199, + 5062, 231, 192, 197, 5061, 70, 5060, 5059, 5057, 5056, + 4281, 1713, 5055, 214, 5053, 5052, 5051, 5049, 5048, 5046, + 292, 350, 182, 244, 332, 330, 343, 5043, 119, 76, + 289, 5040, 5039, 5038, 127, 180, 5037, 5036, 5035, 5034, + 57, 123, 5033, 38, 5032, 43, 46, 59, 5029, 85, + 5028, 5027, 5026, 9, 263, 5025, 5023, 5021, 11, 5019, + 5016, 7, 5003, 5002, 174, 4998, 141, 44, 225, 224, + 4996, 4991, 131, 270, 187, 4990, 4989, 170, 319, 4988, + 284, 4987, 193, 318, 341, 4986, 295, 4983, 4982, 4980, + 301, 4979, 1703, 4978, 4977, 309, 109, 130, 4976, 306, + 169, 4972, 4971, 135, 221, 172, 191, 80, 132, 4970, + 161, 285, 4966, 279, 4965, 312, 4964, 4963, 4962, 4961, + 232, 4960, 4959, 4958, 4957, 271, 4956, 4955, 272, 314, + 4954, 4951, 322, 316, 4950, 4949, 4948, 4947, 4945, 4942, + 4939, 4938, 96, 4937, 4936, 328, 380, 4935, 4934, 94, + 4933, 4932, +} + +//line mysql_sql.y:17042 +type yySymType struct { + union interface{} + id int + str string + item interface{} + pos int + yys int +} + +func (st *yySymType) PartitionNamesUnion() tree.IdentifierList { + v, _ := st.union.(tree.IdentifierList) + return v +} + +func (st *yySymType) accessModeUnion() tree.AccessModeType { + v, _ := st.union.(tree.AccessModeType) + return v +} + +func (st *yySymType) accountAuthOptionUnion() tree.AccountAuthOption { + v, _ := st.union.(tree.AccountAuthOption) + return v +} + +func (st *yySymType) accountCommentUnion() tree.AccountComment { + v, _ := st.union.(tree.AccountComment) + return v +} + +func (st *yySymType) accountCommentOrAttributeUnion() tree.AccountCommentOrAttribute { + v, _ := st.union.(tree.AccountCommentOrAttribute) + return v +} + +func (st *yySymType) accountIdentifiedUnion() tree.AccountIdentified { + v, _ := st.union.(tree.AccountIdentified) + return v +} + +func (st *yySymType) accountRoleUnion() *tree.Role { + v, _ := st.union.(*tree.Role) + return v +} + +func (st *yySymType) accountStatusUnion() tree.AccountStatus { + v, _ := st.union.(tree.AccountStatus) + return v +} + +func (st *yySymType) accountsSetOptionUnion() *tree.AccountsSetOption { + v, _ := st.union.(*tree.AccountsSetOption) + return v +} + +func (st *yySymType) aliasedTableExprUnion() *tree.AliasedTableExpr { + v, _ := st.union.(*tree.AliasedTableExpr) + return v +} + +func (st *yySymType) allCDCOptionUnion() *tree.AllOrNotCDC { + v, _ := st.union.(*tree.AllOrNotCDC) + return v +} + +func (st *yySymType) alterAccountAuthOptionUnion() tree.AlterAccountAuthOption { + v, _ := st.union.(tree.AlterAccountAuthOption) + return v +} + +func (st *yySymType) alterColPositionUnion() *tree.ColumnPosition { + v, _ := st.union.(*tree.ColumnPosition) + return v +} + +func (st *yySymType) alterColumnOrderUnion() *tree.AlterColumnOrder { + v, _ := st.union.(*tree.AlterColumnOrder) + return v +} + +func (st *yySymType) alterColumnOrderByUnion() []*tree.AlterColumnOrder { + v, _ := st.union.([]*tree.AlterColumnOrder) + return v +} + +func (st *yySymType) alterPartitionOptionUnion() tree.AlterPartitionOption { + v, _ := st.union.(tree.AlterPartitionOption) + return v +} + +func (st *yySymType) alterTableUnion() tree.AlterTable { + v, _ := st.union.(tree.AlterTable) + return v +} + +func (st *yySymType) alterTableOptionUnion() tree.AlterTableOption { + v, _ := st.union.(tree.AlterTableOption) + return v +} + +func (st *yySymType) alterTableOptionsUnion() tree.AlterTableOptions { + v, _ := st.union.(tree.AlterTableOptions) + return v +} + +func (st *yySymType) alterTypeOptionUnion() *tree.TypeOption { + v, _ := st.union.(*tree.TypeOption) + return v +} + +func (st *yySymType) analyzeTableEntriesUnion() []*tree.AnalyzeTableEntry { + v, _ := st.union.([]*tree.AnalyzeTableEntry) + return v +} + +func (st *yySymType) analyzeTableEntryUnion() *tree.AnalyzeTableEntry { + v, _ := st.union.(*tree.AnalyzeTableEntry) + return v +} + +func (st *yySymType) applyTableExprUnion() *tree.ApplyTableExpr { + v, _ := st.union.(*tree.ApplyTableExpr) + return v +} + +func (st *yySymType) assignmentUnion() *tree.Assignment { + v, _ := st.union.(*tree.Assignment) + return v +} + +func (st *yySymType) assignmentsUnion() []*tree.Assignment { + v, _ := st.union.([]*tree.Assignment) + return v +} + +func (st *yySymType) atTimeStampUnion() *tree.AtTimeStamp { + v, _ := st.union.(*tree.AtTimeStamp) + return v +} + +func (st *yySymType) attributeNullUnion() tree.AttributeNull { + v, _ := st.union.(tree.AttributeNull) + return v +} + +func (st *yySymType) attributeReferenceUnion() *tree.AttributeReference { + v, _ := st.union.(*tree.AttributeReference) + return v +} + +func (st *yySymType) authRecordUnion() *tree.AuthRecord { + v, _ := st.union.(*tree.AuthRecord) + return v +} + +func (st *yySymType) boolValUnion() bool { + v, _ := st.union.(bool) + return v +} + +func (st *yySymType) checkTableOptionUnion() tree.CheckTableOption { + v, _ := st.union.(tree.CheckTableOption) + return v +} + +func (st *yySymType) clusterByOptionUnion() *tree.ClusterByOption { + v, _ := st.union.(*tree.ClusterByOption) + return v +} + +func (st *yySymType) columnAttributeUnion() tree.ColumnAttribute { + v, _ := st.union.(tree.ColumnAttribute) + return v +} + +func (st *yySymType) columnAttributesUnion() []tree.ColumnAttribute { + v, _ := st.union.([]tree.ColumnAttribute) + return v +} + +func (st *yySymType) columnTableDefUnion() *tree.ColumnTableDef { + v, _ := st.union.(*tree.ColumnTableDef) + return v +} + +func (st *yySymType) columnTypeUnion() *tree.T { + v, _ := st.union.(*tree.T) + return v +} + +func (st *yySymType) comparisionExprUnion() *tree.ComparisonExpr { + v, _ := st.union.(*tree.ComparisonExpr) + return v +} + +func (st *yySymType) comparisonOpUnion() tree.ComparisonOp { + v, _ := st.union.(tree.ComparisonOp) + return v +} + +func (st *yySymType) completionTypeUnion() tree.CompletionType { + v, _ := st.union.(tree.CompletionType) + return v +} + +func (st *yySymType) conflictOptUnion() *tree.ConflictOpt { + v, _ := st.union.(*tree.ConflictOpt) + return v +} + +func (st *yySymType) createOptionUnion() tree.CreateOption { + v, _ := st.union.(tree.CreateOption) + return v +} + +func (st *yySymType) createOptionsUnion() []tree.CreateOption { + v, _ := st.union.([]tree.CreateOption) + return v +} + +func (st *yySymType) cstrUnion() *tree.CStr { + v, _ := st.union.(*tree.CStr) + return v +} + +func (st *yySymType) cteUnion() *tree.CTE { + v, _ := st.union.(*tree.CTE) + return v +} + +func (st *yySymType) cteListUnion() []*tree.CTE { + v, _ := st.union.([]*tree.CTE) + return v +} + +func (st *yySymType) cycleOptionUnion() *tree.CycleOption { + v, _ := st.union.(*tree.CycleOption) + return v +} + +func (st *yySymType) datastreamOptionUnion() *tree.DataStreamOption { + v, _ := st.union.(*tree.DataStreamOption) + return v +} + +func (st *yySymType) datastreamOptionsUnion() tree.DataStreamOptions { + v, _ := st.union.(tree.DataStreamOptions) + return v +} + +func (st *yySymType) datastreamTableParamUnion() *tree.DataStreamTableParam { + v, _ := st.union.(*tree.DataStreamTableParam) + return v +} + +func (st *yySymType) defaultOptionalUnion() bool { + v, _ := st.union.(bool) + return v +} + +func (st *yySymType) diffOutputOptUnion() *tree.DiffOutputOpt { + v, _ := st.union.(*tree.DiffOutputOpt) + return v +} + +func (st *yySymType) directionUnion() tree.Direction { + v, _ := st.union.(tree.Direction) + return v +} + +func (st *yySymType) duplicateKeyUnion() tree.DuplicateKey { + v, _ := st.union.(tree.DuplicateKey) + return v +} + +func (st *yySymType) elseIfClauseUnion() *tree.ElseIfStmt { + v, _ := st.union.(*tree.ElseIfStmt) + return v +} + +func (st *yySymType) elseIfClauseListUnion() []*tree.ElseIfStmt { + v, _ := st.union.([]*tree.ElseIfStmt) + return v +} + +func (st *yySymType) explainOptionUnion() tree.OptionElem { + v, _ := st.union.(tree.OptionElem) + return v +} + +func (st *yySymType) explainOptionsUnion() []tree.OptionElem { + v, _ := st.union.([]tree.OptionElem) + return v +} + +func (st *yySymType) exportParmUnion() *tree.ExportParam { + v, _ := st.union.(*tree.ExportParam) + return v +} + +func (st *yySymType) exprUnion() tree.Expr { + v, _ := st.union.(tree.Expr) + return v +} + +func (st *yySymType) exprsUnion() tree.Exprs { + v, _ := st.union.(tree.Exprs) + return v +} + +func (st *yySymType) fieldsUnion() *tree.Fields { + v, _ := st.union.(*tree.Fields) + return v +} + +func (st *yySymType) fieldsListUnion() []*tree.Fields { + v, _ := st.union.([]*tree.Fields) + return v +} + +func (st *yySymType) fillModeUnion() tree.FillMode { + v, _ := st.union.(tree.FillMode) + return v +} + +func (st *yySymType) foreignTableOptionUnion() tree.ForeignTableOption { + v, _ := st.union.(tree.ForeignTableOption) + return v +} + +func (st *yySymType) foreignTableOptionsUnion() tree.ForeignTableOptions { + v, _ := st.union.(tree.ForeignTableOptions) + return v +} + +func (st *yySymType) foreignTableParamUnion() *tree.ForeignTableParam { + v, _ := st.union.(*tree.ForeignTableParam) + return v +} + +func (st *yySymType) frameBoundUnion() *tree.FrameBound { + v, _ := st.union.(*tree.FrameBound) + return v +} + +func (st *yySymType) frameClauseUnion() *tree.FrameClause { + v, _ := st.union.(*tree.FrameClause) + return v +} + +func (st *yySymType) frameTypeUnion() tree.FrameType { + v, _ := st.union.(tree.FrameType) + return v +} + +func (st *yySymType) fromUnion() *tree.From { + v, _ := st.union.(*tree.From) + return v +} + +func (st *yySymType) fullOptUnion() bool { + v, _ := st.union.(bool) + return v +} + +func (st *yySymType) fullTextSearchTypeUnion() tree.FullTextSearchType { + v, _ := st.union.(tree.FullTextSearchType) + return v +} + +func (st *yySymType) funcArgUnion() tree.FunctionArg { + v, _ := st.union.(tree.FunctionArg) + return v +} + +func (st *yySymType) funcArgDeclUnion() *tree.FunctionArgDecl { + v, _ := st.union.(*tree.FunctionArgDecl) + return v +} + +func (st *yySymType) funcArgsUnion() tree.FunctionArgs { + v, _ := st.union.(tree.FunctionArgs) + return v +} + +func (st *yySymType) funcExprUnion() *tree.FuncExpr { + v, _ := st.union.(*tree.FuncExpr) + return v +} + +func (st *yySymType) funcReturnUnion() *tree.ReturnType { + v, _ := st.union.(*tree.ReturnType) + return v +} + +func (st *yySymType) funcTypeUnion() tree.FuncType { + v, _ := st.union.(tree.FuncType) + return v +} + +func (st *yySymType) functionNameUnion() *tree.FunctionName { + v, _ := st.union.(*tree.FunctionName) + return v +} + +func (st *yySymType) groupByUnion() *tree.GroupByClause { + v, _ := st.union.(*tree.GroupByClause) + return v +} + +func (st *yySymType) icebergOptionUnion() *tree.IcebergOption { + v, _ := st.union.(*tree.IcebergOption) + return v +} + +func (st *yySymType) icebergOptionsUnion() tree.IcebergOptions { + v, _ := st.union.(tree.IcebergOptions) + return v +} + +func (st *yySymType) icebergRefSpecUnion() *tree.IcebergRefSpec { + v, _ := st.union.(*tree.IcebergRefSpec) + return v +} + +func (st *yySymType) icebergTableParamUnion() *tree.IcebergTableParam { + v, _ := st.union.(*tree.IcebergTableParam) + return v +} + +func (st *yySymType) identifierListUnion() tree.IdentifierList { + v, _ := st.union.(tree.IdentifierList) + return v +} + +func (st *yySymType) ifNotExistsUnion() bool { + v, _ := st.union.(bool) + return v +} + +func (st *yySymType) incrementByOptionUnion() *tree.IncrementByOption { + v, _ := st.union.(*tree.IncrementByOption) + return v +} + +func (st *yySymType) indexCategoryUnion() tree.IndexCategory { + v, _ := st.union.(tree.IndexCategory) + return v +} + +func (st *yySymType) indexHintUnion() *tree.IndexHint { + v, _ := st.union.(*tree.IndexHint) + return v +} + +func (st *yySymType) indexHintListUnion() []*tree.IndexHint { + v, _ := st.union.([]*tree.IndexHint) + return v +} + +func (st *yySymType) indexHintScopeUnion() tree.IndexHintScope { + v, _ := st.union.(tree.IndexHintScope) + return v +} + +func (st *yySymType) indexHintTypeUnion() tree.IndexHintType { + v, _ := st.union.(tree.IndexHintType) + return v +} + +func (st *yySymType) indexOptionUnion() *tree.IndexOption { + v, _ := st.union.(*tree.IndexOption) + return v +} + +func (st *yySymType) indexTypeUnion() tree.IndexType { + v, _ := st.union.(tree.IndexType) + return v +} + +func (st *yySymType) indexVisibilityUnion() tree.VisibleType { + v, _ := st.union.(tree.VisibleType) + return v +} + +func (st *yySymType) insertUnion() *tree.Insert { + v, _ := st.union.(*tree.Insert) + return v +} + +func (st *yySymType) insertColumnsUnion() tree.InsertColumns { + v, _ := st.union.(tree.InsertColumns) + return v +} + +func (st *yySymType) insertPartitionUnion() *tree.InsertPartitionClause { + v, _ := st.union.(*tree.InsertPartitionClause) + return v +} + +func (st *yySymType) int64ValUnion() int64 { + v, _ := st.union.(int64) + return v +} + +func (st *yySymType) isolationLevelUnion() tree.IsolationLevelType { + v, _ := st.union.(tree.IsolationLevelType) + return v +} + +func (st *yySymType) joinCondUnion() tree.JoinCond { + v, _ := st.union.(tree.JoinCond) + return v +} + +func (st *yySymType) joinTableExprUnion() *tree.JoinTableExpr { + v, _ := st.union.(*tree.JoinTableExpr) + return v +} + +func (st *yySymType) jsonTableColumnUnion() *tree.JSONTableColumn { + v, _ := st.union.(*tree.JSONTableColumn) + return v +} + +func (st *yySymType) jsonTableColumnsUnion() []*tree.JSONTableColumn { + v, _ := st.union.([]*tree.JSONTableColumn) + return v +} + +func (st *yySymType) jsonTableResponseUnion() *tree.JSONTableResponse { + v, _ := st.union.(*tree.JSONTableResponse) + return v +} + +func (st *yySymType) kafkaTableOptionUnion() *tree.KafkaTableOption { + v, _ := st.union.(*tree.KafkaTableOption) + return v +} + +func (st *yySymType) kafkaTableOptionsUnion() tree.KafkaTableOptions { + v, _ := st.union.(tree.KafkaTableOptions) + return v +} + +func (st *yySymType) kafkaTableParamUnion() *tree.KafkaTableParam { + v, _ := st.union.(*tree.KafkaTableParam) + return v +} + +func (st *yySymType) keyPartUnion() *tree.KeyPart { + v, _ := st.union.(*tree.KeyPart) + return v +} + +func (st *yySymType) keyPartsUnion() []*tree.KeyPart { + v, _ := st.union.([]*tree.KeyPart) + return v +} + +func (st *yySymType) killOptionUnion() tree.KillOption { + v, _ := st.union.(tree.KillOption) + return v +} + +func (st *yySymType) lengthOptUnion() int32 { + v, _ := st.union.(int32) + return v +} + +func (st *yySymType) lengthScaleOptUnion() tree.LengthScaleOpt { + v, _ := st.union.(tree.LengthScaleOpt) + return v +} + +func (st *yySymType) limitUnion() *tree.Limit { + v, _ := st.union.(*tree.Limit) + return v +} + +func (st *yySymType) linesUnion() *tree.Lines { + v, _ := st.union.(*tree.Lines) + return v +} + +func (st *yySymType) loadColumnUnion() tree.LoadColumn { + v, _ := st.union.(tree.LoadColumn) + return v +} + +func (st *yySymType) loadColumnsUnion() []tree.LoadColumn { + v, _ := st.union.([]tree.LoadColumn) + return v +} + +func (st *yySymType) loadParamUnion() *tree.ExternParam { + v, _ := st.union.(*tree.ExternParam) + return v +} + +func (st *yySymType) matchTypeUnion() tree.MatchType { + v, _ := st.union.(tree.MatchType) + return v +} + +func (st *yySymType) maxValueOptionUnion() *tree.MaxValueOption { + v, _ := st.union.(*tree.MaxValueOption) + return v +} + +func (st *yySymType) mergeUnion() *tree.Merge { + v, _ := st.union.(*tree.Merge) + return v +} + +func (st *yySymType) mergeClauseUnion() *tree.MergeClause { + v, _ := st.union.(*tree.MergeClause) + return v +} + +func (st *yySymType) mergeClausesUnion() tree.MergeClauses { + v, _ := st.union.(tree.MergeClauses) + return v +} + +func (st *yySymType) minValueOptionUnion() *tree.MinValueOption { + v, _ := st.union.(*tree.MinValueOption) + return v +} + +func (st *yySymType) mongodbOptionUnion() *tree.MongoDBOption { + v, _ := st.union.(*tree.MongoDBOption) + return v +} + +func (st *yySymType) mongodbOptionsUnion() tree.MongoDBOptions { + v, _ := st.union.(tree.MongoDBOptions) + return v +} + +func (st *yySymType) mongodbTableParamUnion() *tree.MongoDBTableParam { + v, _ := st.union.(*tree.MongoDBTableParam) + return v +} + +func (st *yySymType) multiInsertTargetUnion() *tree.MultiInsertTarget { + v, _ := st.union.(*tree.MultiInsertTarget) + return v +} + +func (st *yySymType) multiInsertTargetsUnion() []*tree.MultiInsertTarget { + v, _ := st.union.([]*tree.MultiInsertTarget) + return v +} + +func (st *yySymType) multiInsertWhenUnion() *tree.MultiInsertWhen { + v, _ := st.union.(*tree.MultiInsertWhen) + return v +} + +func (st *yySymType) multiInsertWhensUnion() []*tree.MultiInsertWhen { + v, _ := st.union.([]*tree.MultiInsertWhen) + return v +} + +func (st *yySymType) nullsPositionUnion() tree.NullsPosition { + v, _ := st.union.(tree.NullsPosition) + return v +} + +func (st *yySymType) numValUnion() *tree.NumVal { + v, _ := st.union.(*tree.NumVal) + return v +} + +func (st *yySymType) objectTypeUnion() tree.ObjectType { + v, _ := st.union.(tree.ObjectType) + return v +} + +func (st *yySymType) orderUnion() *tree.Order { + v, _ := st.union.(*tree.Order) + return v +} + +func (st *yySymType) orderByUnion() tree.OrderBy { + v, _ := st.union.(tree.OrderBy) + return v +} + +func (st *yySymType) parenTableExprUnion() *tree.ParenTableExpr { + v, _ := st.union.(*tree.ParenTableExpr) + return v +} + +func (st *yySymType) partitionUnion() *tree.Partition { + v, _ := st.union.(*tree.Partition) + return v +} + +func (st *yySymType) partitionByUnion() *tree.PartitionBy { + v, _ := st.union.(*tree.PartitionBy) + return v +} + +func (st *yySymType) partitionOptionUnion() *tree.PartitionOption { + v, _ := st.union.(*tree.PartitionOption) + return v +} + +func (st *yySymType) partitionValuesUnion() tree.PartitionValues { + v, _ := st.union.(tree.PartitionValues) + return v +} + +func (st *yySymType) partitionsUnion() []*tree.Partition { + v, _ := st.union.([]*tree.Partition) + return v +} + +func (st *yySymType) pickKeysUnion() *tree.PickKeys { + v, _ := st.union.(*tree.PickKeys) + return v +} + +func (st *yySymType) privilegeUnion() *tree.Privilege { + v, _ := st.union.(*tree.Privilege) + return v +} + +func (st *yySymType) privilegeLevelUnion() *tree.PrivilegeLevel { + v, _ := st.union.(*tree.PrivilegeLevel) + return v +} + +func (st *yySymType) privilegeTypeUnion() tree.PrivilegeType { + v, _ := st.union.(tree.PrivilegeType) + return v +} + +func (st *yySymType) privilegesUnion() []*tree.Privilege { + v, _ := st.union.([]*tree.Privilege) + return v +} + +func (st *yySymType) procArgUnion() tree.ProcedureArg { + v, _ := st.union.(tree.ProcedureArg) + return v +} + +func (st *yySymType) procArgDeclUnion() *tree.ProcedureArgDecl { + v, _ := st.union.(*tree.ProcedureArgDecl) + return v +} + +func (st *yySymType) procArgTypeUnion() tree.InOutArgType { + v, _ := st.union.(tree.InOutArgType) + return v +} + +func (st *yySymType) procArgsUnion() tree.ProcedureArgs { + v, _ := st.union.(tree.ProcedureArgs) + return v +} + +func (st *yySymType) procNameUnion() *tree.ProcedureName { + v, _ := st.union.(*tree.ProcedureName) + return v +} + +func (st *yySymType) propertiesUnion() []tree.Property { + v, _ := st.union.([]tree.Property) + return v +} + +func (st *yySymType) propertyUnion() tree.Property { + v, _ := st.union.(tree.Property) + return v +} + +func (st *yySymType) pythonFunctionOptionsUnion() tree.PythonFunctionOptions { + v, _ := st.union.(tree.PythonFunctionOptions) + return v +} + +func (st *yySymType) rankOptionUnion() *tree.RankOption { + v, _ := st.union.(*tree.RankOption) + return v +} + +func (st *yySymType) referenceOnRecordUnion() *tree.ReferenceOnRecord { + v, _ := st.union.(*tree.ReferenceOnRecord) + return v +} + +func (st *yySymType) referenceOptionTypeUnion() tree.ReferenceOptionType { + v, _ := st.union.(tree.ReferenceOptionType) + return v +} + +func (st *yySymType) renameTableOptionUnion() *tree.AlterTable { + v, _ := st.union.(*tree.AlterTable) + return v +} + +func (st *yySymType) renameTableOptionsUnion() []*tree.AlterTable { + v, _ := st.union.([]*tree.AlterTable) + return v +} + +func (st *yySymType) replaceUnion() *tree.Replace { + v, _ := st.union.(*tree.Replace) + return v +} + +func (st *yySymType) resourceOptionUnion() tree.ResourceOption { + v, _ := st.union.(tree.ResourceOption) + return v +} + +func (st *yySymType) resourceOptionsUnion() []tree.ResourceOption { + v, _ := st.union.([]tree.ResourceOption) + return v +} + +func (st *yySymType) roleUnion() *tree.Role { + v, _ := st.union.(*tree.Role) + return v +} + +func (st *yySymType) rolesUnion() []*tree.Role { + v, _ := st.union.([]*tree.Role) + return v +} + +func (st *yySymType) rowFormatTypeUnion() tree.RowFormatType { + v, _ := st.union.(tree.RowFormatType) + return v +} + +func (st *yySymType) rowsExprsUnion() []tree.Exprs { + v, _ := st.union.([]tree.Exprs) + return v +} + +func (st *yySymType) selectUnion() *tree.Select { + v, _ := st.union.(*tree.Select) + return v +} + +func (st *yySymType) selectExprUnion() tree.SelectExpr { + v, _ := st.union.(tree.SelectExpr) + return v +} + +func (st *yySymType) selectExprsUnion() tree.SelectExprs { + v, _ := st.union.(tree.SelectExprs) + return v +} + +func (st *yySymType) selectIntoUnion() *tree.SelectInto { + v, _ := st.union.(*tree.SelectInto) + return v +} + +func (st *yySymType) selectLockInfoUnion() *tree.SelectLockInfo { + v, _ := st.union.(*tree.SelectLockInfo) + return v +} + +func (st *yySymType) selectOptionUnion() uint64 { + v, _ := st.union.(uint64) + return v +} + +func (st *yySymType) selectOptionsUnion() uint64 { + v, _ := st.union.(uint64) + return v +} + +func (st *yySymType) selectStatementUnion() tree.SelectStatement { + v, _ := st.union.(tree.SelectStatement) + return v +} + +func (st *yySymType) setDefaultRoleUnion() *tree.SetDefaultRole { + v, _ := st.union.(*tree.SetDefaultRole) + return v +} + +func (st *yySymType) setRoleUnion() *tree.SetRole { + v, _ := st.union.(*tree.SetRole) + return v +} + +func (st *yySymType) showTypeUnion() tree.ShowType { + v, _ := st.union.(tree.ShowType) + return v +} + +func (st *yySymType) snapshotObjectUnion() tree.ObjectInfo { + v, _ := st.union.(tree.ObjectInfo) + return v +} + +func (st *yySymType) sourceOptionalUnion() bool { + v, _ := st.union.(bool) + return v +} + +func (st *yySymType) sqlTaskScheduleUnion() *tree.SQLTaskSchedule { + v, _ := st.union.(*tree.SQLTaskSchedule) + return v +} + +func (st *yySymType) stageCommentUnion() tree.StageComment { + v, _ := st.union.(tree.StageComment) + return v +} + +func (st *yySymType) stageCredentialsUnion() tree.StageCredentials { + v, _ := st.union.(tree.StageCredentials) + return v +} + +func (st *yySymType) stageStatusUnion() tree.StageStatus { + v, _ := st.union.(tree.StageStatus) + return v +} + +func (st *yySymType) stageUrlUnion() tree.StageUrl { + v, _ := st.union.(tree.StageUrl) + return v +} + +func (st *yySymType) startWithOptionUnion() *tree.StartWithOption { + v, _ := st.union.(*tree.StartWithOption) + return v +} + +func (st *yySymType) statementUnion() tree.Statement { + v, _ := st.union.(tree.Statement) + return v +} + +func (st *yySymType) statementOptionUnion() tree.StatementOption { + v, _ := st.union.(tree.StatementOption) + return v +} + +func (st *yySymType) statementsUnion() []tree.Statement { + v, _ := st.union.([]tree.Statement) + return v +} + +func (st *yySymType) strsUnion() []string { + v, _ := st.union.([]string) + return v +} + +func (st *yySymType) subPartitionUnion() *tree.SubPartition { + v, _ := st.union.(*tree.SubPartition) + return v +} + +func (st *yySymType) subPartitionsUnion() []*tree.SubPartition { + v, _ := st.union.([]*tree.SubPartition) + return v +} + +func (st *yySymType) subqueryUnion() *tree.Subquery { + v, _ := st.union.(*tree.Subquery) + return v +} + +func (st *yySymType) subscriptionOptionUnion() *tree.SubscriptionOption { + v, _ := st.union.(*tree.SubscriptionOption) + return v +} + +func (st *yySymType) tableDefUnion() tree.TableDef { + v, _ := st.union.(tree.TableDef) + return v +} + +func (st *yySymType) tableDefsUnion() tree.TableDefs { + v, _ := st.union.(tree.TableDefs) + return v +} + +func (st *yySymType) tableExprUnion() tree.TableExpr { + v, _ := st.union.(tree.TableExpr) + return v +} + +func (st *yySymType) tableExprsUnion() tree.TableExprs { + v, _ := st.union.(tree.TableExprs) + return v +} + +func (st *yySymType) tableLockUnion() tree.TableLock { + v, _ := st.union.(tree.TableLock) + return v +} + +func (st *yySymType) tableLockTypeUnion() tree.TableLockType { + v, _ := st.union.(tree.TableLockType) + return v +} + +func (st *yySymType) tableLocksUnion() []tree.TableLock { + v, _ := st.union.([]tree.TableLock) + return v +} + +func (st *yySymType) tableNameUnion() *tree.TableName { + v, _ := st.union.(*tree.TableName) + return v +} + +func (st *yySymType) tableNamesUnion() tree.TableNames { + v, _ := st.union.(tree.TableNames) + return v +} + +func (st *yySymType) tableOptionUnion() tree.TableOption { + v, _ := st.union.(tree.TableOption) + return v +} + +func (st *yySymType) tableOptionsUnion() []tree.TableOption { + v, _ := st.union.([]tree.TableOption) + return v +} + +func (st *yySymType) tailParamUnion() *tree.TailParameter { + v, _ := st.union.(*tree.TailParameter) + return v +} + +func (st *yySymType) timeFillUnion() *tree.Fill { + v, _ := st.union.(*tree.Fill) + return v +} + +func (st *yySymType) timeIntervalUnion() *tree.Interval { + v, _ := st.union.(*tree.Interval) + return v +} + +func (st *yySymType) timeSlidingUnion() *tree.Sliding { + v, _ := st.union.(*tree.Sliding) + return v +} + +func (st *yySymType) timeWindowUnion() *tree.TimeWindow { + v, _ := st.union.(*tree.TimeWindow) + return v +} + +func (st *yySymType) tlsOptionUnion() tree.TlsOption { + v, _ := st.union.(tree.TlsOption) + return v +} + +func (st *yySymType) tlsOptionsUnion() []tree.TlsOption { + v, _ := st.union.([]tree.TlsOption) + return v +} + +func (st *yySymType) toAccountOptUnion() *tree.ToAccountOpt { + v, _ := st.union.(*tree.ToAccountOpt) + return v +} + +func (st *yySymType) transactionCharacteristicUnion() *tree.TransactionCharacteristic { + v, _ := st.union.(*tree.TransactionCharacteristic) + return v +} + +func (st *yySymType) transactionCharacteristicListUnion() []*tree.TransactionCharacteristic { + v, _ := st.union.([]*tree.TransactionCharacteristic) + return v +} + +func (st *yySymType) tupleUnion() *tree.Tuple { + v, _ := st.union.(*tree.Tuple) + return v +} + +func (st *yySymType) uint64ValUnion() uint64 { + v, _ := st.union.(uint64) + return v +} + +func (st *yySymType) unionTypeRecordUnion() *tree.UnionTypeRecord { + v, _ := st.union.(*tree.UnionTypeRecord) + return v +} + +func (st *yySymType) unresolveNamesUnion() []*tree.UnresolvedName { + v, _ := st.union.([]*tree.UnresolvedName) + return v +} + +func (st *yySymType) unresolvedNameUnion() *tree.UnresolvedName { + v, _ := st.union.(*tree.UnresolvedName) + return v +} + +func (st *yySymType) unresolvedObjectNameUnion() *tree.UnresolvedObjectName { + v, _ := st.union.(*tree.UnresolvedObjectName) + return v +} + +func (st *yySymType) unsignedOptUnion() bool { + v, _ := st.union.(bool) + return v +} + +func (st *yySymType) updateExprUnion() *tree.UpdateExpr { + v, _ := st.union.(*tree.UpdateExpr) + return v +} + +func (st *yySymType) updateExprsUnion() tree.UpdateExprs { + v, _ := st.union.(tree.UpdateExprs) + return v +} + +func (st *yySymType) upgrade_targetUnion() *tree.Target { + v, _ := st.union.(*tree.Target) + return v +} + +func (st *yySymType) userUnion() *tree.User { + v, _ := st.union.(*tree.User) + return v +} + +func (st *yySymType) userIdentifiedUnion() *tree.AccountIdentified { + v, _ := st.union.(*tree.AccountIdentified) + return v +} + +func (st *yySymType) userMiscOptionUnion() tree.UserMiscOption { + v, _ := st.union.(tree.UserMiscOption) + return v +} + +func (st *yySymType) userMiscOptionsUnion() []tree.UserMiscOption { + v, _ := st.union.([]tree.UserMiscOption) + return v +} + +func (st *yySymType) usernameRecordUnion() *tree.UsernameRecord { + v, _ := st.union.(*tree.UsernameRecord) + return v +} + +func (st *yySymType) usersUnion() []*tree.User { + v, _ := st.union.([]*tree.User) + return v +} + +func (st *yySymType) valuesUnion() tree.Values { + v, _ := st.union.(tree.Values) + return v +} + +func (st *yySymType) varAssignmentExprUnion() *tree.VarAssignmentExpr { + v, _ := st.union.(*tree.VarAssignmentExpr) + return v +} + +func (st *yySymType) varAssignmentExprsUnion() []*tree.VarAssignmentExpr { + v, _ := st.union.([]*tree.VarAssignmentExpr) + return v +} + +func (st *yySymType) varExprUnion() *tree.VarExpr { + v, _ := st.union.(*tree.VarExpr) + return v +} + +func (st *yySymType) varExprsUnion() []*tree.VarExpr { + v, _ := st.union.([]*tree.VarExpr) + return v +} + +func (st *yySymType) whenClauseUnion() *tree.When { + v, _ := st.union.(*tree.When) + return v +} + +func (st *yySymType) whenClause2Union() *tree.WhenStmt { + v, _ := st.union.(*tree.WhenStmt) + return v +} + +func (st *yySymType) whenClauseListUnion() []*tree.When { + v, _ := st.union.([]*tree.When) + return v +} + +func (st *yySymType) whenClauseList2Union() []*tree.WhenStmt { + v, _ := st.union.([]*tree.WhenStmt) + return v +} + +func (st *yySymType) whereUnion() *tree.Where { + v, _ := st.union.(*tree.Where) + return v +} + +func (st *yySymType) windowDefinitionUnion() *tree.WindowDefinition { + v, _ := st.union.(*tree.WindowDefinition) + return v +} + +func (st *yySymType) windowDefinitionsUnion() tree.WindowDefinitions { + v, _ := st.union.(tree.WindowDefinitions) + return v +} + +func (st *yySymType) windowSpecUnion() *tree.WindowSpec { + v, _ := st.union.(*tree.WindowSpec) + return v +} + +func (st *yySymType) withClauseUnion() *tree.With { + v, _ := st.union.(*tree.With) + return v +} + +func (st *yySymType) zeroFillOptUnion() bool { + v, _ := st.union.(bool) + return v +} + +var yyR1 = [...]int{ + 0, 759, 763, 12, 12, 9, 13, 13, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 8, + 8, 8, 8, 8, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 168, + 168, 470, 470, 471, 471, 170, 466, 466, 465, 465, + 171, 172, 173, 736, 736, 737, 737, 735, 735, 174, + 175, 214, 734, 734, 734, 734, 734, 734, 734, 734, + 216, 216, 216, 216, 216, 216, 216, 599, 169, 169, + 169, 169, 169, 169, 169, 297, 297, 298, 298, 184, + 184, 185, 185, 186, 186, 220, 220, 220, 220, 220, + 220, 220, 159, 743, 743, 743, 744, 744, 156, 197, + 196, 199, 199, 198, 198, 195, 195, 191, 194, 194, + 193, 193, 192, 187, 189, 189, 188, 190, 190, 157, + 140, 142, 142, 141, 158, 683, 683, 682, 682, 681, + 681, 626, 626, 627, 627, 457, 457, 457, 680, 680, + 680, 679, 679, 678, 678, 676, 676, 677, 677, 674, + 674, 675, 673, 672, 672, 672, 668, 668, 668, 664, + 664, 666, 665, 665, 667, 659, 659, 662, 662, 660, + 660, 660, 660, 663, 658, 658, 658, 657, 657, 139, + 139, 139, 560, 560, 138, 138, 575, 575, 575, 575, + 575, 573, 573, 573, 573, 573, 573, 572, 572, 571, + 571, 576, 576, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, + 574, 574, 574, 574, 127, 127, 127, 127, 127, 127, + 127, 134, 132, 132, 132, 133, 749, 749, 748, 748, + 750, 750, 750, 750, 751, 751, 130, 130, 130, 131, + 570, 570, 570, 128, 129, 129, 559, 559, 565, 565, + 564, 564, 564, 564, 564, 564, 564, 564, 564, 564, + 564, 564, 564, 569, 569, 569, 567, 567, 566, 566, + 568, 568, 117, 117, 117, 117, 117, 117, 121, 122, + 123, 123, 123, 123, 120, 119, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 118, 118, 118, 118, 118, + 118, 103, 103, 103, 103, 103, 102, 102, 104, 104, + 104, 555, 555, 554, 135, 135, 136, 746, 746, 745, + 747, 747, 747, 747, 137, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 146, + 146, 146, 149, 149, 149, 148, 150, 126, 126, 126, + 126, 126, 126, 124, 124, 124, 124, 124, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 125, 125, 709, 709, 709, 709, + 709, 710, 710, 484, 485, 764, 487, 483, 483, 483, + 705, 705, 706, 707, 708, 708, 708, 708, 143, 310, + 310, 308, 308, 309, 309, 144, 311, 311, 311, 145, + 312, 312, 23, 307, 307, 598, 598, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 109, 109, 110, 110, 110, 110, 22, 101, + 106, 106, 106, 108, 421, 421, 422, 420, 420, 420, + 420, 420, 415, 415, 423, 423, 219, 59, 59, 59, + 59, 59, 59, 107, 107, 107, 107, 424, 424, 424, + 430, 430, 431, 431, 416, 416, 416, 416, 416, 416, + 416, 416, 416, 416, 416, 416, 416, 416, 416, 416, + 416, 416, 416, 416, 416, 416, 400, 400, 400, 395, + 395, 395, 395, 396, 396, 397, 397, 398, 398, 398, + 398, 399, 399, 476, 476, 425, 425, 425, 427, 427, + 426, 419, 417, 417, 417, 417, 417, 417, 417, 417, + 418, 418, 418, 418, 428, 428, 429, 429, 99, 111, + 111, 527, 527, 524, 524, 524, 524, 105, 105, 105, + 105, 722, 722, 100, 100, 100, 733, 733, 630, 630, + 498, 498, 497, 497, 497, 497, 497, 497, 497, 497, + 497, 497, 497, 497, 497, 497, 497, 497, 635, 636, + 494, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 60, 61, 165, 165, 167, + 167, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 77, 231, 96, 97, 98, 75, 69, 72, 73, + 218, 221, 221, 221, 221, 68, 68, 68, 68, 544, + 544, 67, 765, 765, 469, 469, 85, 84, 71, 86, + 87, 88, 89, 90, 91, 66, 83, 83, 83, 83, + 83, 83, 83, 83, 94, 653, 653, 767, 767, 767, + 92, 93, 629, 629, 629, 82, 82, 81, 81, 80, + 79, 78, 78, 65, 65, 64, 64, 70, 203, 205, + 74, 204, 204, 206, 206, 491, 491, 491, 493, 493, + 489, 766, 766, 594, 594, 492, 492, 63, 63, 63, + 63, 95, 490, 490, 468, 488, 488, 488, 21, 21, + 19, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 58, 35, 36, 34, 37, 39, 552, 552, 549, + 38, 29, 28, 31, 27, 27, 30, 32, 33, 33, + 17, 17, 17, 17, 24, 24, 25, 267, 267, 343, + 343, 716, 716, 712, 712, 713, 713, 713, 714, 714, + 715, 715, 768, 768, 768, 151, 647, 647, 647, 647, + 647, 647, 15, 15, 15, 15, 641, 641, 641, 646, + 646, 645, 644, 644, 643, 643, 642, 642, 642, 642, + 16, 16, 16, 16, 262, 262, 18, 18, 112, 112, + 113, 113, 114, 114, 114, 114, 114, 114, 116, 115, + 115, 296, 296, 640, 640, 640, 640, 640, 640, 557, + 557, 556, 556, 693, 693, 693, 694, 301, 301, 289, + 289, 289, 300, 300, 300, 300, 648, 648, 515, 695, + 695, 656, 656, 655, 655, 654, 654, 294, 294, 302, + 302, 302, 303, 303, 295, 295, 271, 271, 179, 179, + 179, 670, 670, 671, 671, 661, 661, 661, 661, 669, + 669, 625, 625, 405, 405, 459, 459, 460, 460, 249, + 245, 245, 245, 246, 246, 247, 247, 247, 247, 247, + 247, 247, 247, 247, 247, 247, 752, 752, 753, 754, + 755, 755, 756, 756, 757, 757, 757, 758, 758, 758, + 758, 758, 702, 702, 704, 704, 703, 293, 293, 284, + 284, 286, 286, 286, 285, 285, 285, 287, 288, 288, + 282, 282, 283, 283, 281, 280, 280, 279, 277, 277, + 277, 278, 278, 278, 306, 306, 306, 306, 251, 251, + 251, 251, 250, 250, 250, 250, 250, 250, 250, 250, + 250, 253, 254, 254, 256, 255, 255, 255, 255, 257, + 258, 258, 260, 259, 259, 259, 259, 439, 439, 439, + 439, 439, 439, 439, 439, 439, 439, 439, 439, 252, + 264, 264, 265, 265, 266, 266, 266, 266, 266, 266, + 266, 266, 266, 266, 436, 436, 437, 437, 437, 437, + 437, 177, 177, 634, 634, 435, 435, 261, 261, 263, + 263, 263, 263, 434, 434, 433, 276, 276, 275, 275, + 274, 274, 274, 268, 268, 268, 268, 268, 268, 270, + 445, 445, 444, 444, 443, 443, 443, 443, 443, 443, + 446, 447, 447, 447, 269, 269, 155, 176, 176, 178, + 291, 290, 442, 441, 441, 441, 441, 305, 305, 304, + 304, 292, 292, 273, 273, 273, 273, 440, 272, 272, + 3, 3, 1, 1, 1, 1, 7, 7, 4, 4, + 4, 2, 2, 2, 5, 5, 6, 6, 438, 742, + 742, 741, 741, 740, 738, 738, 738, 739, 739, 739, + 739, 685, 685, 685, 685, 685, 477, 477, 477, 482, + 482, 480, 480, 480, 480, 480, 486, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 52, 53, 57, 160, 160, 163, 163, 161, 161, 162, + 162, 166, 166, 164, 164, 49, 322, 323, 50, 327, + 327, 328, 328, 329, 329, 330, 331, 332, 332, 332, + 332, 534, 534, 48, 313, 313, 314, 314, 315, 315, + 316, 317, 317, 317, 321, 318, 319, 319, 761, 761, + 760, 326, 326, 326, 326, 326, 325, 325, 324, 324, + 47, 47, 40, 40, 224, 224, 225, 225, 225, 227, + 227, 401, 401, 401, 226, 226, 228, 228, 228, 717, + 719, 719, 721, 720, 720, 720, 723, 723, 723, 723, + 723, 724, 724, 724, 724, 725, 725, 41, 200, 200, + 200, 237, 237, 210, 728, 728, 728, 727, 727, 600, + 600, 729, 729, 730, 730, 463, 463, 464, 464, 222, + 223, 223, 212, 202, 236, 236, 236, 236, 236, 238, + 238, 345, 345, 201, 207, 208, 209, 211, 213, 215, + 215, 217, 718, 726, 726, 726, 553, 553, 550, 551, + 551, 548, 547, 547, 547, 732, 732, 731, 731, 731, + 478, 478, 42, 543, 543, 545, 546, 546, 546, 546, + 546, 546, 546, 546, 535, 535, 535, 535, 535, 46, + 539, 539, 541, 541, 542, 542, 540, 540, 540, 540, + 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, + 540, 540, 540, 540, 540, 540, 540, 540, 540, 540, + 540, 540, 540, 540, 540, 540, 540, 540, 536, 536, + 538, 538, 532, 532, 533, 533, 533, 533, 533, 533, + 533, 533, 533, 45, 45, 45, 235, 235, 531, 531, + 528, 528, 528, 320, 320, 525, 525, 526, 526, 523, + 523, 523, 529, 529, 54, 55, 56, 530, 530, 239, + 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, + 299, 299, 244, 244, 244, 244, 244, 244, 242, 242, + 242, 242, 243, 243, 240, 240, 241, 241, 229, 229, + 229, 230, 230, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 181, 180, 180, 180, 180, 180, 183, 183, + 462, 462, 461, 461, 182, 402, 402, 51, 356, 356, + 617, 617, 612, 612, 612, 612, 612, 632, 632, 632, + 613, 613, 613, 614, 614, 614, 616, 616, 616, 615, + 615, 615, 615, 615, 631, 631, 633, 633, 633, 577, + 577, 578, 578, 578, 581, 581, 603, 603, 604, 604, + 602, 602, 610, 610, 609, 609, 608, 608, 606, 606, + 607, 605, 605, 605, 605, 597, 597, 596, 596, 579, + 579, 579, 579, 579, 580, 580, 580, 595, 595, 601, + 601, 365, 366, 366, 367, 367, 368, 232, 232, 233, + 233, 369, 370, 370, 371, 371, 372, 373, 373, 374, + 374, 375, 376, 376, 377, 377, 378, 381, 382, 383, + 383, 384, 384, 385, 389, 389, 386, 386, 387, 387, + 388, 379, 379, 380, 380, 363, 363, 364, 364, 364, + 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, + 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, + 432, 432, 432, 432, 432, 432, 432, 432, 432, 432, + 432, 432, 432, 432, 432, 432, 691, 691, 692, 391, + 391, 403, 403, 403, 403, 403, 403, 390, 390, 392, + 392, 344, 344, 342, 342, 334, 334, 334, 334, 334, + 334, 234, 234, 234, 333, 333, 333, 333, 333, 333, + 335, 335, 336, 336, 337, 337, 337, 341, 341, 340, + 340, 340, 340, 340, 338, 338, 339, 339, 339, 339, + 339, 339, 562, 562, 688, 688, 689, 689, 684, 684, + 684, 687, 687, 687, 687, 687, 687, 687, 687, 687, + 687, 687, 690, 690, 690, 686, 686, 346, 456, 456, + 456, 479, 479, 479, 479, 481, 455, 455, 455, 362, + 362, 361, 361, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, 359, 359, + 359, 359, 359, 359, 359, 359, 359, 359, 359, 563, + 563, 563, 561, 561, 561, 495, 495, 496, 496, 414, + 413, 413, 413, 413, 413, 411, 412, 410, 410, 410, + 410, 410, 407, 407, 406, 406, 406, 408, 408, 408, + 408, 408, 408, 537, 537, 404, 404, 394, 394, 394, + 393, 393, 393, 611, 502, 502, 502, 502, 502, 502, + 502, 502, 502, 502, 502, 502, 502, 502, 502, 504, + 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, + 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, + 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, + 409, 409, 409, 453, 453, 453, 453, 453, 453, 453, + 453, 453, 453, 453, 453, 453, 453, 453, 454, 454, + 454, 454, 454, 454, 454, 454, 505, 505, 511, 511, + 701, 701, 700, 347, 347, 347, 348, 348, 348, 348, + 348, 348, 348, 348, 348, 348, 348, 357, 357, 357, + 591, 591, 591, 591, 591, 592, 592, 592, 592, 592, + 593, 593, 593, 589, 589, 590, 590, 516, 517, 517, + 638, 638, 639, 639, 582, 582, 583, 583, 584, 588, + 588, 586, 586, 587, 587, 585, 452, 452, 452, 452, + 452, 452, 452, 452, 452, 452, 452, 452, 452, 452, + 452, 452, 452, 452, 452, 452, 452, 452, 452, 452, + 452, 452, 452, 452, 652, 652, 652, 449, 449, 449, + 449, 449, 449, 449, 449, 449, 449, 449, 449, 449, + 449, 449, 449, 449, 449, 711, 711, 711, 696, 696, + 696, 697, 697, 697, 697, 697, 697, 697, 697, 697, + 697, 697, 697, 698, 698, 698, 698, 698, 698, 698, + 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, + 699, 699, 699, 699, 451, 451, 451, 451, 451, 450, + 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, + 450, 450, 450, 450, 450, 450, 450, 518, 518, 519, + 519, 649, 649, 649, 649, 649, 649, 650, 650, 651, + 651, 651, 651, 637, 637, 637, 637, 637, 637, 637, + 637, 637, 637, 637, 637, 637, 637, 637, 637, 637, + 637, 637, 637, 637, 637, 637, 637, 637, 637, 637, + 637, 637, 637, 637, 637, 503, 448, 448, 448, 520, + 512, 512, 513, 513, 514, 514, 506, 506, 506, 506, + 506, 507, 507, 509, 509, 509, 509, 509, 509, 509, + 509, 509, 509, 509, 509, 509, 509, 509, 501, 501, + 501, 501, 501, 501, 501, 501, 501, 501, 501, 501, + 501, 501, 501, 501, 501, 508, 508, 771, 771, 510, + 510, 522, 522, 522, 521, 521, 521, 521, 521, 521, + 521, 360, 360, 360, 360, 500, 500, 500, 499, 499, + 499, 499, 499, 499, 499, 499, 499, 499, 499, 499, + 349, 349, 349, 349, 349, 353, 353, 355, 355, 355, + 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, + 355, 354, 354, 354, 354, 354, 354, 352, 352, 352, + 352, 352, 350, 350, 350, 350, 350, 350, 350, 350, + 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, + 350, 350, 350, 350, 350, 350, 350, 152, 153, 248, + 248, 154, 154, 351, 358, 358, 358, 358, 358, 358, + 358, 358, 358, 358, 358, 358, 358, 358, 358, 358, + 358, 358, 458, 458, 618, 618, 621, 621, 619, 619, + 620, 622, 622, 622, 623, 623, 623, 624, 624, 624, + 628, 628, 467, 467, 467, 475, 475, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 474, 474, 474, 474, 474, 474, 474, 474, + 474, 474, 473, 473, 473, 473, 473, 473, 473, 473, + 473, 472, 472, 472, 472, 472, 472, 472, 472, 472, + 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, + 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, + 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, + 472, 472, 472, 472, 472, 472, 472, 472, 472, 472, + 472, 472, 472, 472, 472, 472, 769, 769, 770, 770, + 415, 415, 762, 762, +} + +var yyR2 = [...]int{ + 0, 1, 1, 1, 3, 3, 1, 3, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, + 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 8, + 8, 0, 2, 0, 2, 12, 1, 3, 0, 3, + 3, 3, 5, 0, 1, 1, 1, 1, 2, 4, + 5, 6, 1, 2, 1, 2, 3, 7, 6, 5, + 10, 10, 11, 11, 12, 8, 13, 1, 5, 6, + 8, 5, 3, 5, 8, 1, 3, 3, 5, 5, + 5, 1, 1, 0, 3, 5, 7, 9, 9, 11, + 8, 6, 4, 0, 1, 1, 0, 1, 5, 2, + 2, 6, 9, 6, 9, 4, 7, 8, 0, 1, + 1, 2, 4, 6, 1, 2, 4, 0, 2, 10, + 11, 5, 7, 5, 2, 0, 2, 1, 3, 3, + 3, 0, 2, 0, 2, 1, 3, 5, 0, 2, + 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, + 1, 1, 1, 0, 3, 3, 0, 3, 3, 0, + 1, 3, 0, 1, 3, 0, 2, 1, 2, 3, + 4, 3, 3, 1, 0, 1, 1, 0, 1, 8, + 5, 7, 0, 3, 8, 5, 1, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, + 4, 1, 3, 1, 2, 2, 2, 2, 2, 2, + 2, 1, 2, 2, 2, 2, 1, 1, 2, 2, + 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, + 1, 2, 2, 1, 2, 1, 1, 2, 2, 1, + 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6, 3, 4, 4, 5, 1, 3, 3, 1, + 2, 2, 2, 1, 2, 2, 3, 4, 4, 6, + 1, 1, 1, 2, 4, 6, 1, 4, 1, 3, + 3, 4, 4, 4, 4, 3, 3, 2, 4, 4, + 2, 2, 2, 1, 1, 1, 1, 1, 1, 3, + 1, 3, 1, 1, 1, 1, 1, 1, 2, 3, + 3, 4, 5, 4, 2, 2, 0, 1, 4, 2, + 4, 1, 5, 3, 2, 1, 2, 2, 4, 4, + 5, 2, 1, 3, 4, 4, 1, 2, 10, 8, + 10, 1, 3, 3, 1, 1, 3, 1, 3, 2, + 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 1, 1, 1, 1, 4, + 4, 4, 3, 2, 4, 3, 3, 1, 1, 1, + 1, 1, 1, 2, 3, 4, 7, 1, 5, 5, + 6, 6, 6, 6, 2, 3, 3, 4, 3, 4, + 4, 5, 3, 4, 4, 5, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 2, 1, 1, 1, 1, 1, 4, 0, + 1, 1, 3, 1, 4, 4, 0, 1, 2, 4, + 0, 3, 4, 1, 1, 0, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 6, 8, 6, 8, 5, 5, 10, 7, + 4, 4, 4, 3, 1, 3, 3, 5, 5, 5, + 5, 5, 1, 3, 1, 6, 7, 4, 4, 7, + 8, 6, 6, 8, 6, 11, 10, 3, 3, 3, + 1, 1, 1, 3, 2, 4, 5, 5, 6, 5, + 5, 3, 2, 2, 1, 3, 4, 3, 7, 5, + 8, 2, 2, 1, 3, 2, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 0, 1, 2, 1, 3, + 2, 1, 2, 2, 1, 2, 3, 2, 2, 2, + 3, 5, 3, 3, 1, 1, 3, 3, 7, 4, + 3, 1, 2, 4, 5, 3, 4, 7, 7, 8, + 8, 0, 4, 7, 6, 6, 0, 3, 0, 2, + 0, 1, 1, 1, 1, 4, 2, 2, 3, 3, + 4, 5, 3, 4, 4, 2, 2, 2, 3, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 5, 0, 2, 0, + 2, 5, 7, 8, 5, 5, 7, 9, 8, 8, + 11, 5, 1, 3, 3, 3, 5, 4, 3, 3, + 3, 4, 5, 6, 5, 2, 5, 6, 5, 0, + 2, 7, 0, 1, 0, 1, 5, 5, 3, 3, + 2, 4, 4, 4, 4, 4, 1, 1, 1, 3, + 3, 1, 1, 1, 6, 0, 1, 1, 1, 1, + 5, 5, 0, 1, 1, 3, 6, 3, 6, 3, + 4, 7, 7, 5, 4, 7, 8, 3, 3, 4, + 2, 3, 4, 4, 3, 0, 2, 2, 0, 2, + 2, 1, 1, 1, 1, 0, 1, 5, 5, 6, + 4, 3, 1, 3, 1, 1, 3, 5, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 5, 5, 4, 4, 4, 1, 3, 1, + 4, 6, 6, 5, 4, 4, 3, 7, 3, 5, + 1, 1, 2, 2, 12, 9, 10, 1, 3, 2, + 4, 0, 2, 0, 1, 1, 1, 1, 0, 1, + 0, 1, 0, 1, 1, 6, 2, 1, 5, 4, + 4, 2, 1, 2, 1, 2, 4, 5, 5, 1, + 2, 4, 0, 2, 1, 2, 2, 6, 5, 9, + 6, 6, 6, 7, 0, 2, 1, 2, 8, 10, + 1, 2, 7, 5, 13, 13, 10, 10, 1, 0, + 2, 1, 3, 2, 1, 5, 4, 4, 2, 0, + 1, 5, 4, 0, 1, 3, 3, 1, 3, 1, + 3, 5, 1, 3, 3, 5, 1, 3, 4, 0, + 1, 0, 1, 1, 3, 1, 1, 0, 4, 0, + 4, 4, 3, 5, 1, 3, 2, 1, 0, 10, + 2, 0, 2, 0, 2, 0, 4, 7, 4, 0, + 2, 0, 2, 0, 2, 0, 4, 1, 3, 3, + 1, 1, 1, 1, 4, 7, 4, 6, 4, 5, + 6, 8, 4, 6, 5, 6, 0, 1, 4, 8, + 0, 6, 0, 4, 0, 4, 6, 1, 1, 1, + 1, 1, 2, 3, 1, 3, 6, 0, 3, 0, + 1, 0, 1, 1, 2, 4, 4, 2, 0, 5, + 0, 1, 0, 5, 3, 1, 3, 3, 0, 1, + 1, 0, 2, 2, 0, 2, 2, 4, 3, 3, + 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, + 3, 5, 1, 3, 2, 1, 1, 1, 2, 5, + 1, 3, 2, 1, 1, 1, 1, 1, 2, 2, + 1, 2, 2, 1, 2, 2, 1, 2, 2, 9, + 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 2, 0, 4, 7, 6, + 6, 3, 5, 0, 2, 0, 2, 1, 3, 1, + 2, 3, 5, 0, 1, 2, 1, 3, 1, 4, + 1, 1, 1, 4, 4, 4, 3, 4, 5, 3, + 2, 2, 2, 2, 2, 3, 2, 3, 2, 3, + 2, 2, 3, 4, 0, 2, 4, 1, 3, 4, + 1, 3, 1, 1, 2, 2, 3, 0, 1, 2, + 4, 1, 3, 1, 3, 2, 3, 1, 10, 4, + 1, 3, 3, 5, 5, 7, 0, 1, 1, 1, + 2, 0, 4, 4, 0, 3, 0, 3, 3, 0, + 1, 1, 2, 5, 2, 2, 2, 0, 2, 3, + 3, 0, 1, 3, 1, 3, 0, 1, 2, 1, + 1, 0, 1, 2, 1, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 6, 6, 10, 0, 3, 0, 2, 0, 4, 1, + 1, 0, 2, 0, 2, 7, 1, 1, 9, 1, + 3, 0, 1, 1, 3, 1, 3, 0, 1, 1, + 1, 0, 2, 15, 1, 3, 0, 1, 1, 3, + 1, 1, 2, 4, 1, 1, 1, 1, 0, 1, + 2, 0, 2, 1, 3, 3, 1, 1, 4, 5, + 9, 9, 7, 8, 1, 2, 3, 3, 3, 0, + 4, 1, 1, 1, 1, 1, 0, 1, 1, 1, + 1, 1, 4, 1, 1, 1, 3, 3, 4, 3, + 3, 0, 1, 1, 1, 0, 2, 7, 8, 10, + 8, 2, 2, 8, 0, 3, 3, 0, 3, 0, + 3, 0, 3, 0, 5, 1, 3, 0, 3, 3, + 0, 2, 9, 8, 0, 2, 2, 3, 3, 0, + 2, 0, 2, 4, 5, 4, 4, 4, 6, 4, + 8, 5, 1, 0, 2, 2, 1, 3, 2, 1, + 3, 2, 1, 3, 2, 0, 1, 3, 4, 3, + 1, 1, 4, 1, 3, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 11, + 0, 2, 0, 2, 1, 1, 3, 3, 2, 2, + 3, 1, 1, 3, 3, 3, 3, 3, 3, 4, + 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 3, 3, 3, 3, 3, 1, 3, + 3, 4, 0, 1, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 6, 8, 10, 0, 4, 1, 1, + 0, 3, 3, 0, 1, 0, 1, 1, 2, 4, + 4, 4, 0, 1, 4, 4, 4, 0, 2, 8, + 9, 5, 5, 8, 7, 8, 12, 12, 13, 13, + 0, 4, 0, 3, 3, 3, 2, 2, 0, 3, + 3, 3, 4, 4, 0, 3, 0, 2, 0, 1, + 1, 1, 1, 11, 9, 9, 9, 9, 9, 9, + 6, 11, 6, 9, 7, 10, 8, 11, 7, 6, + 9, 11, 2, 2, 9, 4, 5, 3, 0, 4, + 1, 3, 0, 3, 6, 0, 2, 10, 0, 2, + 0, 2, 0, 3, 2, 4, 3, 0, 2, 1, + 0, 2, 3, 0, 2, 3, 0, 2, 1, 0, + 3, 2, 4, 3, 0, 1, 0, 1, 1, 0, + 6, 0, 3, 5, 0, 4, 0, 3, 1, 3, + 4, 5, 0, 3, 1, 3, 2, 3, 1, 2, + 1, 0, 4, 6, 5, 0, 2, 0, 2, 4, + 5, 4, 5, 1, 5, 6, 5, 0, 3, 0, + 1, 4, 0, 4, 1, 3, 3, 1, 1, 1, + 1, 4, 0, 4, 1, 3, 3, 1, 1, 1, + 1, 4, 0, 4, 1, 3, 3, 4, 4, 0, + 4, 1, 3, 3, 1, 1, 0, 4, 1, 3, + 3, 1, 1, 1, 1, 0, 1, 1, 3, 2, + 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, + 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 1, 5, 4, 1, 3, 3, 2, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 3, 3, 5, 0, 3, 3, 6, 5, + 3, 1, 1, 1, 0, 5, 5, 5, 5, 6, + 0, 1, 1, 3, 1, 1, 1, 1, 1, 7, + 9, 7, 7, 9, 2, 1, 7, 9, 7, 9, + 8, 5, 0, 1, 0, 1, 1, 1, 1, 3, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 1, 3, 1, 3, + 5, 1, 1, 1, 1, 1, 1, 3, 5, 0, + 1, 1, 2, 1, 2, 2, 2, 1, 1, 2, + 2, 2, 2, 2, 3, 3, 2, 2, 1, 5, + 6, 4, 2, 1, 1, 1, 5, 7, 5, 0, + 1, 1, 1, 2, 2, 0, 1, 1, 2, 5, + 0, 1, 1, 2, 2, 3, 3, 1, 1, 2, + 2, 2, 0, 1, 2, 2, 2, 0, 4, 7, + 3, 3, 3, 0, 3, 0, 3, 1, 1, 1, + 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, + 1, 1, 3, 3, 5, 2, 2, 2, 2, 2, + 4, 1, 1, 2, 5, 6, 10, 8, 6, 3, + 6, 6, 1, 1, 1, 1, 1, 1, 3, 9, + 1, 1, 1, 4, 4, 4, 4, 5, 4, 6, + 8, 10, 6, 8, 10, 6, 6, 9, 7, 9, + 7, 7, 7, 9, 7, 7, 0, 2, 0, 1, + 1, 2, 4, 1, 2, 2, 1, 1, 2, 2, + 5, 1, 2, 2, 2, 2, 2, 0, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 2, 5, 0, 1, 3, 0, 1, + 0, 2, 0, 2, 0, 1, 2, 4, 4, 0, + 1, 0, 2, 1, 3, 5, 9, 6, 6, 8, + 6, 6, 5, 5, 6, 6, 6, 6, 6, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 9, 6, + 6, 6, 6, 8, 1, 1, 1, 4, 6, 4, + 6, 8, 6, 6, 4, 6, 4, 4, 4, 3, + 4, 6, 6, 7, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 8, 8, 6, 4, + 2, 3, 2, 4, 2, 2, 4, 6, 2, 2, + 4, 6, 4, 2, 4, 4, 4, 0, 1, 2, + 3, 1, 1, 1, 1, 1, 1, 0, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 0, 1, 1, 3, + 0, 1, 1, 3, 1, 3, 3, 3, 3, 2, + 1, 1, 1, 3, 4, 4, 3, 4, 4, 3, + 4, 4, 3, 4, 4, 3, 4, 1, 3, 4, + 4, 6, 4, 5, 5, 4, 5, 5, 3, 4, + 4, 5, 6, 6, 1, 0, 2, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, + 3, 1, 1, 1, 4, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 3, 2, 2, 2, 2, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 4, 4, 1, 2, 2, 7, + 8, 3, 5, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 0, 1, 0, 3, 0, 3, + 3, 0, 3, 5, 0, 3, 5, 0, 1, 1, + 0, 1, 1, 2, 2, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 2, 0, 2, + 5, 7, 1, 3, +} + +var yyChk = [...]int{ + -1000, -759, -763, -12, -8, -9, -11, -154, -117, 736, + -14, -23, -156, -142, -157, -15, -151, -17, -18, -19, + -213, -21, -124, -146, -148, -150, -149, -62, -20, -143, + -144, -145, -102, -103, -127, -135, -138, -139, -140, -141, + -158, -152, -153, -155, -245, -159, -168, -169, -220, -172, + -174, -175, -208, -209, -239, 725, -118, -119, -120, -121, + -122, -123, -43, -42, -41, -40, -200, -210, -214, -216, + -170, -57, 641, 731, 770, 542, -16, -702, -641, 595, + -24, -25, -112, -26, 278, 305, -483, -125, -484, -485, + -487, -764, -63, -64, -65, -78, -79, -80, -81, -82, + -92, -93, -94, -66, -67, -68, -71, -69, -85, -84, + -86, -87, -88, -89, -90, -91, -70, -74, -203, -204, + -205, -206, -95, -72, -73, -218, -221, -171, -96, -97, + -98, -75, -60, -61, -76, -77, -100, -99, -105, -111, + -101, -106, -202, -212, -22, -219, -107, -59, -109, -110, + -108, 279, 350, 298, -104, 86, -128, -129, -130, -131, + -132, -133, -134, -136, -137, 463, 469, 529, 723, 724, + 71, -247, -249, -251, 772, 773, 776, 626, 628, 323, + 186, 187, 189, 190, 194, 197, -44, -45, -46, -47, + -48, -49, -51, -50, -52, -53, -54, -55, -56, 274, + 22, 20, 24, 64, -27, -30, -28, -31, -29, -38, + -39, -37, -32, -34, -201, -207, -33, -211, -215, -217, + -173, -58, -35, -36, 300, 299, 47, 366, 367, 368, + 467, 275, 277, 23, 40, 51, 442, -250, -254, 96, + -257, -253, 627, 276, -252, -256, 21, 284, 790, -13, + -10, -9, -187, -191, -195, -198, -199, -196, -197, -11, + -154, 131, 290, 726, -479, 459, 727, 729, 728, 99, + 107, -472, -474, 770, 542, 305, 463, 469, 723, 724, + 773, 776, 626, 628, 323, 643, 644, 645, 646, 647, + 648, 649, 650, 652, 653, 654, 655, 656, 657, 658, + 701, 702, 668, 669, 659, 660, 661, 662, 663, 664, + 665, 666, 670, 671, 672, 673, 674, 675, 676, 677, + 678, 679, 680, 681, 682, 683, 598, 599, 703, 705, + 706, 707, 708, 651, 688, 696, 697, 698, 781, 782, + 440, 6, 7, 8, 9, 10, 441, 634, 720, 779, + 317, 341, 496, 347, 354, 421, 186, 204, 200, 229, + 219, 427, 483, 373, 749, 750, 372, 627, 195, 321, + 359, 322, 106, 189, 581, 121, 554, 525, 192, 379, + 382, 380, 381, 336, 338, 340, 453, 343, 342, 344, + 346, 625, 377, 443, 215, 209, 335, 319, 207, 324, + 428, 49, 325, 419, 418, 234, 326, 327, 638, 550, + 439, 556, 351, 62, 523, 208, 339, 553, 719, 242, + 246, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 572, 425, 406, 407, 408, 409, 573, 430, 484, + 177, 178, 558, 748, 755, 756, 757, 759, 760, 761, + 758, 424, 575, 429, 233, 236, 237, 238, 239, 240, + 241, 297, 415, 416, 431, 432, 433, 434, 435, 437, + 438, 52, 636, 309, 576, 244, 766, 223, 232, 227, + 584, 355, 353, 420, 231, 203, 226, 320, 788, 771, + 75, 248, 247, 249, 519, 520, 521, 522, 328, 329, + 457, 571, 751, 752, 222, 210, 444, 196, 31, 579, + 304, 555, 470, 383, 57, 384, 330, 348, 356, 378, + 243, 245, 311, 316, 371, 426, 637, 527, 528, 315, + 485, 563, 564, 352, 577, 206, 308, 337, 303, 580, + 767, 753, 197, 787, 472, 331, 190, 345, 574, 769, + 583, 74, 172, 202, 193, 743, 744, 294, 704, 187, + 313, 318, 721, 768, 332, 333, 334, 358, 357, 349, + 194, 224, 310, 230, 213, 201, 225, 188, 312, 582, + 173, 717, 442, 506, 221, 218, 314, 486, 287, 722, + 578, 557, 191, 510, 175, 216, 360, 711, 712, 713, + 716, 458, 414, 361, 362, 214, 301, 548, 549, 365, + 516, 401, 490, 526, 497, 491, 265, 266, 369, 560, + 562, 235, 714, 385, 386, 387, 552, 388, 389, 390, + 391, 396, 462, 66, 68, 108, 111, 110, 774, 775, + 73, 38, 448, 451, 488, 789, 492, 403, 718, 635, + 400, 404, 405, 452, 34, 508, 474, 512, 511, 58, + 59, 60, 63, 64, 65, 67, 69, 70, 61, 624, + 467, 481, 585, 54, 56, 477, 478, 36, 454, 507, + 530, 399, 509, 541, 55, 539, 540, 561, 35, 456, + 455, 72, 53, 515, 517, 518, 363, 397, 465, 732, + 586, 460, 476, 480, 461, 402, 450, 482, 77, 473, + 733, 468, 466, 783, 784, 398, 639, 640, 410, 667, + 445, 524, 621, 620, 619, 618, 617, 616, 615, 614, + 366, 367, 368, 493, 494, 495, 505, 498, 499, 500, + 501, 502, 503, 504, 544, 545, 734, 735, 565, 567, + 568, 632, 569, 566, 282, 778, 777, 446, 447, 285, + 737, 738, 109, 739, 741, 740, 37, 742, 765, 762, + 763, 764, 642, 570, 629, 745, 631, 630, 689, 690, + 691, 692, 693, -568, -566, -479, 627, 323, 770, 723, + 724, 469, 626, 628, 463, 442, 773, 776, 64, 467, + 305, 366, 367, 368, 542, 440, -327, -479, 284, 777, + -104, -25, -24, -16, -641, -112, -250, -251, -768, 271, + 273, 478, -342, 284, -479, -488, 32, 523, 279, 280, + -126, 524, 96, 87, -479, -17, -140, -15, -151, -102, + -245, -702, 529, -486, -479, 366, 366, 632, -486, 284, + 284, 747, 528, 569, 632, 748, 755, 766, 564, 453, + 110, 111, 743, 744, 36, 284, 464, 311, 562, 560, + 561, 565, 566, 567, 568, -83, -653, -629, 557, 648, + 556, -492, 549, 555, 547, 559, 550, 441, 391, 388, + 641, 390, 395, 274, 737, 623, -467, 490, 526, 585, + 586, 465, 527, 572, 574, 551, 121, 220, 217, -481, + 315, 504, -479, -630, 290, -572, -543, 316, -571, -545, + -574, -546, 41, 274, 276, 275, 641, 312, 24, 467, + 286, 22, 21, 468, 298, 34, 35, 37, 23, 469, + 471, 38, 472, 475, 476, 477, 51, 481, 482, 305, + 99, 107, 102, 689, 690, 691, 692, 693, 323, 284, + -323, -479, -514, -506, 128, -509, -501, -502, -504, -457, + -674, -499, 96, 157, 158, 165, 129, 167, 791, -503, + -611, 45, 131, 647, 651, 688, 596, -449, -450, -451, + -452, -453, -454, 633, -479, -675, -673, 102, 112, 114, + 118, 119, 117, 115, 180, 211, 116, 103, 181, -251, + 99, -696, 657, 663, -473, 680, 705, 706, 707, 708, + 679, 71, -637, -651, 283, -649, 179, 217, 301, 213, + 22, 163, 516, 214, 696, 697, 698, 654, 676, 598, + 599, 703, 658, 781, 782, 668, 683, 649, 650, 652, + 644, 645, 646, 648, 659, 661, 675, -652, 671, 681, + 682, 667, 699, 700, 762, 701, 702, 684, 685, 686, + 695, 694, 687, 689, 690, 691, 692, 693, 741, 101, + 100, 674, 673, 660, 655, 656, 662, 643, 653, 664, + 672, 677, 678, 451, 121, 452, 453, 588, 443, 90, + 454, 290, 523, 9, 80, 455, 456, 457, 458, 243, + 459, 595, 460, 787, 81, 461, 450, 305, 506, 462, + 216, 235, 601, 600, 602, 592, 589, 587, 590, 591, + 593, 594, 665, 666, 670, -248, -250, -702, -251, -176, + -178, 709, -752, -287, -753, -439, 31, -754, 12, 13, + 14, 15, 181, -743, 525, 637, 102, 588, 284, 359, + 440, 25, 747, 395, 625, 747, 395, 625, 373, 191, + 188, -558, 191, 127, 197, 196, 288, 191, -558, -479, + 194, 747, 193, 743, 748, 755, 632, 369, -530, -224, + 440, 506, 388, 108, 315, -535, -531, -631, 363, 359, + 285, 124, -225, 295, 436, 294, 122, 588, 283, 479, + 354, 66, 68, 41, 54, -271, 57, 289, 48, -342, + -704, 622, -703, -479, -712, -713, 271, 272, 273, 48, + 748, 755, 285, 287, 284, 743, 632, 315, 440, -531, + 506, 108, 388, 284, -712, 766, 188, 572, 574, 525, + 315, 504, 50, -565, 516, -564, -566, 573, 584, 100, + 101, 571, -467, 121, 548, 548, -752, -439, -753, -282, + -439, -281, 17, -247, -251, -254, -258, -702, -260, 71, + 625, 747, 632, 748, 755, 285, 440, 506, 315, 286, + -631, 287, 588, 283, 366, 464, 311, 388, 395, 108, + 193, 743, -264, -265, -266, 267, 268, 269, 79, 272, + 270, 76, 41, 42, 43, -342, -8, 135, 790, -506, + -506, -13, 793, -13, -506, -479, -479, 183, -349, -353, + -350, -352, -351, 779, -355, -354, 217, 218, 179, 221, + 223, 228, 224, 225, 226, 227, 229, 230, 231, 232, + 233, 236, 237, 238, 239, 240, 241, 234, 40, 235, + 301, 213, 214, 215, 216, -358, 200, 219, 635, 260, + 201, 261, 202, 262, 203, 263, 177, 178, 264, 204, + 207, 208, 209, 210, 206, 242, 243, 244, 245, 246, + 247, 248, 249, 251, 250, 252, 253, 254, 255, 256, + 257, 258, 259, 182, -307, 102, 41, 96, 182, -342, + 102, -752, -281, -282, -287, -271, 25, -342, -333, 182, + 791, -455, -479, 525, 138, 523, -126, 524, 87, 523, + -126, 524, 279, -126, 87, -705, -706, -707, -709, 279, + 524, 523, 280, 350, -149, 182, 323, 25, -486, -486, + -479, 93, -308, -309, -342, -344, -342, -736, -735, 41, + 632, -312, 32, 570, 750, 752, 548, 758, 767, 768, + 769, 92, -491, 146, 150, -491, -435, 26, -435, 32, + 32, 313, 313, 313, -491, 353, -765, -766, 25, 148, + -489, -766, -489, -489, -491, -767, 286, 558, 52, 314, + 313, -284, -285, 30, 96, -284, 552, 548, -594, 553, + 554, -493, -766, -492, -491, -491, -492, -491, -491, 394, + -491, 41, 389, 390, 284, 287, 588, 388, 738, -765, + -765, 40, 40, -545, 315, -572, -543, 45, 92, 183, + 288, 183, 92, 96, 465, 440, 506, 466, 588, 284, + 479, 287, 315, 480, 440, 506, 284, 287, 588, 315, + 440, 284, 287, 506, 315, 480, 440, 547, 548, 287, + 36, 470, 473, 474, 548, -657, 584, -342, 183, 127, + 124, 126, -506, 145, -521, 138, 139, 140, 141, 142, + 143, 144, 152, 151, 164, 157, 158, 159, 160, 161, + 162, 163, 153, 154, 155, 156, 148, 128, 167, 788, + 146, 150, 147, 130, 125, 170, 169, -251, -506, -514, + 71, -504, -504, -504, -504, -504, -479, -611, -511, -506, + 96, 96, 96, 96, 96, 182, 115, 102, 96, -506, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, -650, 96, 96, -518, -519, 96, 96, + -499, -455, 96, 102, 102, 96, 96, 96, 102, 96, + 96, 96, -519, -519, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, -752, -250, -282, 183, 96, -281, + -282, -288, 29, -287, -252, -251, -256, -260, -506, -755, + 733, 41, 42, 41, 42, 41, 42, 41, 42, 96, + 112, 774, 265, -297, -479, -298, -479, -184, 25, 791, + -479, 743, -735, 389, 632, 632, 389, 632, 274, 24, + 377, 64, 378, 577, 20, 195, 196, 197, -479, 194, + 288, -479, -528, 290, -528, -528, 749, 525, -528, -322, + -479, 311, 464, 287, 287, -225, -528, 25, -528, -528, + -528, -528, 286, -528, 284, 284, 284, -528, 595, 138, + 138, 69, -643, -646, -642, -645, 48, 132, -646, -302, + 307, -271, -271, -342, 183, -704, -293, 96, -714, 199, + -274, -273, -268, -270, -438, -440, -272, 96, -342, -251, + 5, -479, 749, 525, -630, -630, -342, -630, -479, 290, + -546, -630, 623, -468, -527, -479, -524, 220, 50, 169, + -630, -630, -630, -421, -422, -342, -715, 289, 769, -749, + -748, 575, -751, 577, 188, -566, 188, -566, 99, -545, + 315, 315, 183, 138, 32, -567, 138, 149, -566, -566, + -567, -567, -390, 50, -478, 179, -479, 102, -390, 50, + -746, -745, -342, -282, -252, -251, -256, -260, -286, -285, + -287, -255, -252, -256, -251, 71, 29, 97, 97, -282, + -282, -439, -176, 632, -630, -630, 749, 525, -630, -630, + -630, -630, -630, 284, -630, -630, -630, -486, -630, -327, + 290, -630, 389, -630, -630, -630, -261, -263, 159, -506, + -479, -266, -10, -189, -188, 132, 133, 135, 727, 459, + 726, 730, 723, -566, 50, -624, 173, 172, 96, -618, + -620, 96, -619, 96, -619, -619, -619, 218, 221, -618, + -618, -619, -619, -619, -619, -619, -619, 96, 96, -621, + 96, -621, -621, -618, -622, 212, 96, -622, -623, 96, + -623, -622, -479, -598, 20, -512, -514, -479, 288, 48, + -282, -179, -287, 48, -285, -288, -294, 307, 108, -334, + 754, -479, 214, 193, 742, 44, 182, 112, 102, -710, + 233, 224, 138, -126, 87, -149, 138, -126, -126, -149, + 97, 183, -708, 118, 119, -710, 102, -479, -147, 102, + -673, -14, -20, -125, -15, -151, -17, -19, -62, -102, + 40, -153, -143, -239, -245, -483, 298, 626, 628, -676, + -674, -310, 183, 438, 96, -311, 183, 550, 32, -479, + -284, 637, -165, 32, -491, 25, 148, -491, -491, 25, + 148, -491, 315, -435, -504, -504, -506, 440, 588, 284, + -547, 601, 315, -478, -765, -491, -491, -469, -468, -493, + -488, -493, -493, -435, -489, -491, -491, -506, 159, -493, + -489, -435, -479, 548, -435, -435, -594, -468, -491, 102, + -490, -479, -490, -528, -468, -469, -469, 41, 515, 92, + 25, -573, 284, 588, 464, 311, 287, 440, -571, -552, + -549, -547, -545, -548, -547, -576, -455, 548, -180, 531, + 530, 365, 25, -506, -506, -506, -506, 117, 128, 167, + 414, 118, 119, -501, -522, 41, 361, 362, -502, -502, + -502, -502, -502, -502, -502, -502, -502, -502, -502, -502, + -504, -504, -510, -520, -611, 96, 148, 146, 150, 147, + 130, 148, 146, 150, 147, 130, -771, 33, -504, -504, + -502, -502, -504, -347, -349, 172, 173, -392, -478, 179, + 97, 183, -506, -701, -700, 132, -506, -506, -506, -506, + -536, -538, -455, 96, -479, -502, -697, -698, 603, 604, + 605, 606, 607, 608, 609, 610, 611, 612, 613, 455, + 450, 456, 454, 443, 462, 457, 458, 216, 620, 621, + 614, 615, 616, 617, 618, 619, -512, -512, -506, -697, + -502, -512, -448, 42, 41, -514, -514, -514, 97, -506, + -711, 412, 411, 413, -456, -479, -512, 97, 97, 97, + 112, -514, -514, -512, -502, -512, -512, -512, -512, -698, + -698, -699, 301, 213, 215, 214, -448, -506, -506, -448, + -448, -448, 159, -514, -514, -448, -448, -448, -448, 159, + -448, -448, -448, -448, -448, -448, -448, -448, 97, -448, + -448, -448, -448, -448, 97, 97, 97, 97, -506, 97, + -506, -506, -506, -506, -506, 159, -514, -282, -752, -286, + -178, -655, -654, -506, 50, -179, -287, -285, -179, 684, + -288, -756, 735, 96, -455, -744, 102, 102, 791, -184, + 25, 182, 284, -184, 182, 743, 193, -184, 588, 25, + -479, 102, 112, -479, 102, 112, 284, 588, 284, 588, + -342, -342, -342, 578, 579, 192, 196, 195, -479, 194, + -479, -479, 128, 167, -479, -479, -528, -528, -479, 44, + -327, -313, -479, -528, -528, -719, -479, 103, 102, -553, + -550, -547, -479, -479, -543, -479, -468, -528, -528, -528, + -342, -401, 63, 64, 65, -547, -226, 66, 67, -245, + -642, -644, -645, 134, -342, -506, -644, -640, 71, -245, + 96, 40, 96, -302, -302, -703, 44, -292, -479, -715, + 93, -441, -442, -443, -444, -446, -447, -445, 78, 82, + 84, 88, 79, 80, 81, 551, 85, 90, 783, 83, + -477, -482, 44, -479, 102, -477, -251, -276, -275, -274, + 791, -477, 96, 96, -479, -479, -342, -342, -415, -423, + -420, -416, 281, -424, 307, 275, 448, 449, 277, 17, + 276, -432, 354, -529, 596, -396, -397, 87, 51, -399, + 305, 492, 488, 789, 317, 321, 106, 322, 525, 323, + 286, 325, 326, 327, 342, 344, 297, 328, 329, 330, + 516, 331, 187, 343, 332, 333, 334, 466, -391, 12, + 396, 50, 61, 62, 540, 539, 639, 20, 318, -479, + 495, 628, 40, 45, 277, 281, 276, -719, -717, 40, + -479, -527, 40, -524, 40, 220, 169, -475, 138, -553, + -547, -479, -479, 183, 288, -274, -276, -566, 183, 576, + 578, 579, -749, -567, -749, -567, 288, 41, 515, -570, + 515, 41, -543, -564, 572, 574, -559, 102, 516, -548, + -569, 92, 179, -654, -567, -567, -569, -569, 169, 183, + -747, 577, 578, 271, -286, -176, -280, -279, -506, -286, + -286, -259, -252, -260, -256, -251, 112, -737, -735, -479, + 632, -479, -630, -630, -344, -719, -552, -543, -479, -630, + -344, -481, -481, -313, 45, -479, -630, -479, -479, -479, + -179, 183, -480, -479, 44, 102, 182, -190, -188, 134, + -506, -13, 726, -506, -13, -13, -506, -13, -506, -628, + 175, -349, 112, 112, -458, 102, -458, 112, -622, 112, + 112, 642, 97, 102, 102, -286, -288, 710, -677, -673, + -288, -179, -647, 71, -245, 96, 40, 96, -630, 193, + 214, 753, -333, 138, 138, 138, 33, -479, 32, -126, + -126, -710, 102, -149, -710, 102, -126, -706, 182, -565, + 523, 524, 183, -309, -292, -342, 641, 112, -167, 30, + -479, -435, -479, 749, -435, -435, -479, 749, 751, -435, + -546, -479, -479, -479, -544, 93, -650, -479, 794, 100, + -469, -435, -435, -493, -435, -435, 183, 31, 97, -491, + -493, -493, -333, -489, -333, 182, -333, -468, -573, -551, + -548, -575, 159, -479, -560, 183, 20, 288, -732, -731, + 507, 97, 183, -658, 289, 595, 102, 791, 523, 265, + 266, 102, 117, 414, 118, 119, 117, 414, 118, 119, + -611, -514, -510, -504, -504, -502, -502, -510, -504, -504, + -502, -502, 96, -508, 302, -508, 127, -357, 178, 177, + -357, -506, 792, -505, -700, 134, -506, 44, 183, 44, + 183, 93, 183, 97, -618, -506, 182, 183, 97, 97, + 25, 25, 148, 97, -506, 97, 97, 97, 97, 25, + 25, -506, 97, 182, 97, 97, 97, 97, 93, 97, + 183, 97, 97, 97, 97, 183, 183, 183, -514, 97, + 97, -514, -506, -514, 97, 97, 97, -506, -506, -506, + -514, 97, -506, -506, -506, -506, -506, -506, -506, -506, + 780, -506, -506, -514, -506, -506, -583, 543, -583, -583, + -583, 97, -583, 97, 183, 97, 183, 97, 97, 183, + 183, 183, -286, -282, 183, 97, -288, -288, 20, -179, + -757, 734, 96, 112, 183, 775, -462, -461, 102, -186, + 288, 193, 743, -479, -479, -186, -479, -479, 138, -186, + -479, 743, 102, 102, -342, -468, -342, -468, 634, 48, + 48, 193, 197, 197, 196, -479, 102, 45, 45, 32, + 32, 352, -479, -479, -160, 629, -323, 96, 96, 182, + -342, -342, -721, 493, -479, -733, 183, 50, -731, 588, + -222, 365, -532, -533, 93, -235, 372, 25, -342, -342, + -342, -356, 44, -245, -643, 71, 96, 133, -245, -557, + -556, 92, -648, -515, -695, 709, -301, 97, -289, -479, + -693, -694, -289, -295, -303, -479, -640, -640, 96, 97, + 183, 25, -267, -343, -479, -274, -273, -273, -273, -273, + -273, -273, -273, 78, 89, 78, -290, 96, 78, 83, + 78, 83, 78, 83, 78, -443, 78, 78, 80, 89, + -293, -482, 183, 97, 99, -742, -741, -740, -738, 86, + 289, 87, -506, -512, 40, 40, 62, 61, -617, 44, + -293, 183, 307, -341, -476, -338, -340, 292, -496, -339, + 295, 436, -689, 293, 291, 122, 296, 350, 123, 286, + 29, 417, -476, -418, 286, 350, 293, -476, -476, 292, + -400, 288, 44, 29, 307, -417, 286, 123, -479, 292, + 296, 293, 350, 291, -475, -467, 169, 288, 52, 466, + -475, 640, 307, -475, -475, -475, -475, -475, -475, -475, + -475, 324, 324, -475, -475, -475, -475, -475, -475, -475, + -475, -475, -475, -475, 188, -475, -475, -475, -475, -475, + -475, 96, 319, 320, 352, 629, 132, 642, 631, -546, + 288, 563, 563, -722, 493, 40, 446, 446, 447, -475, + 40, -475, -392, -733, 442, 51, 40, -236, 440, -422, + -419, -490, 40, 40, -567, -748, -750, 580, 577, 583, + -569, -569, 112, 288, 96, 138, -569, -569, 50, -478, + -745, 584, 578, -288, 183, -277, 46, 47, 97, 97, + -320, 745, -479, -479, 92, -344, -633, 345, 346, 96, + -327, 102, 25, -320, -434, -433, 25, -263, -479, 102, + -479, 159, 135, -13, 133, -194, -193, -192, 136, 723, + 730, 135, 135, 135, 97, 97, 97, 97, 183, 97, + 97, 97, 183, 97, 183, 112, 771, -661, 553, -288, + -179, 102, 183, -179, -262, 778, -648, -301, 97, -693, + -295, -479, 102, 112, 102, 44, -234, 99, 107, 102, + -334, -506, -479, 102, -506, 214, 182, 525, -126, -126, + -126, -126, -479, 138, -674, 97, 112, -491, -479, -491, + 182, -479, -231, -233, -479, 102, -479, -543, -544, -478, + -491, -435, -506, -506, 557, 556, -435, -491, -491, -493, + -479, -333, -575, 183, 288, 182, 182, -549, 469, -551, + 29, 20, -455, 48, -462, 138, 791, -479, 97, -508, + -508, 127, -508, -508, 127, -504, -504, -501, 97, 135, + -506, 133, -347, 217, -506, -347, -348, -354, 233, 179, + 217, 301, 216, 215, 213, 172, 173, -390, -538, 634, + -277, 97, -479, -514, -506, -506, -502, 97, -506, -506, + 25, -479, -390, -502, -506, -506, -506, -282, -283, 780, + -283, -282, 97, 97, -582, -583, -582, -283, 97, 97, + 97, 97, -582, 97, 97, 97, 97, 97, 97, 97, + 97, 27, 97, 97, 97, 97, 183, -479, 96, -583, + -769, 787, -506, -769, -506, -769, -769, -506, 112, 114, + 112, 114, -288, -286, -654, -179, -179, 470, 96, 307, + 183, 112, 102, 792, 183, 138, 440, -185, -479, 102, + -479, 25, 25, 182, 102, -479, 102, 25, 284, -479, + 25, 25, -342, -342, -342, 197, 102, -734, 359, 440, + 588, 284, 440, 359, 588, 284, -599, 112, -366, 20, + -370, 20, -161, 132, 102, 477, -328, -329, -330, -331, + -332, 148, 184, 185, -314, -315, -316, -317, -349, -455, + 779, 218, 221, 223, 224, 225, 226, 227, 229, 230, + 231, 232, 233, 236, 237, 238, 239, 240, 241, 234, + 235, 301, 213, 214, 215, 216, 200, 219, 635, 201, + 202, 203, 177, 178, 204, 207, 208, 209, 210, 206, + 242, 243, 244, 245, 246, 247, 248, 249, 251, 250, + 252, 253, 254, 255, 256, 257, 258, 259, -479, -293, + -293, -724, 555, 495, 505, -475, 388, -498, -497, 442, + 51, -635, 516, 501, 502, -550, 315, -468, 159, -730, + 109, 138, 92, 400, 404, 406, 408, 407, 405, 401, + 402, 403, -525, -526, -523, -529, -468, 102, -717, 96, + -246, -230, -229, 146, -235, 372, 25, -245, 71, 289, + 595, 96, -365, 327, 96, -612, 385, -349, 96, -301, + -643, -262, 49, 183, 96, 97, 183, 71, 182, 183, + 138, 97, 183, 97, 183, 138, -262, -262, -556, -8, + -479, -342, -267, -479, 25, 183, -716, 182, 92, -305, + -304, 92, 93, -305, -305, -304, -304, 78, -291, 102, + 78, 78, 78, 78, 83, -275, -274, -740, -739, 32, + -689, -689, -689, 183, 97, -367, 96, -368, -232, -479, + 102, -371, 96, -372, -373, -479, 102, -612, -349, 44, + -416, 281, 275, 276, -603, 96, -346, 96, -455, -339, + -688, -689, -688, -528, -479, 123, -688, 123, 96, -579, + 352, 353, -580, -601, 355, -479, -455, -479, -479, -479, + -346, -455, -455, -419, -427, -426, -455, -430, 41, -431, + -479, -479, -479, -479, 123, -479, -479, 123, -395, 50, + 58, 59, 60, -475, -475, 220, -398, 50, 515, 517, + 518, -430, 112, 112, 112, 112, 112, 102, 102, 102, + -475, -475, 112, 102, -482, 102, -690, 196, 54, 55, + 112, 112, 112, 112, 50, 102, -403, 50, 335, 339, + 336, 337, 338, 102, 112, 50, 112, 50, 112, 50, + -479, 96, -691, -692, 102, -599, 102, 96, 112, 102, + 277, -546, 102, 92, -724, -475, 446, -566, 138, 138, + -390, -475, -392, -498, -726, 106, 496, -726, -729, 365, + -238, 588, 41, -296, 281, 276, -717, -555, -554, -455, + -555, -569, 577, 581, 582, -551, -494, 102, -559, -179, + -279, -278, 53, -342, -633, -314, -479, -435, -276, 182, + 131, -13, -190, -192, -506, -13, -506, 726, 459, 727, + 102, 112, 112, 579, -669, 537, 532, 534, -179, -670, + 523, -673, -261, 97, 71, 97, 33, 792, 792, 792, + 792, 102, -479, 112, 102, -435, -491, -435, -231, -491, + -491, 148, -435, -333, -435, -435, -491, 25, -548, -543, + 159, 159, -479, 470, -560, 102, 494, 102, 284, 792, + 102, -462, -501, -501, 97, -506, 97, -619, 44, 97, + 97, -619, -619, -618, -621, -618, -357, -357, 97, 96, + -277, 97, 97, 32, 97, 97, -582, 97, 97, -506, + 182, 97, 97, 183, 183, 97, -638, 597, -582, 27, + -582, -639, 669, -582, -582, -582, -582, -582, -582, -582, + -582, -582, -582, -582, -582, -582, -582, -582, 96, -582, + -582, -582, -582, -506, -584, -588, -479, -583, 53, 97, + 183, -583, 97, 183, -583, -583, 97, 538, 740, 740, + 538, 740, 740, -179, -288, -514, -758, 73, 732, 72, + 515, 117, 355, 97, -697, 183, -470, 360, -470, -461, + 102, -479, 102, 193, 743, -479, 792, 792, 193, 743, + -479, 102, -342, -468, -299, 554, -242, 132, -243, 130, + 52, 102, -479, 25, -479, -479, 352, -479, 352, -479, + -479, 102, 96, 96, -166, 642, 96, -163, 630, 102, + 97, 183, -455, 97, 183, -349, 44, 44, -725, 106, + -720, 102, -479, 103, -479, -726, 181, 444, 50, 497, + 498, 513, 439, 112, 112, 503, -718, -479, -237, 284, + 440, -237, -728, 62, 138, 102, -342, -523, -467, 169, + 326, -333, -479, 388, -335, -336, -337, -346, -338, -340, + -246, 44, -342, -342, 102, -176, -335, -475, -335, -613, + 387, 29, 112, 158, -514, 97, 123, -515, -656, -655, + 71, -245, -289, -648, -479, -694, -654, -479, -479, -506, + -262, 97, -294, 93, 182, -276, -343, -479, 159, -506, + -506, 96, -269, 784, 97, 78, 792, 96, 78, 17, + 27, 102, 183, -367, 138, 183, -371, 138, -613, -245, + -476, -604, -602, 307, -425, 54, 56, -762, -346, -349, + -686, -479, -686, -684, -686, -479, -684, -684, -528, -506, + -596, 356, 96, -594, 96, -594, 123, 401, 404, 406, + 408, 407, 436, 40, 276, -428, 404, 398, 399, -561, + 351, 128, 167, -561, -425, -346, 288, 183, -277, 183, + -479, -390, -390, 40, 102, 102, -344, 97, 183, 138, + 102, -163, -162, -506, -247, -251, 288, 92, 284, -725, + -720, 138, -567, 102, 102, -390, -726, 102, 102, -730, + 138, -345, 284, -468, 183, -296, -296, -435, 25, 183, + 138, -435, 97, -306, 32, 51, 54, 55, 97, 388, + -437, 27, 159, 135, 133, 135, 135, -479, 97, 97, + -625, 711, -665, -667, 532, 29, 29, -306, -671, 716, + 102, 71, -245, -648, 214, 102, 792, -435, -491, -435, + -435, 749, -435, -543, -560, 516, -342, 183, 792, 220, + -347, 220, -409, 102, 103, -479, -506, 97, -479, -506, + -506, 97, 102, 96, 97, 102, -281, 97, 97, -517, + -516, 307, -769, -506, -769, -506, -770, 25, 97, 183, + 97, 97, 97, 183, 97, 97, -306, -179, 97, 183, + 97, -697, -471, 214, 102, -471, -185, -479, -185, -479, + 25, -480, -240, 288, -333, -244, 383, 96, 379, -242, + 193, 96, 102, -479, 25, -479, -599, 352, -599, 352, + 284, -479, -320, -367, -371, -164, 631, 112, -162, 102, + -534, 636, -330, -349, 282, -316, 50, -246, -246, 102, + -723, 507, -600, 393, 112, 50, 112, 181, 499, -636, + -223, 106, -344, 41, -296, -223, -727, 106, 138, 791, + 96, -475, -475, -475, -240, 388, -479, 97, 183, -246, + -241, 60, -479, -282, 97, 748, 97, -614, 306, 112, + 158, 112, 158, 112, 97, 71, 23, 289, 97, -648, + 182, 138, -477, -276, -479, -435, -716, 182, -113, -114, + 132, -292, -503, 181, -685, -479, 291, 29, 29, 554, + -368, 97, -233, -372, 97, -374, -479, 102, -614, 96, + 97, 183, -479, -455, 97, 183, -362, -361, -359, 117, + 128, 167, 50, 488, -360, 106, 756, 757, 169, 340, + 343, 342, 318, 341, -414, -495, 92, 704, 491, 398, + 399, -529, 719, 44, 291, 122, 123, 471, -496, 96, + 96, 96, 93, 360, 96, 96, -686, 97, -581, 357, + 112, -502, 96, -502, 96, -595, 354, 96, -539, -539, + -539, -539, -539, 50, -428, 50, -429, 423, 351, 351, + -425, -455, -426, -479, 169, -390, 97, -692, 102, 97, + -546, 284, -479, -723, 102, -569, -728, 102, -223, -344, + -717, -282, -276, -554, -654, -262, 23, 74, 148, -479, + -436, 28, 29, 290, -13, 727, 459, -405, 712, 102, + 29, 102, -663, 102, -661, 102, -648, 102, -435, -479, + -182, -402, -467, 323, 40, 97, 40, -408, 148, 20, + 97, 97, 97, -283, -281, -582, 97, -582, -282, 29, + -583, 97, -583, 97, -769, 54, 102, 102, -306, -506, + 97, 102, 102, 102, 743, 440, -240, 44, 477, 30, + 648, 384, -292, 380, 381, 382, -479, 102, -514, -247, + 791, 388, -479, 25, 102, -599, 102, -599, -479, 352, + 97, 97, 44, 102, 97, 102, 102, -318, -349, -499, + -227, 20, -227, 29, 20, 181, 443, 50, 112, 50, + 500, 102, -237, 138, 118, 119, -463, -464, 102, -536, + -390, -392, 102, -479, -363, -246, -230, -229, -364, -432, + -529, -337, -240, 36, 388, -286, -181, -365, -369, -375, + -381, -382, -180, 327, -366, -363, -615, 187, 112, 158, + 112, 112, 96, -555, -479, -506, -435, -435, -262, 778, + -114, -116, 128, 167, -479, 97, 97, 183, 96, -615, + -762, -602, -605, 71, -346, -359, 117, 117, -502, 102, + 102, 102, -392, -393, 50, 339, 335, 138, 138, -394, + 50, 319, 320, -404, 96, 350, 23, 112, 220, 720, + 96, 123, 123, -342, -536, -536, -536, -687, 400, 401, + 402, 410, 404, 405, 403, 406, 407, 408, 409, -687, + -536, -536, 96, -562, -561, -603, 29, 97, -576, 97, + -576, 96, 138, -502, -540, 297, 415, 416, 106, 20, + 398, 399, 420, 419, 418, 424, 425, 429, 430, 426, + 428, 427, 431, 435, 432, 433, 434, 437, 421, 422, + 64, 423, 443, 454, 450, -502, -539, 138, -475, 169, + -479, 182, -727, -284, -435, 74, -586, 785, -506, -514, + 762, 764, 765, -479, -479, -459, 713, 112, 102, 534, + -669, -491, -626, 714, -659, -594, -390, 138, -390, -390, + 97, 85, 635, 409, 637, -582, 97, -582, -590, -589, + -593, 538, 352, 546, -514, -769, -769, -583, 97, 97, + 97, -479, -479, -342, 102, 112, 97, 127, 127, 97, + 97, -466, -465, 102, -479, 388, -479, -320, 102, -320, + 102, 352, -599, -9, 636, -228, 70, 584, 102, 103, + 494, 102, 103, 112, 443, -223, 102, 792, 183, 138, + 97, -600, -577, 307, -246, 44, 183, -432, -467, -479, + -182, -475, -577, -632, 196, 386, 20, 112, 158, 112, + -514, -282, -262, -261, -115, 127, -116, -116, -479, 291, + -3, -1, -479, 7, -616, 196, 386, 97, -610, -606, + 96, -607, -432, 309, 148, 102, 102, 112, 96, -649, + 40, 44, -506, -537, 96, 97, 97, 97, 97, 97, + -536, -580, 97, 97, 97, -576, 112, 97, -475, -475, + 102, 102, 397, -475, -475, -475, -475, -475, -475, 96, + 102, 102, -475, -475, -475, -475, -475, -475, 138, 138, + -475, -475, -475, 118, 119, -390, -475, 182, -479, -262, + -262, 75, -587, -585, -479, -634, 20, 763, 96, 96, + 96, 29, -625, -435, -627, 715, 102, -668, 537, -662, + -660, 532, 533, 534, 535, 102, 97, 636, 75, 75, + 638, -592, 130, 499, 503, -500, 103, -503, 112, 114, + 211, -583, -583, 102, -479, 102, 792, 183, 138, -479, + 388, -320, -320, -599, 102, -321, -479, 350, 516, -464, + 102, -541, -578, 359, 29, -246, -432, -475, -600, 755, + 759, -389, 761, 760, 68, -578, 386, 112, 158, 112, + 97, -284, 133, -506, -115, -115, 97, 183, 32, -349, + -7, 6, 386, -610, -607, -609, -608, 357, 310, 96, + 97, -506, -518, -475, 96, 97, -407, -406, 633, -536, + -539, 93, -539, -539, 93, -539, 93, -539, 93, 97, + -597, 358, 97, 112, 112, -479, 112, 112, 112, 112, + 112, 112, -576, 112, 112, 112, 112, 112, 112, 118, + 119, 118, 119, 112, 112, 112, -390, -479, 183, 44, + 765, 96, -514, -514, -460, -479, -663, -405, 102, -672, + 289, -666, -667, 536, -660, 29, 534, 29, 29, -183, + 183, 75, -591, -592, 503, -500, 103, -503, 709, 544, + 544, 544, 544, -242, -243, -242, -243, -320, -465, 102, + -479, 102, -320, -319, 44, 539, 470, -542, -540, -533, + 29, -579, -390, -370, -376, 20, -386, 20, -383, 20, + 112, -262, 23, 24, 133, 133, 97, -1, 8, 6, + 45, 102, 97, 183, -479, 306, 96, -513, -507, -506, + 306, 97, -390, -506, -563, 722, 721, -413, -411, -412, + 92, 551, 348, 349, 97, -687, -687, -687, -687, -414, + 112, 97, -585, 96, -177, 96, 97, 97, 97, 183, + -459, -680, 96, 112, -665, -664, -666, 29, -663, 29, + -663, -663, 541, 20, 127, 545, 545, 545, 545, -242, + -242, -320, 102, -455, 96, -596, 96, 96, 96, 40, + 22, 22, 102, 6, 554, -608, -606, -513, 97, 183, + -561, 97, -412, 92, -411, 92, 24, 23, -539, -539, + -539, -539, -584, 97, 183, -512, -479, -683, 40, 97, + -679, -678, -456, -673, 537, 538, 102, -663, 138, 637, + -591, -761, -760, 739, -576, -581, -377, -378, -379, -479, + 102, -387, -388, -379, -384, -385, -379, -555, 96, 71, + 96, 71, -2, -4, 117, 10, 50, 102, 96, 97, + -507, -563, -410, 345, 346, 40, 196, -410, 97, 96, + 97, -682, -681, -457, 97, 183, 102, 638, -326, 75, + -324, 483, 282, 102, 97, -603, 97, 183, 138, 97, + 183, 138, 97, 183, 138, -300, -479, 96, -300, 96, + 92, 102, -3, 117, 50, 347, -512, 183, 138, -678, + -325, 485, 486, 75, 92, 117, -378, -380, -479, 102, + -388, -380, -385, -380, 97, 183, 182, -514, 97, -514, + 9, 10, 97, 97, -681, 50, -506, -324, -325, 117, + 92, 71, -479, -479, 97, 71, 97, -6, -4, -5, + -4, 484, 117, 96, 182, 96, 92, 92, 484, -514, + -479, -514, 10, 9, 97, 97, +} + +var yyDef = [...]int{ + 23, -2, 1, 2, 3, 19, 20, 21, 22, 18, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 0, 352, 353, 354, 355, + 356, 357, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, + 1255, 1256, 0, 0, 0, 0, 892, 0, 894, 882, + 860, 861, 916, 820, 0, 0, 0, 437, 0, 0, + 0, 0, 661, 662, 663, 664, 665, 666, 667, 668, + 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, + 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, + 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, + 699, 700, 701, 702, 703, 704, 497, 498, 499, 500, + 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, + 511, 0, 0, -2, 386, 382, 294, 295, 296, 297, + 298, 299, 300, 394, 395, 638, 0, 0, 0, 0, + 0, 1000, 1001, -2, 133, 0, 0, 0, 0, 0, + 375, 0, 366, 366, 0, 0, 1257, 1258, 1259, 1260, + 1261, 1262, 1263, 1264, 1265, 1266, 1267, 1268, 1269, -2, + 0, 0, 873, 0, 821, 822, 823, 824, 825, 826, + 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, + 837, 838, 839, 840, 467, 468, 469, 463, 464, 466, + 465, 0, 0, 873, 0, 0, 0, 1016, 1050, 0, + 1070, 1071, 0, 1624, 1072, 1082, 1110, 0, 23, 0, + 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 0, 0, 18, 0, 18, 0, 0, 0, 1841, + 1842, 1843, 1844, 2466, 2822, 2790, -2, 2509, 2467, 2468, + 2713, 2714, 2599, 2616, 2459, 2871, 2872, 2873, 2874, 2875, + 2876, 2877, 2878, 2879, 2880, 2881, 2882, 2883, 2884, 2885, + 2886, 2887, 2888, 2889, 2890, 2891, 2892, 2893, 2894, 2895, + 2896, 2897, 2898, 2899, 2900, 2901, 2902, 2903, 2904, 2905, + 2906, 2907, 2908, 2909, 2910, 2911, 2912, 2913, 2914, 2915, + 2916, 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924, 2925, + 2407, 2408, 2409, 2410, 2411, 2412, 2413, 2414, 2415, 2416, + 2417, 2418, 2419, 2420, 2421, 2422, 2423, 2424, 2425, 2426, + 2427, 2428, 2429, 2430, 2431, 2432, 2433, 2434, 2435, 2436, + 2437, 2438, 2439, 2440, 2441, 2442, 2443, 2444, 2445, 2446, + 2447, 2448, 2449, 2450, 2451, 2452, 2453, 2454, 2455, 2456, + 2457, 2458, 2460, 2461, 2462, 2463, 2464, 2465, 2469, 2470, + 2471, 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, 2480, + 2481, 2482, 2483, 2484, 2485, 2486, 2487, 2488, 2489, 2490, + 2491, 2492, 2493, 2494, 2495, 2496, 2497, 2498, 2499, 2500, + 2501, 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2510, 2511, + 2512, 2513, 2514, 2515, 2516, 2517, 2518, 2519, 2520, 2521, + 2522, 2523, 2524, 2525, 2526, 2527, 2528, 2529, 2530, 2531, + 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2540, 2541, + 2542, 2543, 2544, 2545, 2546, 2547, 2548, 2549, 2550, 2551, + 2552, 2553, 2554, 2555, 2556, 2557, 2558, 2559, 2560, 2561, + 2562, 2563, 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, + 2572, 2573, 2574, 2575, 2576, 2577, 2578, 2579, 2580, 2581, + 2582, 2583, 2584, 2585, 2586, 2587, 2588, 2589, 2590, 2591, + 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2600, 2601, 2602, + 2603, 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611, 2612, + 2613, 2614, 2615, 2617, 2619, 2620, 2621, 2622, 2623, 2624, + 2625, 2626, 2627, 2628, 2629, 2630, 2631, 2632, 2633, 2634, + 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2644, + 2645, 2646, 2647, 2648, 2649, 2650, 2651, 2652, 2653, 2654, + 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662, 2663, 2664, + 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2673, 2674, + 2675, 2676, 2677, 2678, 2679, 2680, 2681, 2682, 2683, 2684, + 2685, 2686, 2687, 2688, 2689, 2690, 2691, 2692, 2693, 2694, + 2695, 2696, 2697, 2698, 2699, 2700, 2701, 2702, 2703, 2704, + 2705, 2706, 2707, 2708, 2709, 2710, 2711, 2712, 2715, 2716, + 2717, 2718, 2719, 2720, 2721, 2722, 2723, 2724, 2725, 2726, + 2727, 2728, 2729, 2730, 2731, 2732, 2733, 2734, 2735, 2736, + 2737, 2738, 2739, 2740, 2741, 2742, 2743, 2744, 2745, 2746, + -2, 2748, 2749, 2750, 2751, 2752, 2753, 2754, 2755, 2756, + 2757, 2758, 2759, 2760, 2761, 2762, 2763, 2764, 2765, 2766, + 2767, 2768, 2769, 2770, 2771, 2772, 2773, 2774, 2775, 2776, + 2777, 2778, 2779, 2780, 2781, 2782, 2783, 2784, 2785, 2786, + 2787, 2788, 2789, 2791, 2792, 2793, 2794, 2795, 2796, 2797, + 2798, 2799, 2800, 2801, 2802, 2803, 2804, 2805, 2806, 2807, + -2, -2, -2, 2811, 2812, 2813, 2814, 2815, 2816, 2817, + 2818, 2819, 2820, 2821, 2823, 2824, 2825, 2826, 2827, 2828, + 2829, 2830, 2831, 2832, 2833, 2834, 2835, 2836, 2837, 2838, + 2839, 2840, 2841, 2842, 2843, 2844, 2845, 2846, 2847, 2848, + 2849, 2850, 2851, 2852, 2853, 2854, 2855, 2856, 2857, 2858, + 2859, 2860, 2861, 0, 350, 348, 2434, 2459, 2466, 2467, + 2468, 2509, 2599, 2616, 2618, 2657, 2713, 2714, 2740, 2747, + 2790, 2808, 2809, 2810, 2822, 0, 0, 1289, 0, 0, + 387, 862, 863, 893, 895, 917, 1016, 1050, 0, 883, + 884, 0, 818, 0, 1784, 433, 0, 2485, 0, 0, + 444, 2799, 0, 0, 815, 427, 428, 429, 430, 431, + 432, 0, 0, 0, 1246, 0, 0, 2830, 423, 0, + 0, 83, 490, 705, 0, 0, 0, 0, 0, 795, + 795, 1135, 1135, 0, 735, 0, 0, 0, 795, 0, + 750, 742, 0, 0, 0, 795, 0, 0, 1039, 0, + 1039, 0, 798, 805, 795, 795, -2, 795, 795, 0, + 790, 795, 0, 0, 0, 756, 757, 758, 742, 742, + 761, 762, 763, 773, 774, 806, 2402, 0, 0, 381, + 2602, 2821, 1845, 0, 0, 0, 0, 0, 237, 1433, + 239, 1435, 243, 251, 0, 0, 0, 256, 257, 260, + 261, 262, 263, 264, 0, 268, 0, 270, 273, 0, + 275, 276, 0, 279, 280, 281, 0, 291, 292, 293, + 1436, 1437, 1438, 1439, 1440, 1441, 1442, 1443, -2, 0, + 164, 1287, 2357, 2224, 0, 2230, 2247, 2264, 1938, 1939, + 1940, 1941, 0, 0, 0, 0, 0, 0, 0, 1951, + 1952, 0, 1998, 2875, 2919, 2920, 0, 1962, 1963, 1964, + 1965, 1966, 1967, 0, 175, 189, 190, 2288, 2289, 2290, + 2291, 2292, 2293, 2294, 0, 2296, 2297, 2298, 0, 1923, + 1841, 0, 2884, 2894, 0, 2908, 2915, 2916, 2917, 2918, + 2907, 0, 0, 2177, 0, 2167, 0, 0, -2, -2, + 0, 0, 2685, -2, 2921, 2922, 2923, 2881, 2904, 2912, + 2913, 2914, 2885, 2924, 2925, 2888, 2911, 2877, 2878, 2879, + 2872, 2873, 2874, 2876, 2890, 2892, 2903, 0, 2899, 2909, + 2910, 2797, 0, 0, 2848, 2886, 2887, 0, 0, 0, + 0, 0, 0, 2857, 2858, 2859, 2860, 2861, 2843, 191, + 192, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, 2188, -2, 2190, + -2, 2192, -2, -2, 2195, -2, -2, -2, -2, -2, + 2201, 2202, -2, -2, 2205, -2, -2, -2, -2, -2, + -2, -2, 2179, 2180, 2181, 2182, 2171, 2172, 2173, 2174, + 2175, 2176, -2, -2, -2, 2358, 1016, 0, 0, 1050, + 1177, 0, 1050, 1048, 1017, 0, 0, 1020, 1097, 1100, + 1103, 1106, 0, 0, 134, 135, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 376, + 377, 365, 367, 0, 371, 0, 0, 367, 364, 358, + 0, 1510, 1510, 1510, 0, 0, 1510, 0, 0, 0, + 1510, 1510, 1510, 1510, 1510, 0, 1510, 0, 0, 0, + 1510, 0, 1334, 1445, 1446, 1447, 1448, 1508, 1509, 1625, + 0, 0, 0, 0, 2750, 969, 2586, 0, 0, 977, + 1032, 0, 1034, 1037, 878, 874, 875, 876, 877, 0, + 0, 0, 638, 638, 0, 638, 0, 0, 638, 0, + 638, 638, 638, 0, 880, 2548, 2652, 2502, 2623, 2444, + 2602, 2821, 0, 323, 2685, 328, 0, 2508, 2552, 0, + 0, 2573, 0, -2, 0, 404, 1050, 0, 1017, 1041, + 0, 1051, 0, 0, 1016, 1050, 1050, 0, 1090, 0, + 0, 638, 638, 0, 0, 638, 638, 638, 638, 638, + 0, 638, 638, 638, 0, 638, 0, 638, 0, 638, + 638, 638, 0, 1111, 1112, 1114, 1115, 1116, 1117, 1118, + 1119, 1120, 1121, 1122, 1123, 1084, 4, 5, 18, 0, + 0, 0, 0, 0, 0, 140, 139, 0, 2361, 2397, + 2301, 2302, 2303, 0, 2384, 2306, 2388, 2388, 2388, 2388, + 0, 2338, 2384, 2340, 2341, 2342, 2384, 2344, 2345, 2346, + 2347, 2388, 2388, 2388, 2388, 2388, 2388, 0, 0, 2356, + 2327, 2386, 2386, 2386, 2384, 2363, 2307, 2308, 2309, 2310, + 2311, 2312, 2313, 2314, 2315, 2316, 2317, 2318, 2319, 2320, + 2391, 2391, 2394, 2394, 2391, 2364, 2365, 2366, 2367, 2368, + 2369, 2370, 2371, 2372, 2373, 2374, 2375, 2376, 2377, 2378, + 2379, 2380, 2381, 0, 495, 493, 494, 2220, 0, 0, + 0, 1050, -2, 0, 1048, 967, 0, 819, 1775, 0, + 0, 434, 1846, 0, 0, 0, 446, 0, 0, 0, + 448, 0, 0, 445, 0, 0, 470, 0, 473, 456, + 457, 458, 459, 460, 452, 0, 217, 0, 425, 426, + 422, 0, 479, 481, 483, 486, 1771, 80, 84, 87, + 0, 1039, 0, 707, 795, 795, 795, 795, 723, 724, + 725, 0, 1135, 0, 0, 728, 729, 0, 730, 0, + 0, 742, 795, 795, 748, 749, 744, 743, 801, 802, + 798, 0, 798, 798, 1135, 0, 767, 768, 769, 795, + 795, 775, 1040, 0, 0, 777, 779, 798, 0, 803, + 804, 1135, 0, 0, 1135, 1135, 0, 787, 788, 0, + 791, 795, 0, 794, 0, 0, 1510, 0, 811, 744, + 744, 2403, 2404, 383, 0, 0, 0, 639, 0, 0, + 0, 0, 0, 0, 248, 244, 252, 255, 265, 272, + 0, 284, 286, 289, 245, 253, 258, 259, 266, 287, + 246, 249, 250, 254, 288, 290, 247, 267, 271, 285, + 269, 274, 277, 278, 283, 0, 218, 0, 0, 0, + 0, 0, 2229, 0, 0, 2274, 2275, 2276, 2277, 2278, + 2279, 2280, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2267, + 0, 0, 0, 0, 0, 0, 0, -2, 2224, 0, + 0, 1945, 1946, 1947, 1948, 1949, 0, 1953, 0, 1999, + 0, 0, 0, 0, 0, 0, 2295, 2299, 0, 0, + 2220, 2220, 0, 0, 2220, 2216, 0, 0, 0, 0, + 0, 0, 2220, 2150, 0, 0, 2152, 2168, 0, 0, + 2154, 2155, 0, 2158, 2159, 2220, 0, 2220, 2163, 2220, + 2220, 2220, 2144, 2145, 0, 0, 0, 2216, 0, 0, + 2216, 2216, 2216, 0, 0, 2216, 2216, 2216, 2216, 2216, + 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216, 2216, + 2216, 2216, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1050, 1016, 1041, 0, 0, -2, + 0, 978, 0, 1048, 1074, 1076, 1078, 1080, 1047, 1022, + 0, 1098, 1099, 1101, 1102, 1104, 1105, 1107, 1108, 0, + 136, 0, 0, 0, 115, 0, 0, 112, 0, 0, + 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 369, 0, 374, 360, 2645, + 0, 359, 0, 0, 0, 0, 1510, 1510, 0, 0, + 1286, 0, 0, 1510, 1510, 1335, 0, 0, 0, 0, + 0, 0, 0, 0, 1510, 1510, 1510, 0, 1528, 0, + 0, 0, 0, 902, 904, 899, 0, 0, 902, 0, + 0, 969, 969, 976, 0, 1033, 0, 0, 880, 879, + 0, 1150, 1151, 1152, 1193, 1236, 1236, 0, 1236, 1197, + 0, 1784, 0, 0, 0, 0, 1522, 0, 0, 0, + 0, 0, 0, 0, 620, 814, 621, 0, 0, 2405, + 0, 0, 0, 523, 524, 0, 0, 881, 0, 302, + 306, 0, 309, 0, 2652, 0, 2652, 0, 0, 316, + 0, 0, 0, 0, 0, 0, 346, 347, 0, 0, + 0, 0, 337, 340, 1767, 1768, 1430, 1431, 341, 342, + 396, 397, 0, 1041, 1073, 1075, 1077, 1079, 999, 1042, + 1043, 1083, 1085, 1086, 1087, 0, 0, 1068, 1069, 1041, + 1041, 0, 1092, 0, 0, 0, 638, 638, 0, 0, + 0, 0, 0, 638, 0, 0, 0, 856, 0, 858, + 0, 0, 638, 0, 0, 0, 978, 1137, 1139, 1241, + 175, 1113, 7, 157, 154, 0, 18, 0, 0, 18, + 18, 0, 18, 351, 0, 2400, 2398, 2399, 0, 2305, + 2385, 0, 2332, 0, 2333, 2334, 2335, 2336, 2337, 2339, + 2343, 2348, 2349, 2350, 2351, 2352, 2353, 0, 0, 2328, + 0, 2329, 2330, 2331, 2321, 2391, 0, 2323, 2324, 0, + 2325, 2326, 349, 492, 0, 0, 2221, 1290, 0, 0, + 1041, 1012, 1048, 0, 1048, 978, 0, 0, 638, 1773, + 0, 1784, 0, 0, 0, 0, 0, 435, 0, 0, + 461, 462, 0, 447, 0, 454, 0, 449, 450, 453, + 0, 0, 472, 474, 475, 476, 477, 816, 419, 420, + 421, 405, 406, 407, 408, 409, 410, 411, 412, 413, + 0, 415, 416, 417, 418, 0, -2, 0, 0, 424, + 185, 478, 0, 480, 0, 485, 0, 487, 0, 88, + 489, 0, 709, 0, 1135, 0, 0, 1135, 1135, 0, + 0, 1135, 0, 727, 796, 797, 1136, 731, 0, 0, + 739, 2177, 2602, 1422, 744, 1135, 1135, 751, 745, 752, + 800, 753, 754, 755, 798, 1135, 1135, 1044, 0, 795, + 798, 780, 799, 798, 1784, 784, 0, 789, 792, 793, + 1784, 812, 1784, 0, 810, 759, 760, 384, 385, 0, + 0, 0, 231, 232, 233, 234, 235, 236, 238, 222, + 847, 849, 1434, 0, 1425, 0, 241, 282, 214, 0, + 0, 0, 0, 2225, 2226, 2227, 2228, 2233, 0, 0, + 2236, 2239, 2242, 2245, 0, 2271, -2, -2, 1924, 1925, + 1926, 1927, 1928, 1929, 1930, 1931, 1932, 1933, 1934, 1935, + 1936, 1937, 2248, 2269, 2270, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2268, 2265, 2265, + 2258, 0, 1942, 1959, 2003, 2017, 2017, 1968, 1769, 1770, + 1943, 0, 0, 1996, 2000, 0, 0, 0, 0, 0, + 0, 1488, 2384, 0, 176, 2264, 2215, 2111, 2112, 2113, + 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123, + 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, + 2134, 2135, 2136, 2137, 2138, 2139, 0, 0, 2224, 0, + 0, 0, 0, 2217, 2218, 0, 0, 0, 2099, 0, + 0, 2105, 2106, 2107, 0, 1838, 0, 2178, 2151, 2169, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2140, 2141, 2142, 2143, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1041, 1050, 1176, + 1178, 0, 963, 965, 966, 1006, 1048, 1048, 1008, 0, + 978, 1024, 0, 0, 0, 132, 137, 0, 1592, 123, + 0, 0, 0, 123, 0, 0, 0, 123, 0, 0, + 0, 1406, 1524, 89, 1405, 1526, 0, 0, 0, 0, + 0, 0, 0, 378, 379, 0, 0, 373, 361, 2645, + 363, 0, 0, 0, 0, 0, 0, 0, 1273, 0, + 0, 0, 1304, 0, 0, 0, 1350, 1351, 0, 636, + 1416, 0, 0, 0, 1432, 1492, 1506, 0, 0, 0, + 1598, 1336, 1341, 1342, 1343, 1337, 1338, 1344, 1345, 896, + 905, 0, 900, 0, 906, 0, 0, 939, 959, 934, + 0, 943, 0, 0, 0, 1035, 0, 0, 1191, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1183, 0, + 0, 0, 1182, 0, 0, 0, 0, 0, 0, 0, + 1037, 1237, 0, 1239, 1240, 1195, -2, 0, 1146, 1148, + 0, 1219, 0, 2220, 0, 0, 1600, 1037, 520, 521, + 522, 532, 593, 534, 0, 593, 593, 593, 576, 0, + 0, 564, 2405, 0, 0, 0, 0, 573, 2405, 0, + 0, 2405, 2405, 2405, 2405, 2405, 2405, 2405, 2405, 0, + 0, 2405, 2405, 2405, 2405, 2405, 2405, 2405, 2405, 2405, + 2405, 2405, 0, 2405, 2405, 2405, 2405, 2405, 1753, 2405, + 0, 1523, 583, 584, 585, 586, 591, 592, 0, 0, + 537, 538, 0, 0, 0, 0, 0, 631, 0, 0, + 1349, 619, 0, 622, 2405, 0, 2405, 0, 2406, 636, + 0, 0, 1394, 0, 0, 1148, 0, 0, 0, 0, + 314, 315, 303, 0, 304, 0, 0, 317, 318, 0, + 320, 321, 322, 329, 2502, 2623, 324, 326, 0, 0, + 330, 343, 344, 345, 0, 0, 335, 336, 0, 0, + 399, 400, 402, 0, 1048, 1088, 1054, 1055, 1058, 0, + 0, 1091, 1093, 1094, 1095, 1096, 1525, 1513, 85, 86, + 2830, 841, 0, 0, 844, 845, 846, 850, 0, 0, + 1626, 854, 855, 0, 0, 1403, 0, 1407, 1409, 1513, + 1143, 0, 1140, 1242, 0, 1244, 0, 0, 155, 18, + 0, 148, 145, 0, 0, 0, 0, 0, 2362, 2300, + 2401, 0, 0, 0, 0, 2382, 0, 0, 2322, 0, + 0, 0, 138, 161, 985, 1048, 978, 0, 980, 187, + 978, 1014, 914, 959, 887, 0, 943, 0, 0, 0, + 0, 0, 1775, 0, 0, 0, 0, 1847, 0, 439, + 438, 0, 0, 455, 0, 0, 451, 471, 0, 414, + 0, 0, 0, 482, 0, 1772, 488, 491, 706, 0, + 708, 711, 795, 0, 714, 715, 795, 0, 0, 721, + 726, 734, 732, 0, 736, 0, 739, 738, 0, 1424, + 795, 746, 747, 1135, 770, 771, 0, 0, 0, 1135, + 795, 795, 783, 798, 807, 0, 808, 1784, 0, 225, + 1419, 0, 226, 230, 220, 0, 0, 0, 1421, 1426, + 0, 240, 0, 0, 215, 216, 1583, 1592, 0, 0, + 0, 163, 2234, 2237, 2240, 2243, 2235, 2238, 2241, 2244, + 2246, 0, 2249, 2265, 2265, 2259, 0, 2250, 2265, 2265, + 2260, 0, 0, 2252, 0, 2255, 0, 2004, 2018, 2019, + 2005, 2225, 1950, 0, 2001, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1058, 0, 0, 0, 2087, 2089, + 0, 0, 0, 2094, 0, 2096, 2097, 2098, 2100, 0, + 0, 0, 2104, 0, 2149, 2170, 2153, 2156, 0, 2160, + 0, 2162, 2164, 2165, 2166, 0, 0, 0, 1050, 1052, + 1052, 1050, 0, 0, 2044, 2044, 1052, 0, 0, 0, + 0, 2044, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1973, 0, 1974, 1975, + 1976, 0, 1978, 2926, 0, 2926, 0, 2926, 2926, 0, + 0, 0, 1048, 1041, 0, 1179, 978, 978, 0, 1009, + 1018, 0, 0, 0, 0, 0, 0, 1590, 0, 108, + 0, 0, 0, 116, 0, 111, 117, 0, 0, 113, + 0, 0, 125, 90, 0, 0, 1531, 1532, 0, 0, + 0, 380, 368, 370, 0, 362, 0, 1511, 1512, 0, + 0, 0, 1672, 1682, 1277, 0, 0, -2, 1306, 0, + 1037, 1037, 1361, 2405, 0, 640, 0, 0, 1418, 0, + 1383, 0, 0, 1493, 0, -2, 0, 0, -2, 0, + 0, 1602, 0, 897, 903, 0, 0, 0, 898, 914, + 940, 0, 933, 956, 0, 960, 0, 0, 947, 949, + 938, 944, 0, 0, 0, 974, 914, 914, 23, 1038, + 0, 0, 0, 867, 871, 0, 1187, 1187, 1187, 1156, + 0, 0, 1159, 1184, 1160, 1185, 0, 0, 1164, 0, + 1166, 0, 1168, 0, 1162, 1163, 1170, 1171, 0, 1161, + 1194, 1238, 0, 1196, 0, 1218, 1220, 1221, 1227, 0, + 0, 0, 0, 0, 0, 0, 516, 517, 1602, 0, + 0, 1522, 1636, 554, 0, 1797, 1798, 594, 0, 1805, + 1814, 1814, 1510, 1887, 0, 1814, 0, 0, 1816, 1817, + 1669, 0, 0, 563, 0, 0, 0, 0, 0, 0, + 0, 577, 578, 0, 0, 562, 0, 0, 604, 0, + 0, 0, 0, 0, 0, 2405, 2405, 0, 571, 572, + 0, 575, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2405, 2405, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1744, 0, 0, 0, 0, 0, + 0, 0, 1759, 1760, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1361, 2405, 0, 0, 0, 0, 0, + 2405, 0, 625, 640, 1413, 1413, 1381, 1399, 0, 525, + 526, 601, 0, 0, 0, 307, 308, 0, 0, 313, + 331, 333, 305, 0, 0, 0, 332, 334, 338, 339, + 398, 401, 403, 978, 0, 1061, 1059, 1060, 1081, 1089, + 82, 1514, 842, 843, 0, 1626, 853, 1627, 1628, 1306, + 859, 1404, 0, 1411, 1135, 1144, 0, 1138, 1243, 1245, + 176, 1141, 0, 158, 18, 157, 149, 150, 0, 18, + 0, 0, 0, 0, 2304, 2390, 2389, 2354, 0, 2355, + 2387, 2392, 0, 2395, 0, 496, 0, 989, 0, 978, + 1015, 981, 0, 1013, 885, 0, 886, 0, 0, 891, + 0, 974, 1408, 1776, 1777, 0, 1780, 1781, 1782, 1783, + 1774, 0, 0, 0, 0, 0, 0, 0, 440, 441, + 442, 443, 817, 0, 186, 484, 710, 1135, 795, 1135, + 0, 795, 795, 722, 1679, 1680, 733, 740, 737, 1423, + 1135, 764, 1045, 1046, 776, 778, 1784, 1135, 1135, 795, + 813, 809, 0, 0, 0, 0, 0, 848, 0, 222, + 0, 0, 242, 0, 0, 0, 1592, 1587, 2219, 2253, + 2256, 0, 2254, 2257, 0, 0, 2266, 2261, 1944, 1954, + 1997, 0, 0, 2388, 0, 0, 0, 2006, 2007, 2388, + 2388, 2011, 2384, 2386, 2384, 2017, 2017, 0, 1489, 0, + 1490, 1058, 177, 0, 0, 0, 0, 2044, 0, 0, + 0, 1839, 0, 0, 0, 0, 0, 2040, 2044, 0, + 2044, 2042, 2044, 2044, 2062, 2045, 2063, 2044, 2044, 2044, + 2044, 2044, 2069, 2044, 2044, 2044, 2044, 2044, 2044, 2044, + 2044, 0, 2044, 2044, 2044, 2044, 0, 2046, 2049, 1977, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2289, 2290, 978, 1048, 964, 1010, 1007, 0, 0, 0, + 0, 0, 71, 71, 1592, 0, 0, 109, 121, 122, + 0, 0, 0, 0, 131, 0, 0, 0, 0, 0, + 0, 0, 1540, 1548, 0, 372, 0, 91, 92, 94, + 0, 0, 0, 0, 0, 0, 0, 107, 1270, 0, + 1271, 0, 1281, 0, 1275, 0, 0, 1292, 1293, 1295, + 0, 1298, 1299, 1300, 0, 1307, 1308, 1310, 1311, 0, + 2416, -2, -2, 2549, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, 2476, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, 1305, 0, + 0, 1365, 1362, 1363, 1364, 0, 0, 1413, 641, 642, + 643, 644, 0, 0, 0, 1417, 0, 0, 0, 1374, + 0, 0, 0, 1494, 1495, 1496, 1497, 1498, 1499, 1500, + 1501, 1502, 1503, -2, 1517, 0, 1784, 0, 0, 1790, + 1572, 0, 0, 0, 1579, 0, 0, 1003, 0, -2, + -2, 1790, 1570, 2405, 1790, 1610, 0, 1599, 0, 0, + 901, 910, 0, 959, 961, 0, 0, 959, 0, 0, + 0, 970, 0, 971, 0, 0, 911, 912, 914, 0, + 1192, 967, 0, -2, 0, 0, 869, 0, 0, 1153, + 1188, 0, 0, 1154, 1155, 1157, 1174, 1186, 0, 1180, + 1165, 1167, 1169, 1172, 0, 1147, 0, 1222, 0, 0, + 1224, 1225, 1226, 0, 1199, 512, 0, 1674, 0, 1677, + 1678, 514, 0, 1684, 0, 1687, 1688, 1610, 1601, 0, + 533, 593, 593, 0, 547, 0, 595, 0, 0, 1804, + 1835, 1815, 1835, 1835, 1888, 1835, 1835, 1510, 0, 1657, + 0, 0, 1663, 0, 1670, 0, 0, 0, 0, 0, + 595, 0, 0, 565, 561, 598, 1058, 548, 550, 551, + 552, 602, 603, 605, 0, 607, 608, 609, 567, 579, + 580, 581, 582, 0, 0, 0, 574, 587, 588, 589, + 590, 549, 1720, 1721, 1722, 1723, 1726, 1727, 1728, 1729, + 0, 0, 1732, 1733, 1734, 1735, 1736, 1832, 1833, 1834, + 1737, 1738, 1739, 1740, 1741, 1742, 1743, 1761, 1762, 1763, + 1764, 1765, 1766, 1745, 1746, 1747, 1748, 1749, 1750, 1751, + 1752, 0, 0, 1756, 0, 0, 1275, 0, 541, 542, + 0, 544, 0, 0, 1365, 0, 0, 0, 0, 0, + 623, 0, 626, 1413, 634, 0, 0, 635, 1383, 0, + 1401, 0, 1395, 1396, 0, 0, 931, 1135, 391, 0, + 1135, 301, 310, 311, 312, 319, 0, 660, 325, 1064, + 1056, 1057, 0, 851, 852, 0, 0, 1126, 1145, 0, + 153, 156, 0, 151, 0, 0, 0, 0, 143, 141, + 2383, 0, 0, 162, 991, 202, 0, 0, 1064, 983, + 0, 188, 915, 0, 959, 968, 0, 1785, 1786, 1787, + 1788, 0, 1848, 436, 0, 712, 1135, 716, 795, 1135, + 1135, 0, 741, 781, 785, 782, 1135, 0, 1420, 222, + 227, 228, 229, 223, 221, 1427, 0, 1429, 0, 1585, + 0, 0, 2262, 2263, 2251, 2002, 1955, 2332, 0, 1958, + 1960, 2008, 2009, 2012, 2013, 2014, 2015, 2016, 1961, 0, + 1491, 2088, 2090, 0, 2092, 2093, 2095, 2101, 2102, 0, + 0, 2157, 2161, 0, 0, 2148, 0, 0, 2057, 0, + 2058, 0, 0, 2060, 2061, 2064, 2065, 2066, 2067, 2068, + 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2077, 0, 2079, + 2080, 2081, 2082, 0, 0, 2038, 2050, 1979, 2927, 2926, + 0, 1982, 2926, 0, 1985, 1986, 2928, 0, 0, 0, + 0, 0, 0, 1064, 978, 1049, 0, 0, 1027, 1028, + 1029, 1030, 1031, 1023, 0, 0, 73, 0, 73, 1591, + 1593, 124, 126, 0, 0, 118, 119, 120, 0, 0, + 0, 1241, 1554, 1784, 1542, 0, 1534, 0, 1548, 0, + 0, 0, 93, 0, 95, 0, 2606, 0, 0, 0, + 0, 1513, 0, 0, 1283, 0, 0, 1274, 0, 1285, + 1301, 1297, 0, 0, 0, 1312, 0, 0, 1332, 0, + 0, 1353, 1354, 1355, 1379, 1367, 0, 646, 647, 0, + 0, 0, 659, 655, 656, 657, 637, 1412, 1390, 0, + 0, 1390, 1377, 0, 0, 1389, 0, 1518, 2405, 2405, + 2405, 1554, 0, 0, 0, 1791, 1792, 1794, 1795, 1796, + 1574, 0, 1578, 1556, 0, 1050, 0, 0, 0, 1613, + 0, 0, 1604, 0, 0, 908, 0, 957, 0, 962, + 959, 937, 948, 936, 950, 945, 946, 975, 0, 972, + 913, 1036, 1236, 0, 0, 1135, 868, 871, 872, 0, + 1189, 0, 1158, 0, 1181, 1173, 1149, 1231, 1228, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1613, 519, + 0, 0, 1638, 0, 566, 596, 0, 0, 2932, -2, + 0, 1836, 0, 0, 1818, 1836, 0, 0, 1835, 0, + 1634, 0, 0, 0, 0, 0, 1667, 0, 1450, 1450, + 1450, 1450, 1450, 0, 0, 610, 0, 614, 615, 612, + 1882, 0, 0, 613, 555, 595, 0, 0, 600, 0, + 606, 1724, 1725, 0, 1730, 1731, 0, 1755, 0, 0, + 536, 539, 0, 1279, 1280, -2, 0, 0, 0, 618, + 0, 0, 0, 627, 628, 624, 633, 1414, 1415, 1374, + 0, 1390, 0, 1400, 0, 1397, 1398, 1050, 0, 0, + 0, 914, 327, 1005, 0, 0, 1062, 1063, 857, 0, + 1124, 0, 1142, 0, 18, 0, 0, 146, 2393, 2396, + 993, 0, 990, 203, 0, 0, 0, 1011, 985, 0, + 982, 959, 890, 889, 0, 1779, 1789, 713, 1135, 718, + 719, 0, 786, 224, 219, 1428, 1595, 0, 1586, 0, + 0, 0, 1907, 1970, 1971, 1972, 0, 2103, 1840, 0, + 0, 1052, 2041, 0, 2044, 2043, 0, 2044, 2047, 1050, + 2039, 0, 0, 0, 0, 0, 2926, 0, 1988, 0, + 1990, 1991, 1992, 0, 1994, 1995, 2359, 1064, 1025, 0, + 1021, 0, 69, 0, 72, 70, 110, 0, 114, 0, + 0, 130, 1529, 0, 1554, 1533, 0, 0, 0, 1535, + 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, + 0, 0, 105, 0, 0, 0, 0, 1282, 0, 1276, + 0, 0, 1294, 1296, 0, 1309, 0, 1339, 1339, 1366, + 1352, 0, 1333, 0, 0, 648, 649, 0, 652, 658, + 1368, 0, 0, 1371, 1372, 1370, 1373, 0, 0, 1387, + 0, 0, 0, 0, 1504, 0, 1507, -2, 0, 1576, + 1554, 0, 0, 1041, 0, 1672, -2, 1619, 0, 1611, + 0, 1603, 0, 1606, 907, 0, 0, 942, 958, 935, + 0, 0, 1135, 1135, -2, 914, 870, 0, 918, 920, + 0, 0, 1175, 0, 0, 1232, 1234, 1229, 1230, 0, + 1675, 513, 1676, 1685, 515, 1686, 1689, 1690, 1619, 0, + 1637, 0, 1651, 597, 2930, 0, 1837, -2, 1851, 1853, + 0, 0, 1523, 1857, 1858, 0, 0, 0, 0, 0, + 0, 0, 0, 1915, 1868, 0, 0, 0, 1873, 1874, + 1875, 0, 0, 0, 0, 2283, 2284, 0, 1886, 0, + 0, 0, 0, 0, 0, 0, 0, 1812, 1636, 0, + 1658, 0, 0, 0, 0, 0, 0, 0, 527, 528, + 529, 530, 531, 0, 559, 560, 1450, 0, 1883, 1884, + 556, 557, 599, 553, 2405, 569, 1754, 1757, 1758, 540, + 543, 0, 0, 632, 629, 630, 1377, 1382, 1393, 1402, + 932, 1039, 1135, 392, 393, 389, 1065, 1066, 0, 1410, + 2051, 0, 0, 147, 152, 0, 0, 995, 0, 992, + 0, 986, 988, 213, 989, 984, 888, 1778, 717, 795, + 171, 205, 0, 0, 0, 1957, 0, 0, 0, 0, + 2091, 2146, 2147, 2044, 0, 2059, 2044, 2083, 2035, 0, + 1980, 2926, 1983, 2926, 0, 2929, 0, 0, 2360, 0, + 1019, 74, 128, 127, 0, 0, 1530, 0, 0, 0, + 1546, 1547, 0, 1549, 1550, 1551, 0, 0, 0, 0, + 78, 0, 0, 0, 1513, 0, 1513, 0, 0, 0, + 1673, 1683, 0, 1284, 1278, 1288, 1302, 0, 1315, 1313, + 1331, 1346, 1330, 0, 0, 0, 645, 650, 0, 653, + 654, 1391, 1390, 0, 1375, 1376, 0, 1385, 0, 0, + 1519, 1520, 1521, 1379, 1629, 1573, 0, 0, -2, 1717, + 0, 1793, 1580, 1557, 0, 1004, 1564, 1565, 1566, 1567, + 1568, 1569, 1595, 2405, 1671, 1629, 1607, 0, 1614, 0, + 1612, 1605, 0, 941, 951, 973, 1050, 914, 865, 0, + 921, 929, 0, 0, 928, 1190, 1223, 0, 0, 1616, + 0, 1639, -2, 0, 2933, 1852, 1854, 1855, 1856, 1859, + 1860, 1861, 1862, 1863, 1920, 1921, 1922, 0, 0, 1866, + 1917, 1918, 1919, 1867, 0, 0, 0, 1872, 0, 0, + 0, 2281, 2282, 1913, 0, 0, 0, 1819, 1821, 1822, + 1823, 1824, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1820, + 0, 0, 0, 1811, 1813, 535, 1669, 1659, 0, 1661, + 0, 0, 0, 0, 1451, 2405, 2405, 0, 0, 0, + 1461, 1462, 2405, 2405, 2405, 2405, 2405, 2405, 0, 0, + 0, 2405, 2405, 2405, 2405, 2405, 2405, 0, 1480, 1481, + 1482, 0, 2405, 2405, 2405, 558, 611, 0, 0, 2405, + 0, 0, 1392, 914, 914, 0, 1109, 0, 1125, 1133, + 2848, 2850, 2847, 142, 144, 159, 0, 994, 204, 0, + 991, 1135, 173, 0, 196, 0, 1596, 0, 0, 2010, + 1969, 0, 0, 0, 0, 2056, 1053, 2078, 2048, 2036, + 0, 2030, 2031, 2032, 2037, 0, 0, 1987, 1989, 1993, + 1026, 0, 1555, 1543, 1544, 1545, 1541, 0, 0, 1552, + 1553, 0, 76, 0, 99, 0, 0, 100, 1513, 101, + 1513, 0, 0, 1272, 0, 0, 1347, 1348, 1356, 1357, + 0, 1359, 1360, 1380, 651, 1369, 1378, 1384, 1387, 0, + 1452, 1505, 1631, 0, 1575, 0, 1522, 1719, 2405, 1379, + 1582, 0, 1631, 1597, 0, 1609, 0, 1621, 0, 1615, + 0, 1039, 866, 919, 0, 0, 929, 929, 1233, 1235, + 0, 1200, 0, -2, 518, 0, 1618, 2931, 1640, -2, + 0, 1648, 1650, 0, 0, 1864, 1865, 0, 0, 2167, + 2405, 0, 0, 1902, 0, 1450, 1450, 1450, 1450, 1450, + 0, 1655, 1660, 1662, 1664, 0, 1668, 1666, 0, 0, + 1458, 1459, 0, 0, 0, 0, 0, 0, 0, 0, + 1470, 1471, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 616, 617, 568, 0, 0, 546, 388, + 390, 1067, 2052, 2053, 0, 1127, 0, 0, 0, 0, + 0, 0, 993, 720, 160, 0, 172, 193, 0, 206, + 207, 0, 0, 0, 0, 1588, 1956, 0, 1910, 1912, + 1911, 2033, 0, 0, 0, 0, 0, 0, 2285, 2286, + 2287, 1981, 1984, 129, 1548, 1548, 1513, 78, 0, 98, + 0, 102, 103, 0, 1513, 0, 1314, 0, 1358, 1386, + 1388, 1449, 1563, 0, 1669, 1577, 1718, 0, 1581, 1682, + 1692, 1706, 1699, 1704, 1705, 1571, 1608, 1620, 0, 1623, + 909, 914, 0, 930, 0, 0, 0, 0, 0, 0, + 0, 1207, 1617, 1641, 1649, 0, 1644, 0, 0, 0, + 1916, 0, 1871, 0, 0, 1879, 1890, 1903, 0, 0, + 1799, 0, 1801, 1802, 0, 1806, 0, 1808, 0, 0, + 1635, 0, 1665, 1456, 1457, 1460, 1463, 1464, 1465, 1466, + 1467, 1468, 0, 1472, 1473, 1474, 1475, 1476, 1477, 1478, + 1479, 1483, 1484, 1485, 1486, 1487, 570, 545, 0, 0, + 1134, 0, 0, 0, 0, 997, 987, 995, 174, 178, + 0, 202, 199, 0, 208, 0, 0, 0, 0, 1584, + 0, 1908, 0, 2020, 0, 0, 0, 0, 2025, 2026, + 2027, 2028, 2029, 1536, 1548, 1537, 1548, 75, 77, 79, + 97, 1513, 104, 0, 1316, 1317, 1340, 1453, 1454, 1455, + 0, 1657, 1724, 1681, 1691, 0, 1697, 0, 1698, 0, + 1622, 864, 0, 923, 0, 0, 1198, 1201, 1202, 0, + 0, 0, 1643, 0, -2, 1652, 0, 0, 2222, 2231, + 2232, 1869, 1876, 0, 1878, 1880, 1881, 1889, 1891, 1892, + 0, 1904, 1905, 1906, 1914, 1450, 1450, 1450, 1450, 1810, + 1656, 1469, 2054, 2049, 0, 2220, 1129, 1130, 996, 0, + 979, 165, 0, 0, 197, 198, 200, 0, 209, 0, + 211, 212, 0, 0, 0, 2021, 2022, 2023, 2024, 1538, + 1539, 106, 1318, 1632, 0, 1634, 0, 0, 0, 0, + 0, 0, 1211, 0, 0, 1645, -2, 0, 1654, 0, + 1870, 1879, 1893, 0, 1894, 0, 0, 0, 1800, 1803, + 1807, 1809, 0, 1128, 0, 0, 998, 1594, 0, 179, + 0, 181, 183, 184, 194, 195, 201, 210, 0, 0, + 2034, 1321, 1319, 0, 0, 1636, 0, 1694, 0, 1711, + 1712, 0, 1708, 0, 0, 1701, 0, 922, 0, 0, + 0, 0, 1203, 0, 1208, 1209, 0, 1204, 0, 1653, + 2223, 1877, 1895, 1897, 1898, 0, 0, 1896, 2055, 2220, + 1131, 166, 167, 0, 180, 0, 1589, 1909, 1303, 0, + 1323, 0, 0, 1320, 1633, 1630, 1693, 0, 0, 1707, + 0, 0, 1700, 0, 0, 0, 952, 0, 0, 0, + 0, 1210, 0, 1899, 1901, 1900, 0, 0, 0, 182, + 1322, 1326, 1327, 0, 0, 0, 1695, 1696, 1713, 1714, + 1709, 1710, 1702, 1703, 0, 0, 0, 0, 0, 0, + 1216, 1214, 1205, 1132, 168, 169, 170, 1324, 1325, 0, + 0, 0, 954, 953, 926, 0, 927, 1212, 0, 1213, + 0, 1328, 0, 0, 0, 0, 0, 0, 1329, 0, + 955, 0, 1217, 1215, 924, 925, +} + +var yyTok1 = [...]int{ + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 129, 3, 3, 3, 162, 152, 3, + 96, 97, 159, 157, 183, 158, 182, 160, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 793, 790, + 139, 138, 140, 3, 794, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 164, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 791, 151, 792, 165, +} + +var yyTok2 = [...]int{ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, + 92, 93, 94, 95, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 130, 131, 132, 133, 134, + 135, 136, 137, 141, 142, 143, 144, 145, 146, 147, + 148, 149, 150, 153, 154, 155, 156, 161, 163, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 184, 185, 186, 187, 188, + 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, + 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, + 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, + 269, 270, 271, 272, 273, 274, +} + +var yyTok3 = [...]int{ + 57600, 275, 57601, 276, 57602, 277, 57603, 278, 57604, 279, + 57605, 280, 57606, 281, 57607, 282, 57608, 283, 57609, 284, + 57610, 285, 57611, 286, 57612, 287, 57613, 288, 57614, 289, + 57615, 290, 57616, 291, 57617, 292, 57618, 293, 57619, 294, + 57620, 295, 57621, 296, 57622, 297, 57623, 298, 57624, 299, + 57625, 300, 57626, 301, 57627, 302, 57628, 303, 57629, 304, + 57630, 305, 57631, 306, 57632, 307, 57633, 308, 57634, 309, + 57635, 310, 57636, 311, 57637, 312, 57638, 313, 57639, 314, + 57640, 315, 57641, 316, 57642, 317, 57643, 318, 57644, 319, + 57645, 320, 57646, 321, 57647, 322, 57648, 323, 57649, 324, + 57650, 325, 57651, 326, 57652, 327, 57653, 328, 57654, 329, + 57655, 330, 57656, 331, 57657, 332, 57658, 333, 57659, 334, + 57660, 335, 57661, 336, 57662, 337, 57663, 338, 57664, 339, + 57665, 340, 57666, 341, 57667, 342, 57668, 343, 57669, 344, + 57670, 345, 57671, 346, 57672, 347, 57673, 348, 57674, 349, + 57675, 350, 57676, 351, 57677, 352, 57678, 353, 57679, 354, + 57680, 355, 57681, 356, 57682, 357, 57683, 358, 57684, 359, + 57685, 360, 57686, 361, 57687, 362, 57688, 363, 57689, 364, + 57690, 365, 57691, 366, 57692, 367, 57693, 368, 57694, 369, + 57695, 370, 57696, 371, 57697, 372, 57698, 373, 57699, 374, + 57700, 375, 57701, 376, 57702, 377, 57703, 378, 57704, 379, + 57705, 380, 57706, 381, 57707, 382, 57708, 383, 57709, 384, + 57710, 385, 57711, 386, 57712, 387, 57713, 388, 57714, 389, + 57715, 390, 57716, 391, 57717, 392, 57718, 393, 57719, 394, + 57720, 395, 57721, 396, 57722, 397, 57723, 398, 57724, 399, + 57725, 400, 57726, 401, 57727, 402, 57728, 403, 57729, 404, + 57730, 405, 57731, 406, 57732, 407, 57733, 408, 57734, 409, + 57735, 410, 57736, 411, 57737, 412, 57738, 413, 57739, 414, + 57740, 415, 57741, 416, 57742, 417, 57743, 418, 57744, 419, + 57745, 420, 57746, 421, 57747, 422, 57748, 423, 57749, 424, + 57750, 425, 57751, 426, 57752, 427, 57753, 428, 57754, 429, + 57755, 430, 57756, 431, 57757, 432, 57758, 433, 57759, 434, + 57760, 435, 57761, 436, 57762, 437, 57763, 438, 57764, 439, + 57765, 440, 57766, 441, 57767, 442, 57768, 443, 57769, 444, + 57770, 445, 57771, 446, 57772, 447, 57773, 448, 57774, 449, + 57775, 450, 57776, 451, 57777, 452, 57778, 453, 57779, 454, + 57780, 455, 57781, 456, 57782, 457, 57783, 458, 57784, 459, + 57785, 460, 57786, 461, 57787, 462, 57788, 463, 57789, 464, + 57790, 465, 57791, 466, 57792, 467, 57793, 468, 57794, 469, + 57795, 470, 57796, 471, 57797, 472, 57798, 473, 57799, 474, + 57800, 475, 57801, 476, 57802, 477, 57803, 478, 57804, 479, + 57805, 480, 57806, 481, 57807, 482, 57808, 483, 57809, 484, + 57810, 485, 57811, 486, 57812, 487, 57813, 488, 57814, 489, + 57815, 490, 57816, 491, 57817, 492, 57818, 493, 57819, 494, + 57820, 495, 57821, 496, 57822, 497, 57823, 498, 57824, 499, + 57825, 500, 57826, 501, 57827, 502, 57828, 503, 57829, 504, + 57830, 505, 57831, 506, 57832, 507, 57833, 508, 57834, 509, + 57835, 510, 57836, 511, 57837, 512, 57838, 513, 57839, 514, + 57840, 515, 57841, 516, 57842, 517, 57843, 518, 57844, 519, + 57845, 520, 57846, 521, 57847, 522, 57848, 523, 57849, 524, + 57850, 525, 57851, 526, 57852, 527, 57853, 528, 57854, 529, + 57855, 530, 57856, 531, 57857, 532, 57858, 533, 57859, 534, + 57860, 535, 57861, 536, 57862, 537, 57863, 538, 57864, 539, + 57865, 540, 57866, 541, 57867, 542, 57868, 543, 57869, 544, + 57870, 545, 57871, 546, 57872, 547, 57873, 548, 57874, 549, + 57875, 550, 57876, 551, 57877, 552, 57878, 553, 57879, 554, + 57880, 555, 57881, 556, 57882, 557, 57883, 558, 57884, 559, + 57885, 560, 57886, 561, 57887, 562, 57888, 563, 57889, 564, + 57890, 565, 57891, 566, 57892, 567, 57893, 568, 57894, 569, + 57895, 570, 57896, 571, 57897, 572, 57898, 573, 57899, 574, + 57900, 575, 57901, 576, 57902, 577, 57903, 578, 57904, 579, + 57905, 580, 57906, 581, 57907, 582, 57908, 583, 57909, 584, + 57910, 585, 57911, 586, 57912, 587, 57913, 588, 57914, 589, + 57915, 590, 57916, 591, 57917, 592, 57918, 593, 57919, 594, + 57920, 595, 57921, 596, 57922, 597, 57923, 598, 57924, 599, + 57925, 600, 57926, 601, 57927, 602, 57928, 603, 57929, 604, + 57930, 605, 57931, 606, 57932, 607, 57933, 608, 57934, 609, + 57935, 610, 57936, 611, 57937, 612, 57938, 613, 57939, 614, + 57940, 615, 57941, 616, 57942, 617, 57943, 618, 57944, 619, + 57945, 620, 57946, 621, 57947, 622, 57948, 623, 57949, 624, + 57950, 625, 57951, 626, 57952, 627, 57953, 628, 57954, 629, + 57955, 630, 57956, 631, 57957, 632, 57958, 633, 57959, 634, + 57960, 635, 57961, 636, 57962, 637, 57963, 638, 57964, 639, + 57965, 640, 57966, 641, 57967, 642, 57968, 643, 57969, 644, + 57970, 645, 57971, 646, 57972, 647, 57973, 648, 57974, 649, + 57975, 650, 57976, 651, 57977, 652, 57978, 653, 57979, 654, + 57980, 655, 57981, 656, 57982, 657, 57983, 658, 57984, 659, + 57985, 660, 57986, 661, 57987, 662, 57988, 663, 57989, 664, + 57990, 665, 57991, 666, 57992, 667, 57993, 668, 57994, 669, + 57995, 670, 57996, 671, 57997, 672, 57998, 673, 57999, 674, + 58000, 675, 58001, 676, 58002, 677, 58003, 678, 58004, 679, + 58005, 680, 58006, 681, 58007, 682, 58008, 683, 58009, 684, + 58010, 685, 58011, 686, 58012, 687, 58013, 688, 58014, 689, + 58015, 690, 58016, 691, 58017, 692, 58018, 693, 58019, 694, + 58020, 695, 58021, 696, 58022, 697, 58023, 698, 58024, 699, + 58025, 700, 58026, 701, 58027, 702, 58028, 703, 58029, 704, + 58030, 705, 58031, 706, 58032, 707, 58033, 708, 58034, 709, + 58035, 710, 58036, 711, 58037, 712, 58038, 713, 58039, 714, + 58040, 715, 58041, 716, 58042, 717, 58043, 718, 58044, 719, + 58045, 720, 58046, 721, 58047, 722, 58048, 723, 58049, 724, + 58050, 725, 58051, 726, 58052, 727, 58053, 728, 58054, 729, + 58055, 730, 58056, 731, 58057, 732, 58058, 733, 58059, 734, + 58060, 735, 58061, 736, 58062, 737, 58063, 738, 58064, 739, + 58065, 740, 58066, 741, 58067, 742, 58068, 743, 58069, 744, + 58070, 745, 58071, 746, 58072, 747, 58073, 748, 58074, 749, + 58075, 750, 58076, 751, 58077, 752, 58078, 753, 58079, 754, + 58080, 755, 58081, 756, 58082, 757, 58083, 758, 58084, 759, + 58085, 760, 58086, 761, 58087, 762, 58088, 763, 58089, 764, + 58090, 765, 58091, 766, 58092, 767, 58093, 768, 58094, 769, + 58095, 770, 58096, 771, 58097, 772, 58098, 773, 58099, 774, + 58100, 775, 58101, 776, 58102, 777, 58103, 778, 58104, 779, + 58105, 780, 58106, 781, 58107, 782, 58108, 783, 58109, 784, + 58110, 785, 58111, 786, 58112, 787, 58113, 788, 58114, 789, + 0, +} + +var yyErrorMessages = [...]struct { + state int + token int + msg string +}{} + +//line yaccpar:1 + +/* parser for yacc output */ + +func yyIaddr(v interface{}) __yyunsafe__.Pointer { + type h struct { + t __yyunsafe__.Pointer + p __yyunsafe__.Pointer + } + return (*h)(__yyunsafe__.Pointer(&v)).p +} + +var ( + yyDebug = 0 + yyErrorVerbose = false +) + +type yyLexer interface { + Lex(lval *yySymType) int + Error(s string) +} + +type yyParser interface { + Parse(yyLexer) int + Lookahead() int +} + +type yyParserImpl struct { + lval yySymType + stack [yyInitialStackSize]yySymType + char int +} + +func (p *yyParserImpl) Lookahead() int { + return p.char +} + +func yyNewParser() yyParser { + return &yyParserImpl{} +} + +const yyFlag = -1000 + +func yyTokname(c int) string { + if c >= 1 && c-1 < len(yyToknames) { + if yyToknames[c-1] != "" { + return yyToknames[c-1] + } + } + return __yyfmt__.Sprintf("tok-%v", c) +} + +func yyStatname(s int) string { + if s >= 0 && s < len(yyStatenames) { + if yyStatenames[s] != "" { + return yyStatenames[s] + } + } + return __yyfmt__.Sprintf("state-%v", s) +} + +func yyErrorMessage(state, lookAhead int) string { + const TOKSTART = 4 + + if !yyErrorVerbose { + return "syntax error" + } + + for _, e := range yyErrorMessages { + if e.state == state && e.token == lookAhead { + return "syntax error: " + e.msg + } + } + + res := "syntax error: unexpected " + yyTokname(lookAhead) + + // To match Bison, suggest at most four expected tokens. + expected := make([]int, 0, 4) + + // Look for shiftable tokens. + base := yyPact[state] + for tok := TOKSTART; tok-1 < len(yyToknames); tok++ { + if n := base + tok; n >= 0 && n < yyLast && yyChk[yyAct[n]] == tok { + if len(expected) == cap(expected) { + return res + } + expected = append(expected, tok) + } + } + + if yyDef[state] == -2 { + i := 0 + for yyExca[i] != -1 || yyExca[i+1] != state { + i += 2 + } + + // Look for tokens that we accept or reduce. + for i += 2; yyExca[i] >= 0; i += 2 { + tok := yyExca[i] + if tok < TOKSTART || yyExca[i+1] == 0 { + continue + } + if len(expected) == cap(expected) { + return res + } + expected = append(expected, tok) + } + + // If the default action is to accept or reduce, give up. + if yyExca[i+1] != 0 { + return res + } + } + + for i, tok := range expected { + if i == 0 { + res += ", expecting " + } else { + res += " or " + } + res += yyTokname(tok) + } + return res +} + +func yylex1(lex yyLexer, lval *yySymType) (char, token int) { + token = 0 + char = lex.Lex(lval) + if char <= 0 { + token = yyTok1[0] + goto out + } + if char < len(yyTok1) { + token = yyTok1[char] + goto out + } + if char >= yyPrivate { + if char < yyPrivate+len(yyTok2) { + token = yyTok2[char-yyPrivate] + goto out + } + } + for i := 0; i < len(yyTok3); i += 2 { + token = yyTok3[i+0] + if token == char { + token = yyTok3[i+1] + goto out + } + } + +out: + if token == 0 { + token = yyTok2[1] /* unknown char */ + } + if yyDebug >= 3 { + __yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char)) + } + return char, token +} + +func yyParse(yylex yyLexer) int { + return yyNewParser().Parse(yylex) +} + +func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int { + var yyn int + var yyVAL yySymType + var yyDollar []yySymType + _ = yyDollar // silence set and not used + yyS := yyrcvr.stack[:] + + Nerrs := 0 /* number of errors */ + Errflag := 0 /* error recovery flag */ + yystate := 0 + yyrcvr.char = -1 + yytoken := -1 // yyrcvr.char translated into internal numbering + defer func() { + // Make sure we report no lookahead when not parsing. + yystate = -1 + yyrcvr.char = -1 + yytoken = -1 + }() + yyp := -1 + goto yystack + +ret0: + return 0 + +ret1: + return 1 + +yystack: + /* put a state and value onto the stack */ + if yyDebug >= 4 { + __yyfmt__.Printf("char %v in %v\n", yyTokname(yytoken), yyStatname(yystate)) + } + + yyp++ + if yyp >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyS[yyp] = yyVAL + yyS[yyp].yys = yystate + +yynewstate: + yyn = yyPact[yystate] + if yyn <= yyFlag { + goto yydefault /* simple state */ + } + if yyrcvr.char < 0 { + yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval) + } + yyn += yytoken + if yyn < 0 || yyn >= yyLast { + goto yydefault + } + yyn = yyAct[yyn] + if yyChk[yyn] == yytoken { /* valid shift */ + yyrcvr.char = -1 + yytoken = -1 + yyVAL = yyrcvr.lval + yystate = yyn + if Errflag > 0 { + Errflag-- + } + goto yystack + } + +yydefault: + /* default state action */ + yyn = yyDef[yystate] + if yyn == -2 { + if yyrcvr.char < 0 { + yyrcvr.char, yytoken = yylex1(yylex, &yyrcvr.lval) + } + + /* look through exception table */ + xi := 0 + for { + if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate { + break + } + xi += 2 + } + for xi += 2; ; xi += 2 { + yyn = yyExca[xi+0] + if yyn < 0 || yyn == yytoken { + break + } + } + yyn = yyExca[xi+1] + if yyn < 0 { + goto ret0 + } + } + if yyn == 0 { + /* error ... attempt to resume parsing */ + switch Errflag { + case 0: /* brand new error */ + yylex.Error(yyErrorMessage(yystate, yytoken)) + Nerrs++ + if yyDebug >= 1 { + __yyfmt__.Printf("%s", yyStatname(yystate)) + __yyfmt__.Printf(" saw %s\n", yyTokname(yytoken)) + } + fallthrough + + case 1, 2: /* incompletely recovered error ... try again */ + Errflag = 3 + + /* find a state where "error" is a legal shift action */ + for yyp >= 0 { + yyn = yyPact[yyS[yyp].yys] + yyErrCode + if yyn >= 0 && yyn < yyLast { + yystate = yyAct[yyn] /* simulate a shift of "error" */ + if yyChk[yystate] == yyErrCode { + goto yystack + } + } + + /* the current p has no shift on "error", pop stack */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) + } + yyp-- + } + /* there is no state on the stack with an error shift ... abort */ + goto ret1 + + case 3: /* no shift yet; clobber input char */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery discards %s\n", yyTokname(yytoken)) + } + if yytoken == yyEofCode { + goto ret1 + } + yyrcvr.char = -1 + yytoken = -1 + goto yynewstate /* try again in the same state */ + } + } + + /* reduction by production yyn */ + if yyDebug >= 2 { + __yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate)) + } + + yynt := yyn + yypt := yyp + _ = yypt // guard against "declared and not used" + + yyp -= yyR2[yyn] + // yyp is now the index of $0. Perform the default action. Iff the + // reduced production is ε, $1 is possibly out of range. + if yyp+1 >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyVAL = yyS[yyp+1] + + /* consult goto table to find next state */ + yyn = yyR1[yyn] + yyg := yyPgo[yyn] + yyj := yyg + yyS[yyp].yys + 1 + + if yyj >= yyLast { + yystate = yyAct[yyg] + } else { + yystate = yyAct[yyj] + if yyChk[yystate] != -yyn { + yystate = yyAct[yyg] + } + } + // dummy call; replaced with literal code + switch yynt { + + case 3: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:1180 + { + if yyDollar[1].statementUnion() != nil { + yylex.(*Lexer).AppendStmt(yyDollar[1].statementUnion()) + } + } + case 4: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:1186 + { + yylex.(*Lexer).AppendTopLevelSemicolon(yyDollar[2].pos) + if yyDollar[3].statementUnion() != nil { + yylex.(*Lexer).AppendStmt(yyDollar[3].statementUnion()) + } + } + case 5: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1195 + { + yyLOCAL = tree.NewCompoundStmt(yyDollar[2].statementsUnion()) + } + yyVAL.union = yyLOCAL + case 6: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.Statement +//line mysql_sql.y:1201 + { + yyLOCAL = []tree.Statement{yyDollar[1].statementUnion()} + } + yyVAL.union = yyLOCAL + case 7: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []tree.Statement +//line mysql_sql.y:1205 + { + yyLOCAL = append(yyDollar[1].statementsUnion(), yyDollar[3].statementUnion()) + } + yyVAL.union = yyLOCAL + case 17: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1220 + { + yyLOCAL = yyDollar[1].statementUnion() + } + yyVAL.union = yyLOCAL + case 18: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1224 + { + yyLOCAL = tree.Statement(nil) + } + yyVAL.union = yyLOCAL + case 19: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1230 + { + yyLOCAL = yyDollar[1].statementUnion() + } + yyVAL.union = yyLOCAL + case 20: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1234 + { + yyLOCAL = yyDollar[1].statementUnion() + } + yyVAL.union = yyLOCAL + case 22: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1239 + { + yyLOCAL = yyDollar[1].statementUnion() + } + yyVAL.union = yyLOCAL + case 23: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1243 + { + yyLOCAL = tree.Statement(nil) + } + yyVAL.union = yyLOCAL + case 58: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1283 + { + yyLOCAL = yyDollar[1].selectUnion() + } + yyVAL.union = yyLOCAL + case 69: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1299 + { + var timestamp = yyDollar[2].str + var isS3 = false + var dir = yyDollar[4].str + var parallelism = yyDollar[6].str + var option []string + var backuptype = yyDollar[7].str + var backupts = yyDollar[8].str + yyLOCAL = tree.NewBackupStart(timestamp, isS3, dir, parallelism, option, backuptype, backupts) + } + yyVAL.union = yyLOCAL + case 70: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1310 + { + var timestamp = yyDollar[2].str + var isS3 = true + var dir string + var parallelism string + var option = yyDollar[5].strsUnion() + var backuptype = yyDollar[7].str + var backupts = yyDollar[8].str + yyLOCAL = tree.NewBackupStart(timestamp, isS3, dir, parallelism, option, backuptype, backupts) + } + yyVAL.union = yyLOCAL + case 71: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:1322 + { + yyVAL.str = "" + } + case 72: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:1326 + { + yyVAL.str = yyDollar[2].str + } + case 73: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:1331 + { + yyVAL.str = "" + } + case 74: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:1335 + { + yyVAL.str = yyDollar[2].str + } + case 75: + yyDollar = yyS[yypt-12 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1341 + { + yyLOCAL = &tree.CreateCDC{ + IfNotExists: yyDollar[3].ifNotExistsUnion(), + TaskName: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + SourceUri: yyDollar[5].str, + SinkType: yyDollar[6].str, + SinkUri: yyDollar[7].str, + Tables: yyDollar[8].str, + Option: yyDollar[10].strsUnion(), + Internal: yyDollar[12].boolValUnion(), + } + } + yyVAL.union = yyLOCAL + case 76: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:1356 + { + yyLOCAL = yyDollar[1].strsUnion() + } + yyVAL.union = yyLOCAL + case 77: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:1360 + { + yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].strsUnion()...) + } + yyVAL.union = yyLOCAL + case 78: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:1364 + { + yyLOCAL = []string{} + } + yyVAL.union = yyLOCAL + case 79: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:1368 + { + yyLOCAL = append(yyLOCAL, yyDollar[1].str) + yyLOCAL = append(yyLOCAL, yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 80: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1375 + { + yyLOCAL = &tree.ShowCDC{ + Option: yyDollar[3].allCDCOptionUnion(), + } + } + yyVAL.union = yyLOCAL + case 81: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1383 + { + yyLOCAL = &tree.PauseCDC{ + Option: yyDollar[3].allCDCOptionUnion(), + } + } + yyVAL.union = yyLOCAL + case 82: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1391 + { + yyLOCAL = tree.NewDropCDC(yyDollar[4].allCDCOptionUnion(), yyDollar[3].boolValUnion(), yyDollar[5].boolValUnion()) + } + yyVAL.union = yyLOCAL + case 83: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.AllOrNotCDC +//line mysql_sql.y:1396 + { + yyLOCAL = &tree.AllOrNotCDC{ + All: true, + TaskName: "", + } + } + yyVAL.union = yyLOCAL + case 84: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.AllOrNotCDC +//line mysql_sql.y:1403 + { + yyLOCAL = yyDollar[1].allCDCOptionUnion() + } + yyVAL.union = yyLOCAL + case 85: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.AllOrNotCDC +//line mysql_sql.y:1409 + { + yyLOCAL = yyDollar[1].allCDCOptionUnion() + } + yyVAL.union = yyLOCAL + case 86: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.AllOrNotCDC +//line mysql_sql.y:1414 + { + yyLOCAL = &tree.AllOrNotCDC{ + All: false, + TaskName: tree.Identifier(yyDollar[1].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 87: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.AllOrNotCDC +//line mysql_sql.y:1423 + { + yyLOCAL = &tree.AllOrNotCDC{ + All: true, + TaskName: "", + } + } + yyVAL.union = yyLOCAL + case 88: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.AllOrNotCDC +//line mysql_sql.y:1430 + { + yyLOCAL = &tree.AllOrNotCDC{ + All: false, + TaskName: tree.Identifier(yyDollar[2].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 89: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1439 + { + yyLOCAL = &tree.ResumeCDC{ + TaskName: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 90: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1447 + { + yyLOCAL = &tree.RestartCDC{ + TaskName: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 91: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1455 + { + yyLOCAL = &tree.CreateSnapShot{ + IfNotExists: yyDollar[3].ifNotExistsUnion(), + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Object: yyDollar[6].snapshotObjectUnion(), + } + } + yyVAL.union = yyLOCAL + case 92: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ObjectInfo +//line mysql_sql.y:1465 + { + spLevel := tree.SnapshotLevelType{ + Level: tree.SNAPSHOTLEVELCLUSTER, + } + yyLOCAL = tree.ObjectInfo{ + SLevel: spLevel, + ObjName: "", + } + } + yyVAL.union = yyLOCAL + case 93: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ObjectInfo +//line mysql_sql.y:1475 + { + spLevel := tree.SnapshotLevelType{ + Level: tree.SNAPSHOTLEVELACCOUNT, + } + yyLOCAL = tree.ObjectInfo{ + SLevel: spLevel, + ObjName: tree.Identifier(yyDollar[2].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 94: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ObjectInfo +//line mysql_sql.y:1485 + { + spLevel := tree.SnapshotLevelType{ + Level: tree.SNAPSHOTLEVELACCOUNT, + } + yyLOCAL = tree.ObjectInfo{ + SLevel: spLevel, + ObjName: tree.Identifier(""), + } + } + yyVAL.union = yyLOCAL + case 95: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ObjectInfo +//line mysql_sql.y:1495 + { + spLevel := tree.SnapshotLevelType{ + Level: tree.SNAPSHOTLEVELDATABASE, + } + yyLOCAL = tree.ObjectInfo{ + SLevel: spLevel, + ObjName: tree.Identifier(yyDollar[2].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 96: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.ObjectInfo +//line mysql_sql.y:1505 + { + spLevel := tree.SnapshotLevelType{ + Level: tree.SNAPSHOTLEVELTABLE, + } + yyLOCAL = tree.ObjectInfo{ + SLevel: spLevel, + ObjName: tree.Identifier(yyDollar[2].cstrUnion().Compare() + "." + yyDollar[3].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 97: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.ObjectInfo +//line mysql_sql.y:1515 + { + spLevel := tree.SnapshotLevelType{ + Level: tree.SNAPSHOTLEVELTABLE, + } + yyLOCAL = tree.ObjectInfo{ + SLevel: spLevel, + ObjName: tree.Identifier(yyDollar[2].cstrUnion().Compare() + "." + yyDollar[3].cstrUnion().Compare()), + AccountName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + PubName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 98: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.ObjectInfo +//line mysql_sql.y:1527 + { + spLevel := tree.SnapshotLevelType{ + Level: tree.SNAPSHOTLEVELDATABASE, + } + yyLOCAL = tree.ObjectInfo{ + SLevel: spLevel, + ObjName: tree.Identifier(yyDollar[2].cstrUnion().Compare()), + AccountName: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + PubName: tree.Identifier(yyDollar[6].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 99: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.ObjectInfo +//line mysql_sql.y:1539 + { + spLevel := tree.SnapshotLevelType{ + Level: tree.SNAPSHOTLEVELACCOUNT, + } + yyLOCAL = tree.ObjectInfo{ + SLevel: spLevel, + AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + PubName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 100: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1552 + { + yyLOCAL = &tree.CreatePitr{ + IfNotExists: yyDollar[3].ifNotExistsUnion(), + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Level: tree.PITRLEVELACCOUNT, + PitrValue: yyDollar[8].int64ValUnion(), + PitrUnit: yyDollar[9].str, + Internal: yyDollar[10].boolValUnion(), + } + } + yyVAL.union = yyLOCAL + case 101: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1563 + { + yyLOCAL = &tree.CreatePitr{ + IfNotExists: yyDollar[3].ifNotExistsUnion(), + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Level: tree.PITRLEVELCLUSTER, + PitrValue: yyDollar[8].int64ValUnion(), + PitrUnit: yyDollar[9].str, + Internal: yyDollar[10].boolValUnion(), + } + } + yyVAL.union = yyLOCAL + case 102: + yyDollar = yyS[yypt-11 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1574 + { + yyLOCAL = &tree.CreatePitr{ + IfNotExists: yyDollar[3].ifNotExistsUnion(), + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Level: tree.PITRLEVELACCOUNT, + AccountName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), + PitrValue: yyDollar[9].int64ValUnion(), + PitrUnit: yyDollar[10].str, + Internal: yyDollar[11].boolValUnion(), + } + } + yyVAL.union = yyLOCAL + case 103: + yyDollar = yyS[yypt-11 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1586 + { + yyLOCAL = &tree.CreatePitr{ + IfNotExists: yyDollar[3].ifNotExistsUnion(), + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Level: tree.PITRLEVELDATABASE, + DatabaseName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), + PitrValue: yyDollar[9].int64ValUnion(), + PitrUnit: yyDollar[10].str, + Internal: yyDollar[11].boolValUnion(), + } + } + yyVAL.union = yyLOCAL + case 104: + yyDollar = yyS[yypt-12 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1598 + { + yyLOCAL = &tree.CreatePitr{ + IfNotExists: yyDollar[3].ifNotExistsUnion(), + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Level: tree.PITRLEVELTABLE, + DatabaseName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), + TableName: tree.Identifier(yyDollar[8].cstrUnion().Compare()), + PitrValue: yyDollar[10].int64ValUnion(), + PitrUnit: yyDollar[11].str, + Internal: yyDollar[12].boolValUnion(), + } + } + yyVAL.union = yyLOCAL + case 105: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1611 + { + yyLOCAL = &tree.CreatePitr{ + IfNotExists: yyDollar[3].ifNotExistsUnion(), + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Level: tree.PITRLEVELACCOUNT, + PitrValue: yyDollar[6].int64ValUnion(), + PitrUnit: yyDollar[7].str, + Internal: yyDollar[8].boolValUnion(), + } + } + yyVAL.union = yyLOCAL + case 106: + yyDollar = yyS[yypt-13 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1622 + { + yyLOCAL = &tree.CreatePitr{ + IfNotExists: yyDollar[3].ifNotExistsUnion(), + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Level: tree.PITRLEVELTABLE, + DatabaseName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), + TableName: tree.Identifier(yyDollar[9].cstrUnion().Compare()), + PitrValue: yyDollar[11].int64ValUnion(), + PitrUnit: yyDollar[12].str, + Internal: yyDollar[13].boolValUnion(), + } + } + yyVAL.union = yyLOCAL + case 107: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:1637 + { + value, ok := signedIntegral(yylex, yyDollar[1].item) + if !ok { + goto ret1 + } + yyLOCAL = value + } + yyVAL.union = yyLOCAL + case 108: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1646 + { + var account tree.Identifier + var database tree.Identifier + switch len(yyDollar[3].identifierListUnion()) { + case 1: + database = yyDollar[3].identifierListUnion()[0] + case 2: + account = yyDollar[3].identifierListUnion()[0] + database = yyDollar[3].identifierListUnion()[1] + default: + yylex.Error("invalid restore database target") + goto ret1 + } + + snapshotName := tree.Identifier(yyDollar[4].str) + result := &tree.RestoreSnapShot{ + Level: tree.RESTORELEVELDATABASE, + DatabaseName: database, + SnapShotName: snapshotName, + } + + if len(account) > 0 { + result.AccountName = account + } + + if len(yyDollar[5].str) > 0 { + result.ToAccountName = tree.Identifier(yyDollar[5].str) + } + + yyLOCAL = result + } + yyVAL.union = yyLOCAL + case 109: + yyDollar = yyS[yypt-6 : yypt+1] +//line mysql_sql.y:1678 + { + yylex.Error(restoreSnapshotFromSyntaxHint) + goto ret1 + } + case 110: + yyDollar = yyS[yypt-8 : yypt+1] +//line mysql_sql.y:1683 + { + yylex.Error(restoreSnapshotFromSyntaxHint) + goto ret1 + } + case 111: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1688 + { + var account tree.Identifier + var database tree.Identifier + var table tree.Identifier + + switch len(yyDollar[3].identifierListUnion()) { + case 2: + database = yyDollar[3].identifierListUnion()[0] + table = yyDollar[3].identifierListUnion()[1] + case 3: + account = yyDollar[3].identifierListUnion()[0] + database = yyDollar[3].identifierListUnion()[1] + table = yyDollar[3].identifierListUnion()[2] + default: + yylex.Error("invalid restore table target") + goto ret1 + } + + snapshotName := tree.Identifier(yyDollar[4].str) + result := &tree.RestoreSnapShot{ + Level: tree.RESTORELEVELTABLE, + DatabaseName: database, + TableName: table, + SnapShotName: snapshotName, + } + + if len(account) > 0 { + result.AccountName = account + } + + if len(yyDollar[5].str) > 0 { + result.ToAccountName = tree.Identifier(yyDollar[5].str) + } + + yyLOCAL = result + } + yyVAL.union = yyLOCAL + case 112: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1725 + { + yyLOCAL = &tree.RestoreSnapShot{ + Level: tree.RESTORELEVELCLUSTER, + SnapShotName: tree.Identifier(yyDollar[3].str), + } + } + yyVAL.union = yyLOCAL + case 113: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1732 + { + result := &tree.RestoreSnapShot{ + Level: tree.RESTORELEVELACCOUNT, + AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + SnapShotName: tree.Identifier(yyDollar[4].str), + } + + if len(yyDollar[5].str) > 0 { + result.ToAccountName = tree.Identifier(yyDollar[5].str) + } + + yyLOCAL = result + } + yyVAL.union = yyLOCAL + case 114: + yyDollar = yyS[yypt-8 : yypt+1] +//line mysql_sql.y:1746 + { + yylex.Error(restoreSnapshotFromSyntaxHint) + goto ret1 + } + case 115: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:1753 + { + yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 116: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:1757 + { + yyLOCAL = tree.IdentifierList{ + tree.Identifier(yyDollar[1].cstrUnion().Compare()), + tree.Identifier(yyDollar[3].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 117: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:1766 + { + yyLOCAL = tree.IdentifierList{ + tree.Identifier(yyDollar[1].cstrUnion().Compare()), + tree.Identifier(yyDollar[3].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 118: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:1773 + { + yyLOCAL = tree.IdentifierList{ + tree.Identifier(yyDollar[1].cstrUnion().Compare()), + tree.Identifier(yyDollar[3].cstrUnion().Compare()), + tree.Identifier(yyDollar[5].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 119: + yyDollar = yyS[yypt-5 : yypt+1] +//line mysql_sql.y:1783 + { + yyVAL.str = yyDollar[4].cstrUnion().Compare() + } + case 120: + yyDollar = yyS[yypt-5 : yypt+1] +//line mysql_sql.y:1787 + { + yyVAL.str = strings.ToLower(yyDollar[4].str) + } + case 121: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:1793 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 122: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:1797 + { + yyVAL.str = yyDollar[1].str + } + case 123: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:1802 + { + yyVAL.str = "" + } + case 124: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:1806 + { + yyVAL.str = yyDollar[3].cstrUnion().Compare() + } + case 125: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1812 + { + yyLOCAL = &tree.RestorePitr{ + Level: tree.RESTORELEVELACCOUNT, + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + TimeStamp: yyDollar[5].str, + } + } + yyVAL.union = yyLOCAL + case 126: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1820 + { + yyLOCAL = &tree.RestorePitr{ + Level: tree.RESTORELEVELDATABASE, + DatabaseName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + Name: tree.Identifier(yyDollar[6].cstrUnion().Compare()), + TimeStamp: yyDollar[7].str, + } + } + yyVAL.union = yyLOCAL + case 127: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1829 + { + yyLOCAL = &tree.RestorePitr{ + Level: tree.RESTORELEVELDATABASE, + AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + DatabaseName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + Name: tree.Identifier(yyDollar[8].cstrUnion().Compare()), + TimeStamp: yyDollar[9].str, + } + } + yyVAL.union = yyLOCAL + case 128: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1839 + { + yyLOCAL = &tree.RestorePitr{ + Level: tree.RESTORELEVELTABLE, + DatabaseName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + TableName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + Name: tree.Identifier(yyDollar[8].cstrUnion().Compare()), + TimeStamp: yyDollar[9].str, + } + } + yyVAL.union = yyLOCAL + case 129: + yyDollar = yyS[yypt-11 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1849 + { + yyLOCAL = &tree.RestorePitr{ + Level: tree.RESTORELEVELTABLE, + AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + DatabaseName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + TableName: tree.Identifier(yyDollar[7].cstrUnion().Compare()), + Name: tree.Identifier(yyDollar[10].cstrUnion().Compare()), + TimeStamp: yyDollar[11].str, + } + } + yyVAL.union = yyLOCAL + case 130: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1860 + { + yyLOCAL = &tree.RestorePitr{ + Level: tree.RESTORELEVELACCOUNT, + AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + Name: tree.Identifier(yyDollar[6].cstrUnion().Compare()), + TimeStamp: yyDollar[7].str, + SrcAccountName: tree.Identifier(yyDollar[8].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 131: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1870 + { + yyLOCAL = &tree.RestorePitr{ + Level: tree.RESTORELEVELCLUSTER, + Name: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + TimeStamp: yyDollar[6].str, + } + } + yyVAL.union = yyLOCAL + case 132: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1880 + { + var connectionId uint64 + switch v := yyDollar[3].item.(type) { + case uint64: + connectionId = v + case int64: + connectionId = uint64(v) + default: + yylex.Error("parse integral fail") + goto ret1 + } + + yyLOCAL = &tree.Kill{ + Option: yyDollar[2].killOptionUnion(), + ConnectionId: connectionId, + StmtOption: yyDollar[4].statementOptionUnion(), + } + } + yyVAL.union = yyLOCAL + case 133: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.KillOption +//line mysql_sql.y:1900 + { + yyLOCAL = tree.KillOption{ + Exist: false, + } + } + yyVAL.union = yyLOCAL + case 134: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.KillOption +//line mysql_sql.y:1906 + { + yyLOCAL = tree.KillOption{ + Exist: true, + Typ: tree.KillTypeConnection, + } + } + yyVAL.union = yyLOCAL + case 135: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.KillOption +//line mysql_sql.y:1913 + { + yyLOCAL = tree.KillOption{ + Exist: true, + Typ: tree.KillTypeQuery, + } + } + yyVAL.union = yyLOCAL + case 136: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.StatementOption +//line mysql_sql.y:1921 + { + yyLOCAL = tree.StatementOption{ + Exist: false, + } + } + yyVAL.union = yyLOCAL + case 137: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.StatementOption +//line mysql_sql.y:1927 + { + yyLOCAL = tree.StatementOption{ + Exist: true, + StatementId: yyDollar[1].str, + } + } + yyVAL.union = yyLOCAL + case 138: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1936 + { + yyLOCAL = &tree.CallStmt{ + Name: yyDollar[2].procNameUnion(), + Args: yyDollar[4].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 139: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1945 + { + yyLOCAL = &tree.LeaveStmt{ + Name: tree.Identifier(yyDollar[2].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 140: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1953 + { + yyLOCAL = &tree.IterateStmt{ + Name: tree.Identifier(yyDollar[2].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 141: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1961 + { + yyLOCAL = &tree.WhileStmt{ + Name: "", + Cond: yyDollar[2].exprUnion(), + Body: yyDollar[4].statementsUnion(), + } + } + yyVAL.union = yyLOCAL + case 142: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1969 + { + yyLOCAL = &tree.WhileStmt{ + Name: tree.Identifier(yyDollar[1].cstrUnion().Compare()), + Cond: yyDollar[4].exprUnion(), + Body: yyDollar[6].statementsUnion(), + } + } + yyVAL.union = yyLOCAL + case 143: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1979 + { + yyLOCAL = &tree.RepeatStmt{ + Name: "", + Body: yyDollar[2].statementsUnion(), + Cond: yyDollar[4].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 144: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1987 + { + yyLOCAL = &tree.RepeatStmt{ + Name: tree.Identifier(yyDollar[1].cstrUnion().Compare()), + Body: yyDollar[4].statementsUnion(), + Cond: yyDollar[6].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 145: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:1997 + { + yyLOCAL = &tree.LoopStmt{ + Name: "", + Body: yyDollar[2].statementsUnion(), + } + } + yyVAL.union = yyLOCAL + case 146: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2004 + { + yyLOCAL = &tree.LoopStmt{ + Name: tree.Identifier(yyDollar[1].cstrUnion().Compare()), + Body: yyDollar[4].statementsUnion(), + } + } + yyVAL.union = yyLOCAL + case 147: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2013 + { + yyLOCAL = &tree.IfStmt{ + Cond: yyDollar[2].exprUnion(), + Body: yyDollar[4].statementsUnion(), + Elifs: yyDollar[5].elseIfClauseListUnion(), + Else: yyDollar[6].statementsUnion(), + } + } + yyVAL.union = yyLOCAL + case 148: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []*tree.ElseIfStmt +//line mysql_sql.y:2023 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 149: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.ElseIfStmt +//line mysql_sql.y:2027 + { + yyLOCAL = yyDollar[1].elseIfClauseListUnion() + } + yyVAL.union = yyLOCAL + case 150: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.ElseIfStmt +//line mysql_sql.y:2033 + { + yyLOCAL = []*tree.ElseIfStmt{yyDollar[1].elseIfClauseUnion()} + } + yyVAL.union = yyLOCAL + case 151: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []*tree.ElseIfStmt +//line mysql_sql.y:2037 + { + yyLOCAL = append(yyDollar[1].elseIfClauseListUnion(), yyDollar[2].elseIfClauseUnion()) + } + yyVAL.union = yyLOCAL + case 152: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.ElseIfStmt +//line mysql_sql.y:2043 + { + yyLOCAL = &tree.ElseIfStmt{ + Cond: yyDollar[2].exprUnion(), + Body: yyDollar[4].statementsUnion(), + } + } + yyVAL.union = yyLOCAL + case 153: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2052 + { + yyLOCAL = &tree.CaseStmt{ + Expr: yyDollar[2].exprUnion(), + Whens: yyDollar[3].whenClauseList2Union(), + Else: yyDollar[4].statementsUnion(), + } + } + yyVAL.union = yyLOCAL + case 154: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.WhenStmt +//line mysql_sql.y:2062 + { + yyLOCAL = []*tree.WhenStmt{yyDollar[1].whenClause2Union()} + } + yyVAL.union = yyLOCAL + case 155: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []*tree.WhenStmt +//line mysql_sql.y:2066 + { + yyLOCAL = append(yyDollar[1].whenClauseList2Union(), yyDollar[2].whenClause2Union()) + } + yyVAL.union = yyLOCAL + case 156: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.WhenStmt +//line mysql_sql.y:2072 + { + yyLOCAL = &tree.WhenStmt{ + Cond: yyDollar[2].exprUnion(), + Body: yyDollar[4].statementsUnion(), + } + } + yyVAL.union = yyLOCAL + case 157: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []tree.Statement +//line mysql_sql.y:2081 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 158: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []tree.Statement +//line mysql_sql.y:2085 + { + yyLOCAL = yyDollar[2].statementsUnion() + } + yyVAL.union = yyLOCAL + case 159: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2091 + { + ep := &tree.ExportParam{ + Outfile: true, + QueryId: yyDollar[3].str, + FilePath: yyDollar[5].str, + Fields: yyDollar[6].fieldsUnion(), + Lines: yyDollar[7].linesUnion(), + Header: yyDollar[8].unsignedOptUnion(), + MaxFileSize: uint64(yyDollar[9].int64ValUnion()) * 1024, + ForceQuote: yyDollar[10].strsUnion(), + } + yyLOCAL = &tree.MoDump{ + ExportParams: ep, + } + } + yyVAL.union = yyLOCAL + case 160: + yyDollar = yyS[yypt-11 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2109 + { + yyLOCAL = &tree.Load{ + Local: yyDollar[3].boolValUnion(), + Param: yyDollar[4].loadParamUnion(), + DuplicateHandling: yyDollar[5].duplicateKeyUnion(), + Table: yyDollar[8].tableNameUnion(), + } + yyLOCAL.(*tree.Load).Param.Tail = yyDollar[9].tailParamUnion() + setLoadParallelOption(yyLOCAL.(*tree.Load).Param, yyDollar[10].int64ValUnion()) + yyLOCAL.(*tree.Load).Param.Strict = yyDollar[11].unsignedOptUnion() + } + yyVAL.union = yyLOCAL + case 161: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2123 + { + yyLOCAL = &tree.DumpTable{Table: yyDollar[3].tableNameUnion(), Path: yyDollar[5].str} + } + yyVAL.union = yyLOCAL + case 162: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2127 + { + yyLOCAL = &tree.DumpTable{Table: yyDollar[3].tableNameUnion(), Path: yyDollar[5].str, MetadataOnly: true} + } + yyVAL.union = yyLOCAL + case 163: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2133 + { + yyLOCAL = &tree.LoadTable{Table: yyDollar[3].tableNameUnion(), Path: yyDollar[5].str} + } + yyVAL.union = yyLOCAL + case 164: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2139 + { + yyLOCAL = &tree.LoadExtension{ + Name: tree.Identifier(yyDollar[2].str), + } + } + yyVAL.union = yyLOCAL + case 165: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.UpdateExprs +//line mysql_sql.y:2146 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 166: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.UpdateExprs +//line mysql_sql.y:2150 + { + yyLOCAL = yyDollar[2].updateExprsUnion() + } + yyVAL.union = yyLOCAL + case 167: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.UpdateExprs +//line mysql_sql.y:2156 + { + yyLOCAL = tree.UpdateExprs{yyDollar[1].updateExprUnion()} + } + yyVAL.union = yyLOCAL + case 168: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.UpdateExprs +//line mysql_sql.y:2160 + { + yyLOCAL = append(yyDollar[1].updateExprsUnion(), yyDollar[3].updateExprUnion()) + } + yyVAL.union = yyLOCAL + case 169: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.UpdateExpr +//line mysql_sql.y:2166 + { + yyLOCAL = &tree.UpdateExpr{ + Names: []*tree.UnresolvedName{yyDollar[1].unresolvedNameUnion()}, + Expr: &tree.DefaultVal{}, + } + } + yyVAL.union = yyLOCAL + case 170: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.UpdateExpr +//line mysql_sql.y:2173 + { + yyLOCAL = &tree.UpdateExpr{ + Names: []*tree.UnresolvedName{yyDollar[1].unresolvedNameUnion()}, + Expr: yyDollar[3].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 171: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:2181 + { + yyLOCAL = -1 + } + yyVAL.union = yyLOCAL + case 172: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:2185 + { + str := strings.ToLower(yyDollar[2].str) + if str == "true" { + yyLOCAL = 1 + } else if str == "false" { + yyLOCAL = 0 + } else { + yylex.Error("error strict flag") + goto ret1 + } + } + yyVAL.union = yyLOCAL + case 173: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:2197 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 174: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:2201 + { + str := strings.ToLower(yyDollar[2].str) + if str == "true" { + yyLOCAL = true + } else if str == "false" { + yyLOCAL = false + } else { + yylex.Error("error parallel flag") + goto ret1 + } + } + yyVAL.union = yyLOCAL + case 175: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:2215 + { + yyLOCAL = tree.NewUnresolvedName(yyDollar[1].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 176: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:2219 + { + tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedName(tblNameCStr, yyDollar[3].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 177: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:2224 + { + dbNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) + tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[3].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedName(dbNameCStr, tblNameCStr, yyDollar[5].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 178: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []tree.LoadColumn +//line mysql_sql.y:2231 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 179: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []tree.LoadColumn +//line mysql_sql.y:2235 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 180: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []tree.LoadColumn +//line mysql_sql.y:2239 + { + yyLOCAL = yyDollar[2].loadColumnsUnion() + } + yyVAL.union = yyLOCAL + case 181: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.LoadColumn +//line mysql_sql.y:2245 + { + switch yyDollar[1].loadColumnUnion().(type) { + case *tree.UnresolvedName: + yyLOCAL = []tree.LoadColumn{yyDollar[1].loadColumnUnion().(*tree.UnresolvedName)} + case *tree.VarExpr: + yyLOCAL = []tree.LoadColumn{yyDollar[1].loadColumnUnion().(*tree.VarExpr)} + } + } + yyVAL.union = yyLOCAL + case 182: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []tree.LoadColumn +//line mysql_sql.y:2254 + { + switch yyDollar[3].loadColumnUnion().(type) { + case *tree.UnresolvedName: + yyLOCAL = append(yyDollar[1].loadColumnsUnion(), yyDollar[3].loadColumnUnion().(*tree.UnresolvedName)) + case *tree.VarExpr: + yyLOCAL = append(yyDollar[1].loadColumnsUnion(), yyDollar[3].loadColumnUnion().(*tree.VarExpr)) + } + } + yyVAL.union = yyLOCAL + case 183: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.LoadColumn +//line mysql_sql.y:2265 + { + yyLOCAL = yyDollar[1].unresolvedNameUnion() + } + yyVAL.union = yyLOCAL + case 184: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.LoadColumn +//line mysql_sql.y:2269 + { + yyLOCAL = yyDollar[1].varExprUnion() + } + yyVAL.union = yyLOCAL + case 185: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.VarExpr +//line mysql_sql.y:2275 + { + yyLOCAL = []*tree.VarExpr{yyDollar[1].varExprUnion()} + } + yyVAL.union = yyLOCAL + case 186: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.VarExpr +//line mysql_sql.y:2279 + { + yyLOCAL = append(yyDollar[1].varExprsUnion(), yyDollar[3].varExprUnion()) + } + yyVAL.union = yyLOCAL + case 187: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.VarExpr +//line mysql_sql.y:2285 + { + yyLOCAL = []*tree.VarExpr{yyDollar[1].varExprUnion()} + } + yyVAL.union = yyLOCAL + case 188: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.VarExpr +//line mysql_sql.y:2289 + { + yyLOCAL = append(yyDollar[1].varExprsUnion(), yyDollar[3].varExprUnion()) + } + yyVAL.union = yyLOCAL + case 189: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.VarExpr +//line mysql_sql.y:2295 + { + yyLOCAL = yyDollar[1].varExprUnion() + } + yyVAL.union = yyLOCAL + case 190: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.VarExpr +//line mysql_sql.y:2299 + { + yyLOCAL = yyDollar[1].varExprUnion() + } + yyVAL.union = yyLOCAL + case 191: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.VarExpr +//line mysql_sql.y:2305 + { + v := strings.ToLower(yyDollar[1].str) + var isGlobal bool + if strings.HasPrefix(v, "global.") { + isGlobal = true + v = strings.TrimPrefix(v, "global.") + } else if strings.HasPrefix(v, "session.") { + v = strings.TrimPrefix(v, "session.") + } else if strings.HasPrefix(v, "local.") { + v = strings.TrimPrefix(v, "local.") + } + yyLOCAL = &tree.VarExpr{ + Name: v, + System: true, + Global: isGlobal, + } + } + yyVAL.union = yyLOCAL + case 192: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.VarExpr +//line mysql_sql.y:2325 + { + // vs := strings.Split($1, ".") + // var r string + // if len(vs) == 2 { + // r = vs[1] + // } else if len(vs) == 1 { + // r = vs[0] + // } else { + // yylex.Error("variable syntax error") + // goto ret1 + // } + yyLOCAL = &tree.VarExpr{ + Name: yyDollar[1].str, + System: false, + Global: false, + } + } + yyVAL.union = yyLOCAL + case 193: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:2344 + { + yyLOCAL = 0 + } + yyVAL.union = yyLOCAL + case 194: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:2348 + { + value, ok := signedIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + yyLOCAL = value + } + yyVAL.union = yyLOCAL + case 195: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:2354 + { + value, ok := signedIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + yyLOCAL = value + } + yyVAL.union = yyLOCAL + case 196: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.Lines +//line mysql_sql.y:2361 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 197: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.Lines +//line mysql_sql.y:2365 + { + yyLOCAL = &tree.Lines{ + StartingBy: yyDollar[2].str, + TerminatedBy: &tree.Terminated{ + Value: yyDollar[3].str, + }, + } + } + yyVAL.union = yyLOCAL + case 198: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.Lines +//line mysql_sql.y:2374 + { + yyLOCAL = &tree.Lines{ + StartingBy: yyDollar[3].str, + TerminatedBy: &tree.Terminated{ + Value: yyDollar[2].str, + }, + } + } + yyVAL.union = yyLOCAL + case 199: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:2384 + { + yyVAL.str = "" + } + case 201: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:2391 + { + yyVAL.str = yyDollar[3].str + } + case 202: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:2396 + { + yyVAL.str = "\n" + } + case 204: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:2403 + { + yyVAL.str = yyDollar[3].str + } + case 205: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.Fields +//line mysql_sql.y:2408 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 206: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.Fields +//line mysql_sql.y:2412 + { + res := &tree.Fields{ + Terminated: &tree.Terminated{ + Value: "\t", + }, + EnclosedBy: &tree.EnclosedBy{ + Value: byte(0), + }, + } + for _, f := range yyDollar[2].fieldsListUnion() { + if f.Terminated != nil { + res.Terminated = f.Terminated + } + if f.Optionally { + res.Optionally = f.Optionally + } + if f.EnclosedBy != nil { + res.EnclosedBy = f.EnclosedBy + } + if f.EscapedBy != nil { + res.EscapedBy = f.EscapedBy + } + } + yyLOCAL = res + } + yyVAL.union = yyLOCAL + case 207: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.Fields +//line mysql_sql.y:2440 + { + yyLOCAL = []*tree.Fields{yyDollar[1].fieldsUnion()} + } + yyVAL.union = yyLOCAL + case 208: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []*tree.Fields +//line mysql_sql.y:2444 + { + yyLOCAL = append(yyDollar[1].fieldsListUnion(), yyDollar[2].fieldsUnion()) + } + yyVAL.union = yyLOCAL + case 209: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.Fields +//line mysql_sql.y:2450 + { + yyLOCAL = &tree.Fields{ + Terminated: &tree.Terminated{ + Value: yyDollar[3].str, + }, + } + } + yyVAL.union = yyLOCAL + case 210: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Fields +//line mysql_sql.y:2458 + { + str := yyDollar[4].str + if str != "\\" && len(str) > 1 { + yylex.Error("error field terminator") + goto ret1 + } + var b byte + if len(str) != 0 { + b = byte(str[0]) + } else { + b = 0 + } + yyLOCAL = &tree.Fields{ + Optionally: true, + EnclosedBy: &tree.EnclosedBy{ + Value: b, + }, + } + } + yyVAL.union = yyLOCAL + case 211: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.Fields +//line mysql_sql.y:2478 + { + str := yyDollar[3].str + if str != "\\" && len(str) > 1 { + yylex.Error("error field terminator") + goto ret1 + } + var b byte + if len(str) != 0 { + b = byte(str[0]) + } else { + b = 0 + } + yyLOCAL = &tree.Fields{ + EnclosedBy: &tree.EnclosedBy{ + Value: b, + }, + } + } + yyVAL.union = yyLOCAL + case 212: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.Fields +//line mysql_sql.y:2497 + { + str := yyDollar[3].str + if str != "\\" && len(str) > 1 { + yylex.Error("error field terminator") + goto ret1 + } + var b byte + if len(str) != 0 { + b = byte(str[0]) + } else { + b = 0 + } + yyLOCAL = &tree.Fields{ + EscapedBy: &tree.EscapedBy{ + Value: b, + }, + } + } + yyVAL.union = yyLOCAL + case 214: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.DuplicateKey +//line mysql_sql.y:2522 + { + yyLOCAL = &tree.DuplicateKeyError{} + } + yyVAL.union = yyLOCAL + case 215: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.DuplicateKey +//line mysql_sql.y:2526 + { + yyLOCAL = &tree.DuplicateKeyIgnore{} + } + yyVAL.union = yyLOCAL + case 216: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.DuplicateKey +//line mysql_sql.y:2530 + { + yyLOCAL = &tree.DuplicateKeyReplace{} + } + yyVAL.union = yyLOCAL + case 217: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:2535 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 218: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:2539 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 219: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2545 + { + yyLOCAL = &tree.Grant{ + Typ: tree.GrantTypePrivilege, + GrantPrivilege: tree.GrantPrivilege{ + Privileges: yyDollar[2].privilegesUnion(), + ObjType: yyDollar[4].objectTypeUnion(), + Level: yyDollar[5].privilegeLevelUnion(), + Roles: yyDollar[7].rolesUnion(), + GrantOption: yyDollar[8].boolValUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 220: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2558 + { + yyLOCAL = &tree.Grant{ + Typ: tree.GrantTypeRole, + GrantRole: tree.GrantRole{ + Roles: yyDollar[2].rolesUnion(), + Users: yyDollar[4].usersUnion(), + GrantOption: yyDollar[5].boolValUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 221: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2569 + { + yyLOCAL = &tree.Grant{ + Typ: tree.GrantTypeProxy, + GrantProxy: tree.GrantProxy{ + ProxyUser: yyDollar[4].userUnion(), + Users: yyDollar[6].usersUnion(), + GrantOption: yyDollar[7].boolValUnion(), + }, + } + + } + yyVAL.union = yyLOCAL + case 222: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:2582 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 223: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:2586 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 224: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2596 + { + yyLOCAL = &tree.Revoke{ + Typ: tree.RevokeTypePrivilege, + RevokePrivilege: tree.RevokePrivilege{ + IfExists: yyDollar[2].boolValUnion(), + Privileges: yyDollar[3].privilegesUnion(), + ObjType: yyDollar[5].objectTypeUnion(), + Level: yyDollar[6].privilegeLevelUnion(), + Roles: yyDollar[8].rolesUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 225: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2609 + { + yyLOCAL = &tree.Revoke{ + Typ: tree.RevokeTypeRole, + RevokeRole: tree.RevokeRole{ + IfExists: yyDollar[2].boolValUnion(), + Roles: yyDollar[3].rolesUnion(), + Users: yyDollar[5].usersUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 226: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.PrivilegeLevel +//line mysql_sql.y:2622 + { + yyLOCAL = &tree.PrivilegeLevel{ + Level: tree.PRIVILEGE_LEVEL_TYPE_STAR, + } + } + yyVAL.union = yyLOCAL + case 227: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.PrivilegeLevel +//line mysql_sql.y:2628 + { + yyLOCAL = &tree.PrivilegeLevel{ + Level: tree.PRIVILEGE_LEVEL_TYPE_STAR_STAR, + } + } + yyVAL.union = yyLOCAL + case 228: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.PrivilegeLevel +//line mysql_sql.y:2634 + { + tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + yyLOCAL = &tree.PrivilegeLevel{ + Level: tree.PRIVILEGE_LEVEL_TYPE_DATABASE_STAR, + DbName: tblName, + } + } + yyVAL.union = yyLOCAL + case 229: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.PrivilegeLevel +//line mysql_sql.y:2642 + { + dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[3].cstrUnion().Origin()) + yyLOCAL = &tree.PrivilegeLevel{ + Level: tree.PRIVILEGE_LEVEL_TYPE_DATABASE_TABLE, + DbName: dbName, + TabName: tblName, + } + } + yyVAL.union = yyLOCAL + case 230: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.PrivilegeLevel +//line mysql_sql.y:2652 + { + tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + yyLOCAL = &tree.PrivilegeLevel{ + Level: tree.PRIVILEGE_LEVEL_TYPE_TABLE, + TabName: tblName, + } + } + yyVAL.union = yyLOCAL + case 231: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ObjectType +//line mysql_sql.y:2662 + { + yyLOCAL = tree.OBJECT_TYPE_TABLE + } + yyVAL.union = yyLOCAL + case 232: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ObjectType +//line mysql_sql.y:2666 + { + yyLOCAL = tree.OBJECT_TYPE_DATABASE + } + yyVAL.union = yyLOCAL + case 233: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ObjectType +//line mysql_sql.y:2670 + { + yyLOCAL = tree.OBJECT_TYPE_FUNCTION + } + yyVAL.union = yyLOCAL + case 234: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ObjectType +//line mysql_sql.y:2674 + { + yyLOCAL = tree.OBJECT_TYPE_PROCEDURE + } + yyVAL.union = yyLOCAL + case 235: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ObjectType +//line mysql_sql.y:2678 + { + yyLOCAL = tree.OBJECT_TYPE_VIEW + } + yyVAL.union = yyLOCAL + case 236: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ObjectType +//line mysql_sql.y:2682 + { + yyLOCAL = tree.OBJECT_TYPE_ACCOUNT + } + yyVAL.union = yyLOCAL + case 237: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.Privilege +//line mysql_sql.y:2688 + { + yyLOCAL = []*tree.Privilege{yyDollar[1].privilegeUnion()} + } + yyVAL.union = yyLOCAL + case 238: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.Privilege +//line mysql_sql.y:2692 + { + yyLOCAL = append(yyDollar[1].privilegesUnion(), yyDollar[3].privilegeUnion()) + } + yyVAL.union = yyLOCAL + case 239: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Privilege +//line mysql_sql.y:2698 + { + yyLOCAL = &tree.Privilege{ + Type: yyDollar[1].privilegeTypeUnion(), + ColumnList: nil, + } + } + yyVAL.union = yyLOCAL + case 240: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Privilege +//line mysql_sql.y:2705 + { + yyLOCAL = &tree.Privilege{ + Type: yyDollar[1].privilegeTypeUnion(), + ColumnList: yyDollar[3].unresolveNamesUnion(), + } + } + yyVAL.union = yyLOCAL + case 241: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.UnresolvedName +//line mysql_sql.y:2714 + { + yyLOCAL = []*tree.UnresolvedName{yyDollar[1].unresolvedNameUnion()} + } + yyVAL.union = yyLOCAL + case 242: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.UnresolvedName +//line mysql_sql.y:2718 + { + yyLOCAL = append(yyDollar[1].unresolveNamesUnion(), yyDollar[3].unresolvedNameUnion()) + } + yyVAL.union = yyLOCAL + case 243: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2724 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALL + } + yyVAL.union = yyLOCAL + case 244: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2728 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_ACCOUNT + } + yyVAL.union = yyLOCAL + case 245: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2732 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_ACCOUNT + } + yyVAL.union = yyLOCAL + case 246: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2736 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_ACCOUNT + } + yyVAL.union = yyLOCAL + case 247: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2740 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_UPGRADE_ACCOUNT + } + yyVAL.union = yyLOCAL + case 248: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2744 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALL + } + yyVAL.union = yyLOCAL + case 249: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2748 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_TABLE + } + yyVAL.union = yyLOCAL + case 250: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2752 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_VIEW + } + yyVAL.union = yyLOCAL + case 251: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2756 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE + } + yyVAL.union = yyLOCAL + case 252: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2760 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_USER + } + yyVAL.union = yyLOCAL + case 253: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2764 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_USER + } + yyVAL.union = yyLOCAL + case 254: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2768 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_USER + } + yyVAL.union = yyLOCAL + case 255: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2772 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_TABLESPACE + } + yyVAL.union = yyLOCAL + case 256: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2776 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_TRIGGER + } + yyVAL.union = yyLOCAL + case 257: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2780 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DELETE + } + yyVAL.union = yyLOCAL + case 258: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2784 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_TABLE + } + yyVAL.union = yyLOCAL + case 259: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2788 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_VIEW + } + yyVAL.union = yyLOCAL + case 260: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2792 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_EXECUTE + } + yyVAL.union = yyLOCAL + case 261: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2796 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_INDEX + } + yyVAL.union = yyLOCAL + case 262: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2800 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_INSERT + } + yyVAL.union = yyLOCAL + case 263: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2804 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SELECT + } + yyVAL.union = yyLOCAL + case 264: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2808 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SUPER + } + yyVAL.union = yyLOCAL + case 265: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2812 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_DATABASE + } + yyVAL.union = yyLOCAL + case 266: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2816 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_DATABASE + } + yyVAL.union = yyLOCAL + case 267: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2820 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SHOW_DATABASES + } + yyVAL.union = yyLOCAL + case 268: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2824 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CONNECT + } + yyVAL.union = yyLOCAL + case 269: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2828 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_MANAGE_GRANTS + } + yyVAL.union = yyLOCAL + case 270: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2832 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_OWNERSHIP + } + yyVAL.union = yyLOCAL + case 271: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2836 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SHOW_TABLES + } + yyVAL.union = yyLOCAL + case 272: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2840 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_TABLE + } + yyVAL.union = yyLOCAL + case 273: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2844 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_UPDATE + } + yyVAL.union = yyLOCAL + case 274: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2848 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_GRANT_OPTION + } + yyVAL.union = yyLOCAL + case 275: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2852 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_REFERENCES + } + yyVAL.union = yyLOCAL + case 276: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2856 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_REFERENCE + } + yyVAL.union = yyLOCAL + case 277: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2860 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_REPLICATION_SLAVE + } + yyVAL.union = yyLOCAL + case 278: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2864 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_REPLICATION_CLIENT + } + yyVAL.union = yyLOCAL + case 279: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2868 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_USAGE + } + yyVAL.union = yyLOCAL + case 280: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2872 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_RELOAD + } + yyVAL.union = yyLOCAL + case 281: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2876 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_FILE + } + yyVAL.union = yyLOCAL + case 282: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2880 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_TEMPORARY_TABLES + } + yyVAL.union = yyLOCAL + case 283: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2884 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_LOCK_TABLES + } + yyVAL.union = yyLOCAL + case 284: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2888 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_VIEW + } + yyVAL.union = yyLOCAL + case 285: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2892 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SHOW_VIEW + } + yyVAL.union = yyLOCAL + case 286: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2896 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_ROLE + } + yyVAL.union = yyLOCAL + case 287: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2900 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_DROP_ROLE + } + yyVAL.union = yyLOCAL + case 288: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2904 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_ROLE + } + yyVAL.union = yyLOCAL + case 289: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2908 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_CREATE_ROUTINE + } + yyVAL.union = yyLOCAL + case 290: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2912 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_ALTER_ROUTINE + } + yyVAL.union = yyLOCAL + case 291: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2916 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_EVENT + } + yyVAL.union = yyLOCAL + case 292: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2920 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_SHUTDOWN + } + yyVAL.union = yyLOCAL + case 293: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PrivilegeType +//line mysql_sql.y:2924 + { + yyLOCAL = tree.PRIVILEGE_TYPE_STATIC_TRUNCATE + } + yyVAL.union = yyLOCAL + case 301: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2939 + { + yyLOCAL = &tree.SetLogserviceSettings{ + Name: yyDollar[4].str, + Value: yyDollar[6].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 302: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2948 + { + yyLOCAL = &tree.SetTransaction{ + Scope: tree.TransactionScopeNext, + CharacterList: yyDollar[3].transactionCharacteristicListUnion(), + } + } + yyVAL.union = yyLOCAL + case 303: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2955 + { + yyLOCAL = &tree.SetTransaction{ + Scope: tree.TransactionScopeGlobal, + CharacterList: yyDollar[4].transactionCharacteristicListUnion(), + } + } + yyVAL.union = yyLOCAL + case 304: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2962 + { + yyLOCAL = &tree.SetTransaction{ + Scope: tree.TransactionScopeSession, + CharacterList: yyDollar[4].transactionCharacteristicListUnion(), + } + } + yyVAL.union = yyLOCAL + case 305: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:2971 + { + var connID uint32 + switch v := yyDollar[5].item.(type) { + case uint64: + connID = uint32(v) + case int64: + connID = uint32(v) + default: + yylex.Error("parse integral fail") + goto ret1 + } + yyLOCAL = &tree.SetConnectionID{ + ConnectionID: connID, + } + } + yyVAL.union = yyLOCAL + case 306: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.TransactionCharacteristic +//line mysql_sql.y:2989 + { + yyLOCAL = []*tree.TransactionCharacteristic{yyDollar[1].transactionCharacteristicUnion()} + } + yyVAL.union = yyLOCAL + case 307: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.TransactionCharacteristic +//line mysql_sql.y:2993 + { + yyLOCAL = append(yyDollar[1].transactionCharacteristicListUnion(), yyDollar[3].transactionCharacteristicUnion()) + } + yyVAL.union = yyLOCAL + case 308: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.TransactionCharacteristic +//line mysql_sql.y:2999 + { + yyLOCAL = &tree.TransactionCharacteristic{ + IsLevel: true, + Isolation: yyDollar[3].isolationLevelUnion(), + } + } + yyVAL.union = yyLOCAL + case 309: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.TransactionCharacteristic +//line mysql_sql.y:3006 + { + yyLOCAL = &tree.TransactionCharacteristic{ + Access: yyDollar[1].accessModeUnion(), + } + } + yyVAL.union = yyLOCAL + case 310: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IsolationLevelType +//line mysql_sql.y:3014 + { + yyLOCAL = tree.ISOLATION_LEVEL_REPEATABLE_READ + } + yyVAL.union = yyLOCAL + case 311: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IsolationLevelType +//line mysql_sql.y:3018 + { + yyLOCAL = tree.ISOLATION_LEVEL_READ_COMMITTED + } + yyVAL.union = yyLOCAL + case 312: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IsolationLevelType +//line mysql_sql.y:3022 + { + yyLOCAL = tree.ISOLATION_LEVEL_READ_UNCOMMITTED + } + yyVAL.union = yyLOCAL + case 313: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IsolationLevelType +//line mysql_sql.y:3026 + { + yyLOCAL = tree.ISOLATION_LEVEL_SERIALIZABLE + } + yyVAL.union = yyLOCAL + case 314: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AccessModeType +//line mysql_sql.y:3032 + { + yyLOCAL = tree.ACCESS_MODE_READ_WRITE + } + yyVAL.union = yyLOCAL + case 315: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AccessModeType +//line mysql_sql.y:3036 + { + yyLOCAL = tree.ACCESS_MODE_READ_ONLY + } + yyVAL.union = yyLOCAL + case 316: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3042 + { + yyLOCAL = &tree.SetRole{ + SecondaryRole: false, + Role: yyDollar[3].roleUnion(), + } + } + yyVAL.union = yyLOCAL + case 317: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3049 + { + yyLOCAL = &tree.SetRole{ + SecondaryRole: true, + SecondaryRoleType: tree.SecondaryRoleTypeAll, + } + } + yyVAL.union = yyLOCAL + case 318: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3056 + { + yyLOCAL = &tree.SetRole{ + SecondaryRole: true, + SecondaryRoleType: tree.SecondaryRoleTypeNone, + } + } + yyVAL.union = yyLOCAL + case 319: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3065 + { + dr := yyDollar[4].setDefaultRoleUnion() + dr.Users = yyDollar[6].usersUnion() + yyLOCAL = dr + } + yyVAL.union = yyLOCAL + case 320: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.SetDefaultRole +//line mysql_sql.y:3095 + { + yyLOCAL = &tree.SetDefaultRole{Type: tree.SET_DEFAULT_ROLE_TYPE_NONE, Roles: nil} + } + yyVAL.union = yyLOCAL + case 321: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.SetDefaultRole +//line mysql_sql.y:3099 + { + yyLOCAL = &tree.SetDefaultRole{Type: tree.SET_DEFAULT_ROLE_TYPE_ALL, Roles: nil} + } + yyVAL.union = yyLOCAL + case 322: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.SetDefaultRole +//line mysql_sql.y:3103 + { + yyLOCAL = &tree.SetDefaultRole{Type: tree.SET_DEFAULT_ROLE_TYPE_NORMAL, Roles: yyDollar[1].rolesUnion()} + } + yyVAL.union = yyLOCAL + case 323: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3109 + { + yyLOCAL = &tree.SetVar{Assignments: yyDollar[2].varAssignmentExprsUnion()} + } + yyVAL.union = yyLOCAL + case 324: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3115 + { + yyLOCAL = &tree.SetPassword{Password: yyDollar[4].str} + } + yyVAL.union = yyLOCAL + case 325: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3119 + { + yyLOCAL = &tree.SetPassword{User: yyDollar[4].userUnion(), Password: yyDollar[6].str} + } + yyVAL.union = yyLOCAL + case 327: + yyDollar = yyS[yypt-4 : yypt+1] +//line mysql_sql.y:3126 + { + yyVAL.str = yyDollar[3].str + } + case 328: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.VarAssignmentExpr +//line mysql_sql.y:3132 + { + yyLOCAL = []*tree.VarAssignmentExpr{yyDollar[1].varAssignmentExprUnion()} + } + yyVAL.union = yyLOCAL + case 329: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.VarAssignmentExpr +//line mysql_sql.y:3136 + { + yyLOCAL = append(yyDollar[1].varAssignmentExprsUnion(), yyDollar[3].varAssignmentExprUnion()) + } + yyVAL.union = yyLOCAL + case 330: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3142 + { + yyLOCAL = &tree.VarAssignmentExpr{ + System: true, + TxnScope: tree.TransactionScopeSession, + Name: yyDollar[1].str, + Value: yyDollar[3].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 331: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3151 + { + yyLOCAL = &tree.VarAssignmentExpr{ + System: true, + Global: true, + TxnScope: tree.TransactionScopeGlobal, + Name: yyDollar[2].str, + Value: yyDollar[4].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 332: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3161 + { + yyLOCAL = &tree.VarAssignmentExpr{ + System: true, + Global: true, + TxnScope: tree.TransactionScopeGlobal, + Name: yyDollar[2].str, + Value: yyDollar[4].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 333: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3171 + { + yyLOCAL = &tree.VarAssignmentExpr{ + System: true, + TxnScope: tree.TransactionScopeSession, + Name: yyDollar[2].str, + Value: yyDollar[4].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 334: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3180 + { + yyLOCAL = &tree.VarAssignmentExpr{ + System: true, + TxnScope: tree.TransactionScopeSession, + Name: yyDollar[2].str, + Value: yyDollar[4].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 335: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3189 + { + vs := strings.Split(yyDollar[1].str, ".") + var isGlobal bool + if strings.ToLower(vs[0]) == "global" { + isGlobal = true + } + var r string + if len(vs) == 2 { + r = vs[1] + } else if len(vs) == 1 { + r = vs[0] + } else { + yylex.Error("variable syntax error") + goto ret1 + } + yyLOCAL = &tree.VarAssignmentExpr{ + System: false, + Global: isGlobal, + Name: r, + Value: yyDollar[3].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 336: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3212 + { + v := strings.ToLower(yyDollar[1].str) + var isGlobal bool + txnScope := tree.TransactionScopeNext + if strings.HasPrefix(v, "global.") { + isGlobal = true + txnScope = tree.TransactionScopeGlobal + v = strings.TrimPrefix(v, "global.") + } else if strings.HasPrefix(v, "session.") { + txnScope = tree.TransactionScopeSession + v = strings.TrimPrefix(v, "session.") + } else if strings.HasPrefix(v, "local.") { + txnScope = tree.TransactionScopeSession + v = strings.TrimPrefix(v, "local.") + } + yyLOCAL = &tree.VarAssignmentExpr{ + System: true, + Global: isGlobal, + TxnScope: txnScope, + Name: v, + Value: yyDollar[3].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 337: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3236 + { + yyLOCAL = &tree.VarAssignmentExpr{ + SetNames: true, + Name: strings.ToLower(yyDollar[1].str), + Value: tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char), + } + } + yyVAL.union = yyLOCAL + case 338: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3244 + { + yyLOCAL = &tree.VarAssignmentExpr{ + SetNames: true, + Name: strings.ToLower(yyDollar[1].str), + Value: tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char), + } + } + yyVAL.union = yyLOCAL + case 339: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3252 + { + yyLOCAL = &tree.VarAssignmentExpr{ + SetNames: true, + Name: strings.ToLower(yyDollar[1].str), + Value: tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char), + Reserved: tree.NewNumVal(yyDollar[4].str, yyDollar[4].str, false, tree.P_char), + } + } + yyVAL.union = yyLOCAL + case 340: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3261 + { + yyLOCAL = &tree.VarAssignmentExpr{ + SetNames: true, + Name: strings.ToLower(yyDollar[1].str), + Value: &tree.DefaultVal{}, + } + } + yyVAL.union = yyLOCAL + case 341: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3269 + { + yyLOCAL = &tree.VarAssignmentExpr{ + CharsetRequest: true, + Name: strings.ToLower(yyDollar[1].str), + Value: tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char), + } + } + yyVAL.union = yyLOCAL + case 342: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.VarAssignmentExpr +//line mysql_sql.y:3277 + { + yyLOCAL = &tree.VarAssignmentExpr{ + CharsetRequest: true, + Name: strings.ToLower(yyDollar[1].str), + Value: &tree.DefaultVal{}, + } + } + yyVAL.union = yyLOCAL + case 343: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:3287 + { + yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_char) + } + yyVAL.union = yyLOCAL + case 344: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:3291 + { + yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_char) + } + yyVAL.union = yyLOCAL + case 345: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:3295 + { + yyLOCAL = yyDollar[1].exprUnion() + } + yyVAL.union = yyLOCAL + case 346: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:3301 + { + yyVAL.str = string(yyDollar[1].str) + } + case 347: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:3305 + { + yyVAL.str = yyDollar[1].str + } + case 348: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:3311 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 349: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:3315 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + "." + yyDollar[3].cstrUnion().Compare() + } + case 350: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:3321 + { + yyLOCAL = []string{yyDollar[1].str} + } + yyVAL.union = yyLOCAL + case 351: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:3325 + { + yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 358: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3339 + { + yyLOCAL = &tree.SavePoint{Name: tree.Identifier(yyDollar[2].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 359: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3345 + { + yyLOCAL = &tree.ReleaseSavePoint{Name: tree.Identifier(yyDollar[3].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 360: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3351 + { + yyLOCAL = &tree.RollbackToSavePoint{Name: tree.Identifier(yyDollar[3].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 361: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3356 + { + yyLOCAL = &tree.RollbackToSavePoint{Name: tree.Identifier(yyDollar[4].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 362: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3361 + { + yyLOCAL = &tree.RollbackToSavePoint{Name: tree.Identifier(yyDollar[5].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 363: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3366 + { + yyLOCAL = &tree.RollbackToSavePoint{Name: tree.Identifier(yyDollar[4].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 364: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3372 + { + yyLOCAL = &tree.RollbackTransaction{Type: yyDollar[2].completionTypeUnion()} + } + yyVAL.union = yyLOCAL + case 365: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3378 + { + yyLOCAL = &tree.CommitTransaction{Type: yyDollar[2].completionTypeUnion()} + } + yyVAL.union = yyLOCAL + case 366: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.CompletionType +//line mysql_sql.y:3383 + { + yyLOCAL = tree.COMPLETION_TYPE_NO_CHAIN + } + yyVAL.union = yyLOCAL + case 367: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.CompletionType +//line mysql_sql.y:3387 + { + yyLOCAL = tree.COMPLETION_TYPE_NO_CHAIN + } + yyVAL.union = yyLOCAL + case 368: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.CompletionType +//line mysql_sql.y:3391 + { + yyLOCAL = tree.COMPLETION_TYPE_CHAIN + } + yyVAL.union = yyLOCAL + case 369: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.CompletionType +//line mysql_sql.y:3395 + { + yyLOCAL = tree.COMPLETION_TYPE_CHAIN + } + yyVAL.union = yyLOCAL + case 370: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.CompletionType +//line mysql_sql.y:3399 + { + yyLOCAL = tree.COMPLETION_TYPE_RELEASE + } + yyVAL.union = yyLOCAL + case 371: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.CompletionType +//line mysql_sql.y:3403 + { + yyLOCAL = tree.COMPLETION_TYPE_RELEASE + } + yyVAL.union = yyLOCAL + case 372: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.CompletionType +//line mysql_sql.y:3407 + { + yyLOCAL = tree.COMPLETION_TYPE_NO_CHAIN + } + yyVAL.union = yyLOCAL + case 373: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.CompletionType +//line mysql_sql.y:3411 + { + yyLOCAL = tree.COMPLETION_TYPE_NO_CHAIN + } + yyVAL.union = yyLOCAL + case 374: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.CompletionType +//line mysql_sql.y:3415 + { + yyLOCAL = tree.COMPLETION_TYPE_NO_CHAIN + } + yyVAL.union = yyLOCAL + case 375: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3421 + { + yyLOCAL = &tree.BeginTransaction{} + } + yyVAL.union = yyLOCAL + case 376: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3425 + { + yyLOCAL = &tree.BeginTransaction{} + } + yyVAL.union = yyLOCAL + case 377: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3429 + { + yyLOCAL = &tree.BeginTransaction{} + } + yyVAL.union = yyLOCAL + case 378: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3433 + { + m := tree.MakeTransactionModes(tree.READ_WRITE_MODE_READ_WRITE) + yyLOCAL = &tree.BeginTransaction{Modes: m} + } + yyVAL.union = yyLOCAL + case 379: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3438 + { + m := tree.MakeTransactionModes(tree.READ_WRITE_MODE_READ_ONLY) + yyLOCAL = &tree.BeginTransaction{Modes: m} + } + yyVAL.union = yyLOCAL + case 380: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3443 + { + yyLOCAL = &tree.BeginTransaction{} + } + yyVAL.union = yyLOCAL + case 381: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3449 + { + name := yyDollar[2].cstrUnion() + secondaryRole := false + var secondaryRoleType tree.SecondaryRoleType = 0 + var role *tree.Role + yyLOCAL = tree.NewUse( + name, + secondaryRole, + secondaryRoleType, + role, + ) + } + yyVAL.union = yyLOCAL + case 382: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3462 + { + name := yylex.(*Lexer).GetDbOrTblNameCStr("") + secondaryRole := false + var secondaryRoleType tree.SecondaryRoleType = 0 + var role *tree.Role + yyLOCAL = tree.NewUse( + name, + secondaryRole, + secondaryRoleType, + role, + ) + } + yyVAL.union = yyLOCAL + case 383: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3475 + { + name := yylex.(*Lexer).GetDbOrTblNameCStr("") + secondaryRole := false + var secondaryRoleType tree.SecondaryRoleType = 0 + role := yyDollar[3].roleUnion() + yyLOCAL = tree.NewUse( + name, + secondaryRole, + secondaryRoleType, + role, + ) + } + yyVAL.union = yyLOCAL + case 384: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3488 + { + name := yylex.(*Lexer).GetDbOrTblNameCStr("") + secondaryRole := true + secondaryRoleType := tree.SecondaryRoleTypeAll + var role *tree.Role + yyLOCAL = tree.NewUse( + name, + secondaryRole, + secondaryRoleType, + role, + ) + } + yyVAL.union = yyLOCAL + case 385: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3501 + { + name := yylex.(*Lexer).GetDbOrTblNameCStr("") + secondaryRole := true + secondaryRoleType := tree.SecondaryRoleTypeNone + var role *tree.Role + yyLOCAL = tree.NewUse( + name, + secondaryRole, + secondaryRoleType, + role, + ) + } + yyVAL.union = yyLOCAL + case 386: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3516 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[1].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = yyDollar[1].statementUnion() + } + yyVAL.union = yyLOCAL + case 387: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3524 + { + yyDollar[2].statementUnion().(*tree.Update).With = yyDollar[1].withClauseUnion() + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[2].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = yyDollar[2].statementUnion() + } + yyVAL.union = yyLOCAL + case 388: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3535 + { + // Single-table syntax + yyLOCAL = &tree.Update{ + Tables: tree.TableExprs{yyDollar[4].tableExprUnion()}, + Exprs: yyDollar[6].updateExprsUnion(), + Priority: yyDollar[2].str, + Ignore: yyDollar[3].str != "", + Where: yyDollar[7].whereUnion(), + OrderBy: yyDollar[8].orderByUnion(), + Limit: yyDollar[9].limitUnion(), + Returning: yyDollar[10].selectExprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 389: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3549 + { + // Multiple-table syntax + yyLOCAL = &tree.Update{ + Tables: tree.TableExprs{yyDollar[4].tableExprUnion()}, + Exprs: yyDollar[6].updateExprsUnion(), + Priority: yyDollar[2].str, + Ignore: yyDollar[3].str != "", + Where: yyDollar[7].whereUnion(), + Returning: yyDollar[8].selectExprsUnion(), + MultiTable: true, + } + } + yyVAL.union = yyLOCAL + case 390: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3562 + { + // PostgreSQL-style UPDATE target SET ... FROM source_tables WHERE ... + // The target table is kept in Tables; FROM-clause sources are stored + // separately in From so the binder/planner can treat them as read-only + // join sources rather than DML targets. + yyLOCAL = &tree.Update{ + Tables: tree.TableExprs{yyDollar[4].tableExprUnion()}, + Exprs: yyDollar[6].updateExprsUnion(), + Priority: yyDollar[2].str, + Ignore: yyDollar[3].str != "", + From: &tree.From{Tables: tree.TableExprs{yyDollar[8].tableExprUnion()}}, + Where: yyDollar[9].whereUnion(), + Returning: yyDollar[10].selectExprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 391: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.UpdateExprs +//line mysql_sql.y:3580 + { + yyLOCAL = tree.UpdateExprs{yyDollar[1].updateExprUnion()} + } + yyVAL.union = yyLOCAL + case 392: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.UpdateExprs +//line mysql_sql.y:3584 + { + yyLOCAL = append(yyDollar[1].updateExprsUnion(), yyDollar[3].updateExprUnion()) + } + yyVAL.union = yyLOCAL + case 393: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.UpdateExpr +//line mysql_sql.y:3590 + { + yyLOCAL = &tree.UpdateExpr{Names: []*tree.UnresolvedName{yyDollar[1].unresolvedNameUnion()}, Expr: yyDollar[3].exprUnion()} + } + yyVAL.union = yyLOCAL + case 396: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3600 + { + yyLOCAL = &tree.LockTableStmt{TableLocks: yyDollar[3].tableLocksUnion()} + } + yyVAL.union = yyLOCAL + case 397: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.TableLock +//line mysql_sql.y:3606 + { + yyLOCAL = []tree.TableLock{yyDollar[1].tableLockUnion()} + } + yyVAL.union = yyLOCAL + case 398: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []tree.TableLock +//line mysql_sql.y:3610 + { + yyLOCAL = append(yyDollar[1].tableLocksUnion(), yyDollar[3].tableLockUnion()) + } + yyVAL.union = yyLOCAL + case 399: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.TableLock +//line mysql_sql.y:3616 + { + yyLOCAL = tree.TableLock{Table: *yyDollar[1].tableNameUnion(), LockType: yyDollar[2].tableLockTypeUnion()} + } + yyVAL.union = yyLOCAL + case 400: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableLockType +//line mysql_sql.y:3622 + { + yyLOCAL = tree.TableLockRead + } + yyVAL.union = yyLOCAL + case 401: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.TableLockType +//line mysql_sql.y:3626 + { + yyLOCAL = tree.TableLockReadLocal + } + yyVAL.union = yyLOCAL + case 402: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableLockType +//line mysql_sql.y:3630 + { + yyLOCAL = tree.TableLockWrite + } + yyVAL.union = yyLOCAL + case 403: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.TableLockType +//line mysql_sql.y:3634 + { + yyLOCAL = tree.TableLockLowPriorityWrite + } + yyVAL.union = yyLOCAL + case 404: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3640 + { + yyLOCAL = &tree.UnLockTableStmt{} + } + yyVAL.union = yyLOCAL + case 414: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3655 + { + yyLOCAL = &tree.SetVar{Assignments: yyDollar[2].varAssignmentExprsUnion()} + } + yyVAL.union = yyLOCAL + case 418: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3662 + { + yyLOCAL = yyDollar[1].selectUnion() + } + yyVAL.union = yyLOCAL + case 419: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3668 + { + yyLOCAL = tree.NewPrepareStmt(tree.Identifier(yyDollar[2].str), yyDollar[4].statementUnion()) + } + yyVAL.union = yyLOCAL + case 420: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3672 + { + yyLOCAL = tree.NewPrepareString(tree.Identifier(yyDollar[2].str), yyDollar[4].str) + } + yyVAL.union = yyLOCAL + case 421: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3676 + { + yyLOCAL = tree.NewPrepareVar(tree.Identifier(yyDollar[2].str), yyDollar[4].varExprUnion()) + } + yyVAL.union = yyLOCAL + case 422: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3682 + { + yyLOCAL = &tree.ExecuteSQLTask{ + Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 423: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3688 + { + yyLOCAL = tree.NewExecute(tree.Identifier(yyDollar[2].str)) + } + yyVAL.union = yyLOCAL + case 424: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3692 + { + yyLOCAL = tree.NewExecuteWithVariables(tree.Identifier(yyDollar[2].str), yyDollar[4].varExprsUnion()) + } + yyVAL.union = yyLOCAL + case 425: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3698 + { + yyLOCAL = tree.NewDeallocate(tree.Identifier(yyDollar[3].str), false) + } + yyVAL.union = yyLOCAL + case 426: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3704 + { + yyLOCAL = tree.NewReset(tree.Identifier(yyDollar[3].str)) + } + yyVAL.union = yyLOCAL + case 432: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3715 + { + yyLOCAL = yyDollar[1].selectUnion() + } + yyVAL.union = yyLOCAL + case 433: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3721 + { + yyLOCAL = &tree.ShowColumns{Table: yyDollar[2].unresolvedObjectNameUnion()} + } + yyVAL.union = yyLOCAL + case 434: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3725 + { + yyLOCAL = &tree.ShowColumns{Table: yyDollar[2].unresolvedObjectNameUnion(), ColName: yyDollar[3].unresolvedNameUnion()} + } + yyVAL.union = yyLOCAL + case 435: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3729 + { + yyLOCAL = tree.NewExplainFor("", integralToUint64(yyDollar[4].item)) + } + yyVAL.union = yyLOCAL + case 436: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3733 + { + yyLOCAL = tree.NewExplainFor(yyDollar[4].str, integralToUint64(yyDollar[7].item)) + } + yyVAL.union = yyLOCAL + case 437: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3737 + { + yyLOCAL = yyDollar[1].statementUnion() + } + yyVAL.union = yyLOCAL + case 438: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3743 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[5].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.FormatOption, yyDollar[4].str), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[5].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 439: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3754 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[5].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.FormatOption, yyDollar[4].str), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[5].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 440: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3765 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[6].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), + tree.MakeOptionElem(tree.FormatOption, yyDollar[5].str), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[6].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 441: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3777 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[6].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), + tree.MakeOptionElem(tree.FormatOption, yyDollar[5].str), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[6].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 442: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3789 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[6].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.PhyPlanOption, "NULL"), + tree.MakeOptionElem(tree.FormatOption, yyDollar[5].str), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[6].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 443: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3801 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[6].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.PhyPlanOption, "NULL"), + tree.MakeOptionElem(tree.FormatOption, yyDollar[5].str), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[6].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 444: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3813 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[2].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = tree.NewExplainStmt(yyDollar[2].statementUnion(), "text") + } + yyVAL.union = yyLOCAL + case 445: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3821 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[3].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.VerboseOption, "NULL"), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[3].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 446: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3832 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[3].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[3].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 447: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3843 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[4].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), + tree.MakeOptionElem(tree.VerboseOption, "NULL"), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[4].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 448: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3855 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[3].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.PhyPlanOption, "NULL"), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[3].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 449: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3866 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[4].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.PhyPlanOption, "NULL"), + tree.MakeOptionElem(tree.VerboseOption, "NULL"), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[4].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 450: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3878 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[4].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.PhyPlanOption, "NULL"), + tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[4].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 451: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3890 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[5].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[5].statementUnion(), yyDollar[3].explainOptionsUnion()) + } + yyVAL.union = yyLOCAL + case 452: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3898 + { + yyLOCAL = tree.MakeExplainStmt(yyDollar[3].statementUnion(), nil) + } + yyVAL.union = yyLOCAL + case 453: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3902 + { + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.VerboseOption, "NULL"), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[4].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 454: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3909 + { + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[4].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 455: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3916 + { + options := []tree.OptionElem{ + tree.MakeOptionElem(tree.AnalyzeOption, "NULL"), + tree.MakeOptionElem(tree.VerboseOption, "NULL"), + } + yyLOCAL = tree.MakeExplainStmt(yyDollar[5].statementUnion(), options) + } + yyVAL.union = yyLOCAL + case 470: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.OptionElem +//line mysql_sql.y:3954 + { + yyLOCAL = []tree.OptionElem{yyDollar[1].explainOptionUnion()} + } + yyVAL.union = yyLOCAL + case 471: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []tree.OptionElem +//line mysql_sql.y:3958 + { + yyLOCAL = append(yyDollar[1].explainOptionsUnion(), yyDollar[3].explainOptionUnion()) + } + yyVAL.union = yyLOCAL + case 472: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.OptionElem +//line mysql_sql.y:3964 + { + yyLOCAL = tree.MakeOptionElem(yyDollar[1].str, yyDollar[2].str) + } + yyVAL.union = yyLOCAL + case 473: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:3970 + { + yyVAL.str = yyDollar[1].str + } + case 474: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:3975 + { + yyVAL.str = "true" + } + case 475: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:3976 + { + yyVAL.str = "false" + } + case 476: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:3977 + { + yyVAL.str = yyDollar[1].str + } + case 477: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:3978 + { + yyVAL.str = yyDollar[1].str + } + case 478: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:3982 + { + stmt := tree.NewAnalyzeStmt(yyDollar[3].analyzeTableEntriesUnion()) + stmt.FullScan = yyDollar[4].boolValUnion() + yyLOCAL = stmt + } + yyVAL.union = yyLOCAL + case 479: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:3990 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 480: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:3994 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 481: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.AnalyzeTableEntry +//line mysql_sql.y:4000 + { + yyLOCAL = []*tree.AnalyzeTableEntry{yyDollar[1].analyzeTableEntryUnion()} + } + yyVAL.union = yyLOCAL + case 482: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.AnalyzeTableEntry +//line mysql_sql.y:4004 + { + yyLOCAL = append(yyDollar[1].analyzeTableEntriesUnion(), yyDollar[3].analyzeTableEntryUnion()) + } + yyVAL.union = yyLOCAL + case 483: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.AnalyzeTableEntry +//line mysql_sql.y:4010 + { + yyLOCAL = &tree.AnalyzeTableEntry{Table: yyDollar[1].tableNameUnion()} + } + yyVAL.union = yyLOCAL + case 484: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.AnalyzeTableEntry +//line mysql_sql.y:4014 + { + yyLOCAL = &tree.AnalyzeTableEntry{Table: yyDollar[1].tableNameUnion(), Cols: yyDollar[3].identifierListUnion()} + } + yyVAL.union = yyLOCAL + case 485: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4020 + { + yyLOCAL = tree.NewCheckTableStmt(yyDollar[3].tableNamesUnion(), yyDollar[4].checkTableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 486: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.CheckTableOption +//line mysql_sql.y:4026 + { + yyLOCAL = tree.CheckTableOptionNone + } + yyVAL.union = yyLOCAL + case 487: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.CheckTableOption +//line mysql_sql.y:4030 + { + yyLOCAL = tree.CheckTableOptionExtended + } + yyVAL.union = yyLOCAL + case 488: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.CheckTableOption +//line mysql_sql.y:4034 + { + yyLOCAL = tree.CheckTableOptionForUpgrade + } + yyVAL.union = yyLOCAL + case 489: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4040 + { + yyLOCAL = tree.NewShowProfileStmt(yyDollar[3].int64ValUnion(), yyDollar[4].limitUnion()) + } + yyVAL.union = yyLOCAL + case 490: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:4046 + { + yyLOCAL = 0 + } + yyVAL.union = yyLOCAL + case 491: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:4050 + { + value, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + yyLOCAL = value + } + yyVAL.union = yyLOCAL + case 492: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4058 + { + yyLOCAL = &tree.UpgradeStatement{ + Target: yyDollar[3].upgrade_targetUnion(), + Retry: yyDollar[4].int64ValUnion(), + } + } + yyVAL.union = yyLOCAL + case 493: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Target +//line mysql_sql.y:4067 + { + yyLOCAL = &tree.Target{ + AccountName: yyDollar[1].str, + IsALLAccount: false, + } + } + yyVAL.union = yyLOCAL + case 494: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Target +//line mysql_sql.y:4074 + { + yyLOCAL = &tree.Target{ + AccountName: "", + IsALLAccount: true, + } + } + yyVAL.union = yyLOCAL + case 495: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:4082 + { + yyLOCAL = -1 + } + yyVAL.union = yyLOCAL + case 496: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:4086 + { + res, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if res <= 0 { + yylex.Error("retry value can not less than 0") + yyLOCAL = -1 + } + yyLOCAL = res + } + yyVAL.union = yyLOCAL + case 512: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4116 + { + yyLOCAL = &tree.AlterIcebergCatalog{ + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Options: yyDollar[6].icebergOptionsUnion(), + } + } + yyVAL.union = yyLOCAL + case 513: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4123 + { + yyLOCAL = &tree.AlterIcebergCatalog{ + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Options: yyDollar[7].icebergOptionsUnion(), + } + } + yyVAL.union = yyLOCAL + case 514: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4132 + { + yyLOCAL = &tree.AlterMongoDBConnection{ + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Action: tree.AlterMongoDBConnectionSet, + Options: yyDollar[6].mongodbOptionsUnion(), + } + } + yyVAL.union = yyLOCAL + case 515: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4140 + { + yyLOCAL = &tree.AlterMongoDBConnection{ + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Action: tree.AlterMongoDBConnectionSet, + Options: yyDollar[7].mongodbOptionsUnion(), + } + } + yyVAL.union = yyLOCAL + case 516: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4148 + { + yyLOCAL = &tree.AlterMongoDBConnection{ + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Action: tree.AlterMongoDBConnectionEnable, + } + } + yyVAL.union = yyLOCAL + case 517: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4155 + { + yyLOCAL = &tree.AlterMongoDBConnection{ + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + Action: tree.AlterMongoDBConnectionDisable, + } + } + yyVAL.union = yyLOCAL + case 518: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4164 + { + var ifExists = yyDollar[3].boolValUnion() + var name = yyDollar[4].tableNameUnion() + var typ = yyDollar[5].alterTypeOptionUnion() + var incrementBy = yyDollar[6].incrementByOptionUnion() + var minValue = yyDollar[7].minValueOptionUnion() + var maxValue = yyDollar[8].maxValueOptionUnion() + var startWith = yyDollar[9].startWithOptionUnion() + var cycle = yyDollar[10].cycleOptionUnion() + yyLOCAL = tree.NewAlterSequence( + ifExists, + name, + typ, + incrementBy, + minValue, + maxValue, + startWith, + cycle, + ) + } + yyVAL.union = yyLOCAL + case 519: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4187 + { + var ifExists = yyDollar[3].boolValUnion() + var name = yyDollar[4].tableNameUnion() + var colNames = yyDollar[5].identifierListUnion() + var asSource = yyDollar[7].selectUnion() + yyLOCAL = tree.NewAlterView(ifExists, name, colNames, asSource) + } + yyVAL.union = yyLOCAL + case 520: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4197 + { + var table = yyDollar[3].tableNameUnion() + alterTable := tree.NewAlterTable(table) + alterTable.Options = yyDollar[4].alterTableOptionsUnion() + yyLOCAL = alterTable + } + yyVAL.union = yyLOCAL + case 521: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4204 + { + var table = yyDollar[3].tableNameUnion() + alterTable := tree.NewAlterTable(table) + alterTable.PartitionOption = yyDollar[4].alterPartitionOptionUnion() + yyLOCAL = alterTable + } + yyVAL.union = yyLOCAL + case 522: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4211 + { + var table = yyDollar[3].tableNameUnion() + alterTable := tree.NewAlterTable(table) + alterTable.Options = []tree.AlterTableOption{yyDollar[4].alterTableOptionUnion()} + yyLOCAL = alterTable + } + yyVAL.union = yyLOCAL + case 523: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4220 + { + alterTables := yyDollar[3].renameTableOptionsUnion() + renameTables := tree.NewRenameTable(alterTables) + yyLOCAL = renameTables + } + yyVAL.union = yyLOCAL + case 524: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.AlterTable +//line mysql_sql.y:4228 + { + yyLOCAL = []*tree.AlterTable{yyDollar[1].renameTableOptionUnion()} + } + yyVAL.union = yyLOCAL + case 525: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.AlterTable +//line mysql_sql.y:4232 + { + yyLOCAL = append(yyDollar[1].renameTableOptionsUnion(), yyDollar[3].renameTableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 526: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.AlterTable +//line mysql_sql.y:4238 + { + var table = yyDollar[1].tableNameUnion() + alterTable := tree.NewAlterTable(table) + opt := tree.AlterTableOption(yyDollar[3].alterTableOptionUnion()) + alterTable.Options = []tree.AlterTableOption{opt} + yyLOCAL = alterTable + } + yyVAL.union = yyLOCAL + case 527: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4248 + { + var io *tree.IndexOption = nil + if yyDollar[5].indexOptionUnion() == nil { + io = tree.NewIndexOption() + io.IType = tree.INDEX_TYPE_IVFFLAT + } else { + io = yyDollar[5].indexOptionUnion() + io.IType = tree.INDEX_TYPE_IVFFLAT + } + var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) + yyLOCAL = tree.NewAlterOptionAlterReIndex(name, io) + } + yyVAL.union = yyLOCAL + case 528: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4261 + { + var io *tree.IndexOption = nil + if yyDollar[5].indexOptionUnion() == nil { + io = tree.NewIndexOption() + io.IType = tree.INDEX_TYPE_HNSW + } else { + io = yyDollar[5].indexOptionUnion() + io.IType = tree.INDEX_TYPE_HNSW + } + var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) + yyLOCAL = tree.NewAlterOptionAlterReIndex(name, io) + } + yyVAL.union = yyLOCAL + case 529: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4274 + { + var io *tree.IndexOption = nil + if yyDollar[5].indexOptionUnion() == nil { + io = tree.NewIndexOption() + io.IType = tree.INDEX_TYPE_IVFPQ + } else { + io = yyDollar[5].indexOptionUnion() + io.IType = tree.INDEX_TYPE_IVFPQ + } + var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) + yyLOCAL = tree.NewAlterOptionAlterReIndex(name, io) + } + yyVAL.union = yyLOCAL + case 530: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4287 + { + var io *tree.IndexOption = nil + if yyDollar[5].indexOptionUnion() == nil { + io = tree.NewIndexOption() + io.IType = tree.INDEX_TYPE_CAGRA + } else { + io = yyDollar[5].indexOptionUnion() + io.IType = tree.INDEX_TYPE_CAGRA + } + var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) + yyLOCAL = tree.NewAlterOptionAlterReIndex(name, io) + } + yyVAL.union = yyLOCAL + case 531: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4300 + { + var io *tree.IndexOption = nil + if yyDollar[5].indexOptionUnion() == nil { + io = tree.NewIndexOption() + io.IType = tree.INDEX_TYPE_FULLTEXT2 + } else { + io = yyDollar[5].indexOptionUnion() + io.IType = tree.INDEX_TYPE_FULLTEXT2 + } + var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) + yyLOCAL = tree.NewAlterOptionAlterReIndex(name, io) + } + yyVAL.union = yyLOCAL + case 532: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.AlterTableOptions +//line mysql_sql.y:4315 + { + yyLOCAL = []tree.AlterTableOption{yyDollar[1].alterTableOptionUnion()} + } + yyVAL.union = yyLOCAL + case 533: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterTableOptions +//line mysql_sql.y:4319 + { + yyLOCAL = append(yyDollar[1].alterTableOptionsUnion(), yyDollar[3].alterTableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 534: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.AlterPartitionOption +//line mysql_sql.y:4325 + { + yyLOCAL = yyDollar[1].alterPartitionOptionUnion() + } + yyVAL.union = yyLOCAL + case 535: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.AlterPartitionOption +//line mysql_sql.y:4329 + { + yyDollar[3].partitionByUnion().Num = uint64(yyDollar[4].int64ValUnion()) + var PartBy = yyDollar[3].partitionByUnion() + var SubPartBy = yyDollar[5].partitionByUnion() + var Partitions = yyDollar[6].partitionsUnion() + + partitionDef := tree.NewPartitionOption( + PartBy, + SubPartBy, + Partitions, + ) + + var typ tree.AlterPartitionOptionType + + opt := tree.NewAlterPartitionRedefinePartitionClause( + typ, + partitionDef, + ) + + yyLOCAL = tree.AlterPartitionOption(opt) + } + yyVAL.union = yyLOCAL + case 536: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4353 + { + var ifExists = yyDollar[3].boolValUnion() + var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + var pitrValue = yyDollar[6].int64ValUnion() + var pitrUnit = yyDollar[7].str + yyLOCAL = tree.NewAlterPitr(ifExists, name, pitrValue, pitrUnit) + } + yyVAL.union = yyLOCAL + case 537: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4363 + { + yyLOCAL = &tree.AlterSQLTask{ + Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + Action: tree.AlterTaskSuspend, + } + } + yyVAL.union = yyLOCAL + case 538: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4370 + { + yyLOCAL = &tree.AlterSQLTask{ + Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + Action: tree.AlterTaskResume, + } + } + yyVAL.union = yyLOCAL + case 539: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4377 + { + yyLOCAL = &tree.AlterSQLTask{ + Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + Action: tree.AlterTaskSetSchedule, + CronExpr: yyDollar[6].str, + Timezone: yyDollar[7].str, + } + } + yyVAL.union = yyLOCAL + case 540: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4386 + { + yyLOCAL = &tree.AlterSQLTask{ + Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + Action: tree.AlterTaskSetWhen, + GateCondition: sqlTaskNodeString(yyDollar[7].exprUnion()), + } + } + yyVAL.union = yyLOCAL + case 541: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4394 + { + yyLOCAL = &tree.AlterSQLTask{ + Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + Action: tree.AlterTaskSetRetry, + RetryLimit: sqlTaskInt64(yyDollar[6].item), + } + } + yyVAL.union = yyLOCAL + case 542: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4402 + { + yyLOCAL = &tree.AlterSQLTask{ + Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + Action: tree.AlterTaskSetTimeout, + Timeout: yyDollar[6].str, + } + } + yyVAL.union = yyLOCAL + case 543: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4412 + { + var oldName = yyDollar[5].cstrUnion().Compare() + var newName = yyDollar[8].cstrUnion().Compare() + yyLOCAL = tree.NewAlterRole(true, oldName, newName) + } + yyVAL.union = yyLOCAL + case 544: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4418 + { + var oldName = yyDollar[3].cstrUnion().Compare() + var newName = yyDollar[6].cstrUnion().Compare() + yyLOCAL = tree.NewAlterRole(false, oldName, newName) + } + yyVAL.union = yyLOCAL + case 545: + yyDollar = yyS[yypt-11 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4424 + { + var roleName = yyDollar[3].cstrUnion().Compare() + var ruleSQL = yyDollar[6].str + var dbName = yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[9].cstrUnion().Origin()).Compare() + var tblName = yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[11].cstrUnion().Origin()).Compare() + var ruleName = dbName + "." + tblName + yyLOCAL = tree.NewAlterRoleAddRule(roleName, ruleName, ruleSQL, dbName, tblName) + } + yyVAL.union = yyLOCAL + case 546: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4433 + { + var roleName = yyDollar[3].cstrUnion().Compare() + var dbName = yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[8].cstrUnion().Origin()).Compare() + var tblName = yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[10].cstrUnion().Origin()).Compare() + yyLOCAL = tree.NewAlterRoleDropRule(roleName, dbName, tblName) + } + yyVAL.union = yyLOCAL + case 547: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterPartitionOption +//line mysql_sql.y:4442 + { + var typ = tree.AlterPartitionAddPartition + var partitions = yyDollar[3].partitionsUnion() + opt := tree.NewAlterPartitionAddPartitionClause( + typ, + partitions, + ) + yyLOCAL = tree.AlterPartitionOption(opt) + } + yyVAL.union = yyLOCAL + case 548: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterPartitionOption +//line mysql_sql.y:4452 + { + var typ = tree.AlterPartitionDropPartition + var partitionNames = yyDollar[3].PartitionNamesUnion() + opt := tree.NewAlterPartitionDropPartitionClause( + typ, + partitionNames, + ) + + if yyDollar[3].PartitionNamesUnion() == nil { + opt.OnAllPartitions = true + } else { + opt.PartitionNames = yyDollar[3].PartitionNamesUnion() + } + yyLOCAL = tree.AlterPartitionOption(opt) + } + yyVAL.union = yyLOCAL + case 549: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterPartitionOption +//line mysql_sql.y:4468 + { + var typ = tree.AlterPartitionTruncatePartition + var partitionNames = yyDollar[3].PartitionNamesUnion() + opt := tree.NewAlterPartitionTruncatePartitionClause( + typ, + partitionNames, + ) + + if yyDollar[3].PartitionNamesUnion() == nil { + opt.OnAllPartitions = true + } else { + opt.PartitionNames = yyDollar[3].PartitionNamesUnion() + } + yyLOCAL = tree.AlterPartitionOption(opt) + } + yyVAL.union = yyLOCAL + case 550: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:4486 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 551: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:4490 + { + yyLOCAL = yyDollar[1].PartitionNamesUnion() + } + yyVAL.union = yyLOCAL + case 552: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:4496 + { + yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 553: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:4500 + { + yyLOCAL = append(yyDollar[1].PartitionNamesUnion(), tree.Identifier(yyDollar[3].cstrUnion().Compare())) + } + yyVAL.union = yyLOCAL + case 554: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4506 + { + var def = yyDollar[2].tableDefUnion() + opt := tree.NewAlterOptionAdd(def) + yyLOCAL = tree.AlterTableOption(opt) + } + yyVAL.union = yyLOCAL + case 555: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4512 + { + var typ = tree.AlterTableModifyColumn + var newColumn = yyDollar[3].columnTableDefUnion() + var position = yyDollar[4].alterColPositionUnion() + opt := tree.NewAlterTableModifyColumnClause(typ, newColumn, position) + yyLOCAL = tree.AlterTableOption(opt) + } + yyVAL.union = yyLOCAL + case 556: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4520 + { + // Type OldColumnName NewColumn Position + var typ = tree.AlterTableChangeColumn + var oldColumnName = yyDollar[3].unresolvedNameUnion() + var newColumn = yyDollar[4].columnTableDefUnion() + var position = yyDollar[5].alterColPositionUnion() + opt := tree.NewAlterTableChangeColumnClause(typ, oldColumnName, newColumn, position) + yyLOCAL = tree.AlterTableOption(opt) + } + yyVAL.union = yyLOCAL + case 557: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4530 + { + var typ = tree.AlterTableRenameColumn + var oldColumnName = yyDollar[3].unresolvedNameUnion() + var newColumnName = yyDollar[5].unresolvedNameUnion() + opt := tree.NewAlterTableRenameColumnClause(typ, oldColumnName, newColumnName) + yyLOCAL = tree.AlterTableOption(opt) + } + yyVAL.union = yyLOCAL + case 558: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4538 + { + var typ = tree.AlterTableAlterColumn + var columnName = yyDollar[3].unresolvedNameUnion() + var defaultExpr = tree.NewAttributeDefault(yyDollar[6].exprUnion()) + var visibility tree.VisibleType + var optionType = tree.AlterColumnOptionSetDefault + opt := tree.NewAlterTableAlterColumnClause(typ, columnName, defaultExpr, visibility, optionType) + yyLOCAL = tree.AlterTableOption(opt) + } + yyVAL.union = yyLOCAL + case 559: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4548 + { + var typ = tree.AlterTableAlterColumn + var columnName = yyDollar[3].unresolvedNameUnion() + var defaultExpr = tree.NewAttributeDefault(nil) + var visibility = yyDollar[5].indexVisibilityUnion() + var optionType = tree.AlterColumnOptionSetVisibility + opt := tree.NewAlterTableAlterColumnClause(typ, columnName, defaultExpr, visibility, optionType) + yyLOCAL = tree.AlterTableOption(opt) + } + yyVAL.union = yyLOCAL + case 560: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4558 + { + var typ = tree.AlterTableAlterColumn + var columnName = yyDollar[3].unresolvedNameUnion() + var defaultExpr = tree.NewAttributeDefault(nil) + var visibility tree.VisibleType + var optionType = tree.AlterColumnOptionDropDefault + opt := tree.NewAlterTableAlterColumnClause(typ, columnName, defaultExpr, visibility, optionType) + yyLOCAL = tree.AlterTableOption(opt) + } + yyVAL.union = yyLOCAL + case 561: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4568 + { + var orderByClauseType = tree.AlterTableOrderByColumn + var orderByColumnList = yyDollar[3].alterColumnOrderByUnion() + opt := tree.NewAlterTableOrderByColumnClause(orderByClauseType, orderByColumnList) + yyLOCAL = tree.AlterTableOption(opt) + } + yyVAL.union = yyLOCAL + case 562: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4575 + { + yyLOCAL = tree.AlterTableOption(yyDollar[2].alterTableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 563: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4579 + { + yyLOCAL = tree.AlterTableOption(yyDollar[2].alterTableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 564: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4583 + { + yyLOCAL = tree.AlterTableOption(yyDollar[1].tableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 565: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4587 + { + yyLOCAL = tree.AlterTableOption(yyDollar[3].alterTableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 566: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4591 + { + var column = yyDollar[3].columnTableDefUnion() + var position = yyDollar[4].alterColPositionUnion() + opt := tree.NewAlterAddCol(column, position) + yyLOCAL = tree.AlterTableOption(opt) + } + yyVAL.union = yyLOCAL + case 567: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4598 + { + yyLOCAL = tree.NewAlterOptionAlgorithm(yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 568: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4602 + { + opt := tree.NewTableOptionCharset(yyDollar[4].str) + opt.Collate = yyDollar[7].str + yyLOCAL = opt + } + yyVAL.union = yyLOCAL + case 569: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4608 + { + opt := tree.NewTableOptionCharset(yyDollar[5].str) + opt.Convert = true + yyLOCAL = opt + } + yyVAL.union = yyLOCAL + case 570: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4614 + { + opt := tree.NewTableOptionCharset(yyDollar[5].str) + opt.Collate = yyDollar[8].str + opt.Convert = true + yyLOCAL = opt + } + yyVAL.union = yyLOCAL + case 571: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4621 + { + opt := tree.NewTableOptionCharset(yyDollar[1].str) + opt.NonCharsetSyntax = true + yyLOCAL = opt + } + yyVAL.union = yyLOCAL + case 572: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4627 + { + opt := tree.NewTableOptionCharset(yyDollar[1].str) + opt.NonCharsetSyntax = true + yyLOCAL = opt + } + yyVAL.union = yyLOCAL + case 573: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4633 + { + opt := tree.NewTableOptionCharset(yyDollar[1].str) + opt.NonCharsetSyntax = true + yyLOCAL = opt + } + yyVAL.union = yyLOCAL + case 574: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4639 + { + yyLOCAL = tree.NewAlterOptionLock(yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 575: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4643 + { + opt := tree.NewTableOptionCharset(yyDollar[1].str) + opt.NonCharsetSyntax = true + yyLOCAL = opt + } + yyVAL.union = yyLOCAL + case 576: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:4650 + { + yyVAL.str = "" + } + case 593: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:4681 + { + yyVAL.str = "" + } + case 594: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:4685 + { + yyVAL.str = string("COLUMN") + } + case 595: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.ColumnPosition +//line mysql_sql.y:4690 + { + var typ = tree.ColumnPositionNone + var relativeColumn *tree.UnresolvedName + yyLOCAL = tree.NewColumnPosition(typ, relativeColumn) + } + yyVAL.union = yyLOCAL + case 596: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.ColumnPosition +//line mysql_sql.y:4696 + { + var typ = tree.ColumnPositionFirst + var relativeColumn *tree.UnresolvedName + yyLOCAL = tree.NewColumnPosition(typ, relativeColumn) + } + yyVAL.union = yyLOCAL + case 597: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.ColumnPosition +//line mysql_sql.y:4702 + { + var typ = tree.ColumnPositionAfter + var relativeColumn = yyDollar[2].unresolvedNameUnion() + yyLOCAL = tree.NewColumnPosition(typ, relativeColumn) + } + yyVAL.union = yyLOCAL + case 598: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.AlterColumnOrder +//line mysql_sql.y:4710 + { + yyLOCAL = []*tree.AlterColumnOrder{yyDollar[1].alterColumnOrderUnion()} + } + yyVAL.union = yyLOCAL + case 599: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.AlterColumnOrder +//line mysql_sql.y:4714 + { + yyLOCAL = append(yyDollar[1].alterColumnOrderByUnion(), yyDollar[3].alterColumnOrderUnion()) + } + yyVAL.union = yyLOCAL + case 600: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.AlterColumnOrder +//line mysql_sql.y:4720 + { + var column = yyDollar[1].unresolvedNameUnion() + var direction = yyDollar[2].directionUnion() + yyLOCAL = tree.NewAlterColumnOrder(column, direction) + } + yyVAL.union = yyLOCAL + case 601: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4728 + { + var name = yyDollar[1].unresolvedObjectNameUnion() + yyLOCAL = tree.NewAlterOptionTableName(name) + } + yyVAL.union = yyLOCAL + case 602: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4735 + { + var dropType = tree.AlterTableDropIndex + var name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) + yyLOCAL = tree.NewAlterOptionDrop(dropType, name) + } + yyVAL.union = yyLOCAL + case 603: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4741 + { + var dropType = tree.AlterTableDropKey + var name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) + yyLOCAL = tree.NewAlterOptionDrop(dropType, name) + } + yyVAL.union = yyLOCAL + case 604: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4747 + { + var dropType = tree.AlterTableDropColumn + var name = tree.Identifier(yyDollar[1].cstrUnion().Compare()) + yyLOCAL = tree.NewAlterOptionDrop(dropType, name) + } + yyVAL.union = yyLOCAL + case 605: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4753 + { + var dropType = tree.AlterTableDropColumn + var name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) + yyLOCAL = tree.NewAlterOptionDrop(dropType, name) + } + yyVAL.union = yyLOCAL + case 606: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4759 + { + var dropType = tree.AlterTableDropForeignKey + var name = tree.Identifier(yyDollar[3].cstrUnion().Compare()) + yyLOCAL = tree.NewAlterOptionDrop(dropType, name) + + } + yyVAL.union = yyLOCAL + case 607: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4766 + { + yyLOCAL = &tree.AlterOptionDrop{ + Typ: tree.AlterTableDropConstraint, + Name: tree.Identifier(yyDollar[2].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 608: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4773 + { + yyLOCAL = tree.NewAlterOptionDrop(tree.AlterTableDropCheck, tree.Identifier(yyDollar[2].cstrUnion().Compare())) + } + yyVAL.union = yyLOCAL + case 609: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4777 + { + var dropType = tree.AlterTableDropPrimaryKey + var name = tree.Identifier("") + yyLOCAL = tree.NewAlterOptionDrop(dropType, name) + } + yyVAL.union = yyLOCAL + case 610: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4785 + { + var indexName = tree.Identifier(yyDollar[2].cstrUnion().Compare()) + var visibility = yyDollar[3].indexVisibilityUnion() + yyLOCAL = tree.NewAlterOptionAlterIndex(indexName, visibility) + } + yyVAL.union = yyLOCAL + case 611: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4791 + { + var io *tree.IndexOption = nil + if yyDollar[5].indexOptionUnion() == nil { + io = tree.NewIndexOption() + io.IType = tree.INDEX_TYPE_IVFFLAT + } else { + io = yyDollar[5].indexOptionUnion() + io.IType = tree.INDEX_TYPE_IVFFLAT + } + var name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) + var auto_update = yyDollar[4].boolValUnion() + io.AutoUpdate = auto_update + yyLOCAL = tree.NewAlterOptionAlterAutoUpdate(name, io) + } + yyVAL.union = yyLOCAL + case 612: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4806 + { + var checkType = yyDollar[1].str + var enforce = yyDollar[3].boolValUnion() + yyLOCAL = tree.NewAlterOptionAlterCheck(checkType, enforce) + } + yyVAL.union = yyLOCAL + case 613: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterTableOption +//line mysql_sql.y:4812 + { + var checkType = yyDollar[1].str + var enforce = yyDollar[3].boolValUnion() + yyLOCAL = tree.NewAlterOptionAlterCheck(checkType, enforce) + } + yyVAL.union = yyLOCAL + case 614: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.VisibleType +//line mysql_sql.y:4820 + { + yyLOCAL = tree.VISIBLE_TYPE_VISIBLE + } + yyVAL.union = yyLOCAL + case 615: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.VisibleType +//line mysql_sql.y:4824 + { + yyLOCAL = tree.VISIBLE_TYPE_INVISIBLE + } + yyVAL.union = yyLOCAL + case 616: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:4830 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 617: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:4834 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 618: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4840 + { + var ifExists = yyDollar[3].boolValUnion() + var name = yyDollar[4].exprUnion() + var authOption = yyDollar[5].alterAccountAuthOptionUnion() + var statusOption = yyDollar[6].accountStatusUnion() + var comment = yyDollar[7].accountCommentUnion() + + yyLOCAL = tree.NewAlterAccount( + ifExists, + name, + authOption, + statusOption, + comment, + ) + } + yyVAL.union = yyLOCAL + case 619: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4858 + { + yyLOCAL = &tree.AlterDatabase{Name: tree.Identifier(yyDollar[3].str), Options: yyDollar[4].createOptionsUnion()} + } + yyVAL.union = yyLOCAL + case 620: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4862 + { + yyLOCAL = &tree.AlterDatabase{Options: yyDollar[3].createOptionsUnion()} + } + yyVAL.union = yyLOCAL + case 621: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.CreateOption +//line mysql_sql.y:4868 + { + yyLOCAL = []tree.CreateOption{yyDollar[1].createOptionUnion()} + } + yyVAL.union = yyLOCAL + case 622: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []tree.CreateOption +//line mysql_sql.y:4872 + { + yyLOCAL = append(yyDollar[1].createOptionsUnion(), yyDollar[2].createOptionUnion()) + } + yyVAL.union = yyLOCAL + case 623: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.CreateOption +//line mysql_sql.y:4878 + { + yyLOCAL = tree.NewCreateOptionCharset(false, yyDollar[4].str) + } + yyVAL.union = yyLOCAL + case 624: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.CreateOption +//line mysql_sql.y:4882 + { + yyLOCAL = tree.NewCreateOptionCharset(true, yyDollar[5].str) + } + yyVAL.union = yyLOCAL + case 625: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.CreateOption +//line mysql_sql.y:4886 + { + yyLOCAL = tree.NewCreateOptionCollate(false, yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 626: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.CreateOption +//line mysql_sql.y:4890 + { + yyLOCAL = tree.NewCreateOptionCollate(true, yyDollar[4].str) + } + yyVAL.union = yyLOCAL + case 627: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4896 + { + var accountName = "" + var dbName = yyDollar[3].str + var isAccountLevel = false + var updateConfig = yyDollar[7].str + + yyLOCAL = tree.NewAlterDataBaseConfig( + accountName, + dbName, + isAccountLevel, + tree.MYSQL_COMPATIBILITY_MODE, + updateConfig, + ) + } + yyVAL.union = yyLOCAL + case 628: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4911 + { + var accountName = "" + var dbName = yyDollar[3].str + var isAccountLevel = false + var updateConfig = yyDollar[7].str + + yyLOCAL = tree.NewAlterDataBaseConfig( + accountName, + dbName, + isAccountLevel, + tree.UNIQUE_CHECK_ON_AUTOINCR, + updateConfig, + ) + } + yyVAL.union = yyLOCAL + case 629: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4926 + { + var accountName = yyDollar[4].str + var dbName = "" + var isAccountLevel = true + var updateConfig = yyDollar[8].str + + yyLOCAL = tree.NewAlterDataBaseConfig( + accountName, + dbName, + isAccountLevel, + tree.MYSQL_COMPATIBILITY_MODE, + updateConfig, + ) + } + yyVAL.union = yyLOCAL + case 630: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4941 + { + assignments := []*tree.VarAssignmentExpr{ + { + System: true, + Global: true, + Name: yyDollar[6].str, + Value: yyDollar[8].exprUnion(), + }, + } + yyLOCAL = &tree.SetVar{Assignments: assignments} + } + yyVAL.union = yyLOCAL + case 631: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.AlterAccountAuthOption +//line mysql_sql.y:4954 + { + yyLOCAL = tree.AlterAccountAuthOption{ + Exist: false, + } + } + yyVAL.union = yyLOCAL + case 632: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.AlterAccountAuthOption +//line mysql_sql.y:4960 + { + yyLOCAL = tree.AlterAccountAuthOption{ + Exist: true, + Equal: yyDollar[2].str, + AdminName: yyDollar[3].exprUnion(), + IdentifiedType: yyDollar[4].accountIdentifiedUnion(), + } + } + yyVAL.union = yyLOCAL + case 633: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4971 + { + // Create temporary variables with meaningful names + ifExists := yyDollar[3].boolValUnion() + users := yyDollar[4].usersUnion() + role := yyDollar[5].accountRoleUnion() + miscOpt := yyDollar[6].userMiscOptionUnion() + commentOrAttribute := yyDollar[7].accountCommentOrAttributeUnion() + + // Use the temporary variables to call the function + yyLOCAL = tree.NewAlterUser(ifExists, users, role, miscOpt, commentOrAttribute) + } + yyVAL.union = yyLOCAL + case 634: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4983 + { + ifExists := yyDollar[3].boolValUnion() + var Username = yyDollar[4].usernameRecordUnion().Username + var Hostname = yyDollar[4].usernameRecordUnion().Hostname + user := tree.NewUser(Username, Hostname, nil) + users := []*tree.User{user} + miscOpt := tree.NewUserMiscOptionAccountUnlock() + commentOrAttribute := yyDollar[6].accountCommentOrAttributeUnion() + yyLOCAL = tree.NewAlterUser(ifExists, users, nil, miscOpt, commentOrAttribute) + } + yyVAL.union = yyLOCAL + case 635: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:4994 + { + ifExists := yyDollar[3].boolValUnion() + var Username = yyDollar[4].usernameRecordUnion().Username + var Hostname = yyDollar[4].usernameRecordUnion().Hostname + user := tree.NewUser(Username, Hostname, nil) + users := []*tree.User{user} + miscOpt := tree.NewUserMiscOptionAccountLock() + commentOrAttribute := yyDollar[6].accountCommentOrAttributeUnion() + yyLOCAL = tree.NewAlterUser(ifExists, users, nil, miscOpt, commentOrAttribute) + } + yyVAL.union = yyLOCAL + case 636: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.Role +//line mysql_sql.y:5006 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 637: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.Role +//line mysql_sql.y:5010 + { + var UserName = yyDollar[3].str + yyLOCAL = tree.NewRole( + UserName, + ) + } + yyVAL.union = yyLOCAL + case 638: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:5018 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 639: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:5022 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 640: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5027 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 641: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5031 + { + yyLOCAL = yyDollar[1].userMiscOptionUnion() + } + yyVAL.union = yyLOCAL + case 642: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5047 + { + yyLOCAL = tree.NewUserMiscOptionAccountUnlock() + } + yyVAL.union = yyLOCAL + case 643: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5051 + { + yyLOCAL = tree.NewUserMiscOptionAccountLock() + } + yyVAL.union = yyLOCAL + case 644: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5055 + { + yyLOCAL = tree.NewUserMiscOptionPasswordExpireNone() + } + yyVAL.union = yyLOCAL + case 645: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5059 + { + Value, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + yyLOCAL = tree.NewUserMiscOptionPasswordExpireInterval( + Value, + ) + } + yyVAL.union = yyLOCAL + case 646: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5067 + { + yyLOCAL = tree.NewUserMiscOptionPasswordExpireNever() + } + yyVAL.union = yyLOCAL + case 647: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5071 + { + yyLOCAL = tree.NewUserMiscOptionPasswordExpireDefault() + } + yyVAL.union = yyLOCAL + case 648: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5075 + { + yyLOCAL = tree.NewUserMiscOptionPasswordHistoryDefault() + } + yyVAL.union = yyLOCAL + case 649: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5079 + { + Value, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + yyLOCAL = tree.NewUserMiscOptionPasswordHistoryCount( + Value, + ) + } + yyVAL.union = yyLOCAL + case 650: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5087 + { + yyLOCAL = tree.NewUserMiscOptionPasswordReuseIntervalDefault() + } + yyVAL.union = yyLOCAL + case 651: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5091 + { + Value, ok := signedIntegral(yylex, yyDollar[4].item) + if !ok { + goto ret1 + } + yyLOCAL = tree.NewUserMiscOptionPasswordReuseIntervalCount( + Value, + ) + } + yyVAL.union = yyLOCAL + case 652: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5099 + { + yyLOCAL = tree.NewUserMiscOptionPasswordRequireCurrentNone() + } + yyVAL.union = yyLOCAL + case 653: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5103 + { + yyLOCAL = tree.NewUserMiscOptionPasswordRequireCurrentDefault() + } + yyVAL.union = yyLOCAL + case 654: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5107 + { + yyLOCAL = tree.NewUserMiscOptionPasswordRequireCurrentOptional() + } + yyVAL.union = yyLOCAL + case 655: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5111 + { + Value, ok := signedIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + yyLOCAL = tree.NewUserMiscOptionFailedLoginAttempts( + Value, + ) + } + yyVAL.union = yyLOCAL + case 656: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5119 + { + Value, ok := signedIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + yyLOCAL = tree.NewUserMiscOptionPasswordLockTimeCount( + Value, + ) + } + yyVAL.union = yyLOCAL + case 657: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.UserMiscOption +//line mysql_sql.y:5127 + { + yyLOCAL = tree.NewUserMiscOptionPasswordLockTimeUnbounded() + } + yyVAL.union = yyLOCAL + case 658: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:5133 + { + yyVAL.item = nil + } + case 659: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:5138 + { + yyVAL.item = nil + } + case 705: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5193 + { + yyLOCAL = &tree.ShowSQLTasks{} + } + yyVAL.union = yyLOCAL + case 706: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5199 + { + stmt := &tree.ShowSQLTaskRuns{} + if yyDollar[4].str != "" { + stmt.TaskName = tree.Identifier(yyDollar[4].str) + stmt.HasTask = true + } + if yyDollar[5].int64ValUnion() >= 0 { + stmt.Limit = yyDollar[5].int64ValUnion() + stmt.HasLimit = true + } + yyLOCAL = stmt + } + yyVAL.union = yyLOCAL + case 707: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:5213 + { + yyVAL.str = "" + } + case 708: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:5217 + { + yyVAL.str = yyDollar[2].cstrUnion().Compare() + } + case 709: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:5222 + { + yyLOCAL = -1 + } + yyVAL.union = yyLOCAL + case 710: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:5226 + { + yyLOCAL = sqlTaskInt64(yyDollar[2].item) + } + yyVAL.union = yyLOCAL + case 711: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5232 + { + yyLOCAL = &tree.ShowIcebergCatalogs{ + Like: yyDollar[4].comparisionExprUnion(), + Where: yyDollar[5].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 712: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5240 + { + yyLOCAL = &tree.ShowIcebergNamespaces{ + Catalog: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + Like: yyDollar[6].comparisionExprUnion(), + Where: yyDollar[7].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 713: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5248 + { + yyLOCAL = &tree.ShowIcebergNamespaces{ + Catalog: tree.Identifier(yyDollar[6].cstrUnion().Compare()), + Like: yyDollar[7].comparisionExprUnion(), + Where: yyDollar[8].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 714: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5256 + { + yyLOCAL = &tree.ShowIcebergNamespaces{ + Like: yyDollar[4].comparisionExprUnion(), + Where: yyDollar[5].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 715: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5263 + { + yyLOCAL = &tree.ShowIcebergTables{ + Like: yyDollar[4].comparisionExprUnion(), + Where: yyDollar[5].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 716: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5270 + { + yyLOCAL = &tree.ShowIcebergTables{ + Catalog: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + Like: yyDollar[6].comparisionExprUnion(), + Where: yyDollar[7].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 717: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5278 + { + yyLOCAL = &tree.ShowIcebergTables{ + Catalog: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + Namespace: yyDollar[7].str, + Like: yyDollar[8].comparisionExprUnion(), + Where: yyDollar[9].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 718: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5287 + { + yyLOCAL = &tree.ShowIcebergTables{ + Catalog: tree.Identifier(yyDollar[6].cstrUnion().Compare()), + Like: yyDollar[7].comparisionExprUnion(), + Where: yyDollar[8].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 719: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5295 + { + yyLOCAL = &tree.ShowIcebergTables{ + Namespace: yyDollar[6].str, + Like: yyDollar[7].comparisionExprUnion(), + Where: yyDollar[8].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 720: + yyDollar = yyS[yypt-11 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5303 + { + yyLOCAL = &tree.ShowIcebergTables{ + Namespace: yyDollar[6].str, + Catalog: tree.Identifier(yyDollar[9].cstrUnion().Compare()), + Like: yyDollar[10].comparisionExprUnion(), + Where: yyDollar[11].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 721: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5314 + { + yyLOCAL = &tree.ShowMongoDBConnections{ + Like: yyDollar[4].comparisionExprUnion(), + Where: yyDollar[5].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 722: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:5323 + { + yyVAL.str = yyDollar[1].str + } + case 723: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5329 + { + yyLOCAL = &tree.ShowLogserviceReplicas{} + } + yyVAL.union = yyLOCAL + case 724: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5335 + { + yyLOCAL = &tree.ShowLogserviceStores{} + } + yyVAL.union = yyLOCAL + case 725: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5341 + { + yyLOCAL = &tree.ShowLogserviceSettings{} + } + yyVAL.union = yyLOCAL + case 726: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5347 + { + yyLOCAL = &tree.ShowRules{ + RoleName: yyDollar[5].cstrUnion().Compare(), + } + } + yyVAL.union = yyLOCAL + case 727: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5355 + { + yyLOCAL = &tree.ShowCollation{ + Like: yyDollar[3].comparisionExprUnion(), + Where: yyDollar[4].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 728: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5364 + { + yyLOCAL = &tree.ShowStages{ + Like: yyDollar[3].comparisionExprUnion(), + } + } + yyVAL.union = yyLOCAL + case 729: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5372 + { + yyLOCAL = &tree.ShowSnapShots{ + Where: yyDollar[3].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 730: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5380 + { + yyLOCAL = &tree.ShowPitr{ + Where: yyDollar[3].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 731: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5388 + { + yyLOCAL = &tree.ShowRecoveryWindow{ + Level: tree.RECOVERYWINDOWLEVELACCOUNT, + } + } + yyVAL.union = yyLOCAL + case 732: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5394 + { + yyLOCAL = &tree.ShowRecoveryWindow{ + Level: tree.RECOVERYWINDOWLEVELDATABASE, + DatabaseName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 733: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5401 + { + yyLOCAL = &tree.ShowRecoveryWindow{ + Level: tree.RECOVERYWINDOWLEVELTABLE, + DatabaseName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + TableName: tree.Identifier(yyDollar[6].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 734: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5409 + { + yyLOCAL = &tree.ShowRecoveryWindow{ + Level: tree.RECOVERYWINDOWLEVELACCOUNT, + AccountName: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 735: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5418 + { + yyLOCAL = &tree.ShowGrants{ShowGrantType: tree.GrantForUser} + } + yyVAL.union = yyLOCAL + case 736: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5422 + { + yyLOCAL = &tree.ShowGrants{Username: yyDollar[4].usernameRecordUnion().Username, Hostname: yyDollar[4].usernameRecordUnion().Hostname, Roles: yyDollar[5].rolesUnion(), ShowGrantType: tree.GrantForUser} + } + yyVAL.union = yyLOCAL + case 737: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5426 + { + yyLOCAL = &tree.ShowGrants{CurrentUser: true, Roles: yyDollar[6].rolesUnion(), ShowGrantType: tree.GrantForUser} + } + yyVAL.union = yyLOCAL + case 738: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5430 + { + s := &tree.ShowGrants{} + roles := []*tree.Role{ + {UserName: yyDollar[5].cstrUnion().Compare()}, + } + s.Roles = roles + s.ShowGrantType = tree.GrantForRole + yyLOCAL = s + } + yyVAL.union = yyLOCAL + case 739: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []*tree.Role +//line mysql_sql.y:5441 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 740: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []*tree.Role +//line mysql_sql.y:5445 + { + yyLOCAL = yyDollar[2].rolesUnion() + } + yyVAL.union = yyLOCAL + case 741: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5451 + { + yyLOCAL = &tree.ShowTableStatus{DbName: yyDollar[5].str, Like: yyDollar[6].comparisionExprUnion(), Where: yyDollar[7].whereUnion()} + } + yyVAL.union = yyLOCAL + case 742: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:5456 + { + } + case 744: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:5460 + { + } + case 746: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5465 + { + yyLOCAL = &tree.ShowFunctionOrProcedureStatus{ + Like: yyDollar[4].comparisionExprUnion(), + Where: yyDollar[5].whereUnion(), + IsFunction: true, + } + } + yyVAL.union = yyLOCAL + case 747: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5475 + { + yyLOCAL = &tree.ShowFunctionOrProcedureStatus{ + Like: yyDollar[4].comparisionExprUnion(), + Where: yyDollar[5].whereUnion(), + IsFunction: false, + } + } + yyVAL.union = yyLOCAL + case 748: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5485 + { + yyLOCAL = &tree.ShowRolesStmt{ + Like: yyDollar[3].comparisionExprUnion(), + } + } + yyVAL.union = yyLOCAL + case 749: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5493 + { + yyLOCAL = &tree.ShowNodeList{} + } + yyVAL.union = yyLOCAL + case 750: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5499 + { + yyLOCAL = &tree.ShowLocks{} + } + yyVAL.union = yyLOCAL + case 751: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5505 + { + yyLOCAL = &tree.ShowTableNumber{DbName: yyDollar[4].str} + } + yyVAL.union = yyLOCAL + case 752: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5511 + { + yyLOCAL = &tree.ShowColumnNumber{Table: yyDollar[3].unresolvedObjectNameUnion(), DbName: yyDollar[4].str} + } + yyVAL.union = yyLOCAL + case 753: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5517 + { + yyLOCAL = &tree.ShowTableValues{Table: yyDollar[3].unresolvedObjectNameUnion(), DbName: yyDollar[4].str} + } + yyVAL.union = yyLOCAL + case 754: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5523 + { + yyLOCAL = &tree.ShowTableSize{Table: yyDollar[3].unresolvedObjectNameUnion(), DbName: yyDollar[4].str} + } + yyVAL.union = yyLOCAL + case 755: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5529 + { + s := yyDollar[2].statementUnion().(*tree.ShowTarget) + s.Like = yyDollar[3].comparisionExprUnion() + s.Where = yyDollar[4].whereUnion() + yyLOCAL = s + } + yyVAL.union = yyLOCAL + case 756: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5538 + { + yyLOCAL = &tree.ShowTarget{Type: tree.ShowConfig} + } + yyVAL.union = yyLOCAL + case 757: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5542 + { + yyLOCAL = &tree.ShowTarget{Type: tree.ShowCharset} + } + yyVAL.union = yyLOCAL + case 758: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5546 + { + yyLOCAL = &tree.ShowTarget{Type: tree.ShowEngines} + } + yyVAL.union = yyLOCAL + case 759: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5550 + { + yyLOCAL = &tree.ShowTarget{DbName: yyDollar[3].str, Type: tree.ShowTriggers} + } + yyVAL.union = yyLOCAL + case 760: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5554 + { + yyLOCAL = &tree.ShowTarget{DbName: yyDollar[3].str, Type: tree.ShowEvents} + } + yyVAL.union = yyLOCAL + case 761: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5558 + { + yyLOCAL = &tree.ShowTarget{Type: tree.ShowPlugins} + } + yyVAL.union = yyLOCAL + case 762: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5562 + { + yyLOCAL = &tree.ShowTarget{Type: tree.ShowPrivileges} + } + yyVAL.union = yyLOCAL + case 763: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5566 + { + yyLOCAL = &tree.ShowTarget{Type: tree.ShowProfiles} + } + yyVAL.union = yyLOCAL + case 764: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5572 + { + yyLOCAL = &tree.ShowIndex{ + TableName: yyDollar[4].unresolvedObjectNameUnion(), + DbName: yyDollar[5].str, + Where: yyDollar[6].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 765: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:5581 + { + } + case 766: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:5583 + { + } + case 770: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5592 + { + yyLOCAL = &tree.ShowVariables{ + Global: yyDollar[2].boolValUnion(), + Like: yyDollar[4].comparisionExprUnion(), + Where: yyDollar[5].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 771: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5602 + { + yyLOCAL = &tree.ShowStatus{ + Global: yyDollar[2].boolValUnion(), + Like: yyDollar[4].comparisionExprUnion(), + Where: yyDollar[5].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 772: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:5611 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 773: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:5615 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 774: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:5619 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 775: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5625 + { + yyLOCAL = &tree.ShowWarnings{Limit: yyDollar[3].limitUnion()} + } + yyVAL.union = yyLOCAL + case 776: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5629 + { + yyLOCAL = &tree.ShowWarnings{Count: true} + } + yyVAL.union = yyLOCAL + case 777: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5635 + { + yyLOCAL = &tree.ShowErrors{Limit: yyDollar[3].limitUnion()} + } + yyVAL.union = yyLOCAL + case 778: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5639 + { + yyLOCAL = &tree.ShowErrors{Count: true} + } + yyVAL.union = yyLOCAL + case 779: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5645 + { + yyLOCAL = &tree.ShowProcessList{Full: yyDollar[2].fullOptUnion()} + } + yyVAL.union = yyLOCAL + case 780: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5651 + { + yyLOCAL = &tree.ShowSequences{ + DBName: yyDollar[3].str, + Where: yyDollar[4].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 781: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5660 + { + yyLOCAL = &tree.ShowTables{ + Open: false, + Full: yyDollar[2].fullOptUnion(), + DBName: yyDollar[4].str, + Like: yyDollar[5].comparisionExprUnion(), + Where: yyDollar[6].whereUnion(), + AtTsExpr: yyDollar[7].atTimeStampUnion(), + } + } + yyVAL.union = yyLOCAL + case 782: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5671 + { + yyLOCAL = &tree.ShowTables{ + Open: true, + Full: yyDollar[3].fullOptUnion(), + DBName: yyDollar[5].str, + Like: yyDollar[6].comparisionExprUnion(), + Where: yyDollar[7].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 783: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5683 + { + yyLOCAL = &tree.ShowDatabases{ + Like: yyDollar[3].comparisionExprUnion(), + Where: yyDollar[4].whereUnion(), + AtTsExpr: yyDollar[5].atTimeStampUnion(), + } + } + yyVAL.union = yyLOCAL + case 784: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5691 + { + yyLOCAL = &tree.ShowDatabases{Like: yyDollar[3].comparisionExprUnion(), Where: yyDollar[4].whereUnion()} + } + yyVAL.union = yyLOCAL + case 785: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5697 + { + yyLOCAL = &tree.ShowColumns{ + Ext: false, + Full: yyDollar[2].fullOptUnion(), + Table: yyDollar[4].unresolvedObjectNameUnion(), + // colName: $3, + DBName: yyDollar[5].str, + Like: yyDollar[6].comparisionExprUnion(), + Where: yyDollar[7].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 786: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5709 + { + yyLOCAL = &tree.ShowColumns{ + Ext: true, + Full: yyDollar[3].fullOptUnion(), + Table: yyDollar[5].unresolvedObjectNameUnion(), + // colName: $3, + DBName: yyDollar[6].str, + Like: yyDollar[7].comparisionExprUnion(), + Where: yyDollar[8].whereUnion(), + } + } + yyVAL.union = yyLOCAL + case 787: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5723 + { + yyLOCAL = &tree.ShowAccounts{Like: yyDollar[3].comparisionExprUnion()} + } + yyVAL.union = yyLOCAL + case 788: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5729 + { + yyLOCAL = &tree.ShowPublications{Like: yyDollar[3].comparisionExprUnion()} + } + yyVAL.union = yyLOCAL + case 789: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5735 + { + yyLOCAL = &tree.ShowPublicationCoverage{Name: yyDollar[4].str} + } + yyVAL.union = yyLOCAL + case 790: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5741 + { + yyLOCAL = &tree.ShowAccountUpgrade{} + } + yyVAL.union = yyLOCAL + case 791: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5747 + { + yyLOCAL = &tree.ShowSubscriptions{Like: yyDollar[3].comparisionExprUnion()} + } + yyVAL.union = yyLOCAL + case 792: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5751 + { + yyLOCAL = &tree.ShowSubscriptions{All: true, Like: yyDollar[4].comparisionExprUnion()} + } + yyVAL.union = yyLOCAL + case 793: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5757 + { + yyLOCAL = &tree.ShowCcprSubscriptions{TaskId: yyDollar[4].str} + } + yyVAL.union = yyLOCAL + case 794: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5761 + { + yyLOCAL = &tree.ShowCcprSubscriptions{} + } + yyVAL.union = yyLOCAL + case 795: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.ComparisonExpr +//line mysql_sql.y:5766 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 796: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.ComparisonExpr +//line mysql_sql.y:5770 + { + yyLOCAL = tree.NewComparisonExpr(tree.LIKE, nil, yyDollar[2].exprUnion()) + } + yyVAL.union = yyLOCAL + case 797: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.ComparisonExpr +//line mysql_sql.y:5774 + { + yyLOCAL = tree.NewComparisonExpr(tree.ILIKE, nil, yyDollar[2].exprUnion()) + } + yyVAL.union = yyLOCAL + case 798: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:5779 + { + yyVAL.str = "" + } + case 799: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:5783 + { + yyVAL.str = yyDollar[2].cstrUnion().Compare() + } + case 800: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.UnresolvedObjectName +//line mysql_sql.y:5789 + { + yyLOCAL = yyDollar[2].unresolvedObjectNameUnion() + } + yyVAL.union = yyLOCAL + case 805: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:5802 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 806: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:5806 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 807: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5812 + { + yyLOCAL = &tree.ShowCreateTable{ + Name: yyDollar[4].unresolvedObjectNameUnion(), + AtTsExpr: yyDollar[5].atTimeStampUnion(), + } + } + yyVAL.union = yyLOCAL + case 808: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5820 + { + yyLOCAL = &tree.ShowCreateView{ + Name: yyDollar[4].unresolvedObjectNameUnion(), + AtTsExpr: yyDollar[5].atTimeStampUnion(), + } + } + yyVAL.union = yyLOCAL + case 809: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5827 + { + yyLOCAL = &tree.ShowCreateDatabase{ + IfNotExists: yyDollar[4].ifNotExistsUnion(), + Name: yyDollar[5].str, + AtTsExpr: yyDollar[6].atTimeStampUnion(), + } + } + yyVAL.union = yyLOCAL + case 810: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5835 + { + yyLOCAL = &tree.ShowCreatePublications{Name: yyDollar[4].str} + } + yyVAL.union = yyLOCAL + case 811: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5841 + { + yyLOCAL = &tree.ShowBackendServers{} + } + yyVAL.union = yyLOCAL + case 812: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.UnresolvedObjectName +//line mysql_sql.y:5847 + { + tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedObjectName(tblName) + } + yyVAL.union = yyLOCAL + case 813: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.UnresolvedObjectName +//line mysql_sql.y:5852 + { + dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[3].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedObjectName(dbName, tblName) + } + yyVAL.union = yyLOCAL + case 814: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:5860 + { + yyVAL.str = yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + } + case 815: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.UnresolvedObjectName +//line mysql_sql.y:5866 + { + tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedObjectName(tblName) + } + yyVAL.union = yyLOCAL + case 816: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.UnresolvedObjectName +//line mysql_sql.y:5871 + { + dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[3].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedObjectName(dbName, tblName) + } + yyVAL.union = yyLOCAL + case 817: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.UnresolvedObjectName +//line mysql_sql.y:5877 + { + yyLOCAL = tree.NewUnresolvedObjectName(yyDollar[1].cstrUnion().Compare(), yyDollar[3].cstrUnion().Compare(), yyDollar[5].cstrUnion().Compare()) + } + yyVAL.union = yyLOCAL + case 818: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5883 + { + yyLOCAL = tree.NewTruncateTable(yyDollar[2].tableNameUnion()) + } + yyVAL.union = yyLOCAL + case 819: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5887 + { + yyLOCAL = tree.NewTruncateTable(yyDollar[3].tableNameUnion()) + } + yyVAL.union = yyLOCAL + case 841: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5918 + { + yyLOCAL = &tree.DropSQLTask{ + IfExists: yyDollar[3].boolValUnion(), + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 842: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5927 + { + yyLOCAL = &tree.DropIcebergCatalog{ + IfExists: yyDollar[4].boolValUnion(), + Name: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 843: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5936 + { + yyLOCAL = &tree.DropMongoDBConnection{ + IfExists: yyDollar[4].boolValUnion(), + Name: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 844: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5945 + { + var ifExists = yyDollar[3].boolValUnion() + var name = yyDollar[4].tableNamesUnion() + yyLOCAL = tree.NewDropSequence(ifExists, name) + } + yyVAL.union = yyLOCAL + case 845: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5953 + { + var ifExists = yyDollar[3].boolValUnion() + var name = yyDollar[4].exprUnion() + yyLOCAL = tree.NewDropAccount(ifExists, name) + } + yyVAL.union = yyLOCAL + case 846: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5961 + { + var ifExists = yyDollar[3].boolValUnion() + var users = yyDollar[4].usersUnion() + yyLOCAL = tree.NewDropUser(ifExists, users) + } + yyVAL.union = yyLOCAL + case 847: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.User +//line mysql_sql.y:5969 + { + yyLOCAL = []*tree.User{yyDollar[1].userUnion()} + } + yyVAL.union = yyLOCAL + case 848: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.User +//line mysql_sql.y:5973 + { + yyLOCAL = append(yyDollar[1].usersUnion(), yyDollar[3].userUnion()) + } + yyVAL.union = yyLOCAL + case 849: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.User +//line mysql_sql.y:5979 + { + var Username = yyDollar[1].usernameRecordUnion().Username + var Hostname = yyDollar[1].usernameRecordUnion().Hostname + var AuthOption *tree.AccountIdentified + yyLOCAL = tree.NewUser( + Username, + Hostname, + AuthOption, + ) + } + yyVAL.union = yyLOCAL + case 850: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:5992 + { + var ifExists = yyDollar[3].boolValUnion() + var roles = yyDollar[4].rolesUnion() + yyLOCAL = tree.NewDropRole(ifExists, roles) + } + yyVAL.union = yyLOCAL + case 851: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6000 + { + var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + var tableName = yyDollar[6].tableNameUnion() + var ifExists = yyDollar[3].boolValUnion() + yyLOCAL = tree.NewDropIndex(name, tableName, ifExists) + } + yyVAL.union = yyLOCAL + case 852: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6009 + { + var ifExists = yyDollar[4].boolValUnion() + var names = yyDollar[5].tableNamesUnion() + var stmt = tree.NewDropTable(ifExists, names) + stmt.Temporary = yyDollar[2].boolValUnion() + yyLOCAL = stmt + } + yyVAL.union = yyLOCAL + case 853: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6019 + { + var ifExists = yyDollar[3].boolValUnion() + var names = yyDollar[4].tableNamesUnion() + yyLOCAL = tree.NewDropView(ifExists, names) + } + yyVAL.union = yyLOCAL + case 854: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6027 + { + var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + var ifExists = yyDollar[3].boolValUnion() + yyLOCAL = tree.NewDropDatabase(name, ifExists) + } + yyVAL.union = yyLOCAL + case 855: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6033 + { + var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + var ifExists = yyDollar[3].boolValUnion() + yyLOCAL = tree.NewDropDatabase(name, ifExists) + } + yyVAL.union = yyLOCAL + case 856: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6041 + { + yyLOCAL = tree.NewDeallocate(tree.Identifier(yyDollar[3].str), true) + } + yyVAL.union = yyLOCAL + case 857: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6047 + { + var ifExists = yyDollar[3].boolValUnion() + var name = yyDollar[4].functionNameUnion() + var args = yyDollar[6].funcArgsUnion() + var dropFunction = tree.NewDropFunction(name, args) + dropFunction.IfExists = ifExists + yyLOCAL = dropFunction + } + yyVAL.union = yyLOCAL + case 858: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6058 + { + var name = yyDollar[3].procNameUnion() + var ifExists = false + yyLOCAL = tree.NewDropProcedure(name, ifExists) + } + yyVAL.union = yyLOCAL + case 859: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6064 + { + var name = yyDollar[5].procNameUnion() + var ifExists = true + yyLOCAL = tree.NewDropProcedure(name, ifExists) + } + yyVAL.union = yyLOCAL + case 860: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6072 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[1].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = yyDollar[1].statementUnion() + } + yyVAL.union = yyLOCAL + case 861: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6080 + { + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[1].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = yyDollar[1].statementUnion() + } + yyVAL.union = yyLOCAL + case 862: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6088 + { + yyDollar[2].statementUnion().(*tree.Delete).With = yyDollar[1].withClauseUnion() + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[2].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = yyDollar[2].statementUnion() + } + yyVAL.union = yyLOCAL + case 863: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6097 + { + yyDollar[2].statementUnion().(*tree.Delete).With = yyDollar[1].withClauseUnion() + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[2].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = yyDollar[2].statementUnion() + } + yyVAL.union = yyLOCAL + case 864: + yyDollar = yyS[yypt-12 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6108 + { + // Single-Table Syntax + t := &tree.AliasedTableExpr{ + Expr: yyDollar[6].tableNameUnion(), + As: tree.AliasClause{ + Alias: tree.Identifier(yyDollar[8].str), + }, + } + yyLOCAL = &tree.Delete{ + Tables: tree.TableExprs{t}, + Priority: yyDollar[2].str, + Quick: yyDollar[3].str != "", + Ignore: yyDollar[4].str != "", + PartitionNames: yyDollar[7].identifierListUnion(), + Where: yyDollar[9].whereUnion(), + OrderBy: yyDollar[10].orderByUnion(), + Limit: yyDollar[11].limitUnion(), + Returning: yyDollar[12].selectExprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 865: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6129 + { + // Multiple-Table Syntax + yyLOCAL = &tree.Delete{ + Tables: yyDollar[5].tableExprsUnion(), + Priority: yyDollar[2].str, + Quick: yyDollar[3].str != "", + Ignore: yyDollar[4].str != "", + Where: yyDollar[8].whereUnion(), + TableRefs: tree.TableExprs{yyDollar[7].tableExprUnion()}, + Returning: yyDollar[9].selectExprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 866: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6144 + { + // Multiple-Table Syntax + yyLOCAL = &tree.Delete{ + Tables: yyDollar[6].tableExprsUnion(), + Priority: yyDollar[2].str, + Quick: yyDollar[3].str != "", + Ignore: yyDollar[4].str != "", + Where: yyDollar[9].whereUnion(), + TableRefs: tree.TableExprs{yyDollar[8].tableExprUnion()}, + Returning: yyDollar[10].selectExprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 867: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableExprs +//line mysql_sql.y:6159 + { + yyLOCAL = tree.TableExprs{yyDollar[1].tableNameUnion()} + } + yyVAL.union = yyLOCAL + case 868: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableExprs +//line mysql_sql.y:6163 + { + yyLOCAL = append(yyDollar[1].tableExprsUnion(), yyDollar[3].tableNameUnion()) + } + yyVAL.union = yyLOCAL + case 869: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.TableName +//line mysql_sql.y:6169 + { + tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + prefix := tree.ObjectNamePrefix{ExplicitSchema: false} + yyLOCAL = tree.NewTableName(tree.Identifier(tblName), prefix, nil) + } + yyVAL.union = yyLOCAL + case 870: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.TableName +//line mysql_sql.y:6175 + { + dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[3].cstrUnion().Origin()) + prefix := tree.ObjectNamePrefix{SchemaName: tree.Identifier(dbName), ExplicitSchema: true} + yyLOCAL = tree.NewTableName(tree.Identifier(tblName), prefix, nil) + } + yyVAL.union = yyLOCAL + case 871: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:6184 + { + } + case 872: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:6186 + { + } + case 873: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:6189 + { + yyVAL.str = "" + } + case 878: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:6198 + { + yyVAL.str = "" + } + case 880: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:6202 + { + yyVAL.str = "" + } + case 881: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:6206 + { + yyVAL.str = "ignore" + } + case 882: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:6214 + { + } + case 885: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6220 + { + rep := yyDollar[5].replaceUnion() + if intoErr := tree.ValidateSelectIntoNotAllowed(rep.Rows); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + rep.Table = yyDollar[3].tableExprUnion() + target := yyDollar[3].tableExprUnion().(*tree.TableName) + rep.TargetDatabaseName = target.SchemaName + rep.TargetTableName = target.ObjectName + rep.PartitionNames = yyDollar[4].identifierListUnion() + rep.Returning = yyDollar[6].selectExprsUnion() + yyLOCAL = rep + } + yyVAL.union = yyLOCAL + case 886: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.Replace +//line mysql_sql.y:6237 + { + vc := tree.NewValuesClause(yyDollar[2].rowsExprsUnion()) + yyLOCAL = &tree.Replace{ + Rows: tree.NewSelect(vc, nil, nil), + } + } + yyVAL.union = yyLOCAL + case 887: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Replace +//line mysql_sql.y:6244 + { + yyLOCAL = &tree.Replace{ + Rows: yyDollar[1].selectUnion(), + } + } + yyVAL.union = yyLOCAL + case 888: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.Replace +//line mysql_sql.y:6250 + { + vc := tree.NewValuesClause(yyDollar[5].rowsExprsUnion()) + yyLOCAL = &tree.Replace{ + Columns: yyDollar[2].insertColumnsUnion().Identifiers, + ColumnNames: yyDollar[2].insertColumnsUnion().Names, + Rows: tree.NewSelect(vc, nil, nil), + } + } + yyVAL.union = yyLOCAL + case 889: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Replace +//line mysql_sql.y:6259 + { + vc := tree.NewValuesClause(yyDollar[4].rowsExprsUnion()) + yyLOCAL = &tree.Replace{ + Rows: tree.NewSelect(vc, nil, nil), + } + } + yyVAL.union = yyLOCAL + case 890: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Replace +//line mysql_sql.y:6266 + { + yyLOCAL = &tree.Replace{ + Columns: yyDollar[2].insertColumnsUnion().Identifiers, + ColumnNames: yyDollar[2].insertColumnsUnion().Names, + Rows: yyDollar[4].selectUnion(), + } + } + yyVAL.union = yyLOCAL + case 891: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.Replace +//line mysql_sql.y:6274 + { + if yyDollar[2].assignmentsUnion() == nil { + yylex.Error("the set list of replace can not be empty") + goto ret1 + } + var identList tree.IdentifierList + var columnNames []*tree.UnresolvedName + var valueList tree.Exprs + for _, a := range yyDollar[2].assignmentsUnion() { + identList = append(identList, a.Column) + columnNames = append(columnNames, a.ColumnName) + valueList = append(valueList, a.Expr) + } + vc := tree.NewValuesClause([]tree.Exprs{valueList}) + yyLOCAL = &tree.Replace{ + Columns: identList, + ColumnNames: columnNames, + Rows: tree.NewSelect(vc, nil, nil), + IsSetFormat: true, + } + } + yyVAL.union = yyLOCAL + case 893: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6299 + { + yyDollar[2].statementUnion().(*tree.Insert).With = yyDollar[1].withClauseUnion() + if intoErr := tree.ValidateSelectIntoEnclosingStatement(yyDollar[2].statementUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = yyDollar[2].statementUnion() + } + yyVAL.union = yyLOCAL + case 895: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6309 + { + yyDollar[2].statementUnion().(*tree.MultiInsert).With = yyDollar[1].withClauseUnion() + yyLOCAL = yyDollar[2].statementUnion() + } + yyVAL.union = yyLOCAL + case 896: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6319 + { + if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[4].selectUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = &tree.MultiInsert{Targets: yyDollar[3].multiInsertTargetsUnion(), Source: yyDollar[4].selectUnion()} + } + yyVAL.union = yyLOCAL + case 897: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6327 + { + if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[5].selectUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = &tree.MultiInsert{Whens: yyDollar[3].multiInsertWhensUnion(), Else: yyDollar[4].multiInsertTargetsUnion(), Source: yyDollar[5].selectUnion()} + } + yyVAL.union = yyLOCAL + case 898: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6335 + { + if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[5].selectUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = &tree.MultiInsert{First: true, Whens: yyDollar[3].multiInsertWhensUnion(), Else: yyDollar[4].multiInsertTargetsUnion(), Source: yyDollar[5].selectUnion()} + } + yyVAL.union = yyLOCAL + case 899: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.MultiInsertWhen +//line mysql_sql.y:6345 + { + yyLOCAL = []*tree.MultiInsertWhen{yyDollar[1].multiInsertWhenUnion()} + } + yyVAL.union = yyLOCAL + case 900: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []*tree.MultiInsertWhen +//line mysql_sql.y:6349 + { + yyLOCAL = append(yyDollar[1].multiInsertWhensUnion(), yyDollar[2].multiInsertWhenUnion()) + } + yyVAL.union = yyLOCAL + case 901: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.MultiInsertWhen +//line mysql_sql.y:6355 + { + yyLOCAL = &tree.MultiInsertWhen{Cond: yyDollar[2].exprUnion(), Targets: yyDollar[4].multiInsertTargetsUnion()} + } + yyVAL.union = yyLOCAL + case 902: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []*tree.MultiInsertTarget +//line mysql_sql.y:6360 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 903: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []*tree.MultiInsertTarget +//line mysql_sql.y:6364 + { + yyLOCAL = yyDollar[2].multiInsertTargetsUnion() + } + yyVAL.union = yyLOCAL + case 904: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.MultiInsertTarget +//line mysql_sql.y:6370 + { + yyLOCAL = []*tree.MultiInsertTarget{yyDollar[1].multiInsertTargetUnion()} + } + yyVAL.union = yyLOCAL + case 905: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []*tree.MultiInsertTarget +//line mysql_sql.y:6374 + { + yyLOCAL = append(yyDollar[1].multiInsertTargetsUnion(), yyDollar[2].multiInsertTargetUnion()) + } + yyVAL.union = yyLOCAL + case 906: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.MultiInsertTarget +//line mysql_sql.y:6380 + { + yyLOCAL = &tree.MultiInsertTarget{Table: yyDollar[2].tableNameUnion()} + } + yyVAL.union = yyLOCAL + case 907: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.MultiInsertTarget +//line mysql_sql.y:6384 + { + yyLOCAL = &tree.MultiInsertTarget{Table: yyDollar[2].tableNameUnion(), Values: yyDollar[5].exprsUnion()} + } + yyVAL.union = yyLOCAL + case 908: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.MultiInsertTarget +//line mysql_sql.y:6388 + { + yyLOCAL = &tree.MultiInsertTarget{Table: yyDollar[2].tableNameUnion(), Columns: yyDollar[4].insertColumnsUnion().Identifiers, ColumnNames: yyDollar[4].insertColumnsUnion().Names} + } + yyVAL.union = yyLOCAL + case 909: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL *tree.MultiInsertTarget +//line mysql_sql.y:6392 + { + yyLOCAL = &tree.MultiInsertTarget{Table: yyDollar[2].tableNameUnion(), Columns: yyDollar[4].insertColumnsUnion().Identifiers, ColumnNames: yyDollar[4].insertColumnsUnion().Names, Values: yyDollar[8].exprsUnion()} + } + yyVAL.union = yyLOCAL + case 910: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6398 + { + ins := yyDollar[4].insertUnion() + if intoErr := tree.ValidateSelectIntoNotAllowed(ins.Rows); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + ins.Table = yyDollar[2].tableExprUnion() + target := yyDollar[2].tableExprUnion().(*tree.TableName) + ins.TargetDatabaseName = target.SchemaName + ins.TargetTableName = target.ObjectName + if yyDollar[3].insertPartitionUnion() != nil { + ins.PartitionNames = yyDollar[3].insertPartitionUnion().Names + ins.PartitionValues = yyDollar[3].insertPartitionUnion().Values + } + ins.OnDuplicateUpdate = yyDollar[5].updateExprsUnion() + if len(ins.OnDuplicateUpdate) == 1 && ins.OnDuplicateUpdate[0] == nil { + ins.Ignore = true + ins.OnDuplicateUpdate = nil + } + ins.Returning = yyDollar[6].selectExprsUnion() + yyLOCAL = ins + } + yyVAL.union = yyLOCAL + case 911: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6421 + { + ins := yyDollar[5].insertUnion() + if intoErr := tree.ValidateSelectIntoNotAllowed(ins.Rows); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + ins.Table = yyDollar[3].tableExprUnion() + target := yyDollar[3].tableExprUnion().(*tree.TableName) + ins.TargetDatabaseName = target.SchemaName + ins.TargetTableName = target.ObjectName + if yyDollar[4].insertPartitionUnion() != nil { + ins.PartitionNames = yyDollar[4].insertPartitionUnion().Names + ins.PartitionValues = yyDollar[4].insertPartitionUnion().Values + } + ins.Overwrite = true + ins.Returning = yyDollar[6].selectExprsUnion() + yyLOCAL = ins + } + yyVAL.union = yyLOCAL + case 912: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6440 + { + ins := yyDollar[5].insertUnion() + if intoErr := tree.ValidateSelectIntoNotAllowed(ins.Rows); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + ins.Table = yyDollar[3].tableExprUnion() + target := yyDollar[3].tableExprUnion().(*tree.TableName) + ins.TargetDatabaseName = target.SchemaName + ins.TargetTableName = target.ObjectName + if yyDollar[4].insertPartitionUnion() != nil { + ins.PartitionNames = yyDollar[4].insertPartitionUnion().Names + ins.PartitionValues = yyDollar[4].insertPartitionUnion().Values + } + ins.Ignore = true + ins.OnDuplicateUpdate = nil + ins.Returning = yyDollar[6].selectExprsUnion() + yyLOCAL = ins + } + yyVAL.union = yyLOCAL + case 913: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6460 + { + ins := yyDollar[5].insertUnion() + if intoErr := tree.ValidateSelectIntoNotAllowed(ins.Rows); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + ins.Table = yyDollar[3].tableExprUnion() + target := yyDollar[3].tableExprUnion().(*tree.TableName) + ins.TargetDatabaseName = target.SchemaName + ins.TargetTableName = target.ObjectName + if yyDollar[4].insertPartitionUnion() != nil { + ins.PartitionNames = yyDollar[4].insertPartitionUnion().Names + ins.PartitionValues = yyDollar[4].insertPartitionUnion().Values + } + ins.Ignore = true + ins.OnDuplicateUpdate = yyDollar[6].updateExprsUnion() + if len(ins.OnDuplicateUpdate) == 1 && ins.OnDuplicateUpdate[0] == nil { + ins.OnDuplicateUpdate = nil + } + ins.Returning = yyDollar[7].selectExprsUnion() + yyLOCAL = ins + } + yyVAL.union = yyLOCAL + case 914: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.SelectExprs +//line mysql_sql.y:6484 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 915: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.SelectExprs +//line mysql_sql.y:6488 + { + yyLOCAL = yyDollar[2].selectExprsUnion() + } + yyVAL.union = yyLOCAL + case 916: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6494 + { + yyLOCAL = yyDollar[1].mergeUnion() + } + yyVAL.union = yyLOCAL + case 917: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:6498 + { + yyDollar[2].mergeUnion().With = yyDollar[1].withClauseUnion() + yyLOCAL = yyDollar[2].mergeUnion() + } + yyVAL.union = yyLOCAL + case 918: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL *tree.Merge +//line mysql_sql.y:6505 + { + yyLOCAL = &tree.Merge{ + Target: yyDollar[3].tableExprUnion(), + Source: yyDollar[5].tableExprUnion(), + On: yyDollar[7].exprUnion(), + Clauses: yyDollar[8].mergeClausesUnion(), + } + } + yyVAL.union = yyLOCAL + case 919: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL *tree.Merge +//line mysql_sql.y:6514 + { + yyLOCAL = &tree.Merge{ + Target: yyDollar[3].tableExprUnion(), + Source: yyDollar[5].tableExprUnion(), + On: yyDollar[7].exprUnion(), + Clauses: yyDollar[8].mergeClausesUnion(), + Returning: yyDollar[10].selectExprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 920: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.MergeClauses +//line mysql_sql.y:6526 + { + yyLOCAL = tree.MergeClauses{yyDollar[1].mergeClauseUnion()} + } + yyVAL.union = yyLOCAL + case 921: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.MergeClauses +//line mysql_sql.y:6530 + { + yyLOCAL = append(yyDollar[1].mergeClausesUnion(), yyDollar[2].mergeClauseUnion()) + } + yyVAL.union = yyLOCAL + case 922: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL *tree.MergeClause +//line mysql_sql.y:6536 + { + yyLOCAL = &tree.MergeClause{ + Matched: true, + Condition: yyDollar[3].exprUnion(), + Action: tree.MergeActionUpdate, + UpdateExprs: yyDollar[7].updateExprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 923: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.MergeClause +//line mysql_sql.y:6545 + { + yyLOCAL = &tree.MergeClause{ + Matched: true, + Condition: yyDollar[3].exprUnion(), + Action: tree.MergeActionDelete, + } + } + yyVAL.union = yyLOCAL + case 924: + yyDollar = yyS[yypt-13 : yypt+1] + var yyLOCAL *tree.MergeClause +//line mysql_sql.y:6553 + { + yyLOCAL = &tree.MergeClause{ + Matched: false, + Condition: yyDollar[4].exprUnion(), + Action: tree.MergeActionInsert, + InsertColumns: yyDollar[8].identifierListUnion(), + InsertValues: yyDollar[12].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 925: + yyDollar = yyS[yypt-13 : yypt+1] + var yyLOCAL *tree.MergeClause +//line mysql_sql.y:6563 + { + yyLOCAL = &tree.MergeClause{ + Matched: false, + Condition: yyDollar[4].exprUnion(), + Action: tree.MergeActionInsert, + InsertColumns: yyDollar[8].identifierListUnion(), + InsertValues: yyDollar[12].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 926: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL *tree.MergeClause +//line mysql_sql.y:6573 + { + yyLOCAL = &tree.MergeClause{ + Matched: false, + Condition: yyDollar[4].exprUnion(), + Action: tree.MergeActionInsert, + InsertValues: yyDollar[9].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 927: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL *tree.MergeClause +//line mysql_sql.y:6582 + { + yyLOCAL = &tree.MergeClause{ + Matched: false, + Condition: yyDollar[4].exprUnion(), + Action: tree.MergeActionInsert, + InsertValues: yyDollar[9].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 928: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:6593 + { + if !strings.EqualFold(yyDollar[1].cstrUnion().Origin(), "matched") { + yylex.Error("expected MATCHED") + goto ret1 + } + yyVAL.str = yyDollar[1].cstrUnion().Origin() + } + case 929: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:6602 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 930: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:6606 + { + yyLOCAL = yyDollar[2].exprUnion() + } + yyVAL.union = yyLOCAL + case 931: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:6612 + { + yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].str)} + } + yyVAL.union = yyLOCAL + case 932: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:6616 + { + yyLOCAL = append(yyDollar[1].identifierListUnion(), tree.Identifier(yyDollar[3].str)) + } + yyVAL.union = yyLOCAL + case 933: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.Insert +//line mysql_sql.y:6622 + { + vc := tree.NewValuesClause(yyDollar[2].rowsExprsUnion()) + yyLOCAL = &tree.Insert{ + Rows: tree.NewSelect(vc, nil, nil), + } + } + yyVAL.union = yyLOCAL + case 934: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Insert +//line mysql_sql.y:6629 + { + yyLOCAL = &tree.Insert{ + Rows: yyDollar[1].selectUnion(), + } + } + yyVAL.union = yyLOCAL + case 935: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.Insert +//line mysql_sql.y:6635 + { + vc := tree.NewValuesClause(yyDollar[5].rowsExprsUnion()) + yyLOCAL = &tree.Insert{ + Columns: yyDollar[2].insertColumnsUnion().Identifiers, + ColumnNames: yyDollar[2].insertColumnsUnion().Names, + Rows: tree.NewSelect(vc, nil, nil), + } + } + yyVAL.union = yyLOCAL + case 936: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Insert +//line mysql_sql.y:6644 + { + vc := tree.NewValuesClause(yyDollar[4].rowsExprsUnion()) + yyLOCAL = &tree.Insert{ + Rows: tree.NewSelect(vc, nil, nil), + } + } + yyVAL.union = yyLOCAL + case 937: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Insert +//line mysql_sql.y:6651 + { + yyLOCAL = &tree.Insert{ + Columns: yyDollar[2].insertColumnsUnion().Identifiers, + ColumnNames: yyDollar[2].insertColumnsUnion().Names, + Rows: yyDollar[4].selectUnion(), + } + } + yyVAL.union = yyLOCAL + case 938: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.Insert +//line mysql_sql.y:6659 + { + if yyDollar[2].assignmentsUnion() == nil { + yylex.Error("the set list of insert can not be empty") + goto ret1 + } + var identList tree.IdentifierList + var columnNames []*tree.UnresolvedName + var valueList tree.Exprs + for _, a := range yyDollar[2].assignmentsUnion() { + identList = append(identList, a.Column) + columnNames = append(columnNames, a.ColumnName) + valueList = append(valueList, a.Expr) + } + vc := tree.NewValuesClause([]tree.Exprs{valueList}) + yyLOCAL = &tree.Insert{ + Columns: identList, + ColumnNames: columnNames, + Rows: tree.NewSelect(vc, nil, nil), + } + } + yyVAL.union = yyLOCAL + case 939: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.UpdateExprs +//line mysql_sql.y:6681 + { + yyLOCAL = []*tree.UpdateExpr{} + } + yyVAL.union = yyLOCAL + case 940: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.UpdateExprs +//line mysql_sql.y:6685 + { + yyLOCAL = yyDollar[1].updateExprsUnion() + } + yyVAL.union = yyLOCAL + case 941: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.UpdateExprs +//line mysql_sql.y:6691 + { + yyLOCAL = yyDollar[5].updateExprsUnion() + } + yyVAL.union = yyLOCAL + case 942: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.UpdateExprs +//line mysql_sql.y:6695 + { + yyLOCAL = []*tree.UpdateExpr{nil} + } + yyVAL.union = yyLOCAL + case 943: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []*tree.Assignment +//line mysql_sql.y:6701 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 944: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.Assignment +//line mysql_sql.y:6705 + { + yyLOCAL = []*tree.Assignment{yyDollar[1].assignmentUnion()} + } + yyVAL.union = yyLOCAL + case 945: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.Assignment +//line mysql_sql.y:6709 + { + yyLOCAL = append(yyDollar[1].assignmentsUnion(), yyDollar[3].assignmentUnion()) + } + yyVAL.union = yyLOCAL + case 946: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.Assignment +//line mysql_sql.y:6715 + { + yyLOCAL = &tree.Assignment{ + Column: tree.Identifier(yyDollar[1].unresolvedNameUnion().ColName()), + ColumnName: yyDollar[1].unresolvedNameUnion(), + Expr: yyDollar[3].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 947: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.InsertColumns +//line mysql_sql.y:6725 + { + yyLOCAL = tree.InsertColumns{ + Identifiers: tree.IdentifierList{tree.Identifier(yyDollar[1].unresolvedNameUnion().ColName())}, + Names: []*tree.UnresolvedName{yyDollar[1].unresolvedNameUnion()}, + } + } + yyVAL.union = yyLOCAL + case 948: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.InsertColumns +//line mysql_sql.y:6732 + { + yyLOCAL = yyDollar[1].insertColumnsUnion() + yyLOCAL.Identifiers = append(yyDollar[1].insertColumnsUnion().Identifiers, tree.Identifier(yyDollar[3].unresolvedNameUnion().ColName())) + yyLOCAL.Names = append(yyDollar[1].insertColumnsUnion().Names, yyDollar[3].unresolvedNameUnion()) + } + yyVAL.union = yyLOCAL + case 949: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:6740 + { + yyLOCAL = tree.NewUnresolvedName(yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin())) + } + yyVAL.union = yyLOCAL + case 950: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:6744 + { + tblName := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedName(tblName, yyDollar[3].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 951: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:6749 + { + dbName := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) + tblName := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[3].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedName(dbName, tblName, yyDollar[5].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 952: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:6757 + { + yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 953: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:6761 + { + yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[3].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 954: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:6765 + { + yyLOCAL = append(yyDollar[1].identifierListUnion(), tree.Identifier(yyDollar[3].cstrUnion().Compare())) + } + yyVAL.union = yyLOCAL + case 955: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:6769 + { + yyLOCAL = append(yyDollar[1].identifierListUnion(), tree.Identifier(yyDollar[5].cstrUnion().Compare())) + } + yyVAL.union = yyLOCAL + case 956: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.Exprs +//line mysql_sql.y:6775 + { + yyLOCAL = []tree.Exprs{yyDollar[1].exprsUnion()} + } + yyVAL.union = yyLOCAL + case 957: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []tree.Exprs +//line mysql_sql.y:6779 + { + yyLOCAL = append(yyDollar[1].rowsExprsUnion(), yyDollar[3].exprsUnion()) + } + yyVAL.union = yyLOCAL + case 958: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:6785 + { + yyLOCAL = yyDollar[3].exprsUnion() + } + yyVAL.union = yyLOCAL + case 959: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:6790 + { + } + case 961: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:6794 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 963: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:6801 + { + yyLOCAL = tree.Exprs{yyDollar[1].exprUnion()} + } + yyVAL.union = yyLOCAL + case 964: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:6805 + { + yyLOCAL = append(yyDollar[1].exprsUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 966: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:6812 + { + yyLOCAL = &tree.DefaultVal{} + } + yyVAL.union = yyLOCAL + case 967: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:6817 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 968: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:6821 + { + yyLOCAL = yyDollar[3].identifierListUnion() + } + yyVAL.union = yyLOCAL + case 969: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.InsertPartitionClause +//line mysql_sql.y:6826 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 970: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.InsertPartitionClause +//line mysql_sql.y:6830 + { + yyLOCAL = &tree.InsertPartitionClause{Names: yyDollar[3].identifierListUnion()} + } + yyVAL.union = yyLOCAL + case 971: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.InsertPartitionClause +//line mysql_sql.y:6834 + { + yyLOCAL = &tree.InsertPartitionClause{Values: yyDollar[3].partitionValuesUnion()} + } + yyVAL.union = yyLOCAL + case 972: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.PartitionValues +//line mysql_sql.y:6840 + { + yyLOCAL = tree.PartitionValues{{Name: tree.Identifier(yyDollar[1].cstrUnion().Compare()), Expr: yyDollar[3].exprUnion()}} + } + yyVAL.union = yyLOCAL + case 973: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.PartitionValues +//line mysql_sql.y:6844 + { + yyLOCAL = append(yyDollar[1].partitionValuesUnion(), tree.PartitionValue{Name: tree.Identifier(yyDollar[3].cstrUnion().Compare()), Expr: yyDollar[5].exprUnion()}) + } + yyVAL.union = yyLOCAL + case 974: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:6850 + { + yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 975: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:6854 + { + yyLOCAL = append(yyDollar[1].identifierListUnion(), tree.Identifier(yyDollar[3].cstrUnion().Compare())) + } + yyVAL.union = yyLOCAL + case 976: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:6860 + { + yyLOCAL = yyDollar[2].tableNameUnion() + } + yyVAL.union = yyLOCAL + case 977: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:6864 + { + yyLOCAL = yyDollar[1].tableNameUnion() + } + yyVAL.union = yyLOCAL + case 978: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.SelectInto +//line mysql_sql.y:6870 + { + yyLOCAL = &tree.SelectInto{} + } + yyVAL.union = yyLOCAL + case 979: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL *tree.SelectInto +//line mysql_sql.y:6874 + { + yyLOCAL = &tree.SelectInto{Export: &tree.ExportParam{ + Outfile: true, + FilePath: yyDollar[3].str, + ExportFormat: yyDollar[4].str, + SplitSize: yyDollar[5].uint64ValUnion(), + Fields: yyDollar[6].fieldsUnion(), + Lines: yyDollar[7].linesUnion(), + Header: yyDollar[8].unsignedOptUnion(), + MaxFileSize: uint64(yyDollar[9].int64ValUnion()) * 1024, + ForceQuote: yyDollar[10].strsUnion(), + }} + } + yyVAL.union = yyLOCAL + case 980: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.SelectInto +//line mysql_sql.y:6888 + { + yyLOCAL = &tree.SelectInto{UserVars: yyDollar[2].varExprsUnion()} + } + yyVAL.union = yyLOCAL + case 981: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:6893 + { + yyVAL.str = "" + } + case 982: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:6897 + { + str := strings.ToLower(yyDollar[2].str) + if str != "csv" && str != "jsonline" && str != "parquet" { + yylex.Error("invalid format, must be csv, jsonline or parquet") + goto ret1 + } + yyVAL.str = str + } + case 983: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:6907 + { + yyLOCAL = uint64(0) + } + yyVAL.union = yyLOCAL + case 984: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:6911 + { + size, err := util.ParseDataSize(yyDollar[2].str) + if err != nil { + yylex.Error("invalid splitsize format: " + err.Error()) + goto ret1 + } + yyLOCAL = size + } + yyVAL.union = yyLOCAL + case 985: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.Fields +//line mysql_sql.y:6921 + { + yyLOCAL = &tree.Fields{ + Terminated: &tree.Terminated{ + Value: ",", + }, + EnclosedBy: &tree.EnclosedBy{ + Value: '"', + }, + } + } + yyVAL.union = yyLOCAL + case 986: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Fields +//line mysql_sql.y:6932 + { + yyLOCAL = &tree.Fields{ + Terminated: &tree.Terminated{ + Value: yyDollar[4].str, + }, + EnclosedBy: &tree.EnclosedBy{ + Value: '"', + }, + } + } + yyVAL.union = yyLOCAL + case 987: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL *tree.Fields +//line mysql_sql.y:6943 + { + str := yyDollar[7].str + if str != "\\" && len(str) > 1 { + yylex.Error("export1 error field terminator") + goto ret1 + } + var b byte + if len(str) != 0 { + b = byte(str[0]) + } else { + b = 0 + } + yyLOCAL = &tree.Fields{ + Terminated: &tree.Terminated{ + Value: yyDollar[4].str, + }, + EnclosedBy: &tree.EnclosedBy{ + Value: b, + }, + } + } + yyVAL.union = yyLOCAL + case 988: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Fields +//line mysql_sql.y:6965 + { + str := yyDollar[4].str + if str != "\\" && len(str) > 1 { + yylex.Error("export2 error field terminator") + goto ret1 + } + var b byte + if len(str) != 0 { + b = byte(str[0]) + } else { + b = 0 + } + yyLOCAL = &tree.Fields{ + Terminated: &tree.Terminated{ + Value: ",", + }, + EnclosedBy: &tree.EnclosedBy{ + Value: b, + }, + } + } + yyVAL.union = yyLOCAL + case 989: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.Lines +//line mysql_sql.y:6988 + { + yyLOCAL = &tree.Lines{ + TerminatedBy: &tree.Terminated{ + Value: "\n", + }, + } + } + yyVAL.union = yyLOCAL + case 990: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.Lines +//line mysql_sql.y:6996 + { + yyLOCAL = &tree.Lines{ + TerminatedBy: &tree.Terminated{ + Value: yyDollar[2].str, + }, + } + } + yyVAL.union = yyLOCAL + case 991: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:7005 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 992: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:7009 + { + str := strings.ToLower(yyDollar[2].str) + if str == "true" { + yyLOCAL = true + } else if str == "false" { + yyLOCAL = false + } else { + yylex.Error("error header flag") + goto ret1 + } + } + yyVAL.union = yyLOCAL + case 993: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:7022 + { + yyLOCAL = 0 + } + yyVAL.union = yyLOCAL + case 994: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:7026 + { + value, ok := signedIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + yyLOCAL = value + } + yyVAL.union = yyLOCAL + case 995: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:7033 + { + yyLOCAL = []string{} + } + yyVAL.union = yyLOCAL + case 996: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:7037 + { + yyLOCAL = yyDollar[3].strsUnion() + } + yyVAL.union = yyLOCAL + case 997: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:7043 + { + yyLOCAL = make([]string, 0, 4) + yyLOCAL = append(yyLOCAL, yyDollar[1].cstrUnion().Compare()) + } + yyVAL.union = yyLOCAL + case 998: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:7048 + { + yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].cstrUnion().Compare()) + } + yyVAL.union = yyLOCAL + case 999: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7057 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), OrderBy: yyDollar[2].orderByUnion(), Limit: yyDollar[3].limitUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), nil), IntoVars: intoVars, DeprecatedInto: deprecatedInto} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1001: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7073 + { + yyLOCAL = yyDollar[1].selectUnion() + } + yyVAL.union = yyLOCAL + case 1002: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7077 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), IntoVars: intoVars, DeprecatedInto: deprecatedInto} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1003: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7097 + { + yyLOCAL = yyDollar[1].selectUnion() + } + yyVAL.union = yyLOCAL + case 1004: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7101 + { + yyLOCAL = tree.NewSelect(&tree.ValuesClause{Rows: yyDollar[2].rowsExprsUnion(), RowWord: true}, yyDollar[3].orderByUnion(), yyDollar[4].limitUnion()) + } + yyVAL.union = yyLOCAL + case 1005: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7107 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion()) { + yylex.Error(tree.MisplacedIntoClauseMessage) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[6].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, SelectLockInfo: yyDollar[7].selectLockInfoUnion()} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1006: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7124 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[4].selectIntoUnion()) { + yylex.Error(tree.MisplacedIntoClauseMessage) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), OrderBy: yyDollar[3].orderByUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[4].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[4].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1007: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7141 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion()) { + yylex.Error(tree.MisplacedIntoClauseMessage) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[6].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1008: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7158 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[4].selectIntoUnion()) { + yylex.Error(tree.MisplacedIntoClauseMessage) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), Limit: yyDollar[2].limitUnion(), RankOption: yyDollar[3].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[4].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[4].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1009: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7175 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[5].selectIntoUnion()) { + yylex.Error(tree.MisplacedIntoClauseMessage) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), Limit: yyDollar[3].limitUnion(), RankOption: yyDollar[4].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[5].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[5].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1010: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7192 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[1].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + if tree.SelectIntoActionConflict(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion()) { + yylex.Error(tree.MisplacedIntoClauseMessage) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[6].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1011: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7209 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[2].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + if tree.SelectIntoActionConflict(yyDollar[2].selectStatementUnion(), yyDollar[7].selectIntoUnion()) { + yylex.Error(tree.MisplacedIntoClauseMessage) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), TimeWindow: yyDollar[3].timeWindowUnion(), OrderBy: yyDollar[4].orderByUnion(), Limit: yyDollar[5].limitUnion(), RankOption: yyDollar[6].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[7].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[7].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, SelectLockInfo: yyDollar[8].selectLockInfoUnion(), With: yyDollar[1].withClauseUnion()} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1012: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7226 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[2].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + if tree.SelectIntoActionConflict(yyDollar[2].selectStatementUnion(), yyDollar[4].selectIntoUnion()) { + yylex.Error(tree.MisplacedIntoClauseMessage) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), OrderBy: yyDollar[3].orderByUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[4].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[4].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, With: yyDollar[1].withClauseUnion()} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1013: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7243 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[2].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + if tree.SelectIntoActionConflict(yyDollar[2].selectStatementUnion(), yyDollar[6].selectIntoUnion()) { + yylex.Error(tree.MisplacedIntoClauseMessage) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[6].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, With: yyDollar[1].withClauseUnion()} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1014: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7260 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[2].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + if tree.SelectIntoActionConflict(yyDollar[2].selectStatementUnion(), yyDollar[5].selectIntoUnion()) { + yylex.Error(tree.MisplacedIntoClauseMessage) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), Limit: yyDollar[3].limitUnion(), RankOption: yyDollar[4].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[5].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[5].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, With: yyDollar[1].withClauseUnion()} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1015: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:7277 + { + intoVars, deprecatedInto, intoErr := tree.SelectIntoVariablesForTopLevel(yyDollar[2].selectStatementUnion()) + if intoErr != "" { + yylex.Error(intoErr) + return 1 + } + if tree.SelectIntoActionConflict(yyDollar[2].selectStatementUnion(), yyDollar[6].selectIntoUnion()) { + yylex.Error(tree.MisplacedIntoClauseMessage) + return 1 + } + yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: append(intoVars, yyDollar[6].selectIntoUnion().UserVars...), DeprecatedInto: deprecatedInto, With: yyDollar[1].withClauseUnion()} + if intoErr := tree.ValidateSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 1016: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.TimeWindow +//line mysql_sql.y:7295 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1017: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.TimeWindow +//line mysql_sql.y:7299 + { + yyLOCAL = yyDollar[1].timeWindowUnion() + } + yyVAL.union = yyLOCAL + case 1018: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.TimeWindow +//line mysql_sql.y:7305 + { + yyLOCAL = &tree.TimeWindow{ + Interval: yyDollar[1].timeIntervalUnion(), + Sliding: yyDollar[2].timeSlidingUnion(), + GapFill: yyDollar[3].boolValUnion(), + Fill: yyDollar[4].timeFillUnion(), + } + } + yyVAL.union = yyLOCAL + case 1019: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL *tree.Interval +//line mysql_sql.y:7316 + { + str := fmt.Sprintf("%v", yyDollar[5].item) + v, errStr := util.GetInt64(yyDollar[5].item) + if errStr != "" { + yylex.Error(errStr) + goto ret1 + } + yyLOCAL = &tree.Interval{ + Col: yyDollar[3].unresolvedNameUnion(), + Val: tree.NewNumVal(v, str, false, tree.P_int64), + Unit: yyDollar[7].str, + } + } + yyVAL.union = yyLOCAL + case 1020: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.Sliding +//line mysql_sql.y:7331 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1021: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.Sliding +//line mysql_sql.y:7335 + { + str := fmt.Sprintf("%v", yyDollar[3].item) + v, errStr := util.GetInt64(yyDollar[3].item) + if errStr != "" { + yylex.Error(errStr) + goto ret1 + } + yyLOCAL = &tree.Sliding{ + Val: tree.NewNumVal(v, str, false, tree.P_int64), + Unit: yyDollar[5].str, + } + } + yyVAL.union = yyLOCAL + case 1022: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:7349 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1023: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:7353 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1024: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.Fill +//line mysql_sql.y:7358 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1025: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Fill +//line mysql_sql.y:7362 + { + yyLOCAL = &tree.Fill{ + Mode: yyDollar[3].fillModeUnion(), + } + } + yyVAL.union = yyLOCAL + case 1026: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.Fill +//line mysql_sql.y:7368 + { + yyLOCAL = &tree.Fill{ + Mode: tree.FillValue, + Val: yyDollar[5].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 1027: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FillMode +//line mysql_sql.y:7377 + { + yyLOCAL = tree.FillPrev + } + yyVAL.union = yyLOCAL + case 1028: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FillMode +//line mysql_sql.y:7381 + { + yyLOCAL = tree.FillNext + } + yyVAL.union = yyLOCAL + case 1029: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FillMode +//line mysql_sql.y:7385 + { + yyLOCAL = tree.FillNone + } + yyVAL.union = yyLOCAL + case 1030: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FillMode +//line mysql_sql.y:7389 + { + yyLOCAL = tree.FillNull + } + yyVAL.union = yyLOCAL + case 1031: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FillMode +//line mysql_sql.y:7393 + { + yyLOCAL = tree.FillLinear + } + yyVAL.union = yyLOCAL + case 1032: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.With +//line mysql_sql.y:7399 + { + yyLOCAL = &tree.With{ + IsRecursive: false, + CTEs: yyDollar[2].cteListUnion(), + } + } + yyVAL.union = yyLOCAL + case 1033: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.With +//line mysql_sql.y:7406 + { + yyLOCAL = &tree.With{ + IsRecursive: true, + CTEs: yyDollar[3].cteListUnion(), + } + } + yyVAL.union = yyLOCAL + case 1034: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.CTE +//line mysql_sql.y:7415 + { + yyLOCAL = []*tree.CTE{yyDollar[1].cteUnion()} + } + yyVAL.union = yyLOCAL + case 1035: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.CTE +//line mysql_sql.y:7419 + { + yyLOCAL = append(yyDollar[1].cteListUnion(), yyDollar[3].cteUnion()) + } + yyVAL.union = yyLOCAL + case 1036: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.CTE +//line mysql_sql.y:7425 + { + // stmt has an EMPTY alternative used for bare trailing semicolons. + // Inside a CTE body that produces a nil Stmt and panics in Format + // (CTAS / PREPARE). Reject like MySQL. See #30146. + if yyDollar[5].statementUnion() == nil { + yylex.Error("empty common table expression body") + goto ret1 + } + yyLOCAL = &tree.CTE{ + Name: &tree.AliasClause{Alias: tree.Identifier(yyDollar[1].cstrUnion().Compare()), Cols: yyDollar[2].identifierListUnion()}, + Stmt: yyDollar[5].statementUnion(), + } + } + yyVAL.union = yyLOCAL + case 1037: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:7440 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1038: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:7444 + { + yyLOCAL = yyDollar[2].identifierListUnion() + } + yyVAL.union = yyLOCAL + case 1039: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.Limit +//line mysql_sql.y:7449 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1040: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Limit +//line mysql_sql.y:7453 + { + yyLOCAL = yyDollar[1].limitUnion() + } + yyVAL.union = yyLOCAL + case 1041: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.Limit +//line mysql_sql.y:7458 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1042: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Limit +//line mysql_sql.y:7462 + { + yyLOCAL = yyDollar[1].limitUnion() + } + yyVAL.union = yyLOCAL + case 1043: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Limit +//line mysql_sql.y:7466 + { + yyLOCAL = yyDollar[1].limitUnion() + } + yyVAL.union = yyLOCAL + case 1044: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.Limit +//line mysql_sql.y:7472 + { + yyLOCAL = &tree.Limit{Count: yyDollar[2].exprUnion()} + } + yyVAL.union = yyLOCAL + case 1045: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Limit +//line mysql_sql.y:7476 + { + yyLOCAL = &tree.Limit{Offset: yyDollar[2].exprUnion(), Count: yyDollar[4].exprUnion()} + } + yyVAL.union = yyLOCAL + case 1046: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Limit +//line mysql_sql.y:7480 + { + yyLOCAL = &tree.Limit{Offset: yyDollar[4].exprUnion(), Count: yyDollar[2].exprUnion()} + } + yyVAL.union = yyLOCAL + case 1047: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.Limit +//line mysql_sql.y:7486 + { + yyLOCAL = &tree.Limit{Offset: yyDollar[2].exprUnion()} + } + yyVAL.union = yyLOCAL + case 1048: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.RankOption +//line mysql_sql.y:7491 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1049: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.RankOption +//line mysql_sql.y:7495 + { + // Parse option strings to extract key=value pairs into a map + optionMap := make(map[string]string) + + for _, expr := range yyDollar[5].exprsUnion() { + var str string + // Handle both NumVal (P_char) and StrVal + if numVal, ok := expr.(*tree.NumVal); ok && numVal.ValType == tree.P_char { + str = numVal.String() + } else if strVal, ok := expr.(*tree.StrVal); ok { + str = strVal.String() + } else { + yylex.Error("rank options must be string literals containing key=value") + return 1 + } + + // Remove quotes if present + if len(str) >= 2 && ((str[0] == '\'' && str[len(str)-1] == '\'') || (str[0] == '"' && str[len(str)-1] == '"')) { + str = str[1 : len(str)-1] + } + + // Parse key=value pairs + parts := strings.Split(str, "=") + if len(parts) != 2 || strings.TrimSpace(parts[0]) == "" || strings.TrimSpace(parts[1]) == "" { + yylex.Error("rank options must contain a nonempty key=value pair") + return 1 + } + key := strings.TrimSpace(strings.ToLower(parts[0])) + value := strings.TrimSpace(parts[1]) + optionMap[key] = value + } + + yyLOCAL = &tree.RankOption{ + Option: optionMap, + } + } + yyVAL.union = yyLOCAL + case 1050: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.OrderBy +//line mysql_sql.y:7533 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1051: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.OrderBy +//line mysql_sql.y:7537 + { + yyLOCAL = yyDollar[1].orderByUnion() + } + yyVAL.union = yyLOCAL + case 1052: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.OrderBy +//line mysql_sql.y:7542 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1053: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.OrderBy +//line mysql_sql.y:7546 + { + yyLOCAL = yyDollar[4].orderByUnion() + } + yyVAL.union = yyLOCAL + case 1054: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.OrderBy +//line mysql_sql.y:7552 + { + yyLOCAL = yyDollar[3].orderByUnion() + } + yyVAL.union = yyLOCAL + case 1055: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.OrderBy +//line mysql_sql.y:7558 + { + yyLOCAL = tree.OrderBy{yyDollar[1].orderUnion()} + } + yyVAL.union = yyLOCAL + case 1056: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.OrderBy +//line mysql_sql.y:7562 + { + yyLOCAL = append(yyDollar[1].orderByUnion(), yyDollar[3].orderUnion()) + } + yyVAL.union = yyLOCAL + case 1057: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.Order +//line mysql_sql.y:7568 + { + yyLOCAL = &tree.Order{Expr: yyDollar[1].exprUnion(), Direction: yyDollar[2].directionUnion(), NullsPosition: yyDollar[3].nullsPositionUnion()} + } + yyVAL.union = yyLOCAL + case 1058: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Direction +//line mysql_sql.y:7573 + { + yyLOCAL = tree.DefaultDirection + } + yyVAL.union = yyLOCAL + case 1059: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Direction +//line mysql_sql.y:7577 + { + yyLOCAL = tree.Ascending + } + yyVAL.union = yyLOCAL + case 1060: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Direction +//line mysql_sql.y:7581 + { + yyLOCAL = tree.Descending + } + yyVAL.union = yyLOCAL + case 1061: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.NullsPosition +//line mysql_sql.y:7586 + { + yyLOCAL = tree.DefaultNullsPosition + } + yyVAL.union = yyLOCAL + case 1062: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:7590 + { + yylex.Error("NULLS FIRST is not supported in MySQL syntax") + return 1 + } + case 1063: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:7594 + { + yylex.Error("NULLS LAST is not supported in MySQL syntax") + return 1 + } + case 1064: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.SelectLockInfo +//line mysql_sql.y:7599 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1065: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.SelectLockInfo +//line mysql_sql.y:7603 + { + yyLOCAL = &tree.SelectLockInfo{ + LockType: tree.SelectLockForUpdate, + } + if strings.EqualFold(yyDollar[2].str, "update nowait") { + yyLOCAL.LockType = tree.SelectLockForUpdateNoWait + } + } + yyVAL.union = yyLOCAL + case 1066: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.SelectLockInfo +//line mysql_sql.y:7612 + { + yyLOCAL = &tree.SelectLockInfo{ + LockType: tree.SelectLockForShare, + } + if strings.EqualFold(yyDollar[2].str, "share nowait") { + yyLOCAL.LockType = tree.SelectLockForShareNoWait + } else if strings.EqualFold(yyDollar[2].str, "share skip locked") { + yyLOCAL.LockType = tree.SelectLockForShareSkipLocked + } + } + yyVAL.union = yyLOCAL + case 1067: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.SelectLockInfo +//line mysql_sql.y:7623 + { + yyLOCAL = &tree.SelectLockInfo{ + LockType: tree.SelectLockForShare, + } + } + yyVAL.union = yyLOCAL + case 1068: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7631 + { + yyLOCAL = &tree.ParenSelect{Select: yyDollar[2].selectUnion()} + } + yyVAL.union = yyLOCAL + case 1069: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7635 + { + yyLOCAL = &tree.ParenSelect{Select: &tree.Select{Select: yyDollar[2].selectStatementUnion()}} + } + yyVAL.union = yyLOCAL + case 1070: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7639 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1071: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7643 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1072: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7648 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1073: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7652 + { + yyLOCAL = &tree.UnionClause{ + Type: yyDollar[2].unionTypeRecordUnion().Type, + Left: yyDollar[1].selectStatementUnion(), + Right: yyDollar[3].selectStatementUnion(), + All: yyDollar[2].unionTypeRecordUnion().All, + Distinct: yyDollar[2].unionTypeRecordUnion().Distinct, + } + } + yyVAL.union = yyLOCAL + case 1074: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7662 + { + yyLOCAL = &tree.UnionClause{ + Type: yyDollar[2].unionTypeRecordUnion().Type, + Left: yyDollar[1].selectStatementUnion(), + Right: yyDollar[3].selectStatementUnion(), + All: yyDollar[2].unionTypeRecordUnion().All, + Distinct: yyDollar[2].unionTypeRecordUnion().Distinct, + } + } + yyVAL.union = yyLOCAL + case 1075: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7672 + { + yyLOCAL = &tree.UnionClause{ + Type: yyDollar[2].unionTypeRecordUnion().Type, + Left: yyDollar[1].selectStatementUnion(), + Right: yyDollar[3].selectStatementUnion(), + All: yyDollar[2].unionTypeRecordUnion().All, + Distinct: yyDollar[2].unionTypeRecordUnion().Distinct, + } + } + yyVAL.union = yyLOCAL + case 1076: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7682 + { + yyLOCAL = &tree.UnionClause{ + Type: yyDollar[2].unionTypeRecordUnion().Type, + Left: yyDollar[1].selectStatementUnion(), + Right: yyDollar[3].selectStatementUnion(), + All: yyDollar[2].unionTypeRecordUnion().All, + Distinct: yyDollar[2].unionTypeRecordUnion().Distinct, + } + } + yyVAL.union = yyLOCAL + case 1077: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7692 + { + yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} + } + yyVAL.union = yyLOCAL + case 1078: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7696 + { + yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} + } + yyVAL.union = yyLOCAL + case 1079: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7700 + { + yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} + } + yyVAL.union = yyLOCAL + case 1080: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7704 + { + yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} + } + yyVAL.union = yyLOCAL + case 1081: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7712 + { + yyLOCAL = &tree.ParenSelect{Select: tree.NewSelect(yyDollar[2].selectStatementUnion(), yyDollar[3].orderByUnion(), yyDollar[4].limitUnion())} + } + yyVAL.union = yyLOCAL + case 1082: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7718 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1083: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7722 + { + yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} + } + yyVAL.union = yyLOCAL + case 1084: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7728 + { + yyLOCAL = makeSelectStarFromTable(yyDollar[2].tableNameUnion()) + } + yyVAL.union = yyLOCAL + case 1085: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7733 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1086: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7737 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1087: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7741 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1088: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7745 + { + yyLOCAL = &tree.ValuesClause{Rows: yyDollar[2].rowsExprsUnion(), RowWord: true} + } + yyVAL.union = yyLOCAL + case 1089: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7751 + { + yyLOCAL = &tree.ParenSelect{Select: tree.NewSelect(yyDollar[2].selectStatementUnion(), yyDollar[3].orderByUnion(), yyDollar[4].limitUnion())} + } + yyVAL.union = yyLOCAL + case 1090: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7757 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1091: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7761 + { + yyLOCAL = &tree.UnionClause{Type: yyDollar[2].unionTypeRecordUnion().Type, Left: yyDollar[1].selectStatementUnion(), Right: yyDollar[3].selectStatementUnion(), All: yyDollar[2].unionTypeRecordUnion().All, Distinct: yyDollar[2].unionTypeRecordUnion().Distinct} + } + yyVAL.union = yyLOCAL + case 1092: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7767 + { + yyLOCAL = &tree.ValuesClause{Rows: yyDollar[2].rowsExprsUnion(), RowWord: true} + } + yyVAL.union = yyLOCAL + case 1093: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7773 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1094: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7777 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1095: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7781 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1096: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7785 + { + yyLOCAL = yyDollar[1].selectStatementUnion() + } + yyVAL.union = yyLOCAL + case 1097: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7791 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.UNION, + All: false, + Distinct: false, + } + } + yyVAL.union = yyLOCAL + case 1098: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7799 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.UNION, + All: true, + Distinct: false, + } + } + yyVAL.union = yyLOCAL + case 1099: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7807 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.UNION, + All: false, + Distinct: true, + } + } + yyVAL.union = yyLOCAL + case 1100: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7816 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.EXCEPT, + All: false, + Distinct: false, + } + } + yyVAL.union = yyLOCAL + case 1101: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7824 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.EXCEPT, + All: true, + Distinct: false, + } + } + yyVAL.union = yyLOCAL + case 1102: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7832 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.EXCEPT, + All: false, + Distinct: true, + } + } + yyVAL.union = yyLOCAL + case 1103: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7840 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.INTERSECT, + All: false, + Distinct: false, + } + } + yyVAL.union = yyLOCAL + case 1104: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7848 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.INTERSECT, + All: true, + Distinct: false, + } + } + yyVAL.union = yyLOCAL + case 1105: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7856 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.INTERSECT, + All: false, + Distinct: true, + } + } + yyVAL.union = yyLOCAL + case 1106: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7864 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.UT_MINUS, + All: false, + Distinct: false, + } + } + yyVAL.union = yyLOCAL + case 1107: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7872 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.UT_MINUS, + All: true, + Distinct: false, + } + } + yyVAL.union = yyLOCAL + case 1108: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.UnionTypeRecord +//line mysql_sql.y:7880 + { + yyLOCAL = &tree.UnionTypeRecord{ + Type: tree.UT_MINUS, + All: false, + Distinct: true, + } + } + yyVAL.union = yyLOCAL + case 1109: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.SelectStatement +//line mysql_sql.y:7890 + { + yyLOCAL = &tree.SelectClause{ + Distinct: tree.QuerySpecOptionDistinct&yyDollar[2].selectOptionsUnion() != 0, + Exprs: yyDollar[3].selectExprsUnion(), + IntoVars: yyDollar[4].selectIntoUnion().UserVars, + IntoExport: yyDollar[4].selectIntoUnion().Export, + From: yyDollar[5].fromUnion(), + Where: yyDollar[6].whereUnion(), + GroupBy: yyDollar[7].groupByUnion(), + Having: yyDollar[8].whereUnion(), + Windows: yyDollar[9].windowDefinitionsUnion(), + Option: yyDollar[2].selectOptionsUnion(), + } + } + yyVAL.union = yyLOCAL + case 1110: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7907 + { + yyLOCAL = tree.QuerySpecOptionNone + } + yyVAL.union = yyLOCAL + case 1111: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7911 + { + yyLOCAL = yyDollar[1].selectOptionsUnion() + } + yyVAL.union = yyLOCAL + case 1112: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7917 + { + yyLOCAL = yyDollar[1].selectOptionUnion() + } + yyVAL.union = yyLOCAL + case 1113: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7921 + { + yyLOCAL = yyDollar[1].selectOptionsUnion() | yyDollar[2].selectOptionUnion() + } + yyVAL.union = yyLOCAL + case 1114: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7927 + { + yyLOCAL = tree.QuerySpecOptionSqlSmallResult + } + yyVAL.union = yyLOCAL + case 1115: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7931 + { + yyLOCAL = tree.QuerySpecOptionSqlBigResult + } + yyVAL.union = yyLOCAL + case 1116: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7935 + { + yyLOCAL = tree.QuerySpecOptionSqlBufferResult + } + yyVAL.union = yyLOCAL + case 1117: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7939 + { + yyLOCAL = tree.QuerySpecOptionStraightJoin + } + yyVAL.union = yyLOCAL + case 1118: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7943 + { + yyLOCAL = tree.QuerySpecOptionHighPriority + } + yyVAL.union = yyLOCAL + case 1119: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7947 + { + yyLOCAL = tree.QuerySpecOptionSqlCalcFoundRows + } + yyVAL.union = yyLOCAL + case 1120: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7951 + { + yyLOCAL = tree.QuerySpecOptionSqlNoCache + } + yyVAL.union = yyLOCAL + case 1121: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7955 + { + yyLOCAL = tree.QuerySpecOptionAll + } + yyVAL.union = yyLOCAL + case 1122: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7959 + { + yyLOCAL = tree.QuerySpecOptionDistinct + } + yyVAL.union = yyLOCAL + case 1123: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL uint64 +//line mysql_sql.y:7963 + { + yyLOCAL = tree.QuerySpecOptionDistinctRow + } + yyVAL.union = yyLOCAL + case 1124: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.Where +//line mysql_sql.y:7985 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1125: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.Where +//line mysql_sql.y:7989 + { + yyLOCAL = &tree.Where{Type: tree.AstHaving, Expr: yyDollar[2].exprUnion()} + } + yyVAL.union = yyLOCAL + case 1126: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.GroupByClause +//line mysql_sql.y:7994 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1127: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.GroupByClause +//line mysql_sql.y:7998 + { + exprsList := []tree.Exprs{yyDollar[3].exprsUnion()} + yyLOCAL = &tree.GroupByClause{ + GroupByExprsList: exprsList, + Apart: false, + Cube: false, + Rollup: yyDollar[4].boolValUnion(), + } + } + yyVAL.union = yyLOCAL + case 1128: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL *tree.GroupByClause +//line mysql_sql.y:8008 + { + yyLOCAL = &tree.GroupByClause{ + GroupByExprsList: yyDollar[6].rowsExprsUnion(), + Apart: false, + Cube: false, + GroupingSets: true, + Rollup: false, + } + } + yyVAL.union = yyLOCAL + case 1129: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.GroupByClause +//line mysql_sql.y:8018 + { + yyLOCAL = &tree.GroupByClause{ + GroupByExprsList: []tree.Exprs{yyDollar[5].exprsUnion()}, + Apart: false, + Cube: true, + Rollup: false, + } + } + yyVAL.union = yyLOCAL + case 1130: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.GroupByClause +//line mysql_sql.y:8027 + { + yyLOCAL = &tree.GroupByClause{ + GroupByExprsList: []tree.Exprs{yyDollar[5].exprsUnion()}, + Apart: false, + Cube: false, + Rollup: true, + } + } + yyVAL.union = yyLOCAL + case 1131: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []tree.Exprs +//line mysql_sql.y:8038 + { + yyLOCAL = []tree.Exprs{yyDollar[2].exprsUnion()} + } + yyVAL.union = yyLOCAL + case 1132: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL []tree.Exprs +//line mysql_sql.y:8042 + { + yyLOCAL = append(yyDollar[1].rowsExprsUnion(), yyDollar[4].exprsUnion()) + } + yyVAL.union = yyLOCAL + case 1133: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:8048 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1134: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:8052 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1135: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.Where +//line mysql_sql.y:8057 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1136: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.Where +//line mysql_sql.y:8061 + { + yyLOCAL = &tree.Where{Type: tree.AstWhere, Expr: yyDollar[2].exprUnion()} + } + yyVAL.union = yyLOCAL + case 1137: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectExprs +//line mysql_sql.y:8067 + { + yyLOCAL = tree.SelectExprs{yyDollar[1].selectExprUnion()} + } + yyVAL.union = yyLOCAL + case 1138: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectExprs +//line mysql_sql.y:8071 + { + yyLOCAL = append(yyDollar[1].selectExprsUnion(), yyDollar[3].selectExprUnion()) + } + yyVAL.union = yyLOCAL + case 1139: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.SelectExpr +//line mysql_sql.y:8077 + { + yyLOCAL = tree.SelectExpr{Expr: tree.StarExpr()} + } + yyVAL.union = yyLOCAL + case 1140: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.SelectExpr +//line mysql_sql.y:8081 + { + yyLOCAL = tree.SelectExpr{Expr: yyDollar[1].exprUnion(), As: yyDollar[2].cstrUnion()} + } + yyVAL.union = yyLOCAL + case 1141: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.SelectExpr +//line mysql_sql.y:8085 + { + yyLOCAL = tree.SelectExpr{Expr: tree.NewUnresolvedNameWithStar(yyDollar[1].cstrUnion())} + } + yyVAL.union = yyLOCAL + case 1142: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.SelectExpr +//line mysql_sql.y:8089 + { + yyLOCAL = tree.SelectExpr{Expr: tree.NewUnresolvedNameWithStar(yyDollar[1].cstrUnion(), yyDollar[3].cstrUnion())} + } + yyVAL.union = yyLOCAL + case 1143: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.From +//line mysql_sql.y:8094 + { + prefix := tree.ObjectNamePrefix{ExplicitSchema: false} + tn := tree.NewTableName(tree.Identifier(""), prefix, nil) + yyLOCAL = &tree.From{ + Tables: tree.TableExprs{&tree.AliasedTableExpr{Expr: tn}}, + } + } + yyVAL.union = yyLOCAL + case 1144: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.From +//line mysql_sql.y:8102 + { + yyLOCAL = yyDollar[1].fromUnion() + } + yyVAL.union = yyLOCAL + case 1145: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.From +//line mysql_sql.y:8108 + { + yyLOCAL = &tree.From{ + Tables: tree.TableExprs{yyDollar[2].tableExprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 1146: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:8116 + { + if t, ok := yyDollar[1].tableExprUnion().(*tree.JoinTableExpr); ok { + yyLOCAL = t + } else if t, ok := yyDollar[1].tableExprUnion().(*tree.ApplyTableExpr); ok { + yyLOCAL = t + } else { + yyLOCAL = &tree.JoinTableExpr{Left: yyDollar[1].tableExprUnion(), Right: nil, JoinType: tree.JOIN_TYPE_CROSS} + } + } + yyVAL.union = yyLOCAL + case 1147: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:8126 + { + yyLOCAL = &tree.JoinTableExpr{Left: yyDollar[1].tableExprUnion(), Right: yyDollar[3].tableExprUnion(), JoinType: tree.JOIN_TYPE_CROSS} + } + yyVAL.union = yyLOCAL + case 1149: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:8133 + { + if !strings.EqualFold(yyDollar[2].str, "OJ") { + yylex.Error("expected OJ in table reference escape") + goto ret1 + } + yyLOCAL = yyDollar[3].tableExprUnion() + } + yyVAL.union = yyLOCAL + case 1151: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:8144 + { + yyLOCAL = yyDollar[1].joinTableExprUnion() + } + yyVAL.union = yyLOCAL + case 1152: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:8148 + { + yyLOCAL = yyDollar[1].applyTableExprUnion() + } + yyVAL.union = yyLOCAL + case 1153: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.JoinTableExpr +//line mysql_sql.y:8154 + { + if strings.Contains(yyDollar[2].str, ":") { + ss := strings.SplitN(yyDollar[2].str, ":", 2) + yyLOCAL = &tree.JoinTableExpr{ + Left: yyDollar[1].tableExprUnion(), + JoinType: ss[0], + Right: yyDollar[3].tableExprUnion(), + Cond: yyDollar[4].joinCondUnion(), + Option: ss[1], + } + } else { + yyLOCAL = &tree.JoinTableExpr{ + Left: yyDollar[1].tableExprUnion(), + JoinType: yyDollar[2].str, + Right: yyDollar[3].tableExprUnion(), + Cond: yyDollar[4].joinCondUnion(), + } + } + } + yyVAL.union = yyLOCAL + case 1154: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.JoinTableExpr +//line mysql_sql.y:8174 + { + yyLOCAL = &tree.JoinTableExpr{ + Left: yyDollar[1].tableExprUnion(), + JoinType: yyDollar[2].str, + Right: yyDollar[3].tableExprUnion(), + Cond: yyDollar[4].joinCondUnion(), + } + } + yyVAL.union = yyLOCAL + case 1155: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.JoinTableExpr +//line mysql_sql.y:8183 + { + if yyDollar[4].joinCondUnion() == nil { + yylex.Error("outer join requires ON/USING clause") + goto ret1 + } + yyLOCAL = &tree.JoinTableExpr{ + Left: yyDollar[1].tableExprUnion(), + JoinType: yyDollar[2].str, + Right: yyDollar[3].tableExprUnion(), + Cond: yyDollar[4].joinCondUnion(), + } + } + yyVAL.union = yyLOCAL + case 1156: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.JoinTableExpr +//line mysql_sql.y:8196 + { + yyLOCAL = &tree.JoinTableExpr{ + Left: yyDollar[1].tableExprUnion(), + JoinType: yyDollar[2].str, + Right: yyDollar[3].tableExprUnion(), + } + } + yyVAL.union = yyLOCAL + case 1157: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.JoinTableExpr +//line mysql_sql.y:8204 + { + yyLOCAL = &tree.JoinTableExpr{ + Left: yyDollar[1].tableExprUnion(), + JoinType: yyDollar[2].str, + Right: yyDollar[3].tableExprUnion(), + Cond: yyDollar[4].joinCondUnion(), + } + } + yyVAL.union = yyLOCAL + case 1158: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.JoinTableExpr +//line mysql_sql.y:8213 + { + if !hasAsofLeftFactorAlias(yyDollar[1].tableExprUnion()) { + yylex.Error("native ASOF JOIN requires an aliased left table factor") + goto ret1 + } + yyLOCAL = &tree.JoinTableExpr{ + Left: yyDollar[1].tableExprUnion(), + JoinType: yyDollar[2].str, + Right: yyDollar[3].tableExprUnion(), + Cond: yyDollar[4].joinCondUnion(), + Tolerance: yyDollar[5].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 1159: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.ApplyTableExpr +//line mysql_sql.y:8229 + { + yyLOCAL = &tree.ApplyTableExpr{ + Left: yyDollar[1].tableExprUnion(), + ApplyType: yyDollar[2].str, + Right: yyDollar[3].tableExprUnion(), + } + } + yyVAL.union = yyLOCAL + case 1160: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8239 + { + yyVAL.str = tree.APPLY_TYPE_CROSS + } + case 1161: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8243 + { + yyVAL.str = tree.APPLY_TYPE_OUTER + } + case 1162: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8249 + { + yyVAL.str = tree.JOIN_TYPE_NATURAL + } + case 1163: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8253 + { + switch yyDollar[2].str { + case tree.JOIN_TYPE_LEFT: + yyVAL.str = tree.JOIN_TYPE_NATURAL_LEFT + case tree.JOIN_TYPE_RIGHT: + yyVAL.str = tree.JOIN_TYPE_NATURAL_RIGHT + case tree.JOIN_TYPE_FULL: + yyVAL.str = tree.JOIN_TYPE_NATURAL_FULL + } + } + case 1164: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8266 + { + yyVAL.str = tree.JOIN_TYPE_LEFT + } + case 1165: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:8270 + { + yyVAL.str = tree.JOIN_TYPE_LEFT + } + case 1166: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8274 + { + yyVAL.str = tree.JOIN_TYPE_RIGHT + } + case 1167: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:8278 + { + yyVAL.str = tree.JOIN_TYPE_RIGHT + } + case 1168: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8282 + { + yyVAL.str = tree.JOIN_TYPE_FULL + } + case 1169: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:8286 + { + yyVAL.str = tree.JOIN_TYPE_FULL + } + case 1170: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8292 + { + yyVAL.str = tree.JOIN_TYPE_DEDUP + } + case 1171: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8298 + { + yyVAL.str = tree.JOIN_TYPE_ASOF + } + case 1172: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:8302 + { + yyVAL.str = tree.JOIN_TYPE_ASOF_LEFT + } + case 1173: + yyDollar = yyS[yypt-4 : yypt+1] +//line mysql_sql.y:8306 + { + yyVAL.str = tree.JOIN_TYPE_ASOF_LEFT + } + case 1174: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:8311 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1175: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:8315 + { + yyLOCAL = yyDollar[2].exprUnion() + } + yyVAL.union = yyLOCAL + case 1176: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:8321 + { + stmt := &tree.ValuesStatement{ + Rows: yyDollar[2].rowsExprsUnion(), + OrderBy: yyDollar[3].orderByUnion(), + Limit: yyDollar[4].limitUnion(), + } + if intoErr := tree.ValidateValuesIntoPlacement(stmt); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + yyLOCAL = stmt + } + yyVAL.union = yyLOCAL + case 1177: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.Exprs +//line mysql_sql.y:8336 + { + yyLOCAL = []tree.Exprs{yyDollar[1].exprsUnion()} + } + yyVAL.union = yyLOCAL + case 1178: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []tree.Exprs +//line mysql_sql.y:8340 + { + yyLOCAL = append(yyDollar[1].rowsExprsUnion(), yyDollar[3].exprsUnion()) + } + yyVAL.union = yyLOCAL + case 1179: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:8346 + { + yyLOCAL = yyDollar[3].exprsUnion() + } + yyVAL.union = yyLOCAL + case 1180: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:8352 + { + yyVAL.str = yyDollar[1].str + } + case 1181: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:8358 + { + yyVAL.str = yyDollar[2].str + } + case 1182: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:8364 + { + yyVAL.str = tree.JOIN_TYPE_STRAIGHT + } + case 1183: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:8370 + { + yyVAL.str = tree.JOIN_TYPE_INNER + } + case 1184: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8374 + { + yyVAL.str = tree.JOIN_TYPE_INNER + } + case 1185: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8378 + { + yyVAL.str = tree.JOIN_TYPE_CROSS + } + case 1186: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:8382 + { + yyVAL.str = tree.JOIN_TYPE_CENTROIDX + ":" + yyDollar[2].str + } + case 1187: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.JoinCond +//line mysql_sql.y:8388 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1188: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.JoinCond +//line mysql_sql.y:8392 + { + yyLOCAL = yyDollar[1].joinCondUnion() + } + yyVAL.union = yyLOCAL + case 1189: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.JoinCond +//line mysql_sql.y:8398 + { + yyLOCAL = &tree.OnJoinCond{Expr: yyDollar[2].exprUnion()} + } + yyVAL.union = yyLOCAL + case 1190: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.JoinCond +//line mysql_sql.y:8402 + { + yyLOCAL = &tree.UsingJoinCond{Cols: yyDollar[3].identifierListUnion()} + } + yyVAL.union = yyLOCAL + case 1191: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:8408 + { + yyLOCAL = tree.IdentifierList{tree.Identifier(yyDollar[1].cstrUnion().Compare())} + } + yyVAL.union = yyLOCAL + case 1192: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:8412 + { + yyLOCAL = append(yyDollar[1].identifierListUnion(), tree.Identifier(yyDollar[3].cstrUnion().Compare())) + } + yyVAL.union = yyLOCAL + case 1193: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:8418 + { + yyLOCAL = yyDollar[1].aliasedTableExprUnion() + } + yyVAL.union = yyLOCAL + case 1194: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:8422 + { + yyLOCAL = &tree.AliasedTableExpr{ + Expr: yyDollar[1].parenTableExprUnion(), + As: tree.AliasClause{ + Alias: tree.Identifier(yyDollar[2].str), + Cols: yyDollar[3].identifierListUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 1195: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:8432 + { + if yyDollar[2].str != "" { + yyLOCAL = &tree.AliasedTableExpr{ + Expr: yyDollar[1].tableExprUnion(), + As: tree.AliasClause{ + Alias: tree.Identifier(yyDollar[2].str), + }, + } + } else { + yyLOCAL = yyDollar[1].tableExprUnion() + } + } + yyVAL.union = yyLOCAL + case 1196: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:8445 + { + yyLOCAL = yyDollar[2].tableExprUnion() + } + yyVAL.union = yyLOCAL + case 1197: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.ParenTableExpr +//line mysql_sql.y:8453 + { + yyLOCAL = &tree.ParenTableExpr{Expr: yyDollar[1].selectStatementUnion().(*tree.ParenSelect).Select} + } + yyVAL.union = yyLOCAL + case 1198: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:8459 + { + name := tree.NewUnresolvedName(tree.NewCStr("json_table", 1)) + yyLOCAL = &tree.TableFunction{ + Func: &tree.FuncExpr{Func: tree.FuncName2ResolvableFunctionReference(name), FuncName: tree.NewCStr("json_table", 1), Exprs: tree.Exprs{yyDollar[3].exprUnion()}, Type: tree.FUNC_TYPE_TABLE}, + JSONTable: &tree.JSONTable{Path: yyDollar[5].str, Columns: yyDollar[8].jsonTableColumnsUnion()}, + } + } + yyVAL.union = yyLOCAL + case 1199: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.TableExpr +//line mysql_sql.y:8468 + { + name := tree.NewUnresolvedName(yyDollar[1].cstrUnion()) + yyLOCAL = &tree.TableFunction{ + Func: &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: yyDollar[1].cstrUnion(), + Exprs: yyDollar[3].exprsUnion(), + Type: tree.FUNC_TYPE_TABLE, + }, + } + } + yyVAL.union = yyLOCAL + case 1200: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.JSONTableColumn +//line mysql_sql.y:8482 + { + yyLOCAL = []*tree.JSONTableColumn{yyDollar[1].jsonTableColumnUnion()} + } + yyVAL.union = yyLOCAL + case 1201: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.JSONTableColumn +//line mysql_sql.y:8484 + { + yyLOCAL = append(yyDollar[1].jsonTableColumnsUnion(), yyDollar[3].jsonTableColumnUnion()) + } + yyVAL.union = yyLOCAL + case 1202: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.JSONTableColumn +//line mysql_sql.y:8488 + { + yyLOCAL = &tree.JSONTableColumn{Name: yyDollar[1].cstrUnion().Origin(), Kind: "ordinality"} + } + yyVAL.union = yyLOCAL + case 1203: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.JSONTableColumn +//line mysql_sql.y:8490 + { + yyLOCAL = yyDollar[5].jsonTableColumnUnion() + yyLOCAL.Name = yyDollar[1].cstrUnion().Origin() + yyLOCAL.Kind = "path" + yyLOCAL.Type = yyDollar[2].columnTypeUnion() + yyLOCAL.Path = yyDollar[4].str + } + yyVAL.union = yyLOCAL + case 1204: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.JSONTableColumn +//line mysql_sql.y:8492 + { + yyLOCAL = &tree.JSONTableColumn{Name: yyDollar[1].cstrUnion().Origin(), Kind: "exists", Type: yyDollar[2].columnTypeUnion(), Path: yyDollar[5].str} + } + yyVAL.union = yyLOCAL + case 1205: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL *tree.JSONTableColumn +//line mysql_sql.y:8494 + { + yyLOCAL = &tree.JSONTableColumn{Kind: "nested", Path: yyDollar[3].str, Children: yyDollar[6].jsonTableColumnsUnion()} + } + yyVAL.union = yyLOCAL + case 1206: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:8497 + { + yyVAL.str = "" + } + case 1207: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:8499 + { + yyVAL.str = yyDollar[1].str + } + case 1208: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.JSONTableResponse +//line mysql_sql.y:8503 + { + yyLOCAL = &tree.JSONTableResponse{Action: "null"} + } + yyVAL.union = yyLOCAL + case 1209: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.JSONTableResponse +//line mysql_sql.y:8505 + { + yyLOCAL = &tree.JSONTableResponse{Action: "error"} + } + yyVAL.union = yyLOCAL + case 1210: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.JSONTableResponse +//line mysql_sql.y:8507 + { + yyLOCAL = &tree.JSONTableResponse{Action: "default", Default: yyDollar[2].str} + } + yyVAL.union = yyLOCAL + case 1211: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.JSONTableColumn +//line mysql_sql.y:8510 + { + yyLOCAL = &tree.JSONTableColumn{} + } + yyVAL.union = yyLOCAL + case 1212: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.JSONTableColumn +//line mysql_sql.y:8512 + { + yyLOCAL = &tree.JSONTableColumn{OnEmpty: yyDollar[1].jsonTableResponseUnion(), OnError: yyDollar[4].jsonTableResponseUnion()} + } + yyVAL.union = yyLOCAL + case 1213: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.JSONTableColumn +//line mysql_sql.y:8514 + { + yyLOCAL = &tree.JSONTableColumn{OnEmpty: yyDollar[4].jsonTableResponseUnion(), OnError: yyDollar[1].jsonTableResponseUnion(), ReversePolicies: yyDollar[4].jsonTableResponseUnion() != nil} + } + yyVAL.union = yyLOCAL + case 1214: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.JSONTableResponse +//line mysql_sql.y:8517 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1215: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.JSONTableResponse +//line mysql_sql.y:8519 + { + yyLOCAL = yyDollar[1].jsonTableResponseUnion() + } + yyVAL.union = yyLOCAL + case 1216: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.JSONTableResponse +//line mysql_sql.y:8522 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1217: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.JSONTableResponse +//line mysql_sql.y:8524 + { + yyLOCAL = yyDollar[1].jsonTableResponseUnion() + } + yyVAL.union = yyLOCAL + case 1218: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.AliasedTableExpr +//line mysql_sql.y:8528 + { + yyLOCAL = &tree.AliasedTableExpr{ + Expr: yyDollar[1].tableNameUnion(), + As: tree.AliasClause{ + Alias: tree.Identifier(yyDollar[2].str), + }, + IndexHints: yyDollar[3].indexHintListUnion(), + } + } + yyVAL.union = yyLOCAL + case 1219: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []*tree.IndexHint +//line mysql_sql.y:8539 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1221: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.IndexHint +//line mysql_sql.y:8546 + { + yyLOCAL = []*tree.IndexHint{yyDollar[1].indexHintUnion()} + } + yyVAL.union = yyLOCAL + case 1222: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []*tree.IndexHint +//line mysql_sql.y:8550 + { + yyLOCAL = append(yyDollar[1].indexHintListUnion(), yyDollar[2].indexHintUnion()) + } + yyVAL.union = yyLOCAL + case 1223: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.IndexHint +//line mysql_sql.y:8556 + { + yyLOCAL = &tree.IndexHint{ + IndexNames: yyDollar[4].strsUnion(), + HintType: yyDollar[1].indexHintTypeUnion(), + HintScope: yyDollar[2].indexHintScopeUnion(), + } + } + yyVAL.union = yyLOCAL + case 1224: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexHintType +//line mysql_sql.y:8566 + { + yyLOCAL = tree.HintUse + } + yyVAL.union = yyLOCAL + case 1225: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexHintType +//line mysql_sql.y:8570 + { + yyLOCAL = tree.HintIgnore + } + yyVAL.union = yyLOCAL + case 1226: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexHintType +//line mysql_sql.y:8574 + { + yyLOCAL = tree.HintForce + } + yyVAL.union = yyLOCAL + case 1227: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.IndexHintScope +//line mysql_sql.y:8579 + { + yyLOCAL = tree.HintForScan + } + yyVAL.union = yyLOCAL + case 1228: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexHintScope +//line mysql_sql.y:8583 + { + yyLOCAL = tree.HintForJoin + } + yyVAL.union = yyLOCAL + case 1229: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IndexHintScope +//line mysql_sql.y:8587 + { + yyLOCAL = tree.HintForOrderBy + } + yyVAL.union = yyLOCAL + case 1230: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IndexHintScope +//line mysql_sql.y:8591 + { + yyLOCAL = tree.HintForGroupBy + } + yyVAL.union = yyLOCAL + case 1231: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:8596 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1232: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:8600 + { + yyLOCAL = []string{yyDollar[1].cstrUnion().Compare()} + } + yyVAL.union = yyLOCAL + case 1233: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:8604 + { + yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].cstrUnion().Compare()) + } + yyVAL.union = yyLOCAL + case 1234: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:8608 + { + yyLOCAL = []string{yyDollar[1].str} + } + yyVAL.union = yyLOCAL + case 1235: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:8612 + { + yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1236: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:8618 + { + yyVAL.str = "" + } + case 1237: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:8622 + { + yyVAL.str = yyDollar[1].str + } + case 1238: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8626 + { + yyVAL.str = yyDollar[2].str + } + case 1239: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:8632 + { + yyVAL.str = yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + } + case 1240: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:8636 + { + yyVAL.str = yylex.(*Lexer).GetDbOrTblName(yyDollar[1].str) + } + case 1241: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:8642 + { + yyLOCAL = tree.NewCStr("", 1) + } + yyVAL.union = yyLOCAL + case 1242: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:8646 + { + yyLOCAL = yyDollar[1].cstrUnion() + } + yyVAL.union = yyLOCAL + case 1243: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:8650 + { + yyLOCAL = yyDollar[2].cstrUnion() + } + yyVAL.union = yyLOCAL + case 1244: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:8654 + { + yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) + } + yyVAL.union = yyLOCAL + case 1245: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:8658 + { + yyLOCAL = tree.NewCStr(yyDollar[2].str, 1) + } + yyVAL.union = yyLOCAL + case 1246: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:8664 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1270: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:8707 + { + yyLOCAL = &tree.CreateIcebergCatalog{ + IfNotExists: yyDollar[4].ifNotExistsUnion(), + Name: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + Options: yyDollar[6].icebergOptionsUnion(), + } + } + yyVAL.union = yyLOCAL + case 1271: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:8717 + { + yyLOCAL = &tree.CreateMongoDBConnection{ + IfNotExists: yyDollar[4].ifNotExistsUnion(), + Name: tree.Identifier(yyDollar[5].cstrUnion().Compare()), + Options: yyDollar[6].mongodbOptionsUnion(), + } + } + yyVAL.union = yyLOCAL + case 1272: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:8727 + { + cronExpr := "" + timezone := "" + if yyDollar[5].sqlTaskScheduleUnion() != nil { + cronExpr = yyDollar[5].sqlTaskScheduleUnion().CronExpr + timezone = yyDollar[5].sqlTaskScheduleUnion().Timezone + } + yyLOCAL = &tree.CreateSQLTask{ + IfNotExists: yyDollar[3].ifNotExistsUnion(), + Name: tree.Identifier(yyDollar[4].cstrUnion().Compare()), + CronExpr: cronExpr, + Timezone: timezone, + GateCondition: sqlTaskNodeString(yyDollar[6].exprUnion()), + RetryLimit: yyDollar[7].int64ValUnion(), + Timeout: yyDollar[8].str, + SQLBody: sqlTaskBodyString(yyDollar[10].statementUnion()), + } + } + yyVAL.union = yyLOCAL + case 1273: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.SQLTaskSchedule +//line mysql_sql.y:8747 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1274: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.SQLTaskSchedule +//line mysql_sql.y:8751 + { + yyLOCAL = &tree.SQLTaskSchedule{ + CronExpr: yyDollar[2].str, + Timezone: yyDollar[3].str, + } + } + yyVAL.union = yyLOCAL + case 1275: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:8759 + { + yyVAL.str = "" + } + case 1276: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8763 + { + yyVAL.str = yyDollar[2].str + } + case 1277: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:8768 + { + yyLOCAL = tree.Expr(nil) + } + yyVAL.union = yyLOCAL + case 1278: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:8772 + { + yyLOCAL = yyDollar[3].exprUnion() + } + yyVAL.union = yyLOCAL + case 1279: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:8778 + { + yyLOCAL = yyDollar[1].exprUnion() + } + yyVAL.union = yyLOCAL + case 1280: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:8782 + { + yyLOCAL = tree.NewSubquery(yyDollar[1].selectUnion(), false) + } + yyVAL.union = yyLOCAL + case 1281: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:8787 + { + yyLOCAL = 0 + } + yyVAL.union = yyLOCAL + case 1282: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:8791 + { + yyLOCAL = sqlTaskInt64(yyDollar[2].item) + } + yyVAL.union = yyLOCAL + case 1283: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:8796 + { + yyVAL.str = "" + } + case 1284: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8800 + { + yyVAL.str = yyDollar[2].str + } + case 1285: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:8806 + { + var Language = yyDollar[3].str + var Name = tree.Identifier(yyDollar[5].str) + var Filename = tree.Identifier(yyDollar[7].str) + yyLOCAL = tree.NewCreateExtension( + Language, + Name, + Filename, + ) + } + yyVAL.union = yyLOCAL + case 1286: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:8819 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1287: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:8825 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1288: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:8831 + { + yyLOCAL = tree.NewCreateProcedure( + yyDollar[2].sourceOptionalUnion(), yyDollar[4].procNameUnion(), yyDollar[6].procArgsUnion(), yyDollar[8].str, yyDollar[9].str, + ) + } + yyVAL.union = yyLOCAL + case 1289: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.ProcedureName +//line mysql_sql.y:8839 + { + prefix := tree.ObjectNamePrefix{ExplicitSchema: false} + yyLOCAL = tree.NewProcedureName(tree.Identifier(yyDollar[1].cstrUnion().Compare()), prefix) + } + yyVAL.union = yyLOCAL + case 1290: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.ProcedureName +//line mysql_sql.y:8844 + { + dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + prefix := tree.ObjectNamePrefix{SchemaName: tree.Identifier(dbName), ExplicitSchema: true} + yyLOCAL = tree.NewProcedureName(tree.Identifier(yyDollar[3].cstrUnion().Compare()), prefix) + } + yyVAL.union = yyLOCAL + case 1291: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.ProcedureArgs +//line mysql_sql.y:8851 + { + yyLOCAL = tree.ProcedureArgs(nil) + } + yyVAL.union = yyLOCAL + case 1293: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ProcedureArgs +//line mysql_sql.y:8858 + { + yyLOCAL = tree.ProcedureArgs{yyDollar[1].procArgUnion()} + } + yyVAL.union = yyLOCAL + case 1294: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.ProcedureArgs +//line mysql_sql.y:8862 + { + yyLOCAL = append(yyDollar[1].procArgsUnion(), yyDollar[3].procArgUnion()) + } + yyVAL.union = yyLOCAL + case 1295: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ProcedureArg +//line mysql_sql.y:8868 + { + yyLOCAL = tree.ProcedureArg(yyDollar[1].procArgDeclUnion()) + } + yyVAL.union = yyLOCAL + case 1296: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.ProcedureArgDecl +//line mysql_sql.y:8874 + { + yyLOCAL = tree.NewProcedureArgDecl(yyDollar[1].procArgTypeUnion(), yyDollar[2].unresolvedNameUnion(), yyDollar[3].columnTypeUnion()) + } + yyVAL.union = yyLOCAL + case 1297: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.InOutArgType +//line mysql_sql.y:8879 + { + yyLOCAL = tree.TYPE_IN + } + yyVAL.union = yyLOCAL + case 1298: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.InOutArgType +//line mysql_sql.y:8883 + { + yyLOCAL = tree.TYPE_IN + } + yyVAL.union = yyLOCAL + case 1299: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.InOutArgType +//line mysql_sql.y:8887 + { + yyLOCAL = tree.TYPE_OUT + } + yyVAL.union = yyLOCAL + case 1300: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.InOutArgType +//line mysql_sql.y:8891 + { + yyLOCAL = tree.TYPE_INOUT + } + yyVAL.union = yyLOCAL + case 1301: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:8896 + { + yyVAL.str = "sql" + } + case 1302: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:8900 + { + yyVAL.str = yyDollar[2].str + } + case 1303: + yyDollar = yyS[yypt-15 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:8906 + { + if yyDollar[13].str == "" { + yylex.Error("no function body error") + goto ret1 + } + if yyDollar[11].str == "python" && yyDollar[14].str == "" { + yylex.Error("no handler error") + goto ret1 + } + + var Replace = yyDollar[2].sourceOptionalUnion() + var Name = yyDollar[4].functionNameUnion() + var Args = yyDollar[6].funcArgsUnion() + var ReturnType = yyDollar[9].funcReturnUnion() + var Language = yyDollar[11].str + var Import = yyDollar[12].boolValUnion() + var Body = yyDollar[13].str + var Handler = yyDollar[14].str + var Options = yyDollar[15].pythonFunctionOptionsUnion() + + node := tree.NewCreateFunction( + Replace, + Name, + Args, + ReturnType, + Language, + Import, + Body, + Handler, + ) + node.Mode = Options.Mode + node.NullPolicy = Options.NullPolicy + yyLOCAL = node + } + yyVAL.union = yyLOCAL + case 1304: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.FunctionName +//line mysql_sql.y:8943 + { + prefix := tree.ObjectNamePrefix{ExplicitSchema: false} + yyLOCAL = tree.NewFuncName(tree.Identifier(yyDollar[1].cstrUnion().Compare()), prefix) + } + yyVAL.union = yyLOCAL + case 1305: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.FunctionName +//line mysql_sql.y:8948 + { + dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + prefix := tree.ObjectNamePrefix{SchemaName: tree.Identifier(dbName), ExplicitSchema: true} + yyLOCAL = tree.NewFuncName(tree.Identifier(yyDollar[3].cstrUnion().Compare()), prefix) + } + yyVAL.union = yyLOCAL + case 1306: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.FunctionArgs +//line mysql_sql.y:8955 + { + yyLOCAL = tree.FunctionArgs(nil) + } + yyVAL.union = yyLOCAL + case 1308: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FunctionArgs +//line mysql_sql.y:8962 + { + yyLOCAL = tree.FunctionArgs{yyDollar[1].funcArgUnion()} + } + yyVAL.union = yyLOCAL + case 1309: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.FunctionArgs +//line mysql_sql.y:8966 + { + yyLOCAL = append(yyDollar[1].funcArgsUnion(), yyDollar[3].funcArgUnion()) + } + yyVAL.union = yyLOCAL + case 1310: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FunctionArg +//line mysql_sql.y:8972 + { + yyLOCAL = tree.FunctionArg(yyDollar[1].funcArgDeclUnion()) + } + yyVAL.union = yyLOCAL + case 1311: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.FunctionArgDecl +//line mysql_sql.y:8978 + { + yyLOCAL = tree.NewFunctionArgDecl(nil, yyDollar[1].columnTypeUnion(), nil) + } + yyVAL.union = yyLOCAL + case 1312: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FunctionArgDecl +//line mysql_sql.y:8982 + { + yyLOCAL = tree.NewFunctionArgDecl(yyDollar[1].unresolvedNameUnion(), yyDollar[2].columnTypeUnion(), nil) + } + yyVAL.union = yyLOCAL + case 1313: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FunctionArgDecl +//line mysql_sql.y:8986 + { + yyLOCAL = tree.NewFunctionArgDecl(yyDollar[1].unresolvedNameUnion(), yyDollar[2].columnTypeUnion(), yyDollar[4].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1314: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:8992 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1315: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.ReturnType +//line mysql_sql.y:8998 + { + yyLOCAL = tree.NewReturnType(yyDollar[1].columnTypeUnion()) + } + yyVAL.union = yyLOCAL + case 1316: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:9004 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1317: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:9008 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1318: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:9013 + { + yyVAL.str = "" + } + case 1320: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:9020 + { + yyVAL.str = yyDollar[2].str + } + case 1321: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.PythonFunctionOptions +//line mysql_sql.y:9025 + { + yyLOCAL = tree.PythonFunctionOptions{} + } + yyVAL.union = yyLOCAL + case 1322: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.PythonFunctionOptions +//line mysql_sql.y:9029 + { + yyLOCAL = tree.PythonFunctionOptions{Mode: yyDollar[2].str} + } + yyVAL.union = yyLOCAL + case 1323: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.PythonFunctionOptions +//line mysql_sql.y:9033 + { + yyLOCAL = tree.PythonFunctionOptions{NullPolicy: yyDollar[1].str} + } + yyVAL.union = yyLOCAL + case 1324: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.PythonFunctionOptions +//line mysql_sql.y:9037 + { + yyLOCAL = tree.PythonFunctionOptions{Mode: yyDollar[2].str, NullPolicy: yyDollar[3].str} + } + yyVAL.union = yyLOCAL + case 1325: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.PythonFunctionOptions +//line mysql_sql.y:9041 + { + yyLOCAL = tree.PythonFunctionOptions{Mode: yyDollar[3].str, NullPolicy: yyDollar[1].str} + } + yyVAL.union = yyLOCAL + case 1326: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:9047 + { + yyVAL.str = "SCALAR" + } + case 1327: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:9051 + { + yyVAL.str = "VECTOR" + } + case 1328: + yyDollar = yyS[yypt-4 : yypt+1] +//line mysql_sql.y:9057 + { + yyVAL.str = "CALLED_ON_NULL_INPUT" + } + case 1329: + yyDollar = yyS[yypt-5 : yypt+1] +//line mysql_sql.y:9061 + { + yyVAL.str = "RETURNS_NULL_ON_NULL_INPUT" + } + case 1330: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9067 + { + var Replace bool + var Name = yyDollar[5].tableNameUnion() + var ColNames = yyDollar[6].identifierListUnion() + var AsSource = yyDollar[8].selectUnion() + var IfNotExists = yyDollar[4].ifNotExistsUnion() + var CheckOption = yyDollar[9].str + if intoErr := tree.ValidateSelectIntoNotAllowed(AsSource); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = tree.NewCreateView( + Replace, + Name, + ColNames, + AsSource, + IfNotExists, CheckOption, + ) + } + yyVAL.union = yyLOCAL + case 1331: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9086 + { + var Replace = yyDollar[2].sourceOptionalUnion() + var Name = yyDollar[5].tableNameUnion() + var ColNames = yyDollar[6].identifierListUnion() + var AsSource = yyDollar[8].selectUnion() + var IfNotExists = yyDollar[4].ifNotExistsUnion() + var CheckOption = yyDollar[9].str + if intoErr := tree.ValidateSelectIntoNotAllowed(AsSource); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + yyLOCAL = tree.NewCreateView( + Replace, + Name, + ColNames, + AsSource, + IfNotExists, CheckOption, + ) + } + yyVAL.union = yyLOCAL + case 1332: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9107 + { + var IfNotExists = yyDollar[3].ifNotExistsUnion() + var Name = yyDollar[4].exprUnion() + var AuthOption = yyDollar[5].accountAuthOptionUnion() + var StatusOption = yyDollar[6].accountStatusUnion() + var Comment = yyDollar[7].accountCommentUnion() + yyLOCAL = tree.NewCreateAccount( + IfNotExists, + Name, + AuthOption, + StatusOption, + Comment, + ) + } + yyVAL.union = yyLOCAL + case 1333: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9122 + { + var FromUri = yyDollar[4].str + var SubscriptionAccountName = yyDollar[5].cstrUnion().Compare() + var PubName = tree.Identifier(yyDollar[7].cstrUnion().Compare()) + var SyncInterval = yyDollar[8].int64ValUnion() + var cs = tree.NewCreateSubscription( + true, // isDatabase + tree.Identifier(""), // dbName (empty for account level) + "", // tableName + FromUri, + SubscriptionAccountName, + PubName, + SyncInterval, + ) + yyLOCAL = cs + } + yyVAL.union = yyLOCAL + case 1334: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:9141 + { + yyVAL.str = yyDollar[1].str + } + case 1335: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:9145 + { + yyVAL.str = yyVAL.str + yyDollar[2].str + } + case 1336: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:9151 + { + yyVAL.str = "ALGORITHM = " + yyDollar[3].str + } + case 1337: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:9155 + { + yyVAL.str = "DEFINER = " + } + case 1338: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:9159 + { + yyVAL.str = "SQL SECURITY " + yyDollar[3].str + } + case 1339: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:9164 + { + yyVAL.str = "NONE" + } + case 1340: + yyDollar = yyS[yypt-4 : yypt+1] +//line mysql_sql.y:9168 + { + yyVAL.str = yyDollar[2].str + if yyVAL.str == "" { + yyVAL.str = "CASCADED" + } + } + case 1346: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:9182 + { + yyVAL.str = "" + } + case 1349: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:9190 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1350: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:9196 + { + var str = yyDollar[1].cstrUnion().Compare() + yyLOCAL = tree.NewNumVal(str, str, false, tree.P_char) + } + yyVAL.union = yyLOCAL + case 1351: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:9201 + { + yyLOCAL = tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()) + } + yyVAL.union = yyLOCAL + case 1352: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.AccountAuthOption +//line mysql_sql.y:9207 + { + var Equal = yyDollar[2].str + var AdminName = yyDollar[3].exprUnion() + var IdentifiedType = yyDollar[4].accountIdentifiedUnion() + yyLOCAL = *tree.NewAccountAuthOption( + Equal, + AdminName, + IdentifiedType, + ) + } + yyVAL.union = yyLOCAL + case 1353: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:9220 + { + var str = yyDollar[1].str + yyLOCAL = tree.NewNumVal(str, str, false, tree.P_char) + } + yyVAL.union = yyLOCAL + case 1354: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:9225 + { + var str = yyDollar[1].cstrUnion().Compare() + yyLOCAL = tree.NewNumVal(str, str, false, tree.P_char) + } + yyVAL.union = yyLOCAL + case 1355: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:9230 + { + yyLOCAL = tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()) + } + yyVAL.union = yyLOCAL + case 1356: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AccountIdentified +//line mysql_sql.y:9236 + { + yyLOCAL = *tree.NewAccountIdentified( + tree.AccountIdentifiedByPassword, + tree.NewNumVal(yyDollar[3].str, yyDollar[3].str, false, tree.P_char), + ) + } + yyVAL.union = yyLOCAL + case 1357: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AccountIdentified +//line mysql_sql.y:9243 + { + yyLOCAL = *tree.NewAccountIdentified( + tree.AccountIdentifiedByPassword, + tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()), + ) + } + yyVAL.union = yyLOCAL + case 1358: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.AccountIdentified +//line mysql_sql.y:9250 + { + yyLOCAL = *tree.NewAccountIdentified( + tree.AccountIdentifiedByRandomPassword, + nil, + ) + } + yyVAL.union = yyLOCAL + case 1359: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AccountIdentified +//line mysql_sql.y:9257 + { + yyLOCAL = *tree.NewAccountIdentified( + tree.AccountIdentifiedWithSSL, + tree.NewNumVal(yyDollar[3].str, yyDollar[3].str, false, tree.P_char), + ) + } + yyVAL.union = yyLOCAL + case 1360: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AccountIdentified +//line mysql_sql.y:9264 + { + yyLOCAL = *tree.NewAccountIdentified( + tree.AccountIdentifiedWithSSL, + tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()), + ) + } + yyVAL.union = yyLOCAL + case 1361: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.AccountStatus +//line mysql_sql.y:9272 + { + as := tree.NewAccountStatus() + as.Exist = false + yyLOCAL = *as + } + yyVAL.union = yyLOCAL + case 1362: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.AccountStatus +//line mysql_sql.y:9278 + { + as := tree.NewAccountStatus() + as.Exist = true + as.Option = tree.AccountStatusOpen + yyLOCAL = *as + } + yyVAL.union = yyLOCAL + case 1363: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.AccountStatus +//line mysql_sql.y:9285 + { + as := tree.NewAccountStatus() + as.Exist = true + as.Option = tree.AccountStatusSuspend + yyLOCAL = *as + } + yyVAL.union = yyLOCAL + case 1364: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.AccountStatus +//line mysql_sql.y:9292 + { + as := tree.NewAccountStatus() + as.Exist = true + as.Option = tree.AccountStatusRestricted + yyLOCAL = *as + } + yyVAL.union = yyLOCAL + case 1365: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.AccountComment +//line mysql_sql.y:9300 + { + ac := tree.NewAccountComment() + ac.Exist = false + yyLOCAL = *ac + } + yyVAL.union = yyLOCAL + case 1366: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AccountComment +//line mysql_sql.y:9306 + { + ac := tree.NewAccountComment() + ac.Exist = true + ac.Comment = yyDollar[2].str + yyLOCAL = *ac + } + yyVAL.union = yyLOCAL + case 1367: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9315 + { + var IfNotExists = yyDollar[3].ifNotExistsUnion() + var Users = yyDollar[4].usersUnion() + var Role = yyDollar[5].accountRoleUnion() + var MiscOpt = yyDollar[6].userMiscOptionUnion() + var CommentOrAttribute = yyDollar[7].accountCommentOrAttributeUnion() + yyLOCAL = tree.NewCreateUser( + IfNotExists, + Users, + Role, + MiscOpt, + CommentOrAttribute, + ) + } + yyVAL.union = yyLOCAL + case 1368: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9332 + { + var IfNotExists = yyDollar[3].ifNotExistsUnion() + var Name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + var Database = tree.Identifier(yyDollar[6].str) + var AccountsSet = yyDollar[7].accountsSetOptionUnion() + var Comment = yyDollar[8].str + yyLOCAL = tree.NewCreatePublication( + IfNotExists, + Name, + Database, + nil, + AccountsSet, + Comment, + ) + } + yyVAL.union = yyLOCAL + case 1369: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9348 + { + var IfNotExists = yyDollar[3].ifNotExistsUnion() + var Name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + var Database = tree.Identifier(yyDollar[6].str) + var Table = yyDollar[8].tableNamesUnion() + var AccountsSet = yyDollar[9].accountsSetOptionUnion() + var Comment = yyDollar[10].str + yyLOCAL = tree.NewCreatePublication( + IfNotExists, + Name, + Database, + Table, + AccountsSet, + Comment, + ) + } + yyVAL.union = yyLOCAL + case 1370: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9365 + { + var IfNotExists = yyDollar[3].ifNotExistsUnion() + var Name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + var Database = tree.Identifier("*") + var AccountsSet = yyDollar[7].accountsSetOptionUnion() + var Comment = yyDollar[8].str + yyLOCAL = tree.NewCreatePublication( + IfNotExists, + Name, + Database, + nil, + AccountsSet, + Comment, + ) + } + yyVAL.union = yyLOCAL + case 1371: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.AccountsSetOption +//line mysql_sql.y:9383 + { + yyLOCAL = &tree.AccountsSetOption{ + All: true, + } + } + yyVAL.union = yyLOCAL + case 1372: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.AccountsSetOption +//line mysql_sql.y:9389 + { + yyLOCAL = &tree.AccountsSetOption{ + SetAccounts: yyDollar[2].identifierListUnion(), + } + } + yyVAL.union = yyLOCAL + case 1373: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9397 + { + var IfNotExists = yyDollar[3].ifNotExistsUnion() + var Name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + var Url = yyDollar[5].str + var Credentials = yyDollar[6].stageCredentialsUnion() + var Status = yyDollar[7].stageStatusUnion() + var Comment = yyDollar[8].stageCommentUnion() + yyLOCAL = tree.NewCreateStage( + IfNotExists, + Name, + Url, + Credentials, + Status, + Comment, + ) + } + yyVAL.union = yyLOCAL + case 1374: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.StageStatus +//line mysql_sql.y:9415 + { + yyLOCAL = tree.StageStatus{ + Exist: false, + } + } + yyVAL.union = yyLOCAL + case 1375: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.StageStatus +//line mysql_sql.y:9421 + { + yyLOCAL = tree.StageStatus{ + Exist: true, + Option: tree.StageStatusEnabled, + } + } + yyVAL.union = yyLOCAL + case 1376: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.StageStatus +//line mysql_sql.y:9428 + { + yyLOCAL = tree.StageStatus{ + Exist: true, + Option: tree.StageStatusDisabled, + } + } + yyVAL.union = yyLOCAL + case 1377: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.StageComment +//line mysql_sql.y:9436 + { + yyLOCAL = tree.StageComment{ + Exist: false, + } + } + yyVAL.union = yyLOCAL + case 1378: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.StageComment +//line mysql_sql.y:9442 + { + yyLOCAL = tree.StageComment{ + Exist: true, + Comment: yyDollar[3].str, + } + } + yyVAL.union = yyLOCAL + case 1379: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:9451 + { + yyLOCAL = int64(0) + } + yyVAL.union = yyLOCAL + case 1380: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:9455 + { + switch v := yyDollar[3].item.(type) { + case int64: + yyLOCAL = v + case uint64: + yyLOCAL = int64(v) + default: + yyLOCAL = int64(0) + } + } + yyVAL.union = yyLOCAL + case 1381: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.StageUrl +//line mysql_sql.y:9467 + { + yyLOCAL = tree.StageUrl{ + Exist: false, + } + } + yyVAL.union = yyLOCAL + case 1382: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.StageUrl +//line mysql_sql.y:9473 + { + yyLOCAL = tree.StageUrl{ + Exist: true, + Url: yyDollar[3].str, + } + } + yyVAL.union = yyLOCAL + case 1383: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.StageCredentials +//line mysql_sql.y:9481 + { + yyLOCAL = tree.StageCredentials{ + Exist: false, + } + } + yyVAL.union = yyLOCAL + case 1384: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.StageCredentials +//line mysql_sql.y:9487 + { + yyLOCAL = tree.StageCredentials{ + Exist: true, + Credentials: yyDollar[4].strsUnion(), + } + } + yyVAL.union = yyLOCAL + case 1385: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:9496 + { + yyLOCAL = yyDollar[1].strsUnion() + } + yyVAL.union = yyLOCAL + case 1386: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:9500 + { + yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].strsUnion()...) + } + yyVAL.union = yyLOCAL + case 1387: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:9505 + { + yyLOCAL = []string{} + } + yyVAL.union = yyLOCAL + case 1388: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:9509 + { + yyLOCAL = append(yyLOCAL, yyDollar[1].str) + yyLOCAL = append(yyLOCAL, yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1389: + yyDollar = yyS[yypt-3 : yypt+1] +//line mysql_sql.y:9516 + { + yyVAL.str = yyDollar[3].str + } + case 1390: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:9521 + { + yyVAL.str = "" + } + case 1391: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:9525 + { + yyVAL.str = yyDollar[2].str + } + case 1392: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9531 + { + var ifNotExists = yyDollar[3].boolValUnion() + var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + var urlOption = yyDollar[6].stageUrlUnion() + var credentialsOption = yyDollar[7].stageCredentialsUnion() + var statusOption = yyDollar[8].stageStatusUnion() + var comment = yyDollar[9].stageCommentUnion() + yyLOCAL = tree.NewAlterStage(ifNotExists, name, urlOption, credentialsOption, statusOption, comment) + } + yyVAL.union = yyLOCAL + case 1393: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9543 + { + var ifExists = yyDollar[3].boolValUnion() + var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + var accountsSet = yyDollar[5].accountsSetOptionUnion() + var dbName = yyDollar[6].str + var table = yyDollar[7].tableNamesUnion() + var comment = yyDollar[8].str + yyLOCAL = tree.NewAlterPublication(ifExists, name, accountsSet, dbName, table, comment) + } + yyVAL.union = yyLOCAL + case 1394: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.AccountsSetOption +//line mysql_sql.y:9554 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1395: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.AccountsSetOption +//line mysql_sql.y:9558 + { + yyLOCAL = &tree.AccountsSetOption{ + All: true, + } + } + yyVAL.union = yyLOCAL + case 1396: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.AccountsSetOption +//line mysql_sql.y:9564 + { + yyLOCAL = &tree.AccountsSetOption{ + SetAccounts: yyDollar[2].identifierListUnion(), + } + } + yyVAL.union = yyLOCAL + case 1397: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.AccountsSetOption +//line mysql_sql.y:9570 + { + yyLOCAL = &tree.AccountsSetOption{ + AddAccounts: yyDollar[3].identifierListUnion(), + } + } + yyVAL.union = yyLOCAL + case 1398: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.AccountsSetOption +//line mysql_sql.y:9576 + { + yyLOCAL = &tree.AccountsSetOption{ + DropAccounts: yyDollar[3].identifierListUnion(), + } + } + yyVAL.union = yyLOCAL + case 1399: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:9583 + { + yyVAL.str = "" + } + case 1400: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:9587 + { + yyVAL.str = yyDollar[2].str + } + case 1401: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.TableNames +//line mysql_sql.y:9592 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1402: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.TableNames +//line mysql_sql.y:9596 + { + yyLOCAL = yyDollar[2].tableNamesUnion() + } + yyVAL.union = yyLOCAL + case 1403: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9602 + { + var ifExists = yyDollar[3].boolValUnion() + var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + yyLOCAL = tree.NewDropPublication(ifExists, name) + } + yyVAL.union = yyLOCAL + case 1404: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9610 + { + var ifExists = yyDollar[4].boolValUnion() + var taskID = yyDollar[5].str + yyLOCAL = tree.NewDropCcprSubscription(ifExists, taskID) + } + yyVAL.union = yyLOCAL + case 1405: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9618 + { + var taskID = yyDollar[4].str + yyLOCAL = tree.NewResumeCcprSubscription(taskID) + } + yyVAL.union = yyLOCAL + case 1406: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9625 + { + var taskID = yyDollar[4].str + yyLOCAL = tree.NewPauseCcprSubscription(taskID) + } + yyVAL.union = yyLOCAL + case 1407: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9632 + { + var ifNotExists = yyDollar[3].boolValUnion() + var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + yyLOCAL = tree.NewDropStage(ifNotExists, name) + } + yyVAL.union = yyLOCAL + case 1408: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9640 + { + var ifExists = yyDollar[5].boolValUnion() + var path = yyDollar[6].str + yyLOCAL = tree.NewRemoveStageFiles(ifExists, path) + } + yyVAL.union = yyLOCAL + case 1409: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9648 + { + var ifExists = yyDollar[3].boolValUnion() + var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + yyLOCAL = tree.NewDropSnapShot(ifExists, name, "", "") + } + yyVAL.union = yyLOCAL + case 1410: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9654 + { + var ifExists = yyDollar[3].boolValUnion() + var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + var accountName = tree.Identifier(yyDollar[6].cstrUnion().Compare()) + var pubName = tree.Identifier(yyDollar[8].cstrUnion().Compare()) + yyLOCAL = tree.NewDropSnapShot(ifExists, name, accountName, pubName) + } + yyVAL.union = yyLOCAL + case 1411: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9664 + { + var ifExists = yyDollar[3].boolValUnion() + var name = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + yyLOCAL = &tree.DropPitr{ + IfExists: ifExists, + Name: name, + Internal: yyDollar[5].boolValUnion(), + } + + } + yyVAL.union = yyLOCAL + case 1412: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:9677 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1413: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.AccountCommentOrAttribute +//line mysql_sql.y:9682 + { + var Exist = false + var IsComment bool + var Str string + yyLOCAL = *tree.NewAccountCommentOrAttribute( + Exist, + IsComment, + Str, + ) + + } + yyVAL.union = yyLOCAL + case 1414: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AccountCommentOrAttribute +//line mysql_sql.y:9694 + { + var Exist = true + var IsComment = true + var Str = yyDollar[2].str + yyLOCAL = *tree.NewAccountCommentOrAttribute( + Exist, + IsComment, + Str, + ) + } + yyVAL.union = yyLOCAL + case 1415: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.AccountCommentOrAttribute +//line mysql_sql.y:9705 + { + var Exist = true + var IsComment = false + var Str = yyDollar[2].str + yyLOCAL = *tree.NewAccountCommentOrAttribute( + Exist, + IsComment, + Str, + ) + } + yyVAL.union = yyLOCAL + case 1416: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.User +//line mysql_sql.y:9813 + { + yyLOCAL = []*tree.User{yyDollar[1].userUnion()} + } + yyVAL.union = yyLOCAL + case 1417: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.User +//line mysql_sql.y:9817 + { + yyLOCAL = append(yyDollar[1].usersUnion(), yyDollar[3].userUnion()) + } + yyVAL.union = yyLOCAL + case 1418: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.User +//line mysql_sql.y:9823 + { + var Username = yyDollar[1].usernameRecordUnion().Username + var Hostname = yyDollar[1].usernameRecordUnion().Hostname + var AuthOption = yyDollar[2].userIdentifiedUnion() + yyLOCAL = tree.NewUser( + Username, + Hostname, + AuthOption, + ) + } + yyVAL.union = yyLOCAL + case 1419: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.User +//line mysql_sql.y:9836 + { + yyLOCAL = []*tree.User{yyDollar[1].userUnion()} + } + yyVAL.union = yyLOCAL + case 1420: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.User +//line mysql_sql.y:9840 + { + yyLOCAL = append(yyDollar[1].usersUnion(), yyDollar[3].userUnion()) + } + yyVAL.union = yyLOCAL + case 1421: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.User +//line mysql_sql.y:9846 + { + var Username = yyDollar[1].usernameRecordUnion().Username + var Hostname = yyDollar[1].usernameRecordUnion().Hostname + var AuthOption = yyDollar[2].userIdentifiedUnion() + yyLOCAL = tree.NewUser( + Username, + Hostname, + AuthOption, + ) + } + yyVAL.union = yyLOCAL + case 1422: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.UsernameRecord +//line mysql_sql.y:9859 + { + yyLOCAL = &tree.UsernameRecord{Username: yyDollar[1].str, Hostname: "%"} + } + yyVAL.union = yyLOCAL + case 1423: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.UsernameRecord +//line mysql_sql.y:9863 + { + yyLOCAL = &tree.UsernameRecord{Username: yyDollar[1].str, Hostname: yyDollar[3].str} + } + yyVAL.union = yyLOCAL + case 1424: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.UsernameRecord +//line mysql_sql.y:9867 + { + yyLOCAL = &tree.UsernameRecord{Username: yyDollar[1].str, Hostname: yyDollar[2].str} + } + yyVAL.union = yyLOCAL + case 1425: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.AccountIdentified +//line mysql_sql.y:9872 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1426: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.AccountIdentified +//line mysql_sql.y:9876 + { + yyLOCAL = yyDollar[1].userIdentifiedUnion() + } + yyVAL.union = yyLOCAL + case 1427: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.AccountIdentified +//line mysql_sql.y:9882 + { + yyLOCAL = &tree.AccountIdentified{ + Typ: tree.AccountIdentifiedByPassword, + Str: tree.NewNumVal(yyDollar[3].str, yyDollar[3].str, false, tree.P_char), + } + } + yyVAL.union = yyLOCAL + case 1428: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.AccountIdentified +//line mysql_sql.y:9889 + { + yyLOCAL = &tree.AccountIdentified{ + Typ: tree.AccountIdentifiedByRandomPassword, + } + } + yyVAL.union = yyLOCAL + case 1429: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.AccountIdentified +//line mysql_sql.y:9895 + { + yyLOCAL = &tree.AccountIdentified{ + Typ: tree.AccountIdentifiedWithSSL, + Str: tree.NewNumVal(yyDollar[3].str, yyDollar[3].str, false, tree.P_char), + } + } + yyVAL.union = yyLOCAL + case 1430: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:9904 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1432: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9911 + { + var IfNotExists = yyDollar[3].ifNotExistsUnion() + var Roles = yyDollar[4].rolesUnion() + yyLOCAL = tree.NewCreateRole( + IfNotExists, + Roles, + ) + } + yyVAL.union = yyLOCAL + case 1433: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.Role +//line mysql_sql.y:9922 + { + yyLOCAL = []*tree.Role{yyDollar[1].roleUnion()} + } + yyVAL.union = yyLOCAL + case 1434: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.Role +//line mysql_sql.y:9926 + { + yyLOCAL = append(yyDollar[1].rolesUnion(), yyDollar[3].roleUnion()) + } + yyVAL.union = yyLOCAL + case 1435: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Role +//line mysql_sql.y:9932 + { + var UserName = yyDollar[1].cstrUnion().Compare() + yyLOCAL = tree.NewRole( + UserName, + ) + } + yyVAL.union = yyLOCAL + case 1436: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:9941 + { + yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) + } + yyVAL.union = yyLOCAL + case 1437: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:9945 + { + yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) + } + yyVAL.union = yyLOCAL + case 1438: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:9949 + { + yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) + } + yyVAL.union = yyLOCAL + case 1439: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:9953 + { + yyLOCAL = tree.NewCStr("lag", 1) + } + yyVAL.union = yyLOCAL + case 1440: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:9957 + { + yyLOCAL = tree.NewCStr("lead", 1) + } + yyVAL.union = yyLOCAL + case 1441: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:9961 + { + yyLOCAL = tree.NewCStr("first_value", 1) + } + yyVAL.union = yyLOCAL + case 1442: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:9965 + { + yyLOCAL = tree.NewCStr("last_value", 1) + } + yyVAL.union = yyLOCAL + case 1443: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:9969 + { + yyLOCAL = tree.NewCStr("nth_value", 1) + } + yyVAL.union = yyLOCAL + case 1444: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.IndexCategory +//line mysql_sql.y:9974 + { + yyLOCAL = tree.INDEX_CATEGORY_NONE + } + yyVAL.union = yyLOCAL + case 1445: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IndexCategory +//line mysql_sql.y:9978 + { + yyLOCAL = tree.INDEX_CATEGORY_FULLTEXT + } + yyVAL.union = yyLOCAL + case 1446: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IndexCategory +//line mysql_sql.y:9982 + { + yyLOCAL = tree.INDEX_CATEGORY_FULLTEXT2 + } + yyVAL.union = yyLOCAL + case 1447: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IndexCategory +//line mysql_sql.y:9986 + { + yyLOCAL = tree.INDEX_CATEGORY_SPATIAL + } + yyVAL.union = yyLOCAL + case 1448: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IndexCategory +//line mysql_sql.y:9990 + { + yyLOCAL = tree.INDEX_CATEGORY_UNIQUE + } + yyVAL.union = yyLOCAL + case 1449: + yyDollar = yyS[yypt-11 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:9996 + { + io := yyDollar[11].indexOptionUnion() + if io == nil { + io = tree.NewIndexOption() + } + // MySQL permits the index type before ON or after the key parts. + // When both forms are present, the trailing type takes precedence. + if io.IType == tree.INDEX_TYPE_INVALID { + io.IType = yyDollar[5].indexTypeUnion() + } + var Name = tree.Identifier(yyDollar[4].cstrUnion().Origin()) + var Table = yyDollar[7].tableNameUnion() + var ifNotExists = false + var IndexCat = yyDollar[2].indexCategoryUnion() + var KeyParts = yyDollar[9].keyPartsUnion() + var IndexOption = io + var MiscOption []tree.MiscOption + yyLOCAL = tree.NewCreateIndex( + Name, + Table, + ifNotExists, + IndexCat, + KeyParts, + IndexOption, + MiscOption, + ) + } + yyVAL.union = yyLOCAL + case 1450: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10025 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1451: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10029 + { + yyLOCAL = mergeIndexOption(yyDollar[1].indexOptionUnion(), yyDollar[2].indexOptionUnion()) + } + yyVAL.union = yyLOCAL + case 1452: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10034 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1453: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10038 + { + yyLOCAL = mergeIndexOption(yyDollar[1].indexOptionUnion(), yyDollar[2].indexOptionUnion()) + } + yyVAL.union = yyLOCAL + case 1454: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10044 + { + yyLOCAL = yyDollar[1].indexOptionUnion() + } + yyVAL.union = yyLOCAL + case 1455: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10048 + { + io := tree.NewIndexOption() + io.IType = yyDollar[1].indexTypeUnion() + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1456: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10056 + { + io := tree.NewIndexOption() + io.KeyBlockSize = integralToUint64(yyDollar[3].item) + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1457: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10062 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("LISTS should be greater than 0") + return 1 + } + + io := tree.NewIndexOption() + io.AlgoParamList = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1458: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10075 + { + io := tree.NewIndexOption() + io.AlgoParamVectorOpType = yyDollar[2].str + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1459: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10081 + { + io := tree.NewIndexOption() + io.Comment = yyDollar[2].str + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1460: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10087 + { + io := tree.NewIndexOption() + io.ParserName = yyDollar[3].cstrUnion().Compare() + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1461: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10093 + { + io := tree.NewIndexOption() + io.Visible = tree.VISIBLE_TYPE_VISIBLE + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1462: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10099 + { + io := tree.NewIndexOption() + io.Visible = tree.VISIBLE_TYPE_INVISIBLE + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1463: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10105 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("M should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.AlgoParamM = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1464: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10117 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("EF_CONSTRUCTION should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.HnswEfConstruction = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1465: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10129 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("EF_SEARCH should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.HnswEfSearch = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1466: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10141 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("INTERMEDIATE_GRAPH_DEGREE should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.IntermediateGraphDegree = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1467: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10153 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("GRAPH_DEGREE should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.GraphDegree = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1468: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10165 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("GRAPH_DEGREE should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.ITopkSize = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1469: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10177 + { + io := tree.NewIndexOption() + io.IncludeColumns = yyDollar[3].unresolveNamesUnion() + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1470: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10183 + { + io := tree.NewIndexOption() + io.Quantization = yyDollar[2].str + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1471: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10189 + { + io := tree.NewIndexOption() + io.DistributionMode = yyDollar[2].str + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1472: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10195 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("M should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.BitsPerCode = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1473: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10207 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("KMEANS_TRAIN_PERCENT should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.KmeansTrainPercent = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1474: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10219 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("QUANTIZER_TRAIN_LIMIT should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.QuantizerTrainLimit = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1475: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10231 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("KMEANS_MAX_ITERATION should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.KmeansMaxIteration = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1476: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10243 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("MAX_INDEX_CAPACITY should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.MaxIndexCapacity = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1477: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10255 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val <= 0 { + yylex.Error("MAX_POSTINGS_CAPACITY should be greater than 0") + return 1 + } + io := tree.NewIndexOption() + io.MaxPostingsCapacity = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1478: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10267 + { + io := tree.NewIndexOption() + io.PositionFree = true + io.PositionFreeSet = true + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1479: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10274 + { + io := tree.NewIndexOption() + io.PositionFree = false + io.PositionFreeSet = true + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1480: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10281 + { + io := tree.NewIndexOption() + io.Async = true + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1481: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10287 + { + io := tree.NewIndexOption() + io.ForceSync = true + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1482: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10293 + { + io := tree.NewIndexOption() + io.Merge = true + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1483: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10299 + { + io := tree.NewIndexOption() + io.AutoUpdate = true + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1484: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10305 + { + io := tree.NewIndexOption() + io.AutoUpdate = false + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1485: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10311 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val < 0 { + yylex.Error("DAY should be greater than or equal to 0") + return 1 + } + io := tree.NewIndexOption() + io.Day = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1486: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10323 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val < 0 || val > 23 { + yylex.Error("HOUR should be between 0 and 23") + return 1 + } + io := tree.NewIndexOption() + io.Hour = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1487: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IndexOption +//line mysql_sql.y:10335 + { + val, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + if val < 0 { + yylex.Error("SECOND should be greater than or equal to 0") + return 1 + } + io := tree.NewIndexOption() + io.Second = val + yyLOCAL = io + } + yyVAL.union = yyLOCAL + case 1488: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.KeyPart +//line mysql_sql.y:10350 + { + yyLOCAL = []*tree.KeyPart{yyDollar[1].keyPartUnion()} + } + yyVAL.union = yyLOCAL + case 1489: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.KeyPart +//line mysql_sql.y:10354 + { + yyLOCAL = append(yyDollar[1].keyPartsUnion(), yyDollar[3].keyPartUnion()) + } + yyVAL.union = yyLOCAL + case 1490: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.KeyPart +//line mysql_sql.y:10360 + { + // Order is parsed but just ignored as MySQL dtree. + var ColName = yyDollar[1].unresolvedNameUnion() + var Length = int(yyDollar[2].lengthOptUnion()) + var Direction = yyDollar[3].directionUnion() + var Expr tree.Expr + yyLOCAL = tree.NewKeyPart( + ColName, + Length, + Direction, + Expr, + ) + } + yyVAL.union = yyLOCAL + case 1491: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.KeyPart +//line mysql_sql.y:10374 + { + var ColName *tree.UnresolvedName + var Length int + var Expr = yyDollar[2].exprUnion() + var Direction = yyDollar[4].directionUnion() + yyLOCAL = tree.NewKeyPart( + ColName, + Length, + Direction, + Expr, + ) + } + yyVAL.union = yyLOCAL + case 1492: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.IndexType +//line mysql_sql.y:10388 + { + yyLOCAL = tree.INDEX_TYPE_INVALID + } + yyVAL.union = yyLOCAL + case 1493: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IndexType +//line mysql_sql.y:10392 + { + yyLOCAL = yyDollar[1].indexTypeUnion() + } + yyVAL.union = yyLOCAL + case 1494: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexType +//line mysql_sql.y:10398 + { + yyLOCAL = tree.INDEX_TYPE_BTREE + } + yyVAL.union = yyLOCAL + case 1495: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexType +//line mysql_sql.y:10402 + { + yyLOCAL = tree.INDEX_TYPE_IVFFLAT + } + yyVAL.union = yyLOCAL + case 1496: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexType +//line mysql_sql.y:10406 + { + yyLOCAL = tree.INDEX_TYPE_HNSW + } + yyVAL.union = yyLOCAL + case 1497: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexType +//line mysql_sql.y:10410 + { + yyLOCAL = tree.INDEX_TYPE_IVFPQ + } + yyVAL.union = yyLOCAL + case 1498: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexType +//line mysql_sql.y:10414 + { + yyLOCAL = tree.INDEX_TYPE_CAGRA + } + yyVAL.union = yyLOCAL + case 1499: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexType +//line mysql_sql.y:10418 + { + yyLOCAL = tree.INDEX_TYPE_MASTER + } + yyVAL.union = yyLOCAL + case 1500: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexType +//line mysql_sql.y:10422 + { + yyLOCAL = tree.INDEX_TYPE_HASH + } + yyVAL.union = yyLOCAL + case 1501: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexType +//line mysql_sql.y:10426 + { + yyLOCAL = tree.INDEX_TYPE_RTREE + } + yyVAL.union = yyLOCAL + case 1502: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.IndexType +//line mysql_sql.y:10430 + { + yyLOCAL = tree.INDEX_TYPE_BSI + } + yyVAL.union = yyLOCAL + case 1503: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10436 + { + var IfNotExists = yyDollar[3].ifNotExistsUnion() + var Name = tree.Identifier(yyDollar[4].str) + var SubscriptionOption = yyDollar[5].subscriptionOptionUnion() + var CreateOptions = yyDollar[6].createOptionsUnion() + yyLOCAL = tree.NewCreateDatabase( + IfNotExists, + Name, + SubscriptionOption, + CreateOptions, + ) + } + yyVAL.union = yyLOCAL + case 1504: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10450 + { + var t = tree.NewCloneDatabase() + t.IfNotExists = yyDollar[3].ifNotExistsUnion() + t.DstDatabase = tree.Identifier(yyDollar[4].str) + t.SrcDatabase = tree.Identifier(yyDollar[6].str) + t.AtTsExpr = yyDollar[7].atTimeStampUnion() + t.ToAccountOpt = yyDollar[8].toAccountOptUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1505: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10460 + { + var DbName = tree.Identifier(yyDollar[4].str) + var FromUri = yyDollar[6].str + var SubscriptionAccountName = yyDollar[7].cstrUnion().Compare() + var PubName = tree.Identifier(yyDollar[9].cstrUnion().Compare()) + var SyncInterval = yyDollar[10].int64ValUnion() + yyLOCAL = tree.NewCreateSubscription( + true, // isDatabase + DbName, + "", + FromUri, + SubscriptionAccountName, + PubName, + SyncInterval, + ) + } + yyVAL.union = yyLOCAL + case 1506: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.SubscriptionOption +//line mysql_sql.y:10478 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1507: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.SubscriptionOption +//line mysql_sql.y:10482 + { + var From = tree.Identifier(yyDollar[2].str) + var Publication = tree.Identifier(yyDollar[4].cstrUnion().Compare()) + yyLOCAL = tree.NewSubscriptionOption(From, Publication) + } + yyVAL.union = yyLOCAL + case 1510: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:10493 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1511: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:10497 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1512: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:10501 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1513: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:10506 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1514: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:10510 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1515: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []tree.CreateOption +//line mysql_sql.y:10515 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1516: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.CreateOption +//line mysql_sql.y:10519 + { + yyLOCAL = yyDollar[1].createOptionsUnion() + } + yyVAL.union = yyLOCAL + case 1517: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.CreateOption +//line mysql_sql.y:10525 + { + yyLOCAL = []tree.CreateOption{yyDollar[1].createOptionUnion()} + } + yyVAL.union = yyLOCAL + case 1518: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []tree.CreateOption +//line mysql_sql.y:10529 + { + yyLOCAL = append(yyDollar[1].createOptionsUnion(), yyDollar[2].createOptionUnion()) + } + yyVAL.union = yyLOCAL + case 1519: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.CreateOption +//line mysql_sql.y:10535 + { + var IsDefault = yyDollar[1].defaultOptionalUnion() + var Charset = yyDollar[4].str + yyLOCAL = tree.NewCreateOptionCharset( + IsDefault, + Charset, + ) + } + yyVAL.union = yyLOCAL + case 1520: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.CreateOption +//line mysql_sql.y:10544 + { + var IsDefault = yyDollar[1].defaultOptionalUnion() + var Collate = yyDollar[4].str + yyLOCAL = tree.NewCreateOptionCollate( + IsDefault, + Collate, + ) + } + yyVAL.union = yyLOCAL + case 1521: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.CreateOption +//line mysql_sql.y:10553 + { + var Encrypt = yyDollar[4].str + yyLOCAL = tree.NewCreateOptionEncryption(Encrypt) + } + yyVAL.union = yyLOCAL + case 1522: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:10559 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1523: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:10563 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1524: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10569 + { + var taskID uint64 + switch v := yyDollar[4].item.(type) { + case uint64: + taskID = v + case int64: + taskID = uint64(v) + default: + yylex.Error("parse integral fail") + goto ret1 + } + yyLOCAL = &tree.PauseDaemonTask{ + TaskID: taskID, + } + } + yyVAL.union = yyLOCAL + case 1525: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10587 + { + var taskID uint64 + switch v := yyDollar[4].item.(type) { + case uint64: + taskID = v + case int64: + taskID = uint64(v) + default: + yylex.Error("parse integral fail") + goto ret1 + } + yyLOCAL = &tree.CancelDaemonTask{ + TaskID: taskID, + } + } + yyVAL.union = yyLOCAL + case 1526: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10605 + { + var taskID uint64 + switch v := yyDollar[4].item.(type) { + case uint64: + taskID = v + case int64: + taskID = uint64(v) + default: + yylex.Error("parse integral fail") + goto ret1 + } + yyLOCAL = &tree.ResumeDaemonTask{ + TaskID: taskID, + } + } + yyVAL.union = yyLOCAL + case 1527: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:10622 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1528: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:10626 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1529: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10632 + { + t := tree.NewDataBranchCreateTable() + t.CreateTable.Table = *yyDollar[5].tableNameUnion() + t.CreateTable.LikeTableName = *yyDollar[7].tableNameUnion() + t.CreateTable.IsAsLike = true + t.SrcTable = *yyDollar[7].tableNameUnion() + t.ToAccountOpt = yyDollar[8].toAccountOptUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1530: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10642 + { + t := tree.NewDataBranchCreateDatabase() + t.DstDatabase = tree.Identifier(yyDollar[5].str) + t.SrcDatabase = tree.Identifier(yyDollar[7].str) + t.AtTsExpr = yyDollar[8].atTimeStampUnion() + t.ToAccountOpt = yyDollar[9].toAccountOptUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1531: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10651 + { + t := tree.NewDataBranchDeleteTable() + t.TableName = *yyDollar[5].tableNameUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1532: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10657 + { + t := tree.NewDataBranchDeleteDatabase() + t.DatabaseName = tree.Identifier(yyDollar[5].str) + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1533: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10663 + { + t := tree.NewDataBranchDiff() + t.TargetTable = *yyDollar[4].tableNameUnion() + t.BaseTable = *yyDollar[6].tableNameUnion() + t.Columns = yyDollar[7].identifierListUnion() + t.OutputOpt = yyDollar[8].diffOutputOptUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1534: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10672 + { + t := tree.NewDataBranchMerge() + t.SrcTable = *yyDollar[4].tableNameUnion() + t.DstTable = *yyDollar[6].tableNameUnion() + t.ConflictOpt = yyDollar[7].conflictOptUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1535: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10680 + { + t := tree.NewDataBranchPick() + t.SrcTable = *yyDollar[4].tableNameUnion() + t.DstTable = *yyDollar[6].tableNameUnion() + t.Keys = yyDollar[7].pickKeysUnion() + t.ConflictOpt = yyDollar[8].conflictOptUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1536: + yyDollar = yyS[yypt-12 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10689 + { + t := tree.NewDataBranchPick() + t.SrcTable = *yyDollar[4].tableNameUnion() + t.DstTable = *yyDollar[6].tableNameUnion() + t.BetweenFrom = yylex.(*Lexer).GetDbOrTblName(yyDollar[9].cstrUnion().Origin()) + t.BetweenTo = yylex.(*Lexer).GetDbOrTblName(yyDollar[11].cstrUnion().Origin()) + t.ConflictOpt = yyDollar[12].conflictOptUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1537: + yyDollar = yyS[yypt-12 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10699 + { + t := tree.NewDataBranchPick() + t.SrcTable = *yyDollar[4].tableNameUnion() + t.DstTable = *yyDollar[6].tableNameUnion() + t.BetweenFrom = yyDollar[9].str + t.BetweenTo = yyDollar[11].str + t.ConflictOpt = yyDollar[12].conflictOptUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1538: + yyDollar = yyS[yypt-13 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10709 + { + t := tree.NewDataBranchPick() + t.SrcTable = *yyDollar[4].tableNameUnion() + t.DstTable = *yyDollar[6].tableNameUnion() + t.BetweenFrom = yylex.(*Lexer).GetDbOrTblName(yyDollar[9].cstrUnion().Origin()) + t.BetweenTo = yylex.(*Lexer).GetDbOrTblName(yyDollar[11].cstrUnion().Origin()) + t.Keys = yyDollar[12].pickKeysUnion() + t.ConflictOpt = yyDollar[13].conflictOptUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1539: + yyDollar = yyS[yypt-13 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10720 + { + t := tree.NewDataBranchPick() + t.SrcTable = *yyDollar[4].tableNameUnion() + t.DstTable = *yyDollar[6].tableNameUnion() + t.BetweenFrom = yyDollar[9].str + t.BetweenTo = yyDollar[11].str + t.Keys = yyDollar[12].pickKeysUnion() + t.ConflictOpt = yyDollar[13].conflictOptUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1540: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:10732 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1541: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.IdentifierList +//line mysql_sql.y:10736 + { + yyLOCAL = yyDollar[3].identifierListUnion() + } + yyVAL.union = yyLOCAL + case 1542: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.DiffOutputOpt +//line mysql_sql.y:10741 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1543: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.DiffOutputOpt +//line mysql_sql.y:10745 + { + yyLOCAL = &tree.DiffOutputOpt{ + As: *yyDollar[3].tableNameUnion(), + } + } + yyVAL.union = yyLOCAL + case 1544: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.DiffOutputOpt +//line mysql_sql.y:10751 + { + yyLOCAL = &tree.DiffOutputOpt{ + DirPath: yyDollar[3].str, + } + } + yyVAL.union = yyLOCAL + case 1545: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.DiffOutputOpt +//line mysql_sql.y:10757 + { + x, errStr := util.GetInt64(yyDollar[3].item) + if errStr != "" { + yylex.Error("OUTPUT LIMIT is out of range") + goto ret1 + } + yyLOCAL = &tree.DiffOutputOpt{ + Limit: &x, + } + } + yyVAL.union = yyLOCAL + case 1546: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.DiffOutputOpt +//line mysql_sql.y:10764 + { + yyLOCAL = &tree.DiffOutputOpt{ + Count: true, + } + } + yyVAL.union = yyLOCAL + case 1547: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.DiffOutputOpt +//line mysql_sql.y:10770 + { + yyLOCAL = &tree.DiffOutputOpt{ + Summary: true, + } + } + yyVAL.union = yyLOCAL + case 1548: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.ConflictOpt +//line mysql_sql.y:10778 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1549: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.ConflictOpt +//line mysql_sql.y:10782 + { + yyLOCAL = &tree.ConflictOpt{ + Opt: tree.CONFLICT_FAIL, + } + } + yyVAL.union = yyLOCAL + case 1550: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.ConflictOpt +//line mysql_sql.y:10788 + { + yyLOCAL = &tree.ConflictOpt{ + Opt: tree.CONFLICT_SKIP, + } + } + yyVAL.union = yyLOCAL + case 1551: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.ConflictOpt +//line mysql_sql.y:10794 + { + yyLOCAL = &tree.ConflictOpt{ + Opt: tree.CONFLICT_ACCEPT, + } + } + yyVAL.union = yyLOCAL + case 1552: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.PickKeys +//line mysql_sql.y:10802 + { + yyLOCAL = &tree.PickKeys{ + Type: tree.PickKeysValues, + KeyExprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 1553: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.PickKeys +//line mysql_sql.y:10809 + { + yyLOCAL = &tree.PickKeys{ + Type: tree.PickKeysSubquery, + Select: yyDollar[3].selectUnion(), + } + } + yyVAL.union = yyLOCAL + case 1554: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.ToAccountOpt +//line mysql_sql.y:10818 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1555: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.ToAccountOpt +//line mysql_sql.y:10822 + { + yyLOCAL = &tree.ToAccountOpt{ + AccountName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + } + } + yyVAL.union = yyLOCAL + case 1556: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:10830 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1557: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:10834 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1558: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:10839 + { + yyVAL.str = "" + } + case 1559: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:10840 + { + yyVAL.str = "ignore" + } + case 1560: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:10841 + { + yyVAL.str = "replace" + } + case 1561: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:10844 + { + yyVAL.str = "ignore" + } + case 1562: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:10845 + { + yyVAL.str = "replace" + } + case 1563: + yyDollar = yyS[yypt-11 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10849 + { + t := tree.NewCreateTable() + t.Temporary = yyDollar[2].boolValUnion() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.Defs = yyDollar[7].tableDefsUnion() + t.Options = yyDollar[9].tableOptionsUnion() + t.PartitionOption = yyDollar[10].partitionOptionUnion() + t.ClusterByOption = yyDollar[11].clusterByOptionUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1564: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10861 + { + t := tree.NewCreateTable() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.Defs = yyDollar[7].tableDefsUnion() + t.Param = yyDollar[9].loadParamUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1565: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10870 + { + t := tree.NewCreateTable() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.Defs = yyDollar[7].tableDefsUnion() + t.IcebergParam = yyDollar[9].icebergTableParamUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1566: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10879 + { + t := tree.NewCreateTable() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.Defs = yyDollar[7].tableDefsUnion() + t.MongoDBParam = yyDollar[9].mongodbTableParamUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1567: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10888 + { + t := tree.NewCreateTable() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.Defs = yyDollar[7].tableDefsUnion() + t.DataStreamParam = yyDollar[9].datastreamTableParamUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1568: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10897 + { + t := tree.NewCreateTable() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.Defs = yyDollar[7].tableDefsUnion() + t.ForeignParam = yyDollar[9].foreignTableParamUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1569: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10906 + { + t := tree.NewCreateTable() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.Defs = yyDollar[7].tableDefsUnion() + t.KafkaParam = yyDollar[9].kafkaTableParamUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1570: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10915 + { + t := tree.NewCreateTable() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.IcebergParam = yyDollar[6].icebergTableParamUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1571: + yyDollar = yyS[yypt-11 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10923 + { + t := tree.NewCreateTable() + t.IsClusterTable = true + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.Defs = yyDollar[7].tableDefsUnion() + t.Options = yyDollar[9].tableOptionsUnion() + t.PartitionOption = yyDollar[10].partitionOptionUnion() + t.ClusterByOption = yyDollar[11].clusterByOptionUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1572: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10935 + { + if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[6].selectUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + t := tree.NewCreateTable() + t.IsAsSelect = true + t.Temporary = yyDollar[2].boolValUnion() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.AsSource = yyDollar[6].selectUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1573: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10949 + { + if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[9].selectUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + t := tree.NewCreateTable() + t.IsAsSelect = true + t.Temporary = yyDollar[2].boolValUnion() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.Defs = yyDollar[7].tableDefsUnion() + t.AsSource = yyDollar[9].selectUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1574: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10964 + { + if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[7].selectUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + t := tree.NewCreateTable() + t.IsAsSelect = true + t.Temporary = yyDollar[2].boolValUnion() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.CTASConflict = yyDollar[6].str + t.AsSource = yyDollar[7].selectUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1575: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10969 + { + if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[10].selectUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + t := tree.NewCreateTable() + t.IsAsSelect = true + t.Temporary = yyDollar[2].boolValUnion() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.Defs = yyDollar[7].tableDefsUnion() + t.CTASConflict = yyDollar[9].str + t.AsSource = yyDollar[10].selectUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1576: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10974 + { + if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[8].selectUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + t := tree.NewCreateTable() + t.IsAsSelect = true + t.Temporary = yyDollar[2].boolValUnion() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.CTASConflict = yyDollar[6].str + t.AsSource = yyDollar[8].selectUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1577: + yyDollar = yyS[yypt-11 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10979 + { + if intoErr := tree.ValidateSelectIntoNotAllowed(yyDollar[11].selectUnion()); intoErr != "" { + yylex.Error(intoErr) + goto ret1 + } + t := tree.NewCreateTable() + t.IsAsSelect = true + t.Temporary = yyDollar[2].boolValUnion() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.Defs = yyDollar[7].tableDefsUnion() + t.CTASConflict = yyDollar[9].str + t.AsSource = yyDollar[11].selectUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1578: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10984 + { + t := tree.NewCreateTable() + t.IsAsLike = true + t.Temporary = yyDollar[2].boolValUnion() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.LikeTableName = *yyDollar[7].tableNameUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1579: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:10994 + { + t := tree.NewCreateTable() + t.Temporary = yyDollar[2].boolValUnion() + t.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.Table = *yyDollar[5].tableNameUnion() + t.SubscriptionOption = yyDollar[6].subscriptionOptionUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1580: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:11003 + { + t := tree.NewCloneTable() + t.CreateTable.Temporary = yyDollar[2].boolValUnion() + t.CreateTable.IfNotExists = yyDollar[4].ifNotExistsUnion() + t.CreateTable.Table = *yyDollar[5].tableNameUnion() + t.CreateTable.LikeTableName = *yyDollar[7].tableNameUnion() + t.CreateTable.IsAsLike = true + t.SrcTable = *yyDollar[7].tableNameUnion() + t.CopyGrants = yyDollar[8].boolValUnion() + t.ToAccountOpt = yyDollar[9].toAccountOptUnion() + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1581: + yyDollar = yyS[yypt-11 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:11016 + { + var TableName = yyDollar[5].tableNameUnion() + var FromUri = yyDollar[7].str + var SubscriptionAccountName = yyDollar[8].cstrUnion().Compare() + var PubName = tree.Identifier(yyDollar[10].cstrUnion().Compare()) + var SyncInterval = yyDollar[11].int64ValUnion() + var TableNameStr = string(TableName.ObjectName) + var DbName = tree.Identifier("") + // Extract database name from table name if explicitly specified + if TableName.ExplicitSchema { + DbName = TableName.SchemaName + } + yyLOCAL = tree.NewCreateSubscription( + false, // isDatabase + DbName, + TableNameStr, + FromUri, + SubscriptionAccountName, + PubName, + SyncInterval, + ) + } + yyVAL.union = yyLOCAL + case 1582: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.ExternParam +//line mysql_sql.y:11041 + { + yyLOCAL = yyDollar[1].loadParamUnion() + yyLOCAL.Tail = yyDollar[2].tailParamUnion() + } + yyVAL.union = yyLOCAL + case 1583: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.ExternParam +//line mysql_sql.y:11048 + { + yyLOCAL = &tree.ExternParam{ + ExParamConst: tree.ExParamConst{ + Filepath: yyDollar[2].str, + CompressType: tree.AUTO, + Format: tree.CSV, + }, + } + } + yyVAL.union = yyLOCAL + case 1584: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL *tree.ExternParam +//line mysql_sql.y:11058 + { + yyLOCAL = &tree.ExternParam{ + ExParamConst: tree.ExParamConst{ + ScanType: tree.INLINE, + Format: strings.ToLower(yyDollar[4].str), + Data: yyDollar[8].str, + }, + ExParam: tree.ExParam{ + JsonData: yyDollar[9].str, + }, + } + } + yyVAL.union = yyLOCAL + case 1585: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.ExternParam +//line mysql_sql.y:11071 + { + yyLOCAL = &tree.ExternParam{ + ExParamConst: tree.ExParamConst{ + Option: yyDollar[3].strsUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 1586: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.ExternParam +//line mysql_sql.y:11079 + { + yyLOCAL = &tree.ExternParam{ + ExParamConst: tree.ExParamConst{ + ScanType: tree.S3, + Option: yyDollar[4].strsUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 1587: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.ExternParam +//line mysql_sql.y:11088 + { + yyLOCAL = &tree.ExternParam{ + ExParamConst: tree.ExParamConst{ + StageName: tree.Identifier(yyDollar[3].cstrUnion().Compare()), + }, + } + } + yyVAL.union = yyLOCAL + case 1588: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:11097 + { + yyVAL.str = "" + } + case 1589: + yyDollar = yyS[yypt-4 : yypt+1] +//line mysql_sql.y:11101 + { + yyVAL.str = yyDollar[4].str + } + case 1590: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:11107 + { + yyLOCAL = yyDollar[1].strsUnion() + } + yyVAL.union = yyLOCAL + case 1591: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:11111 + { + yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].strsUnion()...) + } + yyVAL.union = yyLOCAL + case 1592: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:11116 + { + yyLOCAL = []string{} + } + yyVAL.union = yyLOCAL + case 1593: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:11120 + { + yyLOCAL = append(yyLOCAL, yyDollar[1].str) + yyLOCAL = append(yyLOCAL, yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1594: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.TailParameter +//line mysql_sql.y:11127 + { + yyLOCAL = &tree.TailParameter{ + Charset: yyDollar[1].str, + Fields: yyDollar[2].fieldsUnion(), + Lines: yyDollar[3].linesUnion(), + IgnoredLines: uint64(yyDollar[4].int64ValUnion()), + ColumnList: yyDollar[5].loadColumnsUnion(), + Assignments: yyDollar[6].updateExprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 1595: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:11139 + { + yyVAL.str = "" + } + case 1596: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:11143 + { + yyVAL.str = yyDollar[2].str + } + case 1597: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:11149 + { + var Name = yyDollar[4].tableNameUnion() + var Type = yyDollar[5].columnTypeUnion() + var IfNotExists = yyDollar[3].ifNotExistsUnion() + var IncrementBy = yyDollar[6].incrementByOptionUnion() + var MinValue = yyDollar[7].minValueOptionUnion() + var MaxValue = yyDollar[8].maxValueOptionUnion() + var StartWith = yyDollar[9].startWithOptionUnion() + var Cycle = yyDollar[10].boolValUnion() + yyLOCAL = tree.NewCreateSequence( + Name, + Type, + IfNotExists, + IncrementBy, + MinValue, + MaxValue, + StartWith, + Cycle, + ) + } + yyVAL.union = yyLOCAL + case 1598: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:11170 + { + locale := "" + fstr := "bigint" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: fstr, + Width: 64, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_LONGLONG), + }, + } + } + yyVAL.union = yyLOCAL + case 1599: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:11184 + { + yyLOCAL = yyDollar[2].columnTypeUnion() + } + yyVAL.union = yyLOCAL + case 1600: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.TypeOption +//line mysql_sql.y:11188 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1601: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.TypeOption +//line mysql_sql.y:11192 + { + yyLOCAL = &tree.TypeOption{ + Type: yyDollar[2].columnTypeUnion(), + } + } + yyVAL.union = yyLOCAL + case 1602: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.IncrementByOption +//line mysql_sql.y:11198 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1603: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IncrementByOption +//line mysql_sql.y:11202 + { + yyLOCAL = &tree.IncrementByOption{ + Minus: false, + Num: yyDollar[3].item, + } + } + yyVAL.union = yyLOCAL + case 1604: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.IncrementByOption +//line mysql_sql.y:11209 + { + yyLOCAL = &tree.IncrementByOption{ + Minus: false, + Num: yyDollar[2].item, + } + } + yyVAL.union = yyLOCAL + case 1605: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.IncrementByOption +//line mysql_sql.y:11216 + { + yyLOCAL = &tree.IncrementByOption{ + Minus: true, + Num: yyDollar[4].item, + } + } + yyVAL.union = yyLOCAL + case 1606: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IncrementByOption +//line mysql_sql.y:11223 + { + yyLOCAL = &tree.IncrementByOption{ + Minus: true, + Num: yyDollar[3].item, + } + } + yyVAL.union = yyLOCAL + case 1607: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:11230 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1608: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:11234 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1609: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:11238 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1610: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.MinValueOption +//line mysql_sql.y:11242 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1611: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.MinValueOption +//line mysql_sql.y:11246 + { + yyLOCAL = &tree.MinValueOption{ + Minus: false, + Num: yyDollar[2].item, + } + } + yyVAL.union = yyLOCAL + case 1612: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.MinValueOption +//line mysql_sql.y:11253 + { + yyLOCAL = &tree.MinValueOption{ + Minus: true, + Num: yyDollar[3].item, + } + } + yyVAL.union = yyLOCAL + case 1613: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.MaxValueOption +//line mysql_sql.y:11260 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1614: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.MaxValueOption +//line mysql_sql.y:11264 + { + yyLOCAL = &tree.MaxValueOption{ + Minus: false, + Num: yyDollar[2].item, + } + } + yyVAL.union = yyLOCAL + case 1615: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.MaxValueOption +//line mysql_sql.y:11271 + { + yyLOCAL = &tree.MaxValueOption{ + Minus: true, + Num: yyDollar[3].item, + } + } + yyVAL.union = yyLOCAL + case 1616: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.CycleOption +//line mysql_sql.y:11278 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1617: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.CycleOption +//line mysql_sql.y:11282 + { + yyLOCAL = &tree.CycleOption{ + Cycle: false, + } + } + yyVAL.union = yyLOCAL + case 1618: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CycleOption +//line mysql_sql.y:11288 + { + yyLOCAL = &tree.CycleOption{ + Cycle: true, + } + } + yyVAL.union = yyLOCAL + case 1619: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.StartWithOption +//line mysql_sql.y:11294 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1620: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.StartWithOption +//line mysql_sql.y:11298 + { + yyLOCAL = &tree.StartWithOption{ + Minus: false, + Num: yyDollar[3].item, + } + } + yyVAL.union = yyLOCAL + case 1621: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.StartWithOption +//line mysql_sql.y:11305 + { + yyLOCAL = &tree.StartWithOption{ + Minus: false, + Num: yyDollar[2].item, + } + } + yyVAL.union = yyLOCAL + case 1622: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.StartWithOption +//line mysql_sql.y:11312 + { + yyLOCAL = &tree.StartWithOption{ + Minus: true, + Num: yyDollar[4].item, + } + } + yyVAL.union = yyLOCAL + case 1623: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.StartWithOption +//line mysql_sql.y:11319 + { + yyLOCAL = &tree.StartWithOption{ + Minus: true, + Num: yyDollar[3].item, + } + } + yyVAL.union = yyLOCAL + case 1624: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:11326 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1625: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:11330 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1626: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:11335 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1627: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:11339 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1628: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:11343 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1629: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.PartitionOption +//line mysql_sql.y:11348 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1630: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.PartitionOption +//line mysql_sql.y:11352 + { + yyDollar[3].partitionByUnion().Num = uint64(yyDollar[4].int64ValUnion()) + var PartBy = yyDollar[3].partitionByUnion() + var SubPartBy = yyDollar[5].partitionByUnion() + var Partitions = yyDollar[6].partitionsUnion() + yyLOCAL = tree.NewPartitionOption( + PartBy, + SubPartBy, + Partitions, + ) + } + yyVAL.union = yyLOCAL + case 1631: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.ClusterByOption +//line mysql_sql.y:11365 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1632: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.ClusterByOption +//line mysql_sql.y:11369 + { + var ColumnList = []*tree.UnresolvedName{yyDollar[3].unresolvedNameUnion()} + yyLOCAL = tree.NewClusterByOption( + ColumnList, + ) + + } + yyVAL.union = yyLOCAL + case 1633: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.ClusterByOption +//line mysql_sql.y:11377 + { + var ColumnList = yyDollar[4].unresolveNamesUnion() + yyLOCAL = tree.NewClusterByOption( + ColumnList, + ) + } + yyVAL.union = yyLOCAL + case 1634: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.PartitionBy +//line mysql_sql.y:11385 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1635: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.PartitionBy +//line mysql_sql.y:11389 + { + var IsSubPartition = true + var PType = yyDollar[3].partitionByUnion().PType + var Num = uint64(yyDollar[4].int64ValUnion()) + yyDollar[3].partitionByUnion().PType = nil + yyDollar[3].partitionByUnion().Free() + yyLOCAL = tree.NewPartitionBy2( + IsSubPartition, + PType, + Num, + ) + } + yyVAL.union = yyLOCAL + case 1636: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []*tree.Partition +//line mysql_sql.y:11403 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1637: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.Partition +//line mysql_sql.y:11407 + { + yyLOCAL = yyDollar[2].partitionsUnion() + } + yyVAL.union = yyLOCAL + case 1638: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.Partition +//line mysql_sql.y:11413 + { + yyLOCAL = []*tree.Partition{yyDollar[1].partitionUnion()} + } + yyVAL.union = yyLOCAL + case 1639: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.Partition +//line mysql_sql.y:11417 + { + yyLOCAL = append(yyDollar[1].partitionsUnion(), yyDollar[3].partitionUnion()) + } + yyVAL.union = yyLOCAL + case 1640: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.Partition +//line mysql_sql.y:11423 + { + var Name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) + var Values = yyDollar[3].valuesUnion() + var Options []tree.TableOption + var Subs = yyDollar[4].subPartitionsUnion() + yyLOCAL = tree.NewPartition( + Name, + Values, + Options, + Subs, + ) + } + yyVAL.union = yyLOCAL + case 1641: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.Partition +//line mysql_sql.y:11436 + { + var Name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) + var Values = yyDollar[3].valuesUnion() + var Options = yyDollar[4].tableOptionsUnion() + var Subs = yyDollar[5].subPartitionsUnion() + yyLOCAL = tree.NewPartition( + Name, + Values, + Options, + Subs, + ) + } + yyVAL.union = yyLOCAL + case 1642: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []*tree.SubPartition +//line mysql_sql.y:11450 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1643: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.SubPartition +//line mysql_sql.y:11454 + { + yyLOCAL = yyDollar[2].subPartitionsUnion() + } + yyVAL.union = yyLOCAL + case 1644: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.SubPartition +//line mysql_sql.y:11460 + { + yyLOCAL = []*tree.SubPartition{yyDollar[1].subPartitionUnion()} + } + yyVAL.union = yyLOCAL + case 1645: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.SubPartition +//line mysql_sql.y:11464 + { + yyLOCAL = append(yyDollar[1].subPartitionsUnion(), yyDollar[3].subPartitionUnion()) + } + yyVAL.union = yyLOCAL + case 1646: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.SubPartition +//line mysql_sql.y:11470 + { + var Name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) + var Options []tree.TableOption + yyLOCAL = tree.NewSubPartition( + Name, + Options, + ) + } + yyVAL.union = yyLOCAL + case 1647: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.SubPartition +//line mysql_sql.y:11479 + { + var Name = tree.Identifier(yyDollar[2].cstrUnion().Compare()) + var Options = yyDollar[3].tableOptionsUnion() + yyLOCAL = tree.NewSubPartition( + Name, + Options, + ) + } + yyVAL.union = yyLOCAL + case 1648: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.TableOption +//line mysql_sql.y:11490 + { + yyLOCAL = []tree.TableOption{yyDollar[1].tableOptionUnion()} + } + yyVAL.union = yyLOCAL + case 1649: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []tree.TableOption +//line mysql_sql.y:11494 + { + yyLOCAL = append(yyDollar[1].tableOptionsUnion(), yyDollar[2].tableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 1650: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11500 + { + if option, ok := yyDollar[1].tableOptionUnion().(*tree.TableOptionAutoIDCache); ok { + option.Free() + yylex.Error("AUTO_ID_CACHE is a table option, not a partition or subpartition option") + goto ret1 + } + yyLOCAL = yyDollar[1].tableOptionUnion() + } + yyVAL.union = yyLOCAL + case 1651: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Values +//line mysql_sql.y:11510 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1652: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Values +//line mysql_sql.y:11514 + { + expr := tree.NewMaxValue() + var valueList = tree.Exprs{expr} + yyLOCAL = tree.NewValuesLessThan(valueList) + } + yyVAL.union = yyLOCAL + case 1653: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Values +//line mysql_sql.y:11520 + { + var valueList = yyDollar[5].exprsUnion() + yyLOCAL = tree.NewValuesLessThan(valueList) + } + yyVAL.union = yyLOCAL + case 1654: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Values +//line mysql_sql.y:11525 + { + var valueList = yyDollar[4].exprsUnion() + yyLOCAL = tree.NewValuesIn( + valueList, + ) + } + yyVAL.union = yyLOCAL + case 1655: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:11533 + { + yyLOCAL = 0 + } + yyVAL.union = yyLOCAL + case 1656: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:11537 + { + res, ok := signedIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + if res == 0 { + yylex.Error("partitions can not be 0") + goto ret1 + } + yyLOCAL = res + } + yyVAL.union = yyLOCAL + case 1657: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:11548 + { + yyLOCAL = 0 + } + yyVAL.union = yyLOCAL + case 1658: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:11552 + { + res, ok := signedIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + if res == 0 { + yylex.Error("partitions can not be 0") + goto ret1 + } + yyLOCAL = res + } + yyVAL.union = yyLOCAL + case 1659: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.PartitionBy +//line mysql_sql.y:11564 + { + rangeTyp := tree.NewRangeType() + rangeTyp.Expr = yyDollar[3].exprUnion() + yyLOCAL = tree.NewPartitionBy( + rangeTyp, + ) + } + yyVAL.union = yyLOCAL + case 1660: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.PartitionBy +//line mysql_sql.y:11572 + { + rangeTyp := tree.NewRangeType() + rangeTyp.ColumnList = yyDollar[4].unresolveNamesUnion() + yyLOCAL = tree.NewPartitionBy( + rangeTyp, + ) + } + yyVAL.union = yyLOCAL + case 1661: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.PartitionBy +//line mysql_sql.y:11580 + { + listTyp := tree.NewListType() + listTyp.Expr = yyDollar[3].exprUnion() + yyLOCAL = tree.NewPartitionBy( + listTyp, + ) + } + yyVAL.union = yyLOCAL + case 1662: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.PartitionBy +//line mysql_sql.y:11588 + { + listTyp := tree.NewListType() + listTyp.ColumnList = yyDollar[4].unresolveNamesUnion() + yyLOCAL = tree.NewPartitionBy( + listTyp, + ) + } + yyVAL.union = yyLOCAL + case 1664: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.PartitionBy +//line mysql_sql.y:11599 + { + keyTyp := tree.NewKeyType() + keyTyp.Linear = yyDollar[1].boolValUnion() + keyTyp.Algorithm = yyDollar[3].int64ValUnion() + yyLOCAL = tree.NewPartitionBy( + keyTyp, + ) + } + yyVAL.union = yyLOCAL + case 1665: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.PartitionBy +//line mysql_sql.y:11608 + { + keyTyp := tree.NewKeyType() + keyTyp.Linear = yyDollar[1].boolValUnion() + keyTyp.Algorithm = yyDollar[3].int64ValUnion() + keyTyp.ColumnList = yyDollar[5].unresolveNamesUnion() + yyLOCAL = tree.NewPartitionBy( + keyTyp, + ) + } + yyVAL.union = yyLOCAL + case 1666: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.PartitionBy +//line mysql_sql.y:11618 + { + Linear := yyDollar[1].boolValUnion() + Expr := yyDollar[4].exprUnion() + hashTyp := tree.NewHashType(Linear, Expr) + yyLOCAL = tree.NewPartitionBy( + hashTyp, + ) + } + yyVAL.union = yyLOCAL + case 1667: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:11628 + { + yyLOCAL = 2 + } + yyVAL.union = yyLOCAL + case 1668: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:11632 + { + value, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + yyLOCAL = value + } + yyVAL.union = yyLOCAL + case 1669: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:11639 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1670: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:11643 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1671: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.IcebergTableParam +//line mysql_sql.y:11649 + { + yyLOCAL = tree.NewIcebergTableParam(yyDollar[4].icebergOptionsUnion()) + } + yyVAL.union = yyLOCAL + case 1672: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.IcebergOptions +//line mysql_sql.y:11654 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1673: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.IcebergOptions +//line mysql_sql.y:11658 + { + yyLOCAL = yyDollar[3].icebergOptionsUnion() + } + yyVAL.union = yyLOCAL + case 1674: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.IcebergOptions +//line mysql_sql.y:11664 + { + yyLOCAL = tree.IcebergOptions{yyDollar[1].icebergOptionUnion()} + } + yyVAL.union = yyLOCAL + case 1675: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.IcebergOptions +//line mysql_sql.y:11668 + { + yyLOCAL = append(yyDollar[1].icebergOptionsUnion(), yyDollar[3].icebergOptionUnion()) + } + yyVAL.union = yyLOCAL + case 1676: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IcebergOption +//line mysql_sql.y:11674 + { + yyLOCAL = tree.NewIcebergOption(tree.Identifier(yyDollar[1].str), yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1677: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11680 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1678: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11684 + { + yyVAL.str = yyDollar[1].str + } + case 1679: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11690 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1680: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11694 + { + yyVAL.str = yyDollar[1].str + } + case 1681: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.MongoDBTableParam +//line mysql_sql.y:11700 + { + yyLOCAL = tree.NewMongoDBTableParam(yyDollar[4].mongodbOptionsUnion()) + } + yyVAL.union = yyLOCAL + case 1682: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.MongoDBOptions +//line mysql_sql.y:11705 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1683: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.MongoDBOptions +//line mysql_sql.y:11709 + { + yyLOCAL = yyDollar[3].mongodbOptionsUnion() + } + yyVAL.union = yyLOCAL + case 1684: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.MongoDBOptions +//line mysql_sql.y:11715 + { + yyLOCAL = tree.MongoDBOptions{yyDollar[1].mongodbOptionUnion()} + } + yyVAL.union = yyLOCAL + case 1685: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.MongoDBOptions +//line mysql_sql.y:11719 + { + yyLOCAL = append(yyDollar[1].mongodbOptionsUnion(), yyDollar[3].mongodbOptionUnion()) + } + yyVAL.union = yyLOCAL + case 1686: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.MongoDBOption +//line mysql_sql.y:11725 + { + yyLOCAL = tree.NewMongoDBOption(tree.Identifier(yyDollar[1].str), yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1687: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11731 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1688: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11735 + { + yyVAL.str = yyDollar[1].str + } + case 1689: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11741 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1690: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11745 + { + yyVAL.str = yyDollar[1].str + } + case 1691: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.DataStreamTableParam +//line mysql_sql.y:11751 + { + yyLOCAL = tree.NewDataStreamTableParam(yyDollar[4].datastreamOptionsUnion()) + } + yyVAL.union = yyLOCAL + case 1692: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.DataStreamOptions +//line mysql_sql.y:11756 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1693: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.DataStreamOptions +//line mysql_sql.y:11760 + { + yyLOCAL = yyDollar[3].datastreamOptionsUnion() + } + yyVAL.union = yyLOCAL + case 1694: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.DataStreamOptions +//line mysql_sql.y:11766 + { + yyLOCAL = tree.DataStreamOptions{yyDollar[1].datastreamOptionUnion()} + } + yyVAL.union = yyLOCAL + case 1695: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.DataStreamOptions +//line mysql_sql.y:11770 + { + yyLOCAL = append(yyDollar[1].datastreamOptionsUnion(), yyDollar[3].datastreamOptionUnion()) + } + yyVAL.union = yyLOCAL + case 1696: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.DataStreamOption +//line mysql_sql.y:11776 + { + yyLOCAL = tree.NewDataStreamOption(tree.Identifier(yyDollar[1].str), yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1697: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.ForeignTableParam +//line mysql_sql.y:11782 + { + yyLOCAL = tree.NewForeignTableParam(yyDollar[3].str, yyDollar[4].foreignTableOptionsUnion()) + } + yyVAL.union = yyLOCAL + case 1698: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.KafkaTableParam +//line mysql_sql.y:11788 + { + yyLOCAL = tree.NewKafkaTableParam(yyDollar[4].kafkaTableOptionsUnion()) + } + yyVAL.union = yyLOCAL + case 1699: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.KafkaTableOptions +//line mysql_sql.y:11793 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1700: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.KafkaTableOptions +//line mysql_sql.y:11797 + { + yyLOCAL = yyDollar[3].kafkaTableOptionsUnion() + } + yyVAL.union = yyLOCAL + case 1701: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.KafkaTableOptions +//line mysql_sql.y:11803 + { + yyLOCAL = tree.KafkaTableOptions{yyDollar[1].kafkaTableOptionUnion()} + } + yyVAL.union = yyLOCAL + case 1702: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.KafkaTableOptions +//line mysql_sql.y:11807 + { + yyLOCAL = append(yyDollar[1].kafkaTableOptionsUnion(), yyDollar[3].kafkaTableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 1703: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.KafkaTableOption +//line mysql_sql.y:11813 + { + yyLOCAL = tree.NewKafkaTableOption(tree.Identifier(yyDollar[1].str), yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1704: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11819 + { + yyVAL.str = "esql" + } + case 1705: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11823 + { + yyVAL.str = "sql" + } + case 1706: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.ForeignTableOptions +//line mysql_sql.y:11828 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1707: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.ForeignTableOptions +//line mysql_sql.y:11832 + { + yyLOCAL = yyDollar[3].foreignTableOptionsUnion() + } + yyVAL.union = yyLOCAL + case 1708: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ForeignTableOptions +//line mysql_sql.y:11838 + { + yyLOCAL = tree.ForeignTableOptions{yyDollar[1].foreignTableOptionUnion()} + } + yyVAL.union = yyLOCAL + case 1709: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.ForeignTableOptions +//line mysql_sql.y:11842 + { + yyLOCAL = append(yyDollar[1].foreignTableOptionsUnion(), yyDollar[3].foreignTableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 1710: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.ForeignTableOption +//line mysql_sql.y:11848 + { + yyLOCAL = tree.NewForeignTableOption(tree.Identifier(yyDollar[1].str), yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1711: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11854 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1712: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11858 + { + yyVAL.str = yyDollar[1].str + } + case 1713: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11864 + { + yyVAL.str = yyDollar[1].cstrUnion().Compare() + } + case 1714: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:11868 + { + yyVAL.str = yyDollar[1].str + } + case 1715: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []tree.TableOption +//line mysql_sql.y:11873 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1716: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.TableOption +//line mysql_sql.y:11877 + { + yyLOCAL = yyDollar[1].tableOptionsUnion() + } + yyVAL.union = yyLOCAL + case 1717: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.TableOption +//line mysql_sql.y:11883 + { + yyLOCAL = []tree.TableOption{yyDollar[1].tableOptionUnion()} + } + yyVAL.union = yyLOCAL + case 1718: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []tree.TableOption +//line mysql_sql.y:11887 + { + yyLOCAL = append(yyDollar[1].tableOptionsUnion(), yyDollar[3].tableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 1719: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []tree.TableOption +//line mysql_sql.y:11891 + { + yyLOCAL = append(yyDollar[1].tableOptionsUnion(), yyDollar[2].tableOptionUnion()) + } + yyVAL.union = yyLOCAL + case 1720: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11897 + { + yyLOCAL = tree.NewTableOptionAUTOEXTEND_SIZE(integralToUint64(yyDollar[3].item)) + } + yyVAL.union = yyLOCAL + case 1721: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11901 + { + yyLOCAL = tree.NewTableOptionAutoIncrement(integralToUint64(yyDollar[3].item)) + } + yyVAL.union = yyLOCAL + case 1722: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11905 + { + yyLOCAL = tree.NewTableOptionAutoIDCache(integralToUint64(yyDollar[3].item)) + } + yyVAL.union = yyLOCAL + case 1723: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11909 + { + yyLOCAL = tree.NewTableOptionAvgRowLength(integralToUint64(yyDollar[3].item)) + } + yyVAL.union = yyLOCAL + case 1724: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11913 + { + yyLOCAL = tree.NewTableOptionCharset(yyDollar[4].str) + } + yyVAL.union = yyLOCAL + case 1725: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11917 + { + yyLOCAL = tree.NewTableOptionCollate(yyDollar[4].str) + } + yyVAL.union = yyLOCAL + case 1726: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11921 + { + yyLOCAL = tree.NewTableOptionChecksum(integralToUint64(yyDollar[3].item)) + } + yyVAL.union = yyLOCAL + case 1727: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11925 + { + str := util.DealCommentString(yyDollar[3].str) + yyLOCAL = tree.NewTableOptionComment(str) + } + yyVAL.union = yyLOCAL + case 1728: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11930 + { + yyLOCAL = tree.NewTableOptionCompression(yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1729: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11934 + { + yyLOCAL = tree.NewTableOptionConnection(yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1730: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11938 + { + yyLOCAL = tree.NewTableOptionDataDirectory(yyDollar[4].str) + } + yyVAL.union = yyLOCAL + case 1731: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11942 + { + yyLOCAL = tree.NewTableOptionIndexDirectory(yyDollar[4].str) + } + yyVAL.union = yyLOCAL + case 1732: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11946 + { + yyLOCAL = tree.NewTableOptionDelayKeyWrite(integralToUint64(yyDollar[3].item)) + } + yyVAL.union = yyLOCAL + case 1733: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11950 + { + yyLOCAL = tree.NewTableOptionEncryption(yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1734: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11954 + { + yyLOCAL = tree.NewTableOptionEngine(yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1735: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11958 + { + yyLOCAL = tree.NewTableOptionEngineAttr(yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1736: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11962 + { + yyLOCAL = tree.NewTableOptionInsertMethod(yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1737: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11966 + { + yyLOCAL = tree.NewTableOptionKeyBlockSize(integralToUint64(yyDollar[3].item)) + } + yyVAL.union = yyLOCAL + case 1738: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11970 + { + yyLOCAL = tree.NewTableOptionMaxRows(integralToUint64(yyDollar[3].item)) + } + yyVAL.union = yyLOCAL + case 1739: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11974 + { + yyLOCAL = tree.NewTableOptionMinRows(integralToUint64(yyDollar[3].item)) + } + yyVAL.union = yyLOCAL + case 1740: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11978 + { + t := tree.NewTableOptionPackKeys() + value, ok := signedIntegral(yylex, yyDollar[3].item) + if !ok { + goto ret1 + } + t.Value = value + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1741: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11986 + { + t := tree.NewTableOptionPackKeys() + t.Default = true + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1742: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11992 + { + yyLOCAL = tree.NewTableOptionPassword(yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1743: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:11996 + { + yyLOCAL = tree.NewTableOptionRowFormat(yyDollar[3].rowFormatTypeUnion()) + } + yyVAL.union = yyLOCAL + case 1744: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12000 + { + yyLOCAL = tree.NewTTableOptionStartTrans(true) + } + yyVAL.union = yyLOCAL + case 1745: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12004 + { + yyLOCAL = tree.NewTTableOptionSecondaryEngineAttr(yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 1746: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12008 + { + t := tree.NewTableOptionStatsAutoRecalc() + t.Value = integralToUint64(yyDollar[3].item) + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1747: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12014 + { + t := tree.NewTableOptionStatsAutoRecalc() + t.Default = true + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1748: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12020 + { + t := tree.NewTableOptionStatsPersistent() + t.Value = integralToUint64(yyDollar[3].item) + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1749: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12026 + { + t := tree.NewTableOptionStatsPersistent() + t.Default = true + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1750: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12032 + { + t := tree.NewTableOptionStatsSamplePages() + t.Value = integralToUint64(yyDollar[3].item) + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1751: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12038 + { + t := tree.NewTableOptionStatsSamplePages() + t.Default = true + yyLOCAL = t + } + yyVAL.union = yyLOCAL + case 1752: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12044 + { + yyLOCAL = tree.NewTableOptionTablespace(yyDollar[3].cstrUnion().Compare(), "") + } + yyVAL.union = yyLOCAL + case 1753: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12048 + { + yyLOCAL = tree.NewTableOptionTablespace("", yyDollar[1].str) + } + yyVAL.union = yyLOCAL + case 1754: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12052 + { + yyLOCAL = tree.NewTableOptionUnion(yyDollar[4].tableNamesUnion()) + } + yyVAL.union = yyLOCAL + case 1755: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.TableOption +//line mysql_sql.y:12056 + { + var Preperties = yyDollar[3].propertiesUnion() + yyLOCAL = tree.NewTableOptionProperties(Preperties) + } + yyVAL.union = yyLOCAL + case 1756: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.Property +//line mysql_sql.y:12063 + { + yyLOCAL = []tree.Property{yyDollar[1].propertyUnion()} + } + yyVAL.union = yyLOCAL + case 1757: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []tree.Property +//line mysql_sql.y:12067 + { + yyLOCAL = append(yyDollar[1].propertiesUnion(), yyDollar[3].propertyUnion()) + } + yyVAL.union = yyLOCAL + case 1758: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Property +//line mysql_sql.y:12073 + { + var Key = yyDollar[1].str + var Value = yyDollar[3].str + yyLOCAL = *tree.NewProperty( + Key, + Value, + ) + } + yyVAL.union = yyLOCAL + case 1759: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:12084 + { + yyVAL.str = " " + yyDollar[1].str + " " + yyDollar[2].str + } + case 1760: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:12088 + { + yyVAL.str = " " + yyDollar[1].str + " " + yyDollar[2].str + } + case 1761: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.RowFormatType +//line mysql_sql.y:12094 + { + yyLOCAL = tree.ROW_FORMAT_DEFAULT + } + yyVAL.union = yyLOCAL + case 1762: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.RowFormatType +//line mysql_sql.y:12098 + { + yyLOCAL = tree.ROW_FORMAT_DYNAMIC + } + yyVAL.union = yyLOCAL + case 1763: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.RowFormatType +//line mysql_sql.y:12102 + { + yyLOCAL = tree.ROW_FORMAT_FIXED + } + yyVAL.union = yyLOCAL + case 1764: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.RowFormatType +//line mysql_sql.y:12106 + { + yyLOCAL = tree.ROW_FORMAT_COMPRESSED + } + yyVAL.union = yyLOCAL + case 1765: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.RowFormatType +//line mysql_sql.y:12110 + { + yyLOCAL = tree.ROW_FORMAT_REDUNDANT + } + yyVAL.union = yyLOCAL + case 1766: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.RowFormatType +//line mysql_sql.y:12114 + { + yyLOCAL = tree.ROW_FORMAT_COMPACT + } + yyVAL.union = yyLOCAL + case 1771: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableNames +//line mysql_sql.y:12128 + { + yyLOCAL = tree.TableNames{yyDollar[1].tableNameUnion()} + } + yyVAL.union = yyLOCAL + case 1772: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableNames +//line mysql_sql.y:12132 + { + yyLOCAL = append(yyDollar[1].tableNamesUnion(), yyDollar[3].tableNameUnion()) + } + yyVAL.union = yyLOCAL + case 1773: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.TableName +//line mysql_sql.y:12141 + { + tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + prefix := tree.ObjectNamePrefix{ExplicitSchema: false} + yyLOCAL = tree.NewTableName(tree.Identifier(tblName), prefix, yyDollar[2].atTimeStampUnion()) + yyLOCAL.IcebergRef = yyDollar[3].icebergRefSpecUnion() + } + yyVAL.union = yyLOCAL + case 1774: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.TableName +//line mysql_sql.y:12148 + { + dbName := yylex.(*Lexer).GetDbOrTblName(yyDollar[1].cstrUnion().Origin()) + tblName := yylex.(*Lexer).GetDbOrTblName(yyDollar[3].cstrUnion().Origin()) + prefix := tree.ObjectNamePrefix{SchemaName: tree.Identifier(dbName), ExplicitSchema: true} + yyLOCAL = tree.NewTableName(tree.Identifier(tblName), prefix, yyDollar[4].atTimeStampUnion()) + yyLOCAL.IcebergRef = yyDollar[5].icebergRefSpecUnion() + } + yyVAL.union = yyLOCAL + case 1775: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.IcebergRefSpec +//line mysql_sql.y:12157 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1776: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IcebergRefSpec +//line mysql_sql.y:12161 + { + raw := fmt.Sprintf("%v", yyDollar[3].item) + yyLOCAL = tree.NewIcebergSnapshotRef(tree.NewNumVal(raw, raw, false, tree.P_int64)) + } + yyVAL.union = yyLOCAL + case 1777: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IcebergRefSpec +//line mysql_sql.y:12166 + { + yyLOCAL = tree.NewIcebergSnapshotRef(tree.NewNumVal(yyDollar[3].str, yyDollar[3].str, false, tree.P_char)) + } + yyVAL.union = yyLOCAL + case 1778: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.IcebergRefSpec +//line mysql_sql.y:12170 + { + yyLOCAL = tree.NewIcebergTimestampRef(tree.NewNumVal(yyDollar[6].str, yyDollar[6].str, false, tree.P_char)) + } + yyVAL.union = yyLOCAL + case 1779: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.IcebergRefSpec +//line mysql_sql.y:12174 + { + yyLOCAL = tree.NewIcebergTimestampRef(tree.NewNumVal(yyDollar[5].str, yyDollar[5].str, false, tree.P_char)) + } + yyVAL.union = yyLOCAL + case 1780: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.IcebergRefSpec +//line mysql_sql.y:12178 + { + yyLOCAL = tree.NewIcebergNamedRef(tree.Identifier(yyDollar[3].str)) + } + yyVAL.union = yyLOCAL + case 1781: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:12184 + { + yyVAL.str = yyDollar[1].str + } + case 1782: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:12188 + { + yyVAL.str = yyDollar[1].str + } + case 1783: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:12192 + { + yyVAL.str = yyDollar[1].str + } + case 1784: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.AtTimeStamp +//line mysql_sql.y:12197 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1785: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.AtTimeStamp +//line mysql_sql.y:12201 + { + yyLOCAL = &tree.AtTimeStamp{ + Type: tree.ATTIMESTAMPTIME, + Expr: yyDollar[4].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 1786: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.AtTimeStamp +//line mysql_sql.y:12208 + { + var str = yyDollar[4].cstrUnion().Compare() + yyLOCAL = &tree.AtTimeStamp{ + Type: tree.ATTIMESTAMPSNAPSHOT, + SnapshotName: yylex.(*Lexer).GetDbOrTblName(yyDollar[4].cstrUnion().Origin()), + Expr: tree.NewNumVal(str, str, false, tree.P_char), + } + } + yyVAL.union = yyLOCAL + case 1787: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.AtTimeStamp +//line mysql_sql.y:12217 + { + yyLOCAL = &tree.AtTimeStamp{ + Type: tree.ATTIMESTAMPSNAPSHOT, + SnapshotName: yyDollar[4].str, + Expr: tree.NewNumVal(yyDollar[4].str, yyDollar[4].str, false, tree.P_char), + } + } + yyVAL.union = yyLOCAL + case 1788: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.AtTimeStamp +//line mysql_sql.y:12225 + { + yyLOCAL = &tree.AtTimeStamp{ + Type: tree.ATMOTIMESTAMP, + Expr: yyDollar[4].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 1789: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.AtTimeStamp +//line mysql_sql.y:12232 + { + yyLOCAL = &tree.AtTimeStamp{ + Type: tree.ASOFTIMESTAMP, + Expr: tree.NewNumVal(yyDollar[5].str, yyDollar[5].str, false, tree.P_char), + } + } + yyVAL.union = yyLOCAL + case 1790: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.TableDefs +//line mysql_sql.y:12240 + { + yyLOCAL = tree.TableDefs(nil) + } + yyVAL.union = yyLOCAL + case 1792: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableDefs +//line mysql_sql.y:12247 + { + yyLOCAL = tree.TableDefs{yyDollar[1].tableDefUnion()} + } + yyVAL.union = yyLOCAL + case 1793: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.TableDefs +//line mysql_sql.y:12251 + { + yyLOCAL = append(yyDollar[1].tableDefsUnion(), yyDollar[3].tableDefUnion()) + } + yyVAL.union = yyLOCAL + case 1794: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12257 + { + yyLOCAL = tree.TableDef(yyDollar[1].columnTableDefUnion()) + } + yyVAL.union = yyLOCAL + case 1795: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12261 + { + yyLOCAL = yyDollar[1].tableDefUnion() + } + yyVAL.union = yyLOCAL + case 1796: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12265 + { + yyLOCAL = yyDollar[1].tableDefUnion() + } + yyVAL.union = yyLOCAL + case 1797: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12271 + { + yyLOCAL = yyDollar[1].tableDefUnion() + } + yyVAL.union = yyLOCAL + case 1798: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12275 + { + yyLOCAL = yyDollar[1].tableDefUnion() + } + yyVAL.union = yyLOCAL + case 1799: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12281 + { + var KeyParts = yyDollar[5].keyPartsUnion() + var Name = yyDollar[3].str + var Empty = true + var IndexOption = yyDollar[7].indexOptionUnion() + yyLOCAL = tree.NewFullTextIndex( + KeyParts, + Name, + Empty, + IndexOption, + ) + } + yyVAL.union = yyLOCAL + case 1800: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12294 + { + var KeyParts = yyDollar[5].keyPartsUnion() + var Name = yyDollar[3].str + var Empty = true + var IndexOption = yyDollar[9].indexOptionUnion() + yyLOCAL = tree.NewFullTextIndex( + KeyParts, + Name, + Empty, + IndexOption, + ) + } + yyVAL.union = yyLOCAL + case 1801: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12307 + { + var KeyParts = yyDollar[5].keyPartsUnion() + var Name = yyDollar[3].str + var Empty = true + var IndexOption = yyDollar[7].indexOptionUnion() + fti := tree.NewFullTextIndex( + KeyParts, + Name, + Empty, + IndexOption, + ) + fti.IsV2 = true + yyLOCAL = fti + } + yyVAL.union = yyLOCAL + case 1802: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12322 + { + keyTyp := tree.INDEX_TYPE_INVALID + if yyDollar[3].strsUnion()[1] != "" { + t := strings.ToLower(yyDollar[3].strsUnion()[1]) + switch t { + case "btree": + keyTyp = tree.INDEX_TYPE_BTREE + case "ivfflat": + keyTyp = tree.INDEX_TYPE_IVFFLAT + case "master": + keyTyp = tree.INDEX_TYPE_MASTER + case "hash": + keyTyp = tree.INDEX_TYPE_HASH + case "rtree": + keyTyp = tree.INDEX_TYPE_RTREE + case "zonemap": + keyTyp = tree.INDEX_TYPE_ZONEMAP + case "bsi": + keyTyp = tree.INDEX_TYPE_BSI + case "hnsw": + keyTyp = tree.INDEX_TYPE_HNSW + case "cagra": + keyTyp = tree.INDEX_TYPE_CAGRA + case "ivfpq": + keyTyp = tree.INDEX_TYPE_IVFPQ + default: + yylex.Error("Invalid the type of index") + goto ret1 + } + } + + var IfNotExists = yyDollar[2].ifNotExistsUnion() + var KeyParts = yyDollar[5].keyPartsUnion() + var Name = yyDollar[3].strsUnion()[0] + var KeyType = keyTyp + var IndexOption = yyDollar[7].indexOptionUnion() + yyLOCAL = tree.NewIndex( + IfNotExists, + KeyParts, + Name, + KeyType, + IndexOption, + ) + } + yyVAL.union = yyLOCAL + case 1803: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12367 + { + keyTyp := tree.INDEX_TYPE_INVALID + if yyDollar[3].strsUnion()[1] != "" { + t := strings.ToLower(yyDollar[3].strsUnion()[1]) + switch t { + case "btree": + keyTyp = tree.INDEX_TYPE_BTREE + case "ivfflat": + keyTyp = tree.INDEX_TYPE_IVFFLAT + case "master": + keyTyp = tree.INDEX_TYPE_MASTER + case "hash": + keyTyp = tree.INDEX_TYPE_HASH + case "rtree": + keyTyp = tree.INDEX_TYPE_RTREE + case "zonemap": + keyTyp = tree.INDEX_TYPE_ZONEMAP + case "bsi": + keyTyp = tree.INDEX_TYPE_BSI + case "hnsw": + keyTyp = tree.INDEX_TYPE_HNSW + case "cagra": + keyTyp = tree.INDEX_TYPE_CAGRA + case "ivfpq": + keyTyp = tree.INDEX_TYPE_IVFPQ + default: + yylex.Error("Invalid type of index") + goto ret1 + } + } + var IfNotExists = yyDollar[2].ifNotExistsUnion() + var KeyParts = yyDollar[5].keyPartsUnion() + var Name = yyDollar[3].strsUnion()[0] + var KeyType = keyTyp + var IndexOption = yyDollar[9].indexOptionUnion() + yyLOCAL = tree.NewIndex( + IfNotExists, + KeyParts, + Name, + KeyType, + IndexOption, + ) + } + yyVAL.union = yyLOCAL + case 1804: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12412 + { + if yyDollar[1].str != "" { + switch v := yyDollar[2].tableDefUnion().(type) { + case *tree.PrimaryKeyIndex: + v.ConstraintSymbol = yyDollar[1].str + case *tree.ForeignKey: + v.ConstraintSymbol = yyDollar[1].str + case *tree.UniqueIndex: + v.ConstraintSymbol = yyDollar[1].str + case *tree.CheckIndex: + v.ConstraintSymbol = yyDollar[1].str + } + } + yyLOCAL = yyDollar[2].tableDefUnion() + } + yyVAL.union = yyLOCAL + case 1805: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12427 + { + yyLOCAL = yyDollar[1].tableDefUnion() + } + yyVAL.union = yyLOCAL + case 1806: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12433 + { + var KeyParts = yyDollar[5].keyPartsUnion() + var Name = yyDollar[3].strsUnion()[0] + var Empty = yyDollar[3].strsUnion()[1] == "" + var IndexOption = yyDollar[7].indexOptionUnion() + yyLOCAL = tree.NewPrimaryKeyIndex( + KeyParts, + Name, + Empty, + IndexOption, + ) + } + yyVAL.union = yyLOCAL + case 1807: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12446 + { + var KeyParts = yyDollar[5].keyPartsUnion() + var Name = yyDollar[3].strsUnion()[0] + var Empty = yyDollar[3].strsUnion()[1] == "" + var IndexOption = yyDollar[9].indexOptionUnion() + yyLOCAL = tree.NewPrimaryKeyIndex( + KeyParts, + Name, + Empty, + IndexOption, + ) + } + yyVAL.union = yyLOCAL + case 1808: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12459 + { + var KeyParts = yyDollar[5].keyPartsUnion() + var Name = yyDollar[3].strsUnion()[0] + var Empty = yyDollar[3].strsUnion()[1] == "" + var IndexOption = yyDollar[7].indexOptionUnion() + yyLOCAL = tree.NewUniqueIndex( + KeyParts, + Name, + Empty, + IndexOption, + ) + } + yyVAL.union = yyLOCAL + case 1809: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12472 + { + var KeyParts = yyDollar[5].keyPartsUnion() + var Name = yyDollar[3].strsUnion()[0] + var Empty = yyDollar[3].strsUnion()[1] == "" + var IndexOption = yyDollar[9].indexOptionUnion() + yyLOCAL = tree.NewUniqueIndex( + KeyParts, + Name, + Empty, + IndexOption, + ) + } + yyVAL.union = yyLOCAL + case 1810: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12485 + { + var IfNotExists = yyDollar[3].ifNotExistsUnion() + var KeyParts = yyDollar[6].keyPartsUnion() + var Name = tree.NewCStr(yyDollar[4].str, 1).Compare() + var Refer = yyDollar[8].attributeReferenceUnion() + var Empty = true + yyLOCAL = tree.NewForeignKey( + IfNotExists, + KeyParts, + Name, + Refer, + Empty, + ) + } + yyVAL.union = yyLOCAL + case 1811: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.TableDef +//line mysql_sql.y:12500 + { + var Expr = yyDollar[3].exprUnion() + var Enforced = yyDollar[5].boolValUnion() + yyLOCAL = tree.NewCheckIndex( + Expr, + Enforced, + ) + } + yyVAL.union = yyLOCAL + case 1812: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:12510 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1814: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:12516 + { + yyVAL.str = "" + } + case 1815: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:12520 + { + yyVAL.str = yyDollar[1].str + } + case 1818: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:12530 + { + yyLOCAL = make([]string, 2) + yyLOCAL[0] = yyDollar[1].str + yyLOCAL[1] = "" + } + yyVAL.union = yyLOCAL + case 1819: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:12536 + { + yyLOCAL = make([]string, 2) + yyLOCAL[0] = yyDollar[1].str + yyLOCAL[1] = yyDollar[3].str + } + yyVAL.union = yyLOCAL + case 1820: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:12542 + { + yyLOCAL = make([]string, 2) + yyLOCAL[0] = yyDollar[1].cstrUnion().Origin() + yyLOCAL[1] = yyDollar[3].str + } + yyVAL.union = yyLOCAL + case 1835: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:12567 + { + yyVAL.str = "" + } + case 1836: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:12571 + { + yyVAL.str = yyDollar[1].cstrUnion().Origin() + } + case 1837: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.ColumnTableDef +//line mysql_sql.y:12577 + { + yyLOCAL = tree.NewColumnTableDef(yyDollar[1].unresolvedNameUnion(), yyDollar[2].columnTypeUnion(), yyDollar[3].columnAttributesUnion()) + } + yyVAL.union = yyLOCAL + case 1838: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:12583 + { + yyLOCAL = tree.NewUnresolvedName(yyDollar[1].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 1839: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:12587 + { + tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedName(tblNameCStr, yyDollar[3].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 1840: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:12592 + { + dbNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) + tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[3].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedName(dbNameCStr, tblNameCStr, yyDollar[5].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 1841: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:12600 + { + if rejectSQLModeReservedFunctionName(yylex, yyDollar[1].str) { + goto ret1 + } + yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) + } + yyVAL.union = yyLOCAL + case 1842: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:12604 + { + yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) + } + yyVAL.union = yyLOCAL + case 1843: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:12608 + { + if rejectSQLModeReservedFunctionName(yylex, yyDollar[1].str) { + goto ret1 + } + yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) + } + yyVAL.union = yyLOCAL + case 1844: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:12612 + { + if rejectSQLModeReservedFunctionName(yylex, yyDollar[1].str) { + goto ret1 + } + yyLOCAL = tree.NewCStr(yyDollar[1].str, 1) + } + yyVAL.union = yyLOCAL + case 1845: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:12618 + { + yyLOCAL = yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) + } + yyVAL.union = yyLOCAL + case 1846: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:12624 + { + yyLOCAL = tree.NewUnresolvedName(yyDollar[1].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 1847: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:12628 + { + tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedName(tblNameCStr, yyDollar[3].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 1848: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.UnresolvedName +//line mysql_sql.y:12633 + { + dbNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[1].cstrUnion().Origin()) + tblNameCStr := yylex.(*Lexer).GetDbOrTblNameCStr(yyDollar[3].cstrUnion().Origin()) + yyLOCAL = tree.NewUnresolvedName(dbNameCStr, tblNameCStr, yyDollar[5].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 1849: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []tree.ColumnAttribute +//line mysql_sql.y:12640 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1850: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.ColumnAttribute +//line mysql_sql.y:12644 + { + yyLOCAL = yyDollar[1].columnAttributesUnion() + } + yyVAL.union = yyLOCAL + case 1851: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []tree.ColumnAttribute +//line mysql_sql.y:12650 + { + yyLOCAL = []tree.ColumnAttribute{yyDollar[1].columnAttributeUnion()} + } + yyVAL.union = yyLOCAL + case 1852: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []tree.ColumnAttribute +//line mysql_sql.y:12654 + { + yyLOCAL = append(yyDollar[1].columnAttributesUnion(), yyDollar[2].columnAttributeUnion()) + } + yyVAL.union = yyLOCAL + case 1853: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12660 + { + yyLOCAL = tree.NewAttributeNull(true) + } + yyVAL.union = yyLOCAL + case 1854: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12664 + { + yyLOCAL = tree.NewAttributeNull(false) + } + yyVAL.union = yyLOCAL + case 1855: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12668 + { + yyLOCAL = tree.NewAttributeNull(false) + } + yyVAL.union = yyLOCAL + case 1856: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12672 + { + yyLOCAL = tree.NewAttributeDefault(yyDollar[2].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1857: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12676 + { + yyLOCAL = tree.NewAttributeAutoIncrement() + } + yyVAL.union = yyLOCAL + case 1858: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12680 + { + yyLOCAL = yyDollar[1].columnAttributeUnion() + } + yyVAL.union = yyLOCAL + case 1859: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12684 + { + str := util.DealCommentString(yyDollar[2].str) + yyLOCAL = tree.NewAttributeComment(tree.NewNumVal(str, str, false, tree.P_char)) + } + yyVAL.union = yyLOCAL + case 1860: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12689 + { + yyLOCAL = tree.NewAttributeMongoDBPath(yyDollar[2].str) + } + yyVAL.union = yyLOCAL + case 1861: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12693 + { + yyLOCAL = tree.NewAttributeMongoDBConvert(yyDollar[2].str) + } + yyVAL.union = yyLOCAL + case 1862: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12697 + { + yyLOCAL = tree.NewAttributeCollate(yyDollar[2].str) + } + yyVAL.union = yyLOCAL + case 1863: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12701 + { + yyLOCAL = tree.NewAttributeColumnFormat(yyDollar[2].str) + } + yyVAL.union = yyLOCAL + case 1864: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12705 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1865: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12709 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1866: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12713 + { + yyLOCAL = tree.NewAttributeStorage(yyDollar[2].str) + } + yyVAL.union = yyLOCAL + case 1867: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12717 + { + yyLOCAL = tree.NewAttributeAutoRandom(int(yyDollar[2].int64ValUnion())) + } + yyVAL.union = yyLOCAL + case 1868: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12721 + { + yyLOCAL = yyDollar[1].attributeReferenceUnion() + } + yyVAL.union = yyLOCAL + case 1869: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12725 + { + yyLOCAL = tree.NewAttributeCheckConstraint(yyDollar[4].exprUnion(), true, yyDollar[1].str) + } + yyVAL.union = yyLOCAL + case 1870: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12729 + { + yyLOCAL = tree.NewAttributeCheckConstraint(yyDollar[4].exprUnion(), yyDollar[6].boolValUnion(), yyDollar[1].str) + } + yyVAL.union = yyLOCAL + case 1871: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12733 + { + name := tree.NewUnresolvedColName(yyDollar[3].str) + var es tree.Exprs = nil + if yyDollar[4].exprUnion() != nil { + es = append(es, yyDollar[4].exprUnion()) + } + expr := &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[3].str, 1), + Exprs: es, + } + yyLOCAL = tree.NewAttributeOnUpdate(expr) + } + yyVAL.union = yyLOCAL + case 1872: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12747 + { + v, errStr := util.GetInt64(yyDollar[2].item) + if errStr != "" { + yylex.Error(errStr) + goto ret1 + } + if v < 0 || v > 4294967295 { + yylex.Error("SRID should be between 0 and 4294967295") + goto ret1 + } + yyLOCAL = tree.NewAttributeSRID(uint32(v)) + } + yyVAL.union = yyLOCAL + case 1873: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12760 + { + yyLOCAL = tree.NewAttributeLowCardinality() + } + yyVAL.union = yyLOCAL + case 1874: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12764 + { + yyLOCAL = tree.NewAttributeVisable(true) + } + yyVAL.union = yyLOCAL + case 1875: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12768 + { + yyLOCAL = tree.NewAttributeVisable(false) + } + yyVAL.union = yyLOCAL + case 1876: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12772 + { + yyLOCAL = tree.NewAttributeCharset(yyDollar[5].str) + } + yyVAL.union = yyLOCAL + case 1877: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12776 + { + yyLOCAL = tree.NewAttributeGeneratedAlways(yyDollar[5].exprUnion(), yyDollar[7].boolValUnion()) + } + yyVAL.union = yyLOCAL + case 1878: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:12780 + { + yyLOCAL = tree.NewAttributeGeneratedAlways(yyDollar[3].exprUnion(), yyDollar[5].boolValUnion()) + } + yyVAL.union = yyLOCAL + case 1879: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:12785 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1880: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:12789 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1881: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:12793 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1882: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:12799 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 1883: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:12803 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1884: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:12807 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 1885: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:12812 + { + yyVAL.str = "" + } + case 1886: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:12816 + { + yyVAL.str = yyDollar[1].str + } + case 1887: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:12822 + { + yyVAL.str = "" + } + case 1888: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:12826 + { + yyVAL.str = yyDollar[2].cstrUnion().Compare() + } + case 1889: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.AttributeReference +//line mysql_sql.y:12832 + { + var TableName = yyDollar[2].tableNameUnion() + var KeyParts = yyDollar[3].keyPartsUnion() + var Match = yyDollar[4].matchTypeUnion() + var OnDelete = yyDollar[5].referenceOnRecordUnion().OnDelete + var OnUpdate = yyDollar[5].referenceOnRecordUnion().OnUpdate + yyLOCAL = tree.NewAttributeReference( + TableName, + KeyParts, + Match, + OnDelete, + OnUpdate, + ) + } + yyVAL.union = yyLOCAL + case 1890: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.ReferenceOnRecord +//line mysql_sql.y:12849 + { + yyLOCAL = &tree.ReferenceOnRecord{ + OnDelete: tree.REFERENCE_OPTION_INVALID, + OnUpdate: tree.REFERENCE_OPTION_INVALID, + } + } + yyVAL.union = yyLOCAL + case 1891: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.ReferenceOnRecord +//line mysql_sql.y:12856 + { + yyLOCAL = &tree.ReferenceOnRecord{ + OnDelete: yyDollar[1].referenceOptionTypeUnion(), + OnUpdate: tree.REFERENCE_OPTION_INVALID, + } + } + yyVAL.union = yyLOCAL + case 1892: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.ReferenceOnRecord +//line mysql_sql.y:12863 + { + yyLOCAL = &tree.ReferenceOnRecord{ + OnDelete: tree.REFERENCE_OPTION_INVALID, + OnUpdate: yyDollar[1].referenceOptionTypeUnion(), + } + } + yyVAL.union = yyLOCAL + case 1893: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.ReferenceOnRecord +//line mysql_sql.y:12870 + { + yyLOCAL = &tree.ReferenceOnRecord{ + OnDelete: yyDollar[1].referenceOptionTypeUnion(), + OnUpdate: yyDollar[2].referenceOptionTypeUnion(), + } + } + yyVAL.union = yyLOCAL + case 1894: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.ReferenceOnRecord +//line mysql_sql.y:12877 + { + yyLOCAL = &tree.ReferenceOnRecord{ + OnDelete: yyDollar[2].referenceOptionTypeUnion(), + OnUpdate: yyDollar[1].referenceOptionTypeUnion(), + } + } + yyVAL.union = yyLOCAL + case 1895: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.ReferenceOptionType +//line mysql_sql.y:12886 + { + yyLOCAL = yyDollar[3].referenceOptionTypeUnion() + } + yyVAL.union = yyLOCAL + case 1896: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.ReferenceOptionType +//line mysql_sql.y:12892 + { + yyLOCAL = yyDollar[3].referenceOptionTypeUnion() + } + yyVAL.union = yyLOCAL + case 1897: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ReferenceOptionType +//line mysql_sql.y:12898 + { + yyLOCAL = tree.REFERENCE_OPTION_RESTRICT + } + yyVAL.union = yyLOCAL + case 1898: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ReferenceOptionType +//line mysql_sql.y:12902 + { + yyLOCAL = tree.REFERENCE_OPTION_CASCADE + } + yyVAL.union = yyLOCAL + case 1899: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ReferenceOptionType +//line mysql_sql.y:12906 + { + yyLOCAL = tree.REFERENCE_OPTION_SET_NULL + } + yyVAL.union = yyLOCAL + case 1900: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ReferenceOptionType +//line mysql_sql.y:12910 + { + yyLOCAL = tree.REFERENCE_OPTION_NO_ACTION + } + yyVAL.union = yyLOCAL + case 1901: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ReferenceOptionType +//line mysql_sql.y:12914 + { + yyLOCAL = tree.REFERENCE_OPTION_SET_DEFAULT + } + yyVAL.union = yyLOCAL + case 1902: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.MatchType +//line mysql_sql.y:12919 + { + yyLOCAL = tree.MATCH_INVALID + } + yyVAL.union = yyLOCAL + case 1904: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.MatchType +//line mysql_sql.y:12926 + { + yyLOCAL = tree.MATCH_FULL + } + yyVAL.union = yyLOCAL + case 1905: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.MatchType +//line mysql_sql.y:12930 + { + yyLOCAL = tree.MATCH_PARTIAL + } + yyVAL.union = yyLOCAL + case 1906: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.MatchType +//line mysql_sql.y:12934 + { + yyLOCAL = tree.MATCH_SIMPLE + } + yyVAL.union = yyLOCAL + case 1907: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.FullTextSearchType +//line mysql_sql.y:12939 + { + yyLOCAL = tree.FULLTEXT_DEFAULT + } + yyVAL.union = yyLOCAL + case 1908: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.FullTextSearchType +//line mysql_sql.y:12943 + { + yyLOCAL = tree.FULLTEXT_NL + } + yyVAL.union = yyLOCAL + case 1909: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.FullTextSearchType +//line mysql_sql.y:12947 + { + yyLOCAL = tree.FULLTEXT_NL_QUERY_EXPANSION + } + yyVAL.union = yyLOCAL + case 1910: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.FullTextSearchType +//line mysql_sql.y:12951 + { + yyLOCAL = tree.FULLTEXT_BOOLEAN + } + yyVAL.union = yyLOCAL + case 1911: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.FullTextSearchType +//line mysql_sql.y:12955 + { + yyLOCAL = tree.FULLTEXT_QUERY_EXPANSION + } + yyVAL.union = yyLOCAL + case 1912: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.FullTextSearchType +//line mysql_sql.y:12959 + { + yyLOCAL = tree.FULLTEXT_BM25 + } + yyVAL.union = yyLOCAL + case 1913: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL []*tree.KeyPart +//line mysql_sql.y:12964 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1914: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []*tree.KeyPart +//line mysql_sql.y:12968 + { + yyLOCAL = yyDollar[2].keyPartsUnion() + } + yyVAL.union = yyLOCAL + case 1915: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:12973 + { + yyLOCAL = -1 + } + yyVAL.union = yyLOCAL + case 1916: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL int64 +//line mysql_sql.y:12977 + { + value, ok := signedIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + yyLOCAL = value + } + yyVAL.union = yyLOCAL + case 1923: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.Subquery +//line mysql_sql.y:12995 + { + yyLOCAL = &tree.Subquery{Select: yyDollar[1].selectStatementUnion(), Exists: false} + } + yyVAL.union = yyLOCAL + case 1924: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13001 + { + yyLOCAL = tree.NewBinaryExpr(tree.BIT_AND, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1925: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13005 + { + yyLOCAL = tree.NewBinaryExpr(tree.BIT_OR, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1926: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13009 + { + yyLOCAL = tree.NewBinaryExpr(tree.BIT_XOR, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1927: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13013 + { + yyLOCAL = tree.NewBinaryExpr(tree.PLUS, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1928: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13017 + { + yyLOCAL = tree.NewBinaryExpr(tree.MINUS, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1929: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13021 + { + yyLOCAL = tree.NewBinaryExpr(tree.MULTI, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1930: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13025 + { + yyLOCAL = tree.NewBinaryExpr(tree.DIV, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1931: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13029 + { + yyLOCAL = tree.NewBinaryExpr(tree.INTEGER_DIV, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1932: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13033 + { + yyLOCAL = tree.NewBinaryExpr(tree.MOD, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1933: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13037 + { + yyLOCAL = tree.NewBinaryExpr(tree.MOD, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1934: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13041 + { + yyLOCAL = tree.NewBinaryExpr(tree.LEFT_SHIFT, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1935: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13045 + { + yyLOCAL = tree.NewBinaryExpr(tree.RIGHT_SHIFT, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1936: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13049 + { + name := tree.NewUnresolvedColName("json_extract") + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr("json_extract", 1), + Exprs: tree.Exprs{yyDollar[1].exprUnion(), yyDollar[3].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 1937: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13058 + { + extractName := tree.NewUnresolvedColName("json_extract") + inner := &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(extractName), + FuncName: tree.NewCStr("json_extract", 1), + Exprs: tree.Exprs{yyDollar[1].exprUnion(), yyDollar[3].exprUnion()}, + } + unquoteName := tree.NewUnresolvedColName("json_unquote") + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(unquoteName), + FuncName: tree.NewCStr("json_unquote", 1), + Exprs: tree.Exprs{inner}, + } + } + yyVAL.union = yyLOCAL + case 1938: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13073 + { + yyLOCAL = yyDollar[1].exprUnion() + } + yyVAL.union = yyLOCAL + case 1939: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13079 + { + yyLOCAL = yyDollar[1].unresolvedNameUnion() + } + yyVAL.union = yyLOCAL + case 1940: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13083 + { + yyLOCAL = yyDollar[1].varExprUnion() + } + yyVAL.union = yyLOCAL + case 1941: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13087 + { + yyLOCAL = yyDollar[1].exprUnion() + } + yyVAL.union = yyLOCAL + case 1942: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13091 + { + name := tree.NewUnresolvedColName("concat") + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr("concat", 1), + Exprs: tree.Exprs{yyDollar[1].exprUnion(), yyDollar[3].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 1943: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13100 + { + yyLOCAL = tree.NewParentExpr(yyDollar[2].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1944: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13104 + { + yyLOCAL = tree.NewTuple(append(yyDollar[2].exprsUnion(), yyDollar[4].exprUnion())) + } + yyVAL.union = yyLOCAL + case 1945: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13108 + { + yyLOCAL = tree.NewUnaryExpr(tree.UNARY_PLUS, yyDollar[2].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1946: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13112 + { + yyLOCAL = tree.NewUnaryExpr(tree.UNARY_MINUS, yyDollar[2].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1947: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13116 + { + yyLOCAL = tree.NewUnaryExpr(tree.UNARY_TILDE, yyDollar[2].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1948: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13120 + { + yyLOCAL = tree.NewUnaryExpr(tree.UNARY_MARK, yyDollar[2].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1949: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13124 + { + yyLOCAL = tree.NewNotExpr(yyDollar[2].exprUnion()) + } + yyVAL.union = yyLOCAL + case 1950: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13128 + { + hint := strings.ToLower(yyDollar[2].cstrUnion().Compare()) + switch hint { + case "d": + locale := "" + t := &tree.T{ + InternalType: tree.InternalType{ + Family: tree.TimestampFamily, + FamilyString: "DATETIME", + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DATETIME), + }, + } + yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), t) + case "t": + locale := "" + t := &tree.T{ + InternalType: tree.InternalType{ + Family: tree.TimeFamily, + FamilyString: "TIME", + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TIME), + }, + } + yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), t) + case "ts": + locale := "" + t := &tree.T{ + InternalType: tree.InternalType{ + Family: tree.TimestampFamily, + FamilyString: "TIMESTAMP", + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TIMESTAMP), + }, + } + yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), t) + default: + yylex.Error("Invalid type") + return 1 + } + } + yyVAL.union = yyLOCAL + case 1951: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13170 + { + yyLOCAL = yyDollar[1].exprUnion() + } + yyVAL.union = yyLOCAL + case 1952: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13174 + { + yyLOCAL = yyDollar[1].subqueryUnion() + } + yyVAL.union = yyLOCAL + case 1953: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13178 + { + yyDollar[2].subqueryUnion().Exists = true + yyLOCAL = yyDollar[2].subqueryUnion() + } + yyVAL.union = yyLOCAL + case 1954: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13183 + { + yyLOCAL = &tree.CaseExpr{ + Expr: yyDollar[2].exprUnion(), + Whens: yyDollar[3].whenClauseListUnion(), + Else: yyDollar[4].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 1955: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13191 + { + yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), yyDollar[5].columnTypeUnion()) + } + yyVAL.union = yyLOCAL + case 1956: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13195 + { + yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), makeCharsetCastCharType(yyDollar[6].lengthOptUnion(), yyDollar[9].str)) + } + yyVAL.union = yyLOCAL + case 1957: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13199 + { + yyLOCAL = tree.NewSerialExtractExpr(yyDollar[3].exprUnion(), yyDollar[5].exprUnion(), yyDollar[7].columnTypeUnion()) + } + yyVAL.union = yyLOCAL + case 1958: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13203 + { + yyLOCAL = tree.NewBitCastExpr(yyDollar[3].exprUnion(), yyDollar[5].columnTypeUnion()) + } + yyVAL.union = yyLOCAL + case 1959: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13207 + { + yyLOCAL = tree.NewCastExpr(yyDollar[1].exprUnion(), yyDollar[3].columnTypeUnion()) + } + yyVAL.union = yyLOCAL + case 1960: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13211 + { + yyLOCAL = tree.NewCastExpr(yyDollar[3].exprUnion(), yyDollar[5].columnTypeUnion()) + } + yyVAL.union = yyLOCAL + case 1961: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13215 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + es := tree.NewNumVal(yyDollar[5].str, yyDollar[5].str, false, tree.P_char) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion(), es}, + } + } + yyVAL.union = yyLOCAL + case 1962: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13225 + { + yyLOCAL = yyDollar[1].funcExprUnion() + } + yyVAL.union = yyLOCAL + case 1963: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13229 + { + yyLOCAL = yyDollar[1].funcExprUnion() + } + yyVAL.union = yyLOCAL + case 1964: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13233 + { + yyLOCAL = yyDollar[1].funcExprUnion() + } + yyVAL.union = yyLOCAL + case 1965: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13237 + { + yyLOCAL = yyDollar[1].funcExprUnion() + } + yyVAL.union = yyLOCAL + case 1966: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13241 + { + yyLOCAL = yyDollar[1].funcExprUnion() + } + yyVAL.union = yyLOCAL + case 1967: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13245 + { + yyLOCAL = yyDollar[1].exprUnion() + } + yyVAL.union = yyLOCAL + case 1968: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13249 + { + yyLOCAL = &tree.CollateExpr{Expr: yyDollar[1].exprUnion(), Collation: yyDollar[3].str} + } + yyVAL.union = yyLOCAL + case 1969: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13253 + { + val, err := tree.NewFullTextMatchFuncExpression(yyDollar[3].keyPartsUnion(), yyDollar[7].exprUnion(), yyDollar[8].fullTextSearchTypeUnion()) + if err != nil { + yylex.Error(err.Error()) + goto ret1 + } + yyLOCAL = val + } + yyVAL.union = yyLOCAL + case 1970: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13263 + { + yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_char) + } + yyVAL.union = yyLOCAL + case 1971: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13267 + { + yyLOCAL = tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()) + } + yyVAL.union = yyLOCAL + case 1972: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13271 + { + yyLOCAL = tree.NewUnresolvedName(yyDollar[1].cstrUnion()) + } + yyVAL.union = yyLOCAL + case 1973: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13277 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + WindowSpec: yyDollar[4].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1974: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13286 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + WindowSpec: yyDollar[4].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1975: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13295 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + WindowSpec: yyDollar[4].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1976: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13304 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + WindowSpec: yyDollar[4].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1977: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13313 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion()}, + WindowSpec: yyDollar[5].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1978: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13323 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + WindowSpec: yyDollar[4].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1979: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13332 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion()}, + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1980: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13342 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, + WindowSpec: yyDollar[8].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1981: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13352 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion(), yyDollar[7].exprUnion()}, + WindowSpec: yyDollar[10].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1982: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13362 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion()}, + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1983: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13372 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, + WindowSpec: yyDollar[8].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1984: + yyDollar = yyS[yypt-10 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13382 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion(), yyDollar[7].exprUnion()}, + WindowSpec: yyDollar[10].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1985: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13392 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion()}, + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1986: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13402 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion()}, + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1987: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13412 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, + WindowSpec: yyDollar[9].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 1988: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13424 + { + value, ok := signedIntegral(yylex, yyDollar[5].item) + if !ok { + goto ret1 + } + v := int(value) + val, err := tree.NewSampleRowsFuncExpression(v, true, nil, "block") + if err != nil { + yylex.Error(err.Error()) + goto ret1 + } + yyLOCAL = val + } + yyVAL.union = yyLOCAL + case 1989: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13436 + { + value, ok := signedIntegral(yylex, yyDollar[5].item) + if !ok { + goto ret1 + } + v := int(value) + val, err := tree.NewSampleRowsFuncExpression(v, true, nil, yyDollar[8].str) + if err != nil { + yylex.Error(err.Error()) + goto ret1 + } + yyLOCAL = val + } + yyVAL.union = yyLOCAL + case 1990: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13448 + { + value, ok := signedIntegral(yylex, yyDollar[5].item) + if !ok { + goto ret1 + } + val, err := tree.NewSamplePercentFuncExpression1(value, true, nil) + if err != nil { + yylex.Error(err.Error()) + goto ret1 + } + yyLOCAL = val + } + yyVAL.union = yyLOCAL + case 1991: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13459 + { + val, err := tree.NewSamplePercentFuncExpression2(yyDollar[5].item.(float64), true, nil) + if err != nil { + yylex.Error(err.Error()) + goto ret1 + } + yyLOCAL = val + } + yyVAL.union = yyLOCAL + case 1992: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13469 + { + value, ok := signedIntegral(yylex, yyDollar[5].item) + if !ok { + goto ret1 + } + v := int(value) + val, err := tree.NewSampleRowsFuncExpression(v, false, yyDollar[3].exprsUnion(), "block") + if err != nil { + yylex.Error(err.Error()) + goto ret1 + } + yyLOCAL = val + } + yyVAL.union = yyLOCAL + case 1993: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13481 + { + value, ok := signedIntegral(yylex, yyDollar[5].item) + if !ok { + goto ret1 + } + v := int(value) + val, err := tree.NewSampleRowsFuncExpression(v, false, yyDollar[3].exprsUnion(), yyDollar[8].str) + if err != nil { + yylex.Error(err.Error()) + goto ret1 + } + yyLOCAL = val + } + yyVAL.union = yyLOCAL + case 1994: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13493 + { + value, ok := signedIntegral(yylex, yyDollar[5].item) + if !ok { + goto ret1 + } + val, err := tree.NewSamplePercentFuncExpression1(value, false, yyDollar[3].exprsUnion()) + if err != nil { + yylex.Error(err.Error()) + goto ret1 + } + yyLOCAL = val + } + yyVAL.union = yyLOCAL + case 1995: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13504 + { + val, err := tree.NewSamplePercentFuncExpression2(yyDollar[5].item.(float64), false, yyDollar[3].exprsUnion()) + if err != nil { + yylex.Error(err.Error()) + goto ret1 + } + yyLOCAL = val + } + yyVAL.union = yyLOCAL + case 1996: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13514 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1997: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13518 + { + yyLOCAL = yyDollar[2].exprUnion() + } + yyVAL.union = yyLOCAL + case 1998: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13523 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 1999: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:13527 + { + yyLOCAL = yyDollar[1].exprUnion() + } + yyVAL.union = yyLOCAL + case 2000: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []*tree.When +//line mysql_sql.y:13533 + { + yyLOCAL = []*tree.When{yyDollar[1].whenClauseUnion()} + } + yyVAL.union = yyLOCAL + case 2001: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL []*tree.When +//line mysql_sql.y:13537 + { + yyLOCAL = append(yyDollar[1].whenClauseListUnion(), yyDollar[2].whenClauseUnion()) + } + yyVAL.union = yyLOCAL + case 2002: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.When +//line mysql_sql.y:13543 + { + yyLOCAL = &tree.When{ + Cond: yyDollar[2].exprUnion(), + Val: yyDollar[4].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 2003: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:13552 + { + t := yyVAL.columnTypeUnion() + str := strings.ToLower(t.InternalType.FamilyString) + if str == "binary" { + t.InternalType.Scale = -1 + } else if str == "char" { + if t.InternalType.DisplayWith == -1 { + t.InternalType.FamilyString = "varchar" + t.InternalType.Oid = uint32(defines.MYSQL_TYPE_VARCHAR) + } + } + } + case 2004: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13564 + { + name := yyDollar[1].str + if yyDollar[2].str != "" { + name = yyDollar[2].str + } + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: name, + Width: 64, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_LONGLONG), + }, + } + } + yyVAL.union = yyLOCAL + case 2005: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13581 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[2].str, + Width: 64, + Locale: &locale, + Unsigned: true, + Oid: uint32(defines.MYSQL_TYPE_LONGLONG), + }, + } + } + yyVAL.union = yyLOCAL + case 2007: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13598 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.JsonFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_JSON), + }, + } + } + yyVAL.union = yyLOCAL + case 2008: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13610 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.StringFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_VARCHAR), + DisplayWith: yyDollar[2].lengthOptUnion(), + Scale: -1, + }, + } + } + yyVAL.union = yyLOCAL + case 2009: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13624 + { + locale := "" + oid := uint32(defines.MYSQL_TYPE_STRING) + familyString := yyDollar[1].str + if yyDollar[2].lengthOptUnion() == -1 { + oid = uint32(defines.MYSQL_TYPE_VARCHAR) + familyString = "varchar" + } + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.StringFamily, + FamilyString: familyString, + Locale: &locale, + Oid: oid, + DisplayWith: yyDollar[2].lengthOptUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 2010: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13643 + { + yyLOCAL = makeCharsetCastCharType(yyDollar[2].lengthOptUnion(), yyDollar[5].str) + } + yyVAL.union = yyLOCAL + case 2011: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13647 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.DateFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DATE), + }, + } + } + yyVAL.union = yyLOCAL + case 2012: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13659 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + Width: 16, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_YEAR), + }, + } + } + yyVAL.union = yyLOCAL + case 2013: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13673 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.TimestampFamily, + Scale: yyDollar[2].lengthOptUnion(), + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + TimePrecisionIsSet: false, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DATETIME), + }, + } + } + yyVAL.union = yyLOCAL + case 2014: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13688 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.TimeFamily, + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + Scale: yyDollar[2].lengthOptUnion(), + TimePrecisionIsSet: false, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TIME), + }, + } + } + yyVAL.union = yyLOCAL + case 2015: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13703 + { + name := yyDollar[1].str + if yyDollar[2].str != "" { + name = yyDollar[2].str + } + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: name, + Width: 64, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_LONGLONG), + }, + } + } + yyVAL.union = yyLOCAL + case 2016: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:13720 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[2].str, + Width: 64, + Locale: &locale, + Unsigned: true, + Oid: uint32(defines.MYSQL_TYPE_LONGLONG), + }, + } + } + yyVAL.union = yyLOCAL + case 2017: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:13736 + { + yyVAL.str = "" + } + case 2021: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FrameBound +//line mysql_sql.y:13745 + { + yyLOCAL = &tree.FrameBound{Type: tree.Following, UnBounded: true} + } + yyVAL.union = yyLOCAL + case 2022: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FrameBound +//line mysql_sql.y:13749 + { + yyLOCAL = &tree.FrameBound{Type: tree.Following, Expr: yyDollar[1].exprUnion()} + } + yyVAL.union = yyLOCAL + case 2023: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FrameBound +//line mysql_sql.y:13753 + { + yyLOCAL = &tree.FrameBound{Type: tree.Following, Expr: tree.NewParamExpr(yylex.(*Lexer).GetParamIndex())} + } + yyVAL.union = yyLOCAL + case 2024: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FrameBound +//line mysql_sql.y:13757 + { + yyLOCAL = &tree.FrameBound{Type: tree.Following, Expr: yyDollar[1].exprUnion()} + } + yyVAL.union = yyLOCAL + case 2025: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FrameBound +//line mysql_sql.y:13763 + { + yyLOCAL = &tree.FrameBound{Type: tree.CurrentRow} + } + yyVAL.union = yyLOCAL + case 2026: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FrameBound +//line mysql_sql.y:13767 + { + yyLOCAL = &tree.FrameBound{Type: tree.Preceding, UnBounded: true} + } + yyVAL.union = yyLOCAL + case 2027: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FrameBound +//line mysql_sql.y:13771 + { + yyLOCAL = &tree.FrameBound{Type: tree.Preceding, Expr: yyDollar[1].exprUnion()} + } + yyVAL.union = yyLOCAL + case 2028: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FrameBound +//line mysql_sql.y:13775 + { + yyLOCAL = &tree.FrameBound{Type: tree.Preceding, Expr: tree.NewParamExpr(yylex.(*Lexer).GetParamIndex())} + } + yyVAL.union = yyLOCAL + case 2029: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FrameBound +//line mysql_sql.y:13779 + { + yyLOCAL = &tree.FrameBound{Type: tree.Preceding, Expr: yyDollar[1].exprUnion()} + } + yyVAL.union = yyLOCAL + case 2030: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FrameType +//line mysql_sql.y:13785 + { + yyLOCAL = tree.Rows + } + yyVAL.union = yyLOCAL + case 2031: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FrameType +//line mysql_sql.y:13789 + { + yyLOCAL = tree.Range + } + yyVAL.union = yyLOCAL + case 2032: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FrameType +//line mysql_sql.y:13793 + { + yyLOCAL = tree.Groups + } + yyVAL.union = yyLOCAL + case 2033: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FrameClause +//line mysql_sql.y:13799 + { + yyLOCAL = &tree.FrameClause{ + Type: yyDollar[1].frameTypeUnion(), + Start: yyDollar[2].frameBoundUnion(), + End: &tree.FrameBound{Type: tree.CurrentRow}, + } + } + yyVAL.union = yyLOCAL + case 2034: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.FrameClause +//line mysql_sql.y:13807 + { + yyLOCAL = &tree.FrameClause{ + Type: yyDollar[1].frameTypeUnion(), + HasEnd: true, + Start: yyDollar[3].frameBoundUnion(), + End: yyDollar[5].frameBoundUnion(), + } + } + yyVAL.union = yyLOCAL + case 2035: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.FrameClause +//line mysql_sql.y:13817 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 2036: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.FrameClause +//line mysql_sql.y:13821 + { + yyLOCAL = yyDollar[1].frameClauseUnion() + } + yyVAL.union = yyLOCAL + case 2037: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:13827 + { + yyLOCAL = yyDollar[3].exprsUnion() + } + yyVAL.union = yyLOCAL + case 2038: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:13832 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 2039: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:13836 + { + yyLOCAL = yyDollar[1].exprsUnion() + } + yyVAL.union = yyLOCAL + case 2040: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:13841 + { + yyVAL.str = "," + } + case 2041: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:13845 + { + yyVAL.str = yyDollar[2].str + } + case 2042: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:13850 + { + yyVAL.str = "1,vector_l2_ops,random,false" + } + case 2043: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:13854 + { + yyVAL.str = yyDollar[2].str + } + case 2044: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.WindowSpec +//line mysql_sql.y:13859 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 2046: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.WindowSpec +//line mysql_sql.y:13866 + { + yyLOCAL = makeWindowSpec(yyDollar[2].cstrUnion(), nil, nil, nil) + yyLOCAL.ReferencedOnly = true + } + yyVAL.union = yyLOCAL + case 2047: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.WindowSpec +//line mysql_sql.y:13871 + { + yyLOCAL = yyDollar[3].windowSpecUnion() + } + yyVAL.union = yyLOCAL + case 2048: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.WindowSpec +//line mysql_sql.y:13877 + { + yyLOCAL = makeWindowSpec(yyDollar[1].cstrUnion(), yyDollar[2].exprsUnion(), yyDollar[3].orderByUnion(), yyDollar[4].frameClauseUnion()) + } + yyVAL.union = yyLOCAL + case 2049: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:13886 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 2050: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.CStr +//line mysql_sql.y:13890 + { + yyLOCAL = yyDollar[1].cstrUnion() + } + yyVAL.union = yyLOCAL + case 2051: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.WindowDefinitions +//line mysql_sql.y:13895 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 2052: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.WindowDefinitions +//line mysql_sql.y:13899 + { + yyLOCAL = yyDollar[2].windowDefinitionsUnion() + } + yyVAL.union = yyLOCAL + case 2053: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.WindowDefinitions +//line mysql_sql.y:13905 + { + yyLOCAL = tree.WindowDefinitions{yyDollar[1].windowDefinitionUnion()} + } + yyVAL.union = yyLOCAL + case 2054: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.WindowDefinitions +//line mysql_sql.y:13909 + { + yyLOCAL = append(yyDollar[1].windowDefinitionsUnion(), yyDollar[3].windowDefinitionUnion()) + } + yyVAL.union = yyLOCAL + case 2055: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.WindowDefinition +//line mysql_sql.y:13915 + { + yyLOCAL = &tree.WindowDefinition{Name: yyDollar[1].cstrUnion(), Spec: yyDollar[4].windowSpecUnion()} + } + yyVAL.union = yyLOCAL + case 2056: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13921 + { + functionName := yyDollar[1].str + arguments := yyDollar[4].exprsUnion() + separator := tree.Expr(tree.NewNumVal(yyDollar[6].str, yyDollar[6].str, false, tree.P_char)) + if strings.EqualFold(functionName, "listagg") { + // LISTAGG is a compatibility surface over GROUP_CONCAT. Keep the + // spelling in FuncName for deparsing, but bind the canonical name. + functionName = "group_concat" + if len(arguments) < 1 || len(arguments) > 2 { + yylex.Error("listagg requires one value and an optional delimiter") + return 1 + } + if len(arguments) == 2 { + literal, ok := arguments[1].(*tree.NumVal) + if !ok || (literal.ValType != tree.P_char && literal.ValType != tree.P_null) { + yylex.Error("listagg delimiter must be a string literal or NULL") + return 1 + } + separator = arguments[1] + arguments = arguments[:1] + } + } + name := tree.NewUnresolvedColName(functionName) + if yyDollar[5].orderByUnion() != nil && yyDollar[8].orderByUnion() != nil { + yylex.Error(yyDollar[1].str + " cannot use both ORDER BY and WITHIN GROUP ORDER BY") + return 1 + } + orderBy := yyDollar[5].orderByUnion() + if yyDollar[8].orderByUnion() != nil { + orderBy = yyDollar[8].orderByUnion() + } + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: append(arguments, separator), + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[9].windowSpecUnion(), + OrderBy: orderBy, + WithinGroup: yyDollar[8].orderByUnion() != nil, + } + } + yyVAL.union = yyLOCAL + case 2057: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13963 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion()}, + WindowSpec: yyDollar[6].windowSpecUnion(), + OrderBy: yyDollar[5].orderByUnion(), + WithinGroup: yyDollar[5].orderByUnion() != nil, + } + } + yyVAL.union = yyLOCAL + case 2058: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13975 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion()}, + WindowSpec: yyDollar[6].windowSpecUnion(), + OrderBy: yyDollar[5].orderByUnion(), + WithinGroup: yyDollar[5].orderByUnion() != nil, + } + } + yyVAL.union = yyLOCAL + case 2059: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13987 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: append(yyDollar[4].exprsUnion(), tree.NewNumVal(yyDollar[6].str, yyDollar[6].str, false, tree.P_char)), + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[8].windowSpecUnion(), + OrderBy: yyDollar[5].orderByUnion(), + } + } + yyVAL.union = yyLOCAL + case 2060: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:13999 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2061: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14010 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[4].exprsUnion(), + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2062: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14021 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + es := tree.NewNumVal("*", "*", false, tree.P_star) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{es}, + WindowSpec: yyDollar[5].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2063: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14032 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + WindowSpec: yyDollar[5].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2064: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14042 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + OrderBy: yyDollar[5].orderByUnion(), + WithinGroup: yyDollar[5].orderByUnion() != nil, + } + } + yyVAL.union = yyLOCAL + case 2065: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14054 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2066: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14065 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2067: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14076 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2068: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14087 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[4].exprsUnion(), + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2069: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14098 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + es := tree.NewNumVal("*", "*", false, tree.P_star) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{es}, + WindowSpec: yyDollar[5].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2070: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14109 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2071: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14120 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2072: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14131 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2073: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14142 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2074: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14153 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2075: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14164 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2076: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14175 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2077: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14186 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2078: + yyDollar = yyS[yypt-9 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14197 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + OrderBy: yyDollar[7].orderByUnion(), + WithinGroup: true, + WindowSpec: yyDollar[9].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2079: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14208 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2080: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14219 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2081: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14230 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[4].exprsUnion(), + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2082: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14241 + { + functionName := yyDollar[1].str + if strings.EqualFold(functionName, "array_agg") { + // MatrixOne has no general SQL ARRAY value. ARRAY_AGG deliberately + // adopts JSON_ARRAYAGG's JSON return contract instead. + functionName = "json_arrayagg" + } + name := tree.NewUnresolvedColName(functionName) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2083: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14258 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion(), yyDollar[6].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[8].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2087: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14276 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + IsGeneric: isSQLModeSensitiveFunctionName(yyDollar[1].str), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2088: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14286 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + exprs := tree.Exprs{yyDollar[3].exprUnion()} + exprs = append(exprs, yyDollar[5].exprsUnion()...) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: exprs, + } + } + yyVAL.union = yyLOCAL + case 2089: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14297 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2090: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14306 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2091: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14315 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion(), yyDollar[7].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2092: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14324 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + str := strings.ToLower(yyDollar[3].str) + timeUinit := tree.NewTimeUnitExpr(str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{timeUinit, yyDollar[5].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2093: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14335 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2094: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14344 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2095: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14353 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[4].exprUnion()}, + Type: yyDollar[3].funcTypeUnion(), + WindowSpec: yyDollar[6].windowSpecUnion(), + } + } + yyVAL.union = yyLOCAL + case 2096: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14364 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2097: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14373 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2098: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14382 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2099: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14391 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: nil, + } + } + yyVAL.union = yyLOCAL + case 2100: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14400 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + arg0 := tree.NewNumVal(int64(0), "0", false, tree.P_int64) + arg1 := tree.NewNumVal("both", "both", false, tree.P_char) + arg2 := tree.NewNumVal(" ", " ", false, tree.P_char) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{arg0, arg1, arg2, yyDollar[3].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2101: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14412 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + arg0 := tree.NewNumVal(int64(1), "1", false, tree.P_int64) + arg1 := tree.NewNumVal("both", "both", false, tree.P_char) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{arg0, arg1, yyDollar[3].exprUnion(), yyDollar[5].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2102: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14423 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + arg0 := tree.NewNumVal(int64(2), "2", false, tree.P_int64) + str := strings.ToLower(yyDollar[3].str) + arg1 := tree.NewNumVal(str, str, false, tree.P_char) + arg2 := tree.NewNumVal(" ", " ", false, tree.P_char) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{arg0, arg1, arg2, yyDollar[5].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2103: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14436 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + arg0 := tree.NewNumVal(int64(3), "3", false, tree.P_int64) + str := strings.ToLower(yyDollar[3].str) + arg1 := tree.NewNumVal(str, str, false, tree.P_char) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{arg0, arg1, yyDollar[4].exprUnion(), yyDollar[6].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2104: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14448 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[3].unresolvedNameUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2111: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:14469 + { + yyVAL.str = yyDollar[1].str + } + case 2144: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14511 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + var es tree.Exprs = nil + if yyDollar[2].exprUnion() != nil { + es = append(es, yyDollar[2].exprUnion()) + } + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: es, + } + } + yyVAL.union = yyLOCAL + case 2145: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14524 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + var es tree.Exprs = nil + if yyDollar[2].exprUnion() != nil { + es = append(es, yyDollar[2].exprUnion()) + } + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: es, + } + } + yyVAL.union = yyLOCAL + case 2146: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14537 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + str := strings.ToLower(yyDollar[3].str) + arg1 := tree.NewTimeUnitExpr(str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{arg1, yyDollar[5].exprUnion(), yyDollar[7].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2147: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14548 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + str := strings.ToLower(yyDollar[3].str) + arg1 := tree.NewTimeUnitExpr(str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{arg1, yyDollar[5].exprUnion(), yyDollar[7].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2148: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14559 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + str := strings.ToUpper(yyDollar[3].str) + arg1 := tree.NewNumVal(str, str, false, tree.P_char) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{arg1, yyDollar[5].exprUnion()}, + } + } + yyVAL.union = yyLOCAL + case 2149: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14571 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2150: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14580 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + } + } + yyVAL.union = yyLOCAL + case 2151: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14588 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + } + } + yyVAL.union = yyLOCAL + case 2152: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14596 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + var es tree.Exprs = nil + if yyDollar[2].exprUnion() != nil { + es = append(es, yyDollar[2].exprUnion()) + } + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: es, + } + } + yyVAL.union = yyLOCAL + case 2153: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14609 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2154: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14618 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + exprs := make([]tree.Expr, 1) + exprs[0] = yyDollar[2].exprUnion() + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: exprs, + } + } + yyVAL.union = yyLOCAL + case 2155: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14629 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + exprs := make([]tree.Expr, 1) + exprs[0] = yyDollar[2].unresolvedNameUnion() + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: exprs, + } + } + yyVAL.union = yyLOCAL + case 2156: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14640 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2157: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14649 + { + charName := tree.NewUnresolvedColName(yyDollar[1].str) + charExpr := &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(charName), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + charset := tree.NewNumVal(yyDollar[5].str, yyDollar[5].str, false, tree.P_char) + name := tree.NewUnresolvedColName("convert") + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr("convert", 1), + Exprs: tree.Exprs{charExpr, charset}, + } + } + yyVAL.union = yyLOCAL + case 2158: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14665 + { + val := tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char) + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{val}, + } + } + yyVAL.union = yyLOCAL + case 2159: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14675 + { + val := tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char) + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{val}, + } + } + yyVAL.union = yyLOCAL + case 2160: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14685 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2161: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14694 + { + es := tree.Exprs{yyDollar[3].exprUnion()} + es = append(es, yyDollar[5].exprUnion()) + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: es, + } + } + yyVAL.union = yyLOCAL + case 2162: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14705 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2163: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14714 + { + val := tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_char) + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{val}, + } + } + yyVAL.union = yyLOCAL + case 2164: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14724 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2165: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14733 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2166: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.FuncExpr +//line mysql_sql.y:14742 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: yyDollar[3].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2167: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14752 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 2168: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14756 + { + yyLOCAL = yyDollar[1].exprUnion() + } + yyVAL.union = yyLOCAL + case 2169: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14762 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 2170: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14766 + { + ival, errStr := util.GetInt64(yyDollar[2].item) + if errStr != "" { + yylex.Error(errStr) + goto ret1 + } + str := fmt.Sprintf("%v", yyDollar[2].item) + yyLOCAL = tree.NewNumVal(ival, str, false, tree.P_int64) + } + yyVAL.union = yyLOCAL + case 2177: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:14785 + { + } + case 2178: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:14787 + { + } + case 2215: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14831 + { + name := tree.NewUnresolvedColName(yyDollar[1].str) + str := strings.ToLower(yyDollar[3].str) + arg2 := tree.NewTimeUnitExpr(str) + yyLOCAL = &tree.FuncExpr{ + Func: tree.FuncName2ResolvableFunctionReference(name), + FuncName: tree.NewCStr(yyDollar[1].str, 1), + Exprs: tree.Exprs{yyDollar[2].exprUnion(), arg2}, + } + } + yyVAL.union = yyLOCAL + case 2216: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.FuncType +//line mysql_sql.y:14843 + { + yyLOCAL = tree.FUNC_TYPE_DEFAULT + } + yyVAL.union = yyLOCAL + case 2217: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FuncType +//line mysql_sql.y:14847 + { + yyLOCAL = tree.FUNC_TYPE_DISTINCT + } + yyVAL.union = yyLOCAL + case 2218: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.FuncType +//line mysql_sql.y:14851 + { + yyLOCAL = tree.FUNC_TYPE_ALL + } + yyVAL.union = yyLOCAL + case 2219: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.Tuple +//line mysql_sql.y:14857 + { + yyLOCAL = tree.NewTuple(yyDollar[2].exprsUnion()) + } + yyVAL.union = yyLOCAL + case 2220: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:14862 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 2221: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:14866 + { + yyLOCAL = yyDollar[1].exprsUnion() + } + yyVAL.union = yyLOCAL + case 2222: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:14872 + { + yyLOCAL = tree.Exprs{yyDollar[1].exprUnion()} + } + yyVAL.union = yyLOCAL + case 2223: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:14876 + { + yyLOCAL = append(yyDollar[1].exprsUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2224: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:14882 + { + yyLOCAL = tree.Exprs{yyDollar[1].exprUnion()} + } + yyVAL.union = yyLOCAL + case 2225: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Exprs +//line mysql_sql.y:14886 + { + yyLOCAL = append(yyDollar[1].exprsUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2226: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14893 + { + yyLOCAL = tree.NewAndExpr(yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2227: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14897 + { + yyLOCAL = tree.NewOrExpr(yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2228: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14901 + { + yyLOCAL = tree.NewXorExpr(yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2229: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14905 + { + yyLOCAL = tree.NewNotExpr(yyDollar[2].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2230: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14909 + { + yyLOCAL = yyDollar[1].exprUnion() + } + yyVAL.union = yyLOCAL + case 2231: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14914 + { + yyLOCAL = yyDollar[1].exprUnion() + } + yyVAL.union = yyLOCAL + case 2232: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14918 + { + yyLOCAL = tree.NewMaxValue() + } + yyVAL.union = yyLOCAL + case 2233: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14924 + { + yyLOCAL = tree.NewIsNullExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2234: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14928 + { + yyLOCAL = tree.NewIsNotNullExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2235: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14932 + { + yyLOCAL = tree.NewIsNotNullExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2236: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14936 + { + yyLOCAL = tree.NewIsUnknownExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2237: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14940 + { + yyLOCAL = tree.NewIsNotUnknownExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2238: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14944 + { + yyLOCAL = tree.NewIsNotUnknownExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2239: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14948 + { + yyLOCAL = tree.NewIsTrueExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2240: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14952 + { + yyLOCAL = tree.NewIsNotTrueExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2241: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14956 + { + yyLOCAL = tree.NewIsNotTrueExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2242: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14960 + { + yyLOCAL = tree.NewIsFalseExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2243: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14964 + { + yyLOCAL = tree.NewIsNotFalseExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2244: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14968 + { + yyLOCAL = tree.NewIsNotFalseExpr(yyDollar[1].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2245: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14972 + { + yyLOCAL = tree.NewComparisonExpr(yyDollar[2].comparisonOpUnion(), yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2246: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14976 + { + yyLOCAL = tree.NewSubqueryComparisonExpr(yyDollar[2].comparisonOpUnion(), yyDollar[3].comparisonOpUnion(), yyDollar[1].exprUnion(), yyDollar[4].subqueryUnion()) + yyLOCAL = tree.NewSubqueryComparisonExpr(yyDollar[2].comparisonOpUnion(), yyDollar[3].comparisonOpUnion(), yyDollar[1].exprUnion(), yyDollar[4].subqueryUnion()) + } + yyVAL.union = yyLOCAL + case 2248: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14984 + { + yyLOCAL = tree.NewComparisonExpr(tree.IN, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2249: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14988 + { + yyLOCAL = tree.NewComparisonExpr(tree.NOT_IN, yyDollar[1].exprUnion(), yyDollar[4].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2250: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14992 + { + yyLOCAL = tree.NewComparisonExpr(tree.NOT_IN, yyDollar[1].exprUnion(), yyDollar[4].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2251: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:14996 + { + yyLOCAL = tree.NewComparisonExpr(tree.MEMBER_OF, yyDollar[1].exprUnion(), yyDollar[5].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2252: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15000 + { + yyLOCAL = tree.NewComparisonExprWithEscape(tree.LIKE, yyDollar[1].exprUnion(), yyDollar[3].exprUnion(), yyDollar[4].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2253: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15004 + { + yyLOCAL = tree.NewComparisonExprWithEscape(tree.NOT_LIKE, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[5].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2254: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15008 + { + yyLOCAL = tree.NewComparisonExprWithEscape(tree.NOT_LIKE, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[5].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2255: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15012 + { + yyLOCAL = tree.NewComparisonExprWithEscape(tree.ILIKE, yyDollar[1].exprUnion(), yyDollar[3].exprUnion(), yyDollar[4].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2256: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15016 + { + yyLOCAL = tree.NewComparisonExprWithEscape(tree.NOT_ILIKE, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[5].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2257: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15020 + { + yyLOCAL = tree.NewComparisonExprWithEscape(tree.NOT_ILIKE, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[5].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2258: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15024 + { + yyLOCAL = tree.NewComparisonExpr(tree.REG_MATCH, yyDollar[1].exprUnion(), yyDollar[3].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2259: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15028 + { + yyLOCAL = tree.NewComparisonExpr(tree.NOT_REG_MATCH, yyDollar[1].exprUnion(), yyDollar[4].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2260: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15032 + { + yyLOCAL = tree.NewComparisonExpr(tree.NOT_REG_MATCH, yyDollar[1].exprUnion(), yyDollar[4].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2261: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15036 + { + yyLOCAL = tree.NewRangeCond(false, yyDollar[1].exprUnion(), yyDollar[3].exprUnion(), yyDollar[5].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2262: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15040 + { + yyLOCAL = tree.NewRangeCond(true, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[6].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2263: + yyDollar = yyS[yypt-6 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15044 + { + yyLOCAL = tree.NewRangeCond(true, yyDollar[1].exprUnion(), yyDollar[4].exprUnion(), yyDollar[6].exprUnion()) + } + yyVAL.union = yyLOCAL + case 2265: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15050 + { + yyLOCAL = nil + } + yyVAL.union = yyLOCAL + case 2266: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15054 + { + yyLOCAL = yyDollar[2].exprUnion() + } + yyVAL.union = yyLOCAL + case 2269: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15064 + { + yyLOCAL = yyDollar[1].tupleUnion() + } + yyVAL.union = yyLOCAL + case 2270: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15068 + { + yyLOCAL = yyDollar[1].subqueryUnion() + } + yyVAL.union = yyLOCAL + case 2271: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ComparisonOp +//line mysql_sql.y:15075 + { + yyLOCAL = tree.ALL + } + yyVAL.union = yyLOCAL + case 2272: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ComparisonOp +//line mysql_sql.y:15079 + { + yyLOCAL = tree.ANY + } + yyVAL.union = yyLOCAL + case 2273: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ComparisonOp +//line mysql_sql.y:15083 + { + yyLOCAL = tree.SOME + } + yyVAL.union = yyLOCAL + case 2274: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ComparisonOp +//line mysql_sql.y:15089 + { + yyLOCAL = tree.EQUAL + } + yyVAL.union = yyLOCAL + case 2275: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ComparisonOp +//line mysql_sql.y:15093 + { + yyLOCAL = tree.LESS_THAN + } + yyVAL.union = yyLOCAL + case 2276: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ComparisonOp +//line mysql_sql.y:15097 + { + yyLOCAL = tree.GREAT_THAN + } + yyVAL.union = yyLOCAL + case 2277: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ComparisonOp +//line mysql_sql.y:15101 + { + yyLOCAL = tree.LESS_THAN_EQUAL + } + yyVAL.union = yyLOCAL + case 2278: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ComparisonOp +//line mysql_sql.y:15105 + { + yyLOCAL = tree.GREAT_THAN_EQUAL + } + yyVAL.union = yyLOCAL + case 2279: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ComparisonOp +//line mysql_sql.y:15109 + { + yyLOCAL = tree.NOT_EQUAL + } + yyVAL.union = yyLOCAL + case 2280: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ComparisonOp +//line mysql_sql.y:15113 + { + yyLOCAL = tree.NULL_SAFE_EQUAL + } + yyVAL.union = yyLOCAL + case 2281: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:15119 + { + yyLOCAL = tree.NewAttributePrimaryKey() + } + yyVAL.union = yyLOCAL + case 2282: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:15123 + { + yyLOCAL = tree.NewAttributeUniqueKey() + } + yyVAL.union = yyLOCAL + case 2283: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:15127 + { + yyLOCAL = tree.NewAttributeUnique() + } + yyVAL.union = yyLOCAL + case 2284: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.ColumnAttribute +//line mysql_sql.y:15131 + { + yyLOCAL = tree.NewAttributeKey() + } + yyVAL.union = yyLOCAL + case 2285: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15137 + { + str := fmt.Sprintf("%v", yyDollar[1].item) + switch v := yyDollar[1].item.(type) { + case uint64: + yyLOCAL = tree.NewNumVal(v, str, false, tree.P_uint64) + case int64: + yyLOCAL = tree.NewNumVal(v, str, false, tree.P_int64) + default: + yylex.Error("parse integral fail") + goto ret1 + } + } + yyVAL.union = yyLOCAL + case 2286: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15150 + { + fval := yyDollar[1].item.(float64) + yyLOCAL = tree.NewNumVal(fval, yylex.(*Lexer).scanner.LastToken, false, tree.P_float64) + } + yyVAL.union = yyLOCAL + case 2287: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15155 + { + yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_decimal) + } + yyVAL.union = yyLOCAL + case 2288: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15161 + { + yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_char) + } + yyVAL.union = yyLOCAL + case 2289: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15165 + { + str := fmt.Sprintf("%v", yyDollar[1].item) + switch v := yyDollar[1].item.(type) { + case uint64: + yyLOCAL = tree.NewNumVal(v, str, false, tree.P_uint64) + case int64: + yyLOCAL = tree.NewNumVal(v, str, false, tree.P_int64) + default: + yylex.Error("parse integral fail") + goto ret1 + } + } + yyVAL.union = yyLOCAL + case 2290: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15178 + { + fval := yyDollar[1].item.(float64) + yyLOCAL = tree.NewNumVal(fval, yylex.(*Lexer).scanner.LastToken, false, tree.P_float64) + } + yyVAL.union = yyLOCAL + case 2291: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15183 + { + yyLOCAL = tree.NewNumVal(true, "true", false, tree.P_bool) + } + yyVAL.union = yyLOCAL + case 2292: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15187 + { + yyLOCAL = tree.NewNumVal(false, "false", false, tree.P_bool) + } + yyVAL.union = yyLOCAL + case 2293: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15191 + { + yyLOCAL = tree.NewNumVal("null", "null", false, tree.P_null) + } + yyVAL.union = yyLOCAL + case 2294: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15195 + { + yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_hexnum) + } + yyVAL.union = yyLOCAL + case 2295: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15199 + { + yyLOCAL = tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_ScoreBinaryHexnum) + } + yyVAL.union = yyLOCAL + case 2296: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15203 + { + yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_decimal) + } + yyVAL.union = yyLOCAL + case 2297: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15207 + { + yyLOCAL = tree.NewNumVal(yyDollar[1].str, yyDollar[1].str, false, tree.P_bit) + } + yyVAL.union = yyLOCAL + case 2298: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15211 + { + yyLOCAL = tree.NewParamExpr(yylex.(*Lexer).GetParamIndex()) + } + yyVAL.union = yyLOCAL + case 2299: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Expr +//line mysql_sql.y:15215 + { + yyLOCAL = tree.NewNumVal(yyDollar[2].str, yyDollar[2].str, false, tree.P_ScoreBinary) + } + yyVAL.union = yyLOCAL + case 2300: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15221 + { + yyLOCAL = yyDollar[1].columnTypeUnion() + yyLOCAL.InternalType.Unsigned = yyDollar[2].unsignedOptUnion() + yyLOCAL.InternalType.Zerofill = yyDollar[3].zeroFillOptUnion() + } + yyVAL.union = yyLOCAL + case 2304: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15230 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.ArrayFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TYPED_ARRAY), + ArrayContents: yyDollar[3].columnTypeUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 2305: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15245 + { + yyLOCAL = yyDollar[1].columnTypeUnion() + yyLOCAL.InternalType.DisplayWith = yyDollar[2].lengthOptUnion() + } + yyVAL.union = yyLOCAL + case 2306: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15250 + { + yyLOCAL = yyDollar[1].columnTypeUnion() + } + yyVAL.union = yyLOCAL + case 2307: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15256 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BitFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_BIT), + }, + } + } + yyVAL.union = yyLOCAL + case 2308: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15268 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BoolFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_BOOL), + }, + } + } + yyVAL.union = yyLOCAL + case 2309: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15280 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BoolFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_BOOL), + }, + } + } + yyVAL.union = yyLOCAL + case 2310: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15292 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + Width: 8, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TINY), + }, + } + } + yyVAL.union = yyLOCAL + case 2311: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15305 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + Width: 8, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TINY), + }, + } + } + yyVAL.union = yyLOCAL + case 2312: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15318 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + Width: 16, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_SHORT), + }, + } + } + yyVAL.union = yyLOCAL + case 2313: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15331 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + Width: 16, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_SHORT), + }, + } + } + yyVAL.union = yyLOCAL + case 2314: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15344 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + Width: 24, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_INT24), + }, + } + } + yyVAL.union = yyLOCAL + case 2315: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15357 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + Width: 24, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_INT24), + }, + } + } + yyVAL.union = yyLOCAL + case 2316: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15370 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + Width: 32, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_LONG), + }, + } + } + yyVAL.union = yyLOCAL + case 2317: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15383 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + Width: 32, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_LONG), + }, + } + } + yyVAL.union = yyLOCAL + case 2318: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15396 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + Width: 32, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_LONG), + }, + } + } + yyVAL.union = yyLOCAL + case 2319: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15409 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + Width: 64, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_LONGLONG), + }, + } + } + yyVAL.union = yyLOCAL + case 2320: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15422 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + Width: 64, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_LONGLONG), + }, + } + } + yyVAL.union = yyLOCAL + case 2321: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15437 + { + locale := "" + if yyDollar[2].lengthScaleOptUnion().DisplayWith > 255 { + yylex.Error("Display width for double out of range (max = 255)") + goto ret1 + } + if yyDollar[2].lengthScaleOptUnion().Scale > 30 { + yylex.Error("Display scale for double out of range (max = 30)") + goto ret1 + } + if yyDollar[2].lengthScaleOptUnion().Scale != tree.NotDefineDec && yyDollar[2].lengthScaleOptUnion().Scale > yyDollar[2].lengthScaleOptUnion().DisplayWith { + yylex.Error("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a'))") + goto ret1 + } + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.FloatFamily, + FamilyString: yyDollar[1].str, + Width: 64, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DOUBLE), + DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, + Scale: yyDollar[2].lengthScaleOptUnion().Scale, + }, + } + } + yyVAL.union = yyLOCAL + case 2322: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15464 + { + // DOUBLE PRECISION is the SQL-standard synonym for DOUBLE (float64). + locale := "" + if yyDollar[3].lengthScaleOptUnion().DisplayWith > 255 { + yylex.Error("Display width for double out of range (max = 255)") + goto ret1 + } + if yyDollar[3].lengthScaleOptUnion().Scale > 30 { + yylex.Error("Display scale for double out of range (max = 30)") + goto ret1 + } + if yyDollar[3].lengthScaleOptUnion().Scale != tree.NotDefineDec && yyDollar[3].lengthScaleOptUnion().Scale > yyDollar[3].lengthScaleOptUnion().DisplayWith { + yylex.Error("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a'))") + goto ret1 + } + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.FloatFamily, + FamilyString: yyDollar[1].str, + Width: 64, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DOUBLE), + DisplayWith: yyDollar[3].lengthScaleOptUnion().DisplayWith, + Scale: yyDollar[3].lengthScaleOptUnion().Scale, + }, + } + } + yyVAL.union = yyLOCAL + case 2323: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15492 + { + locale := "" + if yyDollar[2].lengthScaleOptUnion().DisplayWith > 255 { + yylex.Error("Display width for float out of range (max = 255)") + goto ret1 + } + if yyDollar[2].lengthScaleOptUnion().Scale > 30 { + yylex.Error("Display scale for float out of range (max = 30)") + goto ret1 + } + if yyDollar[2].lengthScaleOptUnion().Scale != tree.NotDefineDec && yyDollar[2].lengthScaleOptUnion().Scale > yyDollar[2].lengthScaleOptUnion().DisplayWith { + yylex.Error("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a'))") + goto ret1 + } + if yyDollar[2].lengthScaleOptUnion().Scale == tree.NotDefineDec && yyDollar[2].lengthScaleOptUnion().DisplayWith > 24 { + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.FloatFamily, + FamilyString: yyDollar[1].str, + Width: 64, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DOUBLE), + DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, + Scale: yyDollar[2].lengthScaleOptUnion().Scale, + }, + } + } else { + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.FloatFamily, + FamilyString: yyDollar[1].str, + Width: 32, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_FLOAT), + DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, + Scale: yyDollar[2].lengthScaleOptUnion().Scale, + }, + } + } + } + yyVAL.union = yyLOCAL + case 2324: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15534 + { + locale := "" + if yyDollar[2].lengthScaleOptUnion().Scale != tree.NotDefineDec && yyDollar[2].lengthScaleOptUnion().Scale > yyDollar[2].lengthScaleOptUnion().DisplayWith { + yylex.Error("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a'))") + goto ret1 + } + if yyDollar[2].lengthScaleOptUnion().DisplayWith > 65 || yyDollar[2].lengthScaleOptUnion().DisplayWith < 0 { + yylex.Error("For decimal(M), M must between 0 and 65.") + goto ret1 + } else if yyDollar[2].lengthScaleOptUnion().DisplayWith <= 16 { + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.FloatFamily, + FamilyString: yyDollar[1].str, + Width: 64, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DECIMAL), + DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, + Scale: yyDollar[2].lengthScaleOptUnion().Scale, + }, + } + } else if yyDollar[2].lengthScaleOptUnion().DisplayWith <= 38 { + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.FloatFamily, + FamilyString: yyDollar[1].str, + Width: 128, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DECIMAL), + DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, + Scale: yyDollar[2].lengthScaleOptUnion().Scale, + }, + } + } else { + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.FloatFamily, + FamilyString: yyDollar[1].str, + Width: 256, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DECIMAL), + DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, + Scale: yyDollar[2].lengthScaleOptUnion().Scale, + }, + } + } + } + yyVAL.union = yyLOCAL + case 2325: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15582 + { + locale := "" + if yyDollar[2].lengthScaleOptUnion().Scale != tree.NotDefineDec && yyDollar[2].lengthScaleOptUnion().Scale > yyDollar[2].lengthScaleOptUnion().DisplayWith { + yylex.Error("For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 'a'))") + goto ret1 + } + if yyDollar[2].lengthScaleOptUnion().DisplayWith > 65 || yyDollar[2].lengthScaleOptUnion().DisplayWith < 0 { + yylex.Error("For decimal(M), M must between 0 and 65.") + goto ret1 + } else if yyDollar[2].lengthScaleOptUnion().DisplayWith <= 16 { + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.FloatFamily, + FamilyString: yyDollar[1].str, + Width: 64, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DECIMAL), + DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, + Scale: yyDollar[2].lengthScaleOptUnion().Scale, + }, + } + } else if yyDollar[2].lengthScaleOptUnion().DisplayWith <= 38 { + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.FloatFamily, + FamilyString: yyDollar[1].str, + Width: 128, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DECIMAL), + DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, + Scale: yyDollar[2].lengthScaleOptUnion().Scale, + }, + } + } else { + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.FloatFamily, + FamilyString: yyDollar[1].str, + Width: 256, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DECIMAL), + DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, + Scale: yyDollar[2].lengthScaleOptUnion().Scale, + }, + } + } + } + yyVAL.union = yyLOCAL + case 2326: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15630 + { + locale := "" + width := int32(64) + oid := uint32(defines.MYSQL_TYPE_DOUBLE) + if yylex.(*Lexer).HasSQLMode(SQLModeRealAsFloat) { + width = 32 + oid = uint32(defines.MYSQL_TYPE_FLOAT) + } + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.FloatFamily, + FamilyString: yyDollar[1].str, + Width: width, + Locale: &locale, + Oid: oid, + DisplayWith: yyDollar[2].lengthScaleOptUnion().DisplayWith, + Scale: yyDollar[2].lengthScaleOptUnion().Scale, + }, + } + } + yyVAL.union = yyLOCAL + case 2327: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15653 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.DateFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DATE), + }, + } + } + yyVAL.union = yyLOCAL + case 2328: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15665 + { + locale := "" + if yyDollar[2].lengthOptUnion() < 0 || yyDollar[2].lengthOptUnion() > 6 { + yylex.Error("For Time(fsp), fsp must in [0, 6]") + goto ret1 + } else { + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.TimeFamily, + Scale: yyDollar[2].lengthOptUnion(), + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + TimePrecisionIsSet: true, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TIME), + }, + } + } + } + yyVAL.union = yyLOCAL + case 2329: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15685 + { + locale := "" + if yyDollar[2].lengthOptUnion() < 0 || yyDollar[2].lengthOptUnion() > 6 { + yylex.Error("For Timestamp(fsp), fsp must in [0, 6]") + goto ret1 + } else { + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.TimestampFamily, + Scale: yyDollar[2].lengthOptUnion(), + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + TimePrecisionIsSet: true, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TIMESTAMP), + }, + } + } + } + yyVAL.union = yyLOCAL + case 2330: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15705 + { + locale := "" + if yyDollar[2].lengthOptUnion() < 0 || yyDollar[2].lengthOptUnion() > 6 { + yylex.Error("For Datetime(fsp), fsp must in [0, 6]") + goto ret1 + } else { + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.TimestampFamily, + Scale: yyDollar[2].lengthOptUnion(), + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + TimePrecisionIsSet: true, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_DATETIME), + }, + } + } + } + yyVAL.union = yyLOCAL + case 2331: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15725 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.IntFamily, + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + Width: 16, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_YEAR), + }, + } + } + yyVAL.union = yyLOCAL + case 2332: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15741 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.StringFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_STRING), + DisplayWith: yyDollar[2].lengthOptUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 2333: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15754 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.StringFamily, + Locale: &locale, + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + Oid: uint32(defines.MYSQL_TYPE_VARCHAR), + }, + } + } + yyVAL.union = yyLOCAL + case 2334: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15767 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.StringFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_VARCHAR), + DisplayWith: yyDollar[2].lengthOptUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 2335: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15780 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.StringFamily, + Locale: &locale, + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + Oid: uint32(defines.MYSQL_TYPE_VARCHAR), + }, + } + } + yyVAL.union = yyLOCAL + case 2336: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15793 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BlobFamily, + FamilyString: "mediumtext", + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TEXT), + }, + } + } + yyVAL.union = yyLOCAL + case 2337: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15805 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BlobFamily, + FamilyString: "mediumblob", + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_MEDIUM_BLOB), + }, + } + } + yyVAL.union = yyLOCAL + case 2338: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15817 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BlobFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TEXT), + }, + } + } + yyVAL.union = yyLOCAL + case 2339: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15829 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BlobFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TEXT), + DisplayWith: yyDollar[2].lengthOptUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 2340: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15842 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BlobFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TEXT), + }, + } + } + yyVAL.union = yyLOCAL + case 2341: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15854 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BlobFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TEXT), + }, + } + } + yyVAL.union = yyLOCAL + case 2342: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15866 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BlobFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TEXT), + }, + } + } + yyVAL.union = yyLOCAL + case 2343: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15878 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BlobFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_BLOB), + DisplayWith: yyDollar[2].lengthOptUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 2344: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15891 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BlobFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_TINY_BLOB), + }, + } + } + yyVAL.union = yyLOCAL + case 2345: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15903 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BlobFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_MEDIUM_BLOB), + }, + } + } + yyVAL.union = yyLOCAL + case 2346: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15915 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.BlobFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_LONG_BLOB), + }, + } + } + yyVAL.union = yyLOCAL + case 2347: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15927 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.JsonFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_JSON), + }, + } + } + yyVAL.union = yyLOCAL + case 2348: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15939 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.ArrayFamily, + Locale: &locale, + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + Oid: uint32(defines.MYSQL_TYPE_VARCHAR), + }, + } + } + yyVAL.union = yyLOCAL + case 2349: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15952 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.ArrayFamily, + Locale: &locale, + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + Oid: uint32(defines.MYSQL_TYPE_VARCHAR), + }, + } + } + yyVAL.union = yyLOCAL + case 2350: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15965 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.ArrayFamily, + Locale: &locale, + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + Oid: uint32(defines.MYSQL_TYPE_VARCHAR), + }, + } + } + yyVAL.union = yyLOCAL + case 2351: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15978 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.ArrayFamily, + Locale: &locale, + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + Oid: uint32(defines.MYSQL_TYPE_VARCHAR), + }, + } + } + yyVAL.union = yyLOCAL + case 2352: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:15991 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.ArrayFamily, + Locale: &locale, + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + Oid: uint32(defines.MYSQL_TYPE_VARCHAR), + }, + } + } + yyVAL.union = yyLOCAL + case 2353: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:16004 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.ArrayFamily, + Locale: &locale, + FamilyString: yyDollar[1].str, + DisplayWith: yyDollar[2].lengthOptUnion(), + Oid: uint32(defines.MYSQL_TYPE_VARCHAR), + }, + } + } + yyVAL.union = yyLOCAL + case 2354: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:16017 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.EnumFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_ENUM), + EnumValues: yyDollar[3].strsUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 2355: + yyDollar = yyS[yypt-4 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:16030 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.SetFamily, + FamilyString: yyDollar[1].str, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_SET), + EnumValues: yyDollar[3].strsUnion(), + }, + } + } + yyVAL.union = yyLOCAL + case 2356: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:16043 + { + locale := "" + yyLOCAL = &tree.T{ + InternalType: tree.InternalType{ + Family: tree.UuidFamily, + FamilyString: yyDollar[1].str, + Width: 128, + Locale: &locale, + Oid: uint32(defines.MYSQL_TYPE_UUID), + }, + } + } + yyVAL.union = yyLOCAL + case 2357: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:16058 + { + yyLOCAL = &tree.Do{ + Exprs: yyDollar[2].exprsUnion(), + } + } + yyVAL.union = yyLOCAL + case 2358: + yyDollar = yyS[yypt-2 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:16066 + { + yyDollar[2].selectUnion().IsPerform = true + if intoErr := tree.ValidatePerformSelectIntoPlacement(yyDollar[2].selectUnion()); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + yyLOCAL = yyDollar[2].selectUnion() + } + yyVAL.union = yyLOCAL + case 2359: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:16077 + { + yyLOCAL = &tree.Select{Select: yyDollar[1].selectStatementUnion(), TimeWindow: yyDollar[2].timeWindowUnion(), OrderBy: yyDollar[3].orderByUnion(), Limit: yyDollar[4].limitUnion(), RankOption: yyDollar[5].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[1].selectStatementUnion(), yyDollar[6].selectIntoUnion().Export), IntoVars: yyDollar[6].selectIntoUnion().UserVars, SelectLockInfo: yyDollar[7].selectLockInfoUnion()} + if intoErr := tree.ValidatePerformSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 2360: + yyDollar = yyS[yypt-8 : yypt+1] + var yyLOCAL *tree.Select +//line mysql_sql.y:16085 + { + yyLOCAL = &tree.Select{Select: yyDollar[2].selectStatementUnion(), TimeWindow: yyDollar[3].timeWindowUnion(), OrderBy: yyDollar[4].orderByUnion(), Limit: yyDollar[5].limitUnion(), RankOption: yyDollar[6].rankOptionUnion(), Ep: tree.SelectIntoExportOr(yyDollar[2].selectStatementUnion(), yyDollar[7].selectIntoUnion().Export), IntoVars: yyDollar[7].selectIntoUnion().UserVars, SelectLockInfo: yyDollar[8].selectLockInfoUnion(), With: yyDollar[1].withClauseUnion()} + if intoErr := tree.ValidatePerformSelectIntoPlacement(yyLOCAL); intoErr != "" { + yylex.Error(intoErr) + return 1 + } + } + yyVAL.union = yyLOCAL + case 2361: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:16095 + { + yyLOCAL = &tree.Declare{ + Variables: yyDollar[2].strsUnion(), + ColumnType: yyDollar[3].columnTypeUnion(), + DefaultVal: tree.NewNumVal("null", "null", false, tree.P_null), + } + } + yyVAL.union = yyLOCAL + case 2362: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.Statement +//line mysql_sql.y:16104 + { + yyLOCAL = &tree.Declare{ + Variables: yyDollar[2].strsUnion(), + ColumnType: yyDollar[3].columnTypeUnion(), + DefaultVal: yyDollar[5].exprUnion(), + } + } + yyVAL.union = yyLOCAL + case 2363: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL *tree.T +//line mysql_sql.y:16114 + { + yyLOCAL = tree.NewSpatialType(yyDollar[1].str) + } + yyVAL.union = yyLOCAL + case 2382: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:16142 + { + yyLOCAL = make([]string, 0, 4) + yyLOCAL = append(yyLOCAL, yyDollar[1].str) + } + yyVAL.union = yyLOCAL + case 2383: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL []string +//line mysql_sql.y:16147 + { + yyLOCAL = append(yyDollar[1].strsUnion(), yyDollar[3].str) + } + yyVAL.union = yyLOCAL + case 2384: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int32 +//line mysql_sql.y:16153 + { + yyLOCAL = 0 + } + yyVAL.union = yyLOCAL + case 2386: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int32 +//line mysql_sql.y:16160 + { + yyLOCAL = 0 + } + yyVAL.union = yyLOCAL + case 2387: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL int32 +//line mysql_sql.y:16164 + { + value, ok := typeLengthIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + yyLOCAL = value + } + yyVAL.union = yyLOCAL + case 2388: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL int32 +//line mysql_sql.y:16171 + { + yyLOCAL = int32(-1) + } + yyVAL.union = yyLOCAL + case 2389: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL int32 +//line mysql_sql.y:16175 + { + value, ok := typeLengthIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + yyLOCAL = value + } + yyVAL.union = yyLOCAL + case 2390: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL int32 +//line mysql_sql.y:16183 + { + value, ok := typeLengthIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + yyLOCAL = tree.GetDisplayWith(value) + } + yyVAL.union = yyLOCAL + case 2391: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.LengthScaleOpt +//line mysql_sql.y:16191 + { + yyLOCAL = tree.LengthScaleOpt{ + DisplayWith: tree.NotDefineDisplayWidth, + Scale: tree.NotDefineDec, + } + } + yyVAL.union = yyLOCAL + case 2392: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.LengthScaleOpt +//line mysql_sql.y:16198 + { + value, ok := typeLengthIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + yyLOCAL = tree.LengthScaleOpt{ + DisplayWith: tree.GetDisplayWith(value), + Scale: tree.NotDefineDec, + } + } + yyVAL.union = yyLOCAL + case 2393: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.LengthScaleOpt +//line mysql_sql.y:16207 + { + width, ok := typeLengthIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + scale, ok := typeLengthIntegral(yylex, yyDollar[4].item) + if !ok { + goto ret1 + } + yyLOCAL = tree.LengthScaleOpt{ + DisplayWith: tree.GetDisplayWith(width), + Scale: scale, + } + } + yyVAL.union = yyLOCAL + case 2394: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL tree.LengthScaleOpt +//line mysql_sql.y:16220 + { + yyLOCAL = tree.LengthScaleOpt{ + DisplayWith: 10, // MySQL default precision for DECIMAL/NUMERIC + Scale: 0, + } + } + yyVAL.union = yyLOCAL + case 2395: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.LengthScaleOpt +//line mysql_sql.y:16227 + { + value, ok := typeLengthIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + yyLOCAL = tree.LengthScaleOpt{ + DisplayWith: tree.GetDisplayWith(value), + Scale: 0, + } + } + yyVAL.union = yyLOCAL + case 2396: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.LengthScaleOpt +//line mysql_sql.y:16236 + { + width, ok := typeLengthIntegral(yylex, yyDollar[2].item) + if !ok { + goto ret1 + } + scale, ok := typeLengthIntegral(yylex, yyDollar[4].item) + if !ok { + goto ret1 + } + yyLOCAL = tree.LengthScaleOpt{ + DisplayWith: tree.GetDisplayWith(width), + Scale: scale, + } + } + yyVAL.union = yyLOCAL + case 2397: + yyDollar = yyS[yypt-0 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:16249 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 2398: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:16253 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 2399: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:16257 + { + yyLOCAL = false + } + yyVAL.union = yyLOCAL + case 2400: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:16263 + { + } + case 2401: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL bool +//line mysql_sql.y:16265 + { + yyLOCAL = true + } + yyVAL.union = yyLOCAL + case 2405: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:16275 + { + yyVAL.str = "" + } + case 2406: + yyDollar = yyS[yypt-1 : yypt+1] +//line mysql_sql.y:16279 + { + yyVAL.str = string(yyDollar[1].str) + } + case 2926: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:17002 + { + } + case 2927: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:17005 + { + } + case 2928: + yyDollar = yyS[yypt-0 : yypt+1] +//line mysql_sql.y:17009 + { + } + case 2929: + yyDollar = yyS[yypt-2 : yypt+1] +//line mysql_sql.y:17012 + { + } + case 2930: + yyDollar = yyS[yypt-5 : yypt+1] + var yyLOCAL tree.AlterTableOptions +//line mysql_sql.y:17022 + { + yyLOCAL = yyDollar[4].alterTableOptionsUnion() + } + yyVAL.union = yyLOCAL + case 2931: + yyDollar = yyS[yypt-7 : yypt+1] + var yyLOCAL tree.AlterTableOptions +//line mysql_sql.y:17026 + { + yyLOCAL = append(yyDollar[1].alterTableOptionsUnion(), yyDollar[6].alterTableOptionsUnion()...) + } + yyVAL.union = yyLOCAL + case 2932: + yyDollar = yyS[yypt-1 : yypt+1] + var yyLOCAL tree.AlterTableOptions +//line mysql_sql.y:17032 + { + position := tree.NewColumnPosition(tree.ColumnPositionNone, nil) + yyLOCAL = tree.AlterTableOptions{tree.NewAlterAddCol(yyDollar[1].columnTableDefUnion(), position)} + } + yyVAL.union = yyLOCAL + case 2933: + yyDollar = yyS[yypt-3 : yypt+1] + var yyLOCAL tree.AlterTableOptions +//line mysql_sql.y:17037 + { + position := tree.NewColumnPosition(tree.ColumnPositionNone, nil) + yyLOCAL = append(yyDollar[1].alterTableOptionsUnion(), tree.NewAlterAddCol(yyDollar[3].columnTableDefUnion(), position)) + } + yyVAL.union = yyLOCAL + } + goto yystack /* stack new state and value */ +} diff --git a/pkg/sql/plan/deepcopy_test.go b/pkg/sql/plan/deepcopy_test.go index 00efee37073ce..fd88e1f84b8c4 100644 --- a/pkg/sql/plan/deepcopy_test.go +++ b/pkg/sql/plan/deepcopy_test.go @@ -509,6 +509,11 @@ func TestDeepCopyQueryPreservesExecutionMetadata(t *testing.T) { ArtifactDigest: "artifact", EnvironmentDigest: "environment", }}, + Correlation: &planpb.CorrelationSpec{ + Version: planpb.CorrelationVersion, + StepOwners: []uint32{0, 1}, + Programs: []*planpb.CorrelationProgram{{RootNode: 7}}, + }, } encoded, err := (&planpb.Query{ViewReferences: source.ViewReferences}).Marshal() @@ -554,10 +559,14 @@ func TestDeepCopyQueryPreservesExecutionMetadata(t *testing.T) { cloned.Headings[0] = "changed" cloned.BackgroundQueries[0].Headings[0] = "changed" cloned.RoutineDependencies[0].FunctionRef.Revision = 99 + cloned.Correlation.StepOwners[0] = 99 + cloned.Correlation.Programs[0].RootNode = 99 require.Equal(t, int32(3), source.Steps[0]) require.Equal(t, "id", source.Headings[0]) require.Equal(t, "background", source.BackgroundQueries[0].Headings[0]) require.Equal(t, uint64(7), source.RoutineDependencies[0].FunctionRef.Revision) + require.Equal(t, uint32(0), source.Correlation.StepOwners[0]) + require.Equal(t, int32(7), source.Correlation.Programs[0].RootNode) } func TestDeepCopyDataDefinitionCreateTablePreservesExecutionFields(t *testing.T) { diff --git a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go similarity index 88% rename from pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go rename to pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go index d381aca51c817..90af563d9548d 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_15_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go @@ -23,7 +23,7 @@ import ( "time" "github.com/matrixorigin/matrixone/pkg/bootstrap/versions" - "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_15" + "github.com/matrixorigin/matrixone/pkg/bootstrap/versions/v4_0_18" "github.com/matrixorigin/matrixone/pkg/catalog" moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/matrixorigin/matrixone/pkg/container/vector" @@ -36,7 +36,7 @@ import ( // Reuse the upgrade package's single-CN fixture. A late tenant must be repaired // on its first real login, even when the cluster has already completed upgrade. -func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { +func TestV4018LoginRepairsLegacyRoutineCatalog(t *testing.T) { embed.RunSingleCNBaseClusterTests(t, func(cluster embed.Cluster) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() @@ -46,9 +46,9 @@ func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { systemDB, err := sql.Open("mysql", fmt.Sprintf("dump:111@tcp(127.0.0.1:%d)/", port)) require.NoError(t, err) defer systemDB.Close() - for _, sourceVersion := range []string{"4.0.12", "4.0.13", "4.0.14"} { + for _, sourceVersion := range []string{"4.0.12", "4.0.13", "4.0.14", "4.0.15", "4.0.16", "4.0.17"} { t.Run(sourceVersion, func(t *testing.T) { - account := "routine_repair_4015_" + strings.ReplaceAll(sourceVersion, ".", "") + account := "routine_repair_4018_" + strings.ReplaceAll(sourceVersion, ".", "") _, err = systemDB.ExecContext(ctx, "create account "+account+" ADMIN_NAME 'root' IDENTIFIED BY '111'") require.NoError(t, err) defer func() { @@ -127,7 +127,7 @@ func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 118") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 120") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) @@ -140,20 +140,34 @@ func TestV4015LoginRepairsLegacyRoutineCatalog(t *testing.T) { var result int64 require.NoError(t, tenantDB.QueryRowContext(ctx, "select legacy_plus_seven(5)").Scan(&result)) require.Equal(t, int64(12), result) + // The routine envelope and main's correlated-program metadata + // must coexist after binding and every idempotent repair replay. + rows, err := tenantDB.QueryContext(ctx, "select t.x, (select (select legacy_plus_seven(t.x))) from (select 5 as x union all select 6) t order by t.x") + require.NoError(t, err) + defer rows.Close() + for _, want := range []int64{5, 6} { + require.True(t, rows.Next()) + var input int64 + require.NoError(t, rows.Scan(&input, &result)) + require.Equal(t, want, input) + require.Equal(t, want+7, result) + } + require.False(t, rows.Next()) + require.NoError(t, rows.Err()) } checkResult() - checkCatalog("4.0.15", true) + checkCatalog("4.0.18", true) // Explicit replay reaches the handler; a cached second login would not // prove that its DDL is idempotent against the persisted catalog. for range 2 { var mutations int require.NoError(t, sqlExecutor.ExecTxn(ctx, func(txn executor.TxnExecutor) error { - return v4_0_15.Handler.HandleTenantUpgrade(ctx, int32(accountID), + return v4_0_18.Handler.HandleTenantUpgrade(ctx, int32(accountID), &routineRepairTxn{TxnExecutor: txn, mutations: &mutations}) }, executor.Options{}.WithDatabase(catalog.MO_CATALOG). WithAccountID(catalog.System_Account).WithWaitCommittedLogApplied())) require.Zero(t, mutations) - checkCatalog("4.0.15", true) + checkCatalog("4.0.18", true) checkResult() } }) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index f8fff0123fcda..af2bbf7d0ac43 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion118 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion120 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) diff --git a/test/distributed/cases/dml/show/database_statistics.result b/test/distributed/cases/dml/show/database_statistics.result index b7fb6d1808e84..5d07e84b76168 100644 --- a/test/distributed/cases/dml/show/database_statistics.result +++ b/test/distributed/cases/dml/show/database_statistics.result @@ -9,7 +9,7 @@ show table_number from mysql; 6 show table_number from mo_catalog; ➤ Number of tables in mo_catalog[-5,64,0] 𝄀 -61 +62 show table_number from system; [unknown result because it is related to issue#23182] use mo_task; @@ -350,7 +350,7 @@ show table_number from mysql; 6 show table_number from mo_catalog; ➤ Number of tables in mo_catalog[-5,64,0] 𝄀 -38 +39 show table_number from system_metrics; ➤ Number of tables in system_metrics[-5,64,0] 𝄀 11 diff --git a/test/distributed/cases/dml/show/show.result b/test/distributed/cases/dml/show/show.result index ddf75f6041857..18a62e0747c06 100644 --- a/test/distributed/cases/dml/show/show.result +++ b/test/distributed/cases/dml/show/show.result @@ -320,7 +320,7 @@ mo_view_dependencies 𝄀 mo_view_refresh show table_number from mo_catalog; ➤ Number of tables in mo_catalog[-5,64,0] 𝄀 -61 +62 show column_number from mo_database; ➤ Number of columns in mo_database[-5,64,0] 𝄀 9 From 70060ef3e5e026a76bc9117aeb27afa47727ef7e Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 19 Oct 2026 13:56:31 +0800 Subject: [PATCH 231/241] fix(udf): advance Python capability after session control rebase --- docs/design/python_udf_current_stage.md | 24 ++++++----- .../python_udf_current_stage_approval.md | 27 +++++++++++++ pkg/bootstrap/versions/v4_0_18/upgrade.go | 2 +- .../versions/v4_0_18/upgrade_test.go | 10 ++--- pkg/frontend/python_udf_catalog_test.go | 6 +-- pkg/pb/query/query.pb.go | 9 +++-- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 40 +++++++++++++------ .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 22 +++++----- pkg/sql/compile/remoterun.go | 4 +- .../upgrade/upgrade_v4_0_18_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- pkg/udf/testdata/python_status_wire.json | 20 +++++----- 15 files changed, 111 insertions(+), 63 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index cb79e972298f8..84b9ae156ed19 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r21-2026-10-19` | +| Design revision | `python-udf-current-stage-r22-2026-10-19` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `def799e1260dd547cae2e0e54323ea20ec1b7685` (MORPC 119 for coordinator-owned parameterized subquery programs; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r21 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 120 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `8e315d1fe5cdf6661bbf2802515695190dc1c221` (MORPC 120 for current-session KILL authorization and proxy disconnect cleanup; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r22 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 121 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `120` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `121` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 120 and above, +revision that would become authoritative later. At protocol 121 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -102,13 +102,13 @@ Thus a tenant already at upstream final `4.0.17`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 120 before tenant tasks are created, and the repair handler +requires protocol 121 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -120. That value is rollout state in the service runtime, not a computed live +121. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy @@ -119,9 +119,13 @@ receiver. Missing or malformed protocol state fails closed. The shared `Query` protobuf preserves official `correlation = 19`; this PR uses `routine_dependencies = 20`. Both fields survive serialization, generated descriptor lookup, and deep-copy without aliasing. Python-bearing plans require -protocol 120 before Prepare, publication, send, or execution; main-only dependent +protocol 121 before Prepare, publication, send, or execution; main-only dependent programs retain their independent protocol-119 admission. The read-only -`GetPythonUdfStatus` method uses wire capability 120. Worker capability negotiation +`GetPythonUdfStatus` method uses wire capability 121, query method 47, request +field 49 and response field 50. Official session KILL/disconnect methods 45/46, +request fields 47/48 and response fields 48/49 retain capability 120. The status +wire fixtures use these current allocations; older unmerged candidate allocations +are not a cross-binary compatibility contract. Worker capability negotiation remains a separate exact-contract check. The migration has no down handler. Do not manually remove the revision table, @@ -261,7 +265,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-120 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 119 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-121 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 120 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 97593f2dd2ad3..5c6e6dba3dd41 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -420,3 +420,30 @@ These tests do not establish cross-binary downgrade or independent approval. No new Python runtime, production or security scope is added. Independent Architecture and SQL/Planner approval of r21 remains pending; rebase and validation do not provide that approval. + + +## r22 protocol and query allocation addendum (2026-10-19) + +Official main `8e315d1fe5cdf6661bbf2802515695190dc1c221` owns MORPC 120 +for current-session KILL authorization and proxy disconnect cleanup. The governing +`python-udf-current-stage-r22-2026-10-19` proposal preserves that behavior and +allocates the single Python capability 121. Catalog repair, revision publication +and reads, Prepare, prepared reuse, remote sender/receiver and status admission +reject predecessor 120 and mixed 121/120 CNs before Python mutation or execution. +The status client now explicitly enforces the same floor; its old mapping at 119 +did not enforce the previously documented Python floor. + +Official query methods 45/46, request fields 47/48 and response fields 48/49 +remain unchanged. Python status uses method 47, request field 49 and response +field 50. Regenerated bindings, status wire fixtures and the existing combined +client fixture cover coexistence, immediate predecessor rejection, acceptance and +rollback. Independent dependent-program capability 119, table/defaults capability +118, plan correlation field 19 and routine-dependency field 20 remain unchanged. +Published catalog handlers through 4.0.17 and the separate Python 4.0.18 repair +(minimum source 4.0.17) retain their allocation. + +Validation must refresh overlapping query, frontend, CN/proxy, admission and +login-repair evidence after this rebase. Unchanged worker, transport and storage +evidence retains only its original demonstrated scope. This maintenance adds no +Python runtime, production or security scope. Independent Architecture and +SQL/Planner approval of r22 remains pending; these repairs do not provide it. diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade.go b/pkg/bootstrap/versions/v4_0_18/upgrade.go index e3ad29c17acce..2fcc996ce4b2e 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion120, + RequiredProtocolVersion: defines.MORPCVersion121, }, } diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go index 82b58c13430f1..04e243d1d2e37 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.17", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion120), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion121), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.17")) require.False(t, metadata.CanDirectUpgrade("4.0.16")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:119"}`, - `{"result":"cn-a:120,cn-b:119"}`, + `{"result":"cn-a:120"}`, + `{"result":"cn-a:121,cn-b:120"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 120") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 121") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:120"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:121"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 895501d56199a..cea4943e3e44c 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 120"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 121"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion119) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion120) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 120") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 121") require.Empty(t, background.executedSqls) } diff --git a/pkg/pb/query/query.pb.go b/pkg/pb/query/query.pb.go index 9eab02179e8e0..66ada48ff9554 100644 --- a/pkg/pb/query/query.pb.go +++ b/pkg/pb/query/query.pb.go @@ -6,6 +6,11 @@ package query import ( encoding_binary "encoding/binary" fmt "fmt" + io "io" + math "math" + math_bits "math/bits" + time "time" + _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" github_com_gogo_protobuf_types "github.com/gogo/protobuf/types" @@ -16,10 +21,6 @@ import ( timestamp "github.com/matrixorigin/matrixone/pkg/pb/timestamp" txn "github.com/matrixorigin/matrixone/pkg/pb/txn" _ "google.golang.org/protobuf/types/known/timestamppb" - io "io" - math "math" - math_bits "math/bits" - time "time" ) // Reference imports to suppress errors if they are not otherwise used. diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 9f190a3591d83..b08db495715a0 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion119, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion121, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index a08130a34123e..37d27821c4984 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -16,15 +16,18 @@ package client import ( "context" + "testing" + "github.com/matrixorigin/matrixone/pkg/common/runtime" "github.com/stretchr/testify/require" - "testing" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/common/morpc" "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/pb/metadata" "github.com/matrixorigin/matrixone/pkg/pb/query" "github.com/stretchr/testify/assert" + "go.uber.org/zap" ) func testCreateQueryClient(t *testing.T) QueryClient { @@ -37,10 +40,6 @@ func TestMongoDBClientRetireRequiresProtocolVersion5(t *testing.T) { assert.Equal(t, defines.MORPCVersion5, methodVersions[query.CmdMethod_MongoDBClientRetire]) } -func TestGetPythonUdfStatusRequiresProtocolVersion118(t *testing.T) { - assert.Equal(t, defines.MORPCVersion119, methodVersions[query.CmdMethod_GetPythonUdfStatus]) -} - // The name says 54 because that is the contract: the protocol RefreshSessionAuth shipped with. func TestRefreshSessionAuthRequiresProtocolVersion54(t *testing.T) { // A method's entry in methodVersions records the protocol it SHIPPED with, not whatever is @@ -121,16 +120,24 @@ func TestUnwrapResponseError(t *testing.T) { func TestSessionControlProtocol(t *testing.T) { sid := "session-control-version" - rt := runtime.DefaultRuntime() + rt := runtime.NewRuntime(metadata.ServiceType_CN, sid, zap.NewNop()) runtime.SetupServiceBasedRuntime(sid, rt) t.Cleanup(func() { runtime.CompareAndDeleteServiceBasedRuntime(sid, rt) }) - for _, method := range []query.CmdMethod{query.CmdMethod_KillSession, query.CmdMethod_DisconnectSession} { - req := &query.Request{CmdMethod: method} - rt.SetGlobalVariables(runtime.MOProtocolVersion, defines.MORPCVersion119) + for _, test := range []struct { + method query.CmdMethod + floor int64 + }{ + {query.CmdMethod_KillSession, defines.MORPCVersion120}, + {query.CmdMethod_DisconnectSession, defines.MORPCVersion120}, + {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion121}, + } { + require.Equal(t, test.floor, methodVersions[test.method]) + req := &query.Request{CmdMethod: test.method} + rt.SetGlobalVariables(runtime.MOProtocolVersion, test.floor-1) require.Error(t, CheckMethodVersion(context.Background(), sid, req)) - rt.SetGlobalVariables(runtime.MOProtocolVersion, defines.MORPCVersion120) + rt.SetGlobalVariables(runtime.MOProtocolVersion, test.floor) require.NoError(t, CheckMethodVersion(context.Background(), sid, req)) - rt.SetGlobalVariables(runtime.MOProtocolVersion, defines.MORPCVersion119) + rt.SetGlobalVariables(runtime.MOProtocolVersion, test.floor-1) require.Error(t, CheckMethodVersion(context.Background(), sid, req)) } request := &query.Request{CmdMethod: query.CmdMethod_KillSession, KillSessionRequest: &query.KillSessionRequest{ConnID: 1<<32 + 7, KillConnection: true, StatementID: "stmt", Principal: &query.KillSessionPrincipal{AccountID: 10, UserID: 20, Account: "acme", User: "alice", Role: "reader"}}} @@ -145,7 +152,16 @@ func TestSessionControlProtocol(t *testing.T) { decoded = query.Request{} require.NoError(t, decoded.Unmarshal(data)) require.Equal(t, request, &decoded) - for _, response := range []*query.Response{{CmdMethod: query.CmdMethod_KillSession, KillSessionResponse: &query.KillSessionResponse{Found: true}}, {CmdMethod: query.CmdMethod_DisconnectSession, DisconnectSessionResponse: &query.DisconnectSessionResponse{}}} { + require.Equal(t, query.CmdMethod(45), query.CmdMethod_KillSession) + require.Equal(t, query.CmdMethod(46), query.CmdMethod_DisconnectSession) + require.Equal(t, query.CmdMethod(47), query.CmdMethod_GetPythonUdfStatus) + request = &query.Request{CmdMethod: query.CmdMethod_GetPythonUdfStatus} + data, err = request.Marshal() + require.NoError(t, err) + decoded = query.Request{} + require.NoError(t, decoded.Unmarshal(data)) + require.Equal(t, request, &decoded) + for _, response := range []*query.Response{{CmdMethod: query.CmdMethod_KillSession, KillSessionResponse: &query.KillSessionResponse{Found: true}}, {CmdMethod: query.CmdMethod_DisconnectSession, DisconnectSessionResponse: &query.DisconnectSessionResponse{}}, {CmdMethod: query.CmdMethod_GetPythonUdfStatus, GetPythonUdfStatus: query.GetPythonUdfStatusResponse{CNUUID: "cn", Ready: true}}} { data, err = response.Marshal() require.NoError(t, err) var got query.Response diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index c0ad8b5e5ad37..0163bf58c8be7 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion120, + {features.PythonRoutineContract, defines.MORPCVersion121, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index 2c67fb27c46e2..6bc321d716fdc 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion120) + required = max(required, defines.MORPCVersion121) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 34089fff5990b..74da33e2e5dea 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -579,21 +579,21 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { require.True(t, features.ScalarDivision) require.True(t, features.LeastGreatestCollationSemantics) require.True(t, features.TableCollationFunction) - require.Equal(t, defines.MORPCVersion120, remoteExpressionProtocolVersion(features)) - require.Equal(t, defines.MORPCVersion120, executionRemoteExpressionProtocolVersion(c.proc, features)) + require.Equal(t, defines.MORPCVersion121, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion121, executionRemoteExpressionProtocolVersion(c.proc, features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion119, defines.MORPCVersion120} { + for _, version := range []int64{defines.MORPCVersion120, defines.MORPCVersion121} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion120 { + if version < defines.MORPCVersion121 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion119) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion120) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion121) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) require.Equal(t, client.calls, client.releases) } @@ -633,14 +633,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion120, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion121, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion119 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion119) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion120 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion120) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion121 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion121) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 63478e13dff79..369fe658a8d89 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion120) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 120") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion121) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 121") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go index 90af563d9548d..5a0533064382d 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go @@ -127,7 +127,7 @@ func TestV4018LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 120") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 121") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index af2bbf7d0ac43..d22db3b820664 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion120 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion121 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) diff --git a/pkg/udf/testdata/python_status_wire.json b/pkg/udf/testdata/python_status_wire.json index e0cbf0927428b..823e837cb5bee 100644 --- a/pkg/udf/testdata/python_status_wire.json +++ b/pkg/udf/testdata/python_status_wire.json @@ -2,51 +2,51 @@ { "Class": "", "Reason": "CapabilityHandshakeReady", - "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDMQoEY24tMRIGcHl0aG9uGAEgASgBOhhDYXBhYmlsaXR5SGFuZHNoYWtlUmVhZHmwASo=" + "Wire": "CAcQL9oBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAJIDMQoEY24tMRIGcHl0aG9uGAEgASgBOhhDYXBhYmlsaXR5SGFuZHNoYWtlUmVhZHmwASo=" }, { "Class": "DISABLED", "Reason": "RuntimeDisabled", - "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDLgoEY24tMRIGcHl0aG9uIAEyCERJU0FCTEVEOg9SdW50aW1lRGlzYWJsZWSwASo=" + "Wire": "CAcQL9oBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAJIDLgoEY24tMRIGcHl0aG9uIAEyCERJU0FCTEVEOg9SdW50aW1lRGlzYWJsZWSwASo=" }, { "Class": "NOT_ALLOWED", "Reason": "UnisolatedExecutionNotAllowed", - "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDPwoEY24tMRIGcHl0aG9uGAEyC05PVF9BTExPV0VEOh1Vbmlzb2xhdGVkRXhlY3V0aW9uTm90QWxsb3dlZLABKg==" + "Wire": "CAcQL9oBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAJIDPwoEY24tMRIGcHl0aG9uGAEyC05PVF9BTExPV0VEOh1Vbmlzb2xhdGVkRXhlY3V0aW9uTm90QWxsb3dlZLABKg==" }, { "Class": "UNAVAILABLE", "Reason": "WorkerUnavailable", - "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDNQoEY24tMRIGcHl0aG9uGAEgATILVU5BVkFJTEFCTEU6EVdvcmtlclVuYXZhaWxhYmxlsAEq" + "Wire": "CAcQL9oBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAJIDNQoEY24tMRIGcHl0aG9uGAEgATILVU5BVkFJTEFCTEU6EVdvcmtlclVuYXZhaWxhYmxlsAEq" }, { "Class": "UNAVAILABLE", "Reason": "RuntimeStatusUnavailable", - "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDPAoEY24tMRIGcHl0aG9uGAEgATILVU5BVkFJTEFCTEU6GFJ1bnRpbWVTdGF0dXNVbmF2YWlsYWJsZbABKg==" + "Wire": "CAcQL9oBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAJIDPAoEY24tMRIGcHl0aG9uGAEgATILVU5BVkFJTEFCTEU6GFJ1bnRpbWVTdGF0dXNVbmF2YWlsYWJsZbABKg==" }, { "Class": "CONTRACT_MISMATCH", "Reason": "CapabilityContractMismatch", - "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDRAoEY24tMRIGcHl0aG9uGAEgATIRQ09OVFJBQ1RfTUlTTUFUQ0g6GkNhcGFiaWxpdHlDb250cmFjdE1pc21hdGNosAEq" + "Wire": "CAcQL9oBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAJIDRAoEY24tMRIGcHl0aG9uGAEgATIRQ09OVFJBQ1RfTUlTTUFUQ0g6GkNhcGFiaWxpdHlDb250cmFjdE1pc21hdGNosAEq" }, { "Class": "TIMEOUT", "Reason": "CapabilityRequestTimeout", - "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDOAoEY24tMRIGcHl0aG9uGAEgATIHVElNRU9VVDoYQ2FwYWJpbGl0eVJlcXVlc3RUaW1lb3V0sAEq" + "Wire": "CAcQL9oBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAJIDOAoEY24tMRIGcHl0aG9uGAEgATIHVElNRU9VVDoYQ2FwYWJpbGl0eVJlcXVlc3RUaW1lb3V0sAEq" }, { "Class": "CLOSED", "Reason": "RuntimeClosed", - "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDLAoEY24tMRIGcHl0aG9uGAEgATIGQ0xPU0VEOg1SdW50aW1lQ2xvc2VksAEq" + "Wire": "CAcQL9oBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAJIDLAoEY24tMRIGcHl0aG9uGAEgATIGQ0xPU0VEOg1SdW50aW1lQ2xvc2VksAEq" }, { "Class": "INVALID", "Reason": "InvalidLanguage", - "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDLwoEY24tMRIGcHl0aG9uGAEgATIHSU5WQUxJRDoPSW52YWxpZExhbmd1YWdlsAEq" + "Wire": "CAcQL9oBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAJIDLwoEY24tMRIGcHl0aG9uGAEgATIHSU5WQUxJRDoPSW52YWxpZExhbmd1YWdlsAEq" }, { "Class": "INTERNAL", "Reason": "RuntimeError", - "Wire": "CAcQLdoBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAIIDLQoEY24tMRIGcHl0aG9uGAEgATIISU5URVJOQUw6DFJ1bnRpbWVFcnJvcrABKg==" + "Wire": "CAcQL9oBAOoBAPIBAPoBAIICAIoCAJICAKICAMoCANICAJIDLQoEY24tMRIGcHl0aG9uGAEgATIISU5URVJOQUw6DFJ1bnRpbWVFcnJvcrABKg==" } ] From 8a42a2fecd04866e18ac2e98c91cf6ca7e9aa0d1 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 19 Oct 2026 14:52:49 +0800 Subject: [PATCH 232/241] test(ut): synchronize embedded admission with readiness barriers --- optools/ut_embedded_schedule_test.go | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/optools/ut_embedded_schedule_test.go b/optools/ut_embedded_schedule_test.go index 77eb8d5063779..dc7c535fdd59f 100644 --- a/optools/ut_embedded_schedule_test.go +++ b/optools/ut_embedded_schedule_test.go @@ -349,26 +349,39 @@ artifact_dir=$CLUSTER_PREBUILD_DIR ( trap release_children EXIT trap 'exit 143' TERM INT + # Model expiry of any readiness-local clock without a wall-clock sleep. + # This override belongs only to the controller; dispatcher and child reads + # stay real. Untimed reads must consume all five real readiness messages. + ready_observations=0 + function read() { + local argument + for argument in "$@"; do + [[ "$argument" != -t* ]] || return 142 + done + builtin read "$@" || return $? + ready_observations=$((ready_observations + 1)) + } + # Readiness is a barrier, bounded by the harness's existing outer deadline. for heavy in embed bootstrap; do - read -r -t 5 leaf pid <&8 || exit 100 + read -r leaf pid <&8 || exit 100 [[ "$leaf" == "$heavy" ]] || exit 101 kill -0 "$pid" || exit 102 printf 'release\n' >&10 done if [[ "$UT_EMBEDDED_PACKAGE_PARALLEL" == 2 ]]; then - read -r -t 5 first first_pid <&8 || exit 103 - read -r -t 5 second second_pid <&8 || exit 104 + read -r first first_pid <&8 || exit 103 + read -r second second_pid <&8 || exit 104 [[ "$first $second" == 'arrowload dml' || "$first $second" == 'dml arrowload' ]] || exit 105 [[ "$first_pid" != "$second_pid" ]] || exit 106 kill -0 "$first_pid" && kill -0 "$second_pid" || exit 107 printf 'arrowload\n' >&11 printf 'dml\n' >&12 - read -r -t 5 leaf pid <&8 || exit 108 + read -r leaf pid <&8 || exit 108 [[ "$leaf" == sqlintegration ]] || exit 109 printf 'release\n' >&10 else for next in arrowload sqlintegration dml; do - read -r -t 5 leaf pid <&8 || exit 110 + read -r leaf pid <&8 || exit 110 [[ "$leaf" == "$next" ]] || exit 111 case "$leaf" in arrowload) printf 'arrowload\n' >&11 ;; @@ -377,6 +390,7 @@ artifact_dir=$CLUSTER_PREBUILD_DIR esac done fi + [[ "$ready_observations" == 5 ]] || exit 116 ) & driver_pid=$! status=0 @@ -388,7 +402,7 @@ driver_pid="" if [[ "$MODE" == heavy-failure ]]; then [[ "$status" != 0 ]] || exit 112; else [[ "$status" == 0 ]] || exit 113; fi [[ -z "$CLUSTER_PREBUILD_JOB_PID$CURRENT_UT_PID" && ! -d "$artifact_dir" ]] || exit 114 # Reconstruction proves every exclusion interval, not a sampled absence. -awk -v limit="$UT_EMBEDDED_PACKAGE_PARALLEL" ' +awk -v limit="$UT_EMBEDDED_PACKAGE_PARALLEL" -v mode="$MODE" ' $5 == "stage=embedded" && /detail=package_index=[0-4] .*prebuilt=true/ { package=substr($6,7); heavy=(package !~ /\/(arrowload|dml)$/) if ($4 == "event=start") { @@ -397,6 +411,8 @@ $5 == "stage=embedded" && /detail=package_index=[0-4] .*prebuilt=true/ { if (heavy) heavy_active++ } else if ($4 == "event=finish") { if (!started[package] || finished[package]++) bad=1 + expected_status=(mode == "heavy-failure" && package ~ /\/embed$/) ? "status=7" : "status=0" + if ($7 != expected_status) bad=1 active--; if (heavy) heavy_active-- } if (active<0 || active>limit) bad=1 From c77e842676d06e53ac0cd45097717023eab89227 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 19 Oct 2026 17:10:40 +0800 Subject: [PATCH 233/241] fix(udf): allocate MORPC 122 after DECIMAL DIV rebase Preserve official DECIMAL DIV capability 121 and its legacy rollback boundary. Require 122 for Python catalog, prepared/evaluator, remote and status admission. Extend the existing composition fixture with DIV, immediate-predecessor rollback and coordinator-owned dependent-program rejection. Record the r23 proposal. Validation: incremental vet/lint, focused boundary and 11 owning package tests, real DIV SQL and login repair regressions, and production build passed. --- docs/design/python_udf_current_stage.md | 20 +++---- .../python_udf_current_stage_approval.md | 25 ++++++++ pkg/bootstrap/versions/v4_0_18/upgrade.go | 2 +- .../versions/v4_0_18/upgrade_test.go | 10 ++-- pkg/frontend/python_udf_catalog_test.go | 6 +- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 2 +- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 57 +++++++++++++++---- pkg/sql/compile/remoterun.go | 4 +- .../upgrade/upgrade_v4_0_18_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 13 files changed, 97 insertions(+), 39 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 84b9ae156ed19..9c615b66a6884 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r22-2026-10-19` | +| Design revision | `python-udf-current-stage-r23-2026-10-19` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `8e315d1fe5cdf6661bbf2802515695190dc1c221` (MORPC 120 for current-session KILL authorization and proxy disconnect cleanup; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r22 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 121 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `873282742714436bff407dfcdbbe879147162bd3` (MORPC 121 for exact unsigned DECIMAL DIV result domains; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r23 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 122 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `121` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `122` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 121 and above, +revision that would become authoritative later. At protocol 122 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -102,13 +102,13 @@ Thus a tenant already at upstream final `4.0.17`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 121 before tenant tasks are created, and the repair handler +requires protocol 122 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -121. That value is rollout state in the service runtime, not a computed live +122. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy @@ -119,9 +119,9 @@ receiver. Missing or malformed protocol state fails closed. The shared `Query` protobuf preserves official `correlation = 19`; this PR uses `routine_dependencies = 20`. Both fields survive serialization, generated descriptor lookup, and deep-copy without aliasing. Python-bearing plans require -protocol 121 before Prepare, publication, send, or execution; main-only dependent +protocol 122 before Prepare, publication, send, or execution; main-only dependent programs retain their independent protocol-119 admission. The read-only -`GetPythonUdfStatus` method uses wire capability 121, query method 47, request +`GetPythonUdfStatus` method uses wire capability 122, query method 47, request field 49 and response field 50. Official session KILL/disconnect methods 45/46, request fields 47/48 and response fields 48/49 retain capability 120. The status wire fixtures use these current allocations; older unmerged candidate allocations @@ -265,7 +265,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-121 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 120 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-122 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 121 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 5c6e6dba3dd41..0ce670836c384 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -447,3 +447,28 @@ login-repair evidence after this rebase. Unchanged worker, transport and storage evidence retains only its original demonstrated scope. This maintenance adds no Python runtime, production or security scope. Independent Architecture and SQL/Planner approval of r22 remains pending; these repairs do not provide it. + + +## r23 protocol allocation addendum (2026-10-19) + +Official main `873282742714436bff407dfcdbbe879147162bd3` owns MORPC 121 +for exact unsigned DECIMAL DIV result domains. The governing +`python-udf-current-stage-r23-2026-10-19` proposal preserves that capability and +allocates the single Python capability 122 (`latest + 1`). Catalog repair, +revision publication and reads, Prepare, prepared reuse, evaluator, remote +sender/receiver and status admission reject predecessor 121 and mixed 122/121 +CNs before Python mutation or execution. Rolling back the active floor from +122 to 121 disables Python again while retaining ordinary SQL and DIV 121. + +Shared expression feature detection preserves both capabilities: DIV alone +requires 121, while a pipeline containing Python and DIV requires 122. The +coordinator-only dependent-program execution owner remains mandatory regardless +of capability. Upstream DIV overloads, precision, prepared inference, CTAS/view +schema boundaries and the legacy DIV rollback at 120 are unchanged. + +Query methods 45/46/47 and their wire fields retain the r22 allocations. Published +catalog handlers through 4.0.17 and the separate Python 4.0.18 repair (minimum +source 4.0.17) also retain their allocation. This is a protocol admission and +integration repair, with no new Python runtime, production or security scope. +Independent Architecture and SQL/Planner approval of r23 remains pending; this +allocation repair and its validation do not provide it. diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade.go b/pkg/bootstrap/versions/v4_0_18/upgrade.go index 2fcc996ce4b2e..9e9d9fa289e99 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion121, + RequiredProtocolVersion: defines.MORPCVersion122, }, } diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go index 04e243d1d2e37..1e0d007daef55 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.17", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion121), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion122), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.17")) require.False(t, metadata.CanDirectUpgrade("4.0.16")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:120"}`, - `{"result":"cn-a:121,cn-b:120"}`, + `{"result":"cn-a:121"}`, + `{"result":"cn-a:122,cn-b:121"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 121") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 122") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:121"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:122"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index cea4943e3e44c..021d7ea01a3d7 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 121"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 122"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion120) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion121) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 121") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 122") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index b08db495715a0..208a4a9505de3 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion121, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion122, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 37d27821c4984..893e9a7323aeb 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -129,7 +129,7 @@ func TestSessionControlProtocol(t *testing.T) { }{ {query.CmdMethod_KillSession, defines.MORPCVersion120}, {query.CmdMethod_DisconnectSession, defines.MORPCVersion120}, - {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion121}, + {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion122}, } { require.Equal(t, test.floor, methodVersions[test.method]) req := &query.Request{CmdMethod: test.method} diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 0163bf58c8be7..2ba88488fbd23 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion121, + {features.PythonRoutineContract, defines.MORPCVersion122, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index 6bc321d716fdc..e38c6b5b675b9 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion121) + required = max(required, defines.MORPCVersion122) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 74da33e2e5dea..d36958d3e6167 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -571,30 +571,63 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { {Typ: types.T_varchar.ToType().PlanType(), Expr: &planpb.Expr_Lit{Lit: &planpb.Literal{Value: &planpb.Literal_Sval{Sval: ""}}}}, }) require.NoError(t, err) - p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least, tableCollation}}}} + decimalDiv := decimalDivisionProtocolExpr(types.T_uint64) + decimalDiv.Typ = planpb.Type{Id: int32(types.T_uint64), Width: 7, Scale: 0} + decimalDiv.GetF().Func.Obj = function.EncodeOverloadID(function.INTEGER_DIV, function.DecimalIntegerDivUnsignedOverload) + p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least, tableCollation, decimalDiv}}}} features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) + require.True(t, features.DecimalIntegerDivisionSemantics) require.True(t, features.CalendarIntervalNormalization) require.True(t, features.ScalarDivision) require.True(t, features.LeastGreatestCollationSemantics) require.True(t, features.TableCollationFunction) - require.Equal(t, defines.MORPCVersion121, remoteExpressionProtocolVersion(features)) - require.Equal(t, defines.MORPCVersion121, executionRemoteExpressionProtocolVersion(c.proc, features)) + require.Equal(t, defines.MORPCVersion122, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion122, executionRemoteExpressionProtocolVersion(c.proc, features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion120, defines.MORPCVersion121} { + for _, version := range []int64{defines.MORPCVersion121, defines.MORPCVersion122} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion121 { + if version < defines.MORPCVersion122 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion120) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion121) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion122) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) + + // Capability does not transfer the coordinator's dependent-program owner. + dependent := &planpb.Expr{Typ: decimalDiv.Typ, Expr: &planpb.Expr_Dependent{Dependent: &planpb.DependentExpr{ + ProgramId: 1, Inputs: []*planpb.Expr{expr, decimalDiv}, + }}} + op := projection.NewArgument() + defer op.Release() + op.ProjectList = []*planpb.Expr{dependent} + scope := &Scope{Magic: Remote, Proc: c.proc, NodeInfo: engine.Node{Id: "old-worker", Addr: "remote:6001"}, RootOp: op} + _, err = encodeRemoteScope(scope, c.proc) + require.ErrorContains(t, err, "coordinator execution owner") + data, err := (&pipeline.Pipeline{InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{dependent}}}}).Marshal() + require.NoError(t, err) + _, err = decodeScope(data, c.proc, true, nil) + require.ErrorContains(t, err, "coordinator execution owner") + + // Immediate-predecessor rollback disables Python but preserves DIV alone. + client.version = defines.MORPCVersion121 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion121) + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, p, features), "remote destination does not support Python") + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + divOnly := &pipeline.Pipeline{Node: p.Node, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{decimalDiv}}}} + divFeatures, err := planpb.RequiredRemoteExpressionFeatures(divOnly) + require.NoError(t, err) + require.False(t, divFeatures.PythonRoutineContract) + require.True(t, divFeatures.DecimalIntegerDivisionSemantics) + require.Equal(t, defines.MORPCVersion121, remoteExpressionProtocolVersion(divFeatures)) + require.NoError(t, validateRemoteExpressionDestination(c.proc, divOnly, divFeatures)) + require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, divOnly)) require.Equal(t, client.calls, client.releases) } @@ -633,14 +666,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion121, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion122, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion120 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion120) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion121 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion121) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion122 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion122) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 369fe658a8d89..31fb9302e48a4 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion121) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 121") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion122) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 122") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go index 5a0533064382d..4e1b0ea74c69a 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go @@ -127,7 +127,7 @@ func TestV4018LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 121") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 122") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index d22db3b820664..1ba111eb25162 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion121 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion122 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From 96dfec0adf5767179fd5f6061e0eba6d79030d09 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Mon, 19 Oct 2026 21:21:50 +0800 Subject: [PATCH 234/241] fix(udf): preserve temporal epoch and advance Python admission Preserve official MORPC 122 temporal contracts after rebasing onto main d82e828b0a4df9ce635fe573c1e90c5cde978bf9. Move the Python revision capability to 123 across catalog, prepared, status and remote admission. Carry its minimum through the existing execution-stream handshake, including Python-only scopes. Retain the merged CTAS and routine plan descriptors, extend composition and rollback controls, and record the r24 design allocation. Independent Architecture and SQL/Planner approval remains pending. Validation: incremental vet/lint; affected owning packages; protocol, descriptor, real SQL, prepared and login-upgrade tests; production build; prepared temporal golden comparison twice with teardown verified. --- docs/design/python_udf_current_stage.md | 20 ++--- .../python_udf_current_stage_approval.md | 29 +++++++ pkg/bootstrap/versions/v4_0_18/upgrade.go | 2 +- .../versions/v4_0_18/upgrade_test.go | 10 +-- pkg/frontend/python_udf_catalog_test.go | 6 +- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 2 +- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 76 ++++++++++++++----- pkg/sql/compile/remoterun.go | 8 +- pkg/sql/compile/vector_scan_protocol_test.go | 2 +- .../upgrade/upgrade_v4_0_18_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 14 files changed, 117 insertions(+), 48 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 9c615b66a6884..97e62a7af49bc 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r23-2026-10-19` | +| Design revision | `python-udf-current-stage-r24-2026-10-19` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `873282742714436bff407dfcdbbe879147162bd3` (MORPC 121 for exact unsigned DECIMAL DIV result domains; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r23 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 122 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `d82e828b0a4df9ce635fe573c1e90c5cde978bf9` (MORPC 122 for unary TIMESTAMP and dynamic TIME result contracts; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r24 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 123 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `122` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `123` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 122 and above, +revision that would become authoritative later. At protocol 123 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -102,13 +102,13 @@ Thus a tenant already at upstream final `4.0.17`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 122 before tenant tasks are created, and the repair handler +requires protocol 123 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -122. That value is rollout state in the service runtime, not a computed live +123. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy @@ -119,9 +119,9 @@ receiver. Missing or malformed protocol state fails closed. The shared `Query` protobuf preserves official `correlation = 19`; this PR uses `routine_dependencies = 20`. Both fields survive serialization, generated descriptor lookup, and deep-copy without aliasing. Python-bearing plans require -protocol 122 before Prepare, publication, send, or execution; main-only dependent +protocol 123 before Prepare, publication, send, or execution; main-only dependent programs retain their independent protocol-119 admission. The read-only -`GetPythonUdfStatus` method uses wire capability 122, query method 47, request +`GetPythonUdfStatus` method uses wire capability 123, query method 47, request field 49 and response field 50. Official session KILL/disconnect methods 45/46, request fields 47/48 and response fields 48/49 retain capability 120. The status wire fixtures use these current allocations; older unmerged candidate allocations @@ -265,7 +265,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-122 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 121 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-123 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 122 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 0ce670836c384..2da8273755dbc 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -472,3 +472,32 @@ source 4.0.17) also retain their allocation. This is a protocol admission and integration repair, with no new Python runtime, production or security scope. Independent Architecture and SQL/Planner approval of r23 remains pending; this allocation repair and its validation do not provide it. + + +## r24 temporal/Python integration addendum (2026-10-19) + +Official main `d82e828b0a4df9ce635fe573c1e90c5cde978bf9` owns MORPC 122 +for unary TIMESTAMP and dynamic TIME result contracts. The governing +`python-udf-current-stage-r24-2026-10-19` proposal preserves that capability and +allocates the single Python capability 123 (`latest + 1`). Catalog repair, +revision publication and reads, Prepare, prepared reuse, evaluator, remote +sender/receiver and status admission reject predecessor 122 and mixed 123/122 +CNs before Python mutation or execution. Rolling back the active floor from +123 to 122 disables Python while preserving temporal 122 and DECIMAL DIV 121. + +Shared expression feature detection retains Python, temporal and DIV contracts. +Their combined pipeline requires 123; temporal-only requires 122 and DIV-only +requires 121. The existing execution-stream handshake carries the maximum +required by the encoded Python/temporal scope and vector partition contract; +a replacement receiver at 122 cannot admit a Python scope after a 123 probe. +No second handshake or protocol round trip is introduced. Coordinator-owned +dependent-program execution remains mandatory regardless of capability. + +The merged plan schema preserves routine identities and query dependencies as +well as the upstream execution-only CTAS population scalar at CreateTable field +19. Temporal prepared binding, released overload identities, pre-fold CTAS/view +observation, borrowed-plan admission and schema-only clone cleanup retain their +upstream owners and protocol 122 gates. Query status wire fields and catalog +4.0.18 allocations are unchanged. This repair adds no Python runtime, production +or security scope. Independent Architecture and SQL/Planner approval of r24 +remains pending; rebase and validation do not supply that approval. diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade.go b/pkg/bootstrap/versions/v4_0_18/upgrade.go index 9e9d9fa289e99..35f2dd7a790b9 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion122, + RequiredProtocolVersion: defines.MORPCVersion123, }, } diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go index 1e0d007daef55..3ad045d0f4ed0 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.17", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion122), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion123), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.17")) require.False(t, metadata.CanDirectUpgrade("4.0.16")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:121"}`, - `{"result":"cn-a:122,cn-b:121"}`, + `{"result":"cn-a:122"}`, + `{"result":"cn-a:123,cn-b:122"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 122") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 123") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:122"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:123"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 021d7ea01a3d7..5e81b584ab911 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 122"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 123"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion121) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion122) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 122") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 123") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 208a4a9505de3..ad7246ad7153d 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion122, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion123, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 893e9a7323aeb..966621ad685b3 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -129,7 +129,7 @@ func TestSessionControlProtocol(t *testing.T) { }{ {query.CmdMethod_KillSession, defines.MORPCVersion120}, {query.CmdMethod_DisconnectSession, defines.MORPCVersion120}, - {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion122}, + {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion123}, } { require.Equal(t, test.floor, methodVersions[test.method]) req := &query.Request{CmdMethod: test.method} diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 2ba88488fbd23..cdfc3fb6f6fbf 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion122, + {features.PythonRoutineContract, defines.MORPCVersion123, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index e38c6b5b675b9..d46a6f86b4bb2 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion122) + required = max(required, defines.MORPCVersion123) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index d36958d3e6167..f1804842f78d5 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -574,40 +574,64 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { decimalDiv := decimalDivisionProtocolExpr(types.T_uint64) decimalDiv.Typ = planpb.Type{Id: int32(types.T_uint64), Width: 7, Scale: 0} decimalDiv.GetF().Func.Obj = function.EncodeOverloadID(function.INTEGER_DIV, function.DecimalIntegerDivUnsignedOverload) - p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least, tableCollation, decimalDiv}}}} + timestamp, err := plan2.BindFuncExprImplByPlanExpr(c.proc.Ctx, "timestamp", []*planpb.Expr{{Typ: types.T_datetime.ToTypeWithScale(3).PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 3}}}}) + require.NoError(t, err) + dynamicTime := &planpb.Expr{Typ: types.T_time.ToTypeWithScale(6).PlanType(), Expr: &planpb.Expr_F{F: &planpb.Function{ + Func: &planpb.ObjectRef{Obj: function.EncodeOverloadID(function.ADDTIME, 2)}, + Args: []*planpb.Expr{{Typ: types.T_datetime.ToTypeWithScale(6).PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 4}}}, plan2.MakePlan2StringConstExprWithType("02:00:00.000001")}, + }}} + p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least, tableCollation, decimalDiv, timestamp, dynamicTime}}}} features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) + require.True(t, features.TimestampDatetimeResultContracts) + require.True(t, features.DynamicTimeResultContracts) require.True(t, features.DecimalIntegerDivisionSemantics) require.True(t, features.CalendarIntervalNormalization) require.True(t, features.ScalarDivision) require.True(t, features.LeastGreatestCollationSemantics) require.True(t, features.TableCollationFunction) - require.Equal(t, defines.MORPCVersion122, remoteExpressionProtocolVersion(features)) - require.Equal(t, defines.MORPCVersion122, executionRemoteExpressionProtocolVersion(c.proc, features)) + require.Equal(t, defines.MORPCVersion123, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion123, executionRemoteExpressionProtocolVersion(c.proc, features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion121, defines.MORPCVersion122} { + for _, version := range []int64{defines.MORPCVersion122, defines.MORPCVersion123} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion122 { + if version < defines.MORPCVersion123 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion121) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion122) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion123) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) + // The existing execution stream must negotiate the complete encoded contract. + op := projection.NewArgument() + defer op.Release() + op.ProjectList = p.InstructionList[0].ProjectList + scope := &Scope{Magic: Remote, Proc: c.proc, NodeInfo: engine.Node{Id: "old-worker", Addr: "remote:6001"}, RootOp: op} + var required int64 + wire, err := encodeRemoteScopeWithProtocol(scope, c.proc, &required) + require.NoError(t, err) + require.Equal(t, defines.MORPCVersion123, required) + decoded, err := decodeScope(wire, c.proc, true, nil) + require.NoError(t, err) + decoded.release() + // Python alone needs the same stream fence without a temporal feature. + op.ProjectList = []*planpb.Expr{expr} + required = 0 + _, err = encodeRemoteScopeWithProtocol(scope, c.proc, &required) + require.NoError(t, err) + require.Equal(t, defines.MORPCVersion123, required) + // Capability does not transfer the coordinator's dependent-program owner. dependent := &planpb.Expr{Typ: decimalDiv.Typ, Expr: &planpb.Expr_Dependent{Dependent: &planpb.DependentExpr{ ProgramId: 1, Inputs: []*planpb.Expr{expr, decimalDiv}, }}} - op := projection.NewArgument() - defer op.Release() op.ProjectList = []*planpb.Expr{dependent} - scope := &Scope{Magic: Remote, Proc: c.proc, NodeInfo: engine.Node{Id: "old-worker", Addr: "remote:6001"}, RootOp: op} _, err = encodeRemoteScope(scope, c.proc) require.ErrorContains(t, err, "coordinator execution owner") data, err := (&pipeline.Pipeline{InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{dependent}}}}).Marshal() @@ -615,11 +639,27 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { _, err = decodeScope(data, c.proc, true, nil) require.ErrorContains(t, err, "coordinator execution owner") - // Immediate-predecessor rollback disables Python but preserves DIV alone. - client.version = defines.MORPCVersion121 - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion121) + // Immediate-predecessor rollback disables Python but preserves temporal and DIV. + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion122) + _, err = decodeScope(wire, c.proc, true, nil) + require.ErrorContains(t, err, "Python routine execution requires") + client.version = defines.MORPCVersion122 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion122) require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, p, features), "remote destination does not support Python") require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + temporalOnly := &pipeline.Pipeline{Node: p.Node, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{timestamp, dynamicTime}}}} + temporalFeatures, err := planpb.RequiredRemoteExpressionFeatures(temporalOnly) + require.NoError(t, err) + require.False(t, temporalFeatures.PythonRoutineContract) + require.Equal(t, defines.MORPCVersion122, remoteExpressionProtocolVersion(temporalFeatures)) + require.NoError(t, validateRemoteExpressionDestination(c.proc, temporalOnly, temporalFeatures)) + require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, temporalOnly)) + op.ProjectList = temporalOnly.InstructionList[0].ProjectList + required = 0 + _, err = encodeRemoteScopeWithProtocol(scope, c.proc, &required) + require.NoError(t, err) + require.Equal(t, defines.MORPCVersion122, required) + divOnly := &pipeline.Pipeline{Node: p.Node, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{decimalDiv}}}} divFeatures, err := planpb.RequiredRemoteExpressionFeatures(divOnly) require.NoError(t, err) @@ -666,14 +706,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion122, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion123, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion121 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion121) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion122 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion122) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion123 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion123) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 31fb9302e48a4..5bec0f7936700 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -152,8 +152,8 @@ func encodeRemoteScopeWithProtocol(s *Scope, proc *process.Process, requiredProt if err = validateRemoteExpressionFeatures(proc, features); err != nil { return nil, err } - if requiredProtocol != nil && (features.TimestampDatetimeResultContracts || features.DynamicTimeResultContracts) { - *requiredProtocol = max(*requiredProtocol, defines.MORPCVersion122) + if requiredProtocol != nil && (features.PythonRoutineContract || features.TimestampDatetimeResultContracts || features.DynamicTimeResultContracts) { + *requiredProtocol = max(*requiredProtocol, remoteExpressionProtocolVersion(features)) } if requiredProtocol != nil && features.LoadFKIgnoreCheck { *requiredProtocol = max(*requiredProtocol, defines.MORPCVersion125) @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion122) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 122") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion123) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 123") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/sql/compile/vector_scan_protocol_test.go b/pkg/sql/compile/vector_scan_protocol_test.go index 9d02dcccb4ecc..cf7fb50de51c3 100644 --- a/pkg/sql/compile/vector_scan_protocol_test.go +++ b/pkg/sql/compile/vector_scan_protocol_test.go @@ -41,7 +41,7 @@ import ( ) func TestRemotePipelineProtocolCheckOnExecutionStream(t *testing.T) { - for _, minimum := range []int64{defines.MORPCVersion96, defines.MORPCVersion122, defines.MORPCVersion125} { + for _, minimum := range []int64{defines.MORPCVersion96, defines.MORPCVersion122, defines.MORPCVersion123, defines.MORPCVersion125} { for _, tc := range []struct { name string reply *pipeline.Message diff --git a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go index 4e1b0ea74c69a..e4d8e1456774f 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go @@ -127,7 +127,7 @@ func TestV4018LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 122") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 123") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 1ba111eb25162..6d16e9bd1ee67 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion122 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion123 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From a1801e8793f33a38aeef861d627b6b443a08c4fd Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 20 Oct 2026 09:44:03 +0800 Subject: [PATCH 235/241] fix(udf): preserve nonblocking lock protocol during rebase Advance the shared Python routine capability to MORPC 124 after official main allocated 123 to nonblocking row locks. Keep catalog, Prepare, remote sender/receiver and status admission aligned, with predecessor 123 rejection and rollback coverage. Preserve the merged generated plan/parser contracts, extend the descriptor oracle for lock policy fields, and record RFC r25 without changing its independent approval status. --- docs/design/python_udf_current_stage.md | 20 ++++++------ .../python_udf_current_stage_approval.md | 28 ++++++++++++++++ pkg/bootstrap/versions/v4_0_18/upgrade.go | 2 +- .../versions/v4_0_18/upgrade_test.go | 10 +++--- pkg/frontend/python_udf_catalog_test.go | 6 ++-- pkg/pb/plan/merged_descriptor_test.go | 2 ++ pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 2 +- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 32 +++++++++---------- pkg/sql/compile/remoterun.go | 4 +-- pkg/sql/compile/vector_scan_protocol_test.go | 2 +- .../upgrade/upgrade_v4_0_18_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 15 files changed, 74 insertions(+), 44 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 97e62a7af49bc..c237c5788cb01 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r24-2026-10-19` | +| Design revision | `python-udf-current-stage-r25-2026-10-20` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `d82e828b0a4df9ce635fe573c1e90c5cde978bf9` (MORPC 122 for unary TIMESTAMP and dynamic TIME result contracts; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r24 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 123 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `c7bd2e7c1d9ca53daf80d640b3b307902d54161c` (MORPC 123 for nonblocking row-lock admission; temporal contracts retain MORPC 122; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r25 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 124 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `123` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `124` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 123 and above, +revision that would become authoritative later. At protocol 124 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -102,13 +102,13 @@ Thus a tenant already at upstream final `4.0.17`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 123 before tenant tasks are created, and the repair handler +requires protocol 124 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -123. That value is rollout state in the service runtime, not a computed live +124. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy @@ -119,9 +119,9 @@ receiver. Missing or malformed protocol state fails closed. The shared `Query` protobuf preserves official `correlation = 19`; this PR uses `routine_dependencies = 20`. Both fields survive serialization, generated descriptor lookup, and deep-copy without aliasing. Python-bearing plans require -protocol 123 before Prepare, publication, send, or execution; main-only dependent +protocol 124 before Prepare, publication, send, or execution; main-only dependent programs retain their independent protocol-119 admission. The read-only -`GetPythonUdfStatus` method uses wire capability 123, query method 47, request +`GetPythonUdfStatus` method uses wire capability 124, query method 47, request field 49 and response field 50. Official session KILL/disconnect methods 45/46, request fields 47/48 and response fields 48/49 retain capability 120. The status wire fixtures use these current allocations; older unmerged candidate allocations @@ -265,7 +265,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-123 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 122 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-124 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 123 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 2da8273755dbc..17b9b6cedab5d 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -501,3 +501,31 @@ upstream owners and protocol 122 gates. Query status wire fields and catalog 4.0.18 allocations are unchanged. This repair adds no Python runtime, production or security scope. Independent Architecture and SQL/Planner approval of r24 remains pending; rebase and validation do not supply that approval. + + +## r25 nonblocking-lock/Python allocation addendum (2026-10-20) + +Official main `c7bd2e7c1d9ca53daf80d640b3b307902d54161c` owns MORPC 123 +for nonblocking row-lock admission. The governing +`python-udf-current-stage-r25-2026-10-20` proposal preserves that capability and +allocates the single Python capability 124 (`latest + 1`). Catalog repair, +revision publication and reads, Prepare, prepared reuse, evaluator, remote +sender/receiver and status admission reject predecessor 123 and mixed 124/123 +CNs before Python mutation or execution. Rolling back the active floor from +124 to 123 disables Python while preserving nonblocking locks at 123, temporal +contracts at 122, and DECIMAL DIV at 121. + +The merged plan schema retains upstream LockTarget no_wait/skip_locked fields +18/19 together with routine identities, query dependencies and CTAS admission. +Canonical generation and both plan admission postprocessors preserve the union. +Nonblocking locks and dependent expression programs retain their coordinator +execution owners; Python capability 124 does not authorize remote lock policy +execution. The existing stream handshake carries the maximum required feature +floor, with no new protocol round trip or lifecycle mechanism. + +Catalog 4.0.18, its minimum source 4.0.17, query method/field allocations and +Python runtime scope are unchanged. The upstream SQL/planner and cancellation +harness changes require fresh integration evidence rather than unchanged-base +reuse. This maintenance adds no production or security scope. Independent +Architecture and SQL/Planner approval of r25 remains pending; rebase and +validation do not supply that approval. diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade.go b/pkg/bootstrap/versions/v4_0_18/upgrade.go index 35f2dd7a790b9..63853939369ec 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion123, + RequiredProtocolVersion: defines.MORPCVersion124, }, } diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go index 3ad045d0f4ed0..f129395a3455d 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.17", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion123), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion124), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.17")) require.False(t, metadata.CanDirectUpgrade("4.0.16")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:122"}`, - `{"result":"cn-a:123,cn-b:122"}`, + `{"result":"cn-a:123"}`, + `{"result":"cn-a:124,cn-b:123"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 123") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 124") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:123"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:124"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 5e81b584ab911..207a468892754 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 123"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 124"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion122) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion123) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 123") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 124") require.Empty(t, background.executedSqls) } diff --git a/pkg/pb/plan/merged_descriptor_test.go b/pkg/pb/plan/merged_descriptor_test.go index 0d066f3ee51fa..d3da6851e0e1f 100644 --- a/pkg/pb/plan/merged_descriptor_test.go +++ b/pkg/pb/plan/merged_descriptor_test.go @@ -25,12 +25,14 @@ func TestPlanDescriptorMergedContracts(t *testing.T) { // The compressed descriptor must agree with both generated Go contracts. // Resolving a descriptor-only conflict by choosing either side loses one. want := map[string]map[string]int32{ + "Function": {"routine_call": 6}, "Query": {"correlation": 19, "routine_dependencies": 20}, "CreateDatabase": {"defaults": 5}, "AlterDatabase": {"defaults": 3}, "CreateTable": {"database_defaults": 18, "ctas_execution_protocol_version": 19}, "DatabaseDefaults": {"collation_revision": 6}, "ColDef": {"result_column_kind": 23}, + "LockTarget": {"no_wait": 18, "skip_locked": 19}, } file := decodePlanDescriptor(t, proto.FileDescriptor("plan.proto")) for _, message := range file.GetMessageType() { diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index ad7246ad7153d..99051c81f6d31 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion123, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion124, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 966621ad685b3..e45155c61e8b5 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -129,7 +129,7 @@ func TestSessionControlProtocol(t *testing.T) { }{ {query.CmdMethod_KillSession, defines.MORPCVersion120}, {query.CmdMethod_DisconnectSession, defines.MORPCVersion120}, - {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion123}, + {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion124}, } { require.Equal(t, test.floor, methodVersions[test.method]) req := &query.Request{CmdMethod: test.method} diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index cdfc3fb6f6fbf..3f2627994a00f 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion123, + {features.PythonRoutineContract, defines.MORPCVersion124, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index d46a6f86b4bb2..f71b82be31896 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion123) + required = max(required, defines.MORPCVersion124) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index f1804842f78d5..63e315b2d61d2 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -591,21 +591,21 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { require.True(t, features.ScalarDivision) require.True(t, features.LeastGreatestCollationSemantics) require.True(t, features.TableCollationFunction) - require.Equal(t, defines.MORPCVersion123, remoteExpressionProtocolVersion(features)) - require.Equal(t, defines.MORPCVersion123, executionRemoteExpressionProtocolVersion(c.proc, features)) + require.Equal(t, defines.MORPCVersion124, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion124, executionRemoteExpressionProtocolVersion(c.proc, features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion122, defines.MORPCVersion123} { + for _, version := range []int64{defines.MORPCVersion123, defines.MORPCVersion124} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion123 { + if version < defines.MORPCVersion124 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion122) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion123) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) // The existing execution stream must negotiate the complete encoded contract. @@ -616,7 +616,7 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { var required int64 wire, err := encodeRemoteScopeWithProtocol(scope, c.proc, &required) require.NoError(t, err) - require.Equal(t, defines.MORPCVersion123, required) + require.Equal(t, defines.MORPCVersion124, required) decoded, err := decodeScope(wire, c.proc, true, nil) require.NoError(t, err) decoded.release() @@ -625,7 +625,7 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { required = 0 _, err = encodeRemoteScopeWithProtocol(scope, c.proc, &required) require.NoError(t, err) - require.Equal(t, defines.MORPCVersion123, required) + require.Equal(t, defines.MORPCVersion124, required) // Capability does not transfer the coordinator's dependent-program owner. dependent := &planpb.Expr{Typ: decimalDiv.Typ, Expr: &planpb.Expr_Dependent{Dependent: &planpb.DependentExpr{ @@ -640,11 +640,11 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { require.ErrorContains(t, err, "coordinator execution owner") // Immediate-predecessor rollback disables Python but preserves temporal and DIV. - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion122) + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion123) _, err = decodeScope(wire, c.proc, true, nil) require.ErrorContains(t, err, "Python routine execution requires") - client.version = defines.MORPCVersion122 - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion122) + client.version = defines.MORPCVersion123 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion123) require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, p, features), "remote destination does not support Python") require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") temporalOnly := &pipeline.Pipeline{Node: p.Node, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{timestamp, dynamicTime}}}} @@ -706,14 +706,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion123, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion124, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion122 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion122) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion123 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion123) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion124 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 5bec0f7936700..6ebd13ba0521e 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion123) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 123") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion124) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 124") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/sql/compile/vector_scan_protocol_test.go b/pkg/sql/compile/vector_scan_protocol_test.go index cf7fb50de51c3..eb3090748b8dd 100644 --- a/pkg/sql/compile/vector_scan_protocol_test.go +++ b/pkg/sql/compile/vector_scan_protocol_test.go @@ -41,7 +41,7 @@ import ( ) func TestRemotePipelineProtocolCheckOnExecutionStream(t *testing.T) { - for _, minimum := range []int64{defines.MORPCVersion96, defines.MORPCVersion122, defines.MORPCVersion123, defines.MORPCVersion125} { + for _, minimum := range []int64{defines.MORPCVersion96, defines.MORPCVersion122, defines.MORPCVersion123, defines.MORPCVersion124, defines.MORPCVersion125, defines.MORPCVersion126} { for _, tc := range []struct { name string reply *pipeline.Message diff --git a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go index e4d8e1456774f..781d73c02c167 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go @@ -127,7 +127,7 @@ func TestV4018LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 123") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 124") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 6d16e9bd1ee67..a23fa09d2a8c7 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion123 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion124 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From 000bc06f1d15877f550f5d5e4397cdf2bb2be71e Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 20 Oct 2026 15:32:22 +0800 Subject: [PATCH 236/241] Fix Python protocol admission after fractional TIMESTAMPADD rebase --- docs/design/python_udf_current_stage.md | 20 +++--- .../python_udf_current_stage_approval.md | 27 ++++++++ pkg/bootstrap/versions/v4_0_18/upgrade.go | 2 +- .../versions/v4_0_18/upgrade_test.go | 10 +-- pkg/frontend/python_udf_catalog_test.go | 6 +- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 2 +- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 66 ++++++++++++++----- pkg/sql/compile/remoterun.go | 6 +- .../upgrade/upgrade_v4_0_18_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 13 files changed, 103 insertions(+), 46 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index c237c5788cb01..3889a21abedb5 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r25-2026-10-20` | +| Design revision | `python-udf-current-stage-r26-2026-10-20` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `c7bd2e7c1d9ca53daf80d640b3b307902d54161c` (MORPC 123 for nonblocking row-lock admission; temporal contracts retain MORPC 122; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r25 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 124 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `743e749a1e33d6c845bb73999e8c82d297a2b657` (MORPC 124 for exact fractional TIMESTAMPADD SECOND intervals; nonblocking locks retain 123 and prior temporal contracts retain 122; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r26 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 125 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `124` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `125` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 124 and above, +revision that would become authoritative later. At protocol 125 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -102,13 +102,13 @@ Thus a tenant already at upstream final `4.0.17`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 124 before tenant tasks are created, and the repair handler +requires protocol 125 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -124. That value is rollout state in the service runtime, not a computed live +125. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy @@ -119,9 +119,9 @@ receiver. Missing or malformed protocol state fails closed. The shared `Query` protobuf preserves official `correlation = 19`; this PR uses `routine_dependencies = 20`. Both fields survive serialization, generated descriptor lookup, and deep-copy without aliasing. Python-bearing plans require -protocol 124 before Prepare, publication, send, or execution; main-only dependent +protocol 125 before Prepare, publication, send, or execution; main-only dependent programs retain their independent protocol-119 admission. The read-only -`GetPythonUdfStatus` method uses wire capability 124, query method 47, request +`GetPythonUdfStatus` method uses wire capability 125, query method 47, request field 49 and response field 50. Official session KILL/disconnect methods 45/46, request fields 47/48 and response fields 48/49 retain capability 120. The status wire fixtures use these current allocations; older unmerged candidate allocations @@ -265,7 +265,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-124 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 123 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-125 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 124 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 17b9b6cedab5d..09823798d0bc0 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -529,3 +529,30 @@ harness changes require fresh integration evidence rather than unchanged-base reuse. This maintenance adds no production or security scope. Independent Architecture and SQL/Planner approval of r25 remains pending; rebase and validation do not supply that approval. + + +## r26 fractional-TIMESTAMPADD/Python allocation addendum (2026-10-20) + +Official main 743e749a1e33d6c845bb73999e8c82d297a2b657 owns MORPC 124 +for exact fractional TIMESTAMPADD SECOND intervals. The governing +python-udf-current-stage-r26-2026-10-20 proposal preserves that capability and +allocates the single Python capability 125 (latest + 1). Catalog repair, +revision publication and reads, Prepare, prepared reuse, evaluator, remote +sender/receiver and status admission reject predecessor 124 and mixed 125/124 +CNs before Python mutation or execution. Rolling the active floor from 125 +to 124 disables Python while retaining fractional TIMESTAMPADD at 124, +nonblocking locks at 123, prior temporal contracts at 122 and DECIMAL DIV at 121. + +The combined Python/fractional-temporal pipeline requires 125. Fractional-only +pipelines require 124, and rollback to 123 rejects them. The existing stream +handshake carries the maximum required feature floor; no new round trip or +resource-lifecycle owner is introduced. Coordinator-dependent programs keep +their independent ownership restriction. + +The upstream function identity 601, literal/source normalization, format-3 dump +reader/writer contract and legacy epoch-specific bindings remain upstream-owned. +Fresh protocol composition, dump roundtrip and real SQL/prepared tests are +required after this merge. Catalog 4.0.18 and its minimum source 4.0.17, query +method/field allocations and Python runtime scope are unchanged. Independent +Architecture and SQL/Planner approval of r26 remains pending; rebase and +validation do not supply that approval. No production or security scope is added. diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade.go b/pkg/bootstrap/versions/v4_0_18/upgrade.go index 63853939369ec..2e3c38eff96c3 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion124, + RequiredProtocolVersion: defines.MORPCVersion125, }, } diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go index f129395a3455d..dc434dbf71d42 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.17", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion124), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion125), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.17")) require.False(t, metadata.CanDirectUpgrade("4.0.16")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:123"}`, - `{"result":"cn-a:124,cn-b:123"}`, + `{"result":"cn-a:124"}`, + `{"result":"cn-a:125,cn-b:124"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 124") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 125") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:124"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:125"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 207a468892754..7f02cab7c5f17 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 124"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 125"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion123) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion124) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 124") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 125") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 99051c81f6d31..7647fe6f42183 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion124, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion125, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index e45155c61e8b5..f4fabc05167f7 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -129,7 +129,7 @@ func TestSessionControlProtocol(t *testing.T) { }{ {query.CmdMethod_KillSession, defines.MORPCVersion120}, {query.CmdMethod_DisconnectSession, defines.MORPCVersion120}, - {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion124}, + {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion125}, } { require.Equal(t, test.floor, methodVersions[test.method]) req := &query.Request{CmdMethod: test.method} diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index 3f2627994a00f..f16b2690fd9c0 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion124, + {features.PythonRoutineContract, defines.MORPCVersion125, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index f71b82be31896..fd78e16939e7d 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion124) + required = max(required, defines.MORPCVersion125) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 63e315b2d61d2..125a6ff2de22b 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -580,32 +580,37 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { Func: &planpb.ObjectRef{Obj: function.EncodeOverloadID(function.ADDTIME, 2)}, Args: []*planpb.Expr{{Typ: types.T_datetime.ToTypeWithScale(6).PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 4}}}, plan2.MakePlan2StringConstExprWithType("02:00:00.000001")}, }}} - p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least, tableCollation, decimalDiv, timestamp, dynamicTime}}}} + fractionalSecond := &planpb.Expr{Typ: types.T_int64.ToType().PlanType(), Expr: &planpb.Expr_F{F: &planpb.Function{ + Func: &planpb.ObjectRef{Obj: function.EncodeOverloadID(function.TIMESTAMPADD_SECOND_INTERVAL, 5)}, + Args: []*planpb.Expr{{Typ: planpb.Type{Id: int32(types.T_decimal64), Width: 18, Scale: 7}, Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 5}}}}, + }}} + p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least, tableCollation, decimalDiv, timestamp, dynamicTime, fractionalSecond}}}} features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) require.True(t, features.TimestampDatetimeResultContracts) require.True(t, features.DynamicTimeResultContracts) + require.True(t, features.TimestampAddSecondIntervals) require.True(t, features.DecimalIntegerDivisionSemantics) require.True(t, features.CalendarIntervalNormalization) require.True(t, features.ScalarDivision) require.True(t, features.LeastGreatestCollationSemantics) require.True(t, features.TableCollationFunction) - require.Equal(t, defines.MORPCVersion124, remoteExpressionProtocolVersion(features)) - require.Equal(t, defines.MORPCVersion124, executionRemoteExpressionProtocolVersion(c.proc, features)) + require.Equal(t, defines.MORPCVersion125, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion125, executionRemoteExpressionProtocolVersion(c.proc, features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion123, defines.MORPCVersion124} { + for _, version := range []int64{defines.MORPCVersion124, defines.MORPCVersion125} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion124 { + if version < defines.MORPCVersion125 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion123) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion125) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) // The existing execution stream must negotiate the complete encoded contract. @@ -616,7 +621,7 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { var required int64 wire, err := encodeRemoteScopeWithProtocol(scope, c.proc, &required) require.NoError(t, err) - require.Equal(t, defines.MORPCVersion124, required) + require.Equal(t, defines.MORPCVersion125, required) decoded, err := decodeScope(wire, c.proc, true, nil) require.NoError(t, err) decoded.release() @@ -625,7 +630,7 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { required = 0 _, err = encodeRemoteScopeWithProtocol(scope, c.proc, &required) require.NoError(t, err) - require.Equal(t, defines.MORPCVersion124, required) + require.Equal(t, defines.MORPCVersion125, required) // Capability does not transfer the coordinator's dependent-program owner. dependent := &planpb.Expr{Typ: decimalDiv.Typ, Expr: &planpb.Expr_Dependent{Dependent: &planpb.DependentExpr{ @@ -639,14 +644,39 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { _, err = decodeScope(data, c.proc, true, nil) require.ErrorContains(t, err, "coordinator execution owner") - // Immediate-predecessor rollback disables Python but preserves temporal and DIV. - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion123) + // Immediate-predecessor rollback disables Python but preserves fractional + // TIMESTAMPADD at 124, earlier temporal contracts at 122 and DIV at 121. + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) _, err = decodeScope(wire, c.proc, true, nil) require.ErrorContains(t, err, "Python routine execution requires") - client.version = defines.MORPCVersion123 - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion123) + client.version = defines.MORPCVersion124 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, p, features), "remote destination does not support Python") require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + fractionalOnly := &pipeline.Pipeline{Node: p.Node, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{fractionalSecond}}}} + fractionalFeatures, err := planpb.RequiredRemoteExpressionFeatures(fractionalOnly) + require.NoError(t, err) + require.False(t, fractionalFeatures.PythonRoutineContract) + require.True(t, fractionalFeatures.TimestampAddSecondIntervals) + require.Equal(t, defines.MORPCVersion124, remoteExpressionProtocolVersion(fractionalFeatures)) + require.NoError(t, validateRemoteExpressionDestination(c.proc, fractionalOnly, fractionalFeatures)) + require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, fractionalOnly)) + op.ProjectList = fractionalOnly.InstructionList[0].ProjectList + required = 0 + fractionalWire, err := encodeRemoteScopeWithProtocol(scope, c.proc, &required) + require.NoError(t, err) + require.Equal(t, defines.MORPCVersion124, required) + decoded, err = decodeScope(fractionalWire, c.proc, true, nil) + require.NoError(t, err) + decoded.release() + client.version = defines.MORPCVersion123 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion123) + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, fractionalOnly, fractionalFeatures), "version 124") + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, fractionalOnly), "fractional TIMESTAMPADD SECOND requires") + _, err = decodeScope(fractionalWire, c.proc, true, nil) + require.ErrorContains(t, err, "fractional TIMESTAMPADD SECOND requires") + client.version = defines.MORPCVersion124 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) temporalOnly := &pipeline.Pipeline{Node: p.Node, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{timestamp, dynamicTime}}}} temporalFeatures, err := planpb.RequiredRemoteExpressionFeatures(temporalOnly) require.NoError(t, err) @@ -706,14 +736,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion124, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion125, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion123 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion123) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion124 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion125 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion125) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 6ebd13ba0521e..65f25783101d6 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -152,7 +152,7 @@ func encodeRemoteScopeWithProtocol(s *Scope, proc *process.Process, requiredProt if err = validateRemoteExpressionFeatures(proc, features); err != nil { return nil, err } - if requiredProtocol != nil && (features.PythonRoutineContract || features.TimestampDatetimeResultContracts || features.DynamicTimeResultContracts) { + if requiredProtocol != nil && (features.PythonRoutineContract || features.TimestampDatetimeResultContracts || features.DynamicTimeResultContracts || features.TimestampAddSecondIntervals) { *requiredProtocol = max(*requiredProtocol, remoteExpressionProtocolVersion(features)) } if requiredProtocol != nil && features.LoadFKIgnoreCheck { @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion124) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 124") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion125) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 125") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go index 781d73c02c167..19d6aaed5c7aa 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go @@ -127,7 +127,7 @@ func TestV4018LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 124") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 125") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index a23fa09d2a8c7..31fc5b833bdaf 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion124 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion125 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From ead58467a920bb80baf095da1a2c366ad16f1e5c Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 20 Oct 2026 20:29:14 +0800 Subject: [PATCH 237/241] Test merged diagnostic expression transport contracts --- pkg/pb/plan/merged_descriptor_test.go | 2 ++ pkg/sql/compile/remoterun_test.go | 11 ++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pkg/pb/plan/merged_descriptor_test.go b/pkg/pb/plan/merged_descriptor_test.go index d3da6851e0e1f..b698afdc4f2f8 100644 --- a/pkg/pb/plan/merged_descriptor_test.go +++ b/pkg/pb/plan/merged_descriptor_test.go @@ -26,6 +26,8 @@ func TestPlanDescriptorMergedContracts(t *testing.T) { // Resolving a descriptor-only conflict by choosing either side loses one. want := map[string]map[string]int32{ "Function": {"routine_call": 6}, + "Node": {"dedup_key_exprs": 95}, + "PreInsertUkCtx": {"key_diagnostic_exprs": 19}, "Query": {"correlation": 19, "routine_dependencies": 20}, "CreateDatabase": {"defaults": 5}, "AlterDatabase": {"defaults": 3}, diff --git a/pkg/sql/compile/remoterun_test.go b/pkg/sql/compile/remoterun_test.go index 1bd6704c8dcee..e05c625b6765d 100644 --- a/pkg/sql/compile/remoterun_test.go +++ b/pkg/sql/compile/remoterun_test.go @@ -5436,7 +5436,10 @@ func TestRemoteStatementSendErrorPreservesCauseWithoutMaskingInvariant(t *testin func TestDedupDiagnosticExpressionsRemoteRoundTrip(t *testing.T) { proc := testutil.NewProcess(t) ctx := &scopeContext{id: 1, root: &scopeContext{}, parent: &scopeContext{}} - exprs := []*planpb.Expr{{Typ: types.T_varchar.ToType().PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{RelPos: 1, ColPos: 3}}}} + exprs := []*planpb.Expr{ + {Typ: types.T_varchar.ToType().PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{RelPos: 1, ColPos: 3}}}, + {Expr: &planpb.Expr_F{F: &planpb.Function{RoutineCall: &planpb.RoutineCall{}}}}, + } diagnosticExprs := func(op vm.Operator) []*planpb.Expr { switch arg := op.(type) { case *dedupjoin.DedupJoin: @@ -5462,6 +5465,9 @@ func TestDedupDiagnosticExpressionsRemoteRoundTrip(t *testing.T) { require.NoError(t, err) decoded := new(pipeline.Instruction) require.NoError(t, decoded.Unmarshal(wire)) + features, err := planpb.RequiredRemoteExpressionFeatures(decoded) + require.NoError(t, err) + require.True(t, features.PythonRoutineContract, "diagnostic expression carriers must retain protocol admission") restored, err := convertToVmOperator(decoded, ctx, nil) require.NoError(t, err) require.Equal(t, exprs, diagnosticExprs(restored)) @@ -5474,6 +5480,9 @@ func TestDedupDiagnosticExpressionsRemoteRoundTrip(t *testing.T) { require.NoError(t, err) decoded := new(pipeline.Instruction) require.NoError(t, decoded.Unmarshal(wire)) + features, err := planpb.RequiredRemoteExpressionFeatures(decoded) + require.NoError(t, err) + require.True(t, features.PythonRoutineContract, "diagnostic expression carriers must retain protocol admission") restored, err := convertToVmOperator(decoded, ctx, nil) require.NoError(t, err) require.Equal(t, exprs, restored.(*preinsertunique.PreInsertUnique).PreInsertCtx.KeyDiagnosticExprs[0].List) From af1a708fb179ecca993b26fe858479d4091aa452 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Tue, 20 Oct 2026 23:14:07 +0800 Subject: [PATCH 238/241] Expose fixed-snapshot namespace admission diagnostics --- pkg/embed/check_constraint_namespace_test.go | 57 ++++++++++++-------- pkg/sql/colexec/lockop/admission.go | 9 +++- pkg/sql/colexec/lockop/admission_test.go | 11 ++++ 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/pkg/embed/check_constraint_namespace_test.go b/pkg/embed/check_constraint_namespace_test.go index 976a07bb545d6..25add073f7d8c 100644 --- a/pkg/embed/check_constraint_namespace_test.go +++ b/pkg/embed/check_constraint_namespace_test.go @@ -393,7 +393,8 @@ func TestCheckConstraintNamespace(t *testing.T) { var serverError *mysql.MySQLError require.ErrorAs(t, initialErr, &serverError) require.EqualValues(t, 20619, serverError.Number) - require.Equal(t, "w-w conflict: tableID: 2, catalog namespace snapshot is stale", serverError.Message) + require.Contains(t, serverError.Message, "w-w conflict: tableID: 2, catalog namespace snapshot is stale (snapshot=") + require.Contains(t, serverError.Message, "grant="+grant.Timestamp.DebugString()) require.GreaterOrEqual(t, attempts, 2) require.NotEmpty(t, replacement) require.NotEqual(t, original, replacement, "recovery must create a new autocommit transaction") @@ -465,6 +466,8 @@ func TestCheckConstraintNamespace(t *testing.T) { require.ErrorAs(t, err, &conflict) require.Equal(t, moerr.ErrTxnWWConflict, conflict.ErrorCode()) require.ErrorContains(t, err, "catalog namespace snapshot is stale") + require.ErrorContains(t, err, "snapshot="+originalSnapshot.DebugString()) + require.ErrorContains(t, err, "grant=") grantsMu.Lock() observed := append([]lock.Result(nil), grants...) grantsMu.Unlock() @@ -768,7 +771,9 @@ func execCheckNamespaceSI(parent context.Context, exec func(context.Context, str return attempts, stopped(err) } var serverError *mysql.MySQLError - if !errors.As(err, &serverError) || serverError.Number != 20619 || serverError.Message != "w-w conflict: tableID: 2, catalog namespace snapshot is stale" { + const namespaceAbort = "w-w conflict: tableID: 2, catalog namespace snapshot is stale" + if !errors.As(err, &serverError) || serverError.Number != 20619 || + (serverError.Message != namespaceAbort && !strings.HasPrefix(serverError.Message, namespaceAbort+" (snapshot=")) { return attempts, err } lastConflict = err @@ -780,7 +785,7 @@ func TestCheckNamespaceSIRecoveryControl(t *testing.T) { const syncSQL = "select mo_ctl('cn', 'SYNCCOMMIT', '')" conflict := &mysql.MySQLError{Number: 20619, Message: "w-w conflict: tableID: 2, catalog namespace snapshot is stale"} t.Run("only exact namespace abort is recoverable", func(t *testing.T) { - for _, terminal := range []error{nil, errors.New("connection failure"), &mysql.MySQLError{Number: 3822, Message: "duplicate name"}, &mysql.MySQLError{Number: 3819, Message: "check violation"}, &mysql.MySQLError{Number: 20619, Message: "other write conflict"}, &mysql.MySQLError{Number: 20619, Message: "w-w conflict: tableID: 3, catalog namespace snapshot is stale"}} { + for _, terminal := range []error{nil, errors.New("connection failure"), &mysql.MySQLError{Number: 3822, Message: "duplicate name"}, &mysql.MySQLError{Number: 3819, Message: "check violation"}, &mysql.MySQLError{Number: 20619, Message: "other write conflict"}, &mysql.MySQLError{Number: 20619, Message: "w-w conflict: tableID: 3, catalog namespace snapshot is stale"}, &mysql.MySQLError{Number: 20619, Message: "w-w conflict: tableID: 3, catalog namespace snapshot is stale (snapshot=1-0, grant=2-0)"}, &mysql.MySQLError{Number: 20619, Message: conflict.Message + " extra"}, &mysql.MySQLError{Number: 20619, Message: conflict.Message + " (other=1)"}} { calls := 0 attempts, err := execCheckNamespaceSI(t.Context(), func(_ context.Context, q string) error { calls++ @@ -795,25 +800,33 @@ func TestCheckNamespaceSIRecoveryControl(t *testing.T) { require.Equal(t, terminal, err) } }) - t.Run("recover then preserve terminal result", func(t *testing.T) { - var calls []string - ddl := 0 - terminal := &mysql.MySQLError{Number: 3822} - attempts, err := execCheckNamespaceSI(t.Context(), func(_ context.Context, q string) error { - calls = append(calls, q) - if q == syncSQL { - return nil - } - ddl++ - if ddl == 1 { - return fmt.Errorf("wrapped: %w", conflict) - } - return terminal - }, statement) - require.Equal(t, 2, attempts) - require.Same(t, terminal, err) - require.Equal(t, []string{syncSQL, statement, syncSQL, statement}, calls) - }) + for _, recoverable := range []struct { + name string + err error + }{ + {"legacy", conflict}, + {"diagnostic", &mysql.MySQLError{Number: 20619, Message: conflict.Message + " (snapshot=1-0, grant=2-0, lock-service=\"cn\", binding-version=1, group=0, has-conflict=false, has-prev-commit=false)"}}, + } { + t.Run("recover then preserve terminal result/"+recoverable.name, func(t *testing.T) { + var calls []string + ddl := 0 + terminal := &mysql.MySQLError{Number: 3822} + attempts, err := execCheckNamespaceSI(t.Context(), func(_ context.Context, q string) error { + calls = append(calls, q) + if q == syncSQL { + return nil + } + ddl++ + if ddl == 1 { + return fmt.Errorf("wrapped: %w", recoverable.err) + } + return terminal + }, statement) + require.Equal(t, 2, attempts) + require.Same(t, terminal, err) + require.Equal(t, []string{syncSQL, statement, syncSQL, statement}, calls) + }) + } t.Run("synchronization failure stops before DDL", func(t *testing.T) { failure := errors.New("sync failed") calls := 0 diff --git a/pkg/sql/colexec/lockop/admission.go b/pkg/sql/colexec/lockop/admission.go index cc5870f6f3f8b..1454b25703884 100644 --- a/pkg/sql/colexec/lockop/admission.go +++ b/pkg/sql/colexec/lockop/admission.go @@ -16,6 +16,7 @@ package lockop import ( "context" + "fmt" "github.com/matrixorigin/matrixone/pkg/common/moerr" "github.com/matrixorigin/matrixone/pkg/container/batch" @@ -100,7 +101,13 @@ func LockRowsForFixedSnapshotAdmissionResult( return lock.Result{}, moerr.NewLockTableBindChangedNoCtx() } if proc.GetTxnOperator().Txn().SnapshotTS.Less(result.Timestamp) { - return lock.Result{}, moerr.NewTxnWWConflict(ctx, tableID, "catalog namespace snapshot is stale") + // Keep the fixed snapshot and grant that rejected admission together. + // The binding identifies the lock service, not the committing writer. + reason := fmt.Sprintf("catalog namespace snapshot is stale (snapshot=%s, grant=%s, lock-service=%q, binding-version=%d, group=%d, has-conflict=%t, has-prev-commit=%t)", + proc.GetTxnOperator().Txn().SnapshotTS.DebugString(), result.Timestamp.DebugString(), + result.LockedOn.ServiceID, result.LockedOn.Version, result.LockedOn.Group, + result.HasConflict, result.HasPrevCommit) + return lock.Result{}, moerr.NewTxnWWConflict(ctx, tableID, reason) } return result, nil } diff --git a/pkg/sql/colexec/lockop/admission_test.go b/pkg/sql/colexec/lockop/admission_test.go index 797bf5956aa26..ca7da2d55389f 100644 --- a/pkg/sql/colexec/lockop/admission_test.go +++ b/pkg/sql/colexec/lockop/admission_test.go @@ -16,6 +16,7 @@ package lockop import ( "context" + "fmt" "testing" "time" @@ -98,6 +99,7 @@ func TestFixedSnapshotNamespaceAdmission(t *testing.T) { op.TxnRef().Isolation = txnpb.TxnIsolation_SI snapshot := op.Txn().SnapshotTS ls := proc.GetLockService() + var granted lock.Result proc.Base.LockService = admissionLockService{LockService: ls, lockFn: func(ctx context.Context, table uint64, rows [][]byte, id []byte, opts lock.LockOptions) (lock.Result, error) { require.True(t, opts.KeepRows) require.Equal(t, lock.Granularity_Row, opts.Granularity) @@ -118,6 +120,7 @@ func TestFixedSnapshotNamespaceAdmission(t *testing.T) { case "missing_watermark": result.Timestamp = timestamp.Timestamp{} } + granted = result return result, err }} result, err := LockRowsForFixedSnapshotAdmissionResult(proc.Ctx, nil, proc, 48, bat, 0, @@ -133,6 +136,14 @@ func TestFixedSnapshotNamespaceAdmission(t *testing.T) { default: require.True(t, moerr.IsMoErrCode(err, moerr.ErrTxnWWConflict), "%v", err) require.Empty(t, result, "failed admission cannot publish a grant") + require.ErrorContains(t, err, "catalog namespace snapshot is stale") + require.ErrorContains(t, err, "snapshot="+snapshot.DebugString()) + require.ErrorContains(t, err, "grant="+snapshot.Next().DebugString()) + require.ErrorContains(t, err, fmt.Sprintf("lock-service=%q", granted.LockedOn.ServiceID)) + require.ErrorContains(t, err, fmt.Sprintf("binding-version=%d", granted.LockedOn.Version)) + require.ErrorContains(t, err, fmt.Sprintf("group=%d", granted.LockedOn.Group)) + require.ErrorContains(t, err, fmt.Sprintf("has-conflict=%t", outcome == "waited_newer")) + require.ErrorContains(t, err, fmt.Sprintf("has-prev-commit=%t", outcome == "waited_newer")) } require.Equal(t, snapshot, op.Txn().SnapshotTS) require.Equal(t, 1, waiter.calls, "SI admission must never call the snapshot waiter") From 1e50e33908d8254022e0b8e09dccfd8d257fc744 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 21 Oct 2026 11:04:56 +0800 Subject: [PATCH 239/241] Reset prepared FIELD history when routine dependencies change --- pkg/frontend/computation_wrapper.go | 19 ++- pkg/frontend/prepared_execution.go | 17 +++ pkg/frontend/prepared_field_retry_test.go | 100 +++++++++++++++ .../prepared_routine_field_test.go | 121 ++++++++++++++++++ 4 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 pkg/tests/sqlintegration/prepared_routine_field_test.go diff --git a/pkg/frontend/computation_wrapper.go b/pkg/frontend/computation_wrapper.go index 507206ef59ec4..315e593f49d8a 100644 --- a/pkg/frontend/computation_wrapper.go +++ b/pkg/frontend/computation_wrapper.go @@ -1506,14 +1506,14 @@ func initExecuteStmtParamWithResolverInSession( cwft.planGenerationReused = !needRebuild fieldTypes := prepareStmt.fieldTypes // Session DDL and temporary-table revisions conservatively invalidate plans, - // not SQL type history. Reset only for changed captured dependencies or + // not SQL type history. Reset for changed captured table/routine dependencies or // type-affecting mode/protocol changes. Rebinding may discover a different // dependency (e.g. a temporary table shadow), checked before publication. boolModeMismatch := prepareStmt.sqlModeFlagsSet && prepareStmt.BoolSumAvg != currentBoolSumAvg numericModeMismatch := boolModeMismatch || prepareStmt.sqlModeFlagsSet && prepareStmt.NoUnsignedSubtraction != currentNoUnsignedSubtraction || prepareStmt.divPrecisionIncrementSet && prepareStmt.divPrecisionIncrement != currentDivPrecisionIncrement - resetFieldTypes := schemaChanged || prepareStmt.NativeMode != currentNativeMode || protocolMismatch || prepareStmt.fieldTypesResetPending + resetFieldTypes := schemaChanged || routineChanged || prepareStmt.NativeMode != currentNativeMode || protocolMismatch || prepareStmt.fieldTypesResetPending if resetFieldTypes { fieldTypes = nil } @@ -2079,6 +2079,8 @@ func (cwft *TxnComputationWrapper) releaseRuntimeCacheRetiredCompiles() { type preparedExecutionRetry struct { fieldTypes *plan2.PreparedFieldTypes fieldSchemas []*plan2.ObjectRef + fieldRoutines []*plan.RoutinePlanDependency + fieldRoutineErr error bindings []plan2.PreparedSourceBinding paramVals []any preparedPlan *plan2.Plan @@ -3039,6 +3041,9 @@ func buildPlanForCompileRetry( ctx = plan2.WithPreparedUserVariableBindings(ctx, preparedRetry.preparedPlan) ctx = plan2.WithPreparedFieldTypes(ctx, preparedRetry.fieldTypes) if preparedRetry.fieldTypes != nil { + if preparedRetry.fieldRoutineErr != nil { + return nil, preparedRetry.fieldRoutineErr + } previous := compilerContext.GetContext() compilerContext.SetContext(ctx) defer compilerContext.SetContext(previous) @@ -3047,6 +3052,7 @@ func buildPlanForCompileRetry( // binding with retained history; retry is not another history publisher. dependencies := &plan.Plan{Plan: &plan.Plan_Query{Query: &plan.Query{ CatalogDependencies: preparedRetry.fieldSchemas, + RoutineDependencies: preparedRetry.fieldRoutines, }}} changed, err := checkModify(dependencies, compilerContext.Resolve) if err != nil { @@ -3055,6 +3061,15 @@ func buildPlanForCompileRetry( if changed { return nil, moerr.NewTxnNeedRetryWithDefChanged(ctx) } + // Routine return declarations also belong to this generation, even + // when the plan has no table dependency or retains the same UINT64 result. + changed, err = validateRoutinePlanDependencies(ctx, ses, dependencies) + if err != nil { + return nil, err + } + if changed { + return nil, moerr.NewTxnNeedRetryWithDefChanged(ctx) + } } bound, err := buildPreparedBoundQuery(ctx, ses, compilerContext, stmt, preparedRetry.bindings, preparedRetry.paramVals) if err != nil { diff --git a/pkg/frontend/prepared_execution.go b/pkg/frontend/prepared_execution.go index 537723fc8b8f4..b9b4c1173377a 100644 --- a/pkg/frontend/prepared_execution.go +++ b/pkg/frontend/prepared_execution.go @@ -25,6 +25,7 @@ import ( "github.com/matrixorigin/matrixone/pkg/container/types" "github.com/matrixorigin/matrixone/pkg/container/vector" "github.com/matrixorigin/matrixone/pkg/defines" + "github.com/matrixorigin/matrixone/pkg/pb/plan" "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql" "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" @@ -185,6 +186,8 @@ func (cwft *TxnComputationWrapper) preparedExecutionRetry() *preparedExecutionRe var preparedPlan *plan2.Plan var fieldTypes *plan2.PreparedFieldTypes var fieldSchemas []*plan2.ObjectRef + var fieldRoutines []*plan.RoutinePlanDependency + var fieldRoutineErr error if cwft.preparedStmt != nil { fieldTypes = cwft.preparedStmt.fieldTypes if fieldTypes != nil { @@ -197,6 +200,18 @@ func (cwft *TxnComputationWrapper) preparedExecutionRetry() *preparedExecutionRe fieldSchemas[i] = proto.Clone(schema).(*plan2.ObjectRef) } } + // Include nested background-query dependencies under the existing + // count/byte/depth bounds. Retry must retain facts, not the mutable plan. + var routines []*plan.RoutinePlanDependency + routines, fieldRoutineErr = routinePlanDependencies(cwft.preparedStmt.PreparePlan.GetDcl().GetPrepare().Plan) + if fieldRoutineErr == nil { + fieldRoutines = make([]*plan.RoutinePlanDependency, len(routines)) + for i, dependency := range routines { + if dependency != nil { + fieldRoutines[i] = proto.Clone(dependency).(*plan.RoutinePlanDependency) + } + } + } } } if cwft.preparedStmt != nil && strings.IndexByte(cwft.preparedStmt.Sql, '@') >= 0 { @@ -205,6 +220,8 @@ func (cwft *TxnComputationWrapper) preparedExecutionRetry() *preparedExecutionRe return &preparedExecutionRetry{ fieldTypes: fieldTypes, fieldSchemas: fieldSchemas, + fieldRoutines: fieldRoutines, + fieldRoutineErr: fieldRoutineErr, paramVals: append([]any(nil), cwft.paramVals...), bindings: append([]plan2.PreparedSourceBinding(nil), cwft.paramBindings...), preparedPlan: preparedPlan, diff --git a/pkg/frontend/prepared_field_retry_test.go b/pkg/frontend/prepared_field_retry_test.go index 72ca716476bff..1d47be38cef68 100644 --- a/pkg/frontend/prepared_field_retry_test.go +++ b/pkg/frontend/prepared_field_retry_test.go @@ -15,6 +15,7 @@ package frontend import ( + "context" "errors" "testing" @@ -30,6 +31,8 @@ import ( "github.com/matrixorigin/matrixone/pkg/pb/timestamp" "github.com/matrixorigin/matrixone/pkg/sql/colexec" plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" + "github.com/matrixorigin/matrixone/pkg/sql/plan/function" + "github.com/matrixorigin/matrixone/pkg/udf" "github.com/stretchr/testify/require" ) @@ -252,3 +255,100 @@ func TestPreparedFieldRetryDeclarationGeneration(t *testing.T) { }) } } + +// Routine revision metadata is outside table Schemas. Retry must validate an +// immutable, bounded snapshot before applying the preceding FIELD declaration. +func TestPreparedFieldRoutineRetryGeneration(t *testing.T) { + setSharedRoutineRevisionProtocolForTest(t, sharedRoutineRevisionProtocolVersion) + for _, name := range []string{"unchanged", "revision", "catalog error", "nested immutable facts", "capture error", "protocol rollback"} { + t.Run(name, func(t *testing.T) { + ses, prepared, cw, ec := newPreparedExecuteEnvForSQL(t, 312, + "select field(case when ? then ? else null end,'A','a')") + prepared.proc = cw.proc + t.Cleanup(func() { cw.proc.SetPrepareParams(nil); ses.Close() }) + prepared.params = vector.NewVec(types.T_text.ToType()) + require.NoError(t, vector.AppendBytes(prepared.params, []byte("1"), false, cw.proc.Mp())) + require.NoError(t, vector.AppendBytes(prepared.params, []byte("a"), false, cw.proc.Mp())) + prepared.ParamTypes = []byte{byte(defines.MYSQL_TYPE_LONGLONG), 0, byte(defines.MYSQL_TYPE_VAR_STRING), 0} + _, _, clone, _, owned, err := initExecuteStmtParam(ec, ses, cw, nil, prepared.Name) + if owned && clone != nil { + clone.Free() + } + require.NoError(t, err) + require.NotNil(t, prepared.fieldTypes) + history := prepared.fieldTypes + dependency := testRoutinePlanDependency() + dependency.Language, dependency.SecurityMode = udf.LanguageSQL, "DEFINER" + dependency.ArtifactDigest, dependency.EnvironmentDigest = "", "" + const body, args, ret = "$1", "[\"bigint\"]", "bigint" + dependency.DefinitionFingerprint, err = function.SQLRoutineFingerprint(body, args, ret) + require.NoError(t, err) + member := namespaceMember(41, args) + member[2], member[3] = uint64(7), uint64(12) + namespaces, err := decodeRoutineNamespaces(context.Background(), namespaceRows(member)) + require.NoError(t, err) + dependency.NamespaceFingerprint = namespaces[41] + query := prepared.PreparePlan.GetDcl().GetPrepare().Plan.GetQuery() + if name == "nested immutable facts" { + query.BackgroundQueries = []*plan.Query{{RoutineDependencies: []*plan.RoutinePlanDependency{dependency}}} + } else { + query.RoutineDependencies = []*plan.RoutinePlanDependency{dependency} + } + if name == "capture error" { + query.BackgroundQueries = []*plan.Query{query} + } + retry := cw.preparedExecutionRetry() + require.NotNil(t, retry) + require.Same(t, history, retry.fieldTypes) + query.BackgroundQueries = nil + query.RoutineDependencies = nil + row := []interface{}{uint64(41), uint64(7), uint64(12), uint64(8), uint64(7), + udf.LanguageSQL, "VOLATILE", dependency.DefinitionFingerprint, "", "", + "", "", int64(0), "", body, args, ret, int64(udf.SQLDefinitionSchemaVersion), + "", "", "", udf.NullCallHandler, "DEFINER", "DEFINER"} + catalog := &routinePlanValidationExec{catalogResultSets: []interface{}{routinePlanCatalogResultSet(row)}, namespaceResultSets: []interface{}{namespaceRows(member)}} + if name == "capture error" { + require.ErrorContains(t, retry.fieldRoutineErr, "cycle") + } else { + require.NoError(t, retry.fieldRoutineErr) + require.Len(t, retry.fieldRoutines, 1) + require.NotSame(t, dependency, retry.fieldRoutines[0]) + require.NotSame(t, dependency.FunctionRef, retry.fieldRoutines[0].FunctionRef) + dependency.FunctionRef.Revision = 99 + require.Equal(t, uint64(7), retry.fieldRoutines[0].FunctionRef.Revision) + } + switch name { + case "revision": + row[1], row[4] = uint64(8), uint64(8) + case "catalog error": + catalog.failOn = "mo_user_defined_function" + case "protocol rollback": + setSharedRoutineRevisionProtocolForTest(t, sharedRoutineRevisionProtocolVersion-1) + } + execution := &routinePlanValidationSession{FeSession: ses, exec: catalog} + compiler := ses.GetTxnCompileCtx() + originalContext := compiler.GetContext() + rebuilt, err := buildPlanForCompileRetry(ec.reqCtx, execution, compiler, prepared.PrepareStmt, false, retry) + require.Equal(t, originalContext, compiler.GetContext()) + require.Same(t, history, prepared.fieldTypes, "retry cannot publish replacement history") + require.Same(t, history, retry.fieldTypes) + switch name { + case "unchanged", "nested immutable facts": + require.NoError(t, err) + require.NotNil(t, rebuilt) + require.NotEmpty(t, catalog.statements, "validate through the catalog, not table-only proofs") + case "capture error": + require.Same(t, retry.fieldRoutineErr, err) + require.Empty(t, catalog.statements) + case "catalog error": + require.ErrorContains(t, err, "injected routine catalog read failure") + require.Equal(t, "rollback;", catalog.statements[len(catalog.statements)-1]) + default: + require.True(t, moerr.IsMoErrCode(err, moerr.ErrTxnNeedRetryWithDefChanged), "%v", err) + } + if name != "unchanged" && name != "nested immutable facts" { + require.Nil(t, rebuilt) + } + }) + } +} diff --git a/pkg/tests/sqlintegration/prepared_routine_field_test.go b/pkg/tests/sqlintegration/prepared_routine_field_test.go new file mode 100644 index 0000000000000..26947d120f553 --- /dev/null +++ b/pkg/tests/sqlintegration/prepared_routine_field_test.go @@ -0,0 +1,121 @@ +// Copyright 2026 Matrix Origin +// +// 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 sqlintegration + +import ( + "context" + "database/sql" + "fmt" + "testing" + "time" + + "github.com/matrixorigin/matrixone/pkg/embed" + "github.com/stretchr/testify/require" +) + +func TestPreparedRoutineFieldHistory(t *testing.T) { + runSQLIntegration(t, func(c embed.Cluster) { + cn, err := c.GetCNService(0) + require.NoError(t, err) + ctx, cancel := context.WithTimeout(t.Context(), 120*time.Second) + defer cancel() + db, err := sql.Open("mysql", fmt.Sprintf("dump:111@tcp(127.0.0.1:%d)/", cn.GetServiceConfig().CN.Frontend.Port)) + require.NoError(t, err) + defer db.Close() + conn, err := db.Conn(ctx) + require.NoError(t, err) + defer conn.Close() + const schema = "prepared_routine_field" + defer cleanupSQLIntegration(t, cn, "drop database if exists "+schema) + exec := func(q string) { + t.Helper() + _, err := conn.ExecContext(ctx, q) + require.NoError(t, err, q) + } + exec("create database " + schema) + exec("use " + schema) + + for _, protocol := range []string{"binary", "text"} { + t.Run(protocol, func(t *testing.T) { + + exec := func(q string) { + t.Helper() + _, err := conn.ExecContext(ctx, q) + require.NoError(t, err, q) + } + name := "f_" + protocol + create := func(replace bool, ret, body string) { + ddl := "create function " + if replace { + ddl = "create or replace function " + } + exec(ddl + name + "(x varchar(10)) returns " + ret + " language sql as '" + body + "'") + } + create(false, "varbinary(10)", "cast($1 as binary)") + var revision uint64 + require.NoError(t, conn.QueryRowContext(ctx, "select active_revision from mo_catalog.mo_user_defined_function where db=? and name=?", schema, name).Scan(&revision)) + require.Positive(t, revision, "exercise the revision-bearing routine dependency contract") + var initial uint64 + require.NoError(t, conn.QueryRowContext(ctx, "select field("+name+"('a'),'A','a')").Scan(&initial)) + require.Equal(t, uint64(2), initial, "the body owns a binary comparison domain") + query := "select field(case when ? then " + name + "('a') else ? end,'A','a')" + var stmt *sql.Stmt + if protocol == "binary" { + stmt, err = conn.PrepareContext(ctx, query) + require.NoError(t, err) + defer stmt.Close() + } else { + exec("prepare routine_field from " + query) + defer exec("deallocate prepare routine_field") + exec("set @field_choose=0") + } + check := func(value any, want uint64) { + t.Helper() + var got uint64 + if stmt != nil { + require.NoError(t, stmt.QueryRowContext(ctx, int64(0), value).Scan(&got)) + } else { + if _, binary := value.([]byte); binary { + exec("set @field_value=cast('a' as binary)") + } else { + exec("set @field_value='a'") + } + require.NoError(t, conn.QueryRowContext(ctx, "execute routine_field using @field_choose,@field_value").Scan(&got)) + } + require.Equal(t, want, got) + } + // Even the unselected routine branch contributes its declaration. + check([]byte("a"), 2) + + // SQL routine DDL is autocommit-only. Changing the body and + // restoring it both publish new routine declaration generations. + create(true, "varbinary(10)", "cast($1 as char)") + check("a", 1) + create(true, "varbinary(10)", "cast($1 as binary)") + + check([]byte("a"), 2) + // A return-type change uses the supported DROP/CREATE contract. + exec("drop function " + name + "(varchar(10))") + create(false, "varchar(10)", "cast($1 as char)") + var direct uint64 + require.NoError(t, conn.QueryRowContext(ctx, "select field(case when false then "+name+"('a') else 'a' end,'A','a')").Scan(&direct)) + require.Equal(t, uint64(1), direct) + check("a", 1) + check("a", 1) + }) + } + + }) +} From 3bc4a4903787abbb30258e7e2cb4933736899fe5 Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 21 Oct 2026 11:42:53 +0800 Subject: [PATCH 240/241] Advance Python protocol admission after LOAD FK integration --- docs/design/python_udf_current_stage.md | 20 +++--- .../python_udf_current_stage_approval.md | 28 +++++++- pkg/bootstrap/versions/v4_0_18/upgrade.go | 2 +- .../versions/v4_0_18/upgrade_test.go | 10 +-- pkg/frontend/python_udf_catalog_test.go | 6 +- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 2 +- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 64 +++++++++++++------ pkg/sql/compile/remoterun.go | 4 +- .../upgrade/upgrade_v4_0_18_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 13 files changed, 100 insertions(+), 46 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 3889a21abedb5..8c66687f77e6a 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r26-2026-10-20` | +| Design revision | `python-udf-current-stage-r27-2026-10-21` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `743e749a1e33d6c845bb73999e8c82d297a2b657` (MORPC 124 for exact fractional TIMESTAMPADD SECOND intervals; nonblocking locks retain 123 and prior temporal contracts retain 122; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r26 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 125 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `63a964a82fbaae4759cfabb45655e0185bc0979c` (MORPC 125 for LOAD IGNORE foreign-key diagnostics, 124 for exact fractional TIMESTAMPADD SECOND intervals; nonblocking locks retain 123 and prior temporal contracts retain 122; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r27 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 126 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `125` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `126` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 125 and above, +revision that would become authoritative later. At protocol 126 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -102,13 +102,13 @@ Thus a tenant already at upstream final `4.0.17`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 125 before tenant tasks are created, and the repair handler +requires protocol 126 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -125. That value is rollout state in the service runtime, not a computed live +126. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy @@ -119,9 +119,9 @@ receiver. Missing or malformed protocol state fails closed. The shared `Query` protobuf preserves official `correlation = 19`; this PR uses `routine_dependencies = 20`. Both fields survive serialization, generated descriptor lookup, and deep-copy without aliasing. Python-bearing plans require -protocol 125 before Prepare, publication, send, or execution; main-only dependent +protocol 126 before Prepare, publication, send, or execution; main-only dependent programs retain their independent protocol-119 admission. The read-only -`GetPythonUdfStatus` method uses wire capability 125, query method 47, request +`GetPythonUdfStatus` method uses wire capability 126, query method 47, request field 49 and response field 50. Official session KILL/disconnect methods 45/46, request fields 47/48 and response fields 48/49 retain capability 120. The status wire fixtures use these current allocations; older unmerged candidate allocations @@ -265,7 +265,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-125 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 124 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-126 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 125 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index 09823798d0bc0..e7e9d2eed5866 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -5,7 +5,7 @@ | Record | `python-udf-current-stage-r1-2026-09-24-approval` | | Issue | [MatrixOne #28132](https://github.com/matrixorigin/matrixone/issues/28132) | | Implementation PR | [MatrixOne #29152](https://github.com/matrixorigin/matrixone/pull/29152) | -| Current-stage proposal | [`python-udf-current-stage-r18-2026-10-17`](python_udf_current_stage.md); historical r1 approval retained below | +| Current-stage proposal | [`python-udf-current-stage-r27-2026-10-21`](python_udf_current_stage.md); historical r1 approval retained below | | Scope | Explicitly enabled test/development adapter; no production rollout or production-readiness claim | This record separates the immutable current-stage design artifact, the feature @@ -556,3 +556,29 @@ required after this merge. Catalog 4.0.18 and its minimum source 4.0.17, query method/field allocations and Python runtime scope are unchanged. Independent Architecture and SQL/Planner approval of r26 remains pending; rebase and validation do not supply that approval. No production or security scope is added. + + +## r27 LOAD FK/Python allocation addendum (2026-10-21) + +Official main 63a964a82fbaae4759cfabb45655e0185bc0979c owns MORPC 125 +for LOAD IGNORE foreign-key row rejection diagnostics and builtin identity 602. +The governing python-udf-current-stage-r27-2026-10-21 proposal preserves this +capability and allocates Python 126 (latest + 1). Catalog repair, revision +publication and reads, Prepare, prepared reuse, evaluator, remote sender/receiver +and status admission reject predecessor 125 and mixed 126/125 CNs before Python +mutation or execution. Rollback from126 to125 disables Python while retaining +LOAD FK125, fractional TIMESTAMPADD124, nonblocking locks123 and temporal122. + +Combined LOAD FK/Python pipelines require126; LOAD-only requires125 and rejects +124; fractional-only remains124. The existing execution stream carries the +maximum required feature floor, with no new RPC or lifecycle owner. Upstream +FK filtering barriers, diagnostic-expression traversal and function identity602 +remain unchanged. The prepared FIELD history integration also resets retained +comparison history when a captured routine declaration changes and revalidates +bounded immutable routine facts before compile retry applies old history. + +Catalog4.0.18, minimum source4.0.17, query method/field allocations, immutable +historical approval artifacts and Python runtime scope remain unchanged. +Independent Architecture and SQL/Planner approval of r27 remains pending; +maintenance validation does not supply that approval. No production or security +scope is added. diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade.go b/pkg/bootstrap/versions/v4_0_18/upgrade.go index 2e3c38eff96c3..2bb4581c61011 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion125, + RequiredProtocolVersion: defines.MORPCVersion126, }, } diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go index dc434dbf71d42..85426c4b0641c 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.17", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion125), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion126), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.17")) require.False(t, metadata.CanDirectUpgrade("4.0.16")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:124"}`, - `{"result":"cn-a:125,cn-b:124"}`, + `{"result":"cn-a:125"}`, + `{"result":"cn-a:126,cn-b:125"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 125") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 126") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:125"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:126"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index 7f02cab7c5f17..c6f44d4d77fa2 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 125"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 126"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion124) + setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion125) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 125") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 126") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 7647fe6f42183..252448b134256 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion125, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion126, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index f4fabc05167f7..79adedd55faa5 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -129,7 +129,7 @@ func TestSessionControlProtocol(t *testing.T) { }{ {query.CmdMethod_KillSession, defines.MORPCVersion120}, {query.CmdMethod_DisconnectSession, defines.MORPCVersion120}, - {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion125}, + {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion126}, } { require.Equal(t, test.floor, methodVersions[test.method]) req := &query.Request{CmdMethod: test.method} diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index f16b2690fd9c0..ba410da7e2dbe 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion125, + {features.PythonRoutineContract, defines.MORPCVersion126, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index fd78e16939e7d..79f02a6eda675 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion125) + required = max(required, defines.MORPCVersion126) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index 125a6ff2de22b..e3d07573ac0cf 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -554,6 +554,11 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { c.proc.SetResolveVariableFunc(nil) require.True(t, c.proc.DivisionByZeroWarningsEnabled()) expr := &planpb.Expr{Expr: &planpb.Expr_F{F: &planpb.Function{RoutineCall: &planpb.RoutineCall{}}}} + loadFK, err := plan2.BindFuncExprImplByPlanExpr(c.proc.Ctx, "_load_fk_ignore_check", []*planpb.Expr{ + {Typ: types.T_bool.ToType().PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 6}}}, + }) + require.NoError(t, err) + require.Equal(t, function.EncodeOverloadID(602, 0), loadFK.GetF().Func.Obj) calendar := &planpb.Expr{Expr: &planpb.Expr_F{F: &planpb.Function{Func: &planpb.ObjectRef{Obj: function.EncodeOverloadID(function.TO_CALENDAR_INTERVAL, 0)}}}} division, err := plan2.BindFuncExprImplByPlanExpr(c.proc.Ctx, "div", []*planpb.Expr{ {Typ: types.T_int64.ToType().PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 0}}}, @@ -584,10 +589,11 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { Func: &planpb.ObjectRef{Obj: function.EncodeOverloadID(function.TIMESTAMPADD_SECOND_INTERVAL, 5)}, Args: []*planpb.Expr{{Typ: planpb.Type{Id: int32(types.T_decimal64), Width: 18, Scale: 7}, Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 5}}}}, }}} - p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least, tableCollation, decimalDiv, timestamp, dynamicTime, fractionalSecond}}}} + p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least, tableCollation, decimalDiv, timestamp, dynamicTime, fractionalSecond, loadFK}}}} features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) + require.True(t, features.LoadFKIgnoreCheck) require.True(t, features.TimestampDatetimeResultContracts) require.True(t, features.DynamicTimeResultContracts) require.True(t, features.TimestampAddSecondIntervals) @@ -596,21 +602,21 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { require.True(t, features.ScalarDivision) require.True(t, features.LeastGreatestCollationSemantics) require.True(t, features.TableCollationFunction) - require.Equal(t, defines.MORPCVersion125, remoteExpressionProtocolVersion(features)) - require.Equal(t, defines.MORPCVersion125, executionRemoteExpressionProtocolVersion(c.proc, features)) + require.Equal(t, defines.MORPCVersion126, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion126, executionRemoteExpressionProtocolVersion(c.proc, features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion124, defines.MORPCVersion125} { + for _, version := range []int64{defines.MORPCVersion125, defines.MORPCVersion126} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion125 { + if version < defines.MORPCVersion126 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion125) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion126) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) // The existing execution stream must negotiate the complete encoded contract. @@ -621,7 +627,7 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { var required int64 wire, err := encodeRemoteScopeWithProtocol(scope, c.proc, &required) require.NoError(t, err) - require.Equal(t, defines.MORPCVersion125, required) + require.Equal(t, defines.MORPCVersion126, required) decoded, err := decodeScope(wire, c.proc, true, nil) require.NoError(t, err) decoded.release() @@ -630,7 +636,7 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { required = 0 _, err = encodeRemoteScopeWithProtocol(scope, c.proc, &required) require.NoError(t, err) - require.Equal(t, defines.MORPCVersion125, required) + require.Equal(t, defines.MORPCVersion126, required) // Capability does not transfer the coordinator's dependent-program owner. dependent := &planpb.Expr{Typ: decimalDiv.Typ, Expr: &planpb.Expr_Dependent{Dependent: &planpb.DependentExpr{ @@ -645,14 +651,36 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { require.ErrorContains(t, err, "coordinator execution owner") // Immediate-predecessor rollback disables Python but preserves fractional - // TIMESTAMPADD at 124, earlier temporal contracts at 122 and DIV at 121. - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) + // TIMESTAMPADD at 124, LOAD FK at125, temporal contracts at122 and DIV at121. + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion125) _, err = decodeScope(wire, c.proc, true, nil) require.ErrorContains(t, err, "Python routine execution requires") - client.version = defines.MORPCVersion124 - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) + client.version = defines.MORPCVersion125 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion125) require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, p, features), "remote destination does not support Python") require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + loadOnly := &pipeline.Pipeline{Node: p.Node, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{loadFK}}}} + loadFeatures, err := planpb.RequiredRemoteExpressionFeatures(loadOnly) + require.NoError(t, err) + require.False(t, loadFeatures.PythonRoutineContract) + require.True(t, loadFeatures.LoadFKIgnoreCheck) + require.Equal(t, defines.MORPCVersion125, remoteExpressionProtocolVersion(loadFeatures)) + require.NoError(t, validateRemoteExpressionDestination(c.proc, loadOnly, loadFeatures)) + require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, loadOnly)) + op.ProjectList = loadOnly.InstructionList[0].ProjectList + required = 0 + loadWire, err := encodeRemoteScopeWithProtocol(scope, c.proc, &required) + require.NoError(t, err) + require.Equal(t, defines.MORPCVersion125, required) + decoded, err = decodeScope(loadWire, c.proc, true, nil) + require.NoError(t, err) + decoded.release() + client.version = defines.MORPCVersion124 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, loadOnly, loadFeatures), "version 125") + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, loadOnly), "foreign-key filtering requires") + _, err = decodeScope(loadWire, c.proc, true, nil) + require.ErrorContains(t, err, "foreign-key filtering requires") fractionalOnly := &pipeline.Pipeline{Node: p.Node, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{fractionalSecond}}}} fractionalFeatures, err := planpb.RequiredRemoteExpressionFeatures(fractionalOnly) require.NoError(t, err) @@ -736,14 +764,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion125, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion126, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion124 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion124) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion125 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion125) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion126 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion126) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index 65f25783101d6..fa18d07f2de9b 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion125) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 125") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion126) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 126") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go index 19d6aaed5c7aa..329c99a663c70 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go @@ -127,7 +127,7 @@ func TestV4018LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 125") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 126") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index 31fc5b833bdaf..f0618921afe3c 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion125 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion126 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" ) From 5416fe52daa6bd491a3db35fea9eab78f1d982ae Mon Sep 17 00:00:00 2001 From: iamlinjunhong <1030420200@qq.com> Date: Wed, 21 Oct 2026 19:18:46 +0800 Subject: [PATCH 241/241] Fix Python routine protocol after VIEWS rebase --- docs/design/python_udf_current_stage.md | 36 +++++----- .../python_udf_current_stage_approval.md | 28 ++++++++ pkg/bootstrap/versions/v4_0_18/upgrade.go | 2 +- .../versions/v4_0_18/upgrade_test.go | 10 +-- .../versions/v4_0_7/tenant_upgrade_list.go | 7 +- pkg/bootstrap/versions/v4_0_7/upgrade_test.go | 15 +++-- pkg/frontend/python_udf_catalog_test.go | 6 +- pkg/queryservice/client/query_client.go | 2 +- pkg/queryservice/client/query_client_test.go | 2 +- .../expression_destination_protocol.go | 2 +- pkg/sql/compile/expression_protocol.go | 2 +- pkg/sql/compile/expression_protocol_test.go | 66 ++++++++++++++----- pkg/sql/compile/remoterun.go | 6 +- pkg/sql/compile/vector_scan_protocol_test.go | 2 +- pkg/sql/parsers/dialect/mysql/mysql_sql.go | 2 +- .../upgrade/upgrade_v4_0_18_routine_test.go | 2 +- pkg/udf/python_contract.go | 2 +- 17 files changed, 127 insertions(+), 65 deletions(-) diff --git a/docs/design/python_udf_current_stage.md b/docs/design/python_udf_current_stage.md index 8c66687f77e6a..9f044e666caae 100644 --- a/docs/design/python_udf_current_stage.md +++ b/docs/design/python_udf_current_stage.md @@ -2,10 +2,10 @@ | Field | Value | | --- | --- | -| Design revision | `python-udf-current-stage-r27-2026-10-21` | +| Design revision | `python-udf-current-stage-r28-2026-10-21` | | Applies to | MatrixOne PR #29152, test/development-stage Python UDF | -| Upstream repair baseline | `63a964a82fbaae4759cfabb45655e0185bc0979c` (MORPC 125 for LOAD IGNORE foreign-key diagnostics, 124 for exact fractional TIMESTAMPADD SECOND intervals; nonblocking locks retain 123 and prior temporal contracts retain 122; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | -| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r27 contract preserves the upstream catalog handlers through 4.0.17 unchanged, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 126 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | +| Upstream repair baseline | `7038c8520e5fc1ba456914b3c389ccedb69e22f7` (MORPC 126 for parser-derived VIEWS metadata, 125 for LOAD IGNORE foreign-key diagnostics, 124 for exact fractional TIMESTAMPADD SECOND intervals; nonblocking locks retain 123 and prior temporal contracts retain 122; catalog 4.0.17 including the persisted COLUMNS MEDIUMINT refresh) | +| Approval | Feature owner approved the r1 current-stage contract on 2026-09-24 in [PR comment](https://github.com/matrixorigin/matrixone/pull/29152#issuecomment-5809313638). The r28 contract preserves upstream historical upgrade identities through 4.0.17, adds a separate Python revision repair in catalog 4.0.18, and uses protocol 127 admission, including prepared reuse and physical/remote execution. Independent Architecture and SQL/Planner approval of this revision is pending; no production or security scope is added. The immutable approval artifact and independent-review status remain recorded in the [design approval record](python_udf_current_stage_approval.md). | | Not covered | Production tenant isolation, sandbox, Operator rollout, or cross-version rollback/restore | This is the versioned governing proposal for the current PR stage. The owner @@ -77,12 +77,12 @@ The shared revision catalog is additive to the existing SQL UDF contract. During a rolling tenant upgrade, SQL UDF writers continue using the legacy `mo_user_defined_function` row while `mo_function_revisions` is absent. The revision-aware writer and reader contract is admitted only at the active service-runtime -MORPC protocol floor `126` (official main `latest + 1` for this PR). Below that floor, a new +MORPC protocol floor `127` (official main `latest + 1` for this PR). Below that floor, a new binary creates ordinary SQL UDFs in the legacy row only, and readers explicitly use that row so an old writer and a new reader observe the same body. Replacing a function that already has a non-zero shared revision head is rejected below the floor; this prevents a legacy-only write from leaving a stale immutable -revision that would become authoritative later. At protocol 126 and above, +revision that would become authoritative later. At protocol 127 and above, writers publish the compatibility row, immutable revision, and active head in the same caller-owned transaction, and readers use the selected revision. A non-zero head with a missing or malformed revision is a catalog error; it is @@ -90,25 +90,25 @@ never silently repaired or synthesized. The SQL UDF language, body, security, and evaluation semantics remain owned by the existing SQL path. The Python demo's old execution behavior is not a compatibility promise. -Upgrade `4.0.7` contains the original idempotent shared-function schema entries. -Its historical protocol-61 requirement belongs to the already-shipped provenance -contract; it does not prove Python revision capability. The registered repair -`4.0.18` (minimum direct source `4.0.17`) replays the nine shared-function -entries. Upstream handlers `4.0.8` through `4.0.17`, including the protocol-107 -statistics view refresh, the protocol-109 COLUMNS refresh, and the protocol-118 -database-defaults/table-collation upgrade, persisted COLLATIONS refresh, and -4.0.17 COLUMNS MEDIUMINT refresh, remain unchanged. +Historical upgrade `4.0.7` retains its released zero entry offset and +protocol-61 provenance requirement. The nine idempotent shared-function schema +entries are held in a separate helper list; only registered repair `4.0.18` +(minimum direct source `4.0.17`) replays them. They do not execute through the +historical 4.0.7 handler. Upstream 4.0.8 through 4.0.17 upgrade identities, +including statistics, COLUMNS, database defaults/table collation, COLLATIONS +and MEDIUMINT refreshes, remain unchanged. The upstream VIEWS maintenance +retains its independent protocol-126 admission and released handler offsets. Thus a tenant already at upstream final `4.0.17`, including one lacking revision tables, still receives the repair; earlier tenants traverse the normal chain first. Missing, partial and complete schemas converge through idempotent checks. Repair metadata -requires protocol 126 before tenant tasks are created, and the repair handler +requires protocol 127 before tenant tasks are created, and the repair handler rechecks every CN before catalog access on login compensation or direct replay; `Prepare` only selects `mo_catalog` and performs no DDL. Python DDL probes the required tenant schema and refuses admission until it is present. Shared revision publication and Python reads require active protocol -126. That value is rollout state in the service runtime, not a computed live +127. That value is rollout state in the service runtime, not a computed live cluster minimum. Cached/prepared Python plans and new or reused physical evaluators check it again before catalog reads, input evaluation or worker calls. Below the floor, revision-bearing SQL plans invalidate and rebind to the legacy @@ -119,9 +119,9 @@ receiver. Missing or malformed protocol state fails closed. The shared `Query` protobuf preserves official `correlation = 19`; this PR uses `routine_dependencies = 20`. Both fields survive serialization, generated descriptor lookup, and deep-copy without aliasing. Python-bearing plans require -protocol 126 before Prepare, publication, send, or execution; main-only dependent +protocol 127 before Prepare, publication, send, or execution; main-only dependent programs retain their independent protocol-119 admission. The read-only -`GetPythonUdfStatus` method uses wire capability 126, query method 47, request +`GetPythonUdfStatus` method uses wire capability 127, query method 47, request field 49 and response field 50. Official session KILL/disconnect methods 45/46, request fields 47/48 and response fields 48/49 retain capability 120. The status wire fixtures use these current allocations; older unmerged candidate allocations @@ -265,7 +265,7 @@ test/development correctness and backpressure, not hostile-code containment. | Contract | Evidence on the reviewed branch/head | Status | | --- | --- | --- | -| Shared revision schema, protocol-126 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 125 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | +| Shared revision schema, protocol-127 admission, and SQL legacy fallback | `pkg/bootstrap/versions/v4_0_18/upgrade_test.go`; `pkg/bootstrap/service_statistics_upgrade_test.go`; `pkg/frontend/python_udf_catalog_test.go`; prepared, evaluator and remote protocol regression tests | Current repair and admission cases present; framework scheduling and idempotent DDL replay have unit cases. `pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go` verifies real login repair from tenant versions 4.0.12/4.0.13/4.0.14/4.0.15/4.0.16/4.0.17, rejection at protocol 126 before mutation, legacy SQL UDF results, and two idempotent replays. This does not verify cross-binary downgrade. Historical upgrade-compatibility CI was skipped. | | Exact FunctionRef and overload invalidation | `pkg/frontend/routine_plan_validation_test.go`; `pkg/frontend/routine_namespace_test.go`; `test/distributed/cases/udf_python/overload_namespace.sql` | Unit and SQL prepared-plan cases present. | | SQL expression placement and result semantics | `pkg/sql/colexec/external_routine_eval.go`; `test/distributed/cases/udf_python/relational_positions.sql`, `dml_positions.sql`, `vector_mode.sql` | Physical evaluator and ordinary BVT cases present. | | Current-contract restore | `pkg/frontend/clone_database_source.go`; `pkg/frontend/snapshot_catalog_restore.go`; `snapshot_restore.sql` | Same-contract account restore case present; cross-version restore not verified. | diff --git a/docs/design/python_udf_current_stage_approval.md b/docs/design/python_udf_current_stage_approval.md index e7e9d2eed5866..4ba59aea7b72c 100644 --- a/docs/design/python_udf_current_stage_approval.md +++ b/docs/design/python_udf_current_stage_approval.md @@ -582,3 +582,31 @@ historical approval artifacts and Python runtime scope remain unchanged. Independent Architecture and SQL/Planner approval of r27 remains pending; maintenance validation does not supply that approval. No production or security scope is added. + + +## r28 VIEWS/Python allocation and historical upgrade identity addendum (2026-10-21) + +Official main 7038c8520e5fc1ba456914b3c389ccedb69e22f7 owns MORPC126 +for parser-derived information_schema.VIEWS metadata and builtin IDs603/604. +The governing python-udf-current-stage-r28-2026-10-21 proposal preserves this +capability and assigns Python127 (official latest + 1). Catalog repair, +revision publication and reads, Prepare, prepared reuse, evaluator, remote +sender/receiver and status admission reject predecessor126 and mixed127/126 +CNs before Python mutation or execution. Rollback127 to126 disables Python +while retaining VIEWS126, LOAD FK125, fractional TIMESTAMPADD124 and prior +contracts. Combined VIEWS/Python pipelines negotiate127; VIEWS-only negotiates126 +and rejects125 through the existing stream, sender and receiver gates. + +The historical4.0.7 handler keeps its released zero entry offset and protocol61. +Its Python schema entries are a separate helper list replayed only by the +protocol127-gated4.0.18 repair; the upstream VIEWS maintenance keeps its own126 +fence. The old-worker regression uses the actual retained4.0.7 handler rather +than a synthetic replacement. Catalog4.0.18 and minimum source4.0.17, query +method/field allocations and Python runtime scope remain unchanged. + +The prior r27 text described the intended historical-handler preservation but +its implementation still attached the Python list to4.0.7; this addendum and +its offset/worker/upgrade tests correct that discrepancy. Historical approval +records above remain immutable. Independent Architecture and SQL/Planner +approval of r28 remains pending; maintenance validation does not supply it. +No production or security scope is added. diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade.go b/pkg/bootstrap/versions/v4_0_18/upgrade.go index 2bb4581c61011..0d767a81edd83 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade.go @@ -39,7 +39,7 @@ var Handler = &versionHandle{ UpgradeCluster: versions.No, UpgradeTenant: versions.Yes, VersionOffset: uint32(len(tenantUpgEntries)), - RequiredProtocolVersion: defines.MORPCVersion126, + RequiredProtocolVersion: defines.MORPCVersion127, }, } diff --git a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go index 85426c4b0641c..bb6eeec973ad9 100644 --- a/pkg/bootstrap/versions/v4_0_18/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_18/upgrade_test.go @@ -39,7 +39,7 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { require.Equal(t, "4.0.17", metadata.MinUpgradeVersion) require.Equal(t, versions.No, metadata.UpgradeCluster) require.Equal(t, versions.Yes, metadata.UpgradeTenant) - require.Equal(t, int64(defines.MORPCVersion126), metadata.RequiredProtocolVersion) + require.Equal(t, int64(defines.MORPCVersion127), metadata.RequiredProtocolVersion) require.Equal(t, uint32(len(v4_0_7.PythonRevisionUpgradeEntries())), metadata.VersionOffset) require.True(t, metadata.CanDirectUpgrade("4.0.17")) require.False(t, metadata.CanDirectUpgrade("4.0.16")) @@ -48,8 +48,8 @@ func TestPythonRevisionRepairUpgradePath(t *testing.T) { func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) { for _, response := range []string{ - `{"result":"cn-a:125"}`, - `{"result":"cn-a:126,cn-b:125"}`, + `{"result":"cn-a:126"}`, + `{"result":"cn-a:127,cn-b:126"}`, `{"result":""}`, `invalid`, } { @@ -61,7 +61,7 @@ func TestPythonRevisionRepairRejectsOldProtocolBeforeCatalogAccess(t *testing.T) return repairStringResult(t, response), nil }, nil) err := Handler.HandleTenantUpgrade(context.Background(), 7, txn) - require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 126") + require.ErrorContains(t, err, "upgrade requires all CNs to support protocol version 127") require.Equal(t, []string{"SELECT mo_ctl('cn', 'GetProtocolVersion', '')"}, statements) }) } @@ -166,7 +166,7 @@ func newRepairTxnExecutor(t *testing.T, state *pythonRevisionCatalogState) execu } return executor.Result{}, nil case sql == "SELECT mo_ctl('cn', 'GetProtocolVersion', '')": - return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:126"}`), nil + return repairStringResult(t, `{"method":"GETPROTOCOLVERSION","result":"cn-a:127"}`), nil case strings.Contains(lower, "alter table mo_catalog.mo_user_defined_function add column"): for column := range state.columns { if strings.Contains(sql, "add column "+column+" ") { diff --git a/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go b/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go index 4327ce0666de1..e096208645aac 100644 --- a/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go +++ b/pkg/bootstrap/versions/v4_0_7/tenant_upgrade_list.go @@ -31,7 +31,10 @@ import ( // only known at runtime (one metadata table per index, per account), which a fixed UpgSql // cannot express. It runs from HandleTenantUpgrade, the same escape hatch v4_0_6 uses for // upgradeLegacyForeignKeyMetadata. -var tenantUpgEntries = []versions.UpgradeEntry{ +// Keep the released v4.0.7 upgrade identity unchanged. The later repair owns Python migrations. +var tenantUpgEntries = []versions.UpgradeEntry{} + +var pythonRevisionUpgEntries = []versions.UpgradeEntry{ addPythonRevisionHeadColumn("active_revision", "bigint unsigned not null default 0"), addPythonRevisionHeadColumn("namespace_version", "bigint unsigned not null default 0"), addPythonSignatureColumn("canonical_input_descriptor", fmt.Sprintf("varchar(%d) not null default ''", types.MaxStringSize), "arg_types"), @@ -78,7 +81,7 @@ var tenantUpgEntries = []versions.UpgradeEntry{ // migrations so a later repair version can replay them for clusters that // already recorded 4.0.7 or 4.0.8 without executing the original handler. func PythonRevisionUpgradeEntries() []versions.UpgradeEntry { - return append([]versions.UpgradeEntry(nil), tenantUpgEntries...) + return append([]versions.UpgradeEntry(nil), pythonRevisionUpgEntries...) } // addPythonSignatureIndex makes the shared function namespace distinguish the diff --git a/pkg/bootstrap/versions/v4_0_7/upgrade_test.go b/pkg/bootstrap/versions/v4_0_7/upgrade_test.go index b65bd179adc80..66b0be499d36a 100644 --- a/pkg/bootstrap/versions/v4_0_7/upgrade_test.go +++ b/pkg/bootstrap/versions/v4_0_7/upgrade_test.go @@ -31,22 +31,23 @@ func TestPythonFunctionRevisionUpgradeContract(t *testing.T) { if metadata.UpgradeCluster != versions.Yes || metadata.UpgradeTenant != versions.Yes { t.Fatalf("4.0.7 must run both cluster and tenant upgrades: %+v", metadata) } - if metadata.VersionOffset != uint32(len(tenantUpgEntries)) { - t.Fatalf("version offset %d does not match tenant entries %d", metadata.VersionOffset, len(tenantUpgEntries)) + if metadata.VersionOffset != 0 || len(tenantUpgEntries) != 0 { + t.Fatalf("historical 4.0.7 identity changed: offset=%d entries=%d", metadata.VersionOffset, len(tenantUpgEntries)) } if metadata.RequiredProtocolVersion != defines.MORPCVersion61 { t.Fatalf("unexpected 4.0.7 protocol gate: %v", metadata.RequiredProtocolVersion) } - if len(tenantUpgEntries) != 9 { - t.Fatalf("expected six UDF identity columns, index replacement, and one revision table, got %d entries", len(tenantUpgEntries)) + entries := PythonRevisionUpgradeEntries() + if len(entries) != 9 { + t.Fatalf("expected six UDF identity columns, index replacement, and one revision table, got %d entries", len(entries)) } for _, name := range []string{ "active_revision", "namespace_version", "canonical_input_descriptor", "return_descriptor", "signature_key_schema_version", "signature_fingerprint", } { var found bool - for _, entry := range tenantUpgEntries { + for _, entry := range entries { if entry.TableName == "mo_user_defined_function" && strings.Contains(strings.ToLower(entry.UpgSql), "add column "+name) { found = true if entry.UpgType != versions.ADD_COLUMN || entry.Schema != catalog.MO_CATALOG { @@ -61,8 +62,8 @@ func TestPythonFunctionRevisionUpgradeContract(t *testing.T) { } var addIndex, dropIndex, revision *versions.UpgradeEntry - for i := range tenantUpgEntries { - entry := &tenantUpgEntries[i] + for i := range entries { + entry := &entries[i] lower := strings.ToLower(entry.UpgSql) switch { case strings.Contains(lower, "name_db_arg_types_descriptor"): diff --git a/pkg/frontend/python_udf_catalog_test.go b/pkg/frontend/python_udf_catalog_test.go index c6f44d4d77fa2..330e5a85e9891 100644 --- a/pkg/frontend/python_udf_catalog_test.go +++ b/pkg/frontend/python_udf_catalog_test.go @@ -583,7 +583,7 @@ func TestSharedRoutineRevisionProtocolGatesMixedVersionSQLUdfWrites(t *testing.T wantError string }{ {name: "legacy_zero_head"}, - {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 126"}, + {name: "revision_head", revision: 1, namespace: 1, wantError: "SQL UDF revision replacement requires MORPC protocol version 127"}, {name: "half_zero_revision", namespace: 1, wantError: "invalid revision head"}, {name: "half_zero_namespace", revision: 1, wantError: "invalid revision head"}, } { @@ -642,12 +642,12 @@ func TestReadSQLRevisionUsesLegacyBodyBeforeRevisionProtocol(t *testing.T) { } func TestPythonUdfRevisionProtocolRejectsImmediatePredecessor(t *testing.T) { - setSharedRoutineRevisionProtocolForTest(t, defines.MORPCVersion125) + setSharedRoutineRevisionProtocolForTest(t, udf.SharedRoutineRevisionProtocolVersion-1) background := &backgroundExecTestWithHistory{} background.init() err := ensurePythonUdfCatalogReady(context.Background(), background) - require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 126") + require.ErrorContains(t, err, "Python UDF catalog contract requires MORPC protocol version 127") require.Empty(t, background.executedSqls) } diff --git a/pkg/queryservice/client/query_client.go b/pkg/queryservice/client/query_client.go index 252448b134256..fa21fbce28aba 100644 --- a/pkg/queryservice/client/query_client.go +++ b/pkg/queryservice/client/query_client.go @@ -74,7 +74,7 @@ var methodVersions = map[pb.CmdMethod]int64{ pb.CmdMethod_ISCPDrainConsumer: defines.MORPCVersion4, pb.CmdMethod_IcebergCacheInvalidate: defines.MORPCVersion4, pb.CmdMethod_MongoDBClientRetire: defines.MORPCVersion5, - pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion126, + pb.CmdMethod_GetPythonUdfStatus: defines.MORPCVersion127, } type queryClient struct { diff --git a/pkg/queryservice/client/query_client_test.go b/pkg/queryservice/client/query_client_test.go index 79adedd55faa5..287a8c541c0cd 100644 --- a/pkg/queryservice/client/query_client_test.go +++ b/pkg/queryservice/client/query_client_test.go @@ -129,7 +129,7 @@ func TestSessionControlProtocol(t *testing.T) { }{ {query.CmdMethod_KillSession, defines.MORPCVersion120}, {query.CmdMethod_DisconnectSession, defines.MORPCVersion120}, - {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion126}, + {query.CmdMethod_GetPythonUdfStatus, defines.MORPCVersion127}, } { require.Equal(t, test.floor, methodVersions[test.method]) req := &query.Request{CmdMethod: test.method} diff --git a/pkg/sql/compile/expression_destination_protocol.go b/pkg/sql/compile/expression_destination_protocol.go index ba410da7e2dbe..3abbfc6af58b9 100644 --- a/pkg/sql/compile/expression_destination_protocol.go +++ b/pkg/sql/compile/expression_destination_protocol.go @@ -45,7 +45,7 @@ func validateRemoteExpressionDestination(proc *process.Process, p *pipeline.Pipe {features.ScalarDivision && proc.DivisionByZeroWarningsEnabled(), defines.MORPCVersion116, "SELECT division diagnostics require a versioned remote destination", "remote destination does not support SELECT division diagnostics (MORPC version %d)"}, - {features.PythonRoutineContract, defines.MORPCVersion126, + {features.PythonRoutineContract, defines.MORPCVersion127, "Python routine execution requires a versioned remote destination", "remote destination does not support Python routine execution (MORPC version %d)"}, {features.IntegerArithmeticDomains, defines.MORPCVersion71, diff --git a/pkg/sql/compile/expression_protocol.go b/pkg/sql/compile/expression_protocol.go index 79f02a6eda675..7a9c574f075c1 100644 --- a/pkg/sql/compile/expression_protocol.go +++ b/pkg/sql/compile/expression_protocol.go @@ -85,7 +85,7 @@ func remoteExpressionProtocolVersion(features plan.RemoteExpressionFeatures) int required = max(required, defines.MORPCVersion122) } if features.PythonRoutineContract { - required = max(required, defines.MORPCVersion126) + required = max(required, defines.MORPCVersion127) } if features.IntegerArithmeticDomains { required = max(required, defines.MORPCVersion71) diff --git a/pkg/sql/compile/expression_protocol_test.go b/pkg/sql/compile/expression_protocol_test.go index e3d07573ac0cf..9888c4dd76a1e 100644 --- a/pkg/sql/compile/expression_protocol_test.go +++ b/pkg/sql/compile/expression_protocol_test.go @@ -559,6 +559,11 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { }) require.NoError(t, err) require.Equal(t, function.EncodeOverloadID(602, 0), loadFK.GetF().Func.Obj) + viewDefinition, err := plan2.BindFuncExprImplByPlanExpr(c.proc.Ctx, "mo_view_definition", []*planpb.Expr{ + {Typ: types.T_varchar.ToType().PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 7}}}, + }) + require.NoError(t, err) + require.Equal(t, function.EncodeOverloadID(603, 0), viewDefinition.GetF().Func.Obj) calendar := &planpb.Expr{Expr: &planpb.Expr_F{F: &planpb.Function{Func: &planpb.ObjectRef{Obj: function.EncodeOverloadID(function.TO_CALENDAR_INTERVAL, 0)}}}} division, err := plan2.BindFuncExprImplByPlanExpr(c.proc.Ctx, "div", []*planpb.Expr{ {Typ: types.T_int64.ToType().PlanType(), Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 0}}}, @@ -589,11 +594,12 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { Func: &planpb.ObjectRef{Obj: function.EncodeOverloadID(function.TIMESTAMPADD_SECOND_INTERVAL, 5)}, Args: []*planpb.Expr{{Typ: planpb.Type{Id: int32(types.T_decimal64), Width: 18, Scale: 7}, Expr: &planpb.Expr_Col{Col: &planpb.ColRef{ColPos: 5}}}}, }}} - p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least, tableCollation, decimalDiv, timestamp, dynamicTime, fractionalSecond, loadFK}}}} + p := &pipeline.Pipeline{Node: &pipeline.NodeInfo{Id: "old-worker", Addr: "remote:6001"}, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{expr, calendar, division, least, tableCollation, decimalDiv, timestamp, dynamicTime, fractionalSecond, loadFK, viewDefinition}}}} features, err := planpb.RequiredRemoteExpressionFeatures(p) require.NoError(t, err) require.True(t, features.PythonRoutineContract) require.True(t, features.LoadFKIgnoreCheck) + require.True(t, features.ViewMetadataFunctions) require.True(t, features.TimestampDatetimeResultContracts) require.True(t, features.DynamicTimeResultContracts) require.True(t, features.TimestampAddSecondIntervals) @@ -602,21 +608,21 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { require.True(t, features.ScalarDivision) require.True(t, features.LeastGreatestCollationSemantics) require.True(t, features.TableCollationFunction) - require.Equal(t, defines.MORPCVersion126, remoteExpressionProtocolVersion(features)) - require.Equal(t, defines.MORPCVersion126, executionRemoteExpressionProtocolVersion(c.proc, features)) + require.Equal(t, defines.MORPCVersion127, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion127, executionRemoteExpressionProtocolVersion(c.proc, features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - for _, version := range []int64{defines.MORPCVersion125, defines.MORPCVersion126} { + for _, version := range []int64{defines.MORPCVersion126, defines.MORPCVersion127} { client.version = version err := validateRemoteExpressionDestination(c.proc, p, features) - if version < defines.MORPCVersion126 { + if version < defines.MORPCVersion127 { require.ErrorContains(t, err, "remote destination does not support Python") } else { require.NoError(t, err) } } - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion125) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion126) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion127) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, p)) // The existing execution stream must negotiate the complete encoded contract. @@ -627,7 +633,7 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { var required int64 wire, err := encodeRemoteScopeWithProtocol(scope, c.proc, &required) require.NoError(t, err) - require.Equal(t, defines.MORPCVersion126, required) + require.Equal(t, defines.MORPCVersion127, required) decoded, err := decodeScope(wire, c.proc, true, nil) require.NoError(t, err) decoded.release() @@ -636,7 +642,7 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { required = 0 _, err = encodeRemoteScopeWithProtocol(scope, c.proc, &required) require.NoError(t, err) - require.Equal(t, defines.MORPCVersion126, required) + require.Equal(t, defines.MORPCVersion127, required) // Capability does not transfer the coordinator's dependent-program owner. dependent := &planpb.Expr{Typ: decimalDiv.Typ, Expr: &planpb.Expr_Dependent{Dependent: &planpb.DependentExpr{ @@ -651,14 +657,38 @@ func TestPythonRoutineProtocolChecksActualRemoteDestination(t *testing.T) { require.ErrorContains(t, err, "coordinator execution owner") // Immediate-predecessor rollback disables Python but preserves fractional - // TIMESTAMPADD at 124, LOAD FK at125, temporal contracts at122 and DIV at121. - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion125) + // TIMESTAMPADD at124, LOAD FK at125, VIEWS at126, temporal122 and DIV121. + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion126) _, err = decodeScope(wire, c.proc, true, nil) require.ErrorContains(t, err, "Python routine execution requires") - client.version = defines.MORPCVersion125 - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion125) + client.version = defines.MORPCVersion126 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion126) require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, p, features), "remote destination does not support Python") require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, p), "Python routine execution requires") + // The predecessor retains the official VIEWS contract independently of Python. + viewOnly := &pipeline.Pipeline{Node: p.Node, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{viewDefinition}}}} + viewFeatures, err := planpb.RequiredRemoteExpressionFeatures(viewOnly) + require.NoError(t, err) + require.True(t, viewFeatures.Any()) + require.True(t, viewFeatures.ViewMetadataFunctions) + require.False(t, viewFeatures.PythonRoutineContract) + require.Equal(t, defines.MORPCVersion126, remoteExpressionProtocolVersion(viewFeatures)) + require.NoError(t, validateRemoteExpressionDestination(c.proc, viewOnly, viewFeatures)) + require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, viewOnly)) + op.ProjectList = viewOnly.InstructionList[0].ProjectList + required = 0 + viewWire, err := encodeRemoteScopeWithProtocol(scope, c.proc, &required) + require.NoError(t, err) + require.Equal(t, defines.MORPCVersion126, required) + decoded, err = decodeScope(viewWire, c.proc, true, nil) + require.NoError(t, err) + decoded.release() + client.version = defines.MORPCVersion125 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion125) + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, viewOnly, viewFeatures), "version 126") + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, viewOnly), "view metadata remote execution requires") + _, err = decodeScope(viewWire, c.proc, true, nil) + require.ErrorContains(t, err, "view metadata remote execution requires") loadOnly := &pipeline.Pipeline{Node: p.Node, InstructionList: []*pipeline.Instruction{{ProjectList: []*planpb.Expr{loadFK}}}} loadFeatures, err := planpb.RequiredRemoteExpressionFeatures(loadOnly) require.NoError(t, err) @@ -764,14 +794,14 @@ func TestPythonRoutineProtocolInsideIndexSearchScan(t *testing.T) { features, err := planpb.RequiredRemoteExpressionFeatures(&received) require.NoError(t, err) require.True(t, features.PythonRoutineContract) - require.Equal(t, defines.MORPCVersion126, remoteExpressionProtocolVersion(features)) + require.Equal(t, defines.MORPCVersion127, remoteExpressionProtocolVersion(features)) rt := moruntime.ServiceRuntime(c.proc.GetService()) - client.version = defines.MORPCVersion125 - require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") - rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion125) - require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") client.version = defines.MORPCVersion126 + require.ErrorContains(t, validateRemoteExpressionDestination(c.proc, &received, features), "remote destination does not support Python") rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion126) + require.ErrorContains(t, validateRemoteExpressionPipelineProtocol(c.proc, &received), "Python routine execution requires") + client.version = defines.MORPCVersion127 + rt.SetGlobalVariables(moruntime.MOProtocolVersion, defines.MORPCVersion127) require.NoError(t, validateRemoteExpressionDestination(c.proc, &received, features)) require.NoError(t, validateRemoteExpressionPipelineProtocol(c.proc, &received)) require.Equal(t, client.calls, client.releases) diff --git a/pkg/sql/compile/remoterun.go b/pkg/sql/compile/remoterun.go index fa18d07f2de9b..43357867d6e5b 100644 --- a/pkg/sql/compile/remoterun.go +++ b/pkg/sql/compile/remoterun.go @@ -152,7 +152,7 @@ func encodeRemoteScopeWithProtocol(s *Scope, proc *process.Process, requiredProt if err = validateRemoteExpressionFeatures(proc, features); err != nil { return nil, err } - if requiredProtocol != nil && (features.PythonRoutineContract || features.TimestampDatetimeResultContracts || features.DynamicTimeResultContracts || features.TimestampAddSecondIntervals) { + if requiredProtocol != nil && (features.PythonRoutineContract || features.ViewMetadataFunctions || features.TimestampDatetimeResultContracts || features.DynamicTimeResultContracts || features.TimestampAddSecondIntervals) { *requiredProtocol = max(*requiredProtocol, remoteExpressionProtocolVersion(features)) } if requiredProtocol != nil && features.LoadFKIgnoreCheck { @@ -2335,8 +2335,8 @@ func validateRemoteExpressionFeatures(proc *process.Process, features plan.Remot if features.ScalarDivision && proc.DivisionByZeroWarningsEnabled() && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion116) { return moerr.NewNotSupportedNoCtx("SELECT division diagnostics require MORPC protocol version 116") } - if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion126) { - return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 126") + if features.PythonRoutineContract && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion127) { + return moerr.NewNotSupportedNoCtx("Python routine execution requires MORPC protocol version 127") } if features.JSONScalarLiteralContracts && (!hasProtocolVersion || protocolVersion < defines.MORPCVersion104) { return moerr.NewNotSupportedNoCtx("typed JSON scalar literals require MORPC protocol version 104") diff --git a/pkg/sql/compile/vector_scan_protocol_test.go b/pkg/sql/compile/vector_scan_protocol_test.go index eb3090748b8dd..dee7767b74e04 100644 --- a/pkg/sql/compile/vector_scan_protocol_test.go +++ b/pkg/sql/compile/vector_scan_protocol_test.go @@ -41,7 +41,7 @@ import ( ) func TestRemotePipelineProtocolCheckOnExecutionStream(t *testing.T) { - for _, minimum := range []int64{defines.MORPCVersion96, defines.MORPCVersion122, defines.MORPCVersion123, defines.MORPCVersion124, defines.MORPCVersion125, defines.MORPCVersion126} { + for _, minimum := range []int64{defines.MORPCVersion96, defines.MORPCVersion122, defines.MORPCVersion123, defines.MORPCVersion124, defines.MORPCVersion125, defines.MORPCVersion126, defines.MORPCVersion127} { for _, tc := range []struct { name string reply *pipeline.Message diff --git a/pkg/sql/parsers/dialect/mysql/mysql_sql.go b/pkg/sql/parsers/dialect/mysql/mysql_sql.go index 75cb0d54c0cd2..232a2f965c047 100644 --- a/pkg/sql/parsers/dialect/mysql/mysql_sql.go +++ b/pkg/sql/parsers/dialect/mysql/mysql_sql.go @@ -1,4 +1,4 @@ -// Code generated by goyacc -v /Users/linjunhong/.loom/tmp/pr29152-79e4-parser.output -o mysql_sql.go mysql_sql.y. DO NOT EDIT. +// Code generated by goyacc -o mysql_sql.go mysql_sql.y. DO NOT EDIT. //line mysql_sql.y:16 package mysql diff --git a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go index 329c99a663c70..1c0796f04f67e 100644 --- a/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go +++ b/pkg/tests/upgrade/upgrade_v4_0_18_routine_test.go @@ -127,7 +127,7 @@ func TestV4018LoginRepairsLegacyRoutineCatalog(t *testing.T) { db, err := sql.Open("mysql", tenantDSN) require.NoError(t, err) defer db.Close() - require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 126") + require.ErrorContains(t, db.PingContext(ctx), "upgrade requires all CNs to support protocol version 127") }() checkCatalog(sourceVersion, false) tenantDB, err := sql.Open("mysql", tenantDSN) diff --git a/pkg/udf/python_contract.go b/pkg/udf/python_contract.go index f0618921afe3c..e6f1730be5f2b 100644 --- a/pkg/udf/python_contract.go +++ b/pkg/udf/python_contract.go @@ -27,7 +27,7 @@ import ( ) const ( - SharedRoutineRevisionProtocolVersion = defines.MORPCVersion126 + SharedRoutineRevisionProtocolVersion = defines.MORPCVersion127 pythonInlineArtifactDigestDomain = "matrixone-python-inline-artifact" pythonEnvironmentDigestDomain = "matrixone-python-environment" )