diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5fb308e62c..dc5f3d2d3a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,7 +67,7 @@ We've included an example env file `test.env.example` with the environment varia ## Advanced Debugging -If you want to build and test the provider locally you should edit you `~.terraformrc` file to include the following: +If you want to build and test the provider locally you should edit your `~/.terraformrc` file to include the following: ``` provider_installation { diff --git a/docs/resources/table.md b/docs/resources/table.md index c3007e302d..bc62cf6a3c 100644 --- a/docs/resources/table.md +++ b/docs/resources/table.md @@ -121,6 +121,10 @@ Optional: - `masking_policy` (String) Masking policy to apply on column. It has to be a fully qualified name. - `nullable` (Boolean) Whether this column can contain null values. **Note**: Depending on your Snowflake version, the default value will not suffice if this column is used in a primary key constraint. +Read-Only: + +- `schema_evolution_record` (String) Record of schema evolution. + ### Nested Schema for `column.default` diff --git a/pkg/acceptance/helpers/stage_client.go b/pkg/acceptance/helpers/stage_client.go index bbad106f06..20745dbca0 100644 --- a/pkg/acceptance/helpers/stage_client.go +++ b/pkg/acceptance/helpers/stage_client.go @@ -116,3 +116,14 @@ func (c *StageClient) PutOnStageWithContent(t *testing.T, id sdk.SchemaObjectIde require.NoError(t, err) }) } + +func (c *StageClient) CopyIntoTableFromFile(t *testing.T, table, stage sdk.SchemaObjectIdentifier, filename string) { + t.Helper() + ctx := context.Background() + + _, err := c.context.client.ExecForTests(ctx, fmt.Sprintf(`COPY INTO %s + FROM @%s/%s + FILE_FORMAT = (type=json) + MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE`, table.FullyQualifiedName(), stage.FullyQualifiedName(), filename)) + require.NoError(t, err) +} diff --git a/pkg/acceptance/helpers/table_client.go b/pkg/acceptance/helpers/table_client.go index eb5e9fa08d..698934daea 100644 --- a/pkg/acceptance/helpers/table_client.go +++ b/pkg/acceptance/helpers/table_client.go @@ -131,4 +131,5 @@ type InformationSchemaColumns struct { IdentityCycle sql.NullString `db:"IDENTITY_CYCLE"` IdentityOrdered sql.NullString `db:"IDENTITY_ORDERED"` Comment sql.NullString `db:"COMMENT"` + SchemaEvolutionRecord sql.NullString `db:"SCHEMA_EVOLUTION_RECORD"` } diff --git a/pkg/resources/table.go b/pkg/resources/table.go index a09174ef79..fe63886893 100644 --- a/pkg/resources/table.go +++ b/pkg/resources/table.go @@ -145,6 +145,11 @@ var tableSchema = map[string]*schema.Schema{ Default: "", Description: "Column collation, e.g. utf8", }, + "schema_evolution_record": { + Type: schema.TypeString, + Computed: true, + Description: "Record of schema evolution.", + }, }, }, }, @@ -496,6 +501,11 @@ func toColumnConfig(descriptions []sdk.TableColumnDetails) []any { flat["default"] = []any{def} } } + + if td.SchemaEvolutionRecord != nil { + flat["schema_evolution_record"] = *td.SchemaEvolutionRecord + } + flattened = append(flattened, flat) } return flattened diff --git a/pkg/resources/table_acceptance_test.go b/pkg/resources/table_acceptance_test.go index 8f03d72471..a3ddfbfe7f 100644 --- a/pkg/resources/table_acceptance_test.go +++ b/pkg/resources/table_acceptance_test.go @@ -164,6 +164,7 @@ func TestAcc_Table(t *testing.T) { resource.TestCheckResourceAttr("snowflake_table.test_table", "column.0.type", "VARIANT"), resource.TestCheckResourceAttr("snowflake_table.test_table", "column.1.name", "column2"), resource.TestCheckResourceAttr("snowflake_table.test_table", "column.1.comment", ""), + resource.TestCheckResourceAttr("snowflake_table.test_table", "column.1.schema_evolution_record", ""), resource.TestCheckNoResourceAttr("snowflake_table.test_table", "primary_key.0"), ), }, diff --git a/pkg/sdk/alerts.go b/pkg/sdk/alerts.go index 35b30dfd8c..90a3fd2428 100644 --- a/pkg/sdk/alerts.go +++ b/pkg/sdk/alerts.go @@ -2,6 +2,7 @@ package sdk import ( "context" + "database/sql" "errors" "fmt" "time" @@ -218,35 +219,37 @@ func (v *Alert) ObjectType() ObjectType { } type Alert struct { - CreatedOn time.Time - Name string - DatabaseName string - SchemaName string - Owner string - Comment *string - Warehouse string - Schedule string - State AlertState - Condition string - Action string + CreatedOn time.Time + Name string + DatabaseName string + SchemaName string + Owner string + Comment *string + Warehouse string + Schedule string + State AlertState + Condition string + Action string + OwnerRoleType string } type alertDBRow struct { - CreatedOn time.Time `db:"created_on"` - Name string `db:"name"` - DatabaseName string `db:"database_name"` - SchemaName string `db:"schema_name"` - Owner string `db:"owner"` - Comment *string `db:"comment"` - Warehouse string `db:"warehouse"` - Schedule string `db:"schedule"` - State string `db:"state"` // suspended, started - Condition string `db:"condition"` - Action string `db:"action"` + CreatedOn time.Time `db:"created_on"` + Name string `db:"name"` + DatabaseName string `db:"database_name"` + SchemaName string `db:"schema_name"` + Owner string `db:"owner"` + Comment *string `db:"comment"` + Warehouse string `db:"warehouse"` + Schedule string `db:"schedule"` + State string `db:"state"` // suspended, started + Condition string `db:"condition"` + Action string `db:"action"` + OwnerRoleType sql.NullString `db:"owner_role_type"` } func (row alertDBRow) convert() *Alert { - return &Alert{ + alert := &Alert{ CreatedOn: row.CreatedOn, Name: row.Name, DatabaseName: row.DatabaseName, @@ -259,6 +262,11 @@ func (row alertDBRow) convert() *Alert { Condition: row.Condition, Action: row.Action, } + if row.OwnerRoleType.Valid { + alert.OwnerRoleType = row.OwnerRoleType.String + } + + return alert } func (opts *ShowAlertOptions) validate() error { diff --git a/pkg/sdk/databases.go b/pkg/sdk/databases.go index 3c3e0745c0..55a37a9d83 100644 --- a/pkg/sdk/databases.go +++ b/pkg/sdk/databases.go @@ -57,6 +57,7 @@ type Database struct { DroppedOn time.Time Transient bool Kind string + OwnerRoleType string } func (v *Database) ID() AccountObjectIdentifier { @@ -80,6 +81,7 @@ type databaseRow struct { ResourceGroup sql.NullString `db:"resource_group"` DroppedOn sql.NullTime `db:"dropped_on"` Kind sql.NullString `db:"kind"` + OwnerRoleType sql.NullString `db:"owner_role_type"` } func (row databaseRow) convert() *Database { @@ -129,6 +131,9 @@ func (row databaseRow) convert() *Database { if row.Kind.Valid { database.Kind = row.Kind.String } + if row.OwnerRoleType.Valid { + database.OwnerRoleType = row.OwnerRoleType.String + } return database } diff --git a/pkg/sdk/dynamic_table.go b/pkg/sdk/dynamic_table.go index b30b55b4bf..7d697e9709 100644 --- a/pkg/sdk/dynamic_table.go +++ b/pkg/sdk/dynamic_table.go @@ -125,6 +125,7 @@ type DynamicTable struct { IsClone bool IsReplica bool DataTimestamp time.Time + OwnerRoleType string } func (dt *DynamicTable) ID() SchemaObjectIdentifier { @@ -153,6 +154,7 @@ type dynamicTableRow struct { IsClone bool `db:"is_clone"` IsReplica bool `db:"is_replica"` DataTimestamp sql.NullTime `db:"data_timestamp"` + OwnerRoleType sql.NullString `db:"owner_role_type"` } func (dtr dynamicTableRow) convert() *DynamicTable { @@ -185,6 +187,10 @@ func (dtr dynamicTableRow) convert() *DynamicTable { if dtr.LastSuspendedOn.Valid { dt.LastSuspendedOn = dtr.LastSuspendedOn.Time } + if dtr.OwnerRoleType.Valid { + dt.OwnerRoleType = dtr.OwnerRoleType.String + } + return dt } diff --git a/pkg/sdk/masking_policy.go b/pkg/sdk/masking_policy.go index 4c50c36ce9..78ededbeec 100644 --- a/pkg/sdk/masking_policy.go +++ b/pkg/sdk/masking_policy.go @@ -230,6 +230,7 @@ type MaskingPolicy struct { Owner string Comment string ExemptOtherPolicies bool + OwnerRoleType string } func (v *MaskingPolicy) ID() SchemaObjectIdentifier { @@ -267,6 +268,7 @@ func (row maskingPolicyDBRow) convert() *MaskingPolicy { Owner: row.Owner, Comment: row.Comment, ExemptOtherPolicies: exemptOtherPolicies, + OwnerRoleType: row.OwnerRoleType, } } diff --git a/pkg/sdk/password_policy.go b/pkg/sdk/password_policy.go index a77dad0bec..16af471c64 100644 --- a/pkg/sdk/password_policy.go +++ b/pkg/sdk/password_policy.go @@ -251,13 +251,14 @@ func (opts *ShowPasswordPolicyOptions) validate() error { // PasswordPolicy is a user-friendly result for a CREATE PASSWORD POLICY query. type PasswordPolicy struct { - CreatedOn time.Time - Name string - DatabaseName string - SchemaName string - Kind string - Owner string - Comment string + CreatedOn time.Time + Name string + DatabaseName string + SchemaName string + Kind string + Owner string + Comment string + OwnerRoleType string } func (v *PasswordPolicy) ID() SchemaObjectIdentifier { @@ -283,13 +284,14 @@ type passwordPolicyDBRow struct { func (row passwordPolicyDBRow) convert() PasswordPolicy { return PasswordPolicy{ - CreatedOn: row.CreatedOn, - Name: row.Name, - DatabaseName: row.DatabaseName, - SchemaName: row.SchemaName, - Kind: row.Kind, - Owner: row.Owner, - Comment: row.Comment, + CreatedOn: row.CreatedOn, + Name: row.Name, + DatabaseName: row.DatabaseName, + SchemaName: row.SchemaName, + Kind: row.Kind, + Owner: row.Owner, + Comment: row.Comment, + OwnerRoleType: row.OwnerRoleType, } } diff --git a/pkg/sdk/session_policies_def.go b/pkg/sdk/session_policies_def.go index 2053e48d22..65f8870cf4 100644 --- a/pkg/sdk/session_policies_def.go +++ b/pkg/sdk/session_policies_def.go @@ -73,7 +73,8 @@ var SessionPoliciesDef = g.NewInterface( Field("kind", "string"). Field("owner", "string"). Field("comment", "string"). - Field("options", "string"), + Field("options", "string"). + Field("owner_role_type", "string"), g.PlainStruct("SessionPolicy"). Field("CreatedOn", "string"). Field("Name", "string"). @@ -82,7 +83,8 @@ var SessionPoliciesDef = g.NewInterface( Field("Kind", "string"). Field("Owner", "string"). Field("Comment", "string"). - Field("Options", "string"), + Field("Options", "string"). + Field("OwnerRoleType", "string"), g.NewQueryStruct("ShowSessionPolicies"). Show(). SQL("SESSION POLICIES"), diff --git a/pkg/sdk/session_policies_gen.go b/pkg/sdk/session_policies_gen.go index 00c0480541..461a14b5e5 100644 --- a/pkg/sdk/session_policies_gen.go +++ b/pkg/sdk/session_policies_gen.go @@ -66,25 +66,27 @@ type ShowSessionPolicyOptions struct { } type showSessionPolicyDBRow struct { - CreatedOn string `db:"created_on"` - Name string `db:"name"` - DatabaseName string `db:"database_name"` - SchemaName string `db:"schema_name"` - Kind string `db:"kind"` - Owner string `db:"owner"` - Comment string `db:"comment"` - Options string `db:"options"` + CreatedOn string `db:"created_on"` + Name string `db:"name"` + DatabaseName string `db:"database_name"` + SchemaName string `db:"schema_name"` + Kind string `db:"kind"` + Owner string `db:"owner"` + Comment string `db:"comment"` + Options string `db:"options"` + OwnerRoleType string `db:"owner_role_type"` } type SessionPolicy struct { - CreatedOn string - Name string - DatabaseName string - SchemaName string - Kind string - Owner string - Comment string - Options string + CreatedOn string + Name string + DatabaseName string + SchemaName string + Kind string + Owner string + Comment string + Options string + OwnerRoleType string } // DescribeSessionPolicyOptions is based on https://docs.snowflake.com/en/sql-reference/sql/desc-session-policy. diff --git a/pkg/sdk/session_policies_impl_gen.go b/pkg/sdk/session_policies_impl_gen.go index 1d48dadff7..7d6284f0f3 100644 --- a/pkg/sdk/session_policies_impl_gen.go +++ b/pkg/sdk/session_policies_impl_gen.go @@ -110,14 +110,15 @@ func (r *ShowSessionPolicyRequest) toOpts() *ShowSessionPolicyOptions { func (r showSessionPolicyDBRow) convert() *SessionPolicy { return &SessionPolicy{ - CreatedOn: r.CreatedOn, - Name: r.Name, - DatabaseName: r.DatabaseName, - SchemaName: r.SchemaName, - Kind: r.Kind, - Owner: r.Owner, - Comment: r.Comment, - Options: r.Options, + CreatedOn: r.CreatedOn, + Name: r.Name, + DatabaseName: r.DatabaseName, + SchemaName: r.SchemaName, + Kind: r.Kind, + Owner: r.Owner, + Comment: r.Comment, + Options: r.Options, + OwnerRoleType: r.OwnerRoleType, } } diff --git a/pkg/sdk/tables.go b/pkg/sdk/tables.go index 5933e6d4fe..bba157ba8f 100644 --- a/pkg/sdk/tables.go +++ b/pkg/sdk/tables.go @@ -669,33 +669,35 @@ type describeTableColumnsOptions struct { } type TableColumnDetails struct { - Name string - Type DataType - Kind string - IsNullable bool - Default *string - IsPrimary bool - IsUnique bool - Check *bool - Expression *string - Comment *string - PolicyName *string - Collation *string + Name string + Type DataType + Kind string + IsNullable bool + Default *string + IsPrimary bool + IsUnique bool + Check *bool + Expression *string + Comment *string + PolicyName *string + Collation *string + SchemaEvolutionRecord *string } // tableColumnDetailsRow based on https://docs.snowflake.com/en/sql-reference/sql/desc-table type tableColumnDetailsRow struct { - Name string `db:"name"` - Type DataType `db:"type"` - Kind string `db:"kind"` - IsNullable string `db:"null?"` - Default sql.NullString `db:"default"` - IsPrimary string `db:"primary key"` - IsUnique string `db:"unique key"` - Check sql.NullString `db:"check"` - Expression sql.NullString `db:"expression"` - Comment sql.NullString `db:"comment"` - PolicyName sql.NullString `db:"policy name"` + Name string `db:"name"` + Type DataType `db:"type"` + Kind string `db:"kind"` + IsNullable string `db:"null?"` + Default sql.NullString `db:"default"` + IsPrimary string `db:"primary key"` + IsUnique string `db:"unique key"` + Check sql.NullString `db:"check"` + Expression sql.NullString `db:"expression"` + Comment sql.NullString `db:"comment"` + PolicyName sql.NullString `db:"policy name"` + SchemaEvolutionRecord sql.NullString `db:"schema evolution record"` } func (r tableColumnDetailsRow) convert() *TableColumnDetails { @@ -725,6 +727,9 @@ func (r tableColumnDetailsRow) convert() *TableColumnDetails { if r.PolicyName.Valid { details.PolicyName = String(r.PolicyName.String) } + if r.SchemaEvolutionRecord.Valid { + details.SchemaEvolutionRecord = String(r.SchemaEvolutionRecord.String) + } return details } diff --git a/pkg/sdk/tags.go b/pkg/sdk/tags.go index 1ef6f1e0a7..78f90e755a 100644 --- a/pkg/sdk/tags.go +++ b/pkg/sdk/tags.go @@ -70,7 +70,7 @@ type Tag struct { Owner string Comment string AllowedValues []string - OwnerRole string + OwnerRoleType string } func (v *Tag) ID() SchemaObjectIdentifier { @@ -90,13 +90,13 @@ type tagRow struct { func (tr tagRow) convert() *Tag { t := &Tag{ - CreatedOn: tr.CreatedOn, - Name: tr.Name, - DatabaseName: tr.DatabaseName, - SchemaName: tr.SchemaName, - Owner: tr.Owner, - Comment: tr.Comment, - OwnerRole: tr.OwnerRoleType, + CreatedOn: tr.CreatedOn, + Name: tr.Name, + DatabaseName: tr.DatabaseName, + SchemaName: tr.SchemaName, + Owner: tr.Owner, + Comment: tr.Comment, + OwnerRoleType: tr.OwnerRoleType, } if tr.AllowedValues.Valid { // remove brackets diff --git a/pkg/sdk/testint/alerts_integration_test.go b/pkg/sdk/testint/alerts_integration_test.go index b8be2f9bed..143a988e12 100644 --- a/pkg/sdk/testint/alerts_integration_test.go +++ b/pkg/sdk/testint/alerts_integration_test.go @@ -424,4 +424,14 @@ func TestInt_AlertsShowByID(t *testing.T) { require.NoError(t, err) require.Equal(t, id2, e2.ID()) }) + + t.Run("show by id: check fields", func(t *testing.T) { + name := random.AlphaN(4) + id1 := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, name) + createAlertHandle(t, id1) + + alert, err := client.Alerts.ShowByID(ctx, id1) + require.NoError(t, err) + assert.Equal(t, "ROLE", alert.OwnerRoleType) + }) } diff --git a/pkg/sdk/testint/databases_integration_test.go b/pkg/sdk/testint/databases_integration_test.go index 82a832de1d..e627c8c65b 100644 --- a/pkg/sdk/testint/databases_integration_test.go +++ b/pkg/sdk/testint/databases_integration_test.go @@ -329,6 +329,7 @@ func TestInt_DatabasesShow(t *testing.T) { } assert.Contains(t, databaseIDs, databaseTest.ID()) assert.Contains(t, databaseIDs, databaseTest2.ID()) + assert.Equal(t, "ROLE", databases[0].OwnerRoleType) }) t.Run("with terse", func(t *testing.T) { diff --git a/pkg/sdk/testint/dynamic_table_integration_test.go b/pkg/sdk/testint/dynamic_table_integration_test.go index e312fc0f41..92a7b27812 100644 --- a/pkg/sdk/testint/dynamic_table_integration_test.go +++ b/pkg/sdk/testint/dynamic_table_integration_test.go @@ -46,6 +46,7 @@ func TestInt_DynamicTableCreateAndDrop(t *testing.T) { require.Equal(t, name.Name(), dynamicTableById.Name) require.Equal(t, testWarehouse(t).ID().Name(), dynamicTableById.Warehouse) require.Equal(t, *targetLag.MaximumDuration, dynamicTableById.TargetLag) + assert.Equal(t, "ROLE", dynamicTableById.OwnerRoleType) }) t.Run("test complete with target lag", func(t *testing.T) { diff --git a/pkg/sdk/testint/masking_policy_integration_test.go b/pkg/sdk/testint/masking_policy_integration_test.go index 80d3710219..4338f016a1 100644 --- a/pkg/sdk/testint/masking_policy_integration_test.go +++ b/pkg/sdk/testint/masking_policy_integration_test.go @@ -418,6 +418,20 @@ func TestInt_MaskingPoliciesShowByID(t *testing.T) { t.Cleanup(cleanupMaskingPolicyHandle(t, id)) } + assertMaskingPolicy := func(t *testing.T, mp *sdk.MaskingPolicy, id sdk.SchemaObjectIdentifier) { + t.Helper() + assert.Equal(t, id, mp.ID()) + assert.NotEmpty(t, mp.CreatedOn) + assert.Equal(t, id.Name(), mp.Name) + assert.Equal(t, testDb(t).Name, mp.DatabaseName) + assert.Equal(t, testSchema(t).Name, mp.SchemaName) + assert.Equal(t, "MASKING_POLICY", mp.Kind) + assert.Equal(t, "ACCOUNTADMIN", mp.Owner) + assert.Equal(t, "", mp.Comment) + assert.Equal(t, false, mp.ExemptOtherPolicies) + assert.Equal(t, "ROLE", mp.OwnerRoleType) + } + t.Run("show by id - same name in different schemas", func(t *testing.T) { schema, schemaCleanup := testClientHelper().Schema.CreateSchema(t) t.Cleanup(schemaCleanup) @@ -437,4 +451,15 @@ func TestInt_MaskingPoliciesShowByID(t *testing.T) { require.NoError(t, err) require.Equal(t, id2, e2.ID()) }) + + t.Run("show by id: check fields", func(t *testing.T) { + name := random.AlphaN(4) + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, name) + + createMaskingPolicyHandle(t, id) + + mp, err := client.MaskingPolicies.ShowByID(ctx, id) + require.NoError(t, err) + assertMaskingPolicy(t, mp, id) + }) } diff --git a/pkg/sdk/testint/password_policy_integration_test.go b/pkg/sdk/testint/password_policy_integration_test.go index 1998fbb460..893688d96d 100644 --- a/pkg/sdk/testint/password_policy_integration_test.go +++ b/pkg/sdk/testint/password_policy_integration_test.go @@ -356,4 +356,15 @@ func TestInt_PasswordPoliciesShowByID(t *testing.T) { require.NoError(t, err) require.Equal(t, id2, e2.ID()) }) + + t.Run("show by id: check fields", func(t *testing.T) { + name := random.AlphaN(4) + id1 := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, name) + + createPasswordPolicyHandle(t, id1) + + sl, err := client.PasswordPolicies.ShowByID(ctx, id1) + require.NoError(t, err) + assert.Equal(t, "ROLE", sl.OwnerRoleType) + }) } diff --git a/pkg/sdk/testint/schemas_integration_test.go b/pkg/sdk/testint/schemas_integration_test.go index 10f03c2539..4e3004f569 100644 --- a/pkg/sdk/testint/schemas_integration_test.go +++ b/pkg/sdk/testint/schemas_integration_test.go @@ -333,6 +333,7 @@ func TestInt_SchemasShow(t *testing.T) { schemaNames[i] = s.Name } assert.Contains(t, schemaNames, schema.Name) + assert.Equal(t, "ROLE", schema.OwnerRoleType) }) } diff --git a/pkg/sdk/testint/session_policies_gen_integration_test.go b/pkg/sdk/testint/session_policies_gen_integration_test.go index a2db1bc29b..45cb386eb9 100644 --- a/pkg/sdk/testint/session_policies_gen_integration_test.go +++ b/pkg/sdk/testint/session_policies_gen_integration_test.go @@ -24,6 +24,7 @@ func TestInt_SessionPolicies(t *testing.T) { assert.Equal(t, expectedComment, sessionPolicy.Comment) assert.Equal(t, "SESSION_POLICY", sessionPolicy.Kind) assert.Equal(t, "", sessionPolicy.Options) + assert.Equal(t, "ROLE", sessionPolicy.OwnerRoleType) } assertSessionPolicyDescription := func( diff --git a/pkg/sdk/testint/stages_gen_integration_test.go b/pkg/sdk/testint/stages_gen_integration_test.go index 25bba24664..dd57dcf4b2 100644 --- a/pkg/sdk/testint/stages_gen_integration_test.go +++ b/pkg/sdk/testint/stages_gen_integration_test.go @@ -553,6 +553,7 @@ func TestInt_Stages(t *testing.T) { assert.Nil(t, stage.StorageIntegration) assert.Nil(t, stage.Endpoint) assert.True(t, stage.DirectoryEnabled) + assert.Equal(t, "ROLE", *stage.OwnerRoleType) }) } diff --git a/pkg/sdk/testint/tables_integration_test.go b/pkg/sdk/testint/tables_integration_test.go index 030e9412f6..523ebdd78a 100644 --- a/pkg/sdk/testint/tables_integration_test.go +++ b/pkg/sdk/testint/tables_integration_test.go @@ -61,6 +61,7 @@ func TestInt_Table(t *testing.T) { assert.Equal(t, "TABLE", table.Kind) assert.Equal(t, 0, table.Rows) assert.Equal(t, "ACCOUNTADMIN", table.Owner) + assert.Equal(t, "ROLE", table.OwnerRoleType) } assertTableTerse := func(t *testing.T, table *sdk.Table, id sdk.SchemaObjectIdentifier) { @@ -1032,4 +1033,42 @@ func TestInt_TablesShowByID(t *testing.T) { require.NoError(t, err) require.Equal(t, id2, e2.ID()) }) + + t.Run("show by id: check schema evolution record", func(t *testing.T) { + name := random.AlphaN(4) + id := sdk.NewSchemaObjectIdentifier(databaseTest.Name, schemaTest.Name, name) + + columns := []sdk.TableColumnRequest{ + *sdk.NewTableColumnRequest("c1", sdk.DataTypeNumber).WithDefaultValue(sdk.NewColumnDefaultValueRequest().WithIdentity(sdk.NewColumnIdentityRequest(1, 1))), + } + err := client.Tables.Create(ctx, sdk.NewCreateTableRequest(id, columns).WithEnableSchemaEvolution(sdk.Pointer(true))) + require.NoError(t, err) + t.Cleanup(cleanupTableHandle(id)) + + table, err := client.Tables.ShowByID(ctx, id) + require.NoError(t, err) + + err = client.Grants.GrantPrivilegesToAccountRole(ctx, + &sdk.AccountRoleGrantPrivileges{SchemaObjectPrivileges: []sdk.SchemaObjectPrivilege{sdk.SchemaObjectPrivilegeEvolveSchema}}, + &sdk.AccountRoleGrantOn{SchemaObject: &sdk.GrantOnSchemaObject{SchemaObject: &sdk.Object{ObjectType: sdk.ObjectTypeTable, Name: sdk.NewObjectIdentifierFromFullyQualifiedName(table.ID().FullyQualifiedName())}}}, + sdk.NewAccountObjectIdentifier("ACCOUNTADMIN"), + nil) + require.NoError(t, err) + + stage, stageCleanup := testClientHelper().Stage.CreateStageInSchema(t, sdk.NewDatabaseObjectIdentifier(testDb(t).Name, schemaTest.Name)) + t.Cleanup(stageCleanup) + + testClientHelper().Stage.PutOnStage(t, stage.ID(), "schema_evolution_record.json") + + testClientHelper().Stage.CopyIntoTableFromFile(t, table.ID(), stage.ID(), "schema_evolution_record.json") + + currentColumns := testClientHelper().Table.GetTableColumnsFor(t, table.ID()) + require.Len(t, currentColumns, 2) + assert.NotEmpty(t, currentColumns[1].SchemaEvolutionRecord) + + descColumns, err := client.Tables.DescribeColumns(ctx, sdk.NewDescribeTableColumnsRequest(id)) + require.NoError(t, err) + require.Len(t, descColumns, 2) + assert.NotEmpty(t, descColumns[1].SchemaEvolutionRecord) + }) } diff --git a/pkg/sdk/testint/tags_integration_test.go b/pkg/sdk/testint/tags_integration_test.go index feeda3fbd8..8c3704f9e1 100644 --- a/pkg/sdk/testint/tags_integration_test.go +++ b/pkg/sdk/testint/tags_integration_test.go @@ -28,6 +28,7 @@ func TestInt_Tags(t *testing.T) { assert.Equal(t, "ACCOUNTADMIN", tag.Owner) assert.Equal(t, expectedComment, tag.Comment) assert.Equal(t, expectedAllowedValues, tag.AllowedValues) + assert.Equal(t, "ROLE", tag.OwnerRoleType) } cleanupTagHandle := func(id sdk.SchemaObjectIdentifier) func() { return func() { diff --git a/pkg/sdk/testint/testdata/schema_evolution_record.json b/pkg/sdk/testint/testdata/schema_evolution_record.json new file mode 100644 index 0000000000..c7a8202565 --- /dev/null +++ b/pkg/sdk/testint/testdata/schema_evolution_record.json @@ -0,0 +1 @@ +{"c1": 1, "c2": "42"} diff --git a/pkg/sdk/testint/warehouses_integration_test.go b/pkg/sdk/testint/warehouses_integration_test.go index 035c45cc70..7279ffdae2 100644 --- a/pkg/sdk/testint/warehouses_integration_test.go +++ b/pkg/sdk/testint/warehouses_integration_test.go @@ -39,6 +39,7 @@ func TestInt_WarehousesShow(t *testing.T) { assert.Equal(t, 1, len(warehouses)) assert.Equal(t, warehouse.Name, warehouses[0].Name) assert.Equal(t, sdk.WarehouseSizeSmall, warehouses[0].Size) + assert.Equal(t, "ROLE", warehouses[0].OwnerRoleType) }) t.Run("when searching a non-existent password policy", func(t *testing.T) { diff --git a/pkg/sdk/warehouses.go b/pkg/sdk/warehouses.go index 56e071b907..61801e365b 100644 --- a/pkg/sdk/warehouses.go +++ b/pkg/sdk/warehouses.go @@ -378,40 +378,42 @@ type Warehouse struct { QueryAccelerationMaxScaleFactor int ResourceMonitor string ScalingPolicy ScalingPolicy + OwnerRoleType string } type warehouseDBRow struct { - Name string `db:"name"` - State string `db:"state"` - Type string `db:"type"` - Size string `db:"size"` - MinClusterCount int `db:"min_cluster_count"` - MaxClusterCount int `db:"max_cluster_count"` - StartedClusters int `db:"started_clusters"` - Running int `db:"running"` - Queued int `db:"queued"` - IsDefault string `db:"is_default"` - IsCurrent string `db:"is_current"` - AutoSuspend sql.NullInt64 `db:"auto_suspend"` - AutoResume bool `db:"auto_resume"` - Available string `db:"available"` - Provisioning string `db:"provisioning"` - Quiescing string `db:"quiescing"` - Other string `db:"other"` - CreatedOn time.Time `db:"created_on"` - ResumedOn time.Time `db:"resumed_on"` - UpdatedOn time.Time `db:"updated_on"` - Owner string `db:"owner"` - Comment string `db:"comment"` - EnableQueryAcceleration bool `db:"enable_query_acceleration"` - QueryAccelerationMaxScaleFactor int `db:"query_acceleration_max_scale_factor"` - ResourceMonitor string `db:"resource_monitor"` - Actives string `db:"actives"` - Pendings string `db:"pendings"` - Failed string `db:"failed"` - Suspended string `db:"suspended"` - UUID string `db:"uuid"` - ScalingPolicy string `db:"scaling_policy"` + Name string `db:"name"` + State string `db:"state"` + Type string `db:"type"` + Size string `db:"size"` + MinClusterCount int `db:"min_cluster_count"` + MaxClusterCount int `db:"max_cluster_count"` + StartedClusters int `db:"started_clusters"` + Running int `db:"running"` + Queued int `db:"queued"` + IsDefault string `db:"is_default"` + IsCurrent string `db:"is_current"` + AutoSuspend sql.NullInt64 `db:"auto_suspend"` + AutoResume bool `db:"auto_resume"` + Available string `db:"available"` + Provisioning string `db:"provisioning"` + Quiescing string `db:"quiescing"` + Other string `db:"other"` + CreatedOn time.Time `db:"created_on"` + ResumedOn time.Time `db:"resumed_on"` + UpdatedOn time.Time `db:"updated_on"` + Owner string `db:"owner"` + Comment string `db:"comment"` + EnableQueryAcceleration bool `db:"enable_query_acceleration"` + QueryAccelerationMaxScaleFactor int `db:"query_acceleration_max_scale_factor"` + ResourceMonitor string `db:"resource_monitor"` + Actives string `db:"actives"` + Pendings string `db:"pendings"` + Failed string `db:"failed"` + Suspended string `db:"suspended"` + UUID string `db:"uuid"` + ScalingPolicy string `db:"scaling_policy"` + OwnerRoleType sql.NullString `db:"owner_role_type"` } func (row warehouseDBRow) convert() *Warehouse { @@ -453,6 +455,9 @@ func (row warehouseDBRow) convert() *Warehouse { if row.AutoSuspend.Valid { wh.AutoSuspend = int(row.AutoSuspend.Int64) } + if row.OwnerRoleType.Valid { + wh.OwnerRoleType = row.OwnerRoleType.String + } return wh }