diff --git a/go.mod b/go.mod index 100c7c8064..0ce3fa2431 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/PuerkitoBio/goquery v1.8.1 github.com/cockroachdb/apd/v2 v2.0.3-0.20200518165714-d020e156310a github.com/cockroachdb/errors v1.7.5 - github.com/dolthub/dolt/go v0.40.5-0.20260205001014-db7263eb669c + github.com/dolthub/dolt/go v0.40.5-0.20260205190625-38d74885c6f4 github.com/dolthub/eventsapi_schema v0.0.0-20250915094920-eadfd39051ca github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 github.com/dolthub/go-mysql-server v0.20.1-0.20260204193159-86990113e4cc diff --git a/go.sum b/go.sum index 15b8600719..50a2f45ac0 100644 --- a/go.sum +++ b/go.sum @@ -228,8 +228,8 @@ github.com/dolthub/aws-sdk-go-ini-parser v0.0.0-20250305001723-2821c37f6c12 h1:I github.com/dolthub/aws-sdk-go-ini-parser v0.0.0-20250305001723-2821c37f6c12/go.mod h1:rN7X8BHwkjPcfMQQ2QTAq/xM3leUSGLfb+1Js7Y6TVo= github.com/dolthub/dolt-mcp v0.2.2 h1:bpROmam74n95uU4EA3BpOIVlTDT0pzeFMBwe/YRq2mI= github.com/dolthub/dolt-mcp v0.2.2/go.mod h1:S++DJ4QWTAXq+0TNzFa7Oq3IhoT456DJHwAINFAHgDQ= -github.com/dolthub/dolt/go v0.40.5-0.20260205001014-db7263eb669c h1:lrTKtYUO5T5ka0/rgOx9TnSIFuzUv6R86wx7cRDVuUU= -github.com/dolthub/dolt/go v0.40.5-0.20260205001014-db7263eb669c/go.mod h1:GTxR5JEXqpGgYHQc6nBnu/m+TgEC/LP9IPB+b3tIrvc= +github.com/dolthub/dolt/go v0.40.5-0.20260205190625-38d74885c6f4 h1:RiRxt09K8viSZwl4f72KTLZQ228y59tPgdPJXSKvNnA= +github.com/dolthub/dolt/go v0.40.5-0.20260205190625-38d74885c6f4/go.mod h1:GTxR5JEXqpGgYHQc6nBnu/m+TgEC/LP9IPB+b3tIrvc= github.com/dolthub/eventsapi_schema v0.0.0-20250915094920-eadfd39051ca h1:BGFz/0OlKIuC6qHIZQbvPapFvdAJkeEyGXWVgL5clmE= github.com/dolthub/eventsapi_schema v0.0.0-20250915094920-eadfd39051ca/go.mod h1:CoDLfgPqHyBtth0Cp+fi/CmC4R81zJNX4wPjShdZ+Bw= github.com/dolthub/flatbuffers/v23 v23.3.3-dh.2 h1:u3PMzfF8RkKd3lB9pZ2bfn0qEG+1Gms9599cr0REMww= diff --git a/server/hook/delete_table.go b/server/hook/delete_table.go index 301001a0eb..41201e8f91 100644 --- a/server/hook/delete_table.go +++ b/server/hook/delete_table.go @@ -30,7 +30,7 @@ import ( // BeforeTableDeletion performs all validation necessary to ensure that table deletion does not leave the database in an // invalid state. -func BeforeTableDeletion(ctx *sql.Context, runner sql.StatementRunner, nodeInterface sql.Node) (sql.Node, error) { +func BeforeTableDeletion(ctx *sql.Context, _ sql.StatementRunner, nodeInterface sql.Node) (sql.Node, error) { n, ok := nodeInterface.(*plan.DropTable) if !ok { return nil, errors.Newf("DROP TABLE pre-hook expected `*plan.DropTable` but received `%T`", nodeInterface) diff --git a/server/types/type.go b/server/types/type.go index 927ee2d5f4..281651e751 100644 --- a/server/types/type.go +++ b/server/types/type.go @@ -24,6 +24,7 @@ import ( "time" "github.com/cockroachdb/errors" + "github.com/dolthub/dolt/go/store/val" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/types" "github.com/dolthub/vitess/go/sqltypes" @@ -93,6 +94,7 @@ var _ sql.ExtendedType = &DoltgresType{} var _ sql.NullType = &DoltgresType{} var _ sql.StringType = &DoltgresType{} var _ sql.NumberType = &DoltgresType{} +var _ val.TupleTypeHandler = &DoltgresType{} // NewUnresolvedDoltgresType returns a DoltgresType that is not resolved. // The type will have the schema and name defined with given values, with IsUnresolved == true. @@ -1045,6 +1047,32 @@ func (t *DoltgresType) DeserializeValue(ctx context.Context, val []byte) (any, e } } +// SerializationCompatible implements the val.TupleTypeHandler interface. +func (t *DoltgresType) SerializationCompatible(other val.TupleTypeHandler) bool { + ot, ok := other.(*DoltgresType) + return ok && t.Equals(ot) +} + +// ConvertSerialized implements the val.TupleTypeHandler interface. +func (t *DoltgresType) ConvertSerialized(ctx context.Context, other val.TupleTypeHandler, val []byte) ([]byte, error) { + ot, ok := other.(*DoltgresType) + if !ok { + return nil, errors.Errorf("expected DoltgresType, got %T", other) + } + + value, err := ot.DeserializeValue(ctx, val) + if err != nil { + return nil, err + } + + toValue, _, err := t.ConvertToType(nil, ot, value) + if err != nil { + return nil, err + } + + return t.SerializeValue(ctx, toValue) +} + // TypeCastFunction is a function that takes a value of a particular kind of type, and returns it as another kind of type. // The targetType given should match the "To" type used to obtain the cast. type TypeCastFunction func(ctx *sql.Context, val any, targetType *DoltgresType) (any, error) diff --git a/servercfg/config.go b/servercfg/config.go index 957e973cfd..f2d4a85534 100755 --- a/servercfg/config.go +++ b/servercfg/config.go @@ -21,10 +21,11 @@ import ( "github.com/dolthub/go-mysql-server/sql" "gopkg.in/yaml.v2" + "github.com/dolthub/doltgresql/server/hook" + pgsql "github.com/dolthub/doltgresql/postgres/parser/parser/sql" "github.com/dolthub/doltgresql/server/analyzer" "github.com/dolthub/doltgresql/server/expression" - "github.com/dolthub/doltgresql/server/hook" "github.com/dolthub/doltgresql/servercfg/cfgdetails" ) diff --git a/testing/go/foreign_keys_test.go b/testing/go/foreign_keys_test.go index c3bff65821..8325754379 100755 --- a/testing/go/foreign_keys_test.go +++ b/testing/go/foreign_keys_test.go @@ -1124,6 +1124,887 @@ func TestForeignKeys(t *testing.T) { }, }, }, + { + Name: "foreign keys in drizzle migration and merge", + SetUpScript: []string{ + `CREATE SCHEMA "drizzle";`, + `CREATE SEQUENCE drizzle."__drizzle_migrations_id_seq" AS int4;`, + `CREATE TABLE "__drizzle_migrations" ( + "id" integer NOT NULL DEFAULT (nextval('drizzle.__drizzle_migrations_id_seq')), + "hash" text NOT NULL, + "created_at" bigint, + PRIMARY KEY ("id") +);`, + `INSERT INTO "__drizzle_migrations" ("hash","created_at") VALUES ('d3445cf0eaeb405a6b4b9c8386188aece144d40ba89b9616175ca0f69229cc51',1767821157311);`, + `CREATE TABLE "projects" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "models" jsonb, + "stop_when" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","id") +);`, + `CREATE TABLE "agent" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "default_sub_agent_id" varchar(256), + "context_config_id" varchar(256), + "models" jsonb, + "status_updates" jsonb, + "prompt" text, + "stop_when" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "agent_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "artifact_components" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "props" jsonb, + "render" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "artifact_components_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "context_configs" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "agent_id" varchar(256) NOT NULL, + "headers_schema" jsonb, + "context_variables" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","agent_id","id"), + CONSTRAINT "context_configs_agent_fk" FOREIGN KEY ("tenant_id","project_id","agent_id") REFERENCES "agent" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "credential_references" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "type" varchar(256) NOT NULL, + "credential_store_id" varchar(256) NOT NULL, + "retrieval_params" jsonb, + "tool_id" varchar(256), + "user_id" varchar(256), + "created_by" varchar(256), + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "credential_references_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE UNIQUE INDEX "credential_references_id_unique" ON "credential_references" ("id");`, + `CREATE UNIQUE INDEX "credential_references_tool_user_unique" ON "credential_references" ("tool_id", "user_id");`, + `CREATE TABLE "data_components" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "props" jsonb, + "render" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "data_components_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "dataset" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "dataset_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "dataset_item" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "dataset_id" text NOT NULL, + "input" jsonb NOT NULL, + "expected_output" jsonb, + "simulation_agent" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "dataset_item_dataset_fk" FOREIGN KEY ("tenant_id","project_id","dataset_id") REFERENCES "dataset" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "dataset_run_config" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "dataset_id" text NOT NULL, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "dataset_run_config_dataset_fk" FOREIGN KEY ("tenant_id","project_id","dataset_id") REFERENCES "dataset" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "dataset_run_config_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "dataset_run_config_agent_relations" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "dataset_run_config_id" text NOT NULL, + "agent_id" text NOT NULL, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "dataset_run_config_agent_relations_agent_fk" FOREIGN KEY ("tenant_id","project_id","agent_id") REFERENCES "agent" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "dataset_run_config_agent_relations_dataset_run_config_fk" FOREIGN KEY ("tenant_id","project_id","dataset_run_config_id") REFERENCES "dataset_run_config" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "evaluation_job_config" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "job_filters" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "evaluation_job_config_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "evaluator" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "prompt" text NOT NULL, + "schema" jsonb NOT NULL, + "model" jsonb NOT NULL, + "pass_criteria" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "evaluator_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "evaluation_job_config_evaluator_relations" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "evaluation_job_config_id" text NOT NULL, + "evaluator_id" text NOT NULL, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "eval_job_cfg_evaluator_rel_evaluator_fk" FOREIGN KEY ("tenant_id","project_id","evaluator_id") REFERENCES "evaluator" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "eval_job_cfg_evaluator_rel_job_cfg_fk" FOREIGN KEY ("tenant_id","project_id","evaluation_job_config_id") REFERENCES "evaluation_job_config" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "evaluation_run_config" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "is_active" boolean NOT NULL DEFAULT 'true', + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "evaluation_run_config_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "evaluation_suite_config" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "filters" jsonb, + "sample_rate" double precision, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "evaluation_suite_config_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "evaluation_run_config_evaluation_suite_config_relations" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "evaluation_run_config_id" text NOT NULL, + "evaluation_suite_config_id" text NOT NULL, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "eval_run_cfg_eval_suite_rel_run_cfg_fk" FOREIGN KEY ("tenant_id","project_id","evaluation_run_config_id") REFERENCES "evaluation_run_config" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "eval_run_cfg_eval_suite_rel_suite_cfg_fk" FOREIGN KEY ("tenant_id","project_id","evaluation_suite_config_id") REFERENCES "evaluation_suite_config" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "evaluation_suite_config_evaluator_relations" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "evaluation_suite_config_id" text NOT NULL, + "evaluator_id" text NOT NULL, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "eval_suite_cfg_evaluator_rel_evaluator_fk" FOREIGN KEY ("tenant_id","project_id","evaluator_id") REFERENCES "evaluator" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "eval_suite_cfg_evaluator_rel_suite_cfg_fk" FOREIGN KEY ("tenant_id","project_id","evaluation_suite_config_id") REFERENCES "evaluation_suite_config" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "external_agents" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "base_url" text NOT NULL, + "credential_reference_id" varchar(256), + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "external_agents_credential_reference_fk" FOREIGN KEY ("credential_reference_id") REFERENCES "credential_references" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, + CONSTRAINT "external_agents_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "functions" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "input_schema" jsonb, + "execute_code" text NOT NULL, + "dependencies" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "functions_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "function_tools" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "agent_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "function_id" varchar(256) NOT NULL, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","agent_id","id"), + CONSTRAINT "function_tools_agent_fk" FOREIGN KEY ("tenant_id","project_id","agent_id") REFERENCES "agent" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "function_tools_function_fk" FOREIGN KEY ("tenant_id","project_id","function_id") REFERENCES "functions" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "sub_agents" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "agent_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "prompt" text, + "conversation_history_config" jsonb DEFAULT '{"mode":"full","limit":50,"maxOutputTokens":4000,"includeInternal":false,"messageTypes":["chat","tool-result"]}'::JSONB, + "models" jsonb, + "stop_when" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","agent_id","id"), + CONSTRAINT "sub_agents_agents_fk" FOREIGN KEY ("tenant_id","project_id","agent_id") REFERENCES "agent" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "tools" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "config" jsonb NOT NULL, + "credential_reference_id" varchar(256), + "credential_scope" varchar(50) NOT NULL DEFAULT 'project', + "headers" jsonb, + "image_url" text, + "capabilities" jsonb, + "last_error" text, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "tools_credential_reference_fk" FOREIGN KEY ("credential_reference_id") REFERENCES "credential_references" ("id") ON DELETE SET NULL ON UPDATE NO ACTION, + CONSTRAINT "tools_project_fk" FOREIGN KEY ("tenant_id","project_id") REFERENCES "projects" ("tenant_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "sub_agent_artifact_components" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "agent_id" varchar(256) NOT NULL, + "sub_agent_id" varchar(256) NOT NULL, + "artifact_component_id" varchar(256) NOT NULL, + "created_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","agent_id","sub_agent_id","id"), + CONSTRAINT "sub_agent_artifact_components_artifact_component_fk" FOREIGN KEY ("tenant_id","project_id","artifact_component_id") REFERENCES "artifact_components" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "sub_agent_artifact_components_sub_agent_fk" FOREIGN KEY ("tenant_id","project_id","agent_id","sub_agent_id") REFERENCES "sub_agents" ("tenant_id","project_id","agent_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "sub_agent_data_components" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "agent_id" varchar(256) NOT NULL, + "sub_agent_id" varchar(256) NOT NULL, + "data_component_id" varchar(256) NOT NULL, + "created_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","id"), + CONSTRAINT "sub_agent_data_components_data_component_fk" FOREIGN KEY ("tenant_id","project_id","data_component_id") REFERENCES "data_components" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "sub_agent_data_components_sub_agent_fk" FOREIGN KEY ("tenant_id","project_id","agent_id","sub_agent_id") REFERENCES "sub_agents" ("tenant_id","project_id","agent_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "sub_agent_external_agent_relations" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "agent_id" varchar(256) NOT NULL, + "sub_agent_id" varchar(256) NOT NULL, + "external_agent_id" varchar(256) NOT NULL, + "headers" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","agent_id","id"), + CONSTRAINT "sub_agent_external_agent_relations_external_agent_fk" FOREIGN KEY ("tenant_id","project_id","external_agent_id") REFERENCES "external_agents" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "sub_agent_external_agent_relations_sub_agent_fk" FOREIGN KEY ("tenant_id","project_id","agent_id","sub_agent_id") REFERENCES "sub_agents" ("tenant_id","project_id","agent_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "sub_agent_function_tool_relations" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "agent_id" varchar(256) NOT NULL, + "sub_agent_id" varchar(256) NOT NULL, + "function_tool_id" varchar(256) NOT NULL, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","agent_id","id"), + CONSTRAINT "sub_agent_function_tool_relations_function_tool_fk" FOREIGN KEY ("tenant_id","project_id","agent_id","function_tool_id") REFERENCES "function_tools" ("tenant_id","project_id","agent_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "sub_agent_function_tool_relations_sub_agent_fk" FOREIGN KEY ("tenant_id","project_id","agent_id","sub_agent_id") REFERENCES "sub_agents" ("tenant_id","project_id","agent_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "sub_agent_relations" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "agent_id" varchar(256) NOT NULL, + "source_sub_agent_id" varchar(256) NOT NULL, + "target_sub_agent_id" varchar(256), + "relation_type" varchar(256), + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","agent_id","id"), + CONSTRAINT "sub_agent_relations_agent_fk" FOREIGN KEY ("tenant_id","project_id","agent_id") REFERENCES "agent" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "sub_agent_team_agent_relations" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "agent_id" varchar(256) NOT NULL, + "sub_agent_id" varchar(256) NOT NULL, + "target_agent_id" varchar(256) NOT NULL, + "headers" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","agent_id","id"), + CONSTRAINT "sub_agent_team_agent_relations_sub_agent_fk" FOREIGN KEY ("tenant_id","project_id","agent_id","sub_agent_id") REFERENCES "sub_agents" ("tenant_id","project_id","agent_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "sub_agent_team_agent_relations_target_agent_fk" FOREIGN KEY ("tenant_id","project_id","target_agent_id") REFERENCES "agent" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `CREATE TABLE "sub_agent_tool_relations" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "agent_id" varchar(256) NOT NULL, + "sub_agent_id" varchar(256) NOT NULL, + "tool_id" varchar(256) NOT NULL, + "selected_tools" jsonb, + "headers" jsonb, + "tool_policies" jsonb, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","agent_id","id"), + CONSTRAINT "sub_agent_tool_relations_agent_fk" FOREIGN KEY ("tenant_id","project_id","agent_id","sub_agent_id") REFERENCES "sub_agents" ("tenant_id","project_id","agent_id","id") ON DELETE CASCADE ON UPDATE NO ACTION, + CONSTRAINT "sub_agent_tool_relations_tool_fk" FOREIGN KEY ("tenant_id","project_id","tool_id") REFERENCES "tools" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `SELECT DOLT_COMMIT('-Am', 'Applied database migrations');`, + `SELECT DOLT_BRANCH('default_my-weather-project_main');`, + `INSERT INTO "__drizzle_migrations" ("hash","created_at") VALUES ('634b9140001f10d551fe0d81ca19050f3cc8af8da1ab6c9b6e93d99f33e5fc84',1768766675586);`, + `CREATE TABLE "triggers" ( + "tenant_id" varchar(256) NOT NULL, + "id" varchar(256) NOT NULL, + "project_id" varchar(256) NOT NULL, + "agent_id" varchar(256) NOT NULL, + "name" varchar(256) NOT NULL, + "description" text, + "enabled" boolean NOT NULL DEFAULT 'true', + "input_schema" jsonb, + "output_transform" jsonb, + "message_template" text NOT NULL, + "authentication" jsonb, + "signing_secret" text, + "created_at" timestamp NOT NULL DEFAULT (now()), + "updated_at" timestamp NOT NULL DEFAULT (now()), + PRIMARY KEY ("tenant_id","project_id","agent_id","id"), + CONSTRAINT "triggers_agent_fk" FOREIGN KEY ("tenant_id","project_id","agent_id") REFERENCES "agent" ("tenant_id","project_id","id") ON DELETE CASCADE ON UPDATE NO ACTION +);`, + `SELECT DOLT_COMMIT('-Am', 'Applied database migrations');`, + `SELECT DOLT_CHECKOUT('default_my-weather-project_main');`, + `INSERT INTO "projects" ("tenant_id","id","name","description","models","stop_when","created_at","updated_at") VALUES ('default','my-weather-project','Weather Project','Project containing sample agent framework using ','{"base": {"model": "openai/gpt-4o-mini"}}',NULL,'2026-01-22 16:19:32.74','2026-01-22 16:19:32.74');`, + `INSERT INTO "agent" ("tenant_id","id","project_id","name","description","default_sub_agent_id","context_config_id","models","status_updates","prompt","stop_when","created_at","updated_at") VALUES ('default','weather-agent','my-weather-project','Weather agent',NULL,'weather-assistant',NULL,NULL,NULL,NULL,NULL,'2026-01-22 16:19:32.782','2026-01-22 16:19:32.862');`, + `INSERT INTO "data_components" ("tenant_id","id","project_id","name","description","props","render","created_at","updated_at") VALUES ('default','weather-forecast','my-weather-project','WeatherForecast','A hourly forecast for the weather at a given location','{"type": "object", "required": ["forecast"], "properties": {"forecast": {"type": "array", "items": {"type": "object", "required": ["time", "temperature", "code"], "properties": {"code": {"type": "number", "description": "Weather code at given time"}, "time": {"type": "string", "description": "The time of current item E.g. 12PM, 1PM"}, "temperature": {"type": "number", "description": "The temperature at given time in Farenheit"}}, "additionalProperties": false}, "description": "The hourly forecast for the weather at a given location"}}, "additionalProperties": false}',NULL,'2026-01-22 16:19:32.773665','2026-01-22 16:19:32.773665');`, + `INSERT INTO "sub_agents" ("tenant_id","id","project_id","agent_id","name","description","prompt","conversation_history_config","models","stop_when","created_at","updated_at") VALUES ('default','geocoder-agent','my-weather-project','weather-agent','Geocoder agent','Specialized agent for converting addresses and location names into geographic coordinates. This agent handles all location-related queries and provides accurate latitude/longitude data for weather lookups.','You are a geocoding specialist that converts addresses, place names, and location descriptions + into precise geographic coordinates. You help users find the exact location they''re asking about + and provide the coordinates needed for weather forecasting. + + When users provide: + - Street addresses + - City names + - Landmarks + - Postal codes + - General location descriptions + + You should use your geocoding tools to find the most accurate coordinates and provide clear + information about the location found.','{"mode": "full", "limit": 50, "messageTypes": ["chat", "tool-result"], "includeInternal": false, "maxOutputTokens": 4000}',NULL,NULL,'2026-01-22 16:19:32.848333','2026-01-22 16:19:32.848333');`, + `INSERT INTO "sub_agents" ("tenant_id","id","project_id","agent_id","name","description","prompt","conversation_history_config","models","stop_when","created_at","updated_at") VALUES ('default','weather-assistant','my-weather-project','weather-agent','Weather assistant','Main weather assistant that coordinates between geocoding and forecasting services to provide comprehensive weather information. This assistant handles user queries and delegates tasks to specialized sub-agents as needed.','You are a helpful weather assistant that provides comprehensive weather information + for any location worldwide. You coordinate with specialized agents to: + + 1. Convert location names/addresses to coordinates (via geocoder) + 2. Retrieve detailed weather forecasts (via weather forecaster) + 3. Present weather information in a clear, user-friendly format + + When users ask about weather: + - If they provide a location name or address, delegate to the geocoder first + - Once you have coordinates, delegate to the weather forecaster + - Present the final weather information in an organized, easy-to-understand format + - Include relevant details like temperature, conditions, precipitation, wind, etc. + - Provide helpful context and recommendations when appropriate + + You have access to weather forecast data components that can enhance your responses + with structured weather information.','{"mode": "full", "limit": 50, "messageTypes": ["chat", "tool-result"], "includeInternal": false, "maxOutputTokens": 4000}',NULL,NULL,'2026-01-22 16:19:32.851804','2026-01-22 16:19:32.851804');`, + `INSERT INTO "sub_agents" ("tenant_id","id","project_id","agent_id","name","description","prompt","conversation_history_config","models","stop_when","created_at","updated_at") VALUES ('default','weather-forecaster','my-weather-project','weather-agent','Weather forecaster','Specialized agent for retrieving detailed weather forecasts and current conditions. This agent focuses on providing accurate, up-to-date weather information using geographic coordinates.','You are a weather forecasting specialist that provides detailed weather information + including current conditions, forecasts, and weather-related insights. + + You work with precise geographic coordinates to deliver: + - Current weather conditions + - Short-term and long-term forecasts + - Temperature, humidity, wind, and precipitation data + - Weather alerts and advisories + - Seasonal and climate information + + Always provide clear, actionable weather information that helps users plan their activities.','{"mode": "full", "limit": 50, "messageTypes": ["chat", "tool-result"], "includeInternal": false, "maxOutputTokens": 4000}',NULL,NULL,'2026-01-22 16:19:32.844618','2026-01-22 16:19:32.844618');`, + `INSERT INTO "tools" ("tenant_id","id","project_id","name","description","config","credential_reference_id","credential_scope","headers","image_url","capabilities","last_error","created_at","updated_at") VALUES ('default','fUI2riwrBVJ6MepT8rjx0','my-weather-project','Forecast weather',NULL,'{"mcp": {"server": {"url": "https://weather-mcp-hazel.vercel.app/mcp"}}, "type": "mcp"}',NULL,'project',NULL,NULL,NULL,NULL,'2026-01-22 16:19:32.748','2026-01-22 16:19:32.748');`, + `INSERT INTO "tools" ("tenant_id","id","project_id","name","description","config","credential_reference_id","credential_scope","headers","image_url","capabilities","last_error","created_at","updated_at") VALUES ('default','fdxgfv9HL7SXlfynPx8hf','my-weather-project','Geocode address',NULL,'{"mcp": {"server": {"url": "https://weather-mcp-hazel.vercel.app/mcp"}}, "type": "mcp"}',NULL,'project',NULL,NULL,NULL,NULL,'2026-01-22 16:19:32.75','2026-01-22 16:19:32.75');`, + `INSERT INTO "sub_agent_relations" ("tenant_id","id","project_id","agent_id","source_sub_agent_id","target_sub_agent_id","relation_type","created_at","updated_at") VALUES ('default','0y59hwkkyzml4dq4t1sx8','my-weather-project','weather-agent','weather-assistant','weather-forecaster','delegate','2026-01-22 16:19:32.92219','2026-01-22 16:19:32.92219');`, + `INSERT INTO "sub_agent_relations" ("tenant_id","id","project_id","agent_id","source_sub_agent_id","target_sub_agent_id","relation_type","created_at","updated_at") VALUES ('default','7ye45uc4j5442ihgqwn6d','my-weather-project','weather-agent','weather-assistant','geocoder-agent','delegate','2026-01-22 16:19:32.925527','2026-01-22 16:19:32.925527');`, + `INSERT INTO "sub_agent_data_components" ("tenant_id","id","project_id","agent_id","sub_agent_id","data_component_id","created_at") VALUES ('default','689yd78rj16p9880bndfo','my-weather-project','weather-agent','weather-assistant','weather-forecast','2026-01-22 16:19:32.907332');`, + `INSERT INTO "sub_agent_tool_relations" ("tenant_id","id","project_id","agent_id","sub_agent_id","tool_id","selected_tools","headers","tool_policies","created_at","updated_at") VALUES ('default','4kws0lm8bqi1mkzwbvmz4','my-weather-project','weather-agent','weather-forecaster','fUI2riwrBVJ6MepT8rjx0',NULL,NULL,NULL,'2026-01-22 16:19:32.888','2026-01-22 16:19:32.888');`, + `INSERT INTO "sub_agent_tool_relations" ("tenant_id","id","project_id","agent_id","sub_agent_id","tool_id","selected_tools","headers","tool_policies","created_at","updated_at") VALUES ('default','ttz1a9tnso0sxim79iphr','my-weather-project','weather-agent','geocoder-agent','fdxgfv9HL7SXlfynPx8hf',NULL,NULL,NULL,'2026-01-22 16:19:32.889','2026-01-22 16:19:32.889');`, + `SELECT DOLT_COMMIT('-Am', '//Update /manage/tenants/default/project-full/my-weather-project via API');`, + `UPDATE "tools" SET "updated_at"='2026-01-22 16:19:50.912' WHERE "tenant_id"='default' AND "id"='fUI2riwrBVJ6MepT8rjx0' AND "project_id"='my-weather-project';`, + `UPDATE "tools" SET "updated_at"='2026-01-22 16:19:50.967' WHERE "tenant_id"='default' AND "id"='fdxgfv9HL7SXlfynPx8hf' AND "project_id"='my-weather-project';`, + `SELECT DOLT_COMMIT('-Am', 'GET /manage/tenants/default/projects/my-weather-project/tools via API');`, + `INSERT INTO "evaluator" ("tenant_id","id","project_id","name","description","prompt","schema","model","pass_criteria","created_at","updated_at") VALUES ('default','ubqho5lsm6h7bd3ra8loz','my-weather-project','test','test','test','{"type": "object", "required": ["test"], "properties": {"test": {"type": "string", "description": "test"}}, "additionalProperties": false}','{"model": "anthropic/claude-opus-4-5"}',NULL,'2026-01-22 16:20:07.188','2026-01-22 16:20:07.188');`, + `SELECT DOLT_COMMIT('-Am', 'Create /manage/tenants/default/projects/my-weather-project/evals/evaluators via API');`, + `UPDATE "tools" SET "updated_at"='2026-01-22 16:20:11.438' WHERE "tenant_id"='default' AND "id"='fUI2riwrBVJ6MepT8rjx0' AND "project_id"='my-weather-project';`, + `UPDATE "tools" SET "updated_at"='2026-01-22 16:20:11.448' WHERE "tenant_id"='default' AND "id"='fdxgfv9HL7SXlfynPx8hf' AND "project_id"='my-weather-project';`, + `SELECT DOLT_COMMIT('-Am', 'GET /manage/tenants/default/projects/my-weather-project/tools via API');`, + `UPDATE "tools" SET "updated_at"='2026-01-22 16:20:17.821' WHERE "tenant_id"='default' AND "id"='fUI2riwrBVJ6MepT8rjx0' AND "project_id"='my-weather-project';`, + `UPDATE "tools" SET "updated_at"='2026-01-22 16:20:18.082' WHERE "tenant_id"='default' AND "id"='fdxgfv9HL7SXlfynPx8hf' AND "project_id"='my-weather-project';`, + `SELECT DOLT_COMMIT('-Am', 'GET /manage/tenants/default/projects/my-weather-project/tools via API');`, + `INSERT INTO "evaluation_job_config" ("tenant_id","id","project_id","job_filters","created_at","updated_at") VALUES ('default','tj06kzjt8ltlyixgfzeao','my-weather-project','{"dateRange": {"endDate": "2026-01-23T04:59:59.999Z", "startDate": "2026-01-21T05:00:00.000Z"}}','2026-01-22 16:20:55.774','2026-01-22 16:20:55.774');`, + `INSERT INTO "evaluation_job_config_evaluator_relations" ("tenant_id","id","project_id","evaluation_job_config_id","evaluator_id","created_at","updated_at") VALUES ('default','5qk0w692h5ij1sxtohdua','my-weather-project','tj06kzjt8ltlyixgfzeao','ubqho5lsm6h7bd3ra8loz','2026-01-22 16:20:55.781','2026-01-22 16:20:55.781');`, + `SELECT DOLT_COMMIT('-Am', 'Create /manage/tenants/default/projects/my-weather-project/evals/evaluation-job-configs via API');`, + `INSERT INTO "evaluation_suite_config" ("tenant_id","id","project_id","filters","sample_rate","created_at","updated_at") VALUES ('default','j5gvgluqzwzhjhycrsnpf','my-weather-project','{"agentIds": ["weather-agent"]}',NULL,'2026-01-22 16:21:19.974','2026-01-22 16:21:19.974');`, + `INSERT INTO "evaluation_suite_config_evaluator_relations" ("tenant_id","id","project_id","evaluation_suite_config_id","evaluator_id","created_at","updated_at") VALUES ('default','tz51dzynx71gits265e9d','my-weather-project','j5gvgluqzwzhjhycrsnpf','ubqho5lsm6h7bd3ra8loz','2026-01-22 16:21:19.982','2026-01-22 16:21:19.982');`, + `SELECT DOLT_COMMIT('-Am', 'Create /manage/tenants/default/projects/my-weather-project/evals/evaluation-suite-configs via API');`, + `INSERT INTO "evaluation_run_config" ("tenant_id","id","project_id","name","description","is_active","created_at","updated_at") VALUES ('default','74pgwrprmea2o7e6avbh7','my-weather-project','test','test',true,'2026-01-22 16:21:20.104','2026-01-22 16:21:20.104');`, + `INSERT INTO "evaluation_run_config_evaluation_suite_config_relations" ("tenant_id","id","project_id","evaluation_run_config_id","evaluation_suite_config_id","created_at","updated_at") VALUES ('default','plb31qfzw9803g6hbjhef','my-weather-project','74pgwrprmea2o7e6avbh7','j5gvgluqzwzhjhycrsnpf','2026-01-22 16:21:20.111','2026-01-22 16:21:20.111');`, + `SELECT DOLT_COMMIT('-Am', 'Create /manage/tenants/default/projects/my-weather-project/evals/evaluation-run-configs via API');`, + `UPDATE "tools" SET "updated_at"='2026-01-22 16:21:23.521' WHERE "tenant_id"='default' AND "id"='fUI2riwrBVJ6MepT8rjx0' AND "project_id"='my-weather-project';`, + `UPDATE "tools" SET "updated_at"='2026-01-22 16:21:23.771' WHERE "tenant_id"='default' AND "id"='fdxgfv9HL7SXlfynPx8hf' AND "project_id"='my-weather-project';`, + `SELECT DOLT_COMMIT('-Am', 'GET /manage/tenants/default/projects/my-weather-project/tools via API');`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select strpos(dolt_merge('main')::text, 'merge successful') > 0;", + Expected: []sql.Row{{"t"}}, + }, + }, + }, + { + Name: "Merge foreign keys across types, text -> varchar", + SetUpScript: []string{ + `CREATE TABLE table1 ( + table1_col1 VARCHAR(256), + table1_col2 VARCHAR(256), + table1_col3 VARCHAR(256), + PRIMARY KEY (table1_col1, table1_col3, table1_col2) + );`, + `CREATE TABLE table2 ( + table2_col1 VARCHAR(256), + table2_col2 VARCHAR(256), + table2_col3 VARCHAR(256), + table2_col4 TEXT, + PRIMARY KEY (table2_col1, table2_col3, table2_col2), + CONSTRAINT table2_fk FOREIGN KEY (table2_col1, table2_col3, table2_col4) REFERENCES table1 (table1_col1, table1_col3, table1_col2) ON DELETE CASCADE ON UPDATE NO ACTION + );`, + `SELECT DOLT_COMMIT('-Am', '1');`, + `SELECT DOLT_BRANCH('other_branch');`, + `CREATE TABLE table3 (table3_col1 VARCHAR(256));`, + `SELECT DOLT_COMMIT('-Am', '2');`, + `SELECT DOLT_CHECKOUT('other_branch');`, + `INSERT INTO table1 (table1_col1, table1_col2, table1_col3) VALUES ('abc','def','ghi');`, + `SELECT DOLT_COMMIT('-Am', '3');`, + `INSERT INTO table2 (table2_col1, table2_col2, table2_col3, table2_col4) VALUES ('abc','jkl','ghi','def');`, + `SELECT DOLT_COMMIT('-Am', '4');`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select strpos(dolt_merge('main')::text, 'merge successful') > 0;", + Expected: []sql.Row{{"t"}}, + }, + }, + }, + { + Name: "Merge foreign keys across types, varchar -> text", + SetUpScript: []string{ + `CREATE TABLE table1 ( + table1_col1 VARCHAR(256), + table1_col2 text, + table1_col3 text, + PRIMARY KEY (table1_col1, table1_col3, table1_col2) + );`, + `CREATE TABLE table2 ( + table2_col1 VARCHAR(256), + table2_col2 VARCHAR(256), + table2_col3 VARCHAR(256), + table2_col4 VARCHAR(256), + PRIMARY KEY (table2_col1, table2_col3, table2_col2), + CONSTRAINT table2_fk FOREIGN KEY (table2_col1, table2_col3, table2_col4) REFERENCES table1 (table1_col1, table1_col3, table1_col2) ON DELETE CASCADE ON UPDATE NO ACTION + );`, + `SELECT DOLT_COMMIT('-Am', '1');`, + `SELECT DOLT_BRANCH('other_branch');`, + `CREATE TABLE table3 (table3_col1 VARCHAR(256));`, + `SELECT DOLT_COMMIT('-Am', '2');`, + `SELECT DOLT_CHECKOUT('other_branch');`, + `INSERT INTO table1 (table1_col1, table1_col2, table1_col3) VALUES ('abc','def','ghi');`, + `SELECT DOLT_COMMIT('-Am', '3');`, + `INSERT INTO table2 (table2_col1, table2_col2, table2_col3, table2_col4) VALUES ('abc','jkl','ghi','def');`, + `SELECT DOLT_COMMIT('-Am', '4');`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select strpos(dolt_merge('main')::text, 'merge successful') > 0;", + Expected: []sql.Row{{"t"}}, + }, + }, + }, + { + Name: "Merge foreign keys across types, varchar -> text, violation", + SetUpScript: []string{ + `CREATE TABLE parent (a TEXT PRIMARY KEY);`, + `CREATE TABLE child (b INT PRIMARY KEY, c varchar(255), CONSTRAINT fk FOREIGN KEY (c) REFERENCES parent(a) ON DELETE CASCADE ON UPDATE NO ACTION);`, + `INSERT INTO parent (a) VALUES ('abc'), ('def');`, + `INSERT INTO child (b, c) VALUES (1, 'abc'), (2, 'def');`, + `SELECT DOLT_COMMIT('-Am', '1');`, + `SELECT DOLT_BRANCH('other_branch');`, + `DELETE FROM child WHERE b=1;`, + `DELETE FROM parent WHERE a='abc';`, + `SELECT DOLT_COMMIT('-Am', '2');`, + `SELECT DOLT_CHECKOUT('other_branch');`, + `INSERT INTO child (b, c) VALUES (3, 'abc');`, + `SELECT DOLT_COMMIT('-Am', '3');`, + `set dolt_force_transaction_commit=1;`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select strpos(dolt_merge('main')::text, 'merge successful') > 0;", + Expected: []sql.Row{{"f"}}, + }, + { + Query: "select violation_type, b, c from dolt_constraint_violations_child;", + Expected: []sql.Row{{"foreign key", 3, "abc"}}, + }, + }, + }, + { + Name: "Merge foreign keys across types, varchar -> text 2 column key, violation", + SetUpScript: []string{ + `CREATE TABLE parent ( + a VARCHAR(256), + b text, + c VARCHAR(256), + PRIMARY KEY (b, a) + );`, + `CREATE INDEX idx_parent_on_a_b ON parent (a, b);`, + `CREATE TABLE child ( + d VARCHAR(256), + e VARCHAR(256), + f varchar(256), + PRIMARY KEY (e, d), + CONSTRAINT child_fk FOREIGN KEY (d, f) REFERENCES parent (a, b) ON DELETE CASCADE ON UPDATE NO ACTION + );`, + `INSERT INTO parent VALUES ('abc','def', 'xyz');`, + `INSERT INTO child VALUES ('abc','123','def');`, + `SELECT DOLT_COMMIT('-Am', '1');`, + `SELECT DOLT_BRANCH('other_branch');`, + `INSERT INTO child VALUES ('abc','www','def');`, + `SELECT DOLT_COMMIT('-Am', '2');`, + `CREATE TABLE table3 (table3_col1 VARCHAR(256));`, + `SELECT DOLT_COMMIT('-Am', '3');`, + `SELECT DOLT_CHECKOUT('other_branch');`, + `delete from child where e='def';`, + `delete from parent where a='abc';`, + `SELECT DOLT_COMMIT('-Am', '4');`, + `set dolt_force_transaction_commit=1;`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select strpos(dolt_merge('main')::text, 'merge successful') > 0;", + Expected: []sql.Row{{"f"}}, + }, + { + Query: "select violation_type, d, e, f from dolt_constraint_violations_child;", + Expected: []sql.Row{{"foreign key", "abc", "www", "def"}}, + }, + }, + }, + { + Name: "Merge foreign keys across types, varchar -> text 2 column key, no violation", + SetUpScript: []string{ + `CREATE TABLE parent ( + a VARCHAR(256), + b text, + c VARCHAR(256), + PRIMARY KEY (b, a) + );`, + `CREATE INDEX idx_parent_on_a_b ON parent (a, b);`, + `CREATE TABLE child ( + d VARCHAR(256), + e VARCHAR(256), + f varchar(256), + PRIMARY KEY (e, d), + CONSTRAINT child_fk FOREIGN KEY (d, f) REFERENCES parent (a, b) ON DELETE CASCADE ON UPDATE NO ACTION + );`, + `INSERT INTO parent VALUES ('abc','def', 'xyz');`, + `INSERT INTO child VALUES ('abc','123','def');`, + `SELECT DOLT_COMMIT('-Am', '1');`, + `SELECT DOLT_BRANCH('other_branch');`, + `INSERT INTO child VALUES ('abc','www','def');`, + `SELECT DOLT_COMMIT('-Am', '2');`, + `CREATE TABLE table3 (table3_col1 VARCHAR(256));`, + `SELECT DOLT_COMMIT('-Am', '3');`, + `SELECT DOLT_CHECKOUT('other_branch');`, + `INSERT INTO child VALUES ('abc','xyz','def');`, + `SELECT DOLT_COMMIT('-Am', '4');`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select strpos(dolt_merge('main')::text, 'merge successful') > 0;", + Expected: []sql.Row{{"t"}}, + }, + { + Query: "select violation_type, d, e, f from dolt_constraint_violations_child;", + Expected: []sql.Row{}, + }, + }, + }, + { + Name: "Merge foreign keys across types, varchar -> text 2 column key, parent primary index, violation", + SetUpScript: []string{ + `CREATE TABLE parent ( + a VARCHAR(256), + b text, + c VARCHAR(256), + PRIMARY KEY (b, a) + );`, + `CREATE TABLE child ( + d VARCHAR(256), + e VARCHAR(256), + f varchar(256), + PRIMARY KEY (e, d), + CONSTRAINT child_fk FOREIGN KEY (f, d) REFERENCES parent (b, a) ON DELETE CASCADE ON UPDATE NO ACTION + );`, + `INSERT INTO parent VALUES ('abc','def', 'xyz');`, + `INSERT INTO child VALUES ('abc','123','def');`, + `SELECT DOLT_COMMIT('-Am', '1');`, + `SELECT DOLT_BRANCH('other_branch');`, + `INSERT INTO child VALUES ('abc','www','def');`, + `SELECT DOLT_COMMIT('-Am', '2');`, + `CREATE TABLE table3 (table3_col1 VARCHAR(256));`, + `SELECT DOLT_COMMIT('-Am', '3');`, + `SELECT DOLT_CHECKOUT('other_branch');`, + `delete from child where e='def';`, + `delete from parent where a='abc';`, + `SELECT DOLT_COMMIT('-Am', '4');`, + `set dolt_force_transaction_commit=1;`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select strpos(dolt_merge('main')::text, 'merge successful') > 0;", + Expected: []sql.Row{{"f"}}, + }, + { + Query: "select violation_type, d, e, f from dolt_constraint_violations_child;", + Expected: []sql.Row{{"foreign key", "abc", "www", "def"}}, + }, + }, + }, + { + Name: "Merge foreign keys across types, varchar -> text 2 column key, parent primary index, no violation", + SetUpScript: []string{ + `CREATE TABLE parent ( + a VARCHAR(256), + b text, + c VARCHAR(256), + PRIMARY KEY (b, a) + );`, + `CREATE TABLE child ( + d VARCHAR(256), + e VARCHAR(256), + f varchar(256), + PRIMARY KEY (e, d), + CONSTRAINT child_fk FOREIGN KEY (f, d) REFERENCES parent (b, a) ON DELETE CASCADE ON UPDATE NO ACTION + );`, + `INSERT INTO parent VALUES ('abc','def', 'xyz');`, + `INSERT INTO child VALUES ('abc','123','def');`, + `SELECT DOLT_COMMIT('-Am', '1');`, + `SELECT DOLT_BRANCH('other_branch');`, + `INSERT INTO child VALUES ('abc','www','def');`, + `SELECT DOLT_COMMIT('-Am', '2');`, + `CREATE TABLE table3 (table3_col1 VARCHAR(256));`, + `SELECT DOLT_COMMIT('-Am', '3');`, + `SELECT DOLT_CHECKOUT('other_branch');`, + `INSERT INTO child VALUES ('abc','xyz','def');`, + `SELECT DOLT_COMMIT('-Am', '4');`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select strpos(dolt_merge('main')::text, 'merge successful') > 0;", + Expected: []sql.Row{{"t"}}, + }, + { + Query: "select violation_type, d, e, f from dolt_constraint_violations_child;", + Expected: []sql.Row{}, + }, + }, + }, + { + Name: "Merge foreign keys across types, varchar -> text 2 column key, child primary index, violation", + SetUpScript: []string{ + `CREATE TABLE parent ( + a VARCHAR(256), + b text, + c VARCHAR(256), + PRIMARY KEY (b, a) + );`, + `CREATE TABLE child ( + d VARCHAR(256), + e VARCHAR(256), + f varchar(256), + PRIMARY KEY (e, d) + );`, + `INSERT INTO parent VALUES ('abc','def', 'xyz');`, + `INSERT INTO child VALUES ('abc','123', 'def');`, + `SELECT DOLT_COMMIT('-Am', '1');`, + `SELECT DOLT_BRANCH('other_branch');`, + `ALTER TABLE child ADD CONSTRAINT child_fk FOREIGN KEY (f, d) REFERENCES parent (b, a);`, + `SELECT DOLT_COMMIT('-Am', '2');`, + `CREATE TABLE table3 (table3_col1 VARCHAR(256));`, + `SELECT DOLT_COMMIT('-Am', '3');`, + `SELECT DOLT_CHECKOUT('other_branch');`, + `INSERT INTO child VALUES ('abc','def','xxx');`, + `SELECT DOLT_COMMIT('-Am', '4');`, + `set dolt_force_transaction_commit=1;`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select strpos(dolt_merge('main')::text, 'merge successful') > 0;", + Expected: []sql.Row{{"f"}}, + }, + { + Query: "select violation_type, d, e, f from dolt_constraint_violations_child;", + Expected: []sql.Row{{"foreign key", "abc", "def", "xxx"}}, + }, + }, + }, + { + Name: "Merge foreign keys across types, varchar -> text 2 column key, child secondary index, violation", + SetUpScript: []string{ + `CREATE TABLE parent ( + a VARCHAR(256), + b text, + c VARCHAR(256), + PRIMARY KEY (b, a) + );`, + `CREATE TABLE child ( + d VARCHAR(256), + e VARCHAR(256), + f varchar(256), + g VARCHAR(256), + PRIMARY KEY (e, d) + );`, + `INSERT INTO parent VALUES ('abc','def', 'xyz');`, + `INSERT INTO child VALUES ('abc','123', 'abc', 'def');`, + `SELECT DOLT_COMMIT('-Am', '1');`, + `SELECT DOLT_BRANCH('other_branch');`, + `ALTER TABLE child ADD CONSTRAINT child_fk FOREIGN KEY (g, f) REFERENCES parent (b, a);`, + `SELECT DOLT_COMMIT('-Am', '2');`, + `CREATE TABLE table3 (table3_col1 VARCHAR(256));`, + `SELECT DOLT_COMMIT('-Am', '3');`, + `SELECT DOLT_CHECKOUT('other_branch');`, + `INSERT INTO child VALUES ('xyz','123', 'def', 'abc');`, + `SELECT DOLT_COMMIT('-Am', '4');`, + `set dolt_force_transaction_commit=1;`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select strpos(dolt_merge('main')::text, 'merge successful') > 0;", + Expected: []sql.Row{{"f"}}, + }, + { + Query: "select violation_type, d, e, f, g from dolt_constraint_violations_child;", + Expected: []sql.Row{{"foreign key", "xyz", "123", "def", "abc"}}, + }, + }, + }, + { + Name: "Merge foreign keys across types, varchar -> text 3 column key, violation", + SetUpScript: []string{ + `CREATE TABLE table1 ( + table1_col1 VARCHAR(256), + table1_col2 text, + table1_col3 text, + PRIMARY KEY (table1_col1, table1_col3, table1_col2) + );`, + `CREATE TABLE table2 ( + table2_col1 VARCHAR(256), + table2_col2 VARCHAR(256), + table2_col3 VARCHAR(256), + table2_col4 VARCHAR(256), + PRIMARY KEY (table2_col1, table2_col3, table2_col2), + CONSTRAINT table2_fk FOREIGN KEY (table2_col1, table2_col3, table2_col4) REFERENCES table1 (table1_col1, table1_col3, table1_col2) ON DELETE CASCADE ON UPDATE NO ACTION + );`, + `INSERT INTO table1 (table1_col1, table1_col2, table1_col3) VALUES ('abc','def','ghi');`, + `INSERT INTO table2 (table2_col1, table2_col2, table2_col3, table2_col4) VALUES ('abc','jkl','ghi','def');`, + `SELECT DOLT_COMMIT('-Am', '1');`, + `SELECT DOLT_BRANCH('other_branch');`, + `INSERT INTO table2 (table2_col1, table2_col2, table2_col3, table2_col4) VALUES ('abc','xyz','ghi','def');`, + `SELECT DOLT_COMMIT('-Am', '2');`, + `CREATE TABLE table3 (table3_col1 VARCHAR(256));`, + `SELECT DOLT_COMMIT('-Am', '3');`, + `SELECT DOLT_CHECKOUT('other_branch');`, + `delete from table2 where table2_col2='jkl';`, + `delete from table1 where table1_col2='def';`, + `SELECT DOLT_COMMIT('-Am', '4');`, + `set dolt_force_transaction_commit=1;`, + }, + Assertions: []ScriptTestAssertion{ + { + Query: "select strpos(dolt_merge('main')::text, 'merge successful') > 0;", + Expected: []sql.Row{{"f"}}, + }, + { + Query: "select violation_type, table2_col1, table2_col2, table2_col3, table2_col4 from dolt_constraint_violations_table2;", + Expected: []sql.Row{{"foreign key", "abc", "xyz", "ghi", "def"}}, + }, + }, + }, }, ) }