From 72f014fcf82abdd040b73b48679aa29f249426f3 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 1 Dec 2023 20:43:13 +0800 Subject: [PATCH 01/59] table prefix --- .../adminservice/AdminServiceApplication.java | 5 +- .../AdminServiceAutoConfiguration.java | 17 + .../apollo/assembly/ApolloApplication.java | 39 +- .../framework/apollo/biz/ApolloBizConfig.java | 7 + .../apollo/common/ApolloCommonConfig.java | 3 + .../common/jpa/TablePrefixNamingStrategy.java | 46 ++ .../common/jpa/TablePrefixProperties.java | 49 ++ .../ConfigServiceApplication.java | 5 +- .../apollo/portal/PortalApplication.java | 2 + .../portal/PortalApplicationConfig.java | 32 ++ .../component/RetryableRestTemplate.java | 5 +- .../spi/configuration/AuthConfiguration.java | 28 +- .../src/main/resources/application.yml | 7 - .../src/main/resources/portal.properties | 20 + scripts/sql/assembly/apolloconfigdb.sql | 498 ++++++++++++++++++ scripts/sql/assembly/apolloportaldb.sql | 434 +++++++++++++++ 16 files changed, 1153 insertions(+), 44 deletions(-) create mode 100644 apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixNamingStrategy.java create mode 100644 apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixProperties.java create mode 100644 apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalApplicationConfig.java create mode 100644 apollo-portal/src/main/resources/portal.properties create mode 100644 scripts/sql/assembly/apolloconfigdb.sql create mode 100644 scripts/sql/assembly/apolloportaldb.sql diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceApplication.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceApplication.java index 58c66dd4c3f..5dfa9c44057 100644 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceApplication.java +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceApplication.java @@ -21,6 +21,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @@ -29,7 +30,9 @@ @EnableAspectJAutoProxy @Configuration @PropertySource(value = {"classpath:adminservice.properties"}) -@EnableAutoConfiguration +@EnableAutoConfiguration(exclude = { + UserDetailsServiceAutoConfiguration.class, +}) @EnableTransactionManagement @ComponentScan(basePackageClasses = {ApolloCommonConfig.class, ApolloBizConfig.class, diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java index ab7e6bb41dd..18cc2d9c207 100644 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java @@ -21,6 +21,9 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration public class AdminServiceAutoConfiguration { @@ -45,4 +48,18 @@ public FilterRegistrationBean adminServiceAuth return filterRegistrationBean; } + + /** + * for apollo-assembly + */ + @Order(99) + @Configuration + static class AdminServiceSecurityConfigurer extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable(); + http.httpBasic(); + } + } } diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java index 3de97cfe142..9d6bebb2723 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java @@ -25,14 +25,15 @@ import org.slf4j.LoggerFactory; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.context.scope.refresh.RefreshScope; import org.springframework.context.ConfigurableApplicationContext; -@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, - HibernateJpaAutoConfiguration.class, ApolloAuditAutoConfiguration.class}) +@SpringBootApplication(exclude = { + HibernateJpaAutoConfiguration.class, + ApolloAuditAutoConfiguration.class, +}) public class ApolloApplication { private static final Logger logger = LoggerFactory.getLogger(ApolloApplication.class); @@ -43,37 +44,31 @@ public static void main(String[] args) throws Exception { */ ConfigurableApplicationContext commonContext = new SpringApplicationBuilder(ApolloApplication.class).web(WebApplicationType.NONE).run(args); - logger.info(commonContext.getId() + " isActive: " + commonContext.isActive()); + logger.info("commonContext [{}] isActive: {}", commonContext.getId(), commonContext.isActive()); /** * ConfigService */ - if (commonContext.getEnvironment().containsProperty("configservice")) { - ConfigurableApplicationContext configContext = - new SpringApplicationBuilder(ConfigServiceApplication.class).parent(commonContext) - .sources(RefreshScope.class).run(args); - logger.info(configContext.getId() + " isActive: " + configContext.isActive()); - } + ConfigurableApplicationContext configContext = + new SpringApplicationBuilder(ConfigServiceApplication.class).parent(commonContext) + .sources(RefreshScope.class).run(args); + logger.info("configContext [{}] isActive: {}", configContext.getId(), configContext.isActive()); /** * AdminService */ - if (commonContext.getEnvironment().containsProperty("adminservice")) { - ConfigurableApplicationContext adminContext = - new SpringApplicationBuilder(AdminServiceApplication.class).parent(commonContext) - .sources(RefreshScope.class).run(args); - logger.info(adminContext.getId() + " isActive: " + adminContext.isActive()); - } + ConfigurableApplicationContext adminContext = + new SpringApplicationBuilder(AdminServiceApplication.class).parent(commonContext) + .sources(RefreshScope.class).run(args); + logger.info("adminContext [{}] isActive: {}" , adminContext.getId(), adminContext.isActive()); /** * Portal */ - if (commonContext.getEnvironment().containsProperty("portal")) { - ConfigurableApplicationContext portalContext = - new SpringApplicationBuilder(PortalApplication.class).parent(commonContext) - .sources(RefreshScope.class).run(args); - logger.info(portalContext.getId() + " isActive: " + portalContext.isActive()); - } + ConfigurableApplicationContext portalContext = + new SpringApplicationBuilder(PortalApplication.class).parent(commonContext) + .sources(RefreshScope.class).run(args); + logger.info("portalContext [{}] isActive: {}", portalContext.getId(), portalContext.isActive()); } } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/ApolloBizConfig.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/ApolloBizConfig.java index b537d24362b..e23be4efb99 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/ApolloBizConfig.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/ApolloBizConfig.java @@ -16,7 +16,10 @@ */ package com.ctrip.framework.apollo.biz; +import com.ctrip.framework.apollo.common.jpa.TablePrefixNamingStrategy; +import com.ctrip.framework.apollo.common.jpa.TablePrefixProperties; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -25,4 +28,8 @@ @ComponentScan(basePackageClasses = ApolloBizConfig.class) public class ApolloBizConfig { + @Bean + public static TablePrefixNamingStrategy tablePrefixNamingStrategy(TablePrefixProperties tablePrefixProperties) { + return new TablePrefixNamingStrategy(tablePrefixProperties.getConfigPrefix()); + } } diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/ApolloCommonConfig.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/ApolloCommonConfig.java index b6f58b7311b..0f1a7f6fc2b 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/ApolloCommonConfig.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/ApolloCommonConfig.java @@ -16,7 +16,9 @@ */ package com.ctrip.framework.apollo.common; +import com.ctrip.framework.apollo.common.jpa.TablePrefixProperties; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -24,6 +26,7 @@ import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandler; import org.springframework.security.web.firewall.RequestRejectedHandler; +@EnableConfigurationProperties(TablePrefixProperties.class) @EnableAutoConfiguration @Configuration @ComponentScan(basePackageClasses = ApolloCommonConfig.class) diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixNamingStrategy.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixNamingStrategy.java new file mode 100644 index 00000000000..9368ffc969b --- /dev/null +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixNamingStrategy.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.common.jpa; + +import org.apache.commons.lang3.StringUtils; +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.naming.PhysicalNamingStrategy; +import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; + +public class TablePrefixNamingStrategy extends PhysicalNamingStrategyStandardImpl implements + PhysicalNamingStrategy { + + private static final long serialVersionUID = -5268252502936563292L; + + private final String tablePrefix; + + public TablePrefixNamingStrategy(String tablePrefix) { + this.tablePrefix = tablePrefix; + } + + @Override + public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) { + String tablePrefix = this.tablePrefix; + if (StringUtils.isEmpty(tablePrefix)) { + return name; + } + String entityTableName = name.getText(); + String physicalTableName = tablePrefix + entityTableName; + return new Identifier(physicalTableName, name.isQuoted()); + } +} diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixProperties.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixProperties.java new file mode 100644 index 00000000000..22215d5b144 --- /dev/null +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixProperties.java @@ -0,0 +1,49 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.common.jpa; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "spring.jpa.table-prefix") +public class TablePrefixProperties { + + /** + * The table name prefix of config module + */ + private String configPrefix = ""; + + /** + * The table name prefix of portal module + */ + private String portalPrefix = ""; + + public String getConfigPrefix() { + return this.configPrefix; + } + + public void setConfigPrefix(String configPrefix) { + this.configPrefix = configPrefix; + } + + public String getPortalPrefix() { + return this.portalPrefix; + } + + public void setPortalPrefix(String portalPrefix) { + this.portalPrefix = portalPrefix; + } +} diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceApplication.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceApplication.java index 10936fded7f..7010a336336 100644 --- a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceApplication.java +++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceApplication.java @@ -22,6 +22,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @@ -35,7 +36,9 @@ */ @EnableAspectJAutoProxy -@EnableAutoConfiguration +@EnableAutoConfiguration(exclude = { + UserDetailsServiceAutoConfiguration.class, +}) @Configuration @EnableTransactionManagement @PropertySource(value = {"classpath:configservice.properties"}) diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalApplication.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalApplication.java index 2a3afc5f593..ccf0207ff84 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalApplication.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalApplication.java @@ -24,10 +24,12 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.context.annotation.PropertySource; import org.springframework.transaction.annotation.EnableTransactionManagement; @EnableAspectJAutoProxy @Configuration +@PropertySource(value = {"classpath:portal.properties"}) @EnableAutoConfiguration(exclude = {LdapAutoConfiguration.class}) @EnableTransactionManagement @ComponentScan(basePackageClasses = {ApolloCommonConfig.class, diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalApplicationConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalApplicationConfig.java new file mode 100644 index 00000000000..f83e581a7e4 --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalApplicationConfig.java @@ -0,0 +1,32 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.portal; + +import com.ctrip.framework.apollo.common.jpa.TablePrefixNamingStrategy; +import com.ctrip.framework.apollo.common.jpa.TablePrefixProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class PortalApplicationConfig { + + @Bean + public static TablePrefixNamingStrategy tablePrefixNamingStrategy( + TablePrefixProperties tablePrefixProperties) { + return new TablePrefixNamingStrategy(tablePrefixProperties.getPortalPrefix()); + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/RetryableRestTemplate.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/RetryableRestTemplate.java index 922af859ca4..d5138ef882c 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/RetryableRestTemplate.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/component/RetryableRestTemplate.java @@ -32,6 +32,7 @@ import java.net.SocketTimeoutException; import java.util.List; import java.util.Map; +import java.util.Objects; import javax.annotation.PostConstruct; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.conn.HttpHostConnectException; @@ -300,7 +301,9 @@ private T doExecute(HttpMethod method, HttpHeaders extraHeaders, ServiceDTO } private String parseHost(ServiceDTO serviceAddress) { - return serviceAddress.getHomepageUrl() + "/"; + String homepageUrl = serviceAddress.getHomepageUrl(); + Objects.requireNonNull(homepageUrl, "homepageUrl"); + return homepageUrl.endsWith("/") ? homepageUrl : homepageUrl + "/"; } //post,delete,put请求在admin server处理超时情况下不重试 diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java index d7bfcd078fb..3bd7cd9b7f8 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java @@ -18,6 +18,7 @@ package com.ctrip.framework.apollo.portal.spi.configuration; import com.ctrip.framework.apollo.common.condition.ConditionalOnMissingProfile; +import com.ctrip.framework.apollo.common.jpa.TablePrefixProperties; import com.ctrip.framework.apollo.core.utils.StringUtils; import com.ctrip.framework.apollo.portal.repository.AuthorityRepository; import com.ctrip.framework.apollo.portal.repository.UserRepository; @@ -121,7 +122,8 @@ public static JdbcUserDetailsManager jdbcUserDetailsManager( PasswordEncoder passwordEncoder, AuthenticationManagerBuilder auth, DataSource datasource, - EntityManagerFactory entityManagerFactory) throws Exception { + EntityManagerFactory entityManagerFactory, + TablePrefixProperties tablePrefixProperties) throws Exception { char openQuote = '`'; char closeQuote = '`'; try { @@ -133,19 +135,20 @@ public static JdbcUserDetailsManager jdbcUserDetailsManager( } catch (Throwable ex) { //ignore } + String portalPrefix = tablePrefixProperties.getPortalPrefix(); JdbcUserDetailsManager jdbcUserDetailsManager = auth.jdbcAuthentication() .passwordEncoder(passwordEncoder).dataSource(datasource) - .usersByUsernameQuery(MessageFormat.format("SELECT {0}Username{1}, {0}Password{1}, {0}Enabled{1} FROM {0}Users{1} WHERE {0}Username{1} = ?", openQuote, closeQuote)) - .authoritiesByUsernameQuery(MessageFormat.format("SELECT {0}Username{1}, {0}Authority{1} FROM {0}Authorities{1} WHERE {0}Username{1} = ?", openQuote, closeQuote)) + .usersByUsernameQuery(MessageFormat.format("SELECT {0}Username{1}, {0}Password{1}, {0}Enabled{1} FROM {0}{2}Users{1} WHERE {0}Username{1} = ?", openQuote, closeQuote, portalPrefix)) + .authoritiesByUsernameQuery(MessageFormat.format("SELECT {0}Username{1}, {0}Authority{1} FROM {0}{2}Authorities{1} WHERE {0}Username{1} = ?", openQuote, closeQuote, portalPrefix)) .getUserDetailsService(); - jdbcUserDetailsManager.setUserExistsSql(MessageFormat.format("SELECT {0}Username{1} FROM {0}Users{1} WHERE {0}Username{1} = ?", openQuote, closeQuote)); - jdbcUserDetailsManager.setCreateUserSql(MessageFormat.format("INSERT INTO {0}Users{1} ({0}Username{1}, {0}Password{1}, {0}Enabled{1}) values (?,?,?)", openQuote, closeQuote)); - jdbcUserDetailsManager.setUpdateUserSql(MessageFormat.format("UPDATE {0}Users{1} SET {0}Password{1} = ?, {0}Enabled{1} = ? WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote)); - jdbcUserDetailsManager.setDeleteUserSql(MessageFormat.format("DELETE FROM {0}Users{1} WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote)); - jdbcUserDetailsManager.setCreateAuthoritySql(MessageFormat.format("INSERT INTO {0}Authorities{1} ({0}Username{1}, {0}Authority{1}) values (?,?)", openQuote, closeQuote)); - jdbcUserDetailsManager.setDeleteUserAuthoritiesSql(MessageFormat.format("DELETE FROM {0}Authorities{1} WHERE {0}Id{1} in (SELECT a.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}Authorities{1} WHERE {0}Username{1} = ?) AS a)", openQuote, closeQuote)); - jdbcUserDetailsManager.setChangePasswordSql(MessageFormat.format("UPDATE {0}Users{1} SET {0}Password{1} = ? WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote)); + jdbcUserDetailsManager.setUserExistsSql(MessageFormat.format("SELECT {0}Username{1} FROM {0}{2}Users{1} WHERE {0}Username{1} = ?", openQuote, closeQuote, portalPrefix)); + jdbcUserDetailsManager.setCreateUserSql(MessageFormat.format("INSERT INTO {0}{2}Users{1} ({0}Username{1}, {0}Password{1}, {0}Enabled{1}) values (?,?,?)", openQuote, closeQuote, portalPrefix)); + jdbcUserDetailsManager.setUpdateUserSql(MessageFormat.format("UPDATE {0}{2}Users{1} SET {0}Password{1} = ?, {0}Enabled{1} = ? WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}{2}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote, portalPrefix)); + jdbcUserDetailsManager.setDeleteUserSql(MessageFormat.format("DELETE FROM {0}{2}Users{1} WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}{2}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote, portalPrefix)); + jdbcUserDetailsManager.setCreateAuthoritySql(MessageFormat.format("INSERT INTO {0}{2}Authorities{1} ({0}Username{1}, {0}Authority{1}) values (?,?)", openQuote, closeQuote, portalPrefix)); + jdbcUserDetailsManager.setDeleteUserAuthoritiesSql(MessageFormat.format("DELETE FROM {0}{2}Authorities{1} WHERE {0}Id{1} in (SELECT a.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}{2}Authorities{1} WHERE {0}Username{1} = ?) AS a)", openQuote, closeQuote, portalPrefix)); + jdbcUserDetailsManager.setChangePasswordSql(MessageFormat.format("UPDATE {0}{2}Users{1} SET {0}Password{1} = ? WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}{2}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote, portalPrefix)); return jdbcUserDetailsManager; } @@ -364,9 +367,10 @@ public JdbcUserDetailsManager jdbcUserDetailsManager( PasswordEncoder passwordEncoder, AuthenticationManagerBuilder auth, DataSource datasource, - EntityManagerFactory entityManagerFactory) throws Exception { + EntityManagerFactory entityManagerFactory, + TablePrefixProperties tablePrefixProperties) throws Exception { return SpringSecurityAuthAutoConfiguration - .jdbcUserDetailsManager(passwordEncoder, auth, datasource, entityManagerFactory); + .jdbcUserDetailsManager(passwordEncoder, auth, datasource, entityManagerFactory, tablePrefixProperties); } @Bean diff --git a/apollo-portal/src/main/resources/application.yml b/apollo-portal/src/main/resources/application.yml index 475980fb37c..133506bdb97 100644 --- a/apollo-portal/src/main/resources/application.yml +++ b/apollo-portal/src/main/resources/application.yml @@ -14,8 +14,6 @@ # limitations under the License. # spring: - application: - name: apollo-portal profiles: active: ${apollo_profile} jpa: @@ -33,7 +31,6 @@ spring: max-file-size: 200MB # import data configs max-request-size: 200MB server: - port: 8070 compression: enabled: true tomcat: @@ -44,10 +41,6 @@ server: # prevent csrf same-site: Lax -logging: - file: - name: /opt/logs/apollo-portal.log - management: health: status: diff --git a/apollo-portal/src/main/resources/portal.properties b/apollo-portal/src/main/resources/portal.properties new file mode 100644 index 00000000000..cf9847391ec --- /dev/null +++ b/apollo-portal/src/main/resources/portal.properties @@ -0,0 +1,20 @@ +# +# Copyright 2023 Apollo Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#Used for apollo-assembly +spring.application.name= apollo-portal +server.port= 8070 +logging.file.name= /opt/logs/apollo-portal.log +spring.jmx.default-domain = apollo-portal diff --git a/scripts/sql/assembly/apolloconfigdb.sql b/scripts/sql/assembly/apolloconfigdb.sql new file mode 100644 index 00000000000..be387ebd752 --- /dev/null +++ b/scripts/sql/assembly/apolloconfigdb.sql @@ -0,0 +1,498 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +# Create Database +# ------------------------------------------------------------ +CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; + +Use ApolloAssemblyDB; + +# Dump of table app +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_App`; + +CREATE TABLE `C_0_App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +# Dump of table appnamespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AppNamespace`; + +CREATE TABLE `C_0_AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +# Dump of table audit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Audit`; + +CREATE TABLE `C_0_Audit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID', + `OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表'; + + + +# Dump of table cluster +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Cluster`; + +CREATE TABLE `C_0_Cluster` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id', + `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `IX_ParentClusterId` (`ParentClusterId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群'; + + + +# Dump of table commit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Commit`; + +CREATE TABLE `C_0_Commit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `ChangeSets` longtext NOT NULL COMMENT '修改变更集', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `AppId` (`AppId`), + KEY `ClusterName` (`ClusterName`(191)), + KEY `NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表'; + +# Dump of table grayreleaserule +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_GrayReleaseRule`; + +CREATE TABLE `C_0_GrayReleaseRule` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name', + `Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release', + `BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表'; + + +# Dump of table instance +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Instance`; + +CREATE TABLE `C_0_Instance` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name', + `Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`), + KEY `IX_IP` (`Ip`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例'; + + + +# Dump of table instanceconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_InstanceConfig`; + +CREATE TABLE `C_0_InstanceConfig` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id', + `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id', + `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name', + `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), + KEY `IX_ReleaseKey` (`ReleaseKey`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息'; + + + +# Dump of table item +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Item`; + +CREATE TABLE `C_0_Item` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '配置项类型,0: String,1: Number,2: Boolean,3: JSON', + `Value` longtext NOT NULL COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_GroupId` (`NamespaceId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目'; + + + +# Dump of table namespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Namespace`; + +CREATE TABLE `C_0_Namespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间'; + + + +# Dump of table namespacelock +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_NamespaceLock`; + +CREATE TABLE `C_0_NamespaceLock` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁'; + + + +# Dump of table release +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Release`; + +CREATE TABLE `C_0_Release` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字', + `Comment` varchar(256) DEFAULT NULL COMMENT '发布说明', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Configurations` longtext NOT NULL COMMENT '发布配置', + `IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`), + KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布'; + + +# Dump of table releasehistory +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ReleaseHistory`; + +CREATE TABLE `C_0_ReleaseHistory` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id', + `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId', + `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度', + `OperationContext` longtext NOT NULL COMMENT '发布上下文信息', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), + KEY `IX_ReleaseId` (`ReleaseId`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PreviousReleaseId` (`PreviousReleaseId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史'; + + +# Dump of table releasemessage +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ReleaseMessage`; + +CREATE TABLE `C_0_ReleaseMessage` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Message` (`Message`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息'; + + + +# Dump of table serverconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ServerConfig`; + +CREATE TABLE `C_0_ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + +# Dump of table accesskey +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AccessKey`; + +CREATE TABLE `C_0_AccessKey` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret', + `IsEnabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: enabled, 0: disabled', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; + + +# Dump of table serviceregistry +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ServiceRegistry`; + +CREATE TABLE `C_0_ServiceRegistry` ( + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', + `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), + INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; + + +# Config +# ------------------------------------------------------------ +INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +VALUES + ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), + ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), + ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'), + ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), + ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); + + +DROP TABLE IF EXISTS `C_0_AuditLog`; + +CREATE TABLE `C_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + + +DROP TABLE IF EXISTS `C_0_AuditLogDataInfluence`; + +CREATE TABLE `C_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/scripts/sql/assembly/apolloportaldb.sql b/scripts/sql/assembly/apolloportaldb.sql new file mode 100644 index 00000000000..dde438fa88e --- /dev/null +++ b/scripts/sql/assembly/apolloportaldb.sql @@ -0,0 +1,434 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +# Create Database +# ------------------------------------------------------------ +CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; + +Use ApolloAssemblyDB; + +# Dump of table app +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_App`; + +CREATE TABLE `P_0_App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +# Dump of table appnamespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_AppNamespace`; + +CREATE TABLE `P_0_AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +# Dump of table consumer +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Consumer`; + +CREATE TABLE `P_0_Consumer` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者'; + + + +# Dump of table consumeraudit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerAudit`; + +CREATE TABLE `P_0_ConsumerAudit` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri', + `Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_ConsumerId` (`ConsumerId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表'; + + + +# Dump of table consumerrole +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerRole`; + +CREATE TABLE `P_0_ConsumerRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表'; + + + +# Dump of table consumertoken +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerToken`; + +CREATE TABLE `P_0_ConsumerToken` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId', + `Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token', + `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Token_DeletedAt` (`Token`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表'; + +# Dump of table favorite +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Favorite`; + +CREATE TABLE `P_0_Favorite` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`), + KEY `AppId` (`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表'; + +# Dump of table permission +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Permission`; + +CREATE TABLE `P_0_Permission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型', + `TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表'; + + + +# Dump of table role +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Role`; + +CREATE TABLE `P_0_Role` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; + + + +# Dump of table rolepermission +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_RolePermission`; + +CREATE TABLE `P_0_RolePermission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PermissionId` (`PermissionId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表'; + + + +# Dump of table serverconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ServerConfig`; + +CREATE TABLE `P_0_ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_DeletedAt` (`Key`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + + + +# Dump of table userrole +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_UserRole`; + +CREATE TABLE `P_0_UserRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表'; + +# Dump of table Users +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Users`; + +CREATE TABLE `P_0_Users` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户', + `Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码', + `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称', + `Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址', + `Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Username` (`Username`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + + +# Dump of table Authorities +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Authorities`; + +CREATE TABLE `P_0_Authorities` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL, + `Authority` varchar(50) NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + + +# Config +# ------------------------------------------------------------ +INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) +VALUES + ('apollo.portal.envs', 'dev', '可支持的环境列表'), + ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), + ('superAdmin', 'apollo', 'Portal超级管理员'), + ('api.readTimeout', '10000', 'http接口read timeout'), + ('consumer.token.salt', 'someSalt', 'consumer token salt'), + ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'), + ('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔'), + ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); + + +INSERT INTO `P_0_Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) +VALUES + ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); + +INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); + +-- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) +CREATE TABLE `P_0_SPRING_SESSION` ( + PRIMARY_ID CHAR(36) NOT NULL, + SESSION_ID CHAR(36) NOT NULL, + CREATION_TIME BIGINT NOT NULL, + LAST_ACCESS_TIME BIGINT NOT NULL, + MAX_INACTIVE_INTERVAL INT NOT NULL, + EXPIRY_TIME BIGINT NOT NULL, + PRINCIPAL_NAME VARCHAR(100), + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON `P_0_SPRING_SESSION` (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON `P_0_SPRING_SESSION` (EXPIRY_TIME); +CREATE INDEX SPRING_SESSION_IX3 ON `P_0_SPRING_SESSION` (PRINCIPAL_NAME); + +DROP TABLE IF EXISTS `P_0_SPRING_SESSION_ATTRIBUTES`; +CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( + SESSION_PRIMARY_ID CHAR(36) NOT NULL, + ATTRIBUTE_NAME VARCHAR(200) NOT NULL, + ATTRIBUTE_BYTES BLOB NOT NULL, + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES `P_0_SPRING_SESSION`(PRIMARY_ID) ON DELETE CASCADE +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + + +DROP TABLE IF EXISTS `P_0_AuditLog`; + +CREATE TABLE `P_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + + +DROP TABLE IF EXISTS `P_0_AuditLogDataInfluence`; + +CREATE TABLE `P_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; From b0223c262859998ce32ab54e9ba91547e809009b Mon Sep 17 00:00:00 2001 From: vdisk Date: Sat, 2 Dec 2023 00:44:32 +0800 Subject: [PATCH 02/59] assembly config v0.1 --- .../resources/application-github.properties | 37 ++ .../main/resources/jpa/apolloconfigdb.h2.sql | 492 ++++++++++++++++++ .../main/resources/jpa/apolloportaldb.h2.sql | 428 +++++++++++++++ .../src/test/resources/application.properties | 17 +- 4 files changed, 970 insertions(+), 4 deletions(-) create mode 100644 apollo-assembly/src/main/resources/application-github.properties create mode 100644 apollo-assembly/src/main/resources/jpa/apolloconfigdb.h2.sql create mode 100644 apollo-assembly/src/main/resources/jpa/apolloportaldb.h2.sql diff --git a/apollo-assembly/src/main/resources/application-github.properties b/apollo-assembly/src/main/resources/application-github.properties new file mode 100644 index 00000000000..78a7b92074d --- /dev/null +++ b/apollo-assembly/src/main/resources/application-github.properties @@ -0,0 +1,37 @@ +# +# Copyright 2023 Apollo Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# DataSource +spring.datasource.url=${spring_datasource_url} +spring.datasource.username=${spring_datasource_username} +spring.datasource.password=${spring_datasource_password} + +# Default datasource +spring_datasource_url=jdbc:h2:mem:~/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE + +# Table prefix +spring.jpa.hibernate.naming.physical-strategy=com.ctrip.framework.apollo.common.jpa.TablePrefixNamingStrategy +spring.jpa.table-prefix.config-prefix=C_0_ +spring.jpa.table-prefix.portal-prefix=P_0_ + +# H2 datasource +spring.sql.init.schema-locations=classpath:jpa/apolloconfigdb.h2.sql, classpath:jpa/apolloportaldb.h2.sql +spring.jpa.properties.hibernate.show_sql=false +spring.jpa.properties.hibernate.metadata_builder_contributor=com.ctrip.framework.apollo.common.jpa.SqlFunctionsMetadataBuilderContributor +spring.h2.console.enabled=true +spring.h2.console.settings.web-allow-others=true + +# Default env +apollo.portal.env=local \ No newline at end of file diff --git a/apollo-assembly/src/main/resources/jpa/apolloconfigdb.h2.sql b/apollo-assembly/src/main/resources/jpa/apolloconfigdb.h2.sql new file mode 100644 index 00000000000..cffad7d95fa --- /dev/null +++ b/apollo-assembly/src/main/resources/jpa/apolloconfigdb.h2.sql @@ -0,0 +1,492 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +# Dump of table app +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_App`; + +CREATE TABLE `C_0_App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +# Dump of table appnamespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AppNamespace`; + +CREATE TABLE `C_0_AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +# Dump of table audit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Audit`; + +CREATE TABLE `C_0_Audit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID', + `OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表'; + + + +# Dump of table cluster +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Cluster`; + +CREATE TABLE `C_0_Cluster` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id', + `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `IX_ParentClusterId` (`ParentClusterId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群'; + + + +# Dump of table commit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Commit`; + +CREATE TABLE `C_0_Commit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `ChangeSets` longtext NOT NULL COMMENT '修改变更集', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `AppId` (`AppId`), + KEY `ClusterName` (`ClusterName`(191)), + KEY `NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表'; + +# Dump of table grayreleaserule +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_GrayReleaseRule`; + +CREATE TABLE `C_0_GrayReleaseRule` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name', + `Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release', + `BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表'; + + +# Dump of table instance +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Instance`; + +CREATE TABLE `C_0_Instance` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name', + `Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`), + KEY `IX_IP` (`Ip`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例'; + + + +# Dump of table instanceconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_InstanceConfig`; + +CREATE TABLE `C_0_InstanceConfig` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id', + `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id', + `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name', + `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), + KEY `IX_ReleaseKey` (`ReleaseKey`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息'; + + + +# Dump of table item +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Item`; + +CREATE TABLE `C_0_Item` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '配置项类型,0: String,1: Number,2: Boolean,3: JSON', + `Value` longtext NOT NULL COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_GroupId` (`NamespaceId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目'; + + + +# Dump of table namespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Namespace`; + +CREATE TABLE `C_0_Namespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间'; + + + +# Dump of table namespacelock +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_NamespaceLock`; + +CREATE TABLE `C_0_NamespaceLock` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁'; + + + +# Dump of table release +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Release`; + +CREATE TABLE `C_0_Release` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字', + `Comment` varchar(256) DEFAULT NULL COMMENT '发布说明', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Configurations` longtext NOT NULL COMMENT '发布配置', + `IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`), + KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布'; + + +# Dump of table releasehistory +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ReleaseHistory`; + +CREATE TABLE `C_0_ReleaseHistory` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id', + `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId', + `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度', + `OperationContext` longtext NOT NULL COMMENT '发布上下文信息', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), + KEY `IX_ReleaseId` (`ReleaseId`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PreviousReleaseId` (`PreviousReleaseId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史'; + + +# Dump of table releasemessage +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ReleaseMessage`; + +CREATE TABLE `C_0_ReleaseMessage` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Message` (`Message`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息'; + + + +# Dump of table serverconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ServerConfig`; + +CREATE TABLE `C_0_ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + +# Dump of table accesskey +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AccessKey`; + +CREATE TABLE `C_0_AccessKey` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret', + `IsEnabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: enabled, 0: disabled', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; + + +# Dump of table serviceregistry +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ServiceRegistry`; + +CREATE TABLE `C_0_ServiceRegistry` ( + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', + `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), + INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; + + +# Config +# ------------------------------------------------------------ +INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +VALUES + ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), + ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), + ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'), + ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), + ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); + + +DROP TABLE IF EXISTS `C_0_AuditLog`; + +CREATE TABLE `C_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + + +DROP TABLE IF EXISTS `C_0_AuditLogDataInfluence`; + +CREATE TABLE `C_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/apollo-assembly/src/main/resources/jpa/apolloportaldb.h2.sql b/apollo-assembly/src/main/resources/jpa/apolloportaldb.h2.sql new file mode 100644 index 00000000000..640c6df681e --- /dev/null +++ b/apollo-assembly/src/main/resources/jpa/apolloportaldb.h2.sql @@ -0,0 +1,428 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +# Dump of table app +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_App`; + +CREATE TABLE `P_0_App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +# Dump of table appnamespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_AppNamespace`; + +CREATE TABLE `P_0_AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +# Dump of table consumer +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Consumer`; + +CREATE TABLE `P_0_Consumer` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者'; + + + +# Dump of table consumeraudit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerAudit`; + +CREATE TABLE `P_0_ConsumerAudit` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri', + `Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_ConsumerId` (`ConsumerId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表'; + + + +# Dump of table consumerrole +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerRole`; + +CREATE TABLE `P_0_ConsumerRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表'; + + + +# Dump of table consumertoken +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerToken`; + +CREATE TABLE `P_0_ConsumerToken` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId', + `Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token', + `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Token_DeletedAt` (`Token`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表'; + +# Dump of table favorite +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Favorite`; + +CREATE TABLE `P_0_Favorite` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`), + KEY `AppId` (`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表'; + +# Dump of table permission +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Permission`; + +CREATE TABLE `P_0_Permission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型', + `TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表'; + + + +# Dump of table role +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Role`; + +CREATE TABLE `P_0_Role` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; + + + +# Dump of table rolepermission +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_RolePermission`; + +CREATE TABLE `P_0_RolePermission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PermissionId` (`PermissionId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表'; + + + +# Dump of table serverconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ServerConfig`; + +CREATE TABLE `P_0_ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_DeletedAt` (`Key`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + + + +# Dump of table userrole +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_UserRole`; + +CREATE TABLE `P_0_UserRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表'; + +# Dump of table Users +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Users`; + +CREATE TABLE `P_0_Users` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户', + `Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码', + `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称', + `Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址', + `Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Username` (`Username`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + + +# Dump of table Authorities +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Authorities`; + +CREATE TABLE `P_0_Authorities` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL, + `Authority` varchar(50) NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + + +# Config +# ------------------------------------------------------------ +INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) +VALUES + ('apollo.portal.envs', 'dev', '可支持的环境列表'), + ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), + ('superAdmin', 'apollo', 'Portal超级管理员'), + ('api.readTimeout', '10000', 'http接口read timeout'), + ('consumer.token.salt', 'someSalt', 'consumer token salt'), + ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'), + ('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔'), + ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); + + +INSERT INTO `P_0_Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) +VALUES + ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); + +INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); + +-- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) +CREATE TABLE `P_0_SPRING_SESSION` ( + PRIMARY_ID CHAR(36) NOT NULL, + SESSION_ID CHAR(36) NOT NULL, + CREATION_TIME BIGINT NOT NULL, + LAST_ACCESS_TIME BIGINT NOT NULL, + MAX_INACTIVE_INTERVAL INT NOT NULL, + EXPIRY_TIME BIGINT NOT NULL, + PRINCIPAL_NAME VARCHAR(100), + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON `P_0_SPRING_SESSION` (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON `P_0_SPRING_SESSION` (EXPIRY_TIME); +CREATE INDEX SPRING_SESSION_IX3 ON `P_0_SPRING_SESSION` (PRINCIPAL_NAME); + +DROP TABLE IF EXISTS `P_0_SPRING_SESSION_ATTRIBUTES`; +CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( + SESSION_PRIMARY_ID CHAR(36) NOT NULL, + ATTRIBUTE_NAME VARCHAR(200) NOT NULL, + ATTRIBUTE_BYTES BLOB NOT NULL, + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES `P_0_SPRING_SESSION`(PRIMARY_ID) ON DELETE CASCADE +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + + +DROP TABLE IF EXISTS `P_0_AuditLog`; + +CREATE TABLE `P_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + + +DROP TABLE IF EXISTS `P_0_AuditLogDataInfluence`; + +CREATE TABLE `P_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/apollo-assembly/src/test/resources/application.properties b/apollo-assembly/src/test/resources/application.properties index 538c11dcfd7..3ac5d1ac172 100644 --- a/apollo-assembly/src/test/resources/application.properties +++ b/apollo-assembly/src/test/resources/application.properties @@ -13,10 +13,19 @@ # See the License for the specific language governing permissions and # limitations under the License. # -spring.datasource.url = jdbc:h2:mem:~/apolloconfigdb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1 -spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl +spring.datasource.url = jdbc:h2:mem:~/apolloconfigdb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE + +# Table prefix +spring.jpa.hibernate.naming.physical-strategy=com.ctrip.framework.apollo.common.jpa.TablePrefixNamingStrategy +spring.jpa.table-prefix.config-prefix=C_0_ +spring.jpa.table-prefix.portal-prefix=P_0_ + +# H2 datasource +spring.sql.init.schema-locations=classpath:jpa/apolloconfigdb.h2.sql, classpath:jpa/apolloportaldb.h2.sql spring.jpa.properties.hibernate.show_sql=false spring.jpa.properties.hibernate.metadata_builder_contributor=com.ctrip.framework.apollo.common.jpa.SqlFunctionsMetadataBuilderContributor -spring.h2.console.enabled = true +spring.h2.console.enabled=true spring.h2.console.settings.web-allow-others=true -apollo.portal.env= local + +# Default env +apollo.portal.env=local From b518cc696c75c29d39d0b9d5b07adb352c10845b Mon Sep 17 00:00:00 2001 From: vdisk Date: Sat, 2 Dec 2023 01:15:40 +0800 Subject: [PATCH 03/59] assembly config v0.2 --- .../resources/application-github.properties | 2 +- .../main/resources/jpa/apolloconfigdb.h2.sql | 670 +++++++++--------- .../main/resources/jpa/apolloportaldb.h2.sql | 518 +++++++------- .../src/test/resources/application.properties | 2 +- 4 files changed, 602 insertions(+), 590 deletions(-) diff --git a/apollo-assembly/src/main/resources/application-github.properties b/apollo-assembly/src/main/resources/application-github.properties index 78a7b92074d..79295bcf657 100644 --- a/apollo-assembly/src/main/resources/application-github.properties +++ b/apollo-assembly/src/main/resources/application-github.properties @@ -34,4 +34,4 @@ spring.h2.console.enabled=true spring.h2.console.settings.web-allow-others=true # Default env -apollo.portal.env=local \ No newline at end of file +apollo.portal.envs=local \ No newline at end of file diff --git a/apollo-assembly/src/main/resources/jpa/apolloconfigdb.h2.sql b/apollo-assembly/src/main/resources/jpa/apolloconfigdb.h2.sql index cffad7d95fa..6b829014e50 100644 --- a/apollo-assembly/src/main/resources/jpa/apolloconfigdb.h2.sql +++ b/apollo-assembly/src/main/resources/jpa/apolloconfigdb.h2.sql @@ -21,411 +21,417 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -# Dump of table app -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_App`; + + + + + + + + + CREATE TABLE `C_0_App` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', - `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', - `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', - `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', - `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `AppId` varchar(64) NOT NULL DEFAULT 'default' , + `Name` varchar(500) NOT NULL DEFAULT 'default' , + `OrgId` varchar(32) NOT NULL DEFAULT 'default' , + `OrgName` varchar(64) NOT NULL DEFAULT 'default' , + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' , + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_Name` (`Name`(191)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + UNIQUE KEY (`AppId`,`DeletedAt`), + KEY (`DataChange_LastTime`), + KEY (`Name`) +) ; + + + -# Dump of table appnamespace -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_AppNamespace`; CREATE TABLE `C_0_AppNamespace` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', - `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', - `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', - `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', - `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) NOT NULL AUTO_INCREMENT , + `Name` varchar(32) NOT NULL DEFAULT '' , + `AppId` varchar(64) NOT NULL DEFAULT '' , + `Format` varchar(32) NOT NULL DEFAULT 'properties' , + `IsPublic` boolean NOT NULL DEFAULT FALSE , + `Comment` varchar(64) NOT NULL DEFAULT '' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), - KEY `Name_AppId` (`Name`,`AppId`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + UNIQUE KEY (`AppId`,`Name`,`DeletedAt`), + KEY (`Name`,`AppId`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table audit -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_Audit`; CREATE TABLE `C_0_Audit` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', - `EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID', - `OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', - `Comment` varchar(500) DEFAULT NULL COMMENT '备注', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `EntityName` varchar(50) NOT NULL DEFAULT 'default' , + `EntityId` int(10) unsigned DEFAULT NULL , + `OpName` varchar(50) NOT NULL DEFAULT 'default' , + `Comment` varchar(500) DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表'; + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table cluster -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_Cluster`; CREATE TABLE `C_0_Cluster` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', - `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id', - `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `Name` varchar(32) NOT NULL DEFAULT '' , + `AppId` varchar(64) NOT NULL DEFAULT '' , + `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), - KEY `IX_ParentClusterId` (`ParentClusterId`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群'; + UNIQUE KEY (`AppId`,`Name`,`DeletedAt`), + KEY (`ParentClusterId`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table commit -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_Commit`; CREATE TABLE `C_0_Commit` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `ChangeSets` longtext NOT NULL COMMENT '修改变更集', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', - `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', - `Comment` varchar(500) DEFAULT NULL COMMENT '备注', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `ChangeSets` longtext NOT NULL , + `AppId` varchar(64) NOT NULL DEFAULT 'default' , + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' , + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' , + `Comment` varchar(500) DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `AppId` (`AppId`), - KEY `ClusterName` (`ClusterName`(191)), - KEY `NamespaceName` (`NamespaceName`(191)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表'; + KEY (`DataChange_LastTime`), + KEY (`AppId`), + KEY (`ClusterName`), + KEY (`NamespaceName`) +) ; + + + -# Dump of table grayreleaserule -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_GrayReleaseRule`; CREATE TABLE `C_0_GrayReleaseRule` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', - `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', - `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name', - `Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则', - `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release', - `BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `AppId` varchar(64) NOT NULL DEFAULT 'default' , + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' , + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' , + `BranchName` varchar(32) NOT NULL DEFAULT 'default' , + `Rules` varchar(16000) DEFAULT '[]' , + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' , + `BranchStatus` tinyint(2) DEFAULT '1' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表'; + KEY (`DataChange_LastTime`), + KEY (`AppId`,`ClusterName`,`NamespaceName`) +) ; + + + -# Dump of table instance -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_Instance`; CREATE TABLE `C_0_Instance` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', - `DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name', - `Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `AppId` varchar(64) NOT NULL DEFAULT 'default' , + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' , + `DataCenter` varchar(64) NOT NULL DEFAULT 'default' , + `Ip` varchar(32) NOT NULL DEFAULT '' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`), - KEY `IX_IP` (`Ip`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例'; + UNIQUE KEY (`AppId`,`ClusterName`,`Ip`,`DataCenter`), + KEY (`Ip`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table instanceconfig -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_InstanceConfig`; CREATE TABLE `C_0_InstanceConfig` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id', - `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id', - `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name', - `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name', - `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', - `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `InstanceId` int(11) unsigned DEFAULT NULL , + `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' , + `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' , + `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' , + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' , + `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), - KEY `IX_ReleaseKey` (`ReleaseKey`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息'; + UNIQUE KEY (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), + KEY (`ReleaseKey`), + KEY (`DataChange_LastTime`), + KEY (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) +) ; + + + -# Dump of table item -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_Item`; CREATE TABLE `C_0_Item` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', - `Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key', - `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '配置项类型,0: String,1: Number,2: Boolean,3: JSON', - `Value` longtext NOT NULL COMMENT '配置项值', - `Comment` varchar(1024) DEFAULT '' COMMENT '注释', - `LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' , + `Key` varchar(128) NOT NULL DEFAULT 'default' , + `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' , + `Value` longtext NOT NULL , + `Comment` varchar(1024) DEFAULT '' , + `LineNum` int(10) unsigned DEFAULT '0' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY `IX_GroupId` (`NamespaceId`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目'; + KEY (`NamespaceId`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table namespace -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_Namespace`; CREATE TABLE `C_0_Namespace` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', - `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `AppId` varchar(64) NOT NULL DEFAULT 'default' , + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' , + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_NamespaceName` (`NamespaceName`(191)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间'; + UNIQUE KEY (`AppId`,`ClusterName`,`NamespaceName`,`DeletedAt`), + KEY (`DataChange_LastTime`), + KEY (`NamespaceName`) +) ; + + + -# Dump of table namespacelock -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_NamespaceLock`; CREATE TABLE `C_0_NamespaceLock` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - `IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `IsDeleted` boolean DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁'; + UNIQUE KEY (`NamespaceId`,`DeletedAt`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table release -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_Release`; CREATE TABLE `C_0_Release` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', - `Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字', - `Comment` varchar(256) DEFAULT NULL COMMENT '发布说明', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', - `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', - `Configurations` longtext NOT NULL COMMENT '发布配置', - `IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' , + `Name` varchar(64) NOT NULL DEFAULT 'default' , + `Comment` varchar(256) DEFAULT NULL , + `AppId` varchar(64) NOT NULL DEFAULT 'default' , + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' , + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' , + `Configurations` longtext NOT NULL , + `IsAbandoned` boolean NOT NULL DEFAULT FALSE , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`), - KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布'; + UNIQUE KEY (`ReleaseKey`,`DeletedAt`), + KEY (`AppId`,`ClusterName`,`NamespaceName`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table releasehistory -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_ReleaseHistory`; CREATE TABLE `C_0_ReleaseHistory` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', - `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', - `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名', - `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id', - `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId', - `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度', - `OperationContext` longtext NOT NULL COMMENT '发布上下文信息', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `AppId` varchar(64) NOT NULL DEFAULT 'default' , + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' , + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' , + `BranchName` varchar(32) NOT NULL DEFAULT 'default' , + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' , + `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' , + `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' , + `OperationContext` longtext NOT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), - KEY `IX_ReleaseId` (`ReleaseId`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_PreviousReleaseId` (`PreviousReleaseId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史'; + KEY (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), + KEY (`ReleaseId`), + KEY (`DataChange_LastTime`), + KEY (`PreviousReleaseId`) +) ; + + + -# Dump of table releasemessage -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_ReleaseMessage`; CREATE TABLE `C_0_ReleaseMessage` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容', - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `Message` varchar(1024) NOT NULL DEFAULT '' , + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_Message` (`Message`(191)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息'; + KEY (`DataChange_LastTime`), + KEY (`Message`) +) ; + + + -# Dump of table serverconfig -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_ServerConfig`; CREATE TABLE `C_0_ServerConfig` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', - `Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群', - `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', - `Comment` varchar(1024) DEFAULT '' COMMENT '注释', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `Key` varchar(64) NOT NULL DEFAULT 'default' , + `Cluster` varchar(32) NOT NULL DEFAULT 'default' , + `Value` varchar(2048) NOT NULL DEFAULT 'default' , + `Comment` varchar(1024) DEFAULT '' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + UNIQUE KEY (`Key`,`Cluster`,`DeletedAt`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table accesskey -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_AccessKey`; CREATE TABLE `C_0_AccessKey` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret', - `IsEnabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: enabled, 0: disabled', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `AppId` varchar(64) NOT NULL DEFAULT 'default' , + `Secret` varchar(128) NOT NULL DEFAULT '' , + `IsEnabled` boolean NOT NULL DEFAULT FALSE , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; + UNIQUE KEY (`AppId`,`Secret`,`DeletedAt`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table serviceregistry -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `C_0_ServiceRegistry`; CREATE TABLE `C_0_ServiceRegistry` ( - `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', - `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', - `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', - `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', - `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT , + `ServiceName` VARCHAR(64) NOT NULL , + `Uri` VARCHAR(64) NOT NULL , + `Cluster` VARCHAR(64) NOT NULL , + `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' , + `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; +) ; + + -# Config -# ------------------------------------------------------------ INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) VALUES ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), @@ -435,53 +441,53 @@ VALUES ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); -DROP TABLE IF EXISTS `C_0_AuditLog`; + CREATE TABLE `C_0_AuditLog` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', - `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', - `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', - `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', - `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', - `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', - `Description` varchar(200) DEFAULT NULL COMMENT '备注', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `TraceId` varchar(32) NOT NULL DEFAULT '' , + `SpanId` varchar(32) NOT NULL DEFAULT '' , + `ParentSpanId` varchar(32) DEFAULT NULL , + `FollowsFromSpanId` varchar(32) DEFAULT NULL , + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' , + `OpType` varchar(50) NOT NULL DEFAULT 'default' , + `OpName` varchar(150) NOT NULL DEFAULT 'default' , + `Description` varchar(200) DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) DEFAULT NULL , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY `IX_TraceId` (`TraceId`), - KEY `IX_OpName` (`OpName`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_Operator` (`Operator`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + KEY (`TraceId`), + KEY (`OpName`), + KEY (`DataChange_CreatedTime`), + KEY (`Operator`) +) ; + -DROP TABLE IF EXISTS `C_0_AuditLogDataInfluence`; CREATE TABLE `C_0_AuditLogDataInfluence` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', - `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', - `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', - `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', - `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `SpanId` char(32) NOT NULL DEFAULT '' , + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' , + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' , + `FieldName` varchar(50) DEFAULT NULL , + `FieldOldValue` varchar(500) DEFAULT NULL , + `FieldNewValue` varchar(500) DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) DEFAULT NULL , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY `IX_SpanId` (`SpanId`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_EntityId` (`InfluenceEntityId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + KEY (`SpanId`), + KEY (`DataChange_CreatedTime`), + KEY (`InfluenceEntityId`) +) ; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git a/apollo-assembly/src/main/resources/jpa/apolloportaldb.h2.sql b/apollo-assembly/src/main/resources/jpa/apolloportaldb.h2.sql index 640c6df681e..14de726676c 100644 --- a/apollo-assembly/src/main/resources/jpa/apolloportaldb.h2.sql +++ b/apollo-assembly/src/main/resources/jpa/apolloportaldb.h2.sql @@ -21,312 +21,318 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -# Dump of table app -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_App`; + + + + + + + + + CREATE TABLE `P_0_App` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', - `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', - `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', - `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', - `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `AppId` varchar(64) NOT NULL DEFAULT 'default' , + `Name` varchar(500) NOT NULL DEFAULT 'default' , + `OrgId` varchar(32) NOT NULL DEFAULT 'default' , + `OrgName` varchar(64) NOT NULL DEFAULT 'default' , + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' , + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_Name` (`Name`(191)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + UNIQUE KEY (`AppId`,`DeletedAt`), + KEY (`DataChange_LastTime`), + KEY (`Name`) +) ; + + + -# Dump of table appnamespace -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_AppNamespace`; CREATE TABLE `P_0_AppNamespace` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', - `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', - `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', - `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', - `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `Name` varchar(32) NOT NULL DEFAULT '' , + `AppId` varchar(64) NOT NULL DEFAULT '' , + `Format` varchar(32) NOT NULL DEFAULT 'properties' , + `IsPublic` boolean NOT NULL DEFAULT FALSE , + `Comment` varchar(64) NOT NULL DEFAULT '' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), - KEY `Name_AppId` (`Name`,`AppId`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + UNIQUE KEY (`AppId`,`Name`,`DeletedAt`), + KEY (`Name`,`AppId`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table consumer -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_Consumer`; CREATE TABLE `P_0_Consumer` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', - `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', - `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', - `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', - `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `AppId` varchar(64) NOT NULL DEFAULT 'default' , + `Name` varchar(500) NOT NULL DEFAULT 'default' , + `OrgId` varchar(32) NOT NULL DEFAULT 'default' , + `OrgName` varchar(64) NOT NULL DEFAULT 'default' , + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' , + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者'; + UNIQUE KEY (`AppId`,`DeletedAt`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table consumeraudit -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_ConsumerAudit`; CREATE TABLE `P_0_ConsumerAudit` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', - `Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri', - `Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `ConsumerId` int(11) unsigned DEFAULT NULL , + `Uri` varchar(1024) NOT NULL DEFAULT '' , + `Method` varchar(16) NOT NULL DEFAULT '' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_ConsumerId` (`ConsumerId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表'; + KEY (`DataChange_LastTime`), + KEY (`ConsumerId`) +) ; + + + -# Dump of table consumerrole -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_ConsumerRole`; CREATE TABLE `P_0_ConsumerRole` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', - `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `ConsumerId` int(11) unsigned DEFAULT NULL , + `RoleId` int(10) unsigned DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_RoleId` (`RoleId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表'; + UNIQUE KEY (`ConsumerId`,`RoleId`,`DeletedAt`), + KEY (`DataChange_LastTime`), + KEY (`RoleId`) +) ; + + + -# Dump of table consumertoken -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_ConsumerToken`; CREATE TABLE `P_0_ConsumerToken` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId', - `Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token', - `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `ConsumerId` int(11) unsigned DEFAULT NULL , + `Token` varchar(128) NOT NULL DEFAULT '' , + `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_Token_DeletedAt` (`Token`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表'; + UNIQUE KEY (`Token`,`DeletedAt`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table favorite -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_Favorite`; CREATE TABLE `P_0_Favorite` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `UserId` varchar(32) NOT NULL DEFAULT 'default' , + `AppId` varchar(64) NOT NULL DEFAULT 'default' , + `Position` int(32) NOT NULL DEFAULT '10000' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`), - KEY `AppId` (`AppId`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表'; + UNIQUE KEY (`UserId`,`AppId`,`DeletedAt`), + KEY (`AppId`), + KEY (`DataChange_LastTime`) +) AUTO_INCREMENT=23 ; + + + -# Dump of table permission -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_Permission`; CREATE TABLE `P_0_Permission` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型', - `TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `PermissionType` varchar(32) NOT NULL DEFAULT '' , + `TargetId` varchar(256) NOT NULL DEFAULT '' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表'; + UNIQUE KEY (`TargetId`,`PermissionType`,`DeletedAt`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table role -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_Role`; CREATE TABLE `P_0_Role` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `RoleName` varchar(256) NOT NULL DEFAULT '' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; + UNIQUE KEY (`RoleName`,`DeletedAt`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table rolepermission -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_RolePermission`; CREATE TABLE `P_0_RolePermission` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', - `PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `RoleId` int(10) unsigned DEFAULT NULL , + `PermissionId` int(10) unsigned DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_PermissionId` (`PermissionId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表'; + UNIQUE KEY (`RoleId`,`PermissionId`,`DeletedAt`), + KEY (`DataChange_LastTime`), + KEY (`PermissionId`) +) ; + + + -# Dump of table serverconfig -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_ServerConfig`; CREATE TABLE `P_0_ServerConfig` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', - `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', - `Comment` varchar(1024) DEFAULT '' COMMENT '注释', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `Key` varchar(64) NOT NULL DEFAULT 'default' , + `Value` varchar(2048) NOT NULL DEFAULT 'default' , + `Comment` varchar(1024) DEFAULT '' , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_Key_DeletedAt` (`Key`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + UNIQUE KEY (`Key`,`DeletedAt`), + KEY (`DataChange_LastTime`) +) ; + + + -# Dump of table userrole -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_UserRole`; CREATE TABLE `P_0_UserRole` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识', - `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `UserId` varchar(128) DEFAULT '' , + `RoleId` int(10) unsigned DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_RoleId` (`RoleId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表'; + UNIQUE KEY (`UserId`,`RoleId`,`DeletedAt`), + KEY (`DataChange_LastTime`), + KEY (`RoleId`) +) ; + + + -# Dump of table Users -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_Users`; CREATE TABLE `P_0_Users` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户', - `Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码', - `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称', - `Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址', - `Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `Username` varchar(64) NOT NULL DEFAULT 'default' , + `Password` varchar(512) NOT NULL DEFAULT 'default' , + `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' , + `Email` varchar(64) NOT NULL DEFAULT 'default' , + `Enabled` tinyint(4) DEFAULT NULL , PRIMARY KEY (`Id`), - UNIQUE KEY `UK_Username` (`Username`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + UNIQUE KEY (`Username`) +) ; + + + -# Dump of table Authorities -# ------------------------------------------------------------ -DROP TABLE IF EXISTS `P_0_Authorities`; CREATE TABLE `P_0_Authorities` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `Username` varchar(64) NOT NULL, `Authority` varchar(50) NOT NULL, PRIMARY KEY (`Id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +) ; + + -# Config -# ------------------------------------------------------------ INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) VALUES ('apollo.portal.envs', 'dev', '可支持的环境列表'), @@ -355,69 +361,69 @@ CREATE TABLE `P_0_SPRING_SESSION` ( EXPIRY_TIME BIGINT NOT NULL, PRINCIPAL_NAME VARCHAR(100), CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) -) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +) ; CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON `P_0_SPRING_SESSION` (SESSION_ID); CREATE INDEX SPRING_SESSION_IX2 ON `P_0_SPRING_SESSION` (EXPIRY_TIME); CREATE INDEX SPRING_SESSION_IX3 ON `P_0_SPRING_SESSION` (PRINCIPAL_NAME); -DROP TABLE IF EXISTS `P_0_SPRING_SESSION_ATTRIBUTES`; + CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( SESSION_PRIMARY_ID CHAR(36) NOT NULL, ATTRIBUTE_NAME VARCHAR(200) NOT NULL, ATTRIBUTE_BYTES BLOB NOT NULL, CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES `P_0_SPRING_SESSION`(PRIMARY_ID) ON DELETE CASCADE -) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +) ; + -DROP TABLE IF EXISTS `P_0_AuditLog`; CREATE TABLE `P_0_AuditLog` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', - `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', - `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', - `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', - `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', - `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', - `Description` varchar(200) DEFAULT NULL COMMENT '备注', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `TraceId` varchar(32) NOT NULL DEFAULT '' , + `SpanId` varchar(32) NOT NULL DEFAULT '' , + `ParentSpanId` varchar(32) DEFAULT NULL , + `FollowsFromSpanId` varchar(32) DEFAULT NULL , + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' , + `OpType` varchar(50) NOT NULL DEFAULT 'default' , + `OpName` varchar(150) NOT NULL DEFAULT 'default' , + `Description` varchar(200) DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) DEFAULT NULL , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY `IX_TraceId` (`TraceId`), - KEY `IX_OpName` (`OpName`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_Operator` (`Operator`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + KEY (`TraceId`), + KEY (`OpName`), + KEY (`DataChange_CreatedTime`), + KEY (`Operator`) +) ; + -DROP TABLE IF EXISTS `P_0_AuditLogDataInfluence`; CREATE TABLE `P_0_AuditLogDataInfluence` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', - `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', - `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', - `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', - `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `SpanId` char(32) NOT NULL DEFAULT '' , + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' , + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' , + `FieldName` varchar(50) DEFAULT NULL , + `FieldOldValue` varchar(500) DEFAULT NULL , + `FieldNewValue` varchar(500) DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) DEFAULT NULL , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY `IX_SpanId` (`SpanId`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_EntityId` (`InfluenceEntityId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + KEY (`SpanId`), + KEY (`DataChange_CreatedTime`), + KEY (`InfluenceEntityId`) +) ; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; diff --git a/apollo-assembly/src/test/resources/application.properties b/apollo-assembly/src/test/resources/application.properties index 3ac5d1ac172..587f3d00303 100644 --- a/apollo-assembly/src/test/resources/application.properties +++ b/apollo-assembly/src/test/resources/application.properties @@ -28,4 +28,4 @@ spring.h2.console.enabled=true spring.h2.console.settings.web-allow-others=true # Default env -apollo.portal.env=local +apollo.portal.envs=local From aae21a1ffece001ec70cfb2ba115b98f5b80f990 Mon Sep 17 00:00:00 2001 From: vdisk Date: Mon, 4 Dec 2023 10:58:17 +0800 Subject: [PATCH 04/59] assembly db init --- .../apollo/assembly/ApolloApplication.java | 5 ++ ...lyDataSourceScriptDatabaseInitializer.java | 83 +++++++++++++++++++ ...ApolloAssemblySqlInitializationConfig.java | 49 +++++++++++ .../resources/application-github.properties | 5 +- .../apolloconfigdb.sql} | 0 .../apolloportaldb.sql} | 0 .../resources/jpa/mysql}/apolloconfigdb.sql | 0 .../resources/jpa/mysql}/apolloportaldb.sql | 0 .../src/test/resources/application.properties | 3 +- scripts/sql/apolloconfigdb.sql | 16 ++-- scripts/sql/apolloportaldb.sql | 16 ++-- 11 files changed, 158 insertions(+), 19 deletions(-) create mode 100644 apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java create mode 100644 apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java rename apollo-assembly/src/main/resources/jpa/{apolloconfigdb.h2.sql => h2/apolloconfigdb.sql} (100%) rename apollo-assembly/src/main/resources/jpa/{apolloportaldb.h2.sql => h2/apolloportaldb.sql} (100%) rename {scripts/sql/assembly => apollo-assembly/src/main/resources/jpa/mysql}/apolloconfigdb.sql (100%) rename {scripts/sql/assembly => apollo-assembly/src/main/resources/jpa/mysql}/apolloportaldb.sql (100%) diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java index 9d6bebb2723..5f14d948474 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java @@ -17,6 +17,7 @@ package com.ctrip.framework.apollo.assembly; import com.ctrip.framework.apollo.adminservice.AdminServiceApplication; +import com.ctrip.framework.apollo.assembly.datasource.ApolloAssemblySqlInitializationConfig; import com.ctrip.framework.apollo.audit.configuration.ApolloAuditAutoConfiguration; import com.ctrip.framework.apollo.configservice.ConfigServiceApplication; import com.ctrip.framework.apollo.portal.PortalApplication; @@ -29,7 +30,11 @@ import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.context.scope.refresh.RefreshScope; import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Import; +@Import({ + ApolloAssemblySqlInitializationConfig.class, +}) @SpringBootApplication(exclude = { HibernateJpaAutoConfiguration.class, ApolloAuditAutoConfiguration.class, diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java new file mode 100644 index 00000000000..c0514aa230a --- /dev/null +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java @@ -0,0 +1,83 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.assembly.datasource; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.sql.DataSource; +import org.springframework.boot.autoconfigure.sql.init.SqlDataSourceScriptDatabaseInitializer; +import org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties; +import org.springframework.boot.jdbc.DatabaseDriver; +import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.util.StringUtils; + +public class ApolloAssemblyDataSourceScriptDatabaseInitializer extends + SqlDataSourceScriptDatabaseInitializer { + + public ApolloAssemblyDataSourceScriptDatabaseInitializer(DataSource dataSource, + SqlInitializationProperties properties) { + super(dataSource, getSettings(dataSource, properties)); + } + + public static DatabaseInitializationSettings getSettings(DataSource dataSource, + SqlInitializationProperties properties) { + + PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver().withDriverPlatform( + DatabaseDriver.MARIADB, "mysql"); + + List schemaLocations = resolveLocations(properties.getSchemaLocations(), + platformResolver, + dataSource, properties); + List dataLocations = resolveLocations(properties.getDataLocations(), platformResolver, + dataSource, properties); + + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); + settings.setSchemaLocations( + scriptLocations(schemaLocations, "schema", properties.getPlatform())); + settings.setDataLocations(scriptLocations(dataLocations, "data", properties.getPlatform())); + settings.setContinueOnError(properties.isContinueOnError()); + settings.setSeparator(properties.getSeparator()); + settings.setEncoding(properties.getEncoding()); + settings.setMode(properties.getMode()); + return settings; + } + + + private static List resolveLocations(Collection locations, + PlatformPlaceholderDatabaseDriverResolver platformResolver, DataSource dataSource, + SqlInitializationProperties properties) { + + if (StringUtils.hasText(properties.getPlatform())) { + return platformResolver.resolveAll(properties.getPlatform(), + locations.toArray(new String[0])); + } + return platformResolver.resolveAll(dataSource, locations.toArray(new String[0])); + } + + private static List scriptLocations(List locations, String fallback, + String platform) { + if (locations != null) { + return locations; + } + List fallbackLocations = new ArrayList<>(); + fallbackLocations.add("optional:classpath*:" + fallback + "-" + platform + ".sql"); + fallbackLocations.add("optional:classpath*:" + fallback + ".sql"); + return fallbackLocations; + } +} diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java new file mode 100644 index 00000000000..6d034b621bd --- /dev/null +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java @@ -0,0 +1,49 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.assembly.datasource; + +import javax.sql.DataSource; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.datasource.SimpleDriverDataSource; +import org.springframework.util.StringUtils; + +@ConditionalOnProperty(prefix = "spring.sql.init", name = "enabled", matchIfMissing = true) +@Configuration +public class ApolloAssemblySqlInitializationConfig { + + @Bean + ApolloAssemblyDataSourceScriptDatabaseInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource, + SqlInitializationProperties properties) { + return new ApolloAssemblyDataSourceScriptDatabaseInitializer( + determineDataSource(dataSource, properties.getUsername(), properties.getPassword()), properties); + } + + private static DataSource determineDataSource(DataSource dataSource, String username, String password) { + if (StringUtils.hasText(username) && StringUtils.hasText(password)) { + return DataSourceBuilder.derivedFrom(dataSource) + .username(username) + .password(password) + .type(SimpleDriverDataSource.class) + .build(); + } + return dataSource; + } +} diff --git a/apollo-assembly/src/main/resources/application-github.properties b/apollo-assembly/src/main/resources/application-github.properties index 79295bcf657..ae6d154abc8 100644 --- a/apollo-assembly/src/main/resources/application-github.properties +++ b/apollo-assembly/src/main/resources/application-github.properties @@ -27,11 +27,12 @@ spring.jpa.table-prefix.config-prefix=C_0_ spring.jpa.table-prefix.portal-prefix=P_0_ # H2 datasource -spring.sql.init.schema-locations=classpath:jpa/apolloconfigdb.h2.sql, classpath:jpa/apolloportaldb.h2.sql +spring.sql.init.schema-locations=classpath:jpa/@@platform@@/apolloconfigdb.sql, classpath:jpa/@@platform@@/apolloportaldb.h2.sql +spring.sql.init.mode=embedded spring.jpa.properties.hibernate.show_sql=false spring.jpa.properties.hibernate.metadata_builder_contributor=com.ctrip.framework.apollo.common.jpa.SqlFunctionsMetadataBuilderContributor spring.h2.console.enabled=true spring.h2.console.settings.web-allow-others=true # Default env -apollo.portal.envs=local \ No newline at end of file +apollo.portal.envs=local diff --git a/apollo-assembly/src/main/resources/jpa/apolloconfigdb.h2.sql b/apollo-assembly/src/main/resources/jpa/h2/apolloconfigdb.sql similarity index 100% rename from apollo-assembly/src/main/resources/jpa/apolloconfigdb.h2.sql rename to apollo-assembly/src/main/resources/jpa/h2/apolloconfigdb.sql diff --git a/apollo-assembly/src/main/resources/jpa/apolloportaldb.h2.sql b/apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql similarity index 100% rename from apollo-assembly/src/main/resources/jpa/apolloportaldb.h2.sql rename to apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql diff --git a/scripts/sql/assembly/apolloconfigdb.sql b/apollo-assembly/src/main/resources/jpa/mysql/apolloconfigdb.sql similarity index 100% rename from scripts/sql/assembly/apolloconfigdb.sql rename to apollo-assembly/src/main/resources/jpa/mysql/apolloconfigdb.sql diff --git a/scripts/sql/assembly/apolloportaldb.sql b/apollo-assembly/src/main/resources/jpa/mysql/apolloportaldb.sql similarity index 100% rename from scripts/sql/assembly/apolloportaldb.sql rename to apollo-assembly/src/main/resources/jpa/mysql/apolloportaldb.sql diff --git a/apollo-assembly/src/test/resources/application.properties b/apollo-assembly/src/test/resources/application.properties index 587f3d00303..17dbb08c314 100644 --- a/apollo-assembly/src/test/resources/application.properties +++ b/apollo-assembly/src/test/resources/application.properties @@ -21,7 +21,8 @@ spring.jpa.table-prefix.config-prefix=C_0_ spring.jpa.table-prefix.portal-prefix=P_0_ # H2 datasource -spring.sql.init.schema-locations=classpath:jpa/apolloconfigdb.h2.sql, classpath:jpa/apolloportaldb.h2.sql +spring.sql.init.schema-locations=classpath:jpa/@@platform@@/apolloconfigdb.sql, classpath:jpa/@@platform@@/apolloportaldb.h2.sql +spring.sql.init.mode=embedded spring.jpa.properties.hibernate.show_sql=false spring.jpa.properties.hibernate.metadata_builder_contributor=com.ctrip.framework.apollo.common.jpa.SqlFunctionsMetadataBuilderContributor spring.h2.console.enabled=true diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index 51f89640bed..667fed40724 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -440,13 +440,6 @@ VALUES ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; - DROP TABLE IF EXISTS `AuditLog`; @@ -494,4 +487,11 @@ CREATE TABLE `AuditLogDataInfluence` ( KEY `IX_SpanId` (`SpanId`), KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), KEY `IX_EntityId` (`InfluenceEntityId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/scripts/sql/apolloportaldb.sql b/scripts/sql/apolloportaldb.sql index d0f0d0974bd..cf7a744ddb0 100644 --- a/scripts/sql/apolloportaldb.sql +++ b/scripts/sql/apolloportaldb.sql @@ -375,13 +375,6 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES ( CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; - DROP TABLE IF EXISTS `AuditLog`; @@ -429,4 +422,11 @@ CREATE TABLE `AuditLogDataInfluence` ( KEY `IX_SpanId` (`SpanId`), KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), KEY `IX_EntityId` (`InfluenceEntityId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; From 4b5ebeee94068010fcb3102b761751f91ee3b605 Mon Sep 17 00:00:00 2001 From: vdisk Date: Mon, 4 Dec 2023 11:28:00 +0800 Subject: [PATCH 05/59] assembly db init fix --- ...loAssemblyDataSourceScriptDatabaseInitializer.java | 11 ++++++++--- .../src/main/resources/application-github.properties | 2 +- .../src/test/resources/application.properties | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java index c0514aa230a..0d135d8c19d 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java @@ -25,6 +25,7 @@ import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; public class ApolloAssemblyDataSourceScriptDatabaseInitializer extends @@ -63,9 +64,13 @@ private static List resolveLocations(Collection locations, PlatformPlaceholderDatabaseDriverResolver platformResolver, DataSource dataSource, SqlInitializationProperties properties) { - if (StringUtils.hasText(properties.getPlatform())) { - return platformResolver.resolveAll(properties.getPlatform(), - locations.toArray(new String[0])); + if (CollectionUtils.isEmpty(locations)) { + return null; + } + + String platform = properties.getPlatform(); + if (StringUtils.hasText(platform) && !"all".equals(platform)) { + return platformResolver.resolveAll(platform, locations.toArray(new String[0])); } return platformResolver.resolveAll(dataSource, locations.toArray(new String[0])); } diff --git a/apollo-assembly/src/main/resources/application-github.properties b/apollo-assembly/src/main/resources/application-github.properties index ae6d154abc8..20ee6cdbe19 100644 --- a/apollo-assembly/src/main/resources/application-github.properties +++ b/apollo-assembly/src/main/resources/application-github.properties @@ -27,7 +27,7 @@ spring.jpa.table-prefix.config-prefix=C_0_ spring.jpa.table-prefix.portal-prefix=P_0_ # H2 datasource -spring.sql.init.schema-locations=classpath:jpa/@@platform@@/apolloconfigdb.sql, classpath:jpa/@@platform@@/apolloportaldb.h2.sql +spring.sql.init.schema-locations=classpath:jpa/@@platform@@/apolloconfigdb.sql, classpath:jpa/@@platform@@/apolloportaldb.sql spring.sql.init.mode=embedded spring.jpa.properties.hibernate.show_sql=false spring.jpa.properties.hibernate.metadata_builder_contributor=com.ctrip.framework.apollo.common.jpa.SqlFunctionsMetadataBuilderContributor diff --git a/apollo-assembly/src/test/resources/application.properties b/apollo-assembly/src/test/resources/application.properties index 17dbb08c314..2e17bbcf504 100644 --- a/apollo-assembly/src/test/resources/application.properties +++ b/apollo-assembly/src/test/resources/application.properties @@ -21,7 +21,7 @@ spring.jpa.table-prefix.config-prefix=C_0_ spring.jpa.table-prefix.portal-prefix=P_0_ # H2 datasource -spring.sql.init.schema-locations=classpath:jpa/@@platform@@/apolloconfigdb.sql, classpath:jpa/@@platform@@/apolloportaldb.h2.sql +spring.sql.init.schema-locations=classpath:jpa/@@platform@@/apolloconfigdb.sql, classpath:jpa/@@platform@@/apolloportaldb.sql spring.sql.init.mode=embedded spring.jpa.properties.hibernate.show_sql=false spring.jpa.properties.hibernate.metadata_builder_contributor=com.ctrip.framework.apollo.common.jpa.SqlFunctionsMetadataBuilderContributor From d0fbd74cf7afe4c007efe2c334a3a66fe36edc32 Mon Sep 17 00:00:00 2001 From: vdisk Date: Mon, 4 Dec 2023 22:16:16 +0800 Subject: [PATCH 06/59] assembly sql --- scripts/sql/assembly/apolloconfigdb.sql | 498 ++++++++++++++++++++++++ scripts/sql/assembly/apolloportaldb.sql | 434 +++++++++++++++++++++ 2 files changed, 932 insertions(+) create mode 100644 scripts/sql/assembly/apolloconfigdb.sql create mode 100644 scripts/sql/assembly/apolloportaldb.sql diff --git a/scripts/sql/assembly/apolloconfigdb.sql b/scripts/sql/assembly/apolloconfigdb.sql new file mode 100644 index 00000000000..be387ebd752 --- /dev/null +++ b/scripts/sql/assembly/apolloconfigdb.sql @@ -0,0 +1,498 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +# Create Database +# ------------------------------------------------------------ +CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; + +Use ApolloAssemblyDB; + +# Dump of table app +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_App`; + +CREATE TABLE `C_0_App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +# Dump of table appnamespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AppNamespace`; + +CREATE TABLE `C_0_AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +# Dump of table audit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Audit`; + +CREATE TABLE `C_0_Audit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID', + `OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表'; + + + +# Dump of table cluster +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Cluster`; + +CREATE TABLE `C_0_Cluster` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id', + `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `IX_ParentClusterId` (`ParentClusterId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群'; + + + +# Dump of table commit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Commit`; + +CREATE TABLE `C_0_Commit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `ChangeSets` longtext NOT NULL COMMENT '修改变更集', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `AppId` (`AppId`), + KEY `ClusterName` (`ClusterName`(191)), + KEY `NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表'; + +# Dump of table grayreleaserule +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_GrayReleaseRule`; + +CREATE TABLE `C_0_GrayReleaseRule` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name', + `Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release', + `BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表'; + + +# Dump of table instance +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Instance`; + +CREATE TABLE `C_0_Instance` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name', + `Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`), + KEY `IX_IP` (`Ip`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例'; + + + +# Dump of table instanceconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_InstanceConfig`; + +CREATE TABLE `C_0_InstanceConfig` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id', + `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id', + `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name', + `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), + KEY `IX_ReleaseKey` (`ReleaseKey`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息'; + + + +# Dump of table item +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Item`; + +CREATE TABLE `C_0_Item` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '配置项类型,0: String,1: Number,2: Boolean,3: JSON', + `Value` longtext NOT NULL COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_GroupId` (`NamespaceId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目'; + + + +# Dump of table namespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Namespace`; + +CREATE TABLE `C_0_Namespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间'; + + + +# Dump of table namespacelock +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_NamespaceLock`; + +CREATE TABLE `C_0_NamespaceLock` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁'; + + + +# Dump of table release +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Release`; + +CREATE TABLE `C_0_Release` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字', + `Comment` varchar(256) DEFAULT NULL COMMENT '发布说明', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Configurations` longtext NOT NULL COMMENT '发布配置', + `IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`), + KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布'; + + +# Dump of table releasehistory +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ReleaseHistory`; + +CREATE TABLE `C_0_ReleaseHistory` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id', + `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId', + `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度', + `OperationContext` longtext NOT NULL COMMENT '发布上下文信息', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), + KEY `IX_ReleaseId` (`ReleaseId`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PreviousReleaseId` (`PreviousReleaseId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史'; + + +# Dump of table releasemessage +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ReleaseMessage`; + +CREATE TABLE `C_0_ReleaseMessage` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Message` (`Message`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息'; + + + +# Dump of table serverconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ServerConfig`; + +CREATE TABLE `C_0_ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + +# Dump of table accesskey +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AccessKey`; + +CREATE TABLE `C_0_AccessKey` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret', + `IsEnabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: enabled, 0: disabled', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; + + +# Dump of table serviceregistry +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ServiceRegistry`; + +CREATE TABLE `C_0_ServiceRegistry` ( + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', + `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), + INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; + + +# Config +# ------------------------------------------------------------ +INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +VALUES + ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), + ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), + ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'), + ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), + ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); + + +DROP TABLE IF EXISTS `C_0_AuditLog`; + +CREATE TABLE `C_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + + +DROP TABLE IF EXISTS `C_0_AuditLogDataInfluence`; + +CREATE TABLE `C_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/scripts/sql/assembly/apolloportaldb.sql b/scripts/sql/assembly/apolloportaldb.sql new file mode 100644 index 00000000000..dde438fa88e --- /dev/null +++ b/scripts/sql/assembly/apolloportaldb.sql @@ -0,0 +1,434 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +# Create Database +# ------------------------------------------------------------ +CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; + +Use ApolloAssemblyDB; + +# Dump of table app +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_App`; + +CREATE TABLE `P_0_App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +# Dump of table appnamespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_AppNamespace`; + +CREATE TABLE `P_0_AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +# Dump of table consumer +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Consumer`; + +CREATE TABLE `P_0_Consumer` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者'; + + + +# Dump of table consumeraudit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerAudit`; + +CREATE TABLE `P_0_ConsumerAudit` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri', + `Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_ConsumerId` (`ConsumerId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表'; + + + +# Dump of table consumerrole +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerRole`; + +CREATE TABLE `P_0_ConsumerRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表'; + + + +# Dump of table consumertoken +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerToken`; + +CREATE TABLE `P_0_ConsumerToken` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId', + `Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token', + `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Token_DeletedAt` (`Token`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表'; + +# Dump of table favorite +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Favorite`; + +CREATE TABLE `P_0_Favorite` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`), + KEY `AppId` (`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表'; + +# Dump of table permission +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Permission`; + +CREATE TABLE `P_0_Permission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型', + `TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表'; + + + +# Dump of table role +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Role`; + +CREATE TABLE `P_0_Role` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; + + + +# Dump of table rolepermission +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_RolePermission`; + +CREATE TABLE `P_0_RolePermission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PermissionId` (`PermissionId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表'; + + + +# Dump of table serverconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ServerConfig`; + +CREATE TABLE `P_0_ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_DeletedAt` (`Key`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + + + +# Dump of table userrole +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_UserRole`; + +CREATE TABLE `P_0_UserRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表'; + +# Dump of table Users +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Users`; + +CREATE TABLE `P_0_Users` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户', + `Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码', + `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称', + `Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址', + `Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Username` (`Username`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + + +# Dump of table Authorities +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Authorities`; + +CREATE TABLE `P_0_Authorities` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL, + `Authority` varchar(50) NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + + +# Config +# ------------------------------------------------------------ +INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) +VALUES + ('apollo.portal.envs', 'dev', '可支持的环境列表'), + ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), + ('superAdmin', 'apollo', 'Portal超级管理员'), + ('api.readTimeout', '10000', 'http接口read timeout'), + ('consumer.token.salt', 'someSalt', 'consumer token salt'), + ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'), + ('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔'), + ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); + + +INSERT INTO `P_0_Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) +VALUES + ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); + +INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); + +-- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) +CREATE TABLE `P_0_SPRING_SESSION` ( + PRIMARY_ID CHAR(36) NOT NULL, + SESSION_ID CHAR(36) NOT NULL, + CREATION_TIME BIGINT NOT NULL, + LAST_ACCESS_TIME BIGINT NOT NULL, + MAX_INACTIVE_INTERVAL INT NOT NULL, + EXPIRY_TIME BIGINT NOT NULL, + PRINCIPAL_NAME VARCHAR(100), + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON `P_0_SPRING_SESSION` (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON `P_0_SPRING_SESSION` (EXPIRY_TIME); +CREATE INDEX SPRING_SESSION_IX3 ON `P_0_SPRING_SESSION` (PRINCIPAL_NAME); + +DROP TABLE IF EXISTS `P_0_SPRING_SESSION_ATTRIBUTES`; +CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( + SESSION_PRIMARY_ID CHAR(36) NOT NULL, + ATTRIBUTE_NAME VARCHAR(200) NOT NULL, + ATTRIBUTE_BYTES BLOB NOT NULL, + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES `P_0_SPRING_SESSION`(PRIMARY_ID) ON DELETE CASCADE +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + + +DROP TABLE IF EXISTS `P_0_AuditLog`; + +CREATE TABLE `P_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + + +DROP TABLE IF EXISTS `P_0_AuditLogDataInfluence`; + +CREATE TABLE `P_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; From 7bcc979c5a69c1401196b76e29e7985c6d3e7bb0 Mon Sep 17 00:00:00 2001 From: vdisk Date: Wed, 6 Dec 2023 22:34:30 +0800 Subject: [PATCH 07/59] WebSecurity --- .../apollo/adminservice/AdminServiceAutoConfiguration.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java index 18cc2d9c207..2b3717aaef6 100644 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java @@ -21,6 +21,7 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @@ -53,6 +54,7 @@ public FilterRegistrationBean adminServiceAuth * for apollo-assembly */ @Order(99) + @Profile("auth") @Configuration static class AdminServiceSecurityConfigurer extends WebSecurityConfigurerAdapter { From af7f56e51134fb2785d10c15c04ca8d6d2e156f8 Mon Sep 17 00:00:00 2001 From: vdisk Date: Wed, 13 Dec 2023 21:46:48 +0800 Subject: [PATCH 08/59] H2Function --- apollo-assembly/src/main/resources/jpa/h2/apolloconfigdb.sql | 2 +- apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apollo-assembly/src/main/resources/jpa/h2/apolloconfigdb.sql b/apollo-assembly/src/main/resources/jpa/h2/apolloconfigdb.sql index 6b829014e50..a9cb0b88863 100644 --- a/apollo-assembly/src/main/resources/jpa/h2/apolloconfigdb.sql +++ b/apollo-assembly/src/main/resources/jpa/h2/apolloconfigdb.sql @@ -21,7 +21,7 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - +CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; diff --git a/apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql b/apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql index 14de726676c..1e0fc2375a8 100644 --- a/apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql +++ b/apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql @@ -21,7 +21,7 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - +CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; From c22644a008eb7171e9352a91b8256620e3af0f7c Mon Sep 17 00:00:00 2001 From: vdisk Date: Wed, 13 Dec 2023 22:00:05 +0800 Subject: [PATCH 09/59] assembly profile --- .../apollo/adminservice/AdminServiceAutoConfiguration.java | 2 +- .../com/ctrip/framework/apollo/assembly/ApolloApplication.java | 3 +++ .../framework/apollo/biz/service/BizDBPropertySource.java | 2 +- .../apollo/portal/service/PortalDBPropertySource.java | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java index 2b3717aaef6..481f67730af 100644 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java @@ -54,7 +54,7 @@ public FilterRegistrationBean adminServiceAuth * for apollo-assembly */ @Order(99) - @Profile("auth") + @Profile("assembly") @Configuration static class AdminServiceSecurityConfigurer extends WebSecurityConfigurerAdapter { diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java index 5f14d948474..93ab3efcbf2 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java @@ -56,6 +56,7 @@ public static void main(String[] args) throws Exception { */ ConfigurableApplicationContext configContext = new SpringApplicationBuilder(ConfigServiceApplication.class).parent(commonContext) + .profiles("assembly") .sources(RefreshScope.class).run(args); logger.info("configContext [{}] isActive: {}", configContext.getId(), configContext.isActive()); @@ -64,6 +65,7 @@ public static void main(String[] args) throws Exception { */ ConfigurableApplicationContext adminContext = new SpringApplicationBuilder(AdminServiceApplication.class).parent(commonContext) + .profiles("assembly") .sources(RefreshScope.class).run(args); logger.info("adminContext [{}] isActive: {}" , adminContext.getId(), adminContext.isActive()); @@ -72,6 +74,7 @@ public static void main(String[] args) throws Exception { */ ConfigurableApplicationContext portalContext = new SpringApplicationBuilder(PortalApplication.class).parent(commonContext) + .profiles("assembly") .sources(RefreshScope.class).run(args); logger.info("portalContext [{}] isActive: {}", portalContext.getId(), portalContext.isActive()); } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/BizDBPropertySource.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/BizDBPropertySource.java index 43190b06edb..85ecbaafdd2 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/BizDBPropertySource.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/BizDBPropertySource.java @@ -66,7 +66,7 @@ public BizDBPropertySource(final ServerConfigRepository serverConfigRepository, @PostConstruct public void runSqlScript() throws Exception { - if (env.acceptsProfiles(Profiles.of("h2"))) { + if (env.acceptsProfiles(Profiles.of("h2")) && !env.acceptsProfiles(Profiles.of("assembly"))) { Resource resource = new ClassPathResource("jpa/configdb.init.h2.sql"); if (resource.exists()) { DatabasePopulatorUtils.execute(new ResourceDatabasePopulator(resource), dataSource); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/PortalDBPropertySource.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/PortalDBPropertySource.java index 664e6b37e5b..196ae6013ba 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/PortalDBPropertySource.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/PortalDBPropertySource.java @@ -62,7 +62,7 @@ public PortalDBPropertySource(final ServerConfigRepository serverConfigRepositor @PostConstruct public void runSqlScript() throws Exception { - if (env.acceptsProfiles(Profiles.of("h2"))) { + if (env.acceptsProfiles(Profiles.of("h2")) && !env.acceptsProfiles(Profiles.of("assembly"))) { Resource resource = new ClassPathResource("jpa/portaldb.init.h2.sql"); if (resource.exists()) { DatabasePopulatorUtils.execute(new ResourceDatabasePopulator(resource), dataSource); From 73d45a780651800023a0657c97ebc78068cb5abf Mon Sep 17 00:00:00 2001 From: vdisk Date: Wed, 13 Dec 2023 22:15:16 +0800 Subject: [PATCH 10/59] assembly session --- .../src/main/resources/application-github.properties | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apollo-assembly/src/main/resources/application-github.properties b/apollo-assembly/src/main/resources/application-github.properties index 20ee6cdbe19..777cd082309 100644 --- a/apollo-assembly/src/main/resources/application-github.properties +++ b/apollo-assembly/src/main/resources/application-github.properties @@ -25,6 +25,7 @@ spring_datasource_url=jdbc:h2:mem:~/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT spring.jpa.hibernate.naming.physical-strategy=com.ctrip.framework.apollo.common.jpa.TablePrefixNamingStrategy spring.jpa.table-prefix.config-prefix=C_0_ spring.jpa.table-prefix.portal-prefix=P_0_ +spring.session.jdbc.table-name=P_0_SPRING_SESSION # H2 datasource spring.sql.init.schema-locations=classpath:jpa/@@platform@@/apolloconfigdb.sql, classpath:jpa/@@platform@@/apolloportaldb.sql @@ -36,3 +37,6 @@ spring.h2.console.settings.web-allow-others=true # Default env apollo.portal.envs=local + +# Spring Session +spring.session.store-type=none From ab86efea17508c7b7edc6fe237f70b9003d69df2 Mon Sep 17 00:00:00 2001 From: vdisk Date: Wed, 13 Dec 2023 22:43:52 +0800 Subject: [PATCH 11/59] ddl-auto=none --- .../src/main/resources/application-github.properties | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apollo-assembly/src/main/resources/application-github.properties b/apollo-assembly/src/main/resources/application-github.properties index 777cd082309..fcc00f2f359 100644 --- a/apollo-assembly/src/main/resources/application-github.properties +++ b/apollo-assembly/src/main/resources/application-github.properties @@ -30,13 +30,17 @@ spring.session.jdbc.table-name=P_0_SPRING_SESSION # H2 datasource spring.sql.init.schema-locations=classpath:jpa/@@platform@@/apolloconfigdb.sql, classpath:jpa/@@platform@@/apolloportaldb.sql spring.sql.init.mode=embedded +spring.jpa.hibernate.ddl-auto=none spring.jpa.properties.hibernate.show_sql=false spring.jpa.properties.hibernate.metadata_builder_contributor=com.ctrip.framework.apollo.common.jpa.SqlFunctionsMetadataBuilderContributor spring.h2.console.enabled=true spring.h2.console.settings.web-allow-others=true +# Sql logging +#logging.level.org.hibernate.SQL=DEBUG + # Default env apollo.portal.envs=local -# Spring Session +# Spring session spring.session.store-type=none From d248136c687895a65c8b86008d27b88db7115eeb Mon Sep 17 00:00:00 2001 From: vdisk Date: Wed, 13 Dec 2023 23:08:32 +0800 Subject: [PATCH 12/59] DataSource --- .../src/main/resources/application-github.properties | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/apollo-assembly/src/main/resources/application-github.properties b/apollo-assembly/src/main/resources/application-github.properties index fcc00f2f359..f86ce05c34d 100644 --- a/apollo-assembly/src/main/resources/application-github.properties +++ b/apollo-assembly/src/main/resources/application-github.properties @@ -14,12 +14,9 @@ # limitations under the License. # # DataSource -spring.datasource.url=${spring_datasource_url} -spring.datasource.username=${spring_datasource_username} -spring.datasource.password=${spring_datasource_password} - -# Default datasource -spring_datasource_url=jdbc:h2:mem:~/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE +spring.datasource.url=jdbc:h2:mem:~/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE +#spring.datasource.username= +#spring.datasource.password= # Table prefix spring.jpa.hibernate.naming.physical-strategy=com.ctrip.framework.apollo.common.jpa.TablePrefixNamingStrategy From 8caeaa21d8ccc46ca86f099fdfd1a7d6927f1c1a Mon Sep 17 00:00:00 2001 From: vdisk Date: Wed, 13 Dec 2023 23:17:20 +0800 Subject: [PATCH 13/59] doc --- ...ApolloAssemblySqlInitializationConfig.java | 2 + .../main/resources/jpa/h2/apolloportaldb.sql | 2 +- docs/en/deployment/quick-start.md | 146 +++++++++--------- docs/zh/deployment/quick-start.md | 144 ++++++++--------- 4 files changed, 146 insertions(+), 148 deletions(-) diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java index 6d034b621bd..5bbb618aa4f 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java @@ -19,12 +19,14 @@ import javax.sql.DataSource; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.SimpleDriverDataSource; import org.springframework.util.StringUtils; +@EnableConfigurationProperties(SqlInitializationProperties.class) @ConditionalOnProperty(prefix = "spring.sql.init", name = "enabled", matchIfMissing = true) @Configuration public class ApolloAssemblySqlInitializationConfig { diff --git a/apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql b/apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql index 1e0fc2375a8..26ebca6a79d 100644 --- a/apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql +++ b/apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql @@ -336,7 +336,7 @@ CREATE TABLE `P_0_Authorities` ( INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) VALUES ('apollo.portal.envs', 'dev', '可支持的环境列表'), - ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), + ('organizations', '[{"orgId":"TEST1","orgName":"样例部门1"},{"orgId":"TEST2","orgName":"样例部门2"}]', '部门列表'), ('superAdmin', 'apollo', 'Portal超级管理员'), ('api.readTimeout', '10000', 'http接口read timeout'), ('consumer.token.salt', 'someSalt', 'consumer token salt'), diff --git a/docs/en/deployment/quick-start.md b/docs/en/deployment/quick-start.md index 79f770ad097..030593126cf 100644 --- a/docs/en/deployment/quick-start.md +++ b/docs/en/deployment/quick-start.md @@ -29,7 +29,7 @@ Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode) Windows users please make sure that JAVA_HOME environment variable is set. ## 1.2 MySQL - +* If you plan to use H2 in-memory database/H2 file database, there is no need for MySQL, and you can skip this step. * Version requirement: 5.6.5+ Apollo's table structure uses multiple default declarations for `timestamp`, so version 5.6.5+ is required. @@ -66,103 +66,99 @@ Quick Start is only for local testing, so generally users do not need to downloa 2. Execute `mvn clean package -pl apollo-assembly -am -DskipTests=true` in the root directory. 3. Copy the jar package under apollo-assembly/target and rename it to apollo-all-in-one.jar -# II. Installation steps -## 2.1 Create the database -Apollo server side needs a total of two databases: `ApolloPortalDB` and `ApolloConfigDB`, we have prepared the database, table creation and sample data as sql files respectively, just import the database. - -> Note: If you have already created Apollo database locally, please take care to backup the data. The sql file we prepared will clear the Apollo related tables. - -### 2.1.1 Creating ApolloPortalDB -Just import [sql/apolloportaldb.sql](https://github.com/apolloconfig/apollo-quick-start/blob/master/sql/apolloportaldb.sql) through various MySQL clients. +# II. Initialization and Startup +#### Precautions +1. The Apollo server process needs to use ports 8070, 8080, 8090 respectively, please ensure these three ports are not currently in use. +2. The `github` in the SPRING_PROFILES_ACTIVE environment variable in the script is a required profile, `auth` is a profile that provides simple authentication for the portal, it can be removed if authentication is not required or other authentication methods are used. +## 2.1 Use H2 in-memory database, automatic initialization +No configuration is required, just use the following command to start +> Note: When using the in-memory database, any operation will be lost after the Apollo process restarts +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +unset SPRING_SQL_INIT_MODE +java -jar apollo-all-in-one.jar -The following is an example of a native MySQL client. -```sql -source /your_local_path/sql/apolloportaldb.sql ``` -After the successful import, you can verify it by executing the following sql statement. -```sql -select `Id`, `AppId`, `Name` from ApolloPortalDB.App; -``` - -| Id | AppId | Name | -| ---- | --------- | ---------- | -| 1 | SampleApp | Sample App | +## 2.2 Use H2 file database, automatic initialization +#### Precautions +1. The path `~/apollo/apolloassemblydb` in the SPRING_DATASOURCE_URL environment variable in the script can be replaced with other custom paths, you need to ensure that this path has read and write permissions -### 2.1.2 Creating ApolloConfigDB -You can import [sql/apolloconfigdb.sql](https://github.com/apolloconfig/apollo-quick-start/blob/master/sql/apolloconfigdb.sql) through various MySQL clients. +### 2.2.1 First startup +Use the SPRING_SQL_INIT_MODE="always" environment variable for initialization at the first startup +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +export SPRING_SQL_INIT_MODE="always" +export SPRING_DATASOURCE_URL="jdbc:h2:file:~/apollo/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +java -jar apollo-all-in-one.jar -The following is an example of a native MySQL client. -```sql -source /your_local_path/sql/apolloconfigdb.sql ``` -After the successful import, you can verify it by executing the following sql statement. -```sql -select `NamespaceId`, `Key`, `Value`, `Comment` from ApolloConfigDB.Item; +### 2.2.2 Subsequent startup +Remove the SPRING_SQL_INIT_MODE environment variable to avoid repeated initialization at subsequent startup +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +unset SPRING_SQL_INIT_MODE +export SPRING_DATASOURCE_URL="jdbc:h2:file:~/apollo/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +java -jar apollo-all-in-one.jar + ``` -| NamespaceId | Key | Value | Comment | -| ----------- | ------- | ----- | ---------------------------- | -| 1 | timeout | 100 | sample timeout configuration | -## 2.2 Configuring Database Connection Information -The Apollo server needs to know how to connect to the database you created earlier, so you need to edit [demo.sh](https://github.com/apolloconfig/apollo-quick-start/blob/master/demo.sh) and modify ApolloPortalDB and ApolloConfigDB related database connection string information. +## 2.3 Use mysql database, automatic initialization +#### Precautions +1. The your-mysql-server:3306 in the SPRING_DATASOURCE_URL environment variable in the script needs to be replaced with the actual mysql server address and port, ApolloAssemblyDB needs to be replaced with the actual database name +2. The SPRING_DATASOURCE_USERNAME and SPRING_DATASOURCE_PASSWORD environment variables in the script need to fill in the actual username and password -> Note: The filled in user needs to have read and write access to ApolloPortalDB and ApolloConfigDB data. +### 2.3.1 First startup +Use the SPRING_SQL_INIT_MODE="always" environment variable for initialization at the first startup +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +export SPRING_SQL_INIT_MODE="always" +export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_DATASOURCE_USERNAME="apollo-username" +export SPRING_DATASOURCE_PASSWORD="apollo-password" +java -jar apollo-all-in-one.jar -```sh -#apollo config db info -apollo_config_db_url="jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8&serverTimezone=Asia/Shanghai" -apollo_config_db_username=username -apollo_config_db_password=password (if you don't have a password, just leave it blank) - -# apollo portal db info -apollo_portal_db_url="jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8&serverTimezone=Asia/Shanghai" -apollo_portal_db_username=username -apollo_portal_db_password=password (if you don't have a password, just leave it blank) ``` -> Note: Do not modify other parts of demo.sh - -# III. Start Apollo Configuration Center -## 3.1 Make sure the port is not occupied -The Quick Start script will start 3 services locally, using ports 8070, 8080, 8090 respectively, please make sure these 3 ports are not currently used. +### 2.3.2 Subsequent startup +Remove the SPRING_SQL_INIT_MODE environment variable to avoid repeated initialization at subsequent startup +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +unset SPRING_SQL_INIT_MODE +export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_DATASOURCE_USERNAME="apollo-username" +export SPRING_DATASOURCE_PASSWORD="apollo-password" +java -jar apollo-all-in-one.jar -For example, under Linux/Mac, you can check with the following command. -```sh -lsof -i:8080 ``` -## 3.2 Execute the startup script -```sh -./demo.sh start -``` +## 2.4 Use mysql database, manual initialization -When you see the following output, you've started successfully! -```sh -==== starting service ==== -Service logging file is . /service/apollo-service.log -Started [10768] -Waiting for config service startup ....... -Config service started. You may visit http://localhost:8080 for service status now! -Waiting for admin service startup.... -Admin service started -==== starting portal ==== -Portal logging file is . /portal/apollo-portal.log -Started [10846] -Waiting for portal startup ...... -Portal started. You can visit http://localhost:8070 now! -You can visit now! -``` +### 2.4.1 Manually initialize ApolloAssemblyDB +Import [sql/assembly](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/assembly) through various MySQL clients +### 2.4.2 Run +#### Precautions +1. The your-mysql-server:3306 in the SPRING_DATASOURCE_URL environment variable in the script needs to be replaced with the actual mysql server address and port, ApolloAssemblyDB needs to be replaced with the actual database name +2. The SPRING_DATASOURCE_USERNAME and SPRING_DATASOURCE_PASSWORD environment variables in the script need to fill in the actual username and password +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +unset SPRING_SQL_INIT_MODE +export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_DATASOURCE_USERNAME="apollo-username" +export SPRING_DATASOURCE_PASSWORD="apollo-password" +java -jar apollo-all-in-one.jar +``` -## 3.3 Troubleshooting +# III. Additional Startup Instructions +## 3.1 Troubleshooting If you encounter an exception in the startup, you can check the log files in the service and portal directories respectively to troubleshoot the problem. -> Note: During start-up of apollo-configservice, eureka registration failure message will be output in the log, e.g. `com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused`. Note that this is expected because apollo-configservice needs to register the service with Meta Server (itself), but since it is not up yet during the startup process itself, this error is reported. A retry action will be performed later, so it will register properly when the service is up by itself. +> Note: During start-up, eureka registration failure message will be output in the log, e.g. `com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused`. Note that this is expected because apollo-configservice needs to register the service with Meta Server (itself), but since it is not up yet during the startup process itself, this error is reported. A retry action will be performed later, so it will register properly when the service is up by itself. -## 3.4 Note +## 3.2 Note Quick Start is only used to help you quickly experience Apollo project, please refer to: [distributed-deployment-guide](en/deployment/distributed-deployment-guide) for details. diff --git a/docs/zh/deployment/quick-start.md b/docs/zh/deployment/quick-start.md index 9b5ae5be14e..f968970061b 100644 --- a/docs/zh/deployment/quick-start.md +++ b/docs/zh/deployment/quick-start.md @@ -29,7 +29,7 @@ Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode) Windows用户请确保JAVA_HOME环境变量已经设置。 ## 1.2 MySQL - +* 如果使用 H2 内存数据库/H2 文件数据库,则无需 MySQL,可以跳过此步骤 * 版本要求:5.6.5+ Apollo的表结构对`timestamp`使用了多个default声明,所以需要5.6.5以上版本。 @@ -66,100 +66,100 @@ Quick Start只针对本地测试使用,所以一般用户不需要自己下载 2. 在根目录下执行`mvn clean package -pl apollo-assembly -am -DskipTests=true` 3. 复制apollo-assembly/target下的jar包,rename为apollo-all-in-one.jar -# 二、安装步骤 -## 2.1 创建数据库 -Apollo服务端共需要两个数据库:`ApolloPortalDB`和`ApolloConfigDB`,我们把数据库、表的创建和样例数据都分别准备了sql文件,只需要导入数据库即可。 - -> 注意:如果你本地已经创建过Apollo数据库,请注意备份数据。我们准备的sql文件会清空Apollo相关的表。 +# 二、数据库初始化及启动 +#### 注意事项 +1. apollo 服务端进程需要分别使用8070, 8080, 8090端口,请确保这3个端口当前没有被使用。 +2. 脚本中的 SPRING_PROFILES_ACTIVE 环境变量中的 `github` 是必须的 profile,`auth` 是 portal 提供简单认证的 profile,不需要认证或者使用其它认证方式时可以去掉 -### 2.1.1 创建ApolloPortalDB -通过各种MySQL客户端导入[sql/apolloportaldb.sql](https://github.com/apolloconfig/apollo-quick-start/blob/master/sql/apolloportaldb.sql)即可。 +## 2.1 使用 H2 内存数据库,自动初始化 +无需任何配置,直接使用如下命令启动即可 +> 注:使用内存数据库时,任何操作都会在 apollo 进程重启后丢失 +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +unset SPRING_SQL_INIT_MODE +java -jar apollo-all-in-one.jar -下面以MySQL原生客户端为例: -```sql -source /your_local_path/sql/apolloportaldb.sql ``` -导入成功后,可以通过执行以下sql语句来验证: -```sql -select `Id`, `AppId`, `Name` from ApolloPortalDB.App; -``` +## 2.2 使用 H2 文件数据库,自动初始化 +#### 注意事项 +1. 脚本中的 SPRING_DATASOURCE_URL 环境变量中的路径 `~/apollo/apolloassemblydb` 可以替换为其它自定义路径,需要保证该路径有读写权限 -| Id | AppId | Name | -|----|-----------|------------| -| 1 | SampleApp | Sample App | +### 2.2.1 首次启动 +首次启动使用 SPRING_SQL_INIT_MODE="always" 环境变量来进行初始化 +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +export SPRING_SQL_INIT_MODE="always" +export SPRING_DATASOURCE_URL="jdbc:h2:file:~/apollo/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +java -jar apollo-all-in-one.jar -### 2.1.2 创建ApolloConfigDB -通过各种MySQL客户端导入[sql/apolloconfigdb.sql](https://github.com/apolloconfig/apollo-quick-start/blob/master/sql/apolloconfigdb.sql)即可。 - -下面以MySQL原生客户端为例: -```sql -source /your_local_path/sql/apolloconfigdb.sql ``` -导入成功后,可以通过执行以下sql语句来验证: -```sql -select `NamespaceId`, `Key`, `Value`, `Comment` from ApolloConfigDB.Item; +### 2.2.2 后续启动 +后续启动去掉 SPRING_SQL_INIT_MODE 环境变量来避免重复初始化 +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +unset SPRING_SQL_INIT_MODE +export SPRING_DATASOURCE_URL="jdbc:h2:file:~/apollo/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +java -jar apollo-all-in-one.jar + ``` -| NamespaceId | Key | Value | Comment | -|-------------|---------|-------|--------------------| -| 1 | timeout | 100 | sample timeout配置 | -## 2.2 配置数据库连接信息 -Apollo服务端需要知道如何连接到你前面创建的数据库,所以需要编辑[demo.sh](https://github.com/apolloconfig/apollo-quick-start/blob/master/demo.sh),修改ApolloPortalDB和ApolloConfigDB相关的数据库连接串信息。 +## 2.3 使用 mysql 数据库,自动初始化 +#### 注意事项 +1. 脚本中的 SPRING_DATASOURCE_URL 环境变量中的 your-mysql-server:3306 需要替换为实际的 mysql 服务器地址和端口,ApolloAssemblyDB 需要替换为实际的数据库名称 +2. 脚本中的 SPRING_DATASOURCE_USERNAME 和 SPRING_DATASOURCE_PASSWORD 环境变量需要填写实际的用户名和密码 -> 注意:填入的用户需要具备对ApolloPortalDB和ApolloConfigDB数据的读写权限。 +### 2.3.1 首次启动 +首次启动使用 SPRING_SQL_INIT_MODE="always" 环境变量来进行初始化 +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +export SPRING_SQL_INIT_MODE="always" +export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_DATASOURCE_USERNAME="apollo-username" +export SPRING_DATASOURCE_PASSWORD="apollo-password" +java -jar apollo-all-in-one.jar -```sh -#apollo config db info -apollo_config_db_url="jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8&serverTimezone=Asia/Shanghai" -apollo_config_db_username=用户名 -apollo_config_db_password=密码(如果没有密码,留空即可) - -# apollo portal db info -apollo_portal_db_url="jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8&serverTimezone=Asia/Shanghai" -apollo_portal_db_username=用户名 -apollo_portal_db_password=密码(如果没有密码,留空即可) ``` -> 注意:不要修改demo.sh的其它部分 - -# 三、启动Apollo配置中心 -## 3.1 确保端口未被占用 -Quick Start脚本会在本地启动3个服务,分别使用8070, 8080, 8090端口,请确保这3个端口当前没有被使用。 +### 2.3.2 后续启动 +后续启动去掉 SPRING_SQL_INIT_MODE 环境变量来避免重复初始化 +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +unset SPRING_SQL_INIT_MODE +export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_DATASOURCE_USERNAME="apollo-username" +export SPRING_DATASOURCE_PASSWORD="apollo-password" +java -jar apollo-all-in-one.jar -例如,在Linux/Mac下,可以通过如下命令检查: -```sh -lsof -i:8080 ``` -## 3.2 执行启动脚本 -```sh -./demo.sh start -``` +## 2.4 使用 mysql 数据库,手动初始化 + +### 2.4.1 手动初始化 ApolloAssemblyDB +通过各种MySQL客户端导入 [sql/assembly](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/assembly) + +### 2.4.2 运行 +#### 注意事项 +1. 脚本中的 SPRING_DATASOURCE_URL 环境变量中的 your-mysql-server:3306 需要替换为实际的 mysql 服务器地址和端口,ApolloAssemblyDB 需要替换为实际的数据库名称 +2. 脚本中的 SPRING_DATASOURCE_USERNAME 和 SPRING_DATASOURCE_PASSWORD 环境变量需要填写实际的用户名和密码 +```bash +export SPRING_PROFILES_ACTIVE="github,auth" +unset SPRING_SQL_INIT_MODE +export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_DATASOURCE_USERNAME="apollo-username" +export SPRING_DATASOURCE_PASSWORD="apollo-password" +java -jar apollo-all-in-one.jar -当看到如下输出后,就说明启动成功了! -```sh -==== starting service ==== -Service logging file is ./service/apollo-service.log -Started [10768] -Waiting for config service startup....... -Config service started. You may visit http://localhost:8080 for service status now! -Waiting for admin service startup.... -Admin service started -==== starting portal ==== -Portal logging file is ./portal/apollo-portal.log -Started [10846] -Waiting for portal startup...... -Portal started. You can visit http://localhost:8070 now! ``` -## 3.3 异常排查 +# 三、启动额外说明 +## 3.1 异常排查 如果启动遇到了异常,可以分别查看service和portal目录下的log文件排查问题。 -> 注:在启动apollo-configservice的过程中会在日志中输出eureka注册失败的信息,如`com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused`。需要注意的是,这个是预期的情况,因为apollo-configservice需要向Meta Server(它自己)注册服务,但是因为在启动过程中,自己还没起来,所以会报这个错。后面会进行重试的动作,所以等自己服务起来后就会注册正常了。 +> 注:在启动的过程中会在日志中输出eureka注册失败的信息,如`com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectException: Connection refused`。需要注意的是,这个是预期的情况,因为apollo-configservice需要向Meta Server(它自己)注册服务,但是因为在启动过程中,自己还没起来,所以会报这个错。后面会进行重试的动作,所以等自己服务起来后就会注册正常了。 -## 3.4 注意 +## 3.2 注意 Quick Start只是用来帮助大家快速体验Apollo项目,具体实际使用时请参考:[分布式部署指南](zh/deployment/distributed-deployment-guide)。 另外需要注意的是Quick Start不支持增加环境,只有通过分布式部署才可以新增环境,同样请参考:[分布式部署指南](zh/deployment/distributed-deployment-guide) From d1590b504dd932ef930ac44df6fee4c9d33964fd Mon Sep 17 00:00:00 2001 From: vdisk Date: Mon, 18 Dec 2023 17:48:23 +0800 Subject: [PATCH 14/59] admin assembly profile --- ...AdminServiceAssemblyAutoConfiguration.java | 39 +++++++++++++++++++ .../AdminServiceAutoConfiguration.java | 19 --------- 2 files changed, 39 insertions(+), 19 deletions(-) create mode 100644 apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyAutoConfiguration.java diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyAutoConfiguration.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyAutoConfiguration.java new file mode 100644 index 00000000000..174ff1d0fa1 --- /dev/null +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyAutoConfiguration.java @@ -0,0 +1,39 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.adminservice; + +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.core.annotation.Order; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Profile("assembly") +@Configuration +public class AdminServiceAssemblyAutoConfiguration { + + @Order(99) + @Configuration + static class AdminServiceSecurityConfigurer extends WebSecurityConfigurerAdapter { + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.csrf().disable(); + http.httpBasic(); + } + } +} diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java index 481f67730af..ab7e6bb41dd 100644 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAutoConfiguration.java @@ -21,10 +21,6 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import org.springframework.core.annotation.Order; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Configuration public class AdminServiceAutoConfiguration { @@ -49,19 +45,4 @@ public FilterRegistrationBean adminServiceAuth return filterRegistrationBean; } - - /** - * for apollo-assembly - */ - @Order(99) - @Profile("assembly") - @Configuration - static class AdminServiceSecurityConfigurer extends WebSecurityConfigurerAdapter { - - @Override - protected void configure(HttpSecurity http) throws Exception { - http.csrf().disable(); - http.httpBasic(); - } - } } From 3000fa8735c68ba5415a5cc89d15c2968efc2108 Mon Sep 17 00:00:00 2001 From: vdisk Date: Mon, 18 Dec 2023 19:12:35 +0800 Subject: [PATCH 15/59] copy assembly sql on build --- apollo-assembly/pom.xml | 28 + ...lyDataSourceScriptDatabaseInitializer.java | 58 +- .../resources/application-github.properties | 2 +- scripts/sql/assembly/apolloconfigdb.sql | 498 ------------------ scripts/sql/assembly/apolloportaldb.sql | 434 --------------- .../sql/assembly}/h2/apolloconfigdb.sql | 0 .../sql/assembly}/h2/apolloportaldb.sql | 0 scripts/sql/assembly/h2/delta/.git.keep | 0 .../sql/assembly}/mysql/apolloconfigdb.sql | 0 .../sql/assembly}/mysql/apolloportaldb.sql | 0 scripts/sql/assembly/mysql/delta/.git.keep | 0 11 files changed, 85 insertions(+), 935 deletions(-) delete mode 100644 scripts/sql/assembly/apolloconfigdb.sql delete mode 100644 scripts/sql/assembly/apolloportaldb.sql rename {apollo-assembly/src/main/resources/jpa => scripts/sql/assembly}/h2/apolloconfigdb.sql (100%) rename {apollo-assembly/src/main/resources/jpa => scripts/sql/assembly}/h2/apolloportaldb.sql (100%) create mode 100644 scripts/sql/assembly/h2/delta/.git.keep rename {apollo-assembly/src/main/resources/jpa => scripts/sql/assembly}/mysql/apolloconfigdb.sql (100%) rename {apollo-assembly/src/main/resources/jpa => scripts/sql/assembly}/mysql/apolloportaldb.sql (100%) create mode 100644 scripts/sql/assembly/mysql/delta/.git.keep diff --git a/apollo-assembly/pom.xml b/apollo-assembly/pom.xml index 120244bf915..a90125d1061 100644 --- a/apollo-assembly/pom.xml +++ b/apollo-assembly/pom.xml @@ -46,6 +46,34 @@ + + org.apache.maven.plugins + maven-resources-plugin + 3.2.0 + + + copy-resources + validate + + copy-resources + + + ${project.build.directory}/classes/META-INF/sql/assembly + + + ${project.parent.basedir}/scripts/sql/assembly + + h2/apolloconfigdb.sql + h2/apolloportaldb.sql + mysql/apolloconfigdb.sql + mysql/apolloportaldb.sql + + + + + + + org.springframework.boot spring-boot-maven-plugin diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java index 0d135d8c19d..2ae988ca97b 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java @@ -16,6 +16,11 @@ */ package com.ctrip.framework.apollo.assembly.datasource; +import com.ctrip.framework.apollo.assembly.ApolloApplication; +import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.CodeSource; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -68,11 +73,60 @@ private static List resolveLocations(Collection locations, return null; } + Collection convertedLocations = convertRepositoryLocations(locations); + if (CollectionUtils.isEmpty(convertedLocations)) { + return null; + } + String platform = properties.getPlatform(); if (StringUtils.hasText(platform) && !"all".equals(platform)) { - return platformResolver.resolveAll(platform, locations.toArray(new String[0])); + return platformResolver.resolveAll(platform, convertedLocations.toArray(new String[0])); + } + return platformResolver.resolveAll(dataSource, convertedLocations.toArray(new String[0])); + } + + private static Collection convertRepositoryLocations(Collection locations) { + if (CollectionUtils.isEmpty(locations)) { + return null; + } + String repositoryDir = findRepositoryDirectory(); + List convertedLocations = new ArrayList<>(locations.size()); + for (String location : locations) { + String convertedLocation = convertRepositoryLocation(location, repositoryDir); + if (StringUtils.hasText(convertedLocation)) { + convertedLocations.add(convertedLocation); + } + } + return convertedLocations; + } + + private static String findRepositoryDirectory() { + CodeSource codeSource = ApolloApplication.class.getProtectionDomain().getCodeSource(); + URL location = codeSource != null ? codeSource.getLocation() : null; + if (location == null) { + return null; + } + if ("jar".equals(location.getProtocol())) { + // running with jar + return "classpath:META-INF/sql"; + } + if ("file".equals(location.getProtocol())) { + // running with ide + String locationText = location.toString(); + return locationText.replace("/apollo-assembly/target/classes/", "/scripts/sql"); + } + return null; + } + + private static String convertRepositoryLocation(String location, String repositoryDir) { + if (!StringUtils.hasText(location) || !location.contains("@@repository@@")) { + return location; + } + if (!StringUtils.hasText(repositoryDir)) { + // repository dir not found + return null; } - return platformResolver.resolveAll(dataSource, locations.toArray(new String[0])); + return location.replace("@@repository@@", repositoryDir); } private static List scriptLocations(List locations, String fallback, diff --git a/apollo-assembly/src/main/resources/application-github.properties b/apollo-assembly/src/main/resources/application-github.properties index f86ce05c34d..5f9a299c68b 100644 --- a/apollo-assembly/src/main/resources/application-github.properties +++ b/apollo-assembly/src/main/resources/application-github.properties @@ -25,7 +25,7 @@ spring.jpa.table-prefix.portal-prefix=P_0_ spring.session.jdbc.table-name=P_0_SPRING_SESSION # H2 datasource -spring.sql.init.schema-locations=classpath:jpa/@@platform@@/apolloconfigdb.sql, classpath:jpa/@@platform@@/apolloportaldb.sql +spring.sql.init.schema-locations=@@repository@@/assembly/@@platform@@/apolloconfigdb.sql, @@repository@@/assembly/@@platform@@/apolloportaldb.sql spring.sql.init.mode=embedded spring.jpa.hibernate.ddl-auto=none spring.jpa.properties.hibernate.show_sql=false diff --git a/scripts/sql/assembly/apolloconfigdb.sql b/scripts/sql/assembly/apolloconfigdb.sql deleted file mode 100644 index be387ebd752..00000000000 --- a/scripts/sql/assembly/apolloconfigdb.sql +++ /dev/null @@ -1,498 +0,0 @@ --- --- Copyright 2023 Apollo Authors --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - -# Create Database -# ------------------------------------------------------------ -CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; - -Use ApolloAssemblyDB; - -# Dump of table app -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_App`; - -CREATE TABLE `C_0_App` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', - `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', - `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', - `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', - `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_Name` (`Name`(191)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; - - - -# Dump of table appnamespace -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_AppNamespace`; - -CREATE TABLE `C_0_AppNamespace` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', - `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', - `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', - `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', - `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), - KEY `Name_AppId` (`Name`,`AppId`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; - - - -# Dump of table audit -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_Audit`; - -CREATE TABLE `C_0_Audit` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', - `EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID', - `OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', - `Comment` varchar(500) DEFAULT NULL COMMENT '备注', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表'; - - - -# Dump of table cluster -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_Cluster`; - -CREATE TABLE `C_0_Cluster` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', - `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id', - `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), - KEY `IX_ParentClusterId` (`ParentClusterId`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群'; - - - -# Dump of table commit -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_Commit`; - -CREATE TABLE `C_0_Commit` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `ChangeSets` longtext NOT NULL COMMENT '修改变更集', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', - `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', - `Comment` varchar(500) DEFAULT NULL COMMENT '备注', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `AppId` (`AppId`), - KEY `ClusterName` (`ClusterName`(191)), - KEY `NamespaceName` (`NamespaceName`(191)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表'; - -# Dump of table grayreleaserule -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_GrayReleaseRule`; - -CREATE TABLE `C_0_GrayReleaseRule` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', - `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', - `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name', - `Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则', - `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release', - `BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表'; - - -# Dump of table instance -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_Instance`; - -CREATE TABLE `C_0_Instance` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', - `DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name', - `Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`), - KEY `IX_IP` (`Ip`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例'; - - - -# Dump of table instanceconfig -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_InstanceConfig`; - -CREATE TABLE `C_0_InstanceConfig` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id', - `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id', - `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name', - `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name', - `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', - `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), - KEY `IX_ReleaseKey` (`ReleaseKey`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息'; - - - -# Dump of table item -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_Item`; - -CREATE TABLE `C_0_Item` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', - `Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key', - `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '配置项类型,0: String,1: Number,2: Boolean,3: JSON', - `Value` longtext NOT NULL COMMENT '配置项值', - `Comment` varchar(1024) DEFAULT '' COMMENT '注释', - `LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `IX_GroupId` (`NamespaceId`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目'; - - - -# Dump of table namespace -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_Namespace`; - -CREATE TABLE `C_0_Namespace` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', - `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_NamespaceName` (`NamespaceName`(191)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间'; - - - -# Dump of table namespacelock -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_NamespaceLock`; - -CREATE TABLE `C_0_NamespaceLock` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', - `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - `IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁'; - - - -# Dump of table release -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_Release`; - -CREATE TABLE `C_0_Release` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', - `Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字', - `Comment` varchar(256) DEFAULT NULL COMMENT '发布说明', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', - `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', - `Configurations` longtext NOT NULL COMMENT '发布配置', - `IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`), - KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布'; - - -# Dump of table releasehistory -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_ReleaseHistory`; - -CREATE TABLE `C_0_ReleaseHistory` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', - `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', - `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名', - `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id', - `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId', - `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度', - `OperationContext` longtext NOT NULL COMMENT '发布上下文信息', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), - KEY `IX_ReleaseId` (`ReleaseId`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_PreviousReleaseId` (`PreviousReleaseId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史'; - - -# Dump of table releasemessage -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_ReleaseMessage`; - -CREATE TABLE `C_0_ReleaseMessage` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容', - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_Message` (`Message`(191)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息'; - - - -# Dump of table serverconfig -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_ServerConfig`; - -CREATE TABLE `C_0_ServerConfig` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', - `Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群', - `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', - `Comment` varchar(1024) DEFAULT '' COMMENT '注释', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; - -# Dump of table accesskey -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_AccessKey`; - -CREATE TABLE `C_0_AccessKey` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret', - `IsEnabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: enabled, 0: disabled', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; - - -# Dump of table serviceregistry -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `C_0_ServiceRegistry`; - -CREATE TABLE `C_0_ServiceRegistry` ( - `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', - `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', - `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', - `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', - `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), - INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; - - -# Config -# ------------------------------------------------------------ -INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) -VALUES - ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), - ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), - ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'), - ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), - ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); - - -DROP TABLE IF EXISTS `C_0_AuditLog`; - -CREATE TABLE `C_0_AuditLog` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', - `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', - `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', - `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', - `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', - `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', - `Description` varchar(200) DEFAULT NULL COMMENT '备注', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `IX_TraceId` (`TraceId`), - KEY `IX_OpName` (`OpName`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_Operator` (`Operator`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; - - -DROP TABLE IF EXISTS `C_0_AuditLogDataInfluence`; - -CREATE TABLE `C_0_AuditLogDataInfluence` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', - `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', - `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', - `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', - `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `IX_SpanId` (`SpanId`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_EntityId` (`InfluenceEntityId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; - - -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/scripts/sql/assembly/apolloportaldb.sql b/scripts/sql/assembly/apolloportaldb.sql deleted file mode 100644 index dde438fa88e..00000000000 --- a/scripts/sql/assembly/apolloportaldb.sql +++ /dev/null @@ -1,434 +0,0 @@ --- --- Copyright 2023 Apollo Authors --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; -/*!40101 SET NAMES utf8 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; -/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; - -# Create Database -# ------------------------------------------------------------ -CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; - -Use ApolloAssemblyDB; - -# Dump of table app -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_App`; - -CREATE TABLE `P_0_App` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', - `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', - `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', - `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', - `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_Name` (`Name`(191)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; - - - -# Dump of table appnamespace -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_AppNamespace`; - -CREATE TABLE `P_0_AppNamespace` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', - `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', - `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', - `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', - `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', - `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), - KEY `Name_AppId` (`Name`,`AppId`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; - - - -# Dump of table consumer -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_Consumer`; - -CREATE TABLE `P_0_Consumer` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', - `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', - `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', - `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', - `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者'; - - - -# Dump of table consumeraudit -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_ConsumerAudit`; - -CREATE TABLE `P_0_ConsumerAudit` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', - `Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri', - `Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_ConsumerId` (`ConsumerId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表'; - - - -# Dump of table consumerrole -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_ConsumerRole`; - -CREATE TABLE `P_0_ConsumerRole` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', - `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_RoleId` (`RoleId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表'; - - - -# Dump of table consumertoken -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_ConsumerToken`; - -CREATE TABLE `P_0_ConsumerToken` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId', - `Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token', - `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_Token_DeletedAt` (`Token`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表'; - -# Dump of table favorite -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_Favorite`; - -CREATE TABLE `P_0_Favorite` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户', - `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', - `Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`), - KEY `AppId` (`AppId`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表'; - -# Dump of table permission -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_Permission`; - -CREATE TABLE `P_0_Permission` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型', - `TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表'; - - - -# Dump of table role -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_Role`; - -CREATE TABLE `P_0_Role` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; - - - -# Dump of table rolepermission -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_RolePermission`; - -CREATE TABLE `P_0_RolePermission` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', - `PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_PermissionId` (`PermissionId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表'; - - - -# Dump of table serverconfig -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_ServerConfig`; - -CREATE TABLE `P_0_ServerConfig` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', - `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', - `Comment` varchar(1024) DEFAULT '' COMMENT '注释', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_Key_DeletedAt` (`Key`,`DeletedAt`), - KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; - - - -# Dump of table userrole -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_UserRole`; - -CREATE TABLE `P_0_UserRole` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识', - `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`), - KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), - KEY `IX_RoleId` (`RoleId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表'; - -# Dump of table Users -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_Users`; - -CREATE TABLE `P_0_Users` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户', - `Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码', - `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称', - `Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址', - `Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效', - PRIMARY KEY (`Id`), - UNIQUE KEY `UK_Username` (`Username`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; - - -# Dump of table Authorities -# ------------------------------------------------------------ - -DROP TABLE IF EXISTS `P_0_Authorities`; - -CREATE TABLE `P_0_Authorities` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', - `Username` varchar(64) NOT NULL, - `Authority` varchar(50) NOT NULL, - PRIMARY KEY (`Id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - - -# Config -# ------------------------------------------------------------ -INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) -VALUES - ('apollo.portal.envs', 'dev', '可支持的环境列表'), - ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), - ('superAdmin', 'apollo', 'Portal超级管理员'), - ('api.readTimeout', '10000', 'http接口read timeout'), - ('consumer.token.salt', 'someSalt', 'consumer token salt'), - ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'), - ('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔'), - ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); - - -INSERT INTO `P_0_Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) -VALUES - ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); - -INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); - --- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) -CREATE TABLE `P_0_SPRING_SESSION` ( - PRIMARY_ID CHAR(36) NOT NULL, - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME BIGINT NOT NULL, - LAST_ACCESS_TIME BIGINT NOT NULL, - MAX_INACTIVE_INTERVAL INT NOT NULL, - EXPIRY_TIME BIGINT NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) -) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; - -CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON `P_0_SPRING_SESSION` (SESSION_ID); -CREATE INDEX SPRING_SESSION_IX2 ON `P_0_SPRING_SESSION` (EXPIRY_TIME); -CREATE INDEX SPRING_SESSION_IX3 ON `P_0_SPRING_SESSION` (PRINCIPAL_NAME); - -DROP TABLE IF EXISTS `P_0_SPRING_SESSION_ATTRIBUTES`; -CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( - SESSION_PRIMARY_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES `P_0_SPRING_SESSION`(PRIMARY_ID) ON DELETE CASCADE -) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; - - -DROP TABLE IF EXISTS `P_0_AuditLog`; - -CREATE TABLE `P_0_AuditLog` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', - `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', - `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', - `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', - `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', - `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', - `Description` varchar(200) DEFAULT NULL COMMENT '备注', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `IX_TraceId` (`TraceId`), - KEY `IX_OpName` (`OpName`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_Operator` (`Operator`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; - - -DROP TABLE IF EXISTS `P_0_AuditLogDataInfluence`; - -CREATE TABLE `P_0_AuditLogDataInfluence` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', - `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', - `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', - `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', - `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `IX_SpanId` (`SpanId`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_EntityId` (`InfluenceEntityId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; - - -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; -/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/apollo-assembly/src/main/resources/jpa/h2/apolloconfigdb.sql b/scripts/sql/assembly/h2/apolloconfigdb.sql similarity index 100% rename from apollo-assembly/src/main/resources/jpa/h2/apolloconfigdb.sql rename to scripts/sql/assembly/h2/apolloconfigdb.sql diff --git a/apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql b/scripts/sql/assembly/h2/apolloportaldb.sql similarity index 100% rename from apollo-assembly/src/main/resources/jpa/h2/apolloportaldb.sql rename to scripts/sql/assembly/h2/apolloportaldb.sql diff --git a/scripts/sql/assembly/h2/delta/.git.keep b/scripts/sql/assembly/h2/delta/.git.keep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apollo-assembly/src/main/resources/jpa/mysql/apolloconfigdb.sql b/scripts/sql/assembly/mysql/apolloconfigdb.sql similarity index 100% rename from apollo-assembly/src/main/resources/jpa/mysql/apolloconfigdb.sql rename to scripts/sql/assembly/mysql/apolloconfigdb.sql diff --git a/apollo-assembly/src/main/resources/jpa/mysql/apolloportaldb.sql b/scripts/sql/assembly/mysql/apolloportaldb.sql similarity index 100% rename from apollo-assembly/src/main/resources/jpa/mysql/apolloportaldb.sql rename to scripts/sql/assembly/mysql/apolloportaldb.sql diff --git a/scripts/sql/assembly/mysql/delta/.git.keep b/scripts/sql/assembly/mysql/delta/.git.keep new file mode 100644 index 00000000000..e69de29bb2d From 889943f37259bcfddfdb7428bfe8503d7412aab4 Mon Sep 17 00:00:00 2001 From: vdisk Date: Mon, 18 Dec 2023 19:21:33 +0800 Subject: [PATCH 16/59] merge sql conflict --- scripts/sql/assembly/mysql/apolloconfigdb.sql | 22 ++--- scripts/sql/assembly/mysql/apolloportaldb.sql | 88 +++++++++++-------- 2 files changed, 61 insertions(+), 49 deletions(-) diff --git a/scripts/sql/assembly/mysql/apolloconfigdb.sql b/scripts/sql/assembly/mysql/apolloconfigdb.sql index be387ebd752..e8b2bfb6b65 100644 --- a/scripts/sql/assembly/mysql/apolloconfigdb.sql +++ b/scripts/sql/assembly/mysql/apolloconfigdb.sql @@ -429,17 +429,8 @@ CREATE TABLE `C_0_ServiceRegistry` ( INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; - -# Config +# Dump of table AuditLog # ------------------------------------------------------------ -INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) -VALUES - ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), - ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), - ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'), - ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), - ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); - DROP TABLE IF EXISTS `C_0_AuditLog`; @@ -466,6 +457,8 @@ CREATE TABLE `C_0_AuditLog` ( KEY `IX_Operator` (`Operator`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; +# Dump of table AuditLogDataInfluence +# ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_AuditLogDataInfluence`; @@ -489,6 +482,15 @@ CREATE TABLE `C_0_AuditLogDataInfluence` ( KEY `IX_EntityId` (`InfluenceEntityId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; +# Config +# ------------------------------------------------------------ +INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +VALUES + ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), + ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), + ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'), + ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), + ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; diff --git a/scripts/sql/assembly/mysql/apolloportaldb.sql b/scripts/sql/assembly/mysql/apolloportaldb.sql index dde438fa88e..2e65c336bec 100644 --- a/scripts/sql/assembly/mysql/apolloportaldb.sql +++ b/scripts/sql/assembly/mysql/apolloportaldb.sql @@ -330,52 +330,41 @@ CREATE TABLE `P_0_Authorities` ( PRIMARY KEY (`Id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - -# Config +-- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) +# Dump of table SPRING_SESSION # ------------------------------------------------------------ -INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) -VALUES - ('apollo.portal.envs', 'dev', '可支持的环境列表'), - ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), - ('superAdmin', 'apollo', 'Portal超级管理员'), - ('api.readTimeout', '10000', 'http接口read timeout'), - ('consumer.token.salt', 'someSalt', 'consumer token salt'), - ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'), - ('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔'), - ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); - -INSERT INTO `P_0_Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) -VALUES - ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); +DROP TABLE IF EXISTS `P_0_SPRING_SESSION`; -INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); - --- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) CREATE TABLE `P_0_SPRING_SESSION` ( - PRIMARY_ID CHAR(36) NOT NULL, - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME BIGINT NOT NULL, - LAST_ACCESS_TIME BIGINT NOT NULL, - MAX_INACTIVE_INTERVAL INT NOT NULL, - EXPIRY_TIME BIGINT NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) -) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; - -CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON `P_0_SPRING_SESSION` (SESSION_ID); -CREATE INDEX SPRING_SESSION_IX2 ON `P_0_SPRING_SESSION` (EXPIRY_TIME); -CREATE INDEX SPRING_SESSION_IX3 ON `P_0_SPRING_SESSION` (PRINCIPAL_NAME); + `PRIMARY_ID` char(36) NOT NULL, + `SESSION_ID` char(36) NOT NULL, + `CREATION_TIME` bigint NOT NULL, + `LAST_ACCESS_TIME` bigint NOT NULL, + `MAX_INACTIVE_INTERVAL` int NOT NULL, + `EXPIRY_TIME` bigint NOT NULL, + `PRINCIPAL_NAME` varchar(100) DEFAULT NULL, + PRIMARY KEY (`PRIMARY_ID`), + UNIQUE KEY `SPRING_SESSION_IX1` (`SESSION_ID`), + KEY `SPRING_SESSION_IX2` (`EXPIRY_TIME`), + KEY `SPRING_SESSION_IX3` (`PRINCIPAL_NAME`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + +# Dump of table SPRING_SESSION_ATTRIBUTES +# ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_SPRING_SESSION_ATTRIBUTES`; -CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( - SESSION_PRIMARY_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES `P_0_SPRING_SESSION`(PRIMARY_ID) ON DELETE CASCADE -) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( + `SESSION_PRIMARY_ID` char(36) NOT NULL, + `ATTRIBUTE_NAME` varchar(200) NOT NULL, + `ATTRIBUTE_BYTES` blob NOT NULL, + PRIMARY KEY (`SESSION_PRIMARY_ID`,`ATTRIBUTE_NAME`), + CONSTRAINT `SPRING_SESSION_ATTRIBUTES_FK` FOREIGN KEY (`SESSION_PRIMARY_ID`) REFERENCES `P_0_SPRING_SESSION` (`PRIMARY_ID`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + +# Dump of table AuditLog +# ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_AuditLog`; @@ -402,6 +391,8 @@ CREATE TABLE `P_0_AuditLog` ( KEY `IX_Operator` (`Operator`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; +# Dump of table AuditLogDataInfluence +# ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_AuditLogDataInfluence`; @@ -425,6 +416,25 @@ CREATE TABLE `P_0_AuditLogDataInfluence` ( KEY `IX_EntityId` (`InfluenceEntityId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; +# Config +# ------------------------------------------------------------ +INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`) +VALUES + ('apollo.portal.envs', 'dev', '可支持的环境列表'), + ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), + ('superAdmin', 'apollo', 'Portal超级管理员'), + ('api.readTimeout', '10000', 'http接口read timeout'), + ('consumer.token.salt', 'someSalt', 'consumer token salt'), + ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'), + ('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔'), + ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); + + +INSERT INTO `Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) +VALUES + ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); + +INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; From 1782d5851b5f603edc5ab7d9575065489f59a89b Mon Sep 17 00:00:00 2001 From: vdisk Date: Mon, 18 Dec 2023 19:26:31 +0800 Subject: [PATCH 17/59] sql comment --- scripts/sql/assembly/mysql/apolloconfigdb.sql | 84 +++++++++---------- scripts/sql/assembly/mysql/apolloportaldb.sql | 80 +++++++++--------- 2 files changed, 82 insertions(+), 82 deletions(-) diff --git a/scripts/sql/assembly/mysql/apolloconfigdb.sql b/scripts/sql/assembly/mysql/apolloconfigdb.sql index e8b2bfb6b65..a8c4f1e8cf7 100644 --- a/scripts/sql/assembly/mysql/apolloconfigdb.sql +++ b/scripts/sql/assembly/mysql/apolloconfigdb.sql @@ -21,14 +21,14 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -# Create Database -# ------------------------------------------------------------ +-- Create Database +-- ------------------------------------------------------------ CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; Use ApolloAssemblyDB; -# Dump of table app -# ------------------------------------------------------------ +-- Dump of table app +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_App`; @@ -54,8 +54,8 @@ CREATE TABLE `C_0_App` ( -# Dump of table appnamespace -# ------------------------------------------------------------ +-- Dump of table appnamespace +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_AppNamespace`; @@ -80,8 +80,8 @@ CREATE TABLE `C_0_AppNamespace` ( -# Dump of table audit -# ------------------------------------------------------------ +-- Dump of table audit +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_Audit`; @@ -103,8 +103,8 @@ CREATE TABLE `C_0_Audit` ( -# Dump of table cluster -# ------------------------------------------------------------ +-- Dump of table cluster +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_Cluster`; @@ -127,8 +127,8 @@ CREATE TABLE `C_0_Cluster` ( -# Dump of table commit -# ------------------------------------------------------------ +-- Dump of table commit +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_Commit`; @@ -152,8 +152,8 @@ CREATE TABLE `C_0_Commit` ( KEY `NamespaceName` (`NamespaceName`(191)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表'; -# Dump of table grayreleaserule -# ------------------------------------------------------------ +-- Dump of table grayreleaserule +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_GrayReleaseRule`; @@ -178,8 +178,8 @@ CREATE TABLE `C_0_GrayReleaseRule` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表'; -# Dump of table instance -# ------------------------------------------------------------ +-- Dump of table instance +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_Instance`; @@ -199,8 +199,8 @@ CREATE TABLE `C_0_Instance` ( -# Dump of table instanceconfig -# ------------------------------------------------------------ +-- Dump of table instanceconfig +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_InstanceConfig`; @@ -223,8 +223,8 @@ CREATE TABLE `C_0_InstanceConfig` ( -# Dump of table item -# ------------------------------------------------------------ +-- Dump of table item +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_Item`; @@ -249,8 +249,8 @@ CREATE TABLE `C_0_Item` ( -# Dump of table namespace -# ------------------------------------------------------------ +-- Dump of table namespace +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_Namespace`; @@ -273,8 +273,8 @@ CREATE TABLE `C_0_Namespace` ( -# Dump of table namespacelock -# ------------------------------------------------------------ +-- Dump of table namespacelock +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_NamespaceLock`; @@ -294,8 +294,8 @@ CREATE TABLE `C_0_NamespaceLock` ( -# Dump of table release -# ------------------------------------------------------------ +-- Dump of table release +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_Release`; @@ -322,8 +322,8 @@ CREATE TABLE `C_0_Release` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布'; -# Dump of table releasehistory -# ------------------------------------------------------------ +-- Dump of table releasehistory +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_ReleaseHistory`; @@ -351,8 +351,8 @@ CREATE TABLE `C_0_ReleaseHistory` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史'; -# Dump of table releasemessage -# ------------------------------------------------------------ +-- Dump of table releasemessage +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_ReleaseMessage`; @@ -367,8 +367,8 @@ CREATE TABLE `C_0_ReleaseMessage` ( -# Dump of table serverconfig -# ------------------------------------------------------------ +-- Dump of table serverconfig +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_ServerConfig`; @@ -389,8 +389,8 @@ CREATE TABLE `C_0_ServerConfig` ( KEY `DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; -# Dump of table accesskey -# ------------------------------------------------------------ +-- Dump of table accesskey +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_AccessKey`; @@ -411,8 +411,8 @@ CREATE TABLE `C_0_AccessKey` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; -# Dump of table serviceregistry -# ------------------------------------------------------------ +-- Dump of table serviceregistry +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_ServiceRegistry`; @@ -429,8 +429,8 @@ CREATE TABLE `C_0_ServiceRegistry` ( INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; -# Dump of table AuditLog -# ------------------------------------------------------------ +-- Dump of table AuditLog +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_AuditLog`; @@ -457,8 +457,8 @@ CREATE TABLE `C_0_AuditLog` ( KEY `IX_Operator` (`Operator`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; -# Dump of table AuditLogDataInfluence -# ------------------------------------------------------------ +-- Dump of table AuditLogDataInfluence +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `C_0_AuditLogDataInfluence`; @@ -482,8 +482,8 @@ CREATE TABLE `C_0_AuditLogDataInfluence` ( KEY `IX_EntityId` (`InfluenceEntityId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; -# Config -# ------------------------------------------------------------ +-- Config +-- ------------------------------------------------------------ INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) VALUES ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), diff --git a/scripts/sql/assembly/mysql/apolloportaldb.sql b/scripts/sql/assembly/mysql/apolloportaldb.sql index 2e65c336bec..b00a34368c2 100644 --- a/scripts/sql/assembly/mysql/apolloportaldb.sql +++ b/scripts/sql/assembly/mysql/apolloportaldb.sql @@ -21,14 +21,14 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -# Create Database -# ------------------------------------------------------------ +-- Create Database +-- ------------------------------------------------------------ CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; Use ApolloAssemblyDB; -# Dump of table app -# ------------------------------------------------------------ +-- Dump of table app +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_App`; @@ -54,8 +54,8 @@ CREATE TABLE `P_0_App` ( -# Dump of table appnamespace -# ------------------------------------------------------------ +-- Dump of table appnamespace +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_AppNamespace`; @@ -80,8 +80,8 @@ CREATE TABLE `P_0_AppNamespace` ( -# Dump of table consumer -# ------------------------------------------------------------ +-- Dump of table consumer +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_Consumer`; @@ -106,8 +106,8 @@ CREATE TABLE `P_0_Consumer` ( -# Dump of table consumeraudit -# ------------------------------------------------------------ +-- Dump of table consumeraudit +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_ConsumerAudit`; @@ -125,8 +125,8 @@ CREATE TABLE `P_0_ConsumerAudit` ( -# Dump of table consumerrole -# ------------------------------------------------------------ +-- Dump of table consumerrole +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_ConsumerRole`; @@ -148,8 +148,8 @@ CREATE TABLE `P_0_ConsumerRole` ( -# Dump of table consumertoken -# ------------------------------------------------------------ +-- Dump of table consumertoken +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_ConsumerToken`; @@ -169,8 +169,8 @@ CREATE TABLE `P_0_ConsumerToken` ( KEY `DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表'; -# Dump of table favorite -# ------------------------------------------------------------ +-- Dump of table favorite +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_Favorite`; @@ -191,8 +191,8 @@ CREATE TABLE `P_0_Favorite` ( KEY `DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表'; -# Dump of table permission -# ------------------------------------------------------------ +-- Dump of table permission +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_Permission`; @@ -213,8 +213,8 @@ CREATE TABLE `P_0_Permission` ( -# Dump of table role -# ------------------------------------------------------------ +-- Dump of table role +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_Role`; @@ -234,8 +234,8 @@ CREATE TABLE `P_0_Role` ( -# Dump of table rolepermission -# ------------------------------------------------------------ +-- Dump of table rolepermission +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_RolePermission`; @@ -257,8 +257,8 @@ CREATE TABLE `P_0_RolePermission` ( -# Dump of table serverconfig -# ------------------------------------------------------------ +-- Dump of table serverconfig +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_ServerConfig`; @@ -280,8 +280,8 @@ CREATE TABLE `P_0_ServerConfig` ( -# Dump of table userrole -# ------------------------------------------------------------ +-- Dump of table userrole +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_UserRole`; @@ -301,8 +301,8 @@ CREATE TABLE `P_0_UserRole` ( KEY `IX_RoleId` (`RoleId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表'; -# Dump of table Users -# ------------------------------------------------------------ +-- Dump of table Users +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_Users`; @@ -318,8 +318,8 @@ CREATE TABLE `P_0_Users` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; -# Dump of table Authorities -# ------------------------------------------------------------ +-- Dump of table Authorities +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_Authorities`; @@ -331,8 +331,8 @@ CREATE TABLE `P_0_Authorities` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) -# Dump of table SPRING_SESSION -# ------------------------------------------------------------ +-- Dump of table SPRING_SESSION +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_SPRING_SESSION`; @@ -350,8 +350,8 @@ CREATE TABLE `P_0_SPRING_SESSION` ( KEY `SPRING_SESSION_IX3` (`PRINCIPAL_NAME`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; -# Dump of table SPRING_SESSION_ATTRIBUTES -# ------------------------------------------------------------ +-- Dump of table SPRING_SESSION_ATTRIBUTES +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_SPRING_SESSION_ATTRIBUTES`; @@ -363,8 +363,8 @@ CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( CONSTRAINT `SPRING_SESSION_ATTRIBUTES_FK` FOREIGN KEY (`SESSION_PRIMARY_ID`) REFERENCES `P_0_SPRING_SESSION` (`PRIMARY_ID`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; -# Dump of table AuditLog -# ------------------------------------------------------------ +-- Dump of table AuditLog +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_AuditLog`; @@ -391,8 +391,8 @@ CREATE TABLE `P_0_AuditLog` ( KEY `IX_Operator` (`Operator`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; -# Dump of table AuditLogDataInfluence -# ------------------------------------------------------------ +-- Dump of table AuditLogDataInfluence +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `P_0_AuditLogDataInfluence`; @@ -416,8 +416,8 @@ CREATE TABLE `P_0_AuditLogDataInfluence` ( KEY `IX_EntityId` (`InfluenceEntityId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; -# Config -# ------------------------------------------------------------ +-- Config +-- ------------------------------------------------------------ INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`) VALUES ('apollo.portal.envs', 'dev', '可支持的环境列表'), From 497fb9f050f8527278c680c119711c9404088d7c Mon Sep 17 00:00:00 2001 From: vdisk Date: Mon, 18 Dec 2023 23:09:52 +0800 Subject: [PATCH 18/59] sql converter --- apollo-build-maven-extensions/pom.xml | 67 ++++++ .../ApolloAssemblySqlConverter.java | 201 ++++++++++++++++++ pom.xml | 1 + scripts/sql/apolloconfigdb.sql | 84 ++++---- scripts/sql/apolloportaldb.sql | 82 +++---- scripts/sql/assembly/h2/apolloconfigdb.sql | 98 ++++----- scripts/sql/assembly/h2/apolloportaldb.sql | 170 ++++++++------- 7 files changed, 492 insertions(+), 211 deletions(-) create mode 100644 apollo-build-maven-extensions/pom.xml create mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java diff --git a/apollo-build-maven-extensions/pom.xml b/apollo-build-maven-extensions/pom.xml new file mode 100644 index 00000000000..85683a10868 --- /dev/null +++ b/apollo-build-maven-extensions/pom.xml @@ -0,0 +1,67 @@ + + + + + com.ctrip.framework.apollo + apollo + ${revision} + ../pom.xml + + 4.0.0 + apollo-build-maven-extensions + Apollo Build Maven Extensions + + + + + sql-convert + + false + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.codehaus.mojo + exec-maven-plugin + 3.0.0 + + + sql-convert + compile + + java + + + + + com.ctrip.framework.apollo.maven.extensions.ApolloAssemblySqlConverter + + ${project.basedir} + + + + + + + + diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java new file mode 100644 index 00000000000..e36874ca14b --- /dev/null +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java @@ -0,0 +1,201 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.maven.extensions; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ApolloAssemblySqlConverter { + + public static void main(String[] args) { + String moduleDir = args[0]; + String unixModuleDir = moduleDir.replace("\\", "/"); + String repositoryDir = unixModuleDir.replace("/apollo-build-maven-extensions", ""); + + String assemblyMysqlDir = repositoryDir + "/scripts/sql/assembly/mysql"; + + List assemblyMysqlSqlList = new ArrayList<>(); + assemblyMysqlSqlList.add(assemblyMysqlDir + "/apolloconfigdb.sql"); + assemblyMysqlSqlList.add(assemblyMysqlDir + "/apolloportaldb.sql"); + List assemblyMysqlDeltaSqlList = getAssemblyMysqlDeltaSqlList(assemblyMysqlDir); + assemblyMysqlSqlList.addAll(assemblyMysqlDeltaSqlList); + + // '/scripts/sql/assembly/mysql' -> '/scripts/sql' + convertMainMysqlList(assemblyMysqlSqlList, assemblyMysqlDir, repositoryDir); + + // '/scripts/sql/assembly/mysql' -> '/scripts/sql/assembly/h2' + convertAssemblyH2List(assemblyMysqlSqlList, assemblyMysqlDir, repositoryDir); + } + + private static void convertMainMysqlList(List assemblyMysqlSqlList, + String assemblyMysqlDir, String repositoryDir) { + String targetDir = repositoryDir + "/scripts/sql"; + for (String filePath : assemblyMysqlSqlList) { + String targetFilePath = filePath.replace(assemblyMysqlDir, targetDir); + String databaseName; + if (filePath.contains("apolloconfigdb")) { + databaseName = "ApolloConfigDB"; + } else if (filePath.contains("apolloportaldb")) { + databaseName = "ApolloPortalDB"; + } else { + throw new IllegalArgumentException("unknown database name: " + filePath); + } + try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(filePath), + StandardCharsets.UTF_8); + BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetFilePath), + StandardCharsets.UTF_8, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING)) { + for (String line = bufferedReader.readLine(); line != null; + line = bufferedReader.readLine()) { + String convertedLine = line.replace("P_0_", "").replace("C_0_", "") + .replace("ApolloAssemblyDB", databaseName); + bufferedWriter.write(convertedLine); + bufferedWriter.write('\n'); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + private static void convertAssemblyH2List(List assemblyMysqlSqlList, + String assemblyMysqlDir, String repositoryDir) { + String targetDir = repositoryDir + "/scripts/sql/assembly/h2"; + for (String filePath : assemblyMysqlSqlList) { + String targetFilePath = filePath.replace(assemblyMysqlDir, targetDir); + try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(filePath), + StandardCharsets.UTF_8); + BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetFilePath), + StandardCharsets.UTF_8, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING)) { + for (String line = bufferedReader.readLine(); line != null; + line = bufferedReader.readLine()) { + String convertedLine = convertAssemblyH2ListLine(line); + bufferedWriter.write(convertedLine); + bufferedWriter.write('\n'); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + private static String convertAssemblyH2ListLine(String line) { + // database config + if (line.contains("Use ") + || line.contains("DROP TABLE")) { + return ""; + } else if (line.contains("CREATE DATABASE")) { + return "CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR \"com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp\";"; + } + String convertedLine = line; + + // table config + if (convertedLine.contains("ENGINE=InnoDB")) { + convertedLine = convertedLine.replace("ENGINE=InnoDB", ""); + } + if (convertedLine.contains("DEFAULT CHARSET=utf8mb4")) { + convertedLine = convertedLine.replace("DEFAULT CHARSET=utf8mb4", ""); + } + if (convertedLine.contains("ROW_FORMAT=DYNAMIC")) { + convertedLine = convertedLine.replace("ROW_FORMAT=DYNAMIC", ""); + } + Pattern tableCommentPattern = Pattern.compile("COMMENT='[^']*'"); + Matcher tableCommentMatcher = tableCommentPattern.matcher(convertedLine); + if (tableCommentMatcher.find()) { + convertedLine = tableCommentMatcher.replaceAll(""); + } + + // index + if (line.contains("KEY")) { + Pattern indexNamePattern = Pattern.compile("KEY *`[a-zA-Z0-9\\-_]+` *"); + Matcher indexNameMatcher = indexNamePattern.matcher(convertedLine); + if (indexNameMatcher.find()) { + convertedLine = indexNameMatcher.replaceAll("KEY "); + } + Pattern indexPrefixPattern = Pattern.compile("(`[a-zA-Z0-9\\-_]+`)\\([0-9]+\\)"); + for (Matcher indexPrefixMatcher = indexPrefixPattern.matcher(convertedLine); + indexPrefixMatcher.find(); + indexPrefixMatcher = indexPrefixPattern.matcher(convertedLine)) { + convertedLine = indexPrefixMatcher.replaceAll("$1"); + } + } + + // column config + if (line.contains("bit(1)")) { + convertedLine = convertedLine.replace("bit(1)", "boolean"); + } + if (line.contains("b'0'")) { + convertedLine = convertedLine.replace("b'0'", "FALSE"); + } + Pattern columnCommentPattern = Pattern.compile("COMMENT *'[^']*'"); + Matcher columnCommentMatcher = columnCommentPattern.matcher(convertedLine); + if (columnCommentMatcher.find()) { + convertedLine = columnCommentMatcher.replaceAll(""); + } + + // white space + Pattern whiteSpacePrefixPattern = Pattern.compile("^(\\s+)"); + Matcher whiteSpacePrefixMatcher = whiteSpacePrefixPattern.matcher(convertedLine); + String whiteSpacePrefix; + if (whiteSpacePrefixMatcher.find()) { + whiteSpacePrefix = whiteSpacePrefixMatcher.group(1); + } else { + whiteSpacePrefix = ""; + } + + Pattern whiteSpacePattern = Pattern.compile("\\s{2,}"); + Matcher whiteSpaceMatcher = whiteSpacePattern.matcher(convertedLine); + if (whiteSpaceMatcher.find()) { + convertedLine = whiteSpaceMatcher.replaceAll(" "); + } + return whiteSpacePrefix + convertedLine.trim(); + } + + private static List getAssemblyMysqlDeltaSqlList(String assemblyMysqlDir) { + Path dir = Paths.get(assemblyMysqlDir + "/delta"); + if (!Files.exists(dir)) { + return Collections.emptyList(); + } + List assemblyMysqlDeltaSqlList = new ArrayList<>(); + try (DirectoryStream ds = Files.newDirectoryStream(dir)) { + for (Path path : ds) { + String fileName = path.toString(); + if (fileName.endsWith(".sql")) { + assemblyMysqlDeltaSqlList.add(fileName); + } + } + } catch (IOException e) { + throw new UncheckedIOException("failed to open assemblyMysqlDir" + e.getLocalizedMessage(), + e); + } + return assemblyMysqlDeltaSqlList; + } +} diff --git a/pom.xml b/pom.xml index 222574ce2f8..fa3ad3a63eb 100644 --- a/pom.xml +++ b/pom.xml @@ -95,6 +95,7 @@ + apollo-build-maven-extensions apollo-buildtools apollo-common apollo-biz diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index ee22e66587c..dbcca407a86 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -21,14 +21,14 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -# Create Database -# ------------------------------------------------------------ +-- Create Database +-- ------------------------------------------------------------ CREATE DATABASE IF NOT EXISTS ApolloConfigDB DEFAULT CHARACTER SET = utf8mb4; Use ApolloConfigDB; -# Dump of table app -# ------------------------------------------------------------ +-- Dump of table app +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `App`; @@ -54,8 +54,8 @@ CREATE TABLE `App` ( -# Dump of table appnamespace -# ------------------------------------------------------------ +-- Dump of table appnamespace +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `AppNamespace`; @@ -80,8 +80,8 @@ CREATE TABLE `AppNamespace` ( -# Dump of table audit -# ------------------------------------------------------------ +-- Dump of table audit +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Audit`; @@ -103,8 +103,8 @@ CREATE TABLE `Audit` ( -# Dump of table cluster -# ------------------------------------------------------------ +-- Dump of table cluster +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Cluster`; @@ -127,8 +127,8 @@ CREATE TABLE `Cluster` ( -# Dump of table commit -# ------------------------------------------------------------ +-- Dump of table commit +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Commit`; @@ -152,8 +152,8 @@ CREATE TABLE `Commit` ( KEY `NamespaceName` (`NamespaceName`(191)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表'; -# Dump of table grayreleaserule -# ------------------------------------------------------------ +-- Dump of table grayreleaserule +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `GrayReleaseRule`; @@ -178,8 +178,8 @@ CREATE TABLE `GrayReleaseRule` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表'; -# Dump of table instance -# ------------------------------------------------------------ +-- Dump of table instance +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Instance`; @@ -199,8 +199,8 @@ CREATE TABLE `Instance` ( -# Dump of table instanceconfig -# ------------------------------------------------------------ +-- Dump of table instanceconfig +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `InstanceConfig`; @@ -223,8 +223,8 @@ CREATE TABLE `InstanceConfig` ( -# Dump of table item -# ------------------------------------------------------------ +-- Dump of table item +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Item`; @@ -249,8 +249,8 @@ CREATE TABLE `Item` ( -# Dump of table namespace -# ------------------------------------------------------------ +-- Dump of table namespace +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Namespace`; @@ -273,8 +273,8 @@ CREATE TABLE `Namespace` ( -# Dump of table namespacelock -# ------------------------------------------------------------ +-- Dump of table namespacelock +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `NamespaceLock`; @@ -294,8 +294,8 @@ CREATE TABLE `NamespaceLock` ( -# Dump of table release -# ------------------------------------------------------------ +-- Dump of table release +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Release`; @@ -322,8 +322,8 @@ CREATE TABLE `Release` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布'; -# Dump of table releasehistory -# ------------------------------------------------------------ +-- Dump of table releasehistory +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `ReleaseHistory`; @@ -351,8 +351,8 @@ CREATE TABLE `ReleaseHistory` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史'; -# Dump of table releasemessage -# ------------------------------------------------------------ +-- Dump of table releasemessage +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `ReleaseMessage`; @@ -367,8 +367,8 @@ CREATE TABLE `ReleaseMessage` ( -# Dump of table serverconfig -# ------------------------------------------------------------ +-- Dump of table serverconfig +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `ServerConfig`; @@ -389,8 +389,8 @@ CREATE TABLE `ServerConfig` ( KEY `DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; -# Dump of table accesskey -# ------------------------------------------------------------ +-- Dump of table accesskey +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `AccessKey`; @@ -411,8 +411,8 @@ CREATE TABLE `AccessKey` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; -# Dump of table serviceregistry -# ------------------------------------------------------------ +-- Dump of table serviceregistry +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `ServiceRegistry`; @@ -429,8 +429,8 @@ CREATE TABLE `ServiceRegistry` ( INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; -# Dump of table AuditLog -# ------------------------------------------------------------ +-- Dump of table AuditLog +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `AuditLog`; @@ -457,8 +457,8 @@ CREATE TABLE `AuditLog` ( KEY `IX_Operator` (`Operator`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; -# Dump of table AuditLogDataInfluence -# ------------------------------------------------------------ +-- Dump of table AuditLogDataInfluence +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `AuditLogDataInfluence`; @@ -482,8 +482,8 @@ CREATE TABLE `AuditLogDataInfluence` ( KEY `IX_EntityId` (`InfluenceEntityId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; -# Config -# ------------------------------------------------------------ +-- Config +-- ------------------------------------------------------------ INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) VALUES ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), diff --git a/scripts/sql/apolloportaldb.sql b/scripts/sql/apolloportaldb.sql index c49b382053d..14c2b88e2bf 100644 --- a/scripts/sql/apolloportaldb.sql +++ b/scripts/sql/apolloportaldb.sql @@ -21,14 +21,14 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -# Create Database -# ------------------------------------------------------------ +-- Create Database +-- ------------------------------------------------------------ CREATE DATABASE IF NOT EXISTS ApolloPortalDB DEFAULT CHARACTER SET = utf8mb4; Use ApolloPortalDB; -# Dump of table app -# ------------------------------------------------------------ +-- Dump of table app +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `App`; @@ -54,8 +54,8 @@ CREATE TABLE `App` ( -# Dump of table appnamespace -# ------------------------------------------------------------ +-- Dump of table appnamespace +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `AppNamespace`; @@ -80,8 +80,8 @@ CREATE TABLE `AppNamespace` ( -# Dump of table consumer -# ------------------------------------------------------------ +-- Dump of table consumer +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Consumer`; @@ -106,8 +106,8 @@ CREATE TABLE `Consumer` ( -# Dump of table consumeraudit -# ------------------------------------------------------------ +-- Dump of table consumeraudit +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `ConsumerAudit`; @@ -125,8 +125,8 @@ CREATE TABLE `ConsumerAudit` ( -# Dump of table consumerrole -# ------------------------------------------------------------ +-- Dump of table consumerrole +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `ConsumerRole`; @@ -148,8 +148,8 @@ CREATE TABLE `ConsumerRole` ( -# Dump of table consumertoken -# ------------------------------------------------------------ +-- Dump of table consumertoken +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `ConsumerToken`; @@ -169,8 +169,8 @@ CREATE TABLE `ConsumerToken` ( KEY `DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表'; -# Dump of table favorite -# ------------------------------------------------------------ +-- Dump of table favorite +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Favorite`; @@ -191,8 +191,8 @@ CREATE TABLE `Favorite` ( KEY `DataChange_LastTime` (`DataChange_LastTime`) ) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表'; -# Dump of table permission -# ------------------------------------------------------------ +-- Dump of table permission +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Permission`; @@ -213,8 +213,8 @@ CREATE TABLE `Permission` ( -# Dump of table role -# ------------------------------------------------------------ +-- Dump of table role +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Role`; @@ -234,8 +234,8 @@ CREATE TABLE `Role` ( -# Dump of table rolepermission -# ------------------------------------------------------------ +-- Dump of table rolepermission +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `RolePermission`; @@ -257,8 +257,8 @@ CREATE TABLE `RolePermission` ( -# Dump of table serverconfig -# ------------------------------------------------------------ +-- Dump of table serverconfig +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `ServerConfig`; @@ -280,8 +280,8 @@ CREATE TABLE `ServerConfig` ( -# Dump of table userrole -# ------------------------------------------------------------ +-- Dump of table userrole +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `UserRole`; @@ -301,8 +301,8 @@ CREATE TABLE `UserRole` ( KEY `IX_RoleId` (`RoleId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表'; -# Dump of table Users -# ------------------------------------------------------------ +-- Dump of table Users +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Users`; @@ -318,8 +318,8 @@ CREATE TABLE `Users` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; -# Dump of table Authorities -# ------------------------------------------------------------ +-- Dump of table Authorities +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `Authorities`; @@ -331,8 +331,8 @@ CREATE TABLE `Authorities` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) -# Dump of table SPRING_SESSION -# ------------------------------------------------------------ +-- Dump of table SPRING_SESSION +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `SPRING_SESSION`; @@ -350,8 +350,8 @@ CREATE TABLE `SPRING_SESSION` ( KEY `SPRING_SESSION_IX3` (`PRINCIPAL_NAME`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; -# Dump of table SPRING_SESSION_ATTRIBUTES -# ------------------------------------------------------------ +-- Dump of table SPRING_SESSION_ATTRIBUTES +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `SPRING_SESSION_ATTRIBUTES`; @@ -363,8 +363,8 @@ CREATE TABLE `SPRING_SESSION_ATTRIBUTES` ( CONSTRAINT `SPRING_SESSION_ATTRIBUTES_FK` FOREIGN KEY (`SESSION_PRIMARY_ID`) REFERENCES `SPRING_SESSION` (`PRIMARY_ID`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; -# Dump of table AuditLog -# ------------------------------------------------------------ +-- Dump of table AuditLog +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `AuditLog`; @@ -391,8 +391,8 @@ CREATE TABLE `AuditLog` ( KEY `IX_Operator` (`Operator`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; -# Dump of table AuditLogDataInfluence -# ------------------------------------------------------------ +-- Dump of table AuditLogDataInfluence +-- ------------------------------------------------------------ DROP TABLE IF EXISTS `AuditLogDataInfluence`; @@ -416,8 +416,8 @@ CREATE TABLE `AuditLogDataInfluence` ( KEY `IX_EntityId` (`InfluenceEntityId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; -# Config -# ------------------------------------------------------------ +-- Config +-- ------------------------------------------------------------ INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`) VALUES ('apollo.portal.envs', 'dev', '可支持的环境列表'), @@ -441,4 +441,4 @@ INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; \ No newline at end of file +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/scripts/sql/assembly/h2/apolloconfigdb.sql b/scripts/sql/assembly/h2/apolloconfigdb.sql index a9cb0b88863..c6ea3cde6d4 100644 --- a/scripts/sql/assembly/h2/apolloconfigdb.sql +++ b/scripts/sql/assembly/h2/apolloconfigdb.sql @@ -21,14 +21,14 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- Create Database +-- ------------------------------------------------------------ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; - - - - +-- Dump of table app +-- ------------------------------------------------------------ @@ -54,13 +54,13 @@ CREATE TABLE `C_0_App` ( - - +-- Dump of table appnamespace +-- ------------------------------------------------------------ CREATE TABLE `C_0_AppNamespace` ( - `Id` int(10) NOT NULL AUTO_INCREMENT , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Name` varchar(32) NOT NULL DEFAULT '' , `AppId` varchar(64) NOT NULL DEFAULT '' , `Format` varchar(32) NOT NULL DEFAULT 'properties' , @@ -80,8 +80,8 @@ CREATE TABLE `C_0_AppNamespace` ( - - +-- Dump of table audit +-- ------------------------------------------------------------ @@ -103,8 +103,8 @@ CREATE TABLE `C_0_Audit` ( - - +-- Dump of table cluster +-- ------------------------------------------------------------ @@ -127,8 +127,8 @@ CREATE TABLE `C_0_Cluster` ( - - +-- Dump of table commit +-- ------------------------------------------------------------ @@ -152,8 +152,8 @@ CREATE TABLE `C_0_Commit` ( KEY (`NamespaceName`) ) ; - - +-- Dump of table grayreleaserule +-- ------------------------------------------------------------ @@ -178,8 +178,8 @@ CREATE TABLE `C_0_GrayReleaseRule` ( ) ; - - +-- Dump of table instance +-- ------------------------------------------------------------ @@ -199,8 +199,8 @@ CREATE TABLE `C_0_Instance` ( - - +-- Dump of table instanceconfig +-- ------------------------------------------------------------ @@ -223,8 +223,8 @@ CREATE TABLE `C_0_InstanceConfig` ( - - +-- Dump of table item +-- ------------------------------------------------------------ @@ -249,8 +249,8 @@ CREATE TABLE `C_0_Item` ( - - +-- Dump of table namespace +-- ------------------------------------------------------------ @@ -273,8 +273,8 @@ CREATE TABLE `C_0_Namespace` ( - - +-- Dump of table namespacelock +-- ------------------------------------------------------------ @@ -294,8 +294,8 @@ CREATE TABLE `C_0_NamespaceLock` ( - - +-- Dump of table release +-- ------------------------------------------------------------ @@ -322,8 +322,8 @@ CREATE TABLE `C_0_Release` ( ) ; - - +-- Dump of table releasehistory +-- ------------------------------------------------------------ @@ -351,8 +351,8 @@ CREATE TABLE `C_0_ReleaseHistory` ( ) ; - - +-- Dump of table releasemessage +-- ------------------------------------------------------------ @@ -367,8 +367,8 @@ CREATE TABLE `C_0_ReleaseMessage` ( - - +-- Dump of table serverconfig +-- ------------------------------------------------------------ @@ -389,8 +389,8 @@ CREATE TABLE `C_0_ServerConfig` ( KEY (`DataChange_LastTime`) ) ; - - +-- Dump of table accesskey +-- ------------------------------------------------------------ @@ -411,8 +411,8 @@ CREATE TABLE `C_0_AccessKey` ( ) ; - - +-- Dump of table serviceregistry +-- ------------------------------------------------------------ @@ -429,17 +429,8 @@ CREATE TABLE `C_0_ServiceRegistry` ( INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) ) ; - - - -INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) -VALUES - ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), - ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), - ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'), - ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), - ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); - +-- Dump of table AuditLog +-- ------------------------------------------------------------ @@ -466,6 +457,8 @@ CREATE TABLE `C_0_AuditLog` ( KEY (`Operator`) ) ; +-- Dump of table AuditLogDataInfluence +-- ------------------------------------------------------------ @@ -489,6 +482,15 @@ CREATE TABLE `C_0_AuditLogDataInfluence` ( KEY (`InfluenceEntityId`) ) ; +-- Config +-- ------------------------------------------------------------ +INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +VALUES + ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), + ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), + ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'), + ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), + ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; diff --git a/scripts/sql/assembly/h2/apolloportaldb.sql b/scripts/sql/assembly/h2/apolloportaldb.sql index 26ebca6a79d..8879dd4f792 100644 --- a/scripts/sql/assembly/h2/apolloportaldb.sql +++ b/scripts/sql/assembly/h2/apolloportaldb.sql @@ -21,14 +21,14 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- Create Database +-- ------------------------------------------------------------ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; - - - - +-- Dump of table app +-- ------------------------------------------------------------ @@ -54,8 +54,8 @@ CREATE TABLE `P_0_App` ( - - +-- Dump of table appnamespace +-- ------------------------------------------------------------ @@ -76,12 +76,12 @@ CREATE TABLE `P_0_AppNamespace` ( UNIQUE KEY (`AppId`,`Name`,`DeletedAt`), KEY (`Name`,`AppId`), KEY (`DataChange_LastTime`) -) ; - - +) ; +-- Dump of table consumer +-- ------------------------------------------------------------ @@ -102,12 +102,12 @@ CREATE TABLE `P_0_Consumer` ( PRIMARY KEY (`Id`), UNIQUE KEY (`AppId`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; - - +) ; +-- Dump of table consumeraudit +-- ------------------------------------------------------------ @@ -121,12 +121,12 @@ CREATE TABLE `P_0_ConsumerAudit` ( PRIMARY KEY (`Id`), KEY (`DataChange_LastTime`), KEY (`ConsumerId`) -) ; - - +) ; +-- Dump of table consumerrole +-- ------------------------------------------------------------ @@ -144,12 +144,12 @@ CREATE TABLE `P_0_ConsumerRole` ( UNIQUE KEY (`ConsumerId`,`RoleId`,`DeletedAt`), KEY (`DataChange_LastTime`), KEY (`RoleId`) -) ; - - +) ; +-- Dump of table consumertoken +-- ------------------------------------------------------------ @@ -167,10 +167,10 @@ CREATE TABLE `P_0_ConsumerToken` ( PRIMARY KEY (`Id`), UNIQUE KEY (`Token`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; - - +) ; +-- Dump of table favorite +-- ------------------------------------------------------------ @@ -189,10 +189,10 @@ CREATE TABLE `P_0_Favorite` ( UNIQUE KEY (`UserId`,`AppId`,`DeletedAt`), KEY (`AppId`), KEY (`DataChange_LastTime`) -) AUTO_INCREMENT=23 ; - - +) AUTO_INCREMENT=23 ; +-- Dump of table permission +-- ------------------------------------------------------------ @@ -209,12 +209,12 @@ CREATE TABLE `P_0_Permission` ( PRIMARY KEY (`Id`), UNIQUE KEY (`TargetId`,`PermissionType`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; - - +) ; +-- Dump of table role +-- ------------------------------------------------------------ @@ -230,12 +230,12 @@ CREATE TABLE `P_0_Role` ( PRIMARY KEY (`Id`), UNIQUE KEY (`RoleName`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; - - +) ; +-- Dump of table rolepermission +-- ------------------------------------------------------------ @@ -253,12 +253,12 @@ CREATE TABLE `P_0_RolePermission` ( UNIQUE KEY (`RoleId`,`PermissionId`,`DeletedAt`), KEY (`DataChange_LastTime`), KEY (`PermissionId`) -) ; - - +) ; +-- Dump of table serverconfig +-- ------------------------------------------------------------ @@ -276,12 +276,12 @@ CREATE TABLE `P_0_ServerConfig` ( PRIMARY KEY (`Id`), UNIQUE KEY (`Key`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; - - +) ; +-- Dump of table userrole +-- ------------------------------------------------------------ @@ -299,10 +299,10 @@ CREATE TABLE `P_0_UserRole` ( UNIQUE KEY (`UserId`,`RoleId`,`DeletedAt`), KEY (`DataChange_LastTime`), KEY (`RoleId`) -) ; - - +) ; +-- Dump of table Users +-- ------------------------------------------------------------ @@ -315,11 +315,11 @@ CREATE TABLE `P_0_Users` ( `Enabled` tinyint(4) DEFAULT NULL , PRIMARY KEY (`Id`), UNIQUE KEY (`Username`) -) ; - - +) ; +-- Dump of table Authorities +-- ------------------------------------------------------------ @@ -328,54 +328,43 @@ CREATE TABLE `P_0_Authorities` ( `Username` varchar(64) NOT NULL, `Authority` varchar(50) NOT NULL, PRIMARY KEY (`Id`) -) ; - - - +) ; -INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) -VALUES - ('apollo.portal.envs', 'dev', '可支持的环境列表'), - ('organizations', '[{"orgId":"TEST1","orgName":"样例部门1"},{"orgId":"TEST2","orgName":"样例部门2"}]', '部门列表'), - ('superAdmin', 'apollo', 'Portal超级管理员'), - ('api.readTimeout', '10000', 'http接口read timeout'), - ('consumer.token.salt', 'someSalt', 'consumer token salt'), - ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'), - ('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔'), - ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); +-- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) +-- Dump of table SPRING_SESSION +-- ------------------------------------------------------------ -INSERT INTO `P_0_Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) -VALUES - ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); -INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); - --- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) CREATE TABLE `P_0_SPRING_SESSION` ( - PRIMARY_ID CHAR(36) NOT NULL, - SESSION_ID CHAR(36) NOT NULL, - CREATION_TIME BIGINT NOT NULL, - LAST_ACCESS_TIME BIGINT NOT NULL, - MAX_INACTIVE_INTERVAL INT NOT NULL, - EXPIRY_TIME BIGINT NOT NULL, - PRINCIPAL_NAME VARCHAR(100), - CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) + `PRIMARY_ID` char(36) NOT NULL, + `SESSION_ID` char(36) NOT NULL, + `CREATION_TIME` bigint NOT NULL, + `LAST_ACCESS_TIME` bigint NOT NULL, + `MAX_INACTIVE_INTERVAL` int NOT NULL, + `EXPIRY_TIME` bigint NOT NULL, + `PRINCIPAL_NAME` varchar(100) DEFAULT NULL, + PRIMARY KEY (`PRIMARY_ID`), + UNIQUE KEY (`SESSION_ID`), + KEY (`EXPIRY_TIME`), + KEY (`PRINCIPAL_NAME`) ) ; -CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON `P_0_SPRING_SESSION` (SESSION_ID); -CREATE INDEX SPRING_SESSION_IX2 ON `P_0_SPRING_SESSION` (EXPIRY_TIME); -CREATE INDEX SPRING_SESSION_IX3 ON `P_0_SPRING_SESSION` (PRINCIPAL_NAME); +-- Dump of table SPRING_SESSION_ATTRIBUTES +-- ------------------------------------------------------------ + CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( - SESSION_PRIMARY_ID CHAR(36) NOT NULL, - ATTRIBUTE_NAME VARCHAR(200) NOT NULL, - ATTRIBUTE_BYTES BLOB NOT NULL, - CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), - CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES `P_0_SPRING_SESSION`(PRIMARY_ID) ON DELETE CASCADE + `SESSION_PRIMARY_ID` char(36) NOT NULL, + `ATTRIBUTE_NAME` varchar(200) NOT NULL, + `ATTRIBUTE_BYTES` blob NOT NULL, + PRIMARY KEY (`SESSION_PRIMARY_ID`,`ATTRIBUTE_NAME`), + CONSTRAINT `SPRING_SESSION_ATTRIBUTES_FK` FOREIGN KEY (`SESSION_PRIMARY_ID`) REFERENCES `P_0_SPRING_SESSION` (`PRIMARY_ID`) ON DELETE CASCADE ) ; +-- Dump of table AuditLog +-- ------------------------------------------------------------ @@ -400,8 +389,10 @@ CREATE TABLE `P_0_AuditLog` ( KEY (`OpName`), KEY (`DataChange_CreatedTime`), KEY (`Operator`) -) ; +) ; +-- Dump of table AuditLogDataInfluence +-- ------------------------------------------------------------ @@ -423,8 +414,27 @@ CREATE TABLE `P_0_AuditLogDataInfluence` ( KEY (`SpanId`), KEY (`DataChange_CreatedTime`), KEY (`InfluenceEntityId`) -) ; +) ; + +-- Config +-- ------------------------------------------------------------ +INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`) +VALUES + ('apollo.portal.envs', 'dev', '可支持的环境列表'), + ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), + ('superAdmin', 'apollo', 'Portal超级管理员'), + ('api.readTimeout', '10000', 'http接口read timeout'), + ('consumer.token.salt', 'someSalt', 'consumer token salt'), + ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'), + ('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔'), + ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); + + +INSERT INTO `Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) +VALUES + ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); +INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; From 2888dbf5b6ddf229040f63faa9f52c068af48d49 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 22 Dec 2023 21:45:12 +0800 Subject: [PATCH 19/59] sql converter delta --- .../ApolloAssemblySqlConverter.java | 46 ++++++++- scripts/sql/assembly/h2/delta/.git.keep | 0 .../v210-v220/apolloconfigdb-v210-v220.sql | 93 +++++++++++++++++++ .../v210-v220/apolloportaldb-v210-v220.sql | 79 ++++++++++++++++ .../v220-v230/apolloconfigdb-v220-v230.sql | 18 ++++ .../v220-v230/apolloportaldb-v220-v230.sql | 18 ++++ scripts/sql/assembly/mysql/delta/.git.keep | 0 .../v210-v220/apolloconfigdb-v210-v220.sql | 93 +++++++++++++++++++ .../v210-v220/apolloportaldb-v210-v220.sql | 79 ++++++++++++++++ .../v220-v230/apolloconfigdb-v220-v230.sql | 18 ++++ .../v220-v230/apolloportaldb-v220-v230.sql | 18 ++++ .../v210-v220/apolloconfigdb-v210-v220.sql | 4 +- .../v210-v220/apolloportaldb-v210-v220.sql | 4 +- .../v220-v230/apolloconfigdb-v220-v230.sql | 18 ++++ .../v220-v230/apolloportaldb-v220-v230.sql | 18 ++++ 15 files changed, 497 insertions(+), 9 deletions(-) delete mode 100644 scripts/sql/assembly/h2/delta/.git.keep create mode 100644 scripts/sql/assembly/h2/delta/v210-v220/apolloconfigdb-v210-v220.sql create mode 100644 scripts/sql/assembly/h2/delta/v210-v220/apolloportaldb-v210-v220.sql create mode 100644 scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql create mode 100644 scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql delete mode 100644 scripts/sql/assembly/mysql/delta/.git.keep create mode 100644 scripts/sql/assembly/mysql/delta/v210-v220/apolloconfigdb-v210-v220.sql create mode 100644 scripts/sql/assembly/mysql/delta/v210-v220/apolloportaldb-v210-v220.sql create mode 100644 scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql create mode 100644 scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql create mode 100644 scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql create mode 100644 scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java index e36874ca14b..c5b90784c69 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java @@ -58,6 +58,9 @@ private static void convertMainMysqlList(List assemblyMysqlSqlList, String assemblyMysqlDir, String repositoryDir) { String targetDir = repositoryDir + "/scripts/sql"; for (String filePath : assemblyMysqlSqlList) { + if (!filePath.contains(assemblyMysqlDir)) { + throw new IllegalArgumentException("illegal file path: " + filePath); + } String targetFilePath = filePath.replace(assemblyMysqlDir, targetDir); String databaseName; if (filePath.contains("apolloconfigdb")) { @@ -67,6 +70,9 @@ private static void convertMainMysqlList(List assemblyMysqlSqlList, } else { throw new IllegalArgumentException("unknown database name: " + filePath); } + + ensureDirectories(targetFilePath); + try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(filePath), StandardCharsets.UTF_8); BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetFilePath), @@ -85,11 +91,27 @@ private static void convertMainMysqlList(List assemblyMysqlSqlList, } } + private static void ensureDirectories(String targetFilePath) { + Path path = Paths.get(targetFilePath); + Path dirPath = path.getParent(); + try { + Files.createDirectories(dirPath); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + private static void convertAssemblyH2List(List assemblyMysqlSqlList, String assemblyMysqlDir, String repositoryDir) { String targetDir = repositoryDir + "/scripts/sql/assembly/h2"; for (String filePath : assemblyMysqlSqlList) { + if (!filePath.contains(assemblyMysqlDir)) { + throw new IllegalArgumentException("illegal file path: " + filePath); + } String targetFilePath = filePath.replace(assemblyMysqlDir, targetDir); + + ensureDirectories(targetFilePath); + try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(filePath), StandardCharsets.UTF_8); BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetFilePath), @@ -102,7 +124,7 @@ private static void convertAssemblyH2List(List assemblyMysqlSqlList, bufferedWriter.write('\n'); } } catch (IOException e) { - throw new RuntimeException(e); + throw new UncheckedIOException(e); } } } @@ -184,18 +206,32 @@ private static List getAssemblyMysqlDeltaSqlList(String assemblyMysqlDir if (!Files.exists(dir)) { return Collections.emptyList(); } - List assemblyMysqlDeltaSqlList = new ArrayList<>(); + List deltaDirList = new ArrayList<>(); try (DirectoryStream ds = Files.newDirectoryStream(dir)) { for (Path path : ds) { - String fileName = path.toString(); - if (fileName.endsWith(".sql")) { - assemblyMysqlDeltaSqlList.add(fileName); + if (Files.isDirectory(path)) { + deltaDirList.add(path); } } } catch (IOException e) { throw new UncheckedIOException("failed to open assemblyMysqlDir" + e.getLocalizedMessage(), e); } + List assemblyMysqlDeltaSqlList = new ArrayList<>(); + for (Path deltaDir : deltaDirList) { + try (DirectoryStream ds = Files.newDirectoryStream(deltaDir)) { + for (Path path : ds) { + String fileName = path.toString(); + if (fileName.endsWith(".sql")) { + assemblyMysqlDeltaSqlList.add(fileName.replace("\\", "/")); + } + } + } catch (IOException e) { + throw new UncheckedIOException("failed to open assemblyMysqlDir" + e.getLocalizedMessage(), + e); + } + } + return assemblyMysqlDeltaSqlList; } } diff --git a/scripts/sql/assembly/h2/delta/.git.keep b/scripts/sql/assembly/h2/delta/.git.keep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/scripts/sql/assembly/h2/delta/v210-v220/apolloconfigdb-v210-v220.sql b/scripts/sql/assembly/h2/delta/v210-v220/apolloconfigdb-v210-v220.sql new file mode 100644 index 00000000000..6417c1b70aa --- /dev/null +++ b/scripts/sql/assembly/h2/delta/v210-v220/apolloconfigdb-v210-v220.sql @@ -0,0 +1,93 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v2.1.0 to v2.2.0 + + + +ALTER TABLE `C_0_App` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; + +ALTER TABLE `C_0_Commit` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; + +ALTER TABLE `C_0_Namespace` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; + +ALTER TABLE `C_0_Release` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; + +ALTER TABLE `C_0_AccessKey` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; + +ALTER TABLE `C_0_Commit` + DROP INDEX `AppId`, + ADD INDEX `AppId` (`AppId`); + +ALTER TABLE `C_0_Namespace` + DROP INDEX `UK_AppId_ClusterName_NamespaceName_DeletedAt`, + ADD UNIQUE INDEX `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`); + +ALTER TABLE `C_0_Release` + DROP INDEX `AppId_ClusterName_GroupName`, + ADD INDEX `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`); + + + +CREATE TABLE `C_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `TraceId` varchar(32) NOT NULL DEFAULT '' , + `SpanId` varchar(32) NOT NULL DEFAULT '' , + `ParentSpanId` varchar(32) DEFAULT NULL , + `FollowsFromSpanId` varchar(32) DEFAULT NULL , + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' , + `OpType` varchar(50) NOT NULL DEFAULT 'default' , + `OpName` varchar(150) NOT NULL DEFAULT 'default' , + `Description` varchar(200) DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) DEFAULT NULL , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + PRIMARY KEY (`Id`), + KEY (`TraceId`), + KEY (`OpName`), + KEY (`DataChange_CreatedTime`), + KEY (`Operator`) +) ; + + + + +CREATE TABLE `C_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `SpanId` char(32) NOT NULL DEFAULT '' , + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' , + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' , + `FieldName` varchar(50) DEFAULT NULL , + `FieldOldValue` varchar(500) DEFAULT NULL , + `FieldNewValue` varchar(500) DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) DEFAULT NULL , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + PRIMARY KEY (`Id`), + KEY (`SpanId`), + KEY (`DataChange_CreatedTime`), + KEY (`InfluenceEntityId`) +) ; diff --git a/scripts/sql/assembly/h2/delta/v210-v220/apolloportaldb-v210-v220.sql b/scripts/sql/assembly/h2/delta/v210-v220/apolloportaldb-v210-v220.sql new file mode 100644 index 00000000000..fe1d5ef6054 --- /dev/null +++ b/scripts/sql/assembly/h2/delta/v210-v220/apolloportaldb-v210-v220.sql @@ -0,0 +1,79 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v2.1.0 to v2.2.0 + + + +ALTER TABLE `P_0_App` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; + +ALTER TABLE `P_0_Consumer` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; + +ALTER TABLE `P_0_Favorite` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; + +ALTER TABLE `P_0_Favorite` + DROP INDEX `AppId`, + ADD INDEX `AppId` (`AppId`); + + + +CREATE TABLE `P_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `TraceId` varchar(32) NOT NULL DEFAULT '' , + `SpanId` varchar(32) NOT NULL DEFAULT '' , + `ParentSpanId` varchar(32) DEFAULT NULL , + `FollowsFromSpanId` varchar(32) DEFAULT NULL , + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' , + `OpType` varchar(50) NOT NULL DEFAULT 'default' , + `OpName` varchar(150) NOT NULL DEFAULT 'default' , + `Description` varchar(200) DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) DEFAULT NULL , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + PRIMARY KEY (`Id`), + KEY (`TraceId`), + KEY (`OpName`), + KEY (`DataChange_CreatedTime`), + KEY (`Operator`) +) ; + + + + +CREATE TABLE `P_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , + `SpanId` char(32) NOT NULL DEFAULT '' , + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' , + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' , + `FieldName` varchar(50) DEFAULT NULL , + `FieldOldValue` varchar(500) DEFAULT NULL , + `FieldNewValue` varchar(500) DEFAULT NULL , + `IsDeleted` boolean NOT NULL DEFAULT FALSE , + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `DataChange_CreatedBy` varchar(64) DEFAULT NULL , + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + PRIMARY KEY (`Id`), + KEY (`SpanId`), + KEY (`DataChange_CreatedTime`), + KEY (`InfluenceEntityId`) +) ; diff --git a/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql new file mode 100644 index 00000000000..3bfadf81f64 --- /dev/null +++ b/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -0,0 +1,18 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 + + diff --git a/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql new file mode 100644 index 00000000000..b640af550bf --- /dev/null +++ b/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -0,0 +1,18 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 + + diff --git a/scripts/sql/assembly/mysql/delta/.git.keep b/scripts/sql/assembly/mysql/delta/.git.keep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/scripts/sql/assembly/mysql/delta/v210-v220/apolloconfigdb-v210-v220.sql b/scripts/sql/assembly/mysql/delta/v210-v220/apolloconfigdb-v210-v220.sql new file mode 100644 index 00000000000..6142ec27c22 --- /dev/null +++ b/scripts/sql/assembly/mysql/delta/v210-v220/apolloconfigdb-v210-v220.sql @@ -0,0 +1,93 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v2.1.0 to v2.2.0 + +Use ApolloAssemblyDB; + +ALTER TABLE `C_0_App` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `C_0_Commit` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `C_0_Namespace` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `C_0_Release` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `C_0_AccessKey` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `C_0_Commit` + DROP INDEX `AppId`, + ADD INDEX `AppId` (`AppId`); + +ALTER TABLE `C_0_Namespace` + DROP INDEX `UK_AppId_ClusterName_NamespaceName_DeletedAt`, + ADD UNIQUE INDEX `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`); + +ALTER TABLE `C_0_Release` + DROP INDEX `AppId_ClusterName_GroupName`, + ADD INDEX `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`); + +DROP TABLE IF EXISTS `AuditLog`; + +CREATE TABLE `C_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + + +DROP TABLE IF EXISTS `C_0_AuditLogDataInfluence`; + +CREATE TABLE `C_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; \ No newline at end of file diff --git a/scripts/sql/assembly/mysql/delta/v210-v220/apolloportaldb-v210-v220.sql b/scripts/sql/assembly/mysql/delta/v210-v220/apolloportaldb-v210-v220.sql new file mode 100644 index 00000000000..3c0aa2a130d --- /dev/null +++ b/scripts/sql/assembly/mysql/delta/v210-v220/apolloportaldb-v210-v220.sql @@ -0,0 +1,79 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v2.1.0 to v2.2.0 + +Use ApolloAssemblyDB; + +ALTER TABLE `P_0_App` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `P_0_Consumer` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `P_0_Favorite` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `P_0_Favorite` + DROP INDEX `AppId`, + ADD INDEX `AppId` (`AppId`); + +DROP TABLE IF EXISTS `P_0_AuditLog`; + +CREATE TABLE `P_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + + +DROP TABLE IF EXISTS `P_0_AuditLogDataInfluence`; + +CREATE TABLE `P_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; \ No newline at end of file diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql new file mode 100644 index 00000000000..1c073f32003 --- /dev/null +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -0,0 +1,18 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 + +Use ApolloAssemblyDB; diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql new file mode 100644 index 00000000000..bfa66de9cdf --- /dev/null +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -0,0 +1,18 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 + +Use ApolloAssemblyDB; diff --git a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql index 598ebf037fa..9845351af9c 100644 --- a/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql +++ b/scripts/sql/delta/v210-v220/apolloconfigdb-v210-v220.sql @@ -13,7 +13,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- -# delta schema to upgrade apollo config db from v2.1.0 to v2.2.0 +-- delta schema to upgrade apollo config db from v2.1.0 to v2.2.0 Use ApolloConfigDB; @@ -90,4 +90,4 @@ CREATE TABLE `AuditLogDataInfluence` ( KEY `IX_SpanId` (`SpanId`), KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), KEY `IX_EntityId` (`InfluenceEntityId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; diff --git a/scripts/sql/delta/v210-v220/apolloportaldb-v210-v220.sql b/scripts/sql/delta/v210-v220/apolloportaldb-v210-v220.sql index ebc206a9807..67894fe5b33 100644 --- a/scripts/sql/delta/v210-v220/apolloportaldb-v210-v220.sql +++ b/scripts/sql/delta/v210-v220/apolloportaldb-v210-v220.sql @@ -13,7 +13,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- -# delta schema to upgrade apollo portal db from v2.1.0 to v2.2.0 +-- delta schema to upgrade apollo portal db from v2.1.0 to v2.2.0 Use ApolloPortalDB; @@ -76,4 +76,4 @@ CREATE TABLE `AuditLogDataInfluence` ( KEY `IX_SpanId` (`SpanId`), KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), KEY `IX_EntityId` (`InfluenceEntityId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; diff --git a/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql new file mode 100644 index 00000000000..66963bf51ff --- /dev/null +++ b/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -0,0 +1,18 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 + +Use ApolloConfigDB; diff --git a/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql new file mode 100644 index 00000000000..3e8239ad720 --- /dev/null +++ b/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -0,0 +1,18 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 + +Use ApolloPortalDB; From ea07f152d3d3fbd3c0b1611ddf71b1862abbd092 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 22 Dec 2023 22:04:08 +0800 Subject: [PATCH 20/59] sql converter clean --- .../v210-v220/apolloconfigdb-v210-v220.sql | 93 ------------------- .../v210-v220/apolloportaldb-v210-v220.sql | 79 ---------------- .../v210-v220/apolloconfigdb-v210-v220.sql | 93 ------------------- .../v210-v220/apolloportaldb-v210-v220.sql | 79 ---------------- 4 files changed, 344 deletions(-) delete mode 100644 scripts/sql/assembly/h2/delta/v210-v220/apolloconfigdb-v210-v220.sql delete mode 100644 scripts/sql/assembly/h2/delta/v210-v220/apolloportaldb-v210-v220.sql delete mode 100644 scripts/sql/assembly/mysql/delta/v210-v220/apolloconfigdb-v210-v220.sql delete mode 100644 scripts/sql/assembly/mysql/delta/v210-v220/apolloportaldb-v210-v220.sql diff --git a/scripts/sql/assembly/h2/delta/v210-v220/apolloconfigdb-v210-v220.sql b/scripts/sql/assembly/h2/delta/v210-v220/apolloconfigdb-v210-v220.sql deleted file mode 100644 index 6417c1b70aa..00000000000 --- a/scripts/sql/assembly/h2/delta/v210-v220/apolloconfigdb-v210-v220.sql +++ /dev/null @@ -1,93 +0,0 @@ --- --- Copyright 2023 Apollo Authors --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- --- delta schema to upgrade apollo config db from v2.1.0 to v2.2.0 - - - -ALTER TABLE `C_0_App` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; - -ALTER TABLE `C_0_Commit` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; - -ALTER TABLE `C_0_Namespace` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; - -ALTER TABLE `C_0_Release` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; - -ALTER TABLE `C_0_AccessKey` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; - -ALTER TABLE `C_0_Commit` - DROP INDEX `AppId`, - ADD INDEX `AppId` (`AppId`); - -ALTER TABLE `C_0_Namespace` - DROP INDEX `UK_AppId_ClusterName_NamespaceName_DeletedAt`, - ADD UNIQUE INDEX `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`); - -ALTER TABLE `C_0_Release` - DROP INDEX `AppId_ClusterName_GroupName`, - ADD INDEX `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`); - - - -CREATE TABLE `C_0_AuditLog` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `TraceId` varchar(32) NOT NULL DEFAULT '' , - `SpanId` varchar(32) NOT NULL DEFAULT '' , - `ParentSpanId` varchar(32) DEFAULT NULL , - `FollowsFromSpanId` varchar(32) DEFAULT NULL , - `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' , - `OpType` varchar(50) NOT NULL DEFAULT 'default' , - `OpName` varchar(150) NOT NULL DEFAULT 'default' , - `Description` varchar(200) DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) DEFAULT NULL , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , - PRIMARY KEY (`Id`), - KEY (`TraceId`), - KEY (`OpName`), - KEY (`DataChange_CreatedTime`), - KEY (`Operator`) -) ; - - - - -CREATE TABLE `C_0_AuditLogDataInfluence` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `SpanId` char(32) NOT NULL DEFAULT '' , - `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' , - `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' , - `FieldName` varchar(50) DEFAULT NULL , - `FieldOldValue` varchar(500) DEFAULT NULL , - `FieldNewValue` varchar(500) DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) DEFAULT NULL , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , - PRIMARY KEY (`Id`), - KEY (`SpanId`), - KEY (`DataChange_CreatedTime`), - KEY (`InfluenceEntityId`) -) ; diff --git a/scripts/sql/assembly/h2/delta/v210-v220/apolloportaldb-v210-v220.sql b/scripts/sql/assembly/h2/delta/v210-v220/apolloportaldb-v210-v220.sql deleted file mode 100644 index fe1d5ef6054..00000000000 --- a/scripts/sql/assembly/h2/delta/v210-v220/apolloportaldb-v210-v220.sql +++ /dev/null @@ -1,79 +0,0 @@ --- --- Copyright 2023 Apollo Authors --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- --- delta schema to upgrade apollo portal db from v2.1.0 to v2.2.0 - - - -ALTER TABLE `P_0_App` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; - -ALTER TABLE `P_0_Consumer` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; - -ALTER TABLE `P_0_Favorite` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' ; - -ALTER TABLE `P_0_Favorite` - DROP INDEX `AppId`, - ADD INDEX `AppId` (`AppId`); - - - -CREATE TABLE `P_0_AuditLog` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `TraceId` varchar(32) NOT NULL DEFAULT '' , - `SpanId` varchar(32) NOT NULL DEFAULT '' , - `ParentSpanId` varchar(32) DEFAULT NULL , - `FollowsFromSpanId` varchar(32) DEFAULT NULL , - `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' , - `OpType` varchar(50) NOT NULL DEFAULT 'default' , - `OpName` varchar(150) NOT NULL DEFAULT 'default' , - `Description` varchar(200) DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) DEFAULT NULL , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , - PRIMARY KEY (`Id`), - KEY (`TraceId`), - KEY (`OpName`), - KEY (`DataChange_CreatedTime`), - KEY (`Operator`) -) ; - - - - -CREATE TABLE `P_0_AuditLogDataInfluence` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `SpanId` char(32) NOT NULL DEFAULT '' , - `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' , - `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' , - `FieldName` varchar(50) DEFAULT NULL , - `FieldOldValue` varchar(500) DEFAULT NULL , - `FieldNewValue` varchar(500) DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) DEFAULT NULL , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , - PRIMARY KEY (`Id`), - KEY (`SpanId`), - KEY (`DataChange_CreatedTime`), - KEY (`InfluenceEntityId`) -) ; diff --git a/scripts/sql/assembly/mysql/delta/v210-v220/apolloconfigdb-v210-v220.sql b/scripts/sql/assembly/mysql/delta/v210-v220/apolloconfigdb-v210-v220.sql deleted file mode 100644 index 6142ec27c22..00000000000 --- a/scripts/sql/assembly/mysql/delta/v210-v220/apolloconfigdb-v210-v220.sql +++ /dev/null @@ -1,93 +0,0 @@ --- --- Copyright 2023 Apollo Authors --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- --- delta schema to upgrade apollo config db from v2.1.0 to v2.2.0 - -Use ApolloAssemblyDB; - -ALTER TABLE `C_0_App` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; - -ALTER TABLE `C_0_Commit` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; - -ALTER TABLE `C_0_Namespace` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; - -ALTER TABLE `C_0_Release` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; - -ALTER TABLE `C_0_AccessKey` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; - -ALTER TABLE `C_0_Commit` - DROP INDEX `AppId`, - ADD INDEX `AppId` (`AppId`); - -ALTER TABLE `C_0_Namespace` - DROP INDEX `UK_AppId_ClusterName_NamespaceName_DeletedAt`, - ADD UNIQUE INDEX `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`); - -ALTER TABLE `C_0_Release` - DROP INDEX `AppId_ClusterName_GroupName`, - ADD INDEX `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`); - -DROP TABLE IF EXISTS `AuditLog`; - -CREATE TABLE `C_0_AuditLog` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', - `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', - `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', - `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', - `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', - `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', - `Description` varchar(200) DEFAULT NULL COMMENT '备注', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `IX_TraceId` (`TraceId`), - KEY `IX_OpName` (`OpName`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_Operator` (`Operator`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; - - -DROP TABLE IF EXISTS `C_0_AuditLogDataInfluence`; - -CREATE TABLE `C_0_AuditLogDataInfluence` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', - `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', - `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', - `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', - `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `IX_SpanId` (`SpanId`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_EntityId` (`InfluenceEntityId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; \ No newline at end of file diff --git a/scripts/sql/assembly/mysql/delta/v210-v220/apolloportaldb-v210-v220.sql b/scripts/sql/assembly/mysql/delta/v210-v220/apolloportaldb-v210-v220.sql deleted file mode 100644 index 3c0aa2a130d..00000000000 --- a/scripts/sql/assembly/mysql/delta/v210-v220/apolloportaldb-v210-v220.sql +++ /dev/null @@ -1,79 +0,0 @@ --- --- Copyright 2023 Apollo Authors --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- --- delta schema to upgrade apollo portal db from v2.1.0 to v2.2.0 - -Use ApolloAssemblyDB; - -ALTER TABLE `P_0_App` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; - -ALTER TABLE `P_0_Consumer` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; - -ALTER TABLE `P_0_Favorite` - MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; - -ALTER TABLE `P_0_Favorite` - DROP INDEX `AppId`, - ADD INDEX `AppId` (`AppId`); - -DROP TABLE IF EXISTS `P_0_AuditLog`; - -CREATE TABLE `P_0_AuditLog` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', - `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', - `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', - `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', - `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', - `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', - `Description` varchar(200) DEFAULT NULL COMMENT '备注', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `IX_TraceId` (`TraceId`), - KEY `IX_OpName` (`OpName`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_Operator` (`Operator`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; - - -DROP TABLE IF EXISTS `P_0_AuditLogDataInfluence`; - -CREATE TABLE `P_0_AuditLogDataInfluence` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', - `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', - `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', - `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', - `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', - `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', - `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', - `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', - `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', - PRIMARY KEY (`Id`), - KEY `IX_SpanId` (`SpanId`), - KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), - KEY `IX_EntityId` (`InfluenceEntityId`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; \ No newline at end of file From 84a54cc6f6a3f64e7c746ac03cabaad986f1414d Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 22 Dec 2023 22:28:06 +0800 Subject: [PATCH 21/59] fix assembly sql --- scripts/sql/assembly/h2/apolloconfigdb.sql | 2 +- scripts/sql/assembly/h2/apolloportaldb.sql | 6 +++--- scripts/sql/assembly/mysql/apolloconfigdb.sql | 2 +- scripts/sql/assembly/mysql/apolloportaldb.sql | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/sql/assembly/h2/apolloconfigdb.sql b/scripts/sql/assembly/h2/apolloconfigdb.sql index c6ea3cde6d4..67cd159df83 100644 --- a/scripts/sql/assembly/h2/apolloconfigdb.sql +++ b/scripts/sql/assembly/h2/apolloconfigdb.sql @@ -484,7 +484,7 @@ CREATE TABLE `C_0_AuditLogDataInfluence` ( -- Config -- ------------------------------------------------------------ -INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) VALUES ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), diff --git a/scripts/sql/assembly/h2/apolloportaldb.sql b/scripts/sql/assembly/h2/apolloportaldb.sql index 8879dd4f792..eccfbf0c544 100644 --- a/scripts/sql/assembly/h2/apolloportaldb.sql +++ b/scripts/sql/assembly/h2/apolloportaldb.sql @@ -418,7 +418,7 @@ CREATE TABLE `P_0_AuditLogDataInfluence` ( -- Config -- ------------------------------------------------------------ -INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`) +INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) VALUES ('apollo.portal.envs', 'dev', '可支持的环境列表'), ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), @@ -430,11 +430,11 @@ VALUES ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); -INSERT INTO `Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) +INSERT INTO `P_0_Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) VALUES ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); -INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); +INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; diff --git a/scripts/sql/assembly/mysql/apolloconfigdb.sql b/scripts/sql/assembly/mysql/apolloconfigdb.sql index a8c4f1e8cf7..524b68369c0 100644 --- a/scripts/sql/assembly/mysql/apolloconfigdb.sql +++ b/scripts/sql/assembly/mysql/apolloconfigdb.sql @@ -484,7 +484,7 @@ CREATE TABLE `C_0_AuditLogDataInfluence` ( -- Config -- ------------------------------------------------------------ -INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) VALUES ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), diff --git a/scripts/sql/assembly/mysql/apolloportaldb.sql b/scripts/sql/assembly/mysql/apolloportaldb.sql index b00a34368c2..9eceb578d60 100644 --- a/scripts/sql/assembly/mysql/apolloportaldb.sql +++ b/scripts/sql/assembly/mysql/apolloportaldb.sql @@ -418,7 +418,7 @@ CREATE TABLE `P_0_AuditLogDataInfluence` ( -- Config -- ------------------------------------------------------------ -INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`) +INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) VALUES ('apollo.portal.envs', 'dev', '可支持的环境列表'), ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), @@ -430,11 +430,11 @@ VALUES ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); -INSERT INTO `Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) +INSERT INTO `P_0_Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) VALUES ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); -INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); +INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; From 41b010f940001a1d85fb934152225fd02cf59221 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 22 Dec 2023 23:22:42 +0800 Subject: [PATCH 22/59] fix assembly sql temp --- .../ApolloApplication-Mysql-VM-Options.png | Bin 0 -> 123005 bytes .../ApolloApplication-Overview.png | Bin 0 -> 90120 bytes .../ApolloApplication-VM-Options.png | Bin 0 -> 89402 bytes .../development/apollo-development-guide.md | 42 +++++++++++------- scripts/sql/apolloportaldb.sql | 2 +- scripts/sql/assembly/h2/apolloportaldb.sql | 2 +- scripts/sql/assembly/mysql/apolloportaldb.sql | 2 +- 7 files changed, 30 insertions(+), 18 deletions(-) create mode 100644 doc/images/local-development/ApolloApplication-Mysql-VM-Options.png create mode 100644 doc/images/local-development/ApolloApplication-Overview.png create mode 100644 doc/images/local-development/ApolloApplication-VM-Options.png diff --git a/doc/images/local-development/ApolloApplication-Mysql-VM-Options.png b/doc/images/local-development/ApolloApplication-Mysql-VM-Options.png new file mode 100644 index 0000000000000000000000000000000000000000..77abd0887ee60c2a2c9f2f54e567807aa7b48b3d GIT binary patch literal 123005 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 ZACj^b;N!+3CdcN^+xKH(+06xws#wV66NazPp5^ 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 Qe=RBsn(wOLeEjnN0JUtf6aWAK literal 0 HcmV?d00001 diff --git a/doc/images/local-development/ApolloApplication-Overview.png b/doc/images/local-development/ApolloApplication-Overview.png new file mode 100644 index 0000000000000000000000000000000000000000..7015b164ccea632efa96e85f84c428c74f5cb183 GIT binary patch literal 90120 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≪=G>kuwh>Bl zU7qNCB>OItv~S0!$bVcaAp2TVGVX=Q?D|OzL!f|ueg^L|p;gFaH<;N#O{c}P^M!(W zyg5Iv`t2_qO5m~uW^wCwzyUE1d~FsG0@II^k~FYK{qRIU%{B?%dZyl?w?5T7=yTY? zEN;~G<`@>&l*{+$boNe6@~ojy-Br5c0UX7RJ+GuEdSlg+ys&@V3V7l;y*@h?F{$h+ zb~oyY>}ZbAu-D6Q)6&hh*6YWrx2>P8sGa_1j@Q&3=)X_I4a z*}c2XnwZ1)vK@rWt*ry^k7(`cv)DCeB&TFW)QR{+VgA**64tAspu6`6H)KboL5*dI zR`b%N)rmp~BY|DFxH~T)*TZ$tttq&DqhObaZ=fC%7}{hG8a%ggUCN?#w={Q*Xw=cK z(C}T=CuOlVS2<@~aU{oj@r1-Zx+DGo0iCIJSLn?chPxs$4Pe%@seP(SJi!;mxVB@z z=QYe9ni3O&LN(jlD&2R$OHXLCjS8ZS5i$N_4KF$LOw!1cs)W&FO{QM+_i@Jl4vvJC?n_E5v>#zs8d4wzz zAuDrCb|EU^5-_xEpvkd3ZLR@;+C{EZTh6(vgAkYc@Gt8$e1~jVVNZ}Ujd!l9U2zy= zGhE2t!SFaU@$p6o%M=M&D$1&?n{I!c_>fG)h+&h}O)KCYsxj+fivKq}5ztHnthU6O zkVHY-`lwSPetwjU9UQT(IQk1B;iE~f`82Y&T|wukx9|B@v~*x(Z2Tx;ugiiztDb;3 zdj5B^P5QgE8oS_{*@BkCbTttWm}v{G6bWPL>AyL$QtHhbH@+(@(>;_SgL_ZL_zd$L zd=T)xEGfwxt&RNIz;i(w_uCBt(b3#?hnDY^WNObw}AIuyJ^IFPoN^zGNE?;`%_0_$`%yJ@*k z7m3RKu(0pezFOslI?`sP33#$cD6Ub!vfYsr_Hdb!6|M9>D}2$=ZSwX?vnhYTY}MNi za5fhh)^nGsd|^Pj9hcYU^d$V{ZsdjYMFhtSY{&$*Y#7&>3c29J$CyC=F?`#vHW==O za_XL@D4+G5MoIKU-V5Z8nWM58kqRpHXm?M~HAzVaZUnEDN^Ip^O7lb6zO%3}^P=>#`6U^5Xd~XZEAxsUvkqERY(A*<;MsY_k zYB^XIZJdtQyFo_RXhkI@I=#=$%hzWrx4deNg#Fq!+M{#re@jkjz4wWm_~$+G@9D38 zlOv9aal#|4vJ<_c&d1qffWIyfP4QSUf_M-l}){!8x

G1+;EFKu+TXglk1A)_nNq^T9fSuc4e%GwV*bcqaO`-GwQh%|i(`2=h8~iqL34Qr z|4g>|LwvW9opBr@^M8X@Pwvl|*_Wlb&zUTh~s)PJlS!WkD;$i8_ zmu>p5d9g!4Hn08{)IPYUtGry2MU--}Jopco{b~QIA&-!d4F8|C`t|3Q`4y9Ya|2vo zb4W{14INnZY0Ap>Zm4((v_`K;r2j}}&**J+RJpwnZw+eo49Q?ITvRR4bg1jA zqHqaZhcW?os6X#)v9?CbKuAI(y<=q>UIonN%Y7g#&)PdYVHvvV-S+}QP5mGa1RX(* zV_Yib(EZYGtBd3#g~{rP6>6{XFTK?}p}_wNq*K+Er9hb8qss4#rw(!#BkwW_8X9~} z2AvD=A~o277W+8)+bsFG`c^e?{jLZ#j;$a1~fDMHDUkhwV^{&7{RGrK&6 zyKelwx8F}cP4Ci^#x#}R)avUk(A|WPwHejaTsz*!xK^gmS-w~T^>D^yJ(6I3bV14=ETu{Y#LgUs2~ z@`A?Oe$bMmb`6#uRpSg=OB}xdTh_>$i@1$=89qZC7>*CjjW^x>n#$#pKy796^7j+q zgZ!CU`FGTBc{G-7f95hax63xn&Y|BY-}UBm;8lx-cT17|KdJC^uN3VSvw%!lu zIo~6P)Up4kG?XhL?<_W82syJ-Q!z^JMiOcJeTUl5RV%Rjv=|iToi=gec%*AGS$Yo{X&p_9V=$6y1bsJ!Go!& z7E*VAsBpzcW#|3h9rUtyKcB+!A*^M!RRkZb41N4&bLtHb#JB`aES3w(N=;4n#OGb8 zZ@i^1dt)1@{Gn7*eIW0g@~R(|bYYCa;Ps|z7RZZ^(s?0 zVEN6r@Ix=QOcf?754w4R9U4TrQ4`ly(G5IW0ij3`?-q$~^v0aXSqzg>4< zIW_yqJ8MS42E44TX1UVtFPv4!u$4Acd}J#&mK>XX!vlT9tx>A z_qhJ?%DbCNn%z>NdAFWUPL{WRh{WTeRxbkP$qJeVS@Hqz-Ispnsx*)2dS?@UkC5+y zh;p?~Mb5oR-N7p|&9_ObF7E1sAZov}b? z&OQP6D~m2XznU7J~6+QM!Eqps8ZY2WSKUg*B3OdRK`EkB-;EV^j+#P&@24DNQ7O?S5vo9QHZQ-5-u-Son>5r(L?1;LfPefd)2i9Ya+ z+8$1prV>0caC$mB*4Z}7i1VOWUEVxV(Q4mq6<|c+O1YG^g;nW~<9YDBlW~K9kNnt5 zTif%z2bDWp6+aHnu=C>^6OT(s2Df0Ub0OD0d-6z&_>@~ufAbdg@DEoM@a~QiiaTr{ z`L*~<3km+nFvkgTlN((dR#yTTGL3F27{3vWR~xDgI0v58Fm!AHybZ1dg-q?(z*eRX z!W}?=aQtV^NISLZ*uRh3AStYDWQcYBSI%Gd+l(cTDT1Jl*A45na7Fd%x#qWZ=QlgR z3OkVs3CGa_xfA_X0@f&Ro-D8|*1A1N8Bk&WSSC|6L9$=_<7ol!iG`zuo~_?gIv%__ zYy4(w>!r8!Tq!v=4n66ry55ovkA6}KU$eDYqKwtnD|u70aPj7y@puP$ZRhuxsTDKL zLT8V?TensfrgmPq6iK5>QmxM9o2H6I8tV__Tu{GM>Vq!nHUx=yYqjZ)oUA>VGt)aI#=vH%bj$?LfxR893#FRQUk- zSu?Yr>8|?tlYY2hQ$Ni#0pD4nH}8Epf#GUXYHF(+&P0bumN5PfH?WAb_J~8Y%htv* zvkxWGj<6Z)BsDdsxcI;%goLX{tj)eC@9P>Rg%Z5zB`V?ue-(9x-$6xc5_fvSE>uT7 zG-suwLwD7zW=m}fP27Mj>{^Hp$=cS_ayg3C`%UcIbvEnw{x*&2oSlj;s>I6Ax)sp^ zt|$GYdECag9^EjhDKRxUtg)_CRxAH*wfCKa%qj{|NU)xEKQ8!tTvn?&>fte;Oq146 zknBW2S;rZtS|QBF+oZM8{I}08C|s)l;iZ?98(ks<1YojzrbWxQ5OAdgIGalzU{Vx+SX)Q>WsFhb;^_mBQF| z)LHLVaq#^0LkXloc+2q~|UF$`A-Wl5}q3RmtbaXEHOZ?m$*H;_>oF|0Bt_ zR7_UR7s9RM3wEM|Dqsy|CpLTQv)@w4nm`9ZPH zaXB@c%)FY7(S@uQ40qjE!!vlp2ZZ<-IS;x|;XjM!$!+e4OE~nq?1U%CvI#rq5hgO*ZA8OgYQ4C&XZNOG`C!@QX=#Mf|TLa}s zY3SERb}JA5C|+0@zJJ(2R8;3--G|v{?G?>o7Sg)cadwc~m-B`3^@X=-(x%|^CdcY< zjiiSSScL2kx8*XMt`j6rFW)0GvDSd@F9!f^8m^)LOc$o7)%rXI{fmd}tN5iNOe-2f z)-Mj_DmfD$pJYG1=R@-nor}7|uNmX8+Dj1mWM?4|s?*-i{%9CmF#f~)$=WPc7aATzG508Ps@KpG+gI{ZOVcPXR8&kcycHQ_sFA?(YB{x1|Mr!hR zN^J?|6u;fE6Z?tR5jS3ztGkvf=qM_B5=%=iiVicF)#Atr@d|gI5$tfbskBc zMUrpmz&AHh0rnR+p$b>Q{|Nrm!0eQ+;;CodiF9`*>$9YpTG6RmDKj^dLf(CM^$xby zaw)Up?qAWXle#7?1M#4XCoz$lOxv9mQ%@Y*s@$JuKN!@1I=QlvxY^*@ebDdQ#yLOk zToGLI`!$_?Jf3>$+}&+s8{3Bum_vzIi}5n%{%gAc)J)4}%9(}zSx#O91BkC;k6f>J zqTtXf@8dIRf%gzUt{l*LFBX1L@1(QvzWnmS7jLK`AiS>)>A}`b(6`#Yw6y%rCw~aO zjTCRI6HWf7DstJQxAh|K_Z95pBfZgQn(`6*C2~iHJD8yIPqw1$IlIEe;Oebx_iSOw zL2FyBI#_$bZB1t6WcIjiW{swqX1+7eW=M6B<*_O5h|W;wh*`aJQQmW>qyy_45tQArdEE^r}IBX2I*ja;t?S3|=`s%%vfG>zQbU zHpxF!_{-JQGKP)932E}r#X|kJ_7msSdV0PK{^c6^6@2B&uBMP1pX)MdS!w6%`#VX` zQDbv5DDgWa^X~pxwFbyYU&$rHgxsxnC^<(PJFwnPY%V%cLVOHU+C+K)cxEU(#k$?r zSETAtCl@gqflqkC{v*Tvd0p`LeZ)j}r5iVnsw%+`9xT7{At>eaqFJI3xyl(YShajB zKIGn-U=3=p#>AFi5Ub;?&sj?30)%{uUe4mPC0=_(OZ6RHQYbokdWfX=y zFMGI2UYPnn*!%9FCfn{!JE#;9l@2Nj0@9mwk={ZLp%>}Bg-$>~LAvw~(o29y@1WAV zkdQ!V(mO~ANPw_W-}n8#Z+B+@*xA`K^UFUBJmG%sdd_{yb)Ch-vs<6y>7DSfKMS^5 zN-uvYVph(2DWM0Tn%ulA3RBjr4AHG;hzwd8nvlc_O@%$eTwDGwR`>lbdP{!C_kL7y z17ZS+m6ck{DuE8lDFRAi!Ap6@o%d7*!j70BwFRX_U^H#}D>b=Lgjz*E@+FTcdhpS~ zaJ-Pxq$HwM!Qy=r?ase8XyvO9E^mqQw5?R{L5KL36?@0O>h8G`-^r-FDxj_#Q3GCQ zEuR6$BL}y3_Ldb5%c4+@-^Q*F@Hy!XzWG82kJM1C;*GYFE8o!n)Agj-in6ko(j8^& zS|#MGl;N42T~9qOgp>yFSukIZV;o0sNS9B$gwq7iYZK=gS*hOWS6A2M3vfigIgaC7 z1|H=a6f~CCz|>b`vO&!=GxoH%W$5U_O%ZF#l8wS=-h#jbS4{%iet4uZe0rM5yW89U z9a?_Fb>d&wjc!88?uRwWbg0xc09A;bf}5c2`MyCxPtUWjT<2e|fXst<+)%dLc-J+y zN22Uo*DK~rR(n7rHJ56-G8ZklnUi022)d^3~xM||zdMQbOQ1^%qlz+gIb9EQ+aT;t;d=^*aPuijWPrk+{2sML``zr(6+!oIsF@x5P>~M9ghAnDB=1%;0 z;0VMb^D&$!krEFEHb|=~92$$%tuD98vK&dPC`)*OkIrySLBT$A{)YBDBwUoTP+O?V zQ;P!DZt{|bnvyijArS{OcqpU#Wg~A9>r)O54m;d1nj9VQNv&M0&Z_2sv9);23HZI7VZ^UPXSaeV>n4+#9tM_(8AEI_E~K2>(b7L^;H+ln$9 z!>SE3lJ@D8q#S;n8}Y(kYe9Nvr*KVYcdI9|b>~tr&l-2|#4>cKGW}pvpmvV zhPS^VEA~SfV)~lZ@MR3Rbbia94yuZ*L0CgSYyy4IrR0*!s&`H{0b>cN>o`+?eO3Up zw=vuFv)aJT*L1T)LxX^X0b93?2mmy<;9^x)Be}!-AHB|%wAM%Yq`KC?TO=F#CFu2d z?G48Ex zlpWZVa$Huo%c>TPC7{47wU3Wo6B0M@B4AvG)lJr)_GX8*MrExSE{8!ZwZE!aDjKgW zihq3Opc6ALNg96nX@JW>QJKhfdi)`kgNKlKo>Y+%;u}5TrAE=%{f2FN^Fm=gJ1y|* zB9EP6P^Q!C>)yX^z>9V-ih@P5#!D82@i}0P)AWto7WF9TlYsi8%rcD;wYhPVe0L%H z9my#DEqQ^Z;+0`lCXI;PI zV5{Y()I3ObWI(-rwiv|{(^6UK3RPj(7War$f78`&1f^}|j&(gPbG5fogFqtu$oUw2 zf1Q!&`6E{GN7|$GC9RF>#8FYms+*BfH5{sS|A;zg44%&8?`~as_>3s|*1!GsAAZ^Y zqfX%edfERf8P@;3HT%nPf7#?~SlFJPX5_)&M%x>xl$%>MKflmOH$6T)MXsl)SQ@7} zmSOexRx_Y0{X=0RO5^*VI}pz@#Fc~D>iZA2rZ;`IfE~XJ#($4JDL?zaH}L=2X8q&$ z<*T>@Pt5nm<2oe$;=>1MmU)R*=_2I{*VT{GrVgtpW(!wazYEMX_!lG%0<>n<{eX4X z`=fd2M7X()F3h17rHB9UnQ`gjY0gdJD56ba_`eF)%M*vPtAJvh|s%HLqj8Ri?8^45#T4o-?z<_vVSP5 zHg0*er5fPrH9#A6sOj9Hbivai{oMvUWUY76YsIL-PP-e=@MIT`uQ!K$X3^qw0PN=@ z2hW^}7odbL%fe9=A^WfIC!?UI7arSN*vij@{e1qzc$wOY!xHzaxElRK9GCKt3HX8g z^)@j&Wlglw!hURMpkk0C4dt(MalG2T!HGO9SUsLD78gFYo66EVQPwP+%r_g^(!MWc z7p=-o1Kup;3;6NP{zd+r{~DkbtKu}SKljsi=A@PxF$Q!@VEKDvrYte3d>G|pbl;Am zxrbs*F{5N@+F7Y}H4e)PtRR$;kz>K9Bg9HARheq7&o|GO97Av%ko90ER1t1itz;2- z)|j@KV6hzEj>=Z${|Wa<+&pwgarfW*yM1Mk_#)=KW8s-kOx@XAgT88{*|)Dj7GRB% zn~Z0DE(2VfV2?S#wm7gH;L{RieA5M=tGrww1F$vuw>}Qy`^arG5T!?Db8NkZh-LPN zNl3W&E2hVJW;#yb;Z4`y%38@4#s9-|*MOyrNUmtOVip#XWK+0iF^4s7wTRWXJQY9x zK8&YxNtwdT7`H1NOoyP4aB8rNX(?O6T)9+y`rk_T>Th(?WSR0)X6cgFCM}sR8DZZw z?wO14mw{Lx&JjM)8nH2?U}Z}6Zjs$&x`{O;trhd&T~H1^4jEHZ+pQ*z^l9C?UvE7* z$dVRE#mSE>-a1p?_QsluHDC}QED)aFsz@fgQ8%NC3igTj0^ZVkM560||1e@bxa z>glP0T>#2@z3jPNKr2t09njE2TkdG*o7si8qE%W3>9L8Wm>h%m?t_8})f?=Z>j;Uq zj~A0OE21-!F69uaKRZEKDt&CLUp%!H|Svavxe~@@ytP87jByaH${M{^92a+f@%72 z?%E7U<6T_H&J5_O+xv4W#bf{FO+hEzn=HLEQwRnk_>8UUVt=$h;#*CpGT5=j*5JsUNEM%{p4pt$AysO>0J{TBFK2r}wzx|r z>PO+qmf%M6T)UxA$I_QJhM9_y^P)*_0lzyg`I6mgiHTIr2C&ngr-x&Sso~W2Lhjz! zO^|re9Q`(f1AlzQsP8WJLl!Ti9x?Mpg_GY3J)J$hmylW1Kh%xiZF!7>BI92-AW{XL z@Vuic)iSEO5i>lL{@_O4lqjq`=7_W*#U|Z%+t^C; z-7xKJjvT{TeU{hJ`(drRpY>CjEn2XjUj+{@w81m)oWYM*+5p)B7sUOMKS~Pr%c6I@ zv`Ei3ABi=J7$=q&0*xG>a(Kmx??sVrr2U*ef%p9!<-9=r@oYI`nJCWK> z?J2rX3@GRngZywxK9gXpZu*tBrJ*Kw%Q6FPp{IlGhE9H8dZU^D7N}f8DnGL#3sa%> zxD8()o4QBU>o$;ceq(rD^h;7U-lN8*P0!u&e!|UGcsojD?$pD8nel><`23Z4vNBq3T*TL-Q~L zt?>Q5@PA`->$)>nC$ioIm zNT8u|IpucVhH1m%g>$$y6xP#d=#ALV-^^lI5cWs6*Tn(0MPeOld=^D=JZ;RTnl!!V z4Z-p&C72MDrXQ^lI9+7WQ+-6)755_qrcZO8LsQblVG@2O<)TOr)Xr&vI0QB4URU1Z zIw(KnH(zu(UJp~xO(cjCX)70;!!%I)F0GfL&b1``fDf_O1Of;6+X;4JuK#=l#^>`7 z#cKuAp*ay5Y9YO*Z(R#`u@#S=q?bSC7cD3vd2!sAUMnLweDevxqAs{-2Yf}tp=Woz zM*LO{_Rz?M0+B<094;ynf4Qmyx2wM1t_MFHfEt!9eZK zr3X9s07T5=JYn!sR?Nl$V=&Km2fhEvG%$$5r%H_S&FHxwFcq9!eddlnS=upbo!h!J#;dvmjF5OKD3k7_x6}g9 zwqaVYLrJJk;!HtohrLd?+yjUYvqxoe^JdINUi)dN#7s$A$`2B{$sdR0=*8(B&Q&yf zKi$JimT8ksre+nj4oCq{+Ob8|7m{kBtpW9IxVq0c{+;oQvqOb((z_YFkpQ~$8K>IT zFM#I6=6St>7=blyOg`=>EZ4u4yqPkJ06Zr_QZmBh%aDD$mMP)Ghax}FXb2u9YTs~&#XvOp6z4X>9>Hto8IjUTtgkg?VJ zsOL*ex-2O;lpiq@plU#&0FiZ}h}y^93dV)G%=Cyal0kKbthiGrvCV6mnn}-T4sr2? zlf^-22gB8pon?srcRMe!hXIGj9a3|=qg<+M3>QMC>{EJ0cG22pL`12+GH*YX5#<@K z-fH%t;}}z#bqTJTPG;c3laAl~M?~fXN6v0KB7BPCwY%zi+$U%sz8`PX)c54SHr9vQ zDC7?&a!5;urUH~p*Qa$8Nypr_6hHYww|%y#fK#n!kwk{g7GVc~dR_erI8gwsm1*1O zjEetw2G{7uKQ)QzPogYuvkb1#4H)_e53x&P%gN*B3T9KWDG6L!{&dw-hGJM~B;=dF z-fBeVVFFbeul2UQMjp8v9iq%&$aw|E`C`&(Z6YusLzG=az>bo`?&wQs0de!4WZ-N& zuB7Eb^G-t|q(cs~Xbh3VGaayj4>p7piKlOn|2@8k&&UOOt<$)h90#anPOsWw`Z)z^ z%tsge;bUF55#ad*H`NX=hlY7Q86pG?8;fM1$ajUO1r(WxpQGMC$ix=G@=8+;GD?V6 z(n29k{fbO_FO7Psm~Cs~eBX`A09`!M+lb#$bq4@uNY{{^Qzk@Cp1EXE0+eZVa~gb< zSW-4dA>V}OYSKGjmfxA3+uy&-%pbYHlPJ>H@K%}%REjbx9w`0k4_U=$6@7g4NkV=7 zcI|qX6M~@a=hgGwY+SK1c?c6lfx^AmY`qw>|d_ z)qXN`xd_(cUyz%TWk2h#56(noZ?Qkt7&a-vQ-``}EQXq9AQ<&IuVv-ie@j{x3wPWh zZt}2wsN1;By}e14?;94`R1@%}df!q@Y!*E(5JZ_bV^-Z-Znr4r5o^$vwLB@>8%20( zYahp}2Q@&F7*_@}c3N0~&f~27%Sc;y-LT6NS)+UV4+3^IE_}1REZ8SLuC}i)Vvk?} zC7dm;sds&^efrx{ymW)dG&qtV^Qf#hrT=7 z>bO@K$)67DTfP?lz_C$#5=Wm|;Ik2Xm4|?ux~2!0c`+r2L8IC%JK>q0ZBp&RYlD8e z8VN~4ex|9G;bZWouXe{bu64= zG@kiNM;Mb)wJzI?htVKvB}x~E0-HkVMX2PD;AYRhm6d_{5s2ctI*(4x>fQaTjz_JR z;BejyE2%zpZB&o#0Pw+kh+$T)EAT~MP2?8Y^`U8@)QzT0Q*Rs8&?DFzuH;118tBIK zWe3Q2@$*Cd?9pbUV;{)Us)!bns=;Y-Fu7fKM8Q@3Z@aC@k=w?kht+{ab%6R`JEz_ z{D=9|6NHpMj#R&{MlunMwVjDBUyn;J`uTA`V;`(PFf-;J-yu11{Bzpx+*SsA6@}>+ zaqaeAy+yfL#WN_pe15Qr9p@zuq!6v<7Zm*Pk6(bY_bm|*M}tLmAvRc2d|B)~MN#%n zCvRl6&sl19V2y8uz?^7D_Kt^^sy!Q~C^BW-r;81b>5m3KR2VsV?|-()uqlT;oMpc` z3>DKk@ED@YzSHDr%C9P3abA9e>$IC$A=ay1)+?Ai-4&@|W^m6fzS<8*(gEh$4p-NP zI9(hUUJ%0hL7sj)9FR2?&heG5)Np#HmoI2hXB2BsBSeR*amu_#f~|+L1=xXFAc4o0 z#uQ<{yEFdQ++lU)^5ojM&t3#J$&+D{6A^*B?ufK8@{=Z|qnyD-1J?TcBeS72P5}|( zXYY15cscuBjJ8L(gtb5@cg``&E-xu^%73Xe_}kk&X?kVpfmP9Y?OW6)&TUW=S_bf)tvk*t+ zPlrXsGFm^rVot3E7x2hZm@Ya~Cn6Qmd&CZnE@|2Ua*h+*t=OCo%oVE`E`B*O%{PKkID&WN zZL-wAgw1a9e9z20-iUXgU4iZsLRbc6ua9DA2?|^);t1XUzcZR z=Qbp;q%}X+-}biBa_|TccVCVGZ@%&s9bwA!T4F$hxPRg%E*D2Qzz@$htyqK~11i-6 zvjTiCoa^a@rsn-@?_hcoQ7u}6<-=;y(rFJI+hjIfADjC;Uf!`!CQC1w91z?*st^Q9?ysF==8>^xhyP)YN6@m8S z=qeaNR1I;Wnk9b7mJdY!7=gQfM`8P0dk~^(nQ1PWI}IL97e*f~d@oAnRO^JD4h5&{ zNSZlwSfNL^Z3lfS9D6bSKL98!@$LIldQfzTWvz!S%Tud5?dcz^t)~!ATlci7{tG~& zIF|f;tumrD8j1%lwTMHe?7O-KGvsC zzu6QQG%5@Y4dD(GP4MvD*I&U3JSs62rxUw}eM27KOAUPkoQv9iymw=0BvXWp3W7(b z9t=28minym`YgsA_2C_aujkU8M(MIqR>sxRH!H*gv+1`?l*f0n*A|Wa<)4aO2@&gp zoxW+iSWi!!-)TI%dww45gcK`kGEP5TG2UqA9H^XSLrF+rZ=CP{{JvS6+Rf8?9ME2> zuX#0_H@$8>-P2!2wVqfkd#F7ChRYB?MHfizWDnU3<10KayEUzvlpiQM`)s3n#B-`) zKMQB;1!RI}^2QFwt><9k(B>UZwbM)4HwCiok8m7*8KFN$Ew!j|$P_YmOQ{$yeKN{HetS@##jzYGWt%xvHLh0-+gWr`inkkF zIlMMuhug{KA|v@hcrVQEg%rqmhK=nPYy%Li_wTh9{_@_N{qkK^n5?FU@f+9<);5_M z8a$k7Qq|9{Ak7a}t8|A(W3Q|)**PK7#Pd9<@n+Nce7w&Hvww~pNpf*x^~k5#!jhzg zR_s*$T#={0%a2QW%U6U4rBizdQx~9)@Pe4T|DFw8|*c*$`NGg&Gun4gHacME} z4&J+g25gRGUwmrYpOSMgYYC94+yuML)1ROFG9X06$0a^n51g(-&_>7|)%pkGr4nL% zh;xa*uS=iJ1#^6OjBaM-r|NwWky#HLwS_emAFK{TKUFDYN?!ZA_4BpX{=K2z=ww)q z);o$)MD8BhpsR0@_0E}1zkGCjQLSvj(=OH~o%{{tC@A8K&t_wuCZGF?vdV};9JEpP z>2+^mUGx*)w_m!xG{jq4&rg>qs=kla+t5-^fVIGZ=b_DXp|8}n3)y7XHSziFyh>Di z9Q+CQH@3F{^m=WFd>~odutn#;B zuv~*oTe}KSUkM|tO;ZzkaDIQ@w&Jh7$td%I3}59TEu_T;&i7PA-^S+VzO0wIF};9@ zJ_0e3U)bb&KT9aD|3R9NNp4trB_N_mTCvSFbK1pVT=LBMa}CK!r;buZ4u} zMUkbIKRmO*0tM5ueESFvD$<hmu6yIT4BP{i^grj{ulGn`>f&|k}j3pt|G9g4AX5;3vWQe zMGrx;bXVV|%UB4g(ukSv)gq6onU!4_xel)g4badJusWQnxqfoMYU3{M#!smrPNXXr zQmp^y7=x&O9V%MT7MR_zU9VcB)s-e>FxqlFDGQ#e=`9?aTolB+s%0=)Oaf1s4_Duh zEYNH9se3K+k!+34e?_reuNA(gk7uTw?XQvEo93bl!!mogx>VMdC2(YW*4}?cD7We|GfwP zs)tYmEBj{oylN(;2Yy-SZE~KE9A07=j}=qhSl>Q%uM_^p-xbei%$BtB%#{{{xWaXW zcj5r8NUcYX@EB?H$~0J9o3)FJOW<3WBEI5y;33fZ$%%6<@~=0V;EU*Rnf}V|zMW)a z8%bxfrPa~cigx=MX-m)muqRDNPwM2Ji8Uu0k6Vg)vIyH%S{AufQhpxqaU?$%o*Ji; zH%#pPV>`V0=3-@T3HhRM_4CgMVule(=4{<050P02oYXsfT@w>gLaFl7k~OuBLvUAv zXt;VSM*?zy)?B)y+!h9y+mvqeu?1ej#AhAsJPb?qqo z1ke_%DnLt*y0P*qrN7Zp2m$#?;)HBu|Cx7UmT6)Dp0O+b?mcqT($*4PI>u?#Kp!k{ zK;V_jI-HN+D!i(S=iVw*U8Q;?HBbN3CND8;%#|mBGW%mELiuS|Lm7q0IGRaD7uKb# zX>JvqR=!2qyS(IX{2Rlhj}gFQm~4jUr$oG59P1CLl3p4@KV1(iedpBUjCz%N-O>ydc%QpKl+=}q^c ztrwHWW31Ds4bdPWC!&s>%c-?zOzcDZy<5*l=b4X72T>ObWdrF2lea0X^%Ns7jAF!6 zEt{#8Zh`kZZGg2xoJS^UA%$gaz=$!T)I_<%C7iH|eyw74eBRPV<@4%l1qP0*vB(T*8O(%udgksw2&o&!ZEQ?R)enYHhY6n{!oEBr_#E3f zSWAnW?V9G!`M#TK<=xc^#8)aLuIbbdiAF7GhJqLTq7sX)It^IwL+9#f9mg_&Y<%qE z3mRNGe*?Da40o`~W7lWSE?qL-QjnI^8UdHLnpVc$m?YJ=m}Nu<xgIn{*rbIk zr{-Oca80DzbTK0S6#CMUV*nM)SY$ESC~1e!P_%gP7d)!&Xq=6cX1~^Ks!vI>KWBE+ zRmk0y&s#WSz#)BbNv6qvh)9OGQl)$~dmP@wmT4t*dwdW7l^Fr;6D~B?j0WR!H^}49 z(SA6MzfzgJ;=(i2jby^`MPF@&V2eEi;{u)67qf^uw4@XQhqH!Jsk~jbRU$oysi@2s z`fMl;bq|Al37u6tCoPC!=7zqAx!2=+^GDBk#8pytZ`yLOX-l;~((^rZw5iZ`L%$wU zib$|wFRG}M+;(OAim!Tdzht6@NCuhID`u6K1PDtUoy?WBGmI)1Z!B~7p62l0%90GD zV{O$bk2abT*50h#Hwa6sbqs!BK@b#Q2s12?!jzVj<5P-jlF8=7H0)iYHKK0a2i6`A zpypF#b6rv8Ajc*Uz1?gyQW%KRf>yN2h_j94mAOlI7qW;Am2WKEs!cmj-i@yAcgzHO z>;Wd-Yl=%|(IXz3S%fjuNY`9)o`g)YoTjg?{KtB-BWKS+GKW{nQ{v0yp~K)hU2na) zC)vzntN~IXB8o0HLW&27()`>Kxsk#*qpP482b+?3PP-h-NwJf%r=E3!(1LQ!ZGH;i zRwSutDTaz$Q6AH8?Vuhiq7jS4rM7AFkMkFI`IL{RQM29xPEIs4Pp<6?Kl}~j$|zWR zR)5h*=WJ88Vc}M!gfAo?9R}w<_Op-CVL*S$CEl7w}$4h@&*! z?)W~1u&*V1${*;9BH`5PQF6wwe%*=l38qH?z4+wb_T%45?XwR4mip%A7p?6a?vKA0ze~Yc!fi9cX)3ZGCj7JVf$BW77ySME}X8~p0j;#zv*VCF^ z6AQbVEj+Y0m*7+GIprd%vX8|*tC1towMbNH_?Z~eA5lEhF6&G4IDyNoQF~Aoln+$I z;Q2`^c!_bxO)25^{X6KFllVGGPcGg742m21l=IfZHIIVs>v27uHTEd)I;}ZZ+bhTd zw(eKA$~f#i^VSP@Kl@CUh^Rl^OgT^OU82%!@e3Tw-4Y%vK4`9EZAZ2fwyQ0HU=DjH zW$vEEZ9nn>Sxq0)w6lFkqA2_K75-q$TpRwvmWd(ZaO(rKWz$&gPb`0bSk3XMo@`ca z?|PNx$`=Clr(HBo%3q2%FpB}&igSin64y_-!AWe28w z80LFD3ePqk{C|Tw)lyv|4mpKAXo{Y{kydS94!na866pf8 zeN|BF_S0vp(O{FtWBu8w=deufb|9wMG(1>5@h@E4&)YLz{w#$x}`2uAu7A}rLM=S zv>jC!0X~Jmbk`z38=<2?FHRUhB)|g{aUIM>o zQcJMWMETeWoc}z@OrpG`6k~j?o8iXC-m zRauTG5Fg%P6)g=a4cv9N;>_cbFkYtfxWoupPrW%T(mHuuTqfqLaX)x^anPOxu^tgf zFIADRo0hbtihU>AKFFFWraQT74mkre~Qk6P_%vkSFi zYL($dr3Y37B;7(p)fyBW0yoB7))i}=9tnI%@);)uTTCoehjP}^Z)5oR34Cad@Ca9C z+-qrf0?;W{FlJ(sTg$)sbxXL%7+GvAz&4+H{2QfCQ*0dcohEtEW-NJf&ON)tBWGA* z!LpRGwG&LMJf7I4uWz5IAZ1GZJ9SQqbv){xo>L7^L9O30`{q_ulnL* zZy&?R;}f^)lIJzMx*}|;UQ@MUZ?iT&W_%f4h2Iq~(1jnU&-WGt4GbBMPrgaXqw`&~ z2>v)zLL~8aROh$ZoC@(rWMsi1GeIi~??I6lublCyt^lM~+_W?uw3mAxj|xx?)4 zK{Roi&k0|Ba)T$%uHUSdK4Lyx!~S&|PtovLSz|Ibc-}452D0Cq&%!#{NF}B+r!B9{Lumm}JBM4uXcYG_Scq`=X{*oxN3# zb{kf!t^z3ZZ4Cy#xwDi!BA8pXeK&f4o#meQc31?cCV-0F){(X$6jaZ|FBF(m$%huE zQZ%(mf5oEJGr;8znO>D5&3OUn*8KYzko-Od`cQO6ij*?g;33%+vaE_(!(ZU7$9BKL zTO4k_OJSclnN%HP!{7Xd`WVvO>&zZ1kFV zd?KR?0U=`zPU)|lTOvE9ZS$nYnWB>aW9Qy5PTa`&EN!l+*t=7^T#dUz)F|sJhF;#F zuNxQi=KO)4q=~PTwnIK29V~ky(@cEw8#kUamU|#<>}=3OvV#~d_XXZnPHq<8GSSet zXgd+sZ>xnn>_|m{!k0@oUZA&vbxGRPF!%3gWeI@CAvTBrvp@G4% zb`RKQW+3Wyt+g|FunB#+wbS?7oCdQN0G`&PmQ-+IQTlfd$Z`J6%B}O#%5I<@*H3g~Wc4k%c zFy!0%TZRC<9CDcxh+6Tw`SsUA&M+CS|Hnc`mPWj@ z{Z;m}tZ;ak>f{|zwXP7Ls_kbG)Z*Y?y5qvYjmMvDk;H|N6}-)#_#6@Z36%UBf%eI= z3}o1P(EVgdK?zhf@ad>gszA<@wY^w&I~hxWFCtLnws zs37x9rCI$`%v5B9+*^d#UGSg|o`i156kqt_Q%drZC=%~QRFkLi@|7k=isTR5bV%iX#E zxX@Y;@NqX9R;QIH7L*ttH8A5I*rM*vAG}-4CM0t+`6RoOLpVlIfeK!AUqZf(##YU{ zkuI&OA@~0FVfen?bI?1tn7XABcqr{F6klFqMqzG7(b3@sd!a;eu8o*@hCXc0Z zJgQWp5C%wGo;fC>jX2w2dA{k^NN}NXC%nb+8OXx!VJery%7>mbX1Am&-y{rWrJ$#l zdlf8aAN*pm#esTg?`}dELN@gKi<{nm2_3?`I|duq-c*`WI(W&}k%+%ET18*OeUutvZTPlkr`))vzsDmC>_Cn{dkSUq7+H zswkFOhe))s)b6;S-nGX>+5jF0Ol_d3dgKDZdaN1s&9rLgrq>+23tS*HV5%$? ziwaTCE03)1FP*5t1&Dk%i4&XthkVRtkxJD(}x8<7I})VM6_4W;t~@nk8A^2*wJD_VF$pd3s( z3{^#S6YtOR8+s>P#cYhRyoea4v*>YeDwV?1+nhz>$%*WfG+vA1=!K6kGrbMZmn$Ye zcBL9^@`j+pW7h2<7q{Ev6&(uNDL#nRSRmuZ(=y38>&XZC4PwJpG7Ac5V53AZRXS~5 z0}|uq>-PnxHl6>4`CE<7+;wznvSe?UZDirtY*c0M>MGr9pDLeWZRX|A#8oM!HLGtX zud<4X%aS2ow;~QIdaqfmRE(nw@Kgg=Niy#@>AY~R>9B{^ZvcZVD`tyj;A8h098i~8 zzNY67PC{!vy1-p%sRX?BuvK!`{fNjUQqmuD_bY}U4;Q=|5E7eDHSmCinO`QXk0l&) zn1xpsGumFSD5$sHy%V_L!pNjy4ZU2vJxLY9EE`5uU5h7pP}viJ7Iv@S6$p8y&g{TA z1fP#wt+T-!S|9LYR}61rX}RC|eNIiD|IUTy0hwMhx%W73)wXX;NHK~YTYvXRW}>bM zUmVs?`swhR>s4+>c&+o0qDs`k3z&Rcw7>~bjOfmedkruf5!iZCdVpy&ar~Emg!lwq zxt*VOqoLT5i4(cP4?l0^R3Z`0&s)Cg*B$xo&|T2ZzpAz@O;ilCwXP)Q+HEUV_rAtL zuimx4Aj|opz4i2sQ=ahIC7g&tQp<6#>yhh1;_{Q>*P4Wjr0g_`fpt&Rp7|yaThzVP zxRqeo|IFf^^(14&mPJoxX6G=#p4nsT#jNIWJ9Fj&i++_VyxmDWB;GuGw)K2xrZrwa z{Tt#6<&`TRLD>X4wa`oBjB#9p&vF{A8MT)Zb^TH5*iYQ@+2Zu-mp439^uJ9{m-(3l zjedKu%bqCm$)>{*0X~?P?7J6w6E0ksIiU*GC1^FOQWn;kwX67?#h(7@*lTL0EOXJ# zEbwNZO&Fmz4zNU5t*d=BdZZ@RSW64#YuCw7D6LKapBkuB=dxDQ*neC% z6U!8RZjB?I&_g@`y$V=B%TfqmDS8|3JfH(%D%-1aT4|xn5iLZPEr2g`Y<1A| zeb{SF6-S2E2h{WiOaJxR`Q}j=^u9NgkAbZ-3CI>(4JBNzRpE-z7e&Vo4OtfpN4DyN zOoy5r!~k5kG&HH|VEXSe#6s2K_H`{qyp-(Bu&xO@oXHDDAn9`jn_h6TfddE2x`s9C6o$z~H~2H;bR(nyM6 zpM3YMoZM3-?B?aow_zziOJSmKf>fZ*nI`w9$&9ycFpxOJo7^qpUJnnoGR zO77r*fv^YOAKw4@^wN1TGm@Q%>Xvj7NtzOp@O{lEpx%V4gHZ30;#q!)rZ1g!UIYb4 zeoIduolpzj*tn6x|3ZBy!hFq?h(tz5o-h)t&BwB*4{3QYM4dgIbQnl@i{zEshnpI1 zt#Ki>#ZJ~9wn49wFkCD)6x7y1k{V+bMw6-zbZOf);G-SIDq1(S_pXCq`nAb7>`K)P zVYHQ3ODKS4`}`gBN-X74n(&u*81aX??-?AJ@=@=fEDlf z`PWD2U3}!L(yF4TX`$^S!hlHbR& zUe%=1`fVNjZJn5F?ND)0;oGMB2P)rRr(ub}yui%v+(t&pjZJTeeS;a1WmFVNaOJSy z`Q@2>62qVKy zgm{{8Q(eswq)cFF<)Qul=FM;E*Q@VBwCSH=z9l_fZq0Z7@#j0Ap>biq9-+C@hpesb zUn;r9W1|Cju2GT|N8aq5`15b?{opUDI(+UjQvroD=_Ms4zikq4i2Ods2)fEADw>*C zscC4&J7UVhP6EM=|pV%O+*Lt}AIbUBxJQxSqK$%J`?P(t26f{FO0I9~|H@~Ul| zdJ&xQxhSo0SpApZg3?A+{hZ z9_h{!FXivW5M|`z>fK+vqDnT${`KXb1`#x>F{Y3xi*Q$>%>eI zEcMFk3(xN!CUd1lep{awJi9aZv@QOx_H=jf?Xk8;KB_dTkQ}kl_}$5t(65z0EfkLbCew6xI(9VlquR`c-&+Y$Te zu<-(*%I$IN$j@!M0a7xu6UJyxUnUiR!ZB1^LQTQh?2T1+>*E0*=_o+Ypf2wR0e{NZ zjEr~a3Hh|>dMd;3-dnNn?8fM;>5S&$uE)kX5%IcA*$JA4D7+e74fvdSF$?owX!(A4 z+hu4PulsM`YC98Yo7-&q@_|-}IN4a}_GrHcWXHGIN8uqyh{y4GR)*SLv z0GZ&k`bIA)&v|1;b)l(7Z5hbu0r~Ne9-Do--)>uAyrpP5 zPxb*{@aMUY#{yz}yqiMVjuP zM7ZobFUzQqhTC1LYcNb30Dvd$SxR@7o#N3!ep=_b&Yo^juUHsF-0FkN7p``03Q zGMl}`PiL1kbz0!SuJ?nH^F3_?$c|{fD&;%Vo1=s=?`8cKo+--@bP9pa=}9GyX?L1k zIqqKdwxG~eh}YyAeI}gO6Wi{Pjdh$$31Kn=STgZgjdcH{#HfI7QU`*UeLIgWBBM0s zo)}XI+m@z<7Md!*#TE*Vsdgh0)a3g=E5}{o_VA&8+`1O7Tc6Z*xz`FmfAaYG3+t1J z?-O2Mx%GN(mg|dkj%xQhMV5Kr?S<8v+p68x6m^<9*iSr@2lrJOtYFscjg>L`Ccq+yi*_-e1!ko9Okk zGTp^dk5+jjQGTVHHGv)-VffBh9lZ2{TECp`Im<)p_z|N>IfhnxD(;q`H*Z{6;_oo+ zt4N90ZL8tqj88^%B2jaGSDjcSjx!u-(&ChAR$fbK^A9RMeLjGhXcVVOv^`gn9^OlA zif}IrAS862xipk`>Y@EPp|RImA|)n0>U#W%DCuKZSDVG05T)lVIy&Nhi3VrmEvosu zODkeO&ob{Pi42+x-Md|Z6=F(B*hWA1`ynZimcrcBvk#BH>@$^9U-uC>bM268ZG4Di zHy*Y~`EEMwWQe!LCS%><%r0(ptic$EhMK&kX7etZ#xnClt5mda<&64*a@X^LNNwB zD4LPx2qDqji(xPucL8vrJNDs5M7dqO7H`8{6H3!xKF>u=Q4ighQ#YM?67ZS(RwMaA zx}4X*3pmXQaPZn1@kWwwpDEmV22*7ELDFCu8Powa>TLCt2)!tqd1t0VC-RX!@$}Pt zJLf`Hb5=){luFVuxYBJeeQt1(=lNA#FKQ-cJ;CE8i@aEn>|G&c9@KX=z=Nt|I*Gl( zdyjJi6^l@q&ArPDPF>;#fRYN#jqTH&B#4ia<{i=7Zt(KkIjOh(KUW1K+x#aYy;F83 z<$B50Nhj*JM6#os6TnZ>JFh<`?w!nVdwlj~y@V3V7g6PRPhW7mwngr!@~rqZ{KIp4 zRPnRnkuDc~gGePA*WzB)@`>2&9^sJp^4#BgKH)y&_w!TIL8gJKw|x>9PkHjn=z`O> z>VNbkgYpp5ZgP?p6OkZ>0IE&4@pxi*#pf*QuPkM<PNk)ZbZNzw;60J&IchQ100`fO)xLAOmVgraZU+uiHMnFcV)H z$q3J%cX?03o4Yq*dN29jqT0OWbHk*lF@UF89ZJaFjt%oZ>ji~XhB!fA*z17H#Ugq^ z3%RWm*p5}5rsiR6CQ=lDemqNN^xz`;O=6ry|FkuD= zSFRsBTh?BCZ6{we5g$46`R`wf8M2~;rV_Z`0p6H|c$15%1?B`^-kf!aufA^!F8YeK z*26;2c<y$lJ9mC*^`TeScKIj~<9PT1et5kC()v7GAiEplwvBhKIvpjPB#h(9@Z-5MJv5GZ$xEF zQUGh|M+Le+b)}FgPE3w~+_vl-a-+jack;fS)*vwva|u$Sy2Nwxl6OtyS_pn`cwyw< zf<%`wncLx>(m2P=%SBMbV`X-?u^JX0_Wt`oRCCF?LI*9@K9IfZqY$07hF^t^{gmV(1+NIT{0byla3FAsaQGrBB3xN0(CQn7c!A2e^aLPg1I zTuq$yzI#)}T0`qE@-aZc4HrZA3oFi=MinAe+kmJJLw=Q8NYKqqOv|ZFxV!i|#1}I* zouZ;OD^vgiCRc>@WX-tCrJRiq-Nsy%c~x#x4y5gx+ExK=OcNoQd54Up?B#`Wm zjNtP;JRbT~LYbnz**CP8dv%A$|JWaSI&HRX5~d<^niBg5a{Y!4#QI~>KZp**{+{-S z>J41X^Jb`hOxI4+>Y@;0Ur}*8CbM5Xotb=_!{a1^wGjr-Ys%dYzY~$Eop_gZZAAqc zOaVtz8Cfgde<1IAPt|qz672gsI~3}WRRH8R^>-{iERFL@Srs4&%2t0P)pI6rvbVrp zm@Hz=%q-o#sLlz{2sA8CXHH@3gM`HRQwiL2Bi8=%uC37>JbI8Y7qIqH9XH{Vn1#Lr z(35ut1iZ$KlsXva`kwB>t)hU|vzqR}2mykOL-BbCI$F;i_5DYcl!!CG?1X)Kg@jDa z%ZwR>Cu{cMjy&CEl6D8nUK$>cthxv7u%F_x-#5|rBsyw=E9KR}j6B^$Lt@Bdnb5Xq zm?~ex>M3L-saQ%eSFXD-Y2jBAi=S15L&7~dNwa6kJ~eNOYx`uMAET`H?^VRBn>_hk z;`xQ_6BSScs3{S{_`gcpC>YB0L1ktxy-+J-`^wA>M^Cx8N)jev5oA#~cvgQBk?=lsIIv;T4fp+?*52e87HmA?v1dK<^Vi*Y9!$4- z!IOaf(|4v3L;!DKz?l{Irh=sNP)g#NVpEm{a|z<(a7l7no}s6gp~t<8*)rbmTrfP- zc$ylfr``2k^m|fnH1-fU}& zi7%yTFMIVopR4AZ>?^h_f~3#%DijrN-#>*K4Ed;pj?xz66l`RzuL;p4nNdP6u-iYa zRo}}1HXqVX&UM0PZsgH_bym#&F}4#}$ye+}5-Dh`E5Yg}0_GiUwLKu$CLK)nzcMyG<&K#@>}*&Tr^2m{^+9ys7c{S>1B1 zdTR<}?C<<`5-D=jqf9i?nHMh^kBt{T{)I5d4zdtoDjN>uaqbg`0~+k#;j~3x(iw z#((usTNM?os{QK8CHcBAfWL1Z-1q_q7bhtACry&`NS}>s-)}cTEU(ZOeia9kJulH5 zP1xi$e=BHtisM+%zl#7Y<`dh;xGO)?*xkV`-N{B|d9G_)Z%6^@X)=l4eMATqH^N*!0$Z2i|m2Mn=MW>EsISr7=PmS(O9n4hOe;? zJM$jh<^}9|xs|Dpg@%s9BCFpRziLqqA z(MZUV-O*#ljLR0nAuUml+nertzyt^>$hPhdW(*qqWgYc{pUf=QsdrCo3B*~q zkixS&o)M8OA*i_FqQCh6qEv63TSDp$0+WLp-Yxj8T#d|t_chH*I!|n}~ zWF5QgAlLGd;ij**iveNy+AzRu!GWzIA)g!%s2AiUnsjxqnB%gXpBk22s@lp!B_t#? zr{hK*9l|*TEfJ;@HIY=0GoOpdhcP#|z3m6WWOM|Gtya9S*p_iVaz_IA@O7D>LJ)>a~0iHc?cWeN_MP5~g^j#H>D3fL<0V;@t=ZR#Q+0@qr2T!%3$YGHD7W{5LqwDB zBiHd)o25}_U-0RFRwq!nLb&{7@&h5Y`~#MSY7WW%w@Tj;q$P^dc;K?j1C)^d{?WKR zro-O>L7&MrT5f>L+&|h(%Q`=URhIo8rZ<(9&cR=nn(I<>HSAjOBaiY|k1 z?EXhC=^}E)#H6#UxBKu23`|y@x zzWzsRRQQ<}^&X7C!v$&B=}0&DR{7rTeyw5%?+nl4rX-Q5DL z(@8s{oXUd3YjXqM0t4@tem*l&!TU+;rTSm3oWR9Hlgth#Jd#>5ZGJ1)p6mJ7m5{u0 zljN7UabB0lr?79KdMp#U;(tzI%Tj)k=PnlafVAe9;;UT(%UvKOh4STHK_pqHO`?l) z$1ah`LY;co*75J)Lyz@XNy#MLq$RAaKxgJ`q6I z`4~9(km8EyYidU`TI5IN+Fs>bHBm3ve!s&}qd41?QZn9&f2>%LVsAvFwe)TB^~p9- zduIUVDgSE*gNklF%NHA4gv8PBVtkAu@)^#CS6187taOf?NBwy4D8zI#F>!Tg3zha_bOiNM;$|C|SfPD-FO z$4WGk$si~Z{1wH~kH|+jN!4o{$@6YL%gnRonx*}o#_u}zaIcgAFI$aOFl1mQl)ZTJH>DxlFH zkaQK;+l%7wT#3#x*8GQEj1oB5%i162W;v9V8A@8D@Z=;eo3OkY2C6M$BNYGlLD z)Iy~w%ZWFbA z!Laq0#RQ;Uw?EkBAv0zjJ`p#poKun4f15=*gi%~?n>iiz)kA0DVxwo#yyI(vL7ex= z+s@}obw-*u1cu&lusN_c<1FqnUasv#X7R#b{x!jUiGEC>|26aH#N&D!H1%t+B3rCc zDSs=&@-zogx=o+RRxJGTQvWBL@4_^7{p0+_49BEBD|P5n@4Va7_ZUx?p~1V&hlm&jjFNt$R-0lXU|}Q7(Xi! zfKyy^?9Pq9NoabJw&L?bv0V&7M-KZQjW%k(f8asSbjrcE^=FChX@~PIe%=<1_W4%n z%~jljXHVW+hwtt+;v0j}p6dfCrx}gYdFuL&3CVrTL(k=uDea1hT^OepxX;zn zd1j2~A*0?DSnRuV69jq5xUBd4L7pz)r2JeM9&qEi1QGVLb4cvz4ju&qG17o9`u>V1 zzW-hQTyw_`QsajGzCjoS_eXIzjCh|Q44P)tBdO3@mt~Bfm)xZd7oc07(a@zQUSfN@ z`%YiD>jxo*2;f(4Ea*V{O@c-&MHV1jc6m%T0~e(BNtnHvmO=&xq4U#J;b%9}l}vsa zkvpfM?TCFy>ut-8oAfj^;u8ln&UhQ6pdxKrSlR!Xw;->`E8ixqdL?FaR8=?8pnNFD z(q>Ef^e~`Od$Qg}1b%s7M1DPvf|hEZBiws|D6nae^eh@C7|%NW;Dv_Ezifbsn$Wv zAQ}nCLclc~(N2l*WkE6AnMw2buDlmFK_ePk>N?H{NC|msc4U3|4T8Hh+-sfD zk7jwG-&WoADwn3U32-Jww#&-4hhDy?08IBk*}BqJJOY5$W3E((xN-<@^@pxBBYk&E zxN3P?+t>(@kBDckZ%1fzNAYBHuq2DhkxNPg>WHr-+%asS$_8@8f!?;9%)r%}V}%xt z5BzEdlz>}is*xOSZk1n6+jON_+5?{jRa$o3&~bsC(-!Ms5iD0CTKQdGzXvD#N>SmD zu@h4~*i({o3Mo%0EHU%*DPB~5+HJC6g2-U%QH+gd*FT~DW)4)4KNEqLeI;2@8>lle zHeSp1juqx9o1W=jaHU|Ttbr|4)<^5FOQD>KY8W%%GcnBCg^vutt>-$B-i0Udyafpf z*@XPy{e@zft6lOV+k?2$#AV#dy+ks~YT3D!_7QgSi1ZD-E6aI!G=VljBl0rKHxw+^ zoyHQDZ>iF;gWny&IY^*=I*}qcy*sKxCT}Y}AwXrCe|NCH<3;on`~(~V+emC=l&3Wm zzl55|Wsv6jnbJY>6oCwLBVS8T7P#~AsLy8p;4AHl%Dv8tNK~B}Nq%58zckxDhbR6Q zMm+x7c5!7Q+tX|D1)XaBguP0Sd70_3V^vyoQv2JEXpV+x(@I5n8 zrIW$7#^Y4r>9Nzf%kb!_&$$#( z=Kopo(Ys6s)ok?1;qrQkg;!F{LA6Cij8PO;6zSn(Zx9PQe*GC1A5bu&abITb4r|T1 zh~zJyUpU<}&u4`gwP}{qpqPz5obE9g*sLJpIMuzH_>2+4k`s|1MMj;|y(etsuvZg? zsvcIvV&$s=_eAabRWDey96!{_w=w^EzEID0WYZ-r*jip)(zm(~ja84EcS}Wg zs4L~b!VO7!;PDO43b{tZA=548&>7SLgsLPn=y~~Spq=W}-EXWx zQgO@RX0Ojc!B6$W}5beFaJq&iBpzaXA~3cAnRp_Py~3 z4s#a8eMyyhdMPKBs7i{Ro|m@s6ngd9KMP}wuewSm3sVJp8d|#E0mK`}v{dI^ zieAZ1k2D5T$1Q{ogu-OFw1qV6^#JBCM%$V3PD2dO3PLstlG%rTxnYyP&SeucF{xyG zHj%2h;LbLsxqo&n1J&$P)vlD>Wzj>iG3!(Lglvn)23r$5)q%ROU+1KLaT^}O9@7Pq zuYA#jHP0Mkq-oJ8ip}GQ_)sPs7&zyid4UTsM({ z>S7NstfGpf0U+u75*vz&3521wk0&oUqwo799{u!>OAK7|h~_J*8(~Eb%{IG+p_))v z8W;ua+0N-n>+mv$MtY|)sq!B7N$5p$(&ErS>xWFI8KX2{$!5_3a;X3U^+M&Udme{7 zso)>bd`-8Bu&S0Hc65V-_VFgN%52kOo#uNs%upQnqEbzPC6yL4Wu**zoqf^~kt((o z6-r6~x#V<$uBO|wJ|EjK{I$Vv30+sSYaRxapU9aysoke2UGnDw-r31YC#=N@{+4c7 z!TQ+E$ydT0i8bH$c|=CPQ^Pl}VY#qZCg!&@pF`>Op@a>G3I5>KLBlkTX=)Ho?!w5p zZ4*a1uf5ESid}m$ecror1JyYC!ng8XY?-%J4vMJ>a%u6dzetl^m~38u65(EpiL1Sk ze~sN|#x6Cp1=r7?9;+^O*O?X`X=Q3(q9mkqQ1p?9?Jd-6zEqMaf@UYhHbf(>_y+~b zxJ+t>277gMO(|0LDg!fuyliN2HhcRt_k+y1Oif9-x3VI>66r_SIkmq0DCUZxW)C!H zvau0QY03Vdt8?^t@T7b5re0DD*<3io{1yjh>P!zfCkLYIit%9Aqo#9VO$C<2Huts6 zd_W)xUWd-Tk-hN6F!bS%4l6oNvirW<;l2knkJ=rSR=0Ab7x#j)(cQ24#P+Z#-g|NM z&0CRDb-)&!EA~@FO0&RXL{oW~yT1bb;(N_dxm3n<>nM{3tK`&Jxw#oivTEhiMexE0 z5v*e|{-;{Z=+R^zCrGU5gv^yh$NqmYnJB~mxtfS+kHV?5CabeIs;gLs zT{xj1vK~7sijZlWX|EJ&*|k?}?*sJnbrZ!(i{#w&-MUdHR4eODE}>8lr#8YBpy9Hj zg|RB+A@j$oJGCihjk2ep{cLOZSQ9d6(NDHQoG5?Z13RKp&bA4ZFKjJaY&yaI3PDeqn}g^Bo1you>_KVW7K-|T=P+QOo3;Jk<>BxWc#WL-KpS^)ns;7AIS_MWOA~7$!it6Ja$Fdq4D~1C}Xn#pqXX!DO7L>X1rP zWQVM{D>~qp(@>(fOfI0D{hyodyl(dEga@i6@~6M{Hfm{ye5yr>)f3FvU{EhT6Fo*x zBMNdx}y(cK7rV|}K(XbZp z@!_{nVfeeOH-1Y?bQ*Gy=tdqsZ$dhxV z0l6s55JP2}rn={SF$dDiy#zN8Be9iD%}*<{47vrSGn*?Th}J!qpD!+L2Bu|=J;HIU z_kOJP-D0Z7#Vl_!&BBcA?_Sif>ySzK5btssRg*C*wR}sJuX6mQ^fbD; zilaadB_9!qWLX-)K9IVQ19<1-3f>6kuSSIBzv1ZZlMcq0^Gxj-Z1&396GXAb6FJhDPppQ%49f%RPjgho1T8H)YHDwj zO;R?wH;RD~9;NkL-PP|WCSpd+`}!`Njmpu^-)p$+{aMKac zNWsJ8WzRmvUz5eBWWbVRkmmc#2{>}&6Mk5G+3h513`rB4-WD80izVWL#+zB2-~AU+ zz)Xjac@FksKO&u$!OyYaN8XE`*WYgT#Q~iScJ-@&T=v6pncfnrvo{f4!%cZFFsGqc zVIrqIPTtQtM#8?T$kVt!nruAWP#YSY2_Cgs;6R%0bQeAMA3YzMfQWqqNP^2L-#+P% z|E&le@d+tSNWyj#pQjRQA1~D5wV?H!vzZV1tks;nF3-GJB|jC#_|ITsA~FO}nj#&D;~#E06ZaAxGx>h_p$D{(XSMeU)2MN8b6&Tmoutzw|L$> zoz6k1xXllmf9#+%~`r_BiuJrcw zWnXy`l$4ZEz-EF{rWHo!yX~JZZ=cVYe4|m6 zrs{Iq25DnY)O7~Qj^qy!P+!g0zGxY{C(blmTp8uFRo16!336? zle5`m4WWWs< zsm3k!(77f6fC<%DiDY7X4$$4#%B?Z9j;b9I`5{=^lqd#Q8)FG{bX`OS6ohgqg)igdFHiedar;>F}neBPLo~PP!8q2tz^HCynkr z#?zir9($BNE9$zI4$X8-pHN^D_W#M9$iD(s`hf<Bo}JIWcAmH?uu_J z^}q$~>|TUhZmvIlP$Wpca}|f?91eoe!^dT$nOjN)kj5 zg2oQb_=arKiSe4Mc5!z5X)Zg7g{Tj?L7N|10*IZJu~ZJU4^4~h z;BfH#*jny1V8BEgnk#jqMt7P7s-{w>@^fnPl>UBzOMm!4x#K z9LBX1_4WILnfNbvulJK!eY+qOadL#PDb?Ncn~bXXl#HOxAubdJy~xwYX<9!MABSiOQTJL@ivk z=X2Ry+q?lZJf8kn*dH!MmA$d+vs#=UiW3^}zP?&cXVq{Yysy&{s?--OB@2yW;o&rt zH=T$dUDh{#M2ek6gh$4|;gS9j+~APdC1Wz$lwxvf5W7~N)l+)xL8n5f1%wHA1-wQ- zC}>y5?E2YU+Wx#=3<@m?s&)*sCgFCXmno{?TelYEQ%0o69d=)tPfeTd)UCuytF3_4 z%!4pwD}F>VpXw0DFL6tD+Ti$8%E>PB3Je+oz!);pqQsc+B$K?AFAm?#KxA|Zg&`t2 z71f_JE~Vo0sG^6xGR~7`Zb$KM=RkK=aFNlo4Bnlr4DGg2Z%`=y_n7lBvf1?vIUEMI z-l;KBhud3+0v;>jIuSo*n6s>x$j~}?)uXyuD zGXscmv|OoY9?bPPia7oUg_1k`g+gaH#j_k@lf+%0yxz(-7K5j)|5x2F9Qzhu66@ZI z`P(U?oDt7Z&2dlwit>xa?UXMJB#(SNZ(;8gUs9*yx@?tWtzVr_VV54aPtM3H|8DB= ze+A0qAq~hmvtjFst$^d{U|g~AkjY2%6h}ICF9t*88HRq!wQpeRrxrlCynHd*b@B}( z@)KxDZjJn-1L?V#Y`YuLoPJpp$1kb82@fBaPcaNVFDNix76Ps{*Ysw2V%Lw&br9W` z57~DK?hQFkj23q3c zSu@w#qu)nja~1T8YZpy&2L&B8a9+2yp2pSRRmr7}e4EY`r3THm257*O`F~@!Pdeip|aDLk9%OGALJJ0$NoxQoui>)!WkH+6YriZror%O5$ zCGHAf#}V1C?coLhjdDJ?WgYH&p!lfmPhoYdMtTwY`fSvxy*Eb2P7qh6mZij;iF?j%kSB$c<}ah?=PS^Z&@85xDM%E?F&vZx!t<|GyboK5PoFMJWMAcR*K zgQdxw#%vGsea5w}#>K)z!i5}E9ZS#q<0X!OC9_J$XB>!-MX>vt8l-zKCFM_~|hU^P+9*gT)}}BGZ$N{mMS4^DE1} z^?NZUwO^HYznadTA?SJ&l8b!>CaZy5$*2WC0`qS?(!4v`@zU=AKV8IQf`@zM*FPk= zaZ@{<`3@_Sg-D^{iSw6l?O2Yr>8%Z!jdgg>_)LaF?^r&3;>Yr9tQ zWWRLFv=aVW3&PynkCXG0cl}TESY=h?6r6APQ+A8s>p$$-ZGO1P8U-0`GD z&)Otnw|WU*AuQyMDaClg-O5;_^76P;pd)~e>R7^T+iaF|ByUD-gRuUc*OqxVG2JVv z=+5D(v7RQY5!sN*qAc)fQscvems|vz)KtLJ>Sn%-IejFI^{_iFH&Kw(Ye6*XO=5Or z>X%}(Tx@co*SQQmxy2`MV;b}bb!^$XASJ7UUcK1FNzF7aclLQw^*InjdA%A+YOe6_ z=}p+Ptj*+8Yh_CYE+$QSMit=`9LPT?LKUPD z8WOCu*#Z+r!AKMD+24}}xDrywkx)Dp)%hdYtt zcDKjacUmEi-yQ_6bFgRs;P4>-U4;3y+Bm0D8h}tDx=&Se_De4z%{!Fn_h+r=E{7Ey zAH1UsZGsX3LlFWey@OrWN8}YTGX^6`oH0gUii4u!-Z2>8<-M-e(99|LiDRkGDx>^8 zD%Hv;G|fLLTtYdiNa}51VgOf($DfwtbJeLMpNt3=G6n?a4<=F$GbM^kJYgs-=*+&r zLE;h=@vgo8_VUtQ;nvRjy_;Lqro^4<#Dt)lDOr893}V($S5FTLT)@>CHvV*{zolce0;SR8KdgP%3J?&prqnJWh8e|#Ln#n?KigrE56 zSpe_&hM*lNH{0ahR(_Apon}|Th_rVg&fPOHgr+Apz6kCB8hiI;M?3bwgeeJx5FdR1 zW?5S=M9U(Jzb!<*bbYoO0~B||6MH?9h)|B805SVt%*?tz*So1LkxUmh{L0dc8z|VP zImt_0$a33_j~!_I?KKFm`so~0COCdhLEc6gL^LZ)X+wj^;WB=z8tg_OC^d7GBE#X$ zBZv}#9aI~u8;w)fzfGD%pnRSmVrGpdZmTF1a)~v$k?6LPxpzd%$w=J$Y(IhOh+Yxr z`{xN$eIE~Q)95y$U&&^$(?dOu^~Y#gAJJ5iy)&!R8=;`Yh&{%3uL~}6!ENdX58K3i zY!6v}AoccAVdcg?*aL;iRQdSy2}I`D!HBxroY}=Zd)z}bCKm0#>Cv_hk({G!CppGn zSV<8*P4V0f;9+fup@OgZEndM5FY)?>&cXbjjkzIy2U-vI*4cL|vY+h;KCk$bD%!Gl z>mfKY%R^r4!lIXEK^8C>#M^#T{$^yz{})p{Zb>rWt8|5vy7+EtS){~Pj=1q@`YQw# zHU)CY_^^X2YUoY53|~Uubmy571@Rd!PG4Tv4Zb}4gLXQc#UYi0TM(4B{M8E6;7h2} z_pii=4uWdkR467#HfpPq9uQ?$@yvNK1W~c#7_eVKYm8|-qOk{)aog`&6VnR zBv5IGYnhyYdsD#ktR5-Mfe5QwKZ4_^1L<>R|d|X?e$|?ARm`WLzozt0p zJhrK;Xiu!m?7u5++=as8NX(Z$LL;myZ;t1eX272(p`N?&sgJBYRlE7po{n`6CgBio zw9=W0KcmWu`#3ty3;Z#FBLi=~6wpHGm@C zLjeK@CwQDL&o=iq32UXf5!51j?QuW&kq~202e2A43yb`{mYDF!$iDswv+?n{u*Gt{ z#L7}CYb7nXCa_pBp-E2LGgyyZG|@uLa`^(+aR8s;?T`4!J&c>FH``h=VR!S7H~X4+ zY~VyQaX`RITPEyh%yjG0>3hJ{jGuj|aQ|4J4j>*`m%Q-xEP^@|gP;y+W347^YH2un zp~Z?e;OA#7NXh=rgPz*WhlmW4-C4%eud8fgq1<`v?qdV~L-Ar}dkM@?C1&VWXE_!_ z)uHW~`W=*G9DbB!KfK|3p@Xq0GqQn*o)Q9>v9eYLzF`-7`eSie#UtvDAiW-0Q`M2u z*v605&4td~s+HbUou<@l{6U0d_qM*-K0ZDV@qs^>3BKg>RDgVZxYg-uwf#ZGfj3|D zj;{vAVn`B|Sgenu5BjkK^Km_oQ%V#1P?kUX*pmQR{$BYJf6kPDnKQw%&x51rl%yn! zoSN7hfX@q%*aLF=idNK*83^4cM@Grz$?MYtD#~4uOVF3+%a?=9>tuH*jZw z3>PofAyaX9J^Ki*BXZPJ^)i1$FCBL5Bn7Ycy&PGV-}+qUb?PU2f@pAvs5$9mHnhzQ zzIZrUSohqUT5>jDH3n`5h;%l)s)PNplcV$NwPX}{I9p$x1Fv0uYk+LlBeosZbh;did_>>( zQ-iE|W_b+8n+Mdz$2pjG{p0IB;ry@PUpp|u!U>K6F)fsbO=iUi2pXCY#0D#4pk?(E z7a8+gYTzMjsz0wOzn!b@alP~g)pA6#%l(J`P$~ErIgsTSJl-5D*H8h24R4A z|0-^$MKfwWd*-;mxsjLao}y8Q;kL*~Aggq@j%Dc*1yFcjGuVS7Dwx{wOHja%KAwZzgUjGCy5iN+rzM_Vc zc6hWwjdhmiU)*q#L>G$qOkyAK2P{(h{6~;locP;Tf0t#q+-@6(P$-nVSJxZlDmy-J z5h3{+7x!uBGDBvY@~tAh6c$NT@D5`z%JWM^msb@ry>%vhpK;?j*RuBBDWW@jHJtbd z_H%HTOX3kn_tB)cYOXc_6ao-@p4*2m;U>k19<3>;>rEW0sNm8%&`}+#UBXN2NQ^97 zn_a!}da&nJatMX5YrV`hgN`o@fYtIH#v_Cjb(V52R-d*f9UDSkAz0mfhi=IVRZ z)Jdk@`zq@U6!Q#J)u0fQo663x@!8z7o#*&R%+iwg76;^iMtRA6JJ&t0a^eR;{H9RX z**_K-5Gj0&bSCcSlDNO$&L%Rs=!W+iuDz$?!e5ugkV&jtd%qbEW}Gt$Pi{|iz_^w+ zXv$;d9%&8XsE@8@f6WzyV)99!Jg3X8NW}Y9PfrhHsr^pnw6arraZA){5GSh(V+dwM zAmoa1P~pn#x;+9iWYY3JYfn3R5=yY?pIua395{clu&onD=lVgi3krlw{%b!fKh6aR zkDe9qI`aihR*+il0+Dhy=S;|j-CoNw?`7EHQT*&VwS$J-C$!hDFLzV8ht>Exu&(}V zVOv@2{09YJ@jcz@`5f$?zmIWtzb}Fkt48`R&w?AdjckQNt}g4RfsJP9`$G?(6I4Y{ zc&0J1?%jxdl1OhUt3*3@{XLOp3wEfF@16;WpRBNtwZ9#UOF|YrpAm3T51CLy%wXfN<tmErt2} zNV&Dm;Z|pdR3>3u;Ku2UDKNbw8ZU~S9wJK4d;UiB>;e%mbiq@ZMM~!MNZJi)Sf(oy z`}Bw*eH&>RaGUEG%K_Ft=yvHc@t;1x2H_FKe?$7|=JE6G7e9J}wrn<@q!KrK$0ex}T8+w`7UT(stZkp` z3*zqrDvGNH$`yyhj&WDy|92f$5JHC_X+?$mjdHpLJqJyaQ*WqK+t-F=Zxj}+6LuM3 zss25cZ(ZNr7b{6$WQgAehxXYo<(tc-j$d9@kLcS5Zb*=pTM5zY12I96e%$8u4@|#+ z?Ulu~WUFw*-C^KY>&Qr&wcQPZ|8K2=3I-Cgw6yWb-xliO$jrqS900EaiPkH198wFC z1pKgI`5KqOd7?j)rI6qGMCsA$R?6?AR0CNBa((-*J#Xi+K8^SP)od8)fA5g7ooQln z>p05uPemsl!Tb!ltiF03 zpPM&hd$4r#(r>O3A-Ie2dYtJnI4_9$eeBHM8*!Ech@kFYWyQsv$H_@t zsY;xrFRA4d?lAve5$6`MD89@4r3$x4&eX2)KM|I1Xn)V*FpNcvjFfDAaxt%cJq!K0 z%qwQI7hL>r{~gE*@2B3%%x?K!O5zJ-;wYI{j87@F8Mu0TD1V>)@=Mu+or8_0pYHhF zbauN)<@cz7aWeG5SVIy_=lA~M32g>m9VujmqU2!kGDQ!!{zn$wA4w9asaU^`WBy+pvMld1)0X$Oq%V{|A}slzIRF literal 0 HcmV?d00001 diff --git a/doc/images/local-development/ApolloApplication-VM-Options.png b/doc/images/local-development/ApolloApplication-VM-Options.png new file mode 100644 index 0000000000000000000000000000000000000000..73aba7fed56156b72f2d836b3c538cc8e33a54c3 GIT binary patch literal 89402 zcmeFYcT}27_cm;*>85Cm8ucW`hOxJ(QPb>Q0lR4IJ+a1uq^hx=s93N!6tF8AD^a7y z9AA4H%PjWPC4eL+7PI()uJ!2^8ySscMoOOJv^OS+1JofUT&AAi# z;wyDiZw7`3OMiV%y|+Dg_axKS8EE2TN_ut%?7khX=;N%H?_%BKPk>vkJhOE>-W&SSkmuv}rvHxz7fq^cg@!~1)jn&!| zW7b_zW5?F?8j%>JM^b$E@$55F_3UmV<-JSz{O5)5KJF5| zy@N>Z{=}Y*$;A2^5;2ja)}Aˢ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

^YM2!aCh%@08V!)Hx;Fpy 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 literal 0 HcmV?d00001 diff --git a/docs/zh/development/apollo-development-guide.md b/docs/zh/development/apollo-development-guide.md index b84ea049351..3f98ae78a25 100644 --- a/docs/zh/development/apollo-development-guide.md +++ b/docs/zh/development/apollo-development-guide.md @@ -6,7 +6,7 @@ Apollo本地开发需要以下组件: 1. Java: 1.8+ -2. MySQL: 5.6.5+ +2. MySQL: 5.6.5+ (如果使用 H2 内存数据库/H2 文件数据库,则无需 MySQL) 3. IDE: 没有特殊要求 其中MySQL需要创建Apollo数据库并导入基础数据。 @@ -19,12 +19,12 @@ Apollo本地开发需要以下组件: 具体请参考[Apollo配置中心设计](zh/design/apollo-design) # 二、本地启动 -## 2.1 Apollo Config Service和Apollo Admin Service -我们在本地开发时,一般会在IDE中同时启动`apollo-configservice`和`apollo-adminservice`。 +## 2.1 Apollo Assembly +我们在本地开发时,一般会在IDE中启动`apollo-assembly`。 -下面以Intellij Community 2016.2版本为例来说明如何在本地启动`apollo-configservice`和`apollo-adminservice`。 +下面以Intellij Community 2016.2版本为例来说明如何在本地启动`apollo-assembly`。 -![ConfigAdminApplication-Overview](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ConfigAdminApplication-Overview.png) +![ApolloApplication-Overview](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ApolloApplication-Overview.png) ### 2.1.1 新建运行配置 ![NewConfiguration-Application](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/NewConfiguration-Application.png) @@ -32,21 +32,33 @@ Apollo本地开发需要以下组件: ### 2.1.2 Main class配置 `com.ctrip.framework.apollo.assembly.ApolloApplication` -> 注:如果希望独立启动`apollo-configservice`和`apollo-adminservice`,可以把Main Class分别换成 -> `com.ctrip.framework.apollo.configservice.ConfigServiceApplication`和 +> 注:如果希望独立启动`apollo-portal`、`apollo-configservice`和`apollo-adminservice`,可以把Main Class分别换成 +> `com.ctrip.framework.apollo.portal.PortalApplication` +> `com.ctrip.framework.apollo.configservice.ConfigServiceApplication` > `com.ctrip.framework.apollo.adminservice.AdminServiceApplication` ### 2.1.3 VM options配置 -![ConfigAdminApplication-VM-Options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ConfigAdminApplication-VM-Options.png) - - -Dapollo_profile=github - -Dspring.datasource.url=jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8 - -Dspring.datasource.username=root - -Dspring.datasource.password= +![ApolloApplication-VM-Options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ApolloApplication-VM-Options.png) +``` +-Dapollo_profile=github,auth ->注1:spring.datasource相关配置替换成你自己的数据库连接信息,注意数据库是`ApolloConfigDB` +``` +>注1:这里指定了apollo_profile是`github`和`auth`,其中`github`是Apollo必须的一个profile,用于数据库的配置,`auth`是从0.9.0新增的,用来支持使用apollo提供的Spring Security简单认证,更多信息可以参考[Portal-实现用户登录功能](zh/development/portal-how-to-implement-user-login-function) > ->注2:程序默认日志输出为/opt/logs/100003171/apollo-assembly.log,如果需要修改日志文件路径,可以增加`logging.file.name`参数,如下: +>注2:如果需要使用 mysql 数据库,添加spring.datasource相关配置,数据库连接信息替换成你自己的,注意数据库是`ApolloAssemblyDB` +![ApolloApplication-Mysql-VM-Options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ApolloApplication-Mysql-VM-Options.png) + +``` +-Dspring.datasource.url=jdbc:mysql://localhost:3306/ApolloAssemblyDB?characterEncoding=utf8 +-Dspring.datasource.username=root +-Dspring.datasource.password= + +``` +mysql 数据库初始化脚本见 本项目 scripts/sql/assembly/mysql 目录下的文件 +[apolloconfigdb.sql](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/scripts/sql/assembly/mysql/apolloconfigdb.sql) +[apolloportaldb.sql](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/scripts/sql/assembly/mysql/apolloportaldb.sql) + +>注3:程序默认日志输出为/opt/logs/100003171/apollo-assembly.log,如果需要修改日志文件路径,可以增加`logging.file.name`参数,如下: > >-Dlogging.file.name=/your-path/apollo-assembly.log diff --git a/scripts/sql/apolloportaldb.sql b/scripts/sql/apolloportaldb.sql index 14c2b88e2bf..41eed5785a6 100644 --- a/scripts/sql/apolloportaldb.sql +++ b/scripts/sql/apolloportaldb.sql @@ -421,7 +421,7 @@ CREATE TABLE `AuditLogDataInfluence` ( INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`) VALUES ('apollo.portal.envs', 'dev', '可支持的环境列表'), - ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), + ('organizations', '[{"orgId":"TEST1","orgName":"样例部门1"},{"orgId":"TEST2","orgName":"样例部门2"}]', '部门列表'), ('superAdmin', 'apollo', 'Portal超级管理员'), ('api.readTimeout', '10000', 'http接口read timeout'), ('consumer.token.salt', 'someSalt', 'consumer token salt'), diff --git a/scripts/sql/assembly/h2/apolloportaldb.sql b/scripts/sql/assembly/h2/apolloportaldb.sql index eccfbf0c544..f34a93bc0f3 100644 --- a/scripts/sql/assembly/h2/apolloportaldb.sql +++ b/scripts/sql/assembly/h2/apolloportaldb.sql @@ -421,7 +421,7 @@ CREATE TABLE `P_0_AuditLogDataInfluence` ( INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) VALUES ('apollo.portal.envs', 'dev', '可支持的环境列表'), - ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), + ('organizations', '[{"orgId":"TEST1","orgName":"样例部门1"},{"orgId":"TEST2","orgName":"样例部门2"}]', '部门列表'), ('superAdmin', 'apollo', 'Portal超级管理员'), ('api.readTimeout', '10000', 'http接口read timeout'), ('consumer.token.salt', 'someSalt', 'consumer token salt'), diff --git a/scripts/sql/assembly/mysql/apolloportaldb.sql b/scripts/sql/assembly/mysql/apolloportaldb.sql index 9eceb578d60..0aed78abda2 100644 --- a/scripts/sql/assembly/mysql/apolloportaldb.sql +++ b/scripts/sql/assembly/mysql/apolloportaldb.sql @@ -421,7 +421,7 @@ CREATE TABLE `P_0_AuditLogDataInfluence` ( INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) VALUES ('apollo.portal.envs', 'dev', '可支持的环境列表'), - ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), + ('organizations', '[{"orgId":"TEST1","orgName":"样例部门1"},{"orgId":"TEST2","orgName":"样例部门2"}]', '部门列表'), ('superAdmin', 'apollo', 'Portal超级管理员'), ('api.readTimeout', '10000', 'http接口read timeout'), ('consumer.token.salt', 'someSalt', 'consumer token salt'), From 4a6837f6c95dc6036348ad038eec57d177dc02cc Mon Sep 17 00:00:00 2001 From: vdisk Date: Sat, 30 Dec 2023 01:00:37 +0800 Subject: [PATCH 23/59] fix assembly sql temp v0.2 --- ...lyDataSourceScriptDatabaseInitializer.java | 21 + apollo-build-maven-extensions/pom.xml | 2 +- .../ApolloAssemblySqlConverter.java | 237 --------- .../sql/ApolloAssemblyH2ConverterUtil.java | 133 +++++ .../sql/ApolloAssemblyMysqlConverterUtil.java | 65 +++ .../sql/ApolloMainMysqlConverterUtil.java | 80 +++ .../extensions/sql/ApolloSqlConverter.java | 83 +++ .../sql/ApolloSqlConverterUtil.java | 160 ++++++ .../maven/extensions/sql/ConvertResult.java | 37 ++ .../maven/extensions/sql/SqlTemplate.java | 50 ++ .../sql/ApolloSqlConverterTest.java | 227 ++++++++ scripts/sql-src/apolloconfigdb.sql | 500 ++++++++++++++++++ scripts/sql-src/apolloportaldb.sql | 444 ++++++++++++++++ .../v220-v230/apolloconfigdb-v220-v230.sql | 23 + .../v220-v230/apolloportaldb-v220-v230.sql | 23 + .../auto-generated-declaration.sql | 23 + scripts/sql-template/h2-function.sql | 22 + scripts/sql-template/setup-database.sql | 22 + scripts/sql-template/use-database.sql | 19 + scripts/sql/apolloconfigdb.sql | 14 + scripts/sql/apolloportaldb.sql | 14 + scripts/sql/assembly/h2/apolloconfigdb.sql | 17 +- scripts/sql/assembly/h2/apolloportaldb.sql | 17 +- .../v220-v230/apolloconfigdb-v220-v230.sql | 18 + .../v220-v230/apolloportaldb-v220-v230.sql | 18 + scripts/sql/assembly/mysql/apolloconfigdb.sql | 14 + scripts/sql/assembly/mysql/apolloportaldb.sql | 14 + .../v220-v230/apolloconfigdb-v220-v230.sql | 16 + .../v220-v230/apolloportaldb-v220-v230.sql | 16 + .../v220-v230/apolloconfigdb-v220-v230.sql | 16 + .../v220-v230/apolloportaldb-v220-v230.sql | 16 + 31 files changed, 2119 insertions(+), 242 deletions(-) delete mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java create mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyH2ConverterUtil.java create mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyMysqlConverterUtil.java create mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloMainMysqlConverterUtil.java create mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java create mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterUtil.java create mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ConvertResult.java create mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplate.java create mode 100644 apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java create mode 100644 scripts/sql-src/apolloconfigdb.sql create mode 100644 scripts/sql-src/apolloportaldb.sql create mode 100644 scripts/sql-src/delta/v220-v230/apolloconfigdb-v220-v230.sql create mode 100644 scripts/sql-src/delta/v220-v230/apolloportaldb-v220-v230.sql create mode 100644 scripts/sql-template/auto-generated-declaration.sql create mode 100644 scripts/sql-template/h2-function.sql create mode 100644 scripts/sql-template/setup-database.sql create mode 100644 scripts/sql-template/use-database.sql diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java index 2ae988ca97b..ad14d2c707a 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java @@ -21,6 +21,8 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.security.CodeSource; +import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -30,6 +32,11 @@ import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.SingleColumnRowMapper; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; +import org.springframework.jdbc.support.JdbcUtils; +import org.springframework.jdbc.support.MetaDataAccessException; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -139,4 +146,18 @@ private static List scriptLocations(List locations, String fallb fallbackLocations.add("optional:classpath*:" + fallback + ".sql"); return fallbackLocations; } + + @Override + protected void customize(ResourceDatabasePopulator populator) { + DataSource dataSource = this.getDataSource(); + DatabaseDriver databaseDriver = DatabaseDriver.fromDataSource(dataSource); + if (DatabaseDriver.MYSQL.equals(databaseDriver)) { + JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); + String database = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class); + if (database != null) { + populator.setScripts(); + } + System.out.println(database); + } + } } diff --git a/apollo-build-maven-extensions/pom.xml b/apollo-build-maven-extensions/pom.xml index 85683a10868..ed46ab6dc66 100644 --- a/apollo-build-maven-extensions/pom.xml +++ b/apollo-build-maven-extensions/pom.xml @@ -54,7 +54,7 @@ - com.ctrip.framework.apollo.maven.extensions.ApolloAssemblySqlConverter + com.ctrip.framework.apollo.maven.extensions.sql.ApolloSqlConverter ${project.basedir} diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java deleted file mode 100644 index c5b90784c69..00000000000 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/ApolloAssemblySqlConverter.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright 2023 Apollo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.ctrip.framework.apollo.maven.extensions; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class ApolloAssemblySqlConverter { - - public static void main(String[] args) { - String moduleDir = args[0]; - String unixModuleDir = moduleDir.replace("\\", "/"); - String repositoryDir = unixModuleDir.replace("/apollo-build-maven-extensions", ""); - - String assemblyMysqlDir = repositoryDir + "/scripts/sql/assembly/mysql"; - - List assemblyMysqlSqlList = new ArrayList<>(); - assemblyMysqlSqlList.add(assemblyMysqlDir + "/apolloconfigdb.sql"); - assemblyMysqlSqlList.add(assemblyMysqlDir + "/apolloportaldb.sql"); - List assemblyMysqlDeltaSqlList = getAssemblyMysqlDeltaSqlList(assemblyMysqlDir); - assemblyMysqlSqlList.addAll(assemblyMysqlDeltaSqlList); - - // '/scripts/sql/assembly/mysql' -> '/scripts/sql' - convertMainMysqlList(assemblyMysqlSqlList, assemblyMysqlDir, repositoryDir); - - // '/scripts/sql/assembly/mysql' -> '/scripts/sql/assembly/h2' - convertAssemblyH2List(assemblyMysqlSqlList, assemblyMysqlDir, repositoryDir); - } - - private static void convertMainMysqlList(List assemblyMysqlSqlList, - String assemblyMysqlDir, String repositoryDir) { - String targetDir = repositoryDir + "/scripts/sql"; - for (String filePath : assemblyMysqlSqlList) { - if (!filePath.contains(assemblyMysqlDir)) { - throw new IllegalArgumentException("illegal file path: " + filePath); - } - String targetFilePath = filePath.replace(assemblyMysqlDir, targetDir); - String databaseName; - if (filePath.contains("apolloconfigdb")) { - databaseName = "ApolloConfigDB"; - } else if (filePath.contains("apolloportaldb")) { - databaseName = "ApolloPortalDB"; - } else { - throw new IllegalArgumentException("unknown database name: " + filePath); - } - - ensureDirectories(targetFilePath); - - try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(filePath), - StandardCharsets.UTF_8); - BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetFilePath), - StandardCharsets.UTF_8, StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING)) { - for (String line = bufferedReader.readLine(); line != null; - line = bufferedReader.readLine()) { - String convertedLine = line.replace("P_0_", "").replace("C_0_", "") - .replace("ApolloAssemblyDB", databaseName); - bufferedWriter.write(convertedLine); - bufferedWriter.write('\n'); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - private static void ensureDirectories(String targetFilePath) { - Path path = Paths.get(targetFilePath); - Path dirPath = path.getParent(); - try { - Files.createDirectories(dirPath); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private static void convertAssemblyH2List(List assemblyMysqlSqlList, - String assemblyMysqlDir, String repositoryDir) { - String targetDir = repositoryDir + "/scripts/sql/assembly/h2"; - for (String filePath : assemblyMysqlSqlList) { - if (!filePath.contains(assemblyMysqlDir)) { - throw new IllegalArgumentException("illegal file path: " + filePath); - } - String targetFilePath = filePath.replace(assemblyMysqlDir, targetDir); - - ensureDirectories(targetFilePath); - - try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(filePath), - StandardCharsets.UTF_8); - BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetFilePath), - StandardCharsets.UTF_8, StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING)) { - for (String line = bufferedReader.readLine(); line != null; - line = bufferedReader.readLine()) { - String convertedLine = convertAssemblyH2ListLine(line); - bufferedWriter.write(convertedLine); - bufferedWriter.write('\n'); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - } - - private static String convertAssemblyH2ListLine(String line) { - // database config - if (line.contains("Use ") - || line.contains("DROP TABLE")) { - return ""; - } else if (line.contains("CREATE DATABASE")) { - return "CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR \"com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp\";"; - } - String convertedLine = line; - - // table config - if (convertedLine.contains("ENGINE=InnoDB")) { - convertedLine = convertedLine.replace("ENGINE=InnoDB", ""); - } - if (convertedLine.contains("DEFAULT CHARSET=utf8mb4")) { - convertedLine = convertedLine.replace("DEFAULT CHARSET=utf8mb4", ""); - } - if (convertedLine.contains("ROW_FORMAT=DYNAMIC")) { - convertedLine = convertedLine.replace("ROW_FORMAT=DYNAMIC", ""); - } - Pattern tableCommentPattern = Pattern.compile("COMMENT='[^']*'"); - Matcher tableCommentMatcher = tableCommentPattern.matcher(convertedLine); - if (tableCommentMatcher.find()) { - convertedLine = tableCommentMatcher.replaceAll(""); - } - - // index - if (line.contains("KEY")) { - Pattern indexNamePattern = Pattern.compile("KEY *`[a-zA-Z0-9\\-_]+` *"); - Matcher indexNameMatcher = indexNamePattern.matcher(convertedLine); - if (indexNameMatcher.find()) { - convertedLine = indexNameMatcher.replaceAll("KEY "); - } - Pattern indexPrefixPattern = Pattern.compile("(`[a-zA-Z0-9\\-_]+`)\\([0-9]+\\)"); - for (Matcher indexPrefixMatcher = indexPrefixPattern.matcher(convertedLine); - indexPrefixMatcher.find(); - indexPrefixMatcher = indexPrefixPattern.matcher(convertedLine)) { - convertedLine = indexPrefixMatcher.replaceAll("$1"); - } - } - - // column config - if (line.contains("bit(1)")) { - convertedLine = convertedLine.replace("bit(1)", "boolean"); - } - if (line.contains("b'0'")) { - convertedLine = convertedLine.replace("b'0'", "FALSE"); - } - Pattern columnCommentPattern = Pattern.compile("COMMENT *'[^']*'"); - Matcher columnCommentMatcher = columnCommentPattern.matcher(convertedLine); - if (columnCommentMatcher.find()) { - convertedLine = columnCommentMatcher.replaceAll(""); - } - - // white space - Pattern whiteSpacePrefixPattern = Pattern.compile("^(\\s+)"); - Matcher whiteSpacePrefixMatcher = whiteSpacePrefixPattern.matcher(convertedLine); - String whiteSpacePrefix; - if (whiteSpacePrefixMatcher.find()) { - whiteSpacePrefix = whiteSpacePrefixMatcher.group(1); - } else { - whiteSpacePrefix = ""; - } - - Pattern whiteSpacePattern = Pattern.compile("\\s{2,}"); - Matcher whiteSpaceMatcher = whiteSpacePattern.matcher(convertedLine); - if (whiteSpaceMatcher.find()) { - convertedLine = whiteSpaceMatcher.replaceAll(" "); - } - return whiteSpacePrefix + convertedLine.trim(); - } - - private static List getAssemblyMysqlDeltaSqlList(String assemblyMysqlDir) { - Path dir = Paths.get(assemblyMysqlDir + "/delta"); - if (!Files.exists(dir)) { - return Collections.emptyList(); - } - List deltaDirList = new ArrayList<>(); - try (DirectoryStream ds = Files.newDirectoryStream(dir)) { - for (Path path : ds) { - if (Files.isDirectory(path)) { - deltaDirList.add(path); - } - } - } catch (IOException e) { - throw new UncheckedIOException("failed to open assemblyMysqlDir" + e.getLocalizedMessage(), - e); - } - List assemblyMysqlDeltaSqlList = new ArrayList<>(); - for (Path deltaDir : deltaDirList) { - try (DirectoryStream ds = Files.newDirectoryStream(deltaDir)) { - for (Path path : ds) { - String fileName = path.toString(); - if (fileName.endsWith(".sql")) { - assemblyMysqlDeltaSqlList.add(fileName.replace("\\", "/")); - } - } - } catch (IOException e) { - throw new UncheckedIOException("failed to open assemblyMysqlDir" + e.getLocalizedMessage(), - e); - } - } - - return assemblyMysqlDeltaSqlList; - } -} diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyH2ConverterUtil.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyH2ConverterUtil.java new file mode 100644 index 00000000000..29251bbcffa --- /dev/null +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyH2ConverterUtil.java @@ -0,0 +1,133 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.maven.extensions.sql; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ApolloAssemblyH2ConverterUtil { + + public static void convertAssemblyH2(String srcSql, String targetSql, + Map templates) { + + ApolloSqlConverterUtil.ensureDirectories(targetSql); + + try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(srcSql), + StandardCharsets.UTF_8); + BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), + StandardCharsets.UTF_8, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING)) { + for (String line = bufferedReader.readLine(); line != null; + line = bufferedReader.readLine()) { + String convertedLine = convertAssemblyH2Line(line, templates); + bufferedWriter.write(convertedLine); + bufferedWriter.write('\n'); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private static String convertAssemblyH2Line(String line, Map templates) { + String convertedLine = line; + ConvertResult result = ApolloSqlConverterUtil.convertTemplate(convertedLine, + "auto-generated-declaration", templates); + convertedLine = result.convertedLine(); + if (result.matches()) { + return convertedLine; + } + convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "h2-function", templates).convertedLine(); + convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "setup-database", SqlTemplate.empty()).convertedLine(); + convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "use-database", SqlTemplate.empty()).convertedLine(); + + // database config + if (convertedLine.contains("DROP TABLE")) { + return ""; + } + + // table config + if (convertedLine.contains("ENGINE=InnoDB")) { + convertedLine = convertedLine.replace("ENGINE=InnoDB", ""); + } + if (convertedLine.contains("DEFAULT CHARSET=utf8mb4")) { + convertedLine = convertedLine.replace("DEFAULT CHARSET=utf8mb4", ""); + } + if (convertedLine.contains("ROW_FORMAT=DYNAMIC")) { + convertedLine = convertedLine.replace("ROW_FORMAT=DYNAMIC", ""); + } + Pattern tableCommentPattern = Pattern.compile("COMMENT='[^']*'"); + Matcher tableCommentMatcher = tableCommentPattern.matcher(convertedLine); + if (tableCommentMatcher.find()) { + convertedLine = tableCommentMatcher.replaceAll(""); + } + + // index + if (convertedLine.contains("KEY")) { + Pattern indexNamePattern = Pattern.compile("KEY *`[a-zA-Z0-9\\-_]+` *"); + Matcher indexNameMatcher = indexNamePattern.matcher(convertedLine); + if (indexNameMatcher.find()) { + convertedLine = indexNameMatcher.replaceAll("KEY "); + } + Pattern indexPrefixPattern = Pattern.compile("(`[a-zA-Z0-9\\-_]+`)\\([0-9]+\\)"); + for (Matcher indexPrefixMatcher = indexPrefixPattern.matcher(convertedLine); + indexPrefixMatcher.find(); + indexPrefixMatcher = indexPrefixPattern.matcher(convertedLine)) { + convertedLine = indexPrefixMatcher.replaceAll("$1"); + } + } + + // column config + if (convertedLine.contains("bit(1)")) { + convertedLine = convertedLine.replace("bit(1)", "boolean"); + } + if (convertedLine.contains("b'0'")) { + convertedLine = convertedLine.replace("b'0'", "FALSE"); + } + Pattern columnCommentPattern = Pattern.compile("COMMENT *'[^']*'"); + Matcher columnCommentMatcher = columnCommentPattern.matcher(convertedLine); + if (columnCommentMatcher.find()) { + convertedLine = columnCommentMatcher.replaceAll(""); + } + + // white space + Pattern whiteSpacePrefixPattern = Pattern.compile("^(\\s+)"); + Matcher whiteSpacePrefixMatcher = whiteSpacePrefixPattern.matcher(convertedLine); + String whiteSpacePrefix; + if (whiteSpacePrefixMatcher.find()) { + whiteSpacePrefix = whiteSpacePrefixMatcher.group(1); + } else { + whiteSpacePrefix = ""; + } + + Pattern whiteSpacePattern = Pattern.compile("\\s{2,}"); + Matcher whiteSpaceMatcher = whiteSpacePattern.matcher(convertedLine); + if (whiteSpaceMatcher.find()) { + convertedLine = whiteSpaceMatcher.replaceAll(" "); + } + return whiteSpacePrefix + convertedLine.trim(); + } +} diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyMysqlConverterUtil.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyMysqlConverterUtil.java new file mode 100644 index 00000000000..553b65e53aa --- /dev/null +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyMysqlConverterUtil.java @@ -0,0 +1,65 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.maven.extensions.sql; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Map; + +public class ApolloAssemblyMysqlConverterUtil { + + public static void convertAssemblyMysql(String srcSql, String targetSql, + Map templates) { + + ApolloSqlConverterUtil.ensureDirectories(targetSql); + + try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(srcSql), + StandardCharsets.UTF_8); + BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), + StandardCharsets.UTF_8, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING)) { + for (String line = bufferedReader.readLine(); line != null; + line = bufferedReader.readLine()) { + String convertedLine = convertAssemblyMysqlLine(line, templates); + bufferedWriter.write(convertedLine); + bufferedWriter.write('\n'); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private static String convertAssemblyMysqlLine(String line, Map templates) { + String convertedLine = line; + ConvertResult result = ApolloSqlConverterUtil.convertTemplate(convertedLine, + "auto-generated-declaration", templates); + convertedLine = result.convertedLine(); + if (result.matches()) { + return convertedLine; + } + convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "h2-function", SqlTemplate.empty()).convertedLine(); + convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "setup-database", templates).convertedLine(); + convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "use-database", templates).convertedLine(); + return convertedLine; + } +} diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloMainMysqlConverterUtil.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloMainMysqlConverterUtil.java new file mode 100644 index 00000000000..4e7d3571a53 --- /dev/null +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloMainMysqlConverterUtil.java @@ -0,0 +1,80 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.maven.extensions.sql; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Map; +import java.util.Objects; + +public class ApolloMainMysqlConverterUtil { + + public static void convertMainMysql(String srcSql, String targetSql, + Map templates) { + String databaseName; + if (srcSql.contains("apolloconfigdb")) { + databaseName = "ApolloConfigDB"; + } else if (srcSql.contains("apolloportaldb")) { + databaseName = "ApolloPortalDB"; + } else { + throw new IllegalArgumentException("unknown database name: " + srcSql); + } + + ApolloSqlConverterUtil.ensureDirectories(targetSql); + + try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(srcSql), + StandardCharsets.UTF_8); + BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), + StandardCharsets.UTF_8, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING)) { + for (String line = bufferedReader.readLine(); line != null; + line = bufferedReader.readLine()) { + String convertedLine = convertMainMysqlLine(line, databaseName, templates); + bufferedWriter.write(convertedLine); + bufferedWriter.write('\n'); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static String convertMainMysqlLine(String line, String databaseName, + Map templates) { + String convertedLine = line; + ConvertResult result = ApolloSqlConverterUtil.convertTemplate(convertedLine, + "auto-generated-declaration", templates); + convertedLine = result.convertedLine(); + if (result.matches()) { + return convertedLine; + } + convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "h2-function", + SqlTemplate.empty()).convertedLine(); + convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "setup-database", + templates).convertedLine(); + convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "use-database", templates) + .convertedLine(); + + convertedLine = convertedLine.replace("P_0_", "").replace("C_0_", "") + .replace("ApolloAssemblyDB", databaseName); + return convertedLine; + } +} diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java new file mode 100644 index 00000000000..b68eb65b161 --- /dev/null +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java @@ -0,0 +1,83 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.maven.extensions.sql; + +import java.util.List; +import java.util.Map; + +public class ApolloSqlConverter { + + public static void main(String[] args) { + String moduleDir = args[0]; + String unixModuleDir = moduleDir.replace("\\", "/"); + String repositoryDir = ApolloSqlConverterUtil.replacePath(unixModuleDir, + "/apollo-build-maven-extensions", ""); + + Map templates = ApolloSqlConverterUtil.getTemplates(repositoryDir); + + String srcDir = repositoryDir + "/scripts/sql-src"; + String targetParentDir = repositoryDir + "/scripts"; + + convert(srcDir, targetParentDir, templates); + } + + public static List convert(String srcDir, String targetParentDir, + Map templates) { + // '/scripts/sql-src/apolloconfigdb.sql' + // '/scripts/sql-src/apolloportaldb.sql' + // '/scripts/sql-src/delta/**/*.sql' + List srcSqlList = ApolloSqlConverterUtil.getSqlList(srcDir); + + // '/scripts/sql-src' -> '/scripts/sql' + convertMainMysqlList(srcSqlList, srcDir, targetParentDir, templates); + + // '/scripts/sql-src' -> '/scripts/sql/assembly/mysql' + convertAssemblyMysqlList(srcSqlList, srcDir, targetParentDir, templates); + + // '/scripts/sql-src' -> '/scripts/sql/assembly/h2' + convertAssemblyH2List(srcSqlList, srcDir, targetParentDir, templates); + + return srcSqlList; + } + + private static void convertMainMysqlList(List srcSqlList, + String srcDir, String targetParentDir, Map templates) { + String targetDir = targetParentDir + "/sql"; + for (String srcSql : srcSqlList) { + String targetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, targetDir); + ApolloMainMysqlConverterUtil.convertMainMysql(srcSql, targetSql, templates); + } + } + + private static void convertAssemblyMysqlList(List srcSqlList, String srcDir, + String targetParentDir, Map templates) { + String targetDir = targetParentDir + "/sql/assembly/mysql"; + for (String srcSql : srcSqlList) { + String targetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, targetDir); + ApolloAssemblyMysqlConverterUtil.convertAssemblyMysql(srcSql, targetSql, templates); + } + } + + private static void convertAssemblyH2List(List srcSqlList, + String srcDir, String targetParentDir, Map templates) { + String targetDir = targetParentDir + "/sql/assembly/h2"; + for (String srcSql : srcSqlList) { + String targetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, targetDir); + ApolloAssemblyH2ConverterUtil.convertAssemblyH2(srcSql, targetSql, templates); + } + } +} diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterUtil.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterUtil.java new file mode 100644 index 00000000000..161143ddf2a --- /dev/null +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterUtil.java @@ -0,0 +1,160 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.maven.extensions.sql; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringJoiner; + +public class ApolloSqlConverterUtil { + + public static void ensureDirectories(String targetFilePath) { + Path path = Paths.get(targetFilePath); + Path dirPath = path.getParent(); + try { + Files.createDirectories(dirPath); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public static String replacePath(String origin, String src, String target) { + if (!origin.contains(src)) { + throw new IllegalArgumentException("illegal file path: " + origin); + } + return origin.replace(src, target); + } + + public static Map getTemplates(String repositoryDir) { + String templateDir = repositoryDir + "/scripts/sql-template"; + Map templates = new LinkedHashMap<>(); + List templateFiles = list(Paths.get(templateDir)); + for (Path templatePath : templateFiles) { + String fileName = templatePath.getFileName().toString(); + String templateName = replacePath(fileName, ".sql", ""); + + StringJoiner joiner = new StringJoiner("\n"); + boolean accept = false; + try (BufferedReader bufferedReader = Files.newBufferedReader(templatePath, + StandardCharsets.UTF_8)) { + for (String line = bufferedReader.readLine(); line != null; + line = bufferedReader.readLine()) { + if (line.contains("@@template-start@@")) { + accept = true; + continue; + } + if (line.contains("@@template-end@@")) { + break; + } + if (accept) { + joiner.add(line); + } + } + } catch (IOException e) { + throw new UncheckedIOException("failed to open templatePath " + e.getLocalizedMessage(), e); + } + String value = joiner.toString(); + SqlTemplate template = new SqlTemplate(templateName, "@@${" + templateName + "}@@", value); + templates.put(templateName, template); + } + return templates; + } + + public static ConvertResult convertTemplate(String line, String name, + Map templates) { + return convertTemplate(line, name, templates.get(name)); + } + + public static ConvertResult convertTemplate(String line, String name, + SqlTemplate template) { + if (template == null) { + throw new IllegalArgumentException("template not found: " + name); + } + String key = "@@${" + name + "}@@"; + if (line.contains(key)) { + return new ConvertResult(true, template.getValue()); + } + return new ConvertResult(false, line); + } + + public static List getSqlList(String dir, Set ignoreDirs) { + List sqlList = new ArrayList<>(); + if (Files.exists(Paths.get(dir + "/apolloconfigdb.sql"))) { + sqlList.add(dir + "/apolloconfigdb.sql"); + } + if (Files.exists(Paths.get(dir + "/apolloportaldb.sql"))) { + sqlList.add(dir + "/apolloportaldb.sql"); + } + List deltaSqlList = getDeltaSqlList(dir, ignoreDirs); + sqlList.addAll(deltaSqlList); + return sqlList; + } + + public static List getSqlList(String dir) { + return getSqlList(dir, Collections.emptySet()); + } + + public static List list(Path dir) { + List subPathList = new ArrayList<>(); + try (DirectoryStream ds = Files.newDirectoryStream(dir)) { + for (Path path : ds) { + subPathList.add(path); + } + } catch (IOException e) { + throw new UncheckedIOException("failed to open dir " + e.getLocalizedMessage(), e); + } + return subPathList; + } + + private static List getDeltaSqlList(String dir, Set ignoreDirs) { + Path dirPath = Paths.get(dir + "/delta"); + if (!Files.exists(dirPath)) { + return Collections.emptyList(); + } + List deltaDirList = list(dirPath); + List deltaSqlList = new ArrayList<>(); + for (Path deltaDir : deltaDirList) { + if (!Files.isDirectory(deltaDir)) { + continue; + } + if (ignoreDirs.contains(deltaDir.toString().replace("\\", "/"))) { + continue; + } + List deltaFiles = list(deltaDir); + for (Path path : deltaFiles) { + String fileName = path.toString(); + if (fileName.endsWith(".sql")) { + deltaSqlList.add(fileName.replace("\\", "/")); + } + } + } + + return deltaSqlList; + } +} diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ConvertResult.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ConvertResult.java new file mode 100644 index 00000000000..2f3eec52dda --- /dev/null +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ConvertResult.java @@ -0,0 +1,37 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.maven.extensions.sql; + +public class ConvertResult { + + private final boolean matches; + + private final String convertedLine; + + public ConvertResult(boolean matches, String convertedLine) { + this.matches = matches; + this.convertedLine = convertedLine; + } + + public boolean matches() { + return this.matches; + } + + public String convertedLine() { + return this.convertedLine; + } +} diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplate.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplate.java new file mode 100644 index 00000000000..ddabc4dab53 --- /dev/null +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplate.java @@ -0,0 +1,50 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.maven.extensions.sql; + +public class SqlTemplate { + + private static final SqlTemplate EMPTY = new SqlTemplate("empty", "@@${empty}@@", ""); + + private final String name; + + private final String key; + + private final String value; + + public SqlTemplate(String name, String key, String value) { + this.name = name; + this.key = key; + this.value = value; + } + + public static SqlTemplate empty() { + return EMPTY; + } + + public String getName() { + return this.name; + } + + public String getKey() { + return this.key; + } + + public String getValue() { + return this.value; + } +} diff --git a/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java b/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java new file mode 100644 index 00000000000..d06b5fc1f97 --- /dev/null +++ b/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java @@ -0,0 +1,227 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.maven.extensions.sql; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.CodeSource; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class ApolloSqlConverterTest { + + @Test + void checkSql() throws URISyntaxException { + String repositoryDir = this.getRepositoryDir(); + + Map templates = ApolloSqlConverterUtil.getTemplates(repositoryDir); + + String srcDir = repositoryDir + "/scripts/sql-src"; + String checkerParentDir = repositoryDir + "/apollo-build-maven-extensions/target/scripts"; + String repositoryParentDir = repositoryDir + "/scripts"; + + // generate checker sql files + List srcSqlList = ApolloSqlConverter.convert(srcDir, checkerParentDir, templates); + + // compare checker sql files with repository sql files + this.checkSqlList(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); + } + + private String getRepositoryDir() throws URISyntaxException { + ProtectionDomain protectionDomain = ApolloSqlConverterTest.class.getProtectionDomain(); + CodeSource codeSource = protectionDomain.getCodeSource(); + URL location = codeSource.getLocation(); + URI uri = location.toURI(); + Path path = Paths.get(uri); + String unixClassPath = path.toString().replace("\\", "/"); + + Assertions.assertTrue( + unixClassPath.endsWith("/apollo-build-maven-extensions/target/test-classes")); + + return ApolloSqlConverterUtil.replacePath(unixClassPath, + "/apollo-build-maven-extensions/target/test-classes", ""); + } + + private void checkSqlList(List srcSqlList, String srcDir, String checkerParentDir, + String repositoryParentDir) { + + // '/scripts/sql' + this.checkMainMysqlList(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); + + // '/scripts/sql/assembly/mysql' + this.checkAssemblyMysqlList(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); + + // '/scripts/sql/assembly/h2' + this.checkAssemblyH2List(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); + } + + private void checkMainMysqlList(List srcSqlList, String srcDir, + String checkerParentDir, String repositoryParentDir) { + String checkerTargetDir = checkerParentDir + "/sql"; + String repositoryTargetDir = repositoryParentDir + "/sql"; + + List checkerSqlList = ApolloSqlConverterUtil.getSqlList(checkerTargetDir); + + Set ignoreDirs = this.getIgnoreDirs(repositoryTargetDir); + List repositorySqlList = ApolloSqlConverterUtil.getSqlList(repositoryTargetDir, + ignoreDirs); + + List redundantSqlList = this.findRedundantSqlList(checkerTargetDir, checkerSqlList, + repositoryTargetDir, repositorySqlList); + Assertions.assertEquals(0, redundantSqlList.size(), + "redundant sql files, please add sql files in 'scripts/sql-src' and then run 'mvn compile -Psql-convert' to generated. Do not edit 'scripts/sql' manually !!!\npath: " + + redundantSqlList); + + List missingSqlList = this.findMissingSqlList(checkerTargetDir, checkerSqlList, + repositoryTargetDir, repositorySqlList); + Assertions.assertEquals(0, missingSqlList.size(), + "missing sql files, please run 'mvn compile -Psql-convert' to regenerated\npath: " + + missingSqlList); + + for (String srcSql : srcSqlList) { + String checkerTargetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, + checkerTargetDir); + String repositoryTargetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, + repositoryTargetDir); + + this.doCheck(checkerTargetSql, repositoryTargetSql); + } + } + + private Set getIgnoreDirs(String repositoryTargetDir) { + Set ignoreDirs = new LinkedHashSet<>(); + ignoreDirs.add(repositoryTargetDir + "/delta/v040-v050"); + ignoreDirs.add(repositoryTargetDir + "/delta/v060-v062"); + ignoreDirs.add(repositoryTargetDir + "/delta/v080-v090"); + ignoreDirs.add(repositoryTargetDir + "/delta/v151-v160"); + ignoreDirs.add(repositoryTargetDir + "/delta/v170-v180"); + ignoreDirs.add(repositoryTargetDir + "/delta/v180-v190"); + ignoreDirs.add(repositoryTargetDir + "/delta/v190-v200"); + ignoreDirs.add(repositoryTargetDir + "/delta/v200-v210"); + ignoreDirs.add(repositoryTargetDir + "/delta/v210-v220"); + return ignoreDirs; + } + + private List findRedundantSqlList(String checkerTargetDir, List checkerSqlList, + String repositoryTargetDir, List repositorySqlList) { + // repository - checker + Map missingSqlMap = this.findMissing( + repositoryTargetDir, repositorySqlList, checkerTargetDir, checkerSqlList); + return new ArrayList<>(missingSqlMap.keySet()); + } + + private List findMissingSqlList(String checkerTargetDir, List checkerSqlList, + String repositoryTargetDir, List repositorySqlList) { + // checker - repository + Map missingSqlMap = this.findMissing(checkerTargetDir, checkerSqlList, + repositoryTargetDir, repositorySqlList); + return new ArrayList<>(missingSqlMap.values()); + } + + private Map findMissing(String sourceDir, List sourceSqlList, + String targetDir, List targetSqlList) { + Map missingSqlList = new LinkedHashMap<>(); + Set targetSqlSet = new LinkedHashSet<>(targetSqlList); + for (String sourceSql : sourceSqlList) { + String targetSql = ApolloSqlConverterUtil.replacePath(sourceSql, sourceDir, targetDir); + if (!targetSqlSet.contains(targetSql)) { + missingSqlList.put(sourceSql, targetSql); + } + } + return missingSqlList; + } + + private void doCheck(String checkerTargetSql, String repositoryTargetSql) { + List checkerLines = new ArrayList<>(); + try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(checkerTargetSql), + StandardCharsets.UTF_8)) { + for (String line = bufferedReader.readLine(); line != null; + line = bufferedReader.readLine()) { + checkerLines.add(line); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + List repositoryLines = new ArrayList<>(); + try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(repositoryTargetSql), + StandardCharsets.UTF_8)) { + for (String line = bufferedReader.readLine(); line != null; + line = bufferedReader.readLine()) { + repositoryLines.add(line); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + Assertions.assertEquals(checkerLines.size(), repositoryLines.size(), + "invalid sql files, please run 'mvn compile -Psql-convert' to regenerated\npath: " + + repositoryTargetSql); + for (int i = 0; i < checkerLines.size(); i++) { + String checkerLine = checkerLines.get(i); + String repositoryLine = repositoryLines.get(i); + int lineNumber = i + 1; + Assertions.assertEquals(checkerLine, repositoryLine, + "invalid sql file content, please run 'mvn compile -Psql-convert' to regenerated\npath: " + + repositoryTargetSql + "(line: " + lineNumber + ")"); + } + } + + private void checkAssemblyMysqlList(List srcSqlList, String srcDir, + String checkerParentDir, String repositoryParentDir) { + String checkerTargetDir = checkerParentDir + "/sql/assembly/mysql"; + String repositoryTargetDir = repositoryParentDir + "/sql/assembly/mysql"; + for (String srcSql : srcSqlList) { + String checkerTargetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, + checkerTargetDir); + String repositoryTargetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, + repositoryTargetDir); + + this.doCheck(checkerTargetSql, repositoryTargetSql); + } + } + + private void checkAssemblyH2List(List srcSqlList, String srcDir, + String checkerParentDir, String repositoryParentDir) { + String checkerTargetDir = checkerParentDir + "/sql/assembly/h2"; + String repositoryTargetDir = repositoryParentDir + "/sql/assembly/h2"; + for (String srcSql : srcSqlList) { + String checkerTargetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, + checkerTargetDir); + String repositoryTargetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, + repositoryTargetDir); + + this.doCheck(checkerTargetSql, repositoryTargetSql); + } + } + +} \ No newline at end of file diff --git a/scripts/sql-src/apolloconfigdb.sql b/scripts/sql-src/apolloconfigdb.sql new file mode 100644 index 00000000000..5d79fcd38ab --- /dev/null +++ b/scripts/sql-src/apolloconfigdb.sql @@ -0,0 +1,500 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- @@${auto-generated-declaration}@@ +-- @@${h2-function}@@ +-- @@${setup-database}@@ + +-- Dump of table app +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_App`; + +CREATE TABLE `C_0_App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +-- Dump of table appnamespace +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AppNamespace`; + +CREATE TABLE `C_0_AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +-- Dump of table audit +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Audit`; + +CREATE TABLE `C_0_Audit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID', + `OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表'; + + + +-- Dump of table cluster +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Cluster`; + +CREATE TABLE `C_0_Cluster` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id', + `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `IX_ParentClusterId` (`ParentClusterId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群'; + + + +-- Dump of table commit +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Commit`; + +CREATE TABLE `C_0_Commit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `ChangeSets` longtext NOT NULL COMMENT '修改变更集', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `AppId` (`AppId`), + KEY `ClusterName` (`ClusterName`(191)), + KEY `NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表'; + +-- Dump of table grayreleaserule +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_GrayReleaseRule`; + +CREATE TABLE `C_0_GrayReleaseRule` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name', + `Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release', + `BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表'; + + +-- Dump of table instance +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Instance`; + +CREATE TABLE `C_0_Instance` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name', + `Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`), + KEY `IX_IP` (`Ip`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例'; + + + +-- Dump of table instanceconfig +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_InstanceConfig`; + +CREATE TABLE `C_0_InstanceConfig` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id', + `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id', + `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name', + `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), + KEY `IX_ReleaseKey` (`ReleaseKey`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息'; + + + +-- Dump of table item +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Item`; + +CREATE TABLE `C_0_Item` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '配置项类型,0: String,1: Number,2: Boolean,3: JSON', + `Value` longtext NOT NULL COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_GroupId` (`NamespaceId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目'; + + + +-- Dump of table namespace +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Namespace`; + +CREATE TABLE `C_0_Namespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间'; + + + +-- Dump of table namespacelock +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_NamespaceLock`; + +CREATE TABLE `C_0_NamespaceLock` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁'; + + + +-- Dump of table release +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Release`; + +CREATE TABLE `C_0_Release` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字', + `Comment` varchar(256) DEFAULT NULL COMMENT '发布说明', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Configurations` longtext NOT NULL COMMENT '发布配置', + `IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`), + KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布'; + + +-- Dump of table releasehistory +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ReleaseHistory`; + +CREATE TABLE `C_0_ReleaseHistory` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id', + `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId', + `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度', + `OperationContext` longtext NOT NULL COMMENT '发布上下文信息', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), + KEY `IX_ReleaseId` (`ReleaseId`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PreviousReleaseId` (`PreviousReleaseId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史'; + + +-- Dump of table releasemessage +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ReleaseMessage`; + +CREATE TABLE `C_0_ReleaseMessage` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Message` (`Message`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息'; + + + +-- Dump of table serverconfig +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ServerConfig`; + +CREATE TABLE `C_0_ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + +-- Dump of table accesskey +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AccessKey`; + +CREATE TABLE `C_0_AccessKey` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret', + `IsEnabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: enabled, 0: disabled', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; + + +-- Dump of table serviceregistry +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ServiceRegistry`; + +CREATE TABLE `C_0_ServiceRegistry` ( + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', + `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), + INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; + +-- Dump of table AuditLog +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AuditLog`; + +CREATE TABLE `C_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + +-- Dump of table AuditLogDataInfluence +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AuditLogDataInfluence`; + +CREATE TABLE `C_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + +-- Config +-- ------------------------------------------------------------ +INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +VALUES + ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), + ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), + ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'), + ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), + ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); + +-- @@${auto-generated-declaration}@@ + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/scripts/sql-src/apolloportaldb.sql b/scripts/sql-src/apolloportaldb.sql new file mode 100644 index 00000000000..3342995dab2 --- /dev/null +++ b/scripts/sql-src/apolloportaldb.sql @@ -0,0 +1,444 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- @@${auto-generated-declaration}@@ +-- @@${h2-function}@@ +-- @@${setup-database}@@ + +-- Dump of table app +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_App`; + +CREATE TABLE `P_0_App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +-- Dump of table appnamespace +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_AppNamespace`; + +CREATE TABLE `P_0_AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +-- Dump of table consumer +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Consumer`; + +CREATE TABLE `P_0_Consumer` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者'; + + + +-- Dump of table consumeraudit +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerAudit`; + +CREATE TABLE `P_0_ConsumerAudit` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri', + `Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_ConsumerId` (`ConsumerId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表'; + + + +-- Dump of table consumerrole +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerRole`; + +CREATE TABLE `P_0_ConsumerRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表'; + + + +-- Dump of table consumertoken +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerToken`; + +CREATE TABLE `P_0_ConsumerToken` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId', + `Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token', + `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Token_DeletedAt` (`Token`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表'; + +-- Dump of table favorite +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Favorite`; + +CREATE TABLE `P_0_Favorite` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`), + KEY `AppId` (`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表'; + +-- Dump of table permission +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Permission`; + +CREATE TABLE `P_0_Permission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型', + `TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表'; + + + +-- Dump of table role +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Role`; + +CREATE TABLE `P_0_Role` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; + + + +-- Dump of table rolepermission +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_RolePermission`; + +CREATE TABLE `P_0_RolePermission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PermissionId` (`PermissionId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表'; + + + +-- Dump of table serverconfig +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ServerConfig`; + +CREATE TABLE `P_0_ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_DeletedAt` (`Key`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + + + +-- Dump of table userrole +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_UserRole`; + +CREATE TABLE `P_0_UserRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表'; + +-- Dump of table Users +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Users`; + +CREATE TABLE `P_0_Users` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户', + `Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码', + `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称', + `Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址', + `Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Username` (`Username`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + + +-- Dump of table Authorities +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Authorities`; + +CREATE TABLE `P_0_Authorities` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL, + `Authority` varchar(50) NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) +-- Dump of table SPRING_SESSION +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_SPRING_SESSION`; + +CREATE TABLE `P_0_SPRING_SESSION` ( + `PRIMARY_ID` char(36) NOT NULL, + `SESSION_ID` char(36) NOT NULL, + `CREATION_TIME` bigint NOT NULL, + `LAST_ACCESS_TIME` bigint NOT NULL, + `MAX_INACTIVE_INTERVAL` int NOT NULL, + `EXPIRY_TIME` bigint NOT NULL, + `PRINCIPAL_NAME` varchar(100) DEFAULT NULL, + PRIMARY KEY (`PRIMARY_ID`), + UNIQUE KEY `SPRING_SESSION_IX1` (`SESSION_ID`), + KEY `SPRING_SESSION_IX2` (`EXPIRY_TIME`), + KEY `SPRING_SESSION_IX3` (`PRINCIPAL_NAME`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + +-- Dump of table SPRING_SESSION_ATTRIBUTES +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_SPRING_SESSION_ATTRIBUTES`; + +CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( + `SESSION_PRIMARY_ID` char(36) NOT NULL, + `ATTRIBUTE_NAME` varchar(200) NOT NULL, + `ATTRIBUTE_BYTES` blob NOT NULL, + PRIMARY KEY (`SESSION_PRIMARY_ID`,`ATTRIBUTE_NAME`), + CONSTRAINT `SPRING_SESSION_ATTRIBUTES_FK` FOREIGN KEY (`SESSION_PRIMARY_ID`) REFERENCES `P_0_SPRING_SESSION` (`PRIMARY_ID`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + +-- Dump of table AuditLog +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_AuditLog`; + +CREATE TABLE `P_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + +-- Dump of table AuditLogDataInfluence +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_AuditLogDataInfluence`; + +CREATE TABLE `P_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + +-- Config +-- ------------------------------------------------------------ +INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) +VALUES + ('apollo.portal.envs', 'dev', '可支持的环境列表'), + ('organizations', '[{"orgId":"TEST1","orgName":"样例部门1"},{"orgId":"TEST2","orgName":"样例部门2"}]', '部门列表'), + ('superAdmin', 'apollo', 'Portal超级管理员'), + ('api.readTimeout', '10000', 'http接口read timeout'), + ('consumer.token.salt', 'someSalt', 'consumer token salt'), + ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'), + ('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔'), + ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); + + +INSERT INTO `P_0_Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) +VALUES + ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); + +INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); + +-- @@${auto-generated-declaration}@@ + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/scripts/sql-src/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql-src/delta/v220-v230/apolloconfigdb-v220-v230.sql new file mode 100644 index 00000000000..359a6709cb6 --- /dev/null +++ b/scripts/sql-src/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -0,0 +1,23 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 + +-- @@${auto-generated-declaration}@@ +-- @@${h2-function}@@ +-- @@${use-database}@@ + + +-- @@${auto-generated-declaration}@@ diff --git a/scripts/sql-src/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql-src/delta/v220-v230/apolloportaldb-v220-v230.sql new file mode 100644 index 00000000000..442f1ddcb2f --- /dev/null +++ b/scripts/sql-src/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -0,0 +1,23 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 + +-- @@${auto-generated-declaration}@@ +-- @@${h2-function}@@ +-- @@${use-database}@@ + + +-- @@${auto-generated-declaration}@@ diff --git a/scripts/sql-template/auto-generated-declaration.sql b/scripts/sql-template/auto-generated-declaration.sql new file mode 100644 index 00000000000..b64f9b8fba5 --- /dev/null +++ b/scripts/sql-template/auto-generated-declaration.sql @@ -0,0 +1,23 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- @@template-start@@ +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== +-- @@template-end@@ diff --git a/scripts/sql-template/h2-function.sql b/scripts/sql-template/h2-function.sql new file mode 100644 index 00000000000..14595b7e8de --- /dev/null +++ b/scripts/sql-template/h2-function.sql @@ -0,0 +1,22 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- @@template-start@@ + +-- H2 Function +-- ------------------------------------------------------------ +CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; + +-- @@template-end@@ diff --git a/scripts/sql-template/setup-database.sql b/scripts/sql-template/setup-database.sql new file mode 100644 index 00000000000..4dd458cb2ad --- /dev/null +++ b/scripts/sql-template/setup-database.sql @@ -0,0 +1,22 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- @@template-start@@ +-- Create Database +-- ------------------------------------------------------------ +CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; + +Use ApolloAssemblyDB; +-- @@template-end@@ diff --git a/scripts/sql-template/use-database.sql b/scripts/sql-template/use-database.sql new file mode 100644 index 00000000000..7ec64e760df --- /dev/null +++ b/scripts/sql-template/use-database.sql @@ -0,0 +1,19 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- @@template-start@@ +-- Use Database +Use ApolloAssemblyDB; +-- @@template-end@@ diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index dbcca407a86..281f99e4a27 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -21,6 +21,13 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + -- Create Database -- ------------------------------------------------------------ CREATE DATABASE IF NOT EXISTS ApolloConfigDB DEFAULT CHARACTER SET = utf8mb4; @@ -492,6 +499,13 @@ VALUES ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/scripts/sql/apolloportaldb.sql b/scripts/sql/apolloportaldb.sql index 41eed5785a6..20ab7c885fc 100644 --- a/scripts/sql/apolloportaldb.sql +++ b/scripts/sql/apolloportaldb.sql @@ -21,6 +21,13 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + -- Create Database -- ------------------------------------------------------------ CREATE DATABASE IF NOT EXISTS ApolloPortalDB DEFAULT CHARACTER SET = utf8mb4; @@ -436,6 +443,13 @@ VALUES INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/scripts/sql/assembly/h2/apolloconfigdb.sql b/scripts/sql/assembly/h2/apolloconfigdb.sql index 67cd159df83..fb2c5ed2774 100644 --- a/scripts/sql/assembly/h2/apolloconfigdb.sql +++ b/scripts/sql/assembly/h2/apolloconfigdb.sql @@ -21,12 +21,18 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; --- Create Database +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + +-- H2 Function -- ------------------------------------------------------------ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; - -- Dump of table app -- ------------------------------------------------------------ @@ -492,6 +498,13 @@ VALUES ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/scripts/sql/assembly/h2/apolloportaldb.sql b/scripts/sql/assembly/h2/apolloportaldb.sql index f34a93bc0f3..f62fc0dc601 100644 --- a/scripts/sql/assembly/h2/apolloportaldb.sql +++ b/scripts/sql/assembly/h2/apolloportaldb.sql @@ -21,12 +21,18 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; --- Create Database +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + +-- H2 Function -- ------------------------------------------------------------ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; - -- Dump of table app -- ------------------------------------------------------------ @@ -436,6 +442,13 @@ VALUES INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql index 3bfadf81f64..123061005a6 100644 --- a/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -15,4 +15,22 @@ -- -- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== +-- H2 Function +-- ------------------------------------------------------------ +CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; + + + +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== diff --git a/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql index b640af550bf..7f0744cb914 100644 --- a/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -15,4 +15,22 @@ -- -- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== +-- H2 Function +-- ------------------------------------------------------------ +CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; + + + +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== diff --git a/scripts/sql/assembly/mysql/apolloconfigdb.sql b/scripts/sql/assembly/mysql/apolloconfigdb.sql index 524b68369c0..79adf6498f3 100644 --- a/scripts/sql/assembly/mysql/apolloconfigdb.sql +++ b/scripts/sql/assembly/mysql/apolloconfigdb.sql @@ -21,6 +21,13 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + -- Create Database -- ------------------------------------------------------------ CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; @@ -492,6 +499,13 @@ VALUES ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/scripts/sql/assembly/mysql/apolloportaldb.sql b/scripts/sql/assembly/mysql/apolloportaldb.sql index 0aed78abda2..e910860277e 100644 --- a/scripts/sql/assembly/mysql/apolloportaldb.sql +++ b/scripts/sql/assembly/mysql/apolloportaldb.sql @@ -21,6 +21,13 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + -- Create Database -- ------------------------------------------------------------ CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; @@ -436,6 +443,13 @@ VALUES INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql index 1c073f32003..6389bcf4068 100644 --- a/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -15,4 +15,20 @@ -- -- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + +-- Use Database Use ApolloAssemblyDB; + + +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql index bfa66de9cdf..35fe80f4169 100644 --- a/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -15,4 +15,20 @@ -- -- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + +-- Use Database Use ApolloAssemblyDB; + + +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== diff --git a/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql index 66963bf51ff..f0d53e92918 100644 --- a/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -15,4 +15,20 @@ -- -- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + +-- Use Database Use ApolloConfigDB; + + +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== diff --git a/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql index 3e8239ad720..dc48f65b622 100644 --- a/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -15,4 +15,20 @@ -- -- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + +-- Use Database Use ApolloPortalDB; + + +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== From d773cd7024d8b23966cf7095dca4e8c13426a46a Mon Sep 17 00:00:00 2001 From: vdisk Date: Tue, 2 Jan 2024 21:55:11 +0800 Subject: [PATCH 24/59] fix assembly sql temp v0.3 --- apollo-build-maven-extensions/pom.xml | 6 + .../sql/ApolloAssemblyH2ConverterUtil.java | 44 ++---- .../sql/ApolloAssemblyMysqlConverterUtil.java | 51 +++--- .../sql/ApolloMainMysqlConverterUtil.java | 37 ++--- .../extensions/sql/ApolloSqlConverter.java | 115 ++++++++++---- .../sql/ApolloSqlConverterUtil.java | 145 ++++++++++++------ .../maven/extensions/sql/ConvertResult.java | 37 ----- .../maven/extensions/sql/SqlTemplate.java | 33 ++-- .../extensions/sql/SqlTemplateContext.java | 72 +++++++++ .../maven/extensions/sql/SqlTemplateGist.java | 114 ++++++++++++++ .../sql/ApolloSqlConverterTest.java | 25 +-- .../autoGeneratedDeclaration.sql} | 4 +- .../h2Function.sql} | 4 +- .../setupDatabase.sql} | 4 +- .../useDatabase.sql} | 4 +- scripts/sql-src/apolloconfigdb.sql | 8 +- scripts/sql-src/apolloportaldb.sql | 8 +- .../v220-v230/apolloconfigdb-v220-v230.sql | 8 +- .../v220-v230/apolloportaldb-v220-v230.sql | 8 +- scripts/sql/apolloconfigdb.sql | 5 +- scripts/sql/apolloportaldb.sql | 5 +- scripts/sql/assembly/h2/apolloconfigdb.sql | 42 ++--- scripts/sql/assembly/h2/apolloportaldb.sql | 40 ++--- .../v220-v230/apolloconfigdb-v220-v230.sql | 4 + .../v220-v230/apolloportaldb-v220-v230.sql | 4 + scripts/sql/assembly/mysql/apolloconfigdb.sql | 10 +- scripts/sql/assembly/mysql/apolloportaldb.sql | 10 +- .../v220-v230/apolloconfigdb-v220-v230.sql | 7 +- .../v220-v230/apolloportaldb-v220-v230.sql | 7 +- .../v220-v230/apolloconfigdb-v220-v230.sql | 5 +- .../v220-v230/apolloportaldb-v220-v230.sql | 5 +- 31 files changed, 548 insertions(+), 323 deletions(-) delete mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ConvertResult.java create mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateContext.java create mode 100644 apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateGist.java rename scripts/{sql-template/auto-generated-declaration.sql => sql-gist/autoGeneratedDeclaration.sql} (96%) rename scripts/{sql-template/h2-function.sql => sql-gist/h2Function.sql} (94%) rename scripts/{sql-template/setup-database.sql => sql-gist/setupDatabase.sql} (94%) rename scripts/{sql-template/use-database.sql => sql-gist/useDatabase.sql} (93%) diff --git a/apollo-build-maven-extensions/pom.xml b/apollo-build-maven-extensions/pom.xml index ed46ab6dc66..3a5d5dd90c0 100644 --- a/apollo-build-maven-extensions/pom.xml +++ b/apollo-build-maven-extensions/pom.xml @@ -27,6 +27,12 @@ apollo-build-maven-extensions Apollo Build Maven Extensions + + + org.freemarker + freemarker + + diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyH2ConverterUtil.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyH2ConverterUtil.java index 29251bbcffa..9467d842bb0 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyH2ConverterUtil.java +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyH2ConverterUtil.java @@ -19,31 +19,31 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; +import java.io.StringReader; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; -import java.util.Map; -import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ApolloAssemblyH2ConverterUtil { - public static void convertAssemblyH2(String srcSql, String targetSql, - Map templates) { + public static void convertAssemblyH2(SqlTemplate sqlTemplate, String targetSql, + SqlTemplateContext context) { ApolloSqlConverterUtil.ensureDirectories(targetSql); - try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(srcSql), - StandardCharsets.UTF_8); + String rawText = ApolloSqlConverterUtil.process(sqlTemplate, context); + + try (BufferedReader bufferedReader = new BufferedReader(new StringReader(rawText)); BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { for (String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine()) { - String convertedLine = convertAssemblyH2Line(line, templates); + String convertedLine = convertAssemblyH2Line(line); bufferedWriter.write(convertedLine); bufferedWriter.write('\n'); } @@ -52,18 +52,8 @@ public static void convertAssemblyH2(String srcSql, String targetSql, } } - private static String convertAssemblyH2Line(String line, Map templates) { + private static String convertAssemblyH2Line(String line) { String convertedLine = line; - ConvertResult result = ApolloSqlConverterUtil.convertTemplate(convertedLine, - "auto-generated-declaration", templates); - convertedLine = result.convertedLine(); - if (result.matches()) { - return convertedLine; - } - convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "h2-function", templates).convertedLine(); - convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "setup-database", SqlTemplate.empty()).convertedLine(); - convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "use-database", SqlTemplate.empty()).convertedLine(); - // database config if (convertedLine.contains("DROP TABLE")) { return ""; @@ -112,22 +102,6 @@ private static String convertAssemblyH2Line(String line, Map templates) { + public static void convertAssemblyMysql(SqlTemplate sqlTemplate, String targetSql, + SqlTemplateContext context) { - ApolloSqlConverterUtil.ensureDirectories(targetSql); + ApolloSqlConverterUtil.ensureDirectories(targetSql); - try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(srcSql), - StandardCharsets.UTF_8); - BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), - StandardCharsets.UTF_8, StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING)) { - for (String line = bufferedReader.readLine(); line != null; - line = bufferedReader.readLine()) { - String convertedLine = convertAssemblyMysqlLine(line, templates); - bufferedWriter.write(convertedLine); - bufferedWriter.write('\n'); - } - } catch (IOException e) { - throw new UncheckedIOException(e); + String rawText = ApolloSqlConverterUtil.process(sqlTemplate, context); + + try (BufferedReader bufferedReader = new BufferedReader(new StringReader(rawText)); + BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), + StandardCharsets.UTF_8, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING)) { + for (String line = bufferedReader.readLine(); line != null; + line = bufferedReader.readLine()) { + String convertedLine = convertAssemblyMysqlLine(line); + bufferedWriter.write(convertedLine); + bufferedWriter.write('\n'); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } } - } - private static String convertAssemblyMysqlLine(String line, Map templates) { - String convertedLine = line; - ConvertResult result = ApolloSqlConverterUtil.convertTemplate(convertedLine, - "auto-generated-declaration", templates); - convertedLine = result.convertedLine(); - if (result.matches()) { - return convertedLine; + private static String convertAssemblyMysqlLine(String line) { + String convertedLine = line; + return convertedLine; } - convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "h2-function", SqlTemplate.empty()).convertedLine(); - convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "setup-database", templates).convertedLine(); - convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "use-database", templates).convertedLine(); - return convertedLine; - } } diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloMainMysqlConverterUtil.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloMainMysqlConverterUtil.java index 4e7d3571a53..1e1d5844a99 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloMainMysqlConverterUtil.java +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloMainMysqlConverterUtil.java @@ -19,18 +19,18 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; +import java.io.StringReader; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; -import java.util.Map; -import java.util.Objects; public class ApolloMainMysqlConverterUtil { - public static void convertMainMysql(String srcSql, String targetSql, - Map templates) { + public static void convertMainMysql(SqlTemplate sqlTemplate, String targetSql, + SqlTemplateContext context) { String databaseName; + String srcSql = sqlTemplate.getSrcPath(); if (srcSql.contains("apolloconfigdb")) { databaseName = "ApolloConfigDB"; } else if (srcSql.contains("apolloportaldb")) { @@ -41,14 +41,15 @@ public static void convertMainMysql(String srcSql, String targetSql, ApolloSqlConverterUtil.ensureDirectories(targetSql); - try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(srcSql), - StandardCharsets.UTF_8); + String rawText = ApolloSqlConverterUtil.process(sqlTemplate, context); + + try (BufferedReader bufferedReader = new BufferedReader(new StringReader(rawText)); BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { for (String line = bufferedReader.readLine(); line != null; line = bufferedReader.readLine()) { - String convertedLine = convertMainMysqlLine(line, databaseName, templates); + String convertedLine = convertMainMysqlLine(line, databaseName); bufferedWriter.write(convertedLine); bufferedWriter.write('\n'); } @@ -57,24 +58,16 @@ public static void convertMainMysql(String srcSql, String targetSql, } } - private static String convertMainMysqlLine(String line, String databaseName, - Map templates) { + private static String convertMainMysqlLine(String line, String databaseName) { String convertedLine = line; - ConvertResult result = ApolloSqlConverterUtil.convertTemplate(convertedLine, - "auto-generated-declaration", templates); - convertedLine = result.convertedLine(); - if (result.matches()) { - return convertedLine; - } - convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "h2-function", - SqlTemplate.empty()).convertedLine(); - convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "setup-database", - templates).convertedLine(); - convertedLine = ApolloSqlConverterUtil.convertTemplate(convertedLine, "use-database", templates) - .convertedLine(); - convertedLine = convertedLine.replace("P_0_", "").replace("C_0_", "") + convertedLine = convertedLine.replace("P_0_", ""); + + convertedLine = convertedLine.replace("C_0_", "") .replace("ApolloAssemblyDB", databaseName); + + convertedLine = convertedLine.replace("ApolloAssemblyDB", databaseName); + return convertedLine; } } diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java index b68eb65b161..3a0015db70d 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java @@ -16,68 +16,127 @@ */ package com.ctrip.framework.apollo.maven.extensions.sql; +import freemarker.template.Configuration; +import freemarker.template.Template; +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.CodeSource; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; public class ApolloSqlConverter { public static void main(String[] args) { - String moduleDir = args[0]; - String unixModuleDir = moduleDir.replace("\\", "/"); - String repositoryDir = ApolloSqlConverterUtil.replacePath(unixModuleDir, - "/apollo-build-maven-extensions", ""); + String repositoryDir = ApolloSqlConverterUtil.getRepositoryDir(); + String targetParentDir = repositoryDir + "/scripts"; + + convert(targetParentDir); + } - Map templates = ApolloSqlConverterUtil.getTemplates(repositoryDir); + public static List convert(String targetParentDir) { + String repositoryDir = ApolloSqlConverterUtil.getRepositoryDir(); String srcDir = repositoryDir + "/scripts/sql-src"; - String targetParentDir = repositoryDir + "/scripts"; - convert(srcDir, targetParentDir, templates); - } + Configuration configuration = createConfiguration(repositoryDir); + + SqlTemplateGist gists = ApolloSqlConverterUtil.getGists(repositoryDir); - public static List convert(String srcDir, String targetParentDir, - Map templates) { // '/scripts/sql-src/apolloconfigdb.sql' // '/scripts/sql-src/apolloportaldb.sql' // '/scripts/sql-src/delta/**/*.sql' List srcSqlList = ApolloSqlConverterUtil.getSqlList(srcDir); + List templateList = ApolloSqlConverterUtil.toTemplates(srcSqlList, srcDir, + configuration); // '/scripts/sql-src' -> '/scripts/sql' - convertMainMysqlList(srcSqlList, srcDir, targetParentDir, templates); + convertMainMysqlList(templateList, srcDir, targetParentDir, gists); // '/scripts/sql-src' -> '/scripts/sql/assembly/mysql' - convertAssemblyMysqlList(srcSqlList, srcDir, targetParentDir, templates); + convertAssemblyMysqlList(templateList, srcDir, targetParentDir, gists); // '/scripts/sql-src' -> '/scripts/sql/assembly/h2' - convertAssemblyH2List(srcSqlList, srcDir, targetParentDir, templates); + convertAssemblyH2List(templateList, srcDir, targetParentDir, gists); return srcSqlList; } - private static void convertMainMysqlList(List srcSqlList, - String srcDir, String targetParentDir, Map templates) { + private static Configuration createConfiguration(String repositoryDir) { + Configuration configuration = new Configuration(Configuration.VERSION_2_3_32); + try { + configuration.setDirectoryForTemplateLoading(new File(repositoryDir + "/scripts/sql-src")); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + configuration.setDefaultEncoding(StandardCharsets.UTF_8.name()); + return configuration; + } + + private static void convertMainMysqlList(List templateList, + String srcDir, String targetParentDir, SqlTemplateGist gists) { String targetDir = targetParentDir + "/sql"; - for (String srcSql : srcSqlList) { - String targetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, targetDir); - ApolloMainMysqlConverterUtil.convertMainMysql(srcSql, targetSql, templates); + + SqlTemplateGist mainMysqlGists = SqlTemplateGist.builder() + .autoGeneratedDeclaration(gists.getAutoGeneratedDeclaration()) + .h2Function("") + .setupDatabase(gists.getSetupDatabase()) + .useDatabase(gists.getUseDatabase()) + .build(); + SqlTemplateContext context = SqlTemplateContext.builder() + .gists(mainMysqlGists) + .build(); + + for (SqlTemplate sqlTemplate : templateList) { + String targetSql = ApolloSqlConverterUtil.replacePath(sqlTemplate.getSrcPath(), srcDir, targetDir); + ApolloMainMysqlConverterUtil.convertMainMysql(sqlTemplate, targetSql, context); } } - private static void convertAssemblyMysqlList(List srcSqlList, String srcDir, - String targetParentDir, Map templates) { + private static void convertAssemblyMysqlList(List templateList, String srcDir, + String targetParentDir, SqlTemplateGist gists) { String targetDir = targetParentDir + "/sql/assembly/mysql"; - for (String srcSql : srcSqlList) { - String targetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, targetDir); - ApolloAssemblyMysqlConverterUtil.convertAssemblyMysql(srcSql, targetSql, templates); + + SqlTemplateGist mainMysqlGists = SqlTemplateGist.builder() + .autoGeneratedDeclaration(gists.getAutoGeneratedDeclaration()) + .h2Function("") + .setupDatabase("") + .useDatabase("") + .build(); + SqlTemplateContext context = SqlTemplateContext.builder() + .gists(mainMysqlGists) + .build(); + for (SqlTemplate sqlTemplate : templateList) { + String targetSql = ApolloSqlConverterUtil.replacePath(sqlTemplate.getSrcPath(), srcDir, targetDir); + ApolloAssemblyMysqlConverterUtil.convertAssemblyMysql(sqlTemplate, targetSql, context); } } - private static void convertAssemblyH2List(List srcSqlList, - String srcDir, String targetParentDir, Map templates) { + private static void convertAssemblyH2List(List templateList, String srcDir, + String targetParentDir, SqlTemplateGist gists) { String targetDir = targetParentDir + "/sql/assembly/h2"; - for (String srcSql : srcSqlList) { - String targetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, targetDir); - ApolloAssemblyH2ConverterUtil.convertAssemblyH2(srcSql, targetSql, templates); + + SqlTemplateGist mainMysqlGists = SqlTemplateGist.builder() + .autoGeneratedDeclaration(gists.getAutoGeneratedDeclaration()) + .h2Function(gists.getH2Function()) + .setupDatabase("") + .useDatabase("") + .build(); + SqlTemplateContext context = SqlTemplateContext.builder() + .gists(mainMysqlGists) + .build(); + for (SqlTemplate sqlTemplate : templateList) { + String targetSql = ApolloSqlConverterUtil.replacePath(sqlTemplate.getSrcPath(), srcDir, targetDir); + ApolloAssemblyH2ConverterUtil.convertAssemblyH2(sqlTemplate, targetSql, context); } } } diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterUtil.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterUtil.java index 161143ddf2a..537ea62fac8 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterUtil.java +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterUtil.java @@ -16,14 +16,22 @@ */ package com.ctrip.framework.apollo.maven.extensions.sql; +import freemarker.template.Configuration; +import freemarker.template.Template; import java.io.BufferedReader; import java.io.IOException; +import java.io.StringWriter; import java.io.UncheckedIOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.security.CodeSource; +import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; @@ -34,6 +42,28 @@ public class ApolloSqlConverterUtil { + + public static String getRepositoryDir() { + ProtectionDomain protectionDomain = ApolloSqlConverter.class.getProtectionDomain(); + CodeSource codeSource = protectionDomain.getCodeSource(); + URL location = codeSource.getLocation(); + URI uri; + try { + uri = location.toURI(); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e.getLocalizedMessage(),e); + } + Path path = Paths.get(uri); + String unixClassPath = path.toString().replace("\\", "/"); + + if (!unixClassPath.endsWith("/apollo-build-maven-extensions/target/classes")) { + throw new IllegalStateException("illegal class path: " + unixClassPath); + } + + return ApolloSqlConverterUtil.replacePath(unixClassPath, + "/apollo-build-maven-extensions/target/classes", ""); + } + public static void ensureDirectories(String targetFilePath) { Path path = Paths.get(targetFilePath); Path dirPath = path.getParent(); @@ -44,63 +74,67 @@ public static void ensureDirectories(String targetFilePath) { } } - public static String replacePath(String origin, String src, String target) { - if (!origin.contains(src)) { + public static String process(SqlTemplate sqlTemplate, SqlTemplateContext context) { + Template freemarkerTemplate = sqlTemplate.getTemplate(); + StringWriter writer = new StringWriter(); + try { + freemarkerTemplate.process(context, writer); + } catch (Exception e) { + throw new RuntimeException(e); + } + return writer.toString(); + } + + public static String replacePrefix(String origin, String prefix, String target) { + if (!origin.startsWith(prefix)) { throw new IllegalArgumentException("illegal file path: " + origin); } - return origin.replace(src, target); + return origin.replace(prefix, target); } - public static Map getTemplates(String repositoryDir) { - String templateDir = repositoryDir + "/scripts/sql-template"; - Map templates = new LinkedHashMap<>(); - List templateFiles = list(Paths.get(templateDir)); - for (Path templatePath : templateFiles) { - String fileName = templatePath.getFileName().toString(); - String templateName = replacePath(fileName, ".sql", ""); - - StringJoiner joiner = new StringJoiner("\n"); - boolean accept = false; - try (BufferedReader bufferedReader = Files.newBufferedReader(templatePath, - StandardCharsets.UTF_8)) { - for (String line = bufferedReader.readLine(); line != null; - line = bufferedReader.readLine()) { - if (line.contains("@@template-start@@")) { - accept = true; - continue; - } - if (line.contains("@@template-end@@")) { - break; - } - if (accept) { - joiner.add(line); - } - } - } catch (IOException e) { - throw new UncheckedIOException("failed to open templatePath " + e.getLocalizedMessage(), e); - } - String value = joiner.toString(); - SqlTemplate template = new SqlTemplate(templateName, "@@${" + templateName + "}@@", value); - templates.put(templateName, template); + public static String replacePath(String origin, String src, String target) { + if (!origin.contains(src)) { + throw new IllegalArgumentException("illegal file path: " + origin); } - return templates; + return origin.replace(src, target); } - public static ConvertResult convertTemplate(String line, String name, - Map templates) { - return convertTemplate(line, name, templates.get(name)); + public static SqlTemplateGist getGists(String repositoryDir) { + String gistDir = repositoryDir + "/scripts/sql-gist"; + String autoGeneratedDeclaration = getGist(gistDir + "/autoGeneratedDeclaration.sql"); + String h2Function = getGist(gistDir + "/h2Function.sql"); + String setupDatabase = getGist(gistDir + "/setupDatabase.sql"); + String useDatabase = getGist(gistDir + "/useDatabase.sql"); + return SqlTemplateGist.builder() + .autoGeneratedDeclaration(autoGeneratedDeclaration) + .h2Function(h2Function) + .setupDatabase(setupDatabase) + .useDatabase(useDatabase) + .build(); } - public static ConvertResult convertTemplate(String line, String name, - SqlTemplate template) { - if (template == null) { - throw new IllegalArgumentException("template not found: " + name); - } - String key = "@@${" + name + "}@@"; - if (line.contains(key)) { - return new ConvertResult(true, template.getValue()); + private static String getGist(String gistPath) { + StringJoiner joiner = new StringJoiner("\n", "\n", ""); + boolean accept = false; + try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(gistPath), + StandardCharsets.UTF_8)) { + for (String line = bufferedReader.readLine(); line != null; + line = bufferedReader.readLine()) { + if (line.contains("@@gist-start@@")) { + accept = true; + continue; + } + if (line.contains("@@gist-end@@")) { + break; + } + if (accept) { + joiner.add(line); + } + } + } catch (IOException e) { + throw new UncheckedIOException("failed to open gistPath " + e.getLocalizedMessage(), e); } - return new ConvertResult(false, line); + return joiner.toString(); } public static List getSqlList(String dir, Set ignoreDirs) { @@ -157,4 +191,21 @@ private static List getDeltaSqlList(String dir, Set ignoreDirs) return deltaSqlList; } + + + public static List toTemplates(List srcSqlList, String srcDir, + Configuration configuration) { + List templateList = new ArrayList<>(srcSqlList.size()); + for (String srcSql : srcSqlList) { + String templateName = ApolloSqlConverterUtil.replacePrefix(srcSql, srcDir + "/", ""); + Template template; + try { + template = configuration.getTemplate(templateName); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + templateList.add(new SqlTemplate(srcSql, template)); + } + return templateList; + } } diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ConvertResult.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ConvertResult.java deleted file mode 100644 index 2f3eec52dda..00000000000 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ConvertResult.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2023 Apollo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.ctrip.framework.apollo.maven.extensions.sql; - -public class ConvertResult { - - private final boolean matches; - - private final String convertedLine; - - public ConvertResult(boolean matches, String convertedLine) { - this.matches = matches; - this.convertedLine = convertedLine; - } - - public boolean matches() { - return this.matches; - } - - public String convertedLine() { - return this.convertedLine; - } -} diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplate.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplate.java index ddabc4dab53..4222a46374b 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplate.java +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplate.java @@ -16,35 +16,24 @@ */ package com.ctrip.framework.apollo.maven.extensions.sql; -public class SqlTemplate { - - private static final SqlTemplate EMPTY = new SqlTemplate("empty", "@@${empty}@@", ""); - - private final String name; - - private final String key; +import freemarker.template.Template; - private final String value; +public class SqlTemplate { - public SqlTemplate(String name, String key, String value) { - this.name = name; - this.key = key; - this.value = value; - } + private final String srcPath; - public static SqlTemplate empty() { - return EMPTY; - } + private final Template template; - public String getName() { - return this.name; + public SqlTemplate(String srcPath, Template template) { + this.srcPath = srcPath; + this.template = template; } - public String getKey() { - return this.key; + public String getSrcPath() { + return this.srcPath; } - public String getValue() { - return this.value; + public Template getTemplate() { + return this.template; } } diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateContext.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateContext.java new file mode 100644 index 00000000000..8131f72ab78 --- /dev/null +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateContext.java @@ -0,0 +1,72 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.maven.extensions.sql; + +import java.util.Collections; +import java.util.Map; +import java.util.StringJoiner; + +public class SqlTemplateContext { + + /** + * sql gist + */ + private final SqlTemplateGist gists; + + SqlTemplateContext(Builder builder) { + this.gists = builder.gists; + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + Builder builder = new Builder(); + builder.gists = this.gists; + return builder; + } + + public SqlTemplateGist getGists() { + return this.gists; + } + + @Override + public String toString() { + return new StringJoiner(", ", SqlTemplateContext.class.getSimpleName() + "[", "]") + // fields + .add("gists=" + this.gists) + .toString(); + } + + public static final class Builder { + + private SqlTemplateGist gists; + + Builder() { + } + + public Builder gists(SqlTemplateGist gists) { + this.gists = gists; + return this; + } + + public SqlTemplateContext build() { + return new SqlTemplateContext(this); + } + } +} diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateGist.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateGist.java new file mode 100644 index 00000000000..ff52bc62bc2 --- /dev/null +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateGist.java @@ -0,0 +1,114 @@ +/* + * Copyright 2023 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.maven.extensions.sql; + +import java.util.Collections; +import java.util.Map; +import java.util.StringJoiner; + +public class SqlTemplateGist { + + private final String autoGeneratedDeclaration; + + private final String h2Function; + + private final String setupDatabase; + + private final String useDatabase; + + SqlTemplateGist(Builder builder) { + this.autoGeneratedDeclaration = builder.autoGeneratedDeclaration; + this.h2Function = builder.h2Function; + this.setupDatabase = builder.setupDatabase; + this.useDatabase = builder.useDatabase; + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + Builder builder = new Builder(); + builder.autoGeneratedDeclaration = this.autoGeneratedDeclaration; + builder.h2Function = this.h2Function; + builder.setupDatabase = this.setupDatabase; + builder.useDatabase = this.useDatabase; + return builder; + } + + public String getAutoGeneratedDeclaration() { + return this.autoGeneratedDeclaration; + } + + public String getH2Function() { + return this.h2Function; + } + + public String getSetupDatabase() { + return this.setupDatabase; + } + + public String getUseDatabase() { + return this.useDatabase; + } + + @Override + public String toString() { + return new StringJoiner(", ", SqlTemplateGist.class.getSimpleName() + "[", "]") + // fields + .add("autoGeneratedDeclaration='" + this.autoGeneratedDeclaration + "'") + .add("h2Function='" + this.h2Function + "'") + .add("setupDatabase='" + this.setupDatabase + "'") + .add("useDatabase='" + this.useDatabase + "'") + .toString(); + } + + public static final class Builder { + + private String autoGeneratedDeclaration; + private String h2Function; + private String setupDatabase; + private String useDatabase; + + Builder() { + } + + public Builder autoGeneratedDeclaration(String autoGeneratedDeclaration) { + this.autoGeneratedDeclaration = autoGeneratedDeclaration; + return this; + } + + public Builder h2Function(String h2Function) { + this.h2Function = h2Function; + return this; + } + + public Builder setupDatabase(String setupDatabase) { + this.setupDatabase = setupDatabase; + return this; + } + + public Builder useDatabase(String useDatabase) { + this.useDatabase = useDatabase; + return this; + } + + public SqlTemplateGist build() { + return new SqlTemplateGist(this); + } + } +} diff --git a/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java b/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java index d06b5fc1f97..91ecdb2e81f 100644 --- a/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java +++ b/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java @@ -16,8 +16,10 @@ */ package com.ctrip.framework.apollo.maven.extensions.sql; +import freemarker.template.TemplateException; import java.io.BufferedReader; import java.io.IOException; +import java.io.StringWriter; import java.io.UncheckedIOException; import java.net.URI; import java.net.URISyntaxException; @@ -40,37 +42,20 @@ class ApolloSqlConverterTest { @Test - void checkSql() throws URISyntaxException { - String repositoryDir = this.getRepositoryDir(); - - Map templates = ApolloSqlConverterUtil.getTemplates(repositoryDir); + void checkSql() { + String repositoryDir = ApolloSqlConverterUtil.getRepositoryDir(); String srcDir = repositoryDir + "/scripts/sql-src"; String checkerParentDir = repositoryDir + "/apollo-build-maven-extensions/target/scripts"; String repositoryParentDir = repositoryDir + "/scripts"; // generate checker sql files - List srcSqlList = ApolloSqlConverter.convert(srcDir, checkerParentDir, templates); + List srcSqlList = ApolloSqlConverter.convert(checkerParentDir); // compare checker sql files with repository sql files this.checkSqlList(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); } - private String getRepositoryDir() throws URISyntaxException { - ProtectionDomain protectionDomain = ApolloSqlConverterTest.class.getProtectionDomain(); - CodeSource codeSource = protectionDomain.getCodeSource(); - URL location = codeSource.getLocation(); - URI uri = location.toURI(); - Path path = Paths.get(uri); - String unixClassPath = path.toString().replace("\\", "/"); - - Assertions.assertTrue( - unixClassPath.endsWith("/apollo-build-maven-extensions/target/test-classes")); - - return ApolloSqlConverterUtil.replacePath(unixClassPath, - "/apollo-build-maven-extensions/target/test-classes", ""); - } - private void checkSqlList(List srcSqlList, String srcDir, String checkerParentDir, String repositoryParentDir) { diff --git a/scripts/sql-template/auto-generated-declaration.sql b/scripts/sql-gist/autoGeneratedDeclaration.sql similarity index 96% rename from scripts/sql-template/auto-generated-declaration.sql rename to scripts/sql-gist/autoGeneratedDeclaration.sql index b64f9b8fba5..bf8d7981dd3 100644 --- a/scripts/sql-template/auto-generated-declaration.sql +++ b/scripts/sql-gist/autoGeneratedDeclaration.sql @@ -13,11 +13,11 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- --- @@template-start@@ +-- @@gist-start@@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== --- @@template-end@@ +-- @@gist-end@@ diff --git a/scripts/sql-template/h2-function.sql b/scripts/sql-gist/h2Function.sql similarity index 94% rename from scripts/sql-template/h2-function.sql rename to scripts/sql-gist/h2Function.sql index 14595b7e8de..c057539155a 100644 --- a/scripts/sql-template/h2-function.sql +++ b/scripts/sql-gist/h2Function.sql @@ -13,10 +13,10 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- --- @@template-start@@ +-- @@gist-start@@ -- H2 Function -- ------------------------------------------------------------ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; --- @@template-end@@ +-- @@gist-end@@ diff --git a/scripts/sql-template/setup-database.sql b/scripts/sql-gist/setupDatabase.sql similarity index 94% rename from scripts/sql-template/setup-database.sql rename to scripts/sql-gist/setupDatabase.sql index 4dd458cb2ad..2c3d4f389a2 100644 --- a/scripts/sql-template/setup-database.sql +++ b/scripts/sql-gist/setupDatabase.sql @@ -13,10 +13,10 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- --- @@template-start@@ +-- @@gist-start@@ -- Create Database -- ------------------------------------------------------------ CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; Use ApolloAssemblyDB; --- @@template-end@@ +-- @@gist-end@@ diff --git a/scripts/sql-template/use-database.sql b/scripts/sql-gist/useDatabase.sql similarity index 93% rename from scripts/sql-template/use-database.sql rename to scripts/sql-gist/useDatabase.sql index 7ec64e760df..6e2efe4e539 100644 --- a/scripts/sql-template/use-database.sql +++ b/scripts/sql-gist/useDatabase.sql @@ -13,7 +13,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- --- @@template-start@@ +-- @@gist-start@@ -- Use Database Use ApolloAssemblyDB; --- @@template-end@@ +-- @@gist-end@@ diff --git a/scripts/sql-src/apolloconfigdb.sql b/scripts/sql-src/apolloconfigdb.sql index 5d79fcd38ab..ed6a6980a0e 100644 --- a/scripts/sql-src/apolloconfigdb.sql +++ b/scripts/sql-src/apolloconfigdb.sql @@ -21,9 +21,9 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; --- @@${auto-generated-declaration}@@ --- @@${h2-function}@@ --- @@${setup-database}@@ +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.setupDatabase} -- Dump of table app -- ------------------------------------------------------------ @@ -490,7 +490,7 @@ VALUES ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); --- @@${auto-generated-declaration}@@ +-- ${gists.autoGeneratedDeclaration} /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; diff --git a/scripts/sql-src/apolloportaldb.sql b/scripts/sql-src/apolloportaldb.sql index 3342995dab2..55d908a018e 100644 --- a/scripts/sql-src/apolloportaldb.sql +++ b/scripts/sql-src/apolloportaldb.sql @@ -21,9 +21,9 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; --- @@${auto-generated-declaration}@@ --- @@${h2-function}@@ --- @@${setup-database}@@ +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.setupDatabase} -- Dump of table app -- ------------------------------------------------------------ @@ -434,7 +434,7 @@ VALUES INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); --- @@${auto-generated-declaration}@@ +-- ${gists.autoGeneratedDeclaration} /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; diff --git a/scripts/sql-src/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql-src/delta/v220-v230/apolloconfigdb-v220-v230.sql index 359a6709cb6..2561f5813b9 100644 --- a/scripts/sql-src/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql-src/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -15,9 +15,9 @@ -- -- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 --- @@${auto-generated-declaration}@@ --- @@${h2-function}@@ --- @@${use-database}@@ +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} --- @@${auto-generated-declaration}@@ +-- ${gists.autoGeneratedDeclaration} diff --git a/scripts/sql-src/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql-src/delta/v220-v230/apolloportaldb-v220-v230.sql index 442f1ddcb2f..811c031454c 100644 --- a/scripts/sql-src/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql-src/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -15,9 +15,9 @@ -- -- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 --- @@${auto-generated-declaration}@@ --- @@${h2-function}@@ --- @@${use-database}@@ +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} --- @@${auto-generated-declaration}@@ +-- ${gists.autoGeneratedDeclaration} diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index 281f99e4a27..fb130164afd 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -21,13 +21,15 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== - +-- +-- -- Create Database -- ------------------------------------------------------------ CREATE DATABASE IF NOT EXISTS ApolloConfigDB DEFAULT CHARACTER SET = utf8mb4; @@ -499,6 +501,7 @@ VALUES ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == diff --git a/scripts/sql/apolloportaldb.sql b/scripts/sql/apolloportaldb.sql index 20ab7c885fc..136db190ffd 100644 --- a/scripts/sql/apolloportaldb.sql +++ b/scripts/sql/apolloportaldb.sql @@ -21,13 +21,15 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== - +-- +-- -- Create Database -- ------------------------------------------------------------ CREATE DATABASE IF NOT EXISTS ApolloPortalDB DEFAULT CHARACTER SET = utf8mb4; @@ -443,6 +445,7 @@ VALUES INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == diff --git a/scripts/sql/assembly/h2/apolloconfigdb.sql b/scripts/sql/assembly/h2/apolloconfigdb.sql index fb2c5ed2774..5bc1d8202a8 100644 --- a/scripts/sql/assembly/h2/apolloconfigdb.sql +++ b/scripts/sql/assembly/h2/apolloconfigdb.sql @@ -21,17 +21,20 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== +-- -- H2 Function -- ------------------------------------------------------------ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; +-- -- Dump of table app -- ------------------------------------------------------------ @@ -56,7 +59,7 @@ CREATE TABLE `C_0_App` ( UNIQUE KEY (`AppId`,`DeletedAt`), KEY (`DataChange_LastTime`), KEY (`Name`) -) ; +) ; @@ -82,7 +85,7 @@ CREATE TABLE `C_0_AppNamespace` ( UNIQUE KEY (`AppId`,`Name`,`DeletedAt`), KEY (`Name`,`AppId`), KEY (`DataChange_LastTime`) -) ; +) ; @@ -105,7 +108,7 @@ CREATE TABLE `C_0_Audit` ( `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), KEY (`DataChange_LastTime`) -) ; +) ; @@ -129,7 +132,7 @@ CREATE TABLE `C_0_Cluster` ( UNIQUE KEY (`AppId`,`Name`,`DeletedAt`), KEY (`ParentClusterId`), KEY (`DataChange_LastTime`) -) ; +) ; @@ -156,7 +159,7 @@ CREATE TABLE `C_0_Commit` ( KEY (`AppId`), KEY (`ClusterName`), KEY (`NamespaceName`) -) ; +) ; -- Dump of table grayreleaserule -- ------------------------------------------------------------ @@ -181,7 +184,7 @@ CREATE TABLE `C_0_GrayReleaseRule` ( PRIMARY KEY (`Id`), KEY (`DataChange_LastTime`), KEY (`AppId`,`ClusterName`,`NamespaceName`) -) ; +) ; -- Dump of table instance @@ -201,7 +204,7 @@ CREATE TABLE `C_0_Instance` ( UNIQUE KEY (`AppId`,`ClusterName`,`Ip`,`DataCenter`), KEY (`Ip`), KEY (`DataChange_LastTime`) -) ; +) ; @@ -225,7 +228,7 @@ CREATE TABLE `C_0_InstanceConfig` ( KEY (`ReleaseKey`), KEY (`DataChange_LastTime`), KEY (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) -) ; +) ; @@ -251,7 +254,7 @@ CREATE TABLE `C_0_Item` ( PRIMARY KEY (`Id`), KEY (`NamespaceId`), KEY (`DataChange_LastTime`) -) ; +) ; @@ -275,7 +278,7 @@ CREATE TABLE `C_0_Namespace` ( UNIQUE KEY (`AppId`,`ClusterName`,`NamespaceName`,`DeletedAt`), KEY (`DataChange_LastTime`), KEY (`NamespaceName`) -) ; +) ; @@ -296,7 +299,7 @@ CREATE TABLE `C_0_NamespaceLock` ( PRIMARY KEY (`Id`), UNIQUE KEY (`NamespaceId`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; +) ; @@ -325,7 +328,7 @@ CREATE TABLE `C_0_Release` ( UNIQUE KEY (`ReleaseKey`,`DeletedAt`), KEY (`AppId`,`ClusterName`,`NamespaceName`), KEY (`DataChange_LastTime`) -) ; +) ; -- Dump of table releasehistory @@ -354,7 +357,7 @@ CREATE TABLE `C_0_ReleaseHistory` ( KEY (`ReleaseId`), KEY (`DataChange_LastTime`), KEY (`PreviousReleaseId`) -) ; +) ; -- Dump of table releasemessage @@ -369,7 +372,7 @@ CREATE TABLE `C_0_ReleaseMessage` ( PRIMARY KEY (`Id`), KEY (`DataChange_LastTime`), KEY (`Message`) -) ; +) ; @@ -393,7 +396,7 @@ CREATE TABLE `C_0_ServerConfig` ( PRIMARY KEY (`Id`), UNIQUE KEY (`Key`,`Cluster`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; +) ; -- Dump of table accesskey -- ------------------------------------------------------------ @@ -414,7 +417,7 @@ CREATE TABLE `C_0_AccessKey` ( PRIMARY KEY (`Id`), UNIQUE KEY (`AppId`,`Secret`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; +) ; -- Dump of table serviceregistry @@ -433,7 +436,7 @@ CREATE TABLE `C_0_ServiceRegistry` ( PRIMARY KEY (`Id`), UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) ; -- Dump of table AuditLog -- ------------------------------------------------------------ @@ -461,7 +464,7 @@ CREATE TABLE `C_0_AuditLog` ( KEY (`OpName`), KEY (`DataChange_CreatedTime`), KEY (`Operator`) -) ; +) ; -- Dump of table AuditLogDataInfluence -- ------------------------------------------------------------ @@ -486,7 +489,7 @@ CREATE TABLE `C_0_AuditLogDataInfluence` ( KEY (`SpanId`), KEY (`DataChange_CreatedTime`), KEY (`InfluenceEntityId`) -) ; +) ; -- Config -- ------------------------------------------------------------ @@ -498,6 +501,7 @@ VALUES ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == diff --git a/scripts/sql/assembly/h2/apolloportaldb.sql b/scripts/sql/assembly/h2/apolloportaldb.sql index f62fc0dc601..28e19cf73c2 100644 --- a/scripts/sql/assembly/h2/apolloportaldb.sql +++ b/scripts/sql/assembly/h2/apolloportaldb.sql @@ -21,17 +21,20 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== +-- -- H2 Function -- ------------------------------------------------------------ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; +-- -- Dump of table app -- ------------------------------------------------------------ @@ -56,7 +59,7 @@ CREATE TABLE `P_0_App` ( UNIQUE KEY (`AppId`,`DeletedAt`), KEY (`DataChange_LastTime`), KEY (`Name`) -) ; +) ; @@ -82,7 +85,7 @@ CREATE TABLE `P_0_AppNamespace` ( UNIQUE KEY (`AppId`,`Name`,`DeletedAt`), KEY (`Name`,`AppId`), KEY (`DataChange_LastTime`) -) ; +) ; @@ -108,7 +111,7 @@ CREATE TABLE `P_0_Consumer` ( PRIMARY KEY (`Id`), UNIQUE KEY (`AppId`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; +) ; @@ -127,7 +130,7 @@ CREATE TABLE `P_0_ConsumerAudit` ( PRIMARY KEY (`Id`), KEY (`DataChange_LastTime`), KEY (`ConsumerId`) -) ; +) ; @@ -150,7 +153,7 @@ CREATE TABLE `P_0_ConsumerRole` ( UNIQUE KEY (`ConsumerId`,`RoleId`,`DeletedAt`), KEY (`DataChange_LastTime`), KEY (`RoleId`) -) ; +) ; @@ -173,7 +176,7 @@ CREATE TABLE `P_0_ConsumerToken` ( PRIMARY KEY (`Id`), UNIQUE KEY (`Token`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; +) ; -- Dump of table favorite -- ------------------------------------------------------------ @@ -195,7 +198,7 @@ CREATE TABLE `P_0_Favorite` ( UNIQUE KEY (`UserId`,`AppId`,`DeletedAt`), KEY (`AppId`), KEY (`DataChange_LastTime`) -) AUTO_INCREMENT=23 ; +) AUTO_INCREMENT=23 ; -- Dump of table permission -- ------------------------------------------------------------ @@ -215,7 +218,7 @@ CREATE TABLE `P_0_Permission` ( PRIMARY KEY (`Id`), UNIQUE KEY (`TargetId`,`PermissionType`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; +) ; @@ -236,7 +239,7 @@ CREATE TABLE `P_0_Role` ( PRIMARY KEY (`Id`), UNIQUE KEY (`RoleName`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; +) ; @@ -259,7 +262,7 @@ CREATE TABLE `P_0_RolePermission` ( UNIQUE KEY (`RoleId`,`PermissionId`,`DeletedAt`), KEY (`DataChange_LastTime`), KEY (`PermissionId`) -) ; +) ; @@ -282,7 +285,7 @@ CREATE TABLE `P_0_ServerConfig` ( PRIMARY KEY (`Id`), UNIQUE KEY (`Key`,`DeletedAt`), KEY (`DataChange_LastTime`) -) ; +) ; @@ -305,7 +308,7 @@ CREATE TABLE `P_0_UserRole` ( UNIQUE KEY (`UserId`,`RoleId`,`DeletedAt`), KEY (`DataChange_LastTime`), KEY (`RoleId`) -) ; +) ; -- Dump of table Users -- ------------------------------------------------------------ @@ -321,7 +324,7 @@ CREATE TABLE `P_0_Users` ( `Enabled` tinyint(4) DEFAULT NULL , PRIMARY KEY (`Id`), UNIQUE KEY (`Username`) -) ; +) ; -- Dump of table Authorities @@ -334,7 +337,7 @@ CREATE TABLE `P_0_Authorities` ( `Username` varchar(64) NOT NULL, `Authority` varchar(50) NOT NULL, PRIMARY KEY (`Id`) -) ; +) ; -- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) -- Dump of table SPRING_SESSION @@ -354,7 +357,7 @@ CREATE TABLE `P_0_SPRING_SESSION` ( UNIQUE KEY (`SESSION_ID`), KEY (`EXPIRY_TIME`), KEY (`PRINCIPAL_NAME`) -) ; +) ; -- Dump of table SPRING_SESSION_ATTRIBUTES -- ------------------------------------------------------------ @@ -367,7 +370,7 @@ CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( `ATTRIBUTE_BYTES` blob NOT NULL, PRIMARY KEY (`SESSION_PRIMARY_ID`,`ATTRIBUTE_NAME`), CONSTRAINT `SPRING_SESSION_ATTRIBUTES_FK` FOREIGN KEY (`SESSION_PRIMARY_ID`) REFERENCES `P_0_SPRING_SESSION` (`PRIMARY_ID`) ON DELETE CASCADE -) ; +) ; -- Dump of table AuditLog -- ------------------------------------------------------------ @@ -395,7 +398,7 @@ CREATE TABLE `P_0_AuditLog` ( KEY (`OpName`), KEY (`DataChange_CreatedTime`), KEY (`Operator`) -) ; +) ; -- Dump of table AuditLogDataInfluence -- ------------------------------------------------------------ @@ -420,7 +423,7 @@ CREATE TABLE `P_0_AuditLogDataInfluence` ( KEY (`SpanId`), KEY (`DataChange_CreatedTime`), KEY (`InfluenceEntityId`) -) ; +) ; -- Config -- ------------------------------------------------------------ @@ -442,6 +445,7 @@ VALUES INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == diff --git a/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql index 123061005a6..b9f51044ab9 100644 --- a/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -15,19 +15,23 @@ -- -- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== +-- -- H2 Function -- ------------------------------------------------------------ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; +-- +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == diff --git a/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql index 7f0744cb914..0bb35b97faf 100644 --- a/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -15,19 +15,23 @@ -- -- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== +-- -- H2 Function -- ------------------------------------------------------------ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; +-- +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == diff --git a/scripts/sql/assembly/mysql/apolloconfigdb.sql b/scripts/sql/assembly/mysql/apolloconfigdb.sql index 79adf6498f3..28b4b682e74 100644 --- a/scripts/sql/assembly/mysql/apolloconfigdb.sql +++ b/scripts/sql/assembly/mysql/apolloconfigdb.sql @@ -21,18 +21,15 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== - --- Create Database --- ------------------------------------------------------------ -CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; - -Use ApolloAssemblyDB; +-- +-- -- Dump of table app -- ------------------------------------------------------------ @@ -499,6 +496,7 @@ VALUES ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == diff --git a/scripts/sql/assembly/mysql/apolloportaldb.sql b/scripts/sql/assembly/mysql/apolloportaldb.sql index e910860277e..136a88f7f2a 100644 --- a/scripts/sql/assembly/mysql/apolloportaldb.sql +++ b/scripts/sql/assembly/mysql/apolloportaldb.sql @@ -21,18 +21,15 @@ /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== - --- Create Database --- ------------------------------------------------------------ -CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; - -Use ApolloAssemblyDB; +-- +-- -- Dump of table app -- ------------------------------------------------------------ @@ -443,6 +440,7 @@ VALUES INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql index 6389bcf4068..057e8ba5d10 100644 --- a/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -15,17 +15,18 @@ -- -- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== - --- Use Database -Use ApolloAssemblyDB; +-- +-- +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql index 35fe80f4169..671321ac521 100644 --- a/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -15,17 +15,18 @@ -- -- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== - --- Use Database -Use ApolloAssemblyDB; +-- +-- +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == diff --git a/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql index f0d53e92918..87f1b1e2dee 100644 --- a/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -15,17 +15,20 @@ -- -- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== - +-- +-- -- Use Database Use ApolloConfigDB; +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == diff --git a/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql index dc48f65b622..4cfdefd0ba9 100644 --- a/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -15,17 +15,20 @@ -- -- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== - +-- +-- -- Use Database Use ApolloPortalDB; +-- -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == From 7663dd3df5fe6e83148dc8d6d4e11de66a780d43 Mon Sep 17 00:00:00 2001 From: vdisk Date: Tue, 2 Jan 2024 22:13:31 +0800 Subject: [PATCH 25/59] fix assembly sql temp v0.4 --- apollo-assembly/pom.xml | 2 + ...lyDataSourceScriptDatabaseInitializer.java | 34 +- .../resources/application-github.properties | 2 +- .../extensions/sql/ApolloSqlConverter.java | 33 +- .../sql/ApolloSqlConverterTest.java | 17 + .../mysql-without-database/apolloconfigdb.sql | 512 ++++++++++++++++++ .../mysql-without-database/apolloportaldb.sql | 456 ++++++++++++++++ .../v220-v230/apolloconfigdb-v220-v230.sql | 35 ++ .../v220-v230/apolloportaldb-v220-v230.sql | 35 ++ scripts/sql/assembly/mysql/apolloconfigdb.sql | 5 + scripts/sql/assembly/mysql/apolloportaldb.sql | 5 + .../v220-v230/apolloconfigdb-v220-v230.sql | 2 + .../v220-v230/apolloportaldb-v220-v230.sql | 2 + 13 files changed, 1115 insertions(+), 25 deletions(-) create mode 100644 scripts/sql/assembly/mysql-without-database/apolloconfigdb.sql create mode 100644 scripts/sql/assembly/mysql-without-database/apolloportaldb.sql create mode 100644 scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloconfigdb-v220-v230.sql create mode 100644 scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloportaldb-v220-v230.sql diff --git a/apollo-assembly/pom.xml b/apollo-assembly/pom.xml index a90125d1061..eaefb728557 100644 --- a/apollo-assembly/pom.xml +++ b/apollo-assembly/pom.xml @@ -67,6 +67,8 @@ h2/apolloportaldb.sql mysql/apolloconfigdb.sql mysql/apolloportaldb.sql + mysql-without-database/apolloconfigdb.sql + mysql-without-database/apolloportaldb.sql diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java index ad14d2c707a..0082e3178fa 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java @@ -18,11 +18,7 @@ import com.ctrip.framework.apollo.assembly.ApolloApplication; import java.net.URL; -import java.nio.file.Path; -import java.nio.file.Paths; import java.security.CodeSource; -import java.sql.Connection; -import java.sql.DatabaseMetaData; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -33,10 +29,7 @@ import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.SingleColumnRowMapper; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; -import org.springframework.jdbc.support.JdbcUtils; -import org.springframework.jdbc.support.MetaDataAccessException; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -80,7 +73,7 @@ private static List resolveLocations(Collection locations, return null; } - Collection convertedLocations = convertRepositoryLocations(locations); + Collection convertedLocations = convertRepositoryLocations(locations, dataSource); if (CollectionUtils.isEmpty(convertedLocations)) { return null; } @@ -92,14 +85,16 @@ private static List resolveLocations(Collection locations, return platformResolver.resolveAll(dataSource, convertedLocations.toArray(new String[0])); } - private static Collection convertRepositoryLocations(Collection locations) { + private static Collection convertRepositoryLocations(Collection locations, + DataSource dataSource) { if (CollectionUtils.isEmpty(locations)) { return null; } String repositoryDir = findRepositoryDirectory(); + String suffix = findSuffix(dataSource); List convertedLocations = new ArrayList<>(locations.size()); for (String location : locations) { - String convertedLocation = convertRepositoryLocation(location, repositoryDir); + String convertedLocation = convertRepositoryLocation(location, repositoryDir, suffix); if (StringUtils.hasText(convertedLocation)) { convertedLocations.add(convertedLocation); } @@ -107,6 +102,18 @@ private static Collection convertRepositoryLocations(Collection return convertedLocations; } + private static String findSuffix(DataSource dataSource) { + DatabaseDriver databaseDriver = DatabaseDriver.fromDataSource(dataSource); + if (DatabaseDriver.MYSQL.equals(databaseDriver)) { + JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); + String database = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class); + if (database != null) { + return "-without-database"; + } + } + return ""; + } + private static String findRepositoryDirectory() { CodeSource codeSource = ApolloApplication.class.getProtectionDomain().getCodeSource(); URL location = codeSource != null ? codeSource.getLocation() : null; @@ -125,15 +132,16 @@ private static String findRepositoryDirectory() { return null; } - private static String convertRepositoryLocation(String location, String repositoryDir) { - if (!StringUtils.hasText(location) || !location.contains("@@repository@@")) { + private static String convertRepositoryLocation(String location, String repositoryDir, + String suffix) { + if (!StringUtils.hasText(location)) { return location; } if (!StringUtils.hasText(repositoryDir)) { // repository dir not found return null; } - return location.replace("@@repository@@", repositoryDir); + return location.replace("@@repository@@", repositoryDir).replace("@@suffix@@", suffix); } private static List scriptLocations(List locations, String fallback, diff --git a/apollo-assembly/src/main/resources/application-github.properties b/apollo-assembly/src/main/resources/application-github.properties index 5f9a299c68b..09e56c85bb8 100644 --- a/apollo-assembly/src/main/resources/application-github.properties +++ b/apollo-assembly/src/main/resources/application-github.properties @@ -25,7 +25,7 @@ spring.jpa.table-prefix.portal-prefix=P_0_ spring.session.jdbc.table-name=P_0_SPRING_SESSION # H2 datasource -spring.sql.init.schema-locations=@@repository@@/assembly/@@platform@@/apolloconfigdb.sql, @@repository@@/assembly/@@platform@@/apolloportaldb.sql +spring.sql.init.schema-locations=@@repository@@/assembly/@@platform@@@@suffix@@/apolloconfigdb.sql, @@repository@@/assembly/@@platform@@@@suffix@@/apolloportaldb.sql spring.sql.init.mode=embedded spring.jpa.hibernate.ddl-auto=none spring.jpa.properties.hibernate.show_sql=false diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java index 3a0015db70d..413550c6128 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java @@ -17,22 +17,11 @@ package com.ctrip.framework.apollo.maven.extensions.sql; import freemarker.template.Configuration; -import freemarker.template.Template; import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.CodeSource; -import java.security.ProtectionDomain; -import java.util.ArrayList; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; public class ApolloSqlConverter { @@ -65,6 +54,9 @@ public static List convert(String targetParentDir) { // '/scripts/sql-src' -> '/scripts/sql/assembly/mysql' convertAssemblyMysqlList(templateList, srcDir, targetParentDir, gists); + // '/scripts/sql-src' -> '/scripts/sql/assembly/mysql-without-database' + convertAssemblyMysqlWithoutDatabaseList(templateList, srcDir, targetParentDir, gists); + // '/scripts/sql-src' -> '/scripts/sql/assembly/h2' convertAssemblyH2List(templateList, srcDir, targetParentDir, gists); @@ -106,6 +98,25 @@ private static void convertAssemblyMysqlList(List templateList, Str String targetParentDir, SqlTemplateGist gists) { String targetDir = targetParentDir + "/sql/assembly/mysql"; + SqlTemplateGist mainMysqlGists = SqlTemplateGist.builder() + .autoGeneratedDeclaration(gists.getAutoGeneratedDeclaration()) + .h2Function("") + .setupDatabase(gists.getSetupDatabase()) + .useDatabase(gists.getUseDatabase()) + .build(); + SqlTemplateContext context = SqlTemplateContext.builder() + .gists(mainMysqlGists) + .build(); + for (SqlTemplate sqlTemplate : templateList) { + String targetSql = ApolloSqlConverterUtil.replacePath(sqlTemplate.getSrcPath(), srcDir, targetDir); + ApolloAssemblyMysqlConverterUtil.convertAssemblyMysql(sqlTemplate, targetSql, context); + } + } + + private static void convertAssemblyMysqlWithoutDatabaseList(List templateList, String srcDir, + String targetParentDir, SqlTemplateGist gists) { + String targetDir = targetParentDir + "/sql/assembly/mysql-without-database"; + SqlTemplateGist mainMysqlGists = SqlTemplateGist.builder() .autoGeneratedDeclaration(gists.getAutoGeneratedDeclaration()) .h2Function("") diff --git a/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java b/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java index 91ecdb2e81f..b8998d74e9f 100644 --- a/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java +++ b/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java @@ -65,6 +65,9 @@ private void checkSqlList(List srcSqlList, String srcDir, String checker // '/scripts/sql/assembly/mysql' this.checkAssemblyMysqlList(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); + // '/scripts/sql/assembly/mysql-without-database' + this.checkAssemblyMysqlWithoutDatabaseList(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); + // '/scripts/sql/assembly/h2' this.checkAssemblyH2List(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); } @@ -195,6 +198,20 @@ private void checkAssemblyMysqlList(List srcSqlList, String srcDir, } } + private void checkAssemblyMysqlWithoutDatabaseList(List srcSqlList, String srcDir, + String checkerParentDir, String repositoryParentDir) { + String checkerTargetDir = checkerParentDir + "/sql/assembly/mysql-without-database"; + String repositoryTargetDir = repositoryParentDir + "/sql/assembly/mysql-without-database"; + for (String srcSql : srcSqlList) { + String checkerTargetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, + checkerTargetDir); + String repositoryTargetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, + repositoryTargetDir); + + this.doCheck(checkerTargetSql, repositoryTargetSql); + } + } + private void checkAssemblyH2List(List srcSqlList, String srcDir, String checkerParentDir, String repositoryParentDir) { String checkerTargetDir = checkerParentDir + "/sql/assembly/h2"; diff --git a/scripts/sql/assembly/mysql-without-database/apolloconfigdb.sql b/scripts/sql/assembly/mysql-without-database/apolloconfigdb.sql new file mode 100644 index 00000000000..28b4b682e74 --- /dev/null +++ b/scripts/sql/assembly/mysql-without-database/apolloconfigdb.sql @@ -0,0 +1,512 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== +-- +-- + +-- Dump of table app +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_App`; + +CREATE TABLE `C_0_App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +-- Dump of table appnamespace +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AppNamespace`; + +CREATE TABLE `C_0_AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +-- Dump of table audit +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Audit`; + +CREATE TABLE `C_0_Audit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID', + `OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表'; + + + +-- Dump of table cluster +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Cluster`; + +CREATE TABLE `C_0_Cluster` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id', + `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `IX_ParentClusterId` (`ParentClusterId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群'; + + + +-- Dump of table commit +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Commit`; + +CREATE TABLE `C_0_Commit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `ChangeSets` longtext NOT NULL COMMENT '修改变更集', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `AppId` (`AppId`), + KEY `ClusterName` (`ClusterName`(191)), + KEY `NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表'; + +-- Dump of table grayreleaserule +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_GrayReleaseRule`; + +CREATE TABLE `C_0_GrayReleaseRule` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name', + `Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release', + `BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表'; + + +-- Dump of table instance +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Instance`; + +CREATE TABLE `C_0_Instance` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name', + `Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`), + KEY `IX_IP` (`Ip`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例'; + + + +-- Dump of table instanceconfig +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_InstanceConfig`; + +CREATE TABLE `C_0_InstanceConfig` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id', + `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id', + `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name', + `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), + KEY `IX_ReleaseKey` (`ReleaseKey`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息'; + + + +-- Dump of table item +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Item`; + +CREATE TABLE `C_0_Item` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '配置项类型,0: String,1: Number,2: Boolean,3: JSON', + `Value` longtext NOT NULL COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_GroupId` (`NamespaceId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目'; + + + +-- Dump of table namespace +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Namespace`; + +CREATE TABLE `C_0_Namespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间'; + + + +-- Dump of table namespacelock +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_NamespaceLock`; + +CREATE TABLE `C_0_NamespaceLock` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁'; + + + +-- Dump of table release +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_Release`; + +CREATE TABLE `C_0_Release` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字', + `Comment` varchar(256) DEFAULT NULL COMMENT '发布说明', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Configurations` longtext NOT NULL COMMENT '发布配置', + `IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`), + KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布'; + + +-- Dump of table releasehistory +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ReleaseHistory`; + +CREATE TABLE `C_0_ReleaseHistory` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id', + `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId', + `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度', + `OperationContext` longtext NOT NULL COMMENT '发布上下文信息', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), + KEY `IX_ReleaseId` (`ReleaseId`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PreviousReleaseId` (`PreviousReleaseId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史'; + + +-- Dump of table releasemessage +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ReleaseMessage`; + +CREATE TABLE `C_0_ReleaseMessage` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Message` (`Message`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息'; + + + +-- Dump of table serverconfig +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ServerConfig`; + +CREATE TABLE `C_0_ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + +-- Dump of table accesskey +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AccessKey`; + +CREATE TABLE `C_0_AccessKey` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret', + `IsEnabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: enabled, 0: disabled', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; + + +-- Dump of table serviceregistry +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_ServiceRegistry`; + +CREATE TABLE `C_0_ServiceRegistry` ( + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', + `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), + INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; + +-- Dump of table AuditLog +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AuditLog`; + +CREATE TABLE `C_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + +-- Dump of table AuditLogDataInfluence +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `C_0_AuditLogDataInfluence`; + +CREATE TABLE `C_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + +-- Config +-- ------------------------------------------------------------ +INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +VALUES + ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), + ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), + ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'), + ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), + ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); + +-- +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/scripts/sql/assembly/mysql-without-database/apolloportaldb.sql b/scripts/sql/assembly/mysql-without-database/apolloportaldb.sql new file mode 100644 index 00000000000..136a88f7f2a --- /dev/null +++ b/scripts/sql/assembly/mysql-without-database/apolloportaldb.sql @@ -0,0 +1,456 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== +-- +-- + +-- Dump of table app +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_App`; + +CREATE TABLE `P_0_App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +-- Dump of table appnamespace +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_AppNamespace`; + +CREATE TABLE `P_0_AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +-- Dump of table consumer +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Consumer`; + +CREATE TABLE `P_0_Consumer` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者'; + + + +-- Dump of table consumeraudit +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerAudit`; + +CREATE TABLE `P_0_ConsumerAudit` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri', + `Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_ConsumerId` (`ConsumerId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表'; + + + +-- Dump of table consumerrole +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerRole`; + +CREATE TABLE `P_0_ConsumerRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表'; + + + +-- Dump of table consumertoken +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ConsumerToken`; + +CREATE TABLE `P_0_ConsumerToken` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId', + `Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token', + `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Token_DeletedAt` (`Token`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表'; + +-- Dump of table favorite +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Favorite`; + +CREATE TABLE `P_0_Favorite` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`), + KEY `AppId` (`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表'; + +-- Dump of table permission +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Permission`; + +CREATE TABLE `P_0_Permission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型', + `TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表'; + + + +-- Dump of table role +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Role`; + +CREATE TABLE `P_0_Role` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; + + + +-- Dump of table rolepermission +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_RolePermission`; + +CREATE TABLE `P_0_RolePermission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PermissionId` (`PermissionId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表'; + + + +-- Dump of table serverconfig +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_ServerConfig`; + +CREATE TABLE `P_0_ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_DeletedAt` (`Key`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + + + +-- Dump of table userrole +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_UserRole`; + +CREATE TABLE `P_0_UserRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表'; + +-- Dump of table Users +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Users`; + +CREATE TABLE `P_0_Users` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户', + `Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码', + `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称', + `Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址', + `Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Username` (`Username`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + + +-- Dump of table Authorities +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_Authorities`; + +CREATE TABLE `P_0_Authorities` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL, + `Authority` varchar(50) NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) +-- Dump of table SPRING_SESSION +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_SPRING_SESSION`; + +CREATE TABLE `P_0_SPRING_SESSION` ( + `PRIMARY_ID` char(36) NOT NULL, + `SESSION_ID` char(36) NOT NULL, + `CREATION_TIME` bigint NOT NULL, + `LAST_ACCESS_TIME` bigint NOT NULL, + `MAX_INACTIVE_INTERVAL` int NOT NULL, + `EXPIRY_TIME` bigint NOT NULL, + `PRINCIPAL_NAME` varchar(100) DEFAULT NULL, + PRIMARY KEY (`PRIMARY_ID`), + UNIQUE KEY `SPRING_SESSION_IX1` (`SESSION_ID`), + KEY `SPRING_SESSION_IX2` (`EXPIRY_TIME`), + KEY `SPRING_SESSION_IX3` (`PRINCIPAL_NAME`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + +-- Dump of table SPRING_SESSION_ATTRIBUTES +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_SPRING_SESSION_ATTRIBUTES`; + +CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( + `SESSION_PRIMARY_ID` char(36) NOT NULL, + `ATTRIBUTE_NAME` varchar(200) NOT NULL, + `ATTRIBUTE_BYTES` blob NOT NULL, + PRIMARY KEY (`SESSION_PRIMARY_ID`,`ATTRIBUTE_NAME`), + CONSTRAINT `SPRING_SESSION_ATTRIBUTES_FK` FOREIGN KEY (`SESSION_PRIMARY_ID`) REFERENCES `P_0_SPRING_SESSION` (`PRIMARY_ID`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + +-- Dump of table AuditLog +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_AuditLog`; + +CREATE TABLE `P_0_AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + +-- Dump of table AuditLogDataInfluence +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `P_0_AuditLogDataInfluence`; + +CREATE TABLE `P_0_AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + +-- Config +-- ------------------------------------------------------------ +INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) +VALUES + ('apollo.portal.envs', 'dev', '可支持的环境列表'), + ('organizations', '[{"orgId":"TEST1","orgName":"样例部门1"},{"orgId":"TEST2","orgName":"样例部门2"}]', '部门列表'), + ('superAdmin', 'apollo', 'Portal超级管理员'), + ('api.readTimeout', '10000', 'http接口read timeout'), + ('consumer.token.salt', 'someSalt', 'consumer token salt'), + ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'), + ('configView.memberOnly.envs', 'pro', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔'), + ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); + + +INSERT INTO `P_0_Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) +VALUES + ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); + +INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); + +-- +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloconfigdb-v220-v230.sql new file mode 100644 index 00000000000..057e8ba5d10 --- /dev/null +++ b/scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -0,0 +1,35 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 + +-- +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== +-- +-- + + +-- +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== diff --git a/scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloportaldb-v220-v230.sql new file mode 100644 index 00000000000..671321ac521 --- /dev/null +++ b/scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -0,0 +1,35 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v2.2.0 to v2.3.0 + +-- +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== +-- +-- + + +-- +-- =============================================================================== +-- == == +-- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == +-- == DO NOT EDIT !!! == +-- == == +-- =============================================================================== diff --git a/scripts/sql/assembly/mysql/apolloconfigdb.sql b/scripts/sql/assembly/mysql/apolloconfigdb.sql index 28b4b682e74..de75aba3b85 100644 --- a/scripts/sql/assembly/mysql/apolloconfigdb.sql +++ b/scripts/sql/assembly/mysql/apolloconfigdb.sql @@ -30,6 +30,11 @@ -- =============================================================================== -- -- +-- Create Database +-- ------------------------------------------------------------ +CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; + +Use ApolloAssemblyDB; -- Dump of table app -- ------------------------------------------------------------ diff --git a/scripts/sql/assembly/mysql/apolloportaldb.sql b/scripts/sql/assembly/mysql/apolloportaldb.sql index 136a88f7f2a..9f69a185f13 100644 --- a/scripts/sql/assembly/mysql/apolloportaldb.sql +++ b/scripts/sql/assembly/mysql/apolloportaldb.sql @@ -30,6 +30,11 @@ -- =============================================================================== -- -- +-- Create Database +-- ------------------------------------------------------------ +CREATE DATABASE IF NOT EXISTS ApolloAssemblyDB DEFAULT CHARACTER SET = utf8mb4; + +Use ApolloAssemblyDB; -- Dump of table app -- ------------------------------------------------------------ diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql index 057e8ba5d10..2490163bf73 100644 --- a/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -24,6 +24,8 @@ -- =============================================================================== -- -- +-- Use Database +Use ApolloAssemblyDB; -- diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql index 671321ac521..ca2c092f2ce 100644 --- a/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -24,6 +24,8 @@ -- =============================================================================== -- -- +-- Use Database +Use ApolloAssemblyDB; -- From 7930dc3f11b86f72c4cf35bb347c00740dcee60a Mon Sep 17 00:00:00 2001 From: vdisk Date: Tue, 2 Jan 2024 22:22:36 +0800 Subject: [PATCH 26/59] fix assembly sql temp v0.5 --- apollo-assembly/pom.xml | 4 ++-- ...lyDataSourceScriptDatabaseInitializer.java | 17 +---------------- .../extensions/sql/ApolloSqlConverter.java | 9 +++++---- .../sql/ApolloSqlConverterTest.java | 19 ++++++------------- .../apolloconfigdb.sql | 0 .../apolloportaldb.sql | 0 .../v220-v230/apolloconfigdb-v220-v230.sql | 0 .../v220-v230/apolloportaldb-v220-v230.sql | 0 8 files changed, 14 insertions(+), 35 deletions(-) rename scripts/sql/assembly/{mysql-without-database => mysql-database-not-specified}/apolloconfigdb.sql (100%) rename scripts/sql/assembly/{mysql-without-database => mysql-database-not-specified}/apolloportaldb.sql (100%) rename scripts/sql/assembly/{mysql-without-database => mysql-database-not-specified}/delta/v220-v230/apolloconfigdb-v220-v230.sql (100%) rename scripts/sql/assembly/{mysql-without-database => mysql-database-not-specified}/delta/v220-v230/apolloportaldb-v220-v230.sql (100%) diff --git a/apollo-assembly/pom.xml b/apollo-assembly/pom.xml index eaefb728557..dbef818e16a 100644 --- a/apollo-assembly/pom.xml +++ b/apollo-assembly/pom.xml @@ -67,8 +67,8 @@ h2/apolloportaldb.sql mysql/apolloconfigdb.sql mysql/apolloportaldb.sql - mysql-without-database/apolloconfigdb.sql - mysql-without-database/apolloportaldb.sql + mysql-database-not-specified/apolloconfigdb.sql + mysql-database-not-specified/apolloportaldb.sql diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java index 0082e3178fa..92c830d8306 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java @@ -29,7 +29,6 @@ import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -108,7 +107,7 @@ private static String findSuffix(DataSource dataSource) { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); String database = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class); if (database != null) { - return "-without-database"; + return "-database-not-specified"; } } return ""; @@ -154,18 +153,4 @@ private static List scriptLocations(List locations, String fallb fallbackLocations.add("optional:classpath*:" + fallback + ".sql"); return fallbackLocations; } - - @Override - protected void customize(ResourceDatabasePopulator populator) { - DataSource dataSource = this.getDataSource(); - DatabaseDriver databaseDriver = DatabaseDriver.fromDataSource(dataSource); - if (DatabaseDriver.MYSQL.equals(databaseDriver)) { - JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); - String database = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class); - if (database != null) { - populator.setScripts(); - } - System.out.println(database); - } - } } diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java index 413550c6128..0bebc4dbc90 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java +++ b/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java @@ -54,8 +54,8 @@ public static List convert(String targetParentDir) { // '/scripts/sql-src' -> '/scripts/sql/assembly/mysql' convertAssemblyMysqlList(templateList, srcDir, targetParentDir, gists); - // '/scripts/sql-src' -> '/scripts/sql/assembly/mysql-without-database' - convertAssemblyMysqlWithoutDatabaseList(templateList, srcDir, targetParentDir, gists); + // '/scripts/sql-src' -> '/scripts/sql/assembly/mysql-database-not-specified' + convertAssemblyMysqlDatabaseNotSpecifiedList(templateList, srcDir, targetParentDir, gists); // '/scripts/sql-src' -> '/scripts/sql/assembly/h2' convertAssemblyH2List(templateList, srcDir, targetParentDir, gists); @@ -113,9 +113,10 @@ private static void convertAssemblyMysqlList(List templateList, Str } } - private static void convertAssemblyMysqlWithoutDatabaseList(List templateList, String srcDir, + private static void convertAssemblyMysqlDatabaseNotSpecifiedList(List templateList, + String srcDir, String targetParentDir, SqlTemplateGist gists) { - String targetDir = targetParentDir + "/sql/assembly/mysql-without-database"; + String targetDir = targetParentDir + "/sql/assembly/mysql-database-not-specified"; SqlTemplateGist mainMysqlGists = SqlTemplateGist.builder() .autoGeneratedDeclaration(gists.getAutoGeneratedDeclaration()) diff --git a/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java b/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java index b8998d74e9f..54c959b2c63 100644 --- a/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java +++ b/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java @@ -16,20 +16,12 @@ */ package com.ctrip.framework.apollo.maven.extensions.sql; -import freemarker.template.TemplateException; import java.io.BufferedReader; import java.io.IOException; -import java.io.StringWriter; import java.io.UncheckedIOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; -import java.security.CodeSource; -import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -65,8 +57,9 @@ private void checkSqlList(List srcSqlList, String srcDir, String checker // '/scripts/sql/assembly/mysql' this.checkAssemblyMysqlList(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); - // '/scripts/sql/assembly/mysql-without-database' - this.checkAssemblyMysqlWithoutDatabaseList(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); + // '/scripts/sql/assembly/mysql-database-not-specified' + this.checkAssemblyMysqlDatabaseNotSpecifiedList(srcSqlList, srcDir, checkerParentDir, + repositoryParentDir); // '/scripts/sql/assembly/h2' this.checkAssemblyH2List(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); @@ -198,10 +191,10 @@ private void checkAssemblyMysqlList(List srcSqlList, String srcDir, } } - private void checkAssemblyMysqlWithoutDatabaseList(List srcSqlList, String srcDir, + private void checkAssemblyMysqlDatabaseNotSpecifiedList(List srcSqlList, String srcDir, String checkerParentDir, String repositoryParentDir) { - String checkerTargetDir = checkerParentDir + "/sql/assembly/mysql-without-database"; - String repositoryTargetDir = repositoryParentDir + "/sql/assembly/mysql-without-database"; + String checkerTargetDir = checkerParentDir + "/sql/assembly/mysql-database-not-specified"; + String repositoryTargetDir = repositoryParentDir + "/sql/assembly/mysql-database-not-specified"; for (String srcSql : srcSqlList) { String checkerTargetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, checkerTargetDir); diff --git a/scripts/sql/assembly/mysql-without-database/apolloconfigdb.sql b/scripts/sql/assembly/mysql-database-not-specified/apolloconfigdb.sql similarity index 100% rename from scripts/sql/assembly/mysql-without-database/apolloconfigdb.sql rename to scripts/sql/assembly/mysql-database-not-specified/apolloconfigdb.sql diff --git a/scripts/sql/assembly/mysql-without-database/apolloportaldb.sql b/scripts/sql/assembly/mysql-database-not-specified/apolloportaldb.sql similarity index 100% rename from scripts/sql/assembly/mysql-without-database/apolloportaldb.sql rename to scripts/sql/assembly/mysql-database-not-specified/apolloportaldb.sql diff --git a/scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql similarity index 100% rename from scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloconfigdb-v220-v230.sql rename to scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql diff --git a/scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql similarity index 100% rename from scripts/sql/assembly/mysql-without-database/delta/v220-v230/apolloportaldb-v220-v230.sql rename to scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql From 6763f62956a4b257cc46795f349f5150adae6327 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 5 Jan 2024 22:21:33 +0800 Subject: [PATCH 27/59] assembly doc --- .../ApolloApplication-Run.png | Bin 0 -> 15230 bytes .../development/apollo-development-guide.md | 116 +++++++----------- .../development/apollo-development-guide.md | 72 +++-------- 3 files changed, 56 insertions(+), 132 deletions(-) create mode 100644 doc/images/local-development/ApolloApplication-Run.png diff --git a/doc/images/local-development/ApolloApplication-Run.png b/doc/images/local-development/ApolloApplication-Run.png new file mode 100644 index 0000000000000000000000000000000000000000..e32852ac56d2565f783f0be4882067f725d12643 GIT binary patch literal 15230 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 JN>KmL{{f4LTcH2| literal 0 HcmV?d00001 diff --git a/docs/en/development/apollo-development-guide.md b/docs/en/development/apollo-development-guide.md index 7aa8f8edfa4..f33da7e4762 100644 --- a/docs/en/development/apollo-development-guide.md +++ b/docs/en/development/apollo-development-guide.md @@ -9,7 +9,7 @@ This document describes how to compile and run Apollo locally using the IDE so t Apollo local development requires the following components. 1. Java: 1.8+ -2. MySQL: 5.6.5+ 3. +2. MySQL: 5.6.5+ (If you plan to use H2 in-memory database/H2 file database, then there is no need to prepare MySQL) 3. IDE: No special requirements MySQL is required to create Apollo database and import the base data. @@ -24,13 +24,13 @@ Please refer to [Apollo Configuration Center Design](en/design/apollo-design) fo # II. Local startup -## 2.1 Apollo Config Service and Apollo Admin Service +## 2.1 Apollo Assembly -When we develop locally, we usually start both `apollo-config service` and `apollo-adminservice` in the IDE. +When we develop locally, we usually start `apollo-assembly` in the IDE. -The following is an example of how to start `apollo-configService` and `apollo-adminservice` locally with Intellij Community 2016.2 version. +The following is an example of how to start `apollo-assembly` locally with Intellij Community 2016.2 version. -![ConfigAdminApplication-Overview](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ConfigAdminApplication-Overview.png) +![ApolloApplication-Overview](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ApolloApplication-Overview.png) ### 2.1.1 Create a new running configuration @@ -40,34 +40,43 @@ The following is an example of how to start `apollo-configService` and `apollo-a `com.ctrip.framework.apollo.assembly.ApolloApplication` -> Note: If you want to start `apollo-configservice` and `apollo-adminservice` independently, you can replace Main Class with -> ConfigServiceApplication` and +> Note: If you want to start `apollo-portal`, `apollo-configservice` and `apollo-adminservice` independently, you can replace Main Class with +> `com.ctrip.framework.apollo.portal.PortalApplication` +> `com.ctrip.framework.apollo.configservice.ConfigServiceApplication` > `com.ctrip.framework.apollo.adminservice.AdminServiceApplication` ### 2.1.3 VM options configuration -![ConfigAdminApplication-VM-Options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ConfigAdminApplication-VM-Options.png) - - -Dapollo_profile=github - -Dspring.datasource.url=jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8 - -Dspring.datasource.username=root - -Dspring.datasource.password= +![ApolloApplication-VM-Options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ApolloApplication-VM-Options.png) +``` +-Dapollo_profile=github,auth ->Note 1: replace spring.datasource related configuration with your own database connection information, note that the database is `ApolloConfigDB`. +``` +>Note 1: apollo_profile is specified here as `github` and `auth`, where `github` is a profile required by Apollo for database configuration, and `auth` is added from 0.9.0 to support simple authentication using Spring Security provided by apollo. For more information you can refer to [Portal-implement-user-login-function](en/development/portal-how-to-implement-user-login-function) > ->Note 2: The default log output of the program is /opt/logs/100003171/apollo-assembly.log, if you need to modify the log file path, you can add the `logging.file.name` parameter, as follows. +>Note 2: If you plan to use a MySQL database, you need to add `spring.datasource.*` related configuration, replace the database connection information with your own, note that the database is `ApolloAssemblyDB` > ->-Dlogging.file.name=/your-path/apollo-assembly.log +![ApolloApplication-Mysql-VM-Options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ApolloApplication-Mysql-VM-Options.png) + +``` +-Dspring.datasource.url=jdbc:mysql://localhost:3306/ApolloAssemblyDB?characterEncoding=utf8 +-Dspring.datasource.username=root +-Dspring.datasource.password= -### 2.1.4 Program arguments configuration +``` +The initialization script for the MySQL database can be found in the scripts/sql/assembly/mysql directory of this project. +[apolloconfigdb.sql](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/scripts/sql/assembly/mysql/apolloconfigdb.sql) +[apolloportaldb.sql](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/scripts/sql/assembly/mysql/apolloportaldb.sql) -`--configservice --adminservice` +>Note 3: The default log output of the program is /opt/logs/100003171/apollo-assembly.log, if you need to modify the log file path, you can add the `logging.file.name` parameter, as follows. +> +>-Dlogging.file.name=/your-path/apollo-assembly.log -### 2.1.5 Run +### 2.1.4 Run Click Run or Debug for the new run configuration. -![ConfigAdminApplication-Run](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ConfigAdminApplication-Run.png) +![ApolloApplication-Run](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ApolloApplication-Run.png) After starting, open [http://localhost:8080](http://localhost:8080) to see that both `apollo-configservice` and `apollo-adminservice` have been started and registered to Eureka. @@ -88,66 +97,23 @@ After starting, open [http://localhost:8080](http://localhost:8080) to see that > ... > } -## 2.2 Apollo-Portal - -The following is an example of how to start `apollo-portal` locally with Intellij Community 2016.2 version. - -![PortalApplication-Overview](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/PortalApplication-Overview.png) - -### 2.2.1 New run configuration - -![NewConfiguration-Application](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/NewConfiguration-Application.png) - -### 2.2.2 Main class configuration - -`com.ctrip.framework.apollo.portal.PortalApplication` - -### 2.2.3 VM options configuration - -![PortalApplication-VM-Options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/PortalApplication-VM-Options.png) - - -Dapollo_profile=github,auth - -Ddev_meta=http://localhost:8080/ - -Dserver.port=8070 - -Dspring.datasource.url=jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8 - -Dspring.datasource.username=root - -Dspring.datasource.password= - ->Note 1: apollo_profile is specified here as `github` and `auth`, where `github` is a profile required by Apollo for database configuration, and `auth` is added from 0.9.0 to support simple authentication using Spring Security provided by apollo. For more information you can refer to [Portal-implement-user-login-function](en/development/portal-how-to-implement-user-login-function) -> ->Note 2: spring.datasource related configuration replaced with your own database connection information, note that the database is `ApolloPortalDB `. -> ->Note 3: The default configuration imported in ApolloPortalDB will only show the configuration of DEV environment, so the dev\_meta property is configured here, if you want to show the configuration of other environment locally, you need to add the meta server address of other environment here, such as fat\_meta. -> ->Note 4: Here server.port=8070 is specified because `apollo-configservice` starts on port 8080, so here `apollo-portal` is configured to start on port 8070. -> ->Note 5: The default log output of the program is /opt/logs/100003173/apollo-portal.log. If you need to modify the log file path, you can add the `logging.file.name` parameter as follows. -> ->-Dlogging.file.name=/your-path/apollo-portal.log - -### 2.2.4 Running - -Click Run or Debug for the newly created run configuration. - -![PortalApplication-Run](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/PortalApplication-Run.png) - After starting, open [http://localhost:8070](http://localhost:8070) to see the Apollo Configuration Center interface. ![PortalApplication-Home](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/PortalApplication-Home.png) >Note: If `auth` profile is enabled, the default username is apollo and password is admin -### 2.2.5 Demo application access +### 2.1.5 Demo application access For better development and debugging, we usually create a demo project for our own use. You can refer to [General Application Access Guide](en/usage/apollo-user-guide?id=i-general-application-access-guide) to create your own demo project. -## 2.3 Java sample client startup +## 2.2 Java sample client startup There is a sample client project: [apollo-demo-java](https://github.com/apolloconfig/apollo-demo-java), the following is an example of how to start it locally with Intellij. -### 2.3.1 Configure the project AppId +### 2.2.1 Configure the project AppId When creating a demo project in `2.2.5 Demo Application Access`, the system will ask to fill in a globally unique AppId, which we need to configure into the app.properties file of the `apollo-demo` project: `apollo-demo-java/api-demo/src/main/resources/ META-INF/app.properties`. @@ -163,15 +129,15 @@ If our own demo project uses an AppId of 100004458, then the file content would > More ways to configure AppId can be found in [1.2.1 AppId](en/usage/java-sdk-user-guide?id=_121-appid) -### 2.3.2 New run configuration +### 2.2.2 New run configuration ![NewConfiguration-Application](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/NewConfiguration-Application.png) -### 2.3.3 Main class configuration +### 2.2.3 Main class configuration `com.apolloconfig.apollo.demo.api.SimpleApolloConfigDemo` -### 2.3.4 VM options configuration +### 2.2.4 VM options configuration ![apollo-demo-vm-options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/apollo-demo-vm-options.jpg) @@ -181,11 +147,11 @@ If our own demo project uses an AppId of 100004458, then the file content would > For more ways to configure Apollo Meta Server, please refer to [1.2.2 Apollo Meta Server](en/usage/java-sdk-user-guide?id=_122-apollo-meta-server) -### 2.3.5 Overview +### 2.2.5 Overview ![apollo-demo-overview](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/apollo-demo-overview.jpg) -### 2.3.6 Running +### 2.2.6 Running Click Run or Debug on the newly created run configuration. @@ -208,11 +174,11 @@ Enter the value you have configured on the Portal, such as `timeout` in our demo > > -## 2.4 .Net sample client startup +## 2.3 .Net sample client startup The [apollo.net](https://github.com/ctripcorp/apollo.net) project has a sample client project: `ApolloDemo`, here's an example of how to start it locally with VS 2010. -### 2.4.1 Configuring the project AppId +### 2.3.1 Configuring the project AppId When creating a Demo project in `2.2.5 Demo Application Access`, the system will ask to fill in a globally unique AppId, which we need to configure into the App.config file of the `ApolloDemo` project: `apollo.net\ApolloDemo\App.config`. @@ -228,13 +194,13 @@ If our own demo project uses an AppId of 100004458, then the contents of the fil > For public Namespace configurations, the configuration can be obtained without the AppId, but the ability of the application to override the public Namespace configuration is lost. -### 2.4.2 Configuring Service Addresses +### 2.3.2 Configuring Service Addresses Apollo client will get the configuration from different servers for different environments, so we need to configure the server address (Apollo.{ENV}.Meta) in app.config or web.config. Suppose the DEV environment's configuration service (apollo-config service) address is 11.22.33.44, then we will do the following configuration. ![apollo-net-server-url-config](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/apollo-net-server-url-config.png) -### 2.4.3 Running +### 2.3.3 Running Just run `ApolloConfigDemo.cs`. diff --git a/docs/zh/development/apollo-development-guide.md b/docs/zh/development/apollo-development-guide.md index 3f98ae78a25..f5f91fedc63 100644 --- a/docs/zh/development/apollo-development-guide.md +++ b/docs/zh/development/apollo-development-guide.md @@ -45,7 +45,7 @@ Apollo本地开发需要以下组件: ``` >注1:这里指定了apollo_profile是`github`和`auth`,其中`github`是Apollo必须的一个profile,用于数据库的配置,`auth`是从0.9.0新增的,用来支持使用apollo提供的Spring Security简单认证,更多信息可以参考[Portal-实现用户登录功能](zh/development/portal-how-to-implement-user-login-function) > ->注2:如果需要使用 mysql 数据库,添加spring.datasource相关配置,数据库连接信息替换成你自己的,注意数据库是`ApolloAssemblyDB` +>注2:如果需要使用 mysql 数据库,添加`spring.datasource.*`相关配置,数据库连接信息替换成你自己的,注意数据库是`ApolloAssemblyDB` ![ApolloApplication-Mysql-VM-Options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ApolloApplication-Mysql-VM-Options.png) ``` @@ -62,13 +62,10 @@ mysql 数据库初始化脚本见 本项目 scripts/sql/assembly/mysql 目录下 > >-Dlogging.file.name=/your-path/apollo-assembly.log -### 2.1.4 Program arguments配置 -`--configservice --adminservice` - -### 2.1.5 运行 +### 2.1.4 运行 对新建的运行配置点击Run或Debug皆可。 -![ConfigAdminApplication-Run](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ConfigAdminApplication-Run.png) +![ApolloApplication-Run](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ApolloApplication-Run.png) 启动完后,打开[http://localhost:8080](http://localhost:8080)可以看到`apollo-configservice`和`apollo-adminservice`都已经启动完成并注册到Eureka。 @@ -89,62 +86,23 @@ mysql 数据库初始化脚本见 本项目 scripts/sql/assembly/mysql 目录下 > ... > } -## 2.2 Apollo-Portal - -下面以Intellij Community 2016.2版本为例来说明如何在本地启动`apollo-portal`。 - -![PortalApplication-Overview](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/PortalApplication-Overview.png) - -### 2.2.1 新建运行配置 -![NewConfiguration-Application](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/NewConfiguration-Application.png) - -### 2.2.2 Main class配置 -`com.ctrip.framework.apollo.portal.PortalApplication` - -### 2.2.3 VM options配置 -![PortalApplication-VM-Options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/PortalApplication-VM-Options.png) - - -Dapollo_profile=github,auth - -Ddev_meta=http://localhost:8080/ - -Dserver.port=8070 - -Dspring.datasource.url=jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8 - -Dspring.datasource.username=root - -Dspring.datasource.password= - ->注1:这里指定了apollo_profile是`github`和`auth`,其中`github`是Apollo必须的一个profile,用于数据库的配置,`auth`是从0.9.0新增的,用来支持使用apollo提供的Spring Security简单认证,更多信息可以参考[Portal-实现用户登录功能](zh/development/portal-how-to-implement-user-login-function) -> ->注2:spring.datasource相关配置替换成你自己的数据库连接信息,注意数据库是`ApolloPortalDB `。 -> ->注3:默认ApolloPortalDB中导入的配置只会展示DEV环境的配置,所以这里配置了dev\_meta属性,如果你希望在本地展示其它环境的配置,需要在这里增加其它环境的meta服务器地址,如fat\_meta。 -> ->注4:这里指定了server.port=8070是因为`apollo-configservice`启动在8080端口,所以这里配置`apollo-portal`启动在8070端口。 -> ->注5:程序默认日志输出为/opt/logs/100003173/apollo-portal.log,如果需要修改日志文件路径,可以增加`logging.file.name`参数,如下: -> ->-Dlogging.file.name=/your-path/apollo-portal.log - -### 2.2.4 运行 -对新建的运行配置点击Run或Debug皆可。 - -![PortalApplication-Run](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/PortalApplication-Run.png) - 启动完后,打开[http://localhost:8070](http://localhost:8070)就可以看到Apollo配置中心界面了。 ![PortalApplication-Home](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/PortalApplication-Home.png) >注:如果启用了`auth` profile的话,默认的用户名是apollo,密码是admin -### 2.2.5 Demo应用接入 +### 2.1.5 Demo应用接入 为了更好的开发和调试,一般我们都会自己创建一个demo项目给自己使用。 可以参考[一、普通应用接入指南](zh/usage/apollo-user-guide#一、普通应用接入指南)创建自己的demo项目。 -## 2.3 Java样例客户端启动 +## 2.2 Java样例客户端启动 仓库中有一个样例客户端的项目:[apollo-demo-java](https://github.com/apolloconfig/apollo-demo-java),下面以Intellij为例来说明如何在本地启动。 -### 2.3.1 配置项目AppId +### 2.2.1 配置项目AppId 在`2.2.5 Demo应用接入`中创建Demo项目时,系统会要求填入一个全局唯一的AppId,我们需要把这个AppId配置到`apollo-demo`项目的app.properties文件中:`apollo-demo-java/api-demo/src/main/resources/META-INF/app.properties`。 ![apollo-demo-app-properties](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/apollo-demo-app-properties.jpg) @@ -159,13 +117,13 @@ mysql 数据库初始化脚本见 本项目 scripts/sql/assembly/mysql 目录下 > 更多配置AppId的方式可以参考[1.2.1 AppId](zh/usage/java-sdk-user-guide#_121-appid) -### 2.3.2 新建运行配置 +### 2.2.2 新建运行配置 ![NewConfiguration-Application](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/NewConfiguration-Application.png) -### 2.3.3 Main class配置 +### 2.2.3 Main class配置 `com.apolloconfig.apollo.demo.api.SimpleApolloConfigDemo` -### 2.3.4 VM options配置 +### 2.2.4 VM options配置 ![apollo-demo-vm-options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/apollo-demo-vm-options.jpg) -Dapollo.meta=http://localhost:8080 @@ -174,11 +132,11 @@ mysql 数据库初始化脚本见 本项目 scripts/sql/assembly/mysql 目录下 > 更多配置Apollo Meta Server的方式可以参考[1.2.2 Apollo Meta Server](zh/usage/java-sdk-user-guide#_122-apollo-meta-server) -### 2.3.5 概览 +### 2.2.5 概览 ![apollo-demo-overview](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/apollo-demo-overview.jpg) -### 2.3.6 运行 +### 2.2.6 运行 对新建的运行配置点击Run或Debug皆可。 ![apollo-demo-run](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/apollo-demo-run.png) @@ -200,11 +158,11 @@ mysql 数据库初始化脚本见 本项目 scripts/sql/assembly/mysql 目录下 > > ``` -## 2.4 .Net样例客户端启动 +## 2.3 .Net样例客户端启动 [apollo.net](https://github.com/ctripcorp/apollo.net)项目中有一个样例客户端的项目:`ApolloDemo`,下面就以VS 2010为例来说明如何在本地启动。 -### 2.4.1 配置项目AppId +### 2.3.1 配置项目AppId 在`2.2.5 Demo应用接入`中创建Demo项目时,系统会要求填入一个全局唯一的AppId,我们需要把这个AppId配置到`ApolloDemo`项目的APP.config文件中:`apollo.net\ApolloDemo\App.config`。 ![apollo-demo-app-config](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/apollo-net-app-config.png) @@ -218,12 +176,12 @@ mysql 数据库初始化脚本见 本项目 scripts/sql/assembly/mysql 目录下 > 对于公共Namespace的配置,没有AppId也可以获取到配置,但是就失去了应用覆盖公共Namespace配置的能力。 -### 2.4.2 配置服务地址 +### 2.3.2 配置服务地址 Apollo客户端针对不同的环境会从不同的服务器获取配置,所以我们需要在app.config或web.config配置服务器地址(Apollo.{ENV}.Meta)。假设DEV环境的配置服务(apollo-configservice)地址是11.22.33.44,那么我们就做如下配置: ![apollo-net-server-url-config](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/apollo-net-server-url-config.png) -### 2.4.3 运行 +### 2.3.3 运行 运行`ApolloConfigDemo.cs`即可。 启动完后,忽略前面的调试信息,可以看到如下提示: From 1fe8c2752c0a737c28077c16377bd83f57b893da Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 5 Jan 2024 22:53:35 +0800 Subject: [PATCH 28/59] autoGeneratedDeclaration --- .../maven/extensions/sql/ApolloSqlConverterTest.java | 12 ++++++------ scripts/sql-gist/autoGeneratedDeclaration.sql | 5 +++-- scripts/sql/apolloconfigdb.sql | 10 ++++++---- scripts/sql/apolloportaldb.sql | 10 ++++++---- scripts/sql/assembly/h2/apolloconfigdb.sql | 10 ++++++---- scripts/sql/assembly/h2/apolloportaldb.sql | 10 ++++++---- .../h2/delta/v220-v230/apolloconfigdb-v220-v230.sql | 10 ++++++---- .../h2/delta/v220-v230/apolloportaldb-v220-v230.sql | 10 ++++++---- .../mysql-database-not-specified/apolloconfigdb.sql | 10 ++++++---- .../mysql-database-not-specified/apolloportaldb.sql | 10 ++++++---- .../delta/v220-v230/apolloconfigdb-v220-v230.sql | 10 ++++++---- .../delta/v220-v230/apolloportaldb-v220-v230.sql | 10 ++++++---- scripts/sql/assembly/mysql/apolloconfigdb.sql | 10 ++++++---- scripts/sql/assembly/mysql/apolloportaldb.sql | 10 ++++++---- .../delta/v220-v230/apolloconfigdb-v220-v230.sql | 10 ++++++---- .../delta/v220-v230/apolloportaldb-v220-v230.sql | 10 ++++++---- .../sql/delta/v220-v230/apolloconfigdb-v220-v230.sql | 10 ++++++---- .../sql/delta/v220-v230/apolloportaldb-v220-v230.sql | 10 ++++++---- 18 files changed, 105 insertions(+), 72 deletions(-) diff --git a/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java b/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java index 54c959b2c63..55597cfc014 100644 --- a/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java +++ b/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java @@ -33,6 +33,8 @@ class ApolloSqlConverterTest { + private static final String GENERATE_TIPS = "mvn compile -pl apollo-build-maven-extensions -Psql-convert"; + @Test void checkSql() { String repositoryDir = ApolloSqlConverterUtil.getRepositoryDir(); @@ -79,13 +81,14 @@ private void checkMainMysqlList(List srcSqlList, String srcDir, List redundantSqlList = this.findRedundantSqlList(checkerTargetDir, checkerSqlList, repositoryTargetDir, repositorySqlList); Assertions.assertEquals(0, redundantSqlList.size(), - "redundant sql files, please add sql files in 'scripts/sql-src' and then run 'mvn compile -Psql-convert' to generated. Do not edit 'scripts/sql' manually !!!\npath: " + "redundant sql files, please add sql files in 'scripts/sql-src' and then run '" + + GENERATE_TIPS + "' to generated. Do not edit 'scripts/sql' manually !!!\npath: " + redundantSqlList); List missingSqlList = this.findMissingSqlList(checkerTargetDir, checkerSqlList, repositoryTargetDir, repositorySqlList); Assertions.assertEquals(0, missingSqlList.size(), - "missing sql files, please run 'mvn compile -Psql-convert' to regenerated\npath: " + "missing sql files, please run '" + GENERATE_TIPS + "' to regenerated\npath: " + missingSqlList); for (String srcSql : srcSqlList) { @@ -164,15 +167,12 @@ private void doCheck(String checkerTargetSql, String repositoryTargetSql) { throw new UncheckedIOException(e); } - Assertions.assertEquals(checkerLines.size(), repositoryLines.size(), - "invalid sql files, please run 'mvn compile -Psql-convert' to regenerated\npath: " - + repositoryTargetSql); for (int i = 0; i < checkerLines.size(); i++) { String checkerLine = checkerLines.get(i); String repositoryLine = repositoryLines.get(i); int lineNumber = i + 1; Assertions.assertEquals(checkerLine, repositoryLine, - "invalid sql file content, please run 'mvn compile -Psql-convert' to regenerated\npath: " + "invalid sql file content, please run '" + GENERATE_TIPS + "' to regenerated\npath: " + repositoryTargetSql + "(line: " + lineNumber + ")"); } } diff --git a/scripts/sql-gist/autoGeneratedDeclaration.sql b/scripts/sql-gist/autoGeneratedDeclaration.sql index bf8d7981dd3..981ce72231c 100644 --- a/scripts/sql-gist/autoGeneratedDeclaration.sql +++ b/scripts/sql-gist/autoGeneratedDeclaration.sql @@ -16,8 +16,9 @@ -- @@gist-start@@ -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@gist-end@@ diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index fb130164afd..bcb52abea3a 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -24,8 +24,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -504,8 +505,9 @@ VALUES -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/apolloportaldb.sql b/scripts/sql/apolloportaldb.sql index 136db190ffd..94f1d662c02 100644 --- a/scripts/sql/apolloportaldb.sql +++ b/scripts/sql/apolloportaldb.sql @@ -24,8 +24,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -448,8 +449,9 @@ INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/h2/apolloconfigdb.sql b/scripts/sql/assembly/h2/apolloconfigdb.sql index 5bc1d8202a8..0e13b5499e7 100644 --- a/scripts/sql/assembly/h2/apolloconfigdb.sql +++ b/scripts/sql/assembly/h2/apolloconfigdb.sql @@ -24,8 +24,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -504,8 +505,9 @@ VALUES -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/h2/apolloportaldb.sql b/scripts/sql/assembly/h2/apolloportaldb.sql index 28e19cf73c2..304cedfc51d 100644 --- a/scripts/sql/assembly/h2/apolloportaldb.sql +++ b/scripts/sql/assembly/h2/apolloportaldb.sql @@ -24,8 +24,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -448,8 +449,9 @@ INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql index b9f51044ab9..75efa69a482 100644 --- a/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -18,8 +18,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -34,7 +35,8 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql index 0bb35b97faf..57ac0e953b6 100644 --- a/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -18,8 +18,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -34,7 +35,8 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql-database-not-specified/apolloconfigdb.sql b/scripts/sql/assembly/mysql-database-not-specified/apolloconfigdb.sql index 28b4b682e74..2f338f8cc15 100644 --- a/scripts/sql/assembly/mysql-database-not-specified/apolloconfigdb.sql +++ b/scripts/sql/assembly/mysql-database-not-specified/apolloconfigdb.sql @@ -24,8 +24,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -499,8 +500,9 @@ VALUES -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql-database-not-specified/apolloportaldb.sql b/scripts/sql/assembly/mysql-database-not-specified/apolloportaldb.sql index 136a88f7f2a..32532fff4fa 100644 --- a/scripts/sql/assembly/mysql-database-not-specified/apolloportaldb.sql +++ b/scripts/sql/assembly/mysql-database-not-specified/apolloportaldb.sql @@ -24,8 +24,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -443,8 +444,9 @@ INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql index 057e8ba5d10..eaea2e9c27c 100644 --- a/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -18,8 +18,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -29,7 +30,8 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql index 671321ac521..e004adecca7 100644 --- a/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -18,8 +18,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -29,7 +30,8 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql/apolloconfigdb.sql b/scripts/sql/assembly/mysql/apolloconfigdb.sql index de75aba3b85..bc7b8a877f3 100644 --- a/scripts/sql/assembly/mysql/apolloconfigdb.sql +++ b/scripts/sql/assembly/mysql/apolloconfigdb.sql @@ -24,8 +24,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -504,8 +505,9 @@ VALUES -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql/apolloportaldb.sql b/scripts/sql/assembly/mysql/apolloportaldb.sql index 9f69a185f13..089fe62549b 100644 --- a/scripts/sql/assembly/mysql/apolloportaldb.sql +++ b/scripts/sql/assembly/mysql/apolloportaldb.sql @@ -24,8 +24,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -448,8 +449,9 @@ INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql index 2490163bf73..7f31c5bffba 100644 --- a/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -18,8 +18,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -31,7 +32,8 @@ Use ApolloAssemblyDB; -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql index ca2c092f2ce..c3485c28935 100644 --- a/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -18,8 +18,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -31,7 +32,8 @@ Use ApolloAssemblyDB; -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql index 87f1b1e2dee..1524ac41955 100644 --- a/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -18,8 +18,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -31,7 +32,8 @@ Use ApolloConfigDB; -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql index 4cfdefd0ba9..d930298148d 100644 --- a/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -18,8 +18,9 @@ -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== -- @@ -31,7 +32,8 @@ Use ApolloPortalDB; -- -- =============================================================================== -- == == --- == Generated from 'scripts/sql-src/' by running 'mvn compile -Psql-convert'. == --- == DO NOT EDIT !!! == +-- == Generated from 'scripts/sql-src/' == +-- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == DO NOT EDIT !!! == -- == == -- =============================================================================== From cc438b8113854be81fa71c6719b7f63725c67fb9 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 5 Jan 2024 23:06:40 +0800 Subject: [PATCH 29/59] rename sql-converter module --- .../pom.xml | 13 +++++-------- .../converter}/ApolloAssemblyH2ConverterUtil.java | 2 +- .../ApolloAssemblyMysqlConverterUtil.java | 3 +-- .../converter}/ApolloMainMysqlConverterUtil.java | 5 ++--- .../build/sql/converter}/ApolloSqlConverter.java | 2 +- .../sql/converter}/ApolloSqlConverterUtil.java | 8 +++----- .../apollo/build/sql/converter}/SqlTemplate.java | 2 +- .../build/sql/converter}/SqlTemplateContext.java | 4 +--- .../build/sql/converter}/SqlTemplateGist.java | 4 +--- .../sql/converter}/ApolloSqlConverterTest.java | 8 +++++--- pom.xml | 2 +- scripts/sql-gist/autoGeneratedDeclaration.sql | 2 +- scripts/sql/apolloconfigdb.sql | 4 ++-- scripts/sql/apolloportaldb.sql | 4 ++-- scripts/sql/assembly/h2/apolloconfigdb.sql | 4 ++-- scripts/sql/assembly/h2/apolloportaldb.sql | 4 ++-- .../h2/delta/v220-v230/apolloconfigdb-v220-v230.sql | 4 ++-- .../h2/delta/v220-v230/apolloportaldb-v220-v230.sql | 4 ++-- .../mysql-database-not-specified/apolloconfigdb.sql | 4 ++-- .../mysql-database-not-specified/apolloportaldb.sql | 4 ++-- .../delta/v220-v230/apolloconfigdb-v220-v230.sql | 4 ++-- .../delta/v220-v230/apolloportaldb-v220-v230.sql | 4 ++-- scripts/sql/assembly/mysql/apolloconfigdb.sql | 4 ++-- scripts/sql/assembly/mysql/apolloportaldb.sql | 4 ++-- .../delta/v220-v230/apolloconfigdb-v220-v230.sql | 4 ++-- .../delta/v220-v230/apolloportaldb-v220-v230.sql | 4 ++-- .../delta/v220-v230/apolloconfigdb-v220-v230.sql | 4 ++-- .../delta/v220-v230/apolloportaldb-v220-v230.sql | 4 ++-- 28 files changed, 55 insertions(+), 64 deletions(-) rename {apollo-build-maven-extensions => apollo-build-sql-converter}/pom.xml (84%) rename {apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql => apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter}/ApolloAssemblyH2ConverterUtil.java (98%) rename {apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql => apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter}/ApolloAssemblyMysqlConverterUtil.java (96%) rename {apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql => apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter}/ApolloMainMysqlConverterUtil.java (93%) rename {apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql => apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter}/ApolloSqlConverter.java (99%) rename {apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql => apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter}/ApolloSqlConverterUtil.java (96%) rename {apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql => apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter}/SqlTemplate.java (94%) rename {apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql => apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter}/SqlTemplateContext.java (93%) rename {apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql => apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter}/SqlTemplateGist.java (96%) rename {apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql => apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter}/ApolloSqlConverterTest.java (96%) diff --git a/apollo-build-maven-extensions/pom.xml b/apollo-build-sql-converter/pom.xml similarity index 84% rename from apollo-build-maven-extensions/pom.xml rename to apollo-build-sql-converter/pom.xml index 3a5d5dd90c0..d5734be256c 100644 --- a/apollo-build-maven-extensions/pom.xml +++ b/apollo-build-sql-converter/pom.xml @@ -24,8 +24,8 @@ ../pom.xml 4.0.0 - apollo-build-maven-extensions - Apollo Build Maven Extensions + apollo-build-sql-converter + Apollo Build Sql Converter @@ -36,7 +36,7 @@ - sql-convert + sql-converter false @@ -52,7 +52,7 @@ 3.0.0 - sql-convert + sql-converter compile java @@ -60,10 +60,7 @@ - com.ctrip.framework.apollo.maven.extensions.sql.ApolloSqlConverter - - ${project.basedir} - + com.ctrip.framework.apollo.build.sql.converter.ApolloSqlConverter diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyH2ConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloAssemblyH2ConverterUtil.java similarity index 98% rename from apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyH2ConverterUtil.java rename to apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloAssemblyH2ConverterUtil.java index 9467d842bb0..7714ce98750 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyH2ConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloAssemblyH2ConverterUtil.java @@ -14,7 +14,7 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.maven.extensions.sql; +package com.ctrip.framework.apollo.build.sql.converter; import java.io.BufferedReader; import java.io.BufferedWriter; diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyMysqlConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloAssemblyMysqlConverterUtil.java similarity index 96% rename from apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyMysqlConverterUtil.java rename to apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloAssemblyMysqlConverterUtil.java index 728c24299a5..78ef2101b21 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloAssemblyMysqlConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloAssemblyMysqlConverterUtil.java @@ -14,7 +14,7 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.maven.extensions.sql; +package com.ctrip.framework.apollo.build.sql.converter; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -25,7 +25,6 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; -import java.util.Map; public class ApolloAssemblyMysqlConverterUtil { diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloMainMysqlConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloMainMysqlConverterUtil.java similarity index 93% rename from apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloMainMysqlConverterUtil.java rename to apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloMainMysqlConverterUtil.java index 1e1d5844a99..b993911f432 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloMainMysqlConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloMainMysqlConverterUtil.java @@ -14,7 +14,7 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.maven.extensions.sql; +package com.ctrip.framework.apollo.build.sql.converter; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -63,8 +63,7 @@ private static String convertMainMysqlLine(String line, String databaseName) { convertedLine = convertedLine.replace("P_0_", ""); - convertedLine = convertedLine.replace("C_0_", "") - .replace("ApolloAssemblyDB", databaseName); + convertedLine = convertedLine.replace("C_0_", ""); convertedLine = convertedLine.replace("ApolloAssemblyDB", databaseName); diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverter.java similarity index 99% rename from apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java rename to apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverter.java index 0bebc4dbc90..b74f004f2c6 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverter.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverter.java @@ -14,7 +14,7 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.maven.extensions.sql; +package com.ctrip.framework.apollo.build.sql.converter; import freemarker.template.Configuration; import java.io.File; diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterUtil.java similarity index 96% rename from apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterUtil.java rename to apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterUtil.java index 537ea62fac8..80e7c1350cd 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterUtil.java @@ -14,7 +14,7 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.maven.extensions.sql; +package com.ctrip.framework.apollo.build.sql.converter; import freemarker.template.Configuration; import freemarker.template.Template; @@ -34,9 +34,7 @@ import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.StringJoiner; @@ -56,12 +54,12 @@ public static String getRepositoryDir() { Path path = Paths.get(uri); String unixClassPath = path.toString().replace("\\", "/"); - if (!unixClassPath.endsWith("/apollo-build-maven-extensions/target/classes")) { + if (!unixClassPath.endsWith("/apollo-build-sql-converter/target/classes")) { throw new IllegalStateException("illegal class path: " + unixClassPath); } return ApolloSqlConverterUtil.replacePath(unixClassPath, - "/apollo-build-maven-extensions/target/classes", ""); + "/apollo-build-sql-converter/target/classes", ""); } public static void ensureDirectories(String targetFilePath) { diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplate.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlTemplate.java similarity index 94% rename from apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplate.java rename to apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlTemplate.java index 4222a46374b..12ecc28c81b 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplate.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlTemplate.java @@ -14,7 +14,7 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.maven.extensions.sql; +package com.ctrip.framework.apollo.build.sql.converter; import freemarker.template.Template; diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateContext.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlTemplateContext.java similarity index 93% rename from apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateContext.java rename to apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlTemplateContext.java index 8131f72ab78..c2f8fb0690b 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateContext.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlTemplateContext.java @@ -14,10 +14,8 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.maven.extensions.sql; +package com.ctrip.framework.apollo.build.sql.converter; -import java.util.Collections; -import java.util.Map; import java.util.StringJoiner; public class SqlTemplateContext { diff --git a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateGist.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlTemplateGist.java similarity index 96% rename from apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateGist.java rename to apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlTemplateGist.java index ff52bc62bc2..ad26ec9f828 100644 --- a/apollo-build-maven-extensions/src/main/java/com/ctrip/framework/apollo/maven/extensions/sql/SqlTemplateGist.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlTemplateGist.java @@ -14,10 +14,8 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.maven.extensions.sql; +package com.ctrip.framework.apollo.build.sql.converter; -import java.util.Collections; -import java.util.Map; import java.util.StringJoiner; public class SqlTemplateGist { diff --git a/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java similarity index 96% rename from apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java rename to apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java index 55597cfc014..017389dd003 100644 --- a/apollo-build-maven-extensions/src/test/java/com/ctrip/framework/apollo/maven/extensions/sql/ApolloSqlConverterTest.java +++ b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java @@ -14,8 +14,10 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.maven.extensions.sql; +package com.ctrip.framework.apollo.build.sql.converter; +import com.ctrip.framework.apollo.build.sql.converter.ApolloSqlConverter; +import com.ctrip.framework.apollo.build.sql.converter.ApolloSqlConverterUtil; import java.io.BufferedReader; import java.io.IOException; import java.io.UncheckedIOException; @@ -33,14 +35,14 @@ class ApolloSqlConverterTest { - private static final String GENERATE_TIPS = "mvn compile -pl apollo-build-maven-extensions -Psql-convert"; + private static final String GENERATE_TIPS = "mvn compile -pl apollo-build-sql-converter -Psql-converter"; @Test void checkSql() { String repositoryDir = ApolloSqlConverterUtil.getRepositoryDir(); String srcDir = repositoryDir + "/scripts/sql-src"; - String checkerParentDir = repositoryDir + "/apollo-build-maven-extensions/target/scripts"; + String checkerParentDir = repositoryDir + "/apollo-build-sql-converter/target/scripts"; String repositoryParentDir = repositoryDir + "/scripts"; // generate checker sql files diff --git a/pom.xml b/pom.xml index fa3ad3a63eb..08437ef0d06 100644 --- a/pom.xml +++ b/pom.xml @@ -95,7 +95,7 @@ - apollo-build-maven-extensions + apollo-build-sql-converter apollo-buildtools apollo-common apollo-biz diff --git a/scripts/sql-gist/autoGeneratedDeclaration.sql b/scripts/sql-gist/autoGeneratedDeclaration.sql index 981ce72231c..461a5d93e41 100644 --- a/scripts/sql-gist/autoGeneratedDeclaration.sql +++ b/scripts/sql-gist/autoGeneratedDeclaration.sql @@ -17,7 +17,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/apolloconfigdb.sql b/scripts/sql/apolloconfigdb.sql index bcb52abea3a..1fc42dc7e35 100644 --- a/scripts/sql/apolloconfigdb.sql +++ b/scripts/sql/apolloconfigdb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -506,7 +506,7 @@ VALUES -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/apolloportaldb.sql b/scripts/sql/apolloportaldb.sql index 94f1d662c02..238638ac898 100644 --- a/scripts/sql/apolloportaldb.sql +++ b/scripts/sql/apolloportaldb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -450,7 +450,7 @@ INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/h2/apolloconfigdb.sql b/scripts/sql/assembly/h2/apolloconfigdb.sql index 0e13b5499e7..4d221c29cdb 100644 --- a/scripts/sql/assembly/h2/apolloconfigdb.sql +++ b/scripts/sql/assembly/h2/apolloconfigdb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -506,7 +506,7 @@ VALUES -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/h2/apolloportaldb.sql b/scripts/sql/assembly/h2/apolloportaldb.sql index 304cedfc51d..1b955ee27cd 100644 --- a/scripts/sql/assembly/h2/apolloportaldb.sql +++ b/scripts/sql/assembly/h2/apolloportaldb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -450,7 +450,7 @@ INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql index 75efa69a482..aebba82d2c1 100644 --- a/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/assembly/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -36,7 +36,7 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql index 57ac0e953b6..1e1bf835305 100644 --- a/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/assembly/h2/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -36,7 +36,7 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql-database-not-specified/apolloconfigdb.sql b/scripts/sql/assembly/mysql-database-not-specified/apolloconfigdb.sql index 2f338f8cc15..cac0a87951b 100644 --- a/scripts/sql/assembly/mysql-database-not-specified/apolloconfigdb.sql +++ b/scripts/sql/assembly/mysql-database-not-specified/apolloconfigdb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -501,7 +501,7 @@ VALUES -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql-database-not-specified/apolloportaldb.sql b/scripts/sql/assembly/mysql-database-not-specified/apolloportaldb.sql index 32532fff4fa..dcc8025ccd1 100644 --- a/scripts/sql/assembly/mysql-database-not-specified/apolloportaldb.sql +++ b/scripts/sql/assembly/mysql-database-not-specified/apolloportaldb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -445,7 +445,7 @@ INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql index eaea2e9c27c..d3ad8e919f2 100644 --- a/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -31,7 +31,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql index e004adecca7..9cfb0f71593 100644 --- a/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/assembly/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -31,7 +31,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql/apolloconfigdb.sql b/scripts/sql/assembly/mysql/apolloconfigdb.sql index bc7b8a877f3..08c1d14c807 100644 --- a/scripts/sql/assembly/mysql/apolloconfigdb.sql +++ b/scripts/sql/assembly/mysql/apolloconfigdb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -506,7 +506,7 @@ VALUES -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql/apolloportaldb.sql b/scripts/sql/assembly/mysql/apolloportaldb.sql index 089fe62549b..747970a427d 100644 --- a/scripts/sql/assembly/mysql/apolloportaldb.sql +++ b/scripts/sql/assembly/mysql/apolloportaldb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -450,7 +450,7 @@ INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql index 7f31c5bffba..79d2f77bc87 100644 --- a/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -33,7 +33,7 @@ Use ApolloAssemblyDB; -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql index c3485c28935..3af87648fe5 100644 --- a/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -33,7 +33,7 @@ Use ApolloAssemblyDB; -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql index 1524ac41955..5dcb7736cbb 100644 --- a/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -33,7 +33,7 @@ Use ApolloConfigDB; -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql index d930298148d..7bf1ea8e67e 100644 --- a/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -33,7 +33,7 @@ Use ApolloPortalDB; -- =============================================================================== -- == == -- == Generated from 'scripts/sql-src/' == --- == by running 'mvn compile -pl apollo-build-maven-extensions -Psql-convert'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== From b485a2952535ada425975f17db14e2ed5fa3f055 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 5 Jan 2024 23:13:14 +0800 Subject: [PATCH 30/59] sql-converter h2 --- .../ApolloAssemblyH2ConverterUtil.java | 65 +++++++++++++++---- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloAssemblyH2ConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloAssemblyH2ConverterUtil.java index 7714ce98750..3b80e55ec79 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloAssemblyH2ConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloAssemblyH2ConverterUtil.java @@ -30,6 +30,12 @@ public class ApolloAssemblyH2ConverterUtil { + private static final Pattern TABLE_COMMENT_PATTERN = Pattern.compile("COMMENT='[^']*'"); + private static final Pattern INDEX_NAME_PATTERN = Pattern.compile("KEY *`[a-zA-Z0-9\\-_]+` *"); + private static final Pattern PREFIX_INDEX_PATTERN = Pattern.compile( + "(`[a-zA-Z0-9\\-_]+`)\\([0-9]+\\)"); + private static final Pattern COLUMN_COMMENT_PATTERN = Pattern.compile("COMMENT *'[^']*'"); + public static void convertAssemblyH2(SqlTemplate sqlTemplate, String targetSql, SqlTemplateContext context) { @@ -54,12 +60,24 @@ public static void convertAssemblyH2(SqlTemplate sqlTemplate, String targetSql, private static String convertAssemblyH2Line(String line) { String convertedLine = line; - // database config + + // remove drop table if (convertedLine.contains("DROP TABLE")) { return ""; } // table config + convertedLine = convertTableConfig(convertedLine); + + // index + convertedLine = convertIndex(convertedLine); + + // column + convertedLine = convertColumn(convertedLine); + return convertedLine; + } + + private static String convertTableConfig(String convertedLine) { if (convertedLine.contains("ENGINE=InnoDB")) { convertedLine = convertedLine.replace("ENGINE=InnoDB", ""); } @@ -69,39 +87,58 @@ private static String convertAssemblyH2Line(String line) { if (convertedLine.contains("ROW_FORMAT=DYNAMIC")) { convertedLine = convertedLine.replace("ROW_FORMAT=DYNAMIC", ""); } - Pattern tableCommentPattern = Pattern.compile("COMMENT='[^']*'"); - Matcher tableCommentMatcher = tableCommentPattern.matcher(convertedLine); + + // remove table comment + Matcher tableCommentMatcher = TABLE_COMMENT_PATTERN.matcher(convertedLine); if (tableCommentMatcher.find()) { convertedLine = tableCommentMatcher.replaceAll(""); } - // index + return convertedLine; + } + + private static String convertIndex(String convertedLine) { if (convertedLine.contains("KEY")) { - Pattern indexNamePattern = Pattern.compile("KEY *`[a-zA-Z0-9\\-_]+` *"); - Matcher indexNameMatcher = indexNamePattern.matcher(convertedLine); + // remove index name + // KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + // -> + // KEY (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + Matcher indexNameMatcher = INDEX_NAME_PATTERN.matcher(convertedLine); if (indexNameMatcher.find()) { convertedLine = indexNameMatcher.replaceAll("KEY "); } - Pattern indexPrefixPattern = Pattern.compile("(`[a-zA-Z0-9\\-_]+`)\\([0-9]+\\)"); - for (Matcher indexPrefixMatcher = indexPrefixPattern.matcher(convertedLine); - indexPrefixMatcher.find(); - indexPrefixMatcher = indexPrefixPattern.matcher(convertedLine)) { - convertedLine = indexPrefixMatcher.replaceAll("$1"); + + // convert prefix index + // KEY (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + // -> + // KEY (`AppId`,`ClusterName`,`NamespaceName`) + for (Matcher prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedLine); + prefixIndexMatcher.find(); + prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedLine)) { + convertedLine = prefixIndexMatcher.replaceAll("$1"); } } + return convertedLine; + } - // column config + private static String convertColumn(String convertedLine) { + // convert bit(1) to boolean + // `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal' + // -> + // `IsDeleted` boolean NOT NULL DEFAULT FALSE if (convertedLine.contains("bit(1)")) { convertedLine = convertedLine.replace("bit(1)", "boolean"); } if (convertedLine.contains("b'0'")) { convertedLine = convertedLine.replace("b'0'", "FALSE"); } - Pattern columnCommentPattern = Pattern.compile("COMMENT *'[^']*'"); - Matcher columnCommentMatcher = columnCommentPattern.matcher(convertedLine); + + // remove column comment + Matcher columnCommentMatcher = COLUMN_COMMENT_PATTERN.matcher(convertedLine); if (columnCommentMatcher.find()) { convertedLine = columnCommentMatcher.replaceAll(""); } + return convertedLine; } } From e2de6723befc1a31718b9c20d6c2f8a3b803dfc9 Mon Sep 17 00:00:00 2001 From: vdisk Date: Sat, 6 Jan 2024 01:34:28 +0800 Subject: [PATCH 31/59] fix database-discovery --- .../apollo/assembly/ApolloApplication.java | 2 ++ .../application-database-discovery.properties | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 apollo-assembly/src/main/resources/application-database-discovery.properties diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java index 93ab3efcbf2..432e1fdcbab 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.context.scope.refresh.RefreshScope; @@ -36,6 +37,7 @@ ApolloAssemblySqlInitializationConfig.class, }) @SpringBootApplication(exclude = { + DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class, ApolloAuditAutoConfiguration.class, }) diff --git a/apollo-assembly/src/main/resources/application-database-discovery.properties b/apollo-assembly/src/main/resources/application-database-discovery.properties new file mode 100644 index 00000000000..0be74a71835 --- /dev/null +++ b/apollo-assembly/src/main/resources/application-database-discovery.properties @@ -0,0 +1,26 @@ +# +# Copyright 2023 Apollo Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +apollo.eureka.server.enabled=false +eureka.client.enabled=false +spring.cloud.discovery.enabled=false + +apollo.service.registry.enabled=true +apollo.service.registry.cluster=default +apollo.service.registry.heartbeatIntervalInSecond=10 + +apollo.service.discovery.enabled=true +# health check by heartbeat, heartbeat time before 61s ago will be seemed as unhealthy +apollo.service.discovery.healthCheckIntervalInSecond = 61 From 001119f18e5ae59e84f02cd099244b1c2df7914c Mon Sep 17 00:00:00 2001 From: vdisk Date: Mon, 8 Jan 2024 11:04:16 +0800 Subject: [PATCH 32/59] mv sql --- ...AdminServiceAssemblyAutoConfiguration.java | 2 +- ...lyDataSourceScriptDatabaseInitializer.java | 2 +- ...ApolloAssemblySqlInitializationConfig.java | 2 +- .../application-database-discovery.properties | 2 +- .../resources/application-github.properties | 2 +- apollo-build-sql-converter/pom.xml | 2 +- .../ApolloAssemblyH2ConverterUtil.java | 2 +- .../ApolloAssemblyMysqlConverterUtil.java | 2 +- .../ApolloMainMysqlConverterUtil.java | 2 +- .../sql/converter/ApolloSqlConverter.java | 2 +- .../sql/converter/ApolloSqlConverterUtil.java | 2 +- .../build/sql/converter/SqlTemplate.java | 2 +- .../sql/converter/SqlTemplateContext.java | 2 +- .../build/sql/converter/SqlTemplateGist.java | 2 +- .../sql/converter/ApolloSqlConverterTest.java | 2 +- .../common/jpa/TablePrefixNamingStrategy.java | 2 +- .../common/jpa/TablePrefixProperties.java | 2 +- .../portal/PortalApplicationConfig.java | 2 +- .../src/main/resources/portal.properties | 2 +- scripts/sql/assembly/mysql/apolloconfigdb.sql | 519 ------------------ scripts/sql/assembly/mysql/apolloportaldb.sql | 463 ---------------- .../v220-v230/apolloconfigdb-v220-v230.sql | 39 -- .../v220-v230/apolloportaldb-v220-v230.sql | 39 -- .../h2/apolloconfigdb.sql | 2 +- .../h2/apolloportaldb.sql | 2 +- .../v220-v230/apolloconfigdb-v220-v230.sql | 2 +- .../v220-v230/apolloportaldb-v220-v230.sql | 2 +- .../apolloconfigdb.sql | 2 +- .../apolloportaldb.sql | 2 +- .../v220-v230/apolloconfigdb-v220-v230.sql | 2 +- .../v220-v230/apolloportaldb-v220-v230.sql | 2 +- .../mysql-default}/apolloconfigdb.sql | 0 .../mysql-default}/apolloportaldb.sql | 0 .../v040-v050/apolloconfigdb-v040-v050.sql | 0 .../v040-v050/apolloportaldb-v040-v050.sql | 0 .../v060-v062/apolloconfigdb-v060-v062.sql | 0 .../v060-v062/apolloportaldb-v060-v062.sql | 0 .../v080-v090/apolloportaldb-v080-v090.sql | 0 .../v151-v160/apolloconfigdb-v151-v160.sql | 0 .../v170-v180/apolloconfigdb-v170-v180.sql | 0 .../v170-v180/apolloportaldb-v170-v180.sql | 0 .../v180-v190/apolloconfigdb-v180-v190.sql | 0 .../v180-v190/apolloportaldb-v180-v190.sql | 0 .../apolloconfigdb-v190-v200-after.sql | 0 .../v190-v200/apolloconfigdb-v190-v200.sql | 0 .../apolloportaldb-v190-v200-after.sql | 0 .../v190-v200/apolloportaldb-v190-v200.sql | 0 .../v200-v210/apolloconfigdb-v200-v210.sql | 0 .../v210-v220/apolloconfigdb-v210-v220.sql | 0 .../v210-v220/apolloportaldb-v210-v220.sql | 0 .../v220-v230/apolloconfigdb-v220-v230.sql | 2 +- .../v220-v230/apolloportaldb-v220-v230.sql | 2 +- .../{sql-src => sql/src}/apolloconfigdb.sql | 2 +- .../{sql-src => sql/src}/apolloportaldb.sql | 2 +- .../v220-v230/apolloconfigdb-v220-v230.sql | 2 +- .../v220-v230/apolloportaldb-v220-v230.sql | 2 +- .../src/gist}/autoGeneratedDeclaration.sql | 2 +- .../{sql-gist => sql/src/gist}/h2Function.sql | 2 +- .../src/gist}/setupDatabase.sql | 2 +- .../src/gist}/useDatabase.sql | 2 +- 60 files changed, 37 insertions(+), 1097 deletions(-) delete mode 100644 scripts/sql/assembly/mysql/apolloconfigdb.sql delete mode 100644 scripts/sql/assembly/mysql/apolloportaldb.sql delete mode 100644 scripts/sql/assembly/mysql/delta/v220-v230/apolloconfigdb-v220-v230.sql delete mode 100644 scripts/sql/assembly/mysql/delta/v220-v230/apolloportaldb-v220-v230.sql rename scripts/sql/{assembly => profiles}/h2/apolloconfigdb.sql (99%) rename scripts/sql/{assembly => profiles}/h2/apolloportaldb.sql (99%) rename scripts/sql/{assembly => profiles}/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql (98%) rename scripts/sql/{assembly => profiles}/h2/delta/v220-v230/apolloportaldb-v220-v230.sql (98%) rename scripts/sql/{assembly => profiles}/mysql-database-not-specified/apolloconfigdb.sql (99%) rename scripts/sql/{assembly => profiles}/mysql-database-not-specified/apolloportaldb.sql (99%) rename scripts/sql/{assembly => profiles}/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql (98%) rename scripts/sql/{assembly => profiles}/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql (98%) rename scripts/sql/{ => profiles/mysql-default}/apolloconfigdb.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/apolloportaldb.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v040-v050/apolloconfigdb-v040-v050.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v040-v050/apolloportaldb-v040-v050.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v060-v062/apolloconfigdb-v060-v062.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v060-v062/apolloportaldb-v060-v062.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v080-v090/apolloportaldb-v080-v090.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v151-v160/apolloconfigdb-v151-v160.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v170-v180/apolloconfigdb-v170-v180.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v170-v180/apolloportaldb-v170-v180.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v180-v190/apolloconfigdb-v180-v190.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v180-v190/apolloportaldb-v180-v190.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v190-v200/apolloconfigdb-v190-v200-after.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v190-v200/apolloconfigdb-v190-v200.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v190-v200/apolloportaldb-v190-v200-after.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v190-v200/apolloportaldb-v190-v200.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v200-v210/apolloconfigdb-v200-v210.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v210-v220/apolloconfigdb-v210-v220.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v210-v220/apolloportaldb-v210-v220.sql (100%) rename scripts/sql/{ => profiles/mysql-default}/delta/v220-v230/apolloconfigdb-v220-v230.sql (98%) rename scripts/sql/{ => profiles/mysql-default}/delta/v220-v230/apolloportaldb-v220-v230.sql (98%) rename scripts/{sql-src => sql/src}/apolloconfigdb.sql (99%) rename scripts/{sql-src => sql/src}/apolloportaldb.sql (99%) rename scripts/{sql-src => sql/src}/delta/v220-v230/apolloconfigdb-v220-v230.sql (95%) rename scripts/{sql-src => sql/src}/delta/v220-v230/apolloportaldb-v220-v230.sql (95%) rename scripts/{sql-gist => sql/src/gist}/autoGeneratedDeclaration.sql (97%) rename scripts/{sql-gist => sql/src/gist}/h2Function.sql (95%) rename scripts/{sql-gist => sql/src/gist}/setupDatabase.sql (95%) rename scripts/{sql-gist => sql/src/gist}/useDatabase.sql (95%) diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyAutoConfiguration.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyAutoConfiguration.java index 174ff1d0fa1..ddd51a58341 100644 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyAutoConfiguration.java +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Apollo Authors + * Copyright 2024 Apollo Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java index 92c830d8306..60340988614 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Apollo Authors + * Copyright 2024 Apollo Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java index 5bbb618aa4f..1ac8d544710 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Apollo Authors + * Copyright 2024 Apollo Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/apollo-assembly/src/main/resources/application-database-discovery.properties b/apollo-assembly/src/main/resources/application-database-discovery.properties index 0be74a71835..dcdb6f1ab62 100644 --- a/apollo-assembly/src/main/resources/application-database-discovery.properties +++ b/apollo-assembly/src/main/resources/application-database-discovery.properties @@ -1,5 +1,5 @@ # -# Copyright 2023 Apollo Authors +# Copyright 2024 Apollo Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/apollo-assembly/src/main/resources/application-github.properties b/apollo-assembly/src/main/resources/application-github.properties index 09e56c85bb8..e985e33e2ad 100644 --- a/apollo-assembly/src/main/resources/application-github.properties +++ b/apollo-assembly/src/main/resources/application-github.properties @@ -1,5 +1,5 @@ # -# Copyright 2023 Apollo Authors +# Copyright 2024 Apollo Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/apollo-build-sql-converter/pom.xml b/apollo-build-sql-converter/pom.xml index d5734be256c..4490f8ce96e 100644 --- a/apollo-build-sql-converter/pom.xml +++ b/apollo-build-sql-converter/pom.xml @@ -1,6 +1,6 @@ + + @@ -41,4 +45,7 @@ + diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalApplicationConfig.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/ApolloBizAssemblyConfiguration.java similarity index 57% rename from apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalApplicationConfig.java rename to apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/ApolloBizAssemblyConfiguration.java index d9738892ea0..7b3fdf88e1d 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalApplicationConfig.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/ApolloBizAssemblyConfiguration.java @@ -14,19 +14,23 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.portal; +package com.ctrip.framework.apollo.biz; -import com.ctrip.framework.apollo.common.jpa.TablePrefixNamingStrategy; -import com.ctrip.framework.apollo.common.jpa.TablePrefixProperties; +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; +@Profile("assembly") @Configuration -public class PortalApplicationConfig { +public class ApolloBizAssemblyConfiguration { - @Bean - public static TablePrefixNamingStrategy tablePrefixNamingStrategy( - TablePrefixProperties tablePrefixProperties) { - return new TablePrefixNamingStrategy(tablePrefixProperties.getPortalPrefix()); - } + @Primary + @ConfigurationProperties(prefix = "spring.config-datasource") + @Bean + public static DataSourceProperties dataSourceProperties() { + return new DataSourceProperties(); + } } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/ApolloBizConfig.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/ApolloBizConfig.java index 65fc2e2d23f..54e936d2715 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/ApolloBizConfig.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/ApolloBizConfig.java @@ -16,10 +16,7 @@ */ package com.ctrip.framework.apollo.biz; -import com.ctrip.framework.apollo.common.jpa.TablePrefixNamingStrategy; -import com.ctrip.framework.apollo.common.jpa.TablePrefixProperties; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -28,8 +25,4 @@ @ComponentScan(basePackageClasses = ApolloBizConfig.class) public class ApolloBizConfig { - @Bean - public static TablePrefixNamingStrategy tablePrefixNamingStrategy(TablePrefixProperties tablePrefixProperties) { - return new TablePrefixNamingStrategy(tablePrefixProperties.getConfigPrefix()); - } } diff --git a/apollo-biz/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/apollo-biz/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java similarity index 80% rename from apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java rename to apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java index 60340988614..d678f7e8cb5 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblyDataSourceScriptDatabaseInitializer.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java @@ -14,9 +14,8 @@ * limitations under the License. * */ -package com.ctrip.framework.apollo.assembly.datasource; +package com.ctrip.framework.apollo.common.datasource; -import com.ctrip.framework.apollo.assembly.ApolloApplication; import java.net.URL; import java.security.CodeSource; import java.util.ArrayList; @@ -25,23 +24,41 @@ import javax.sql.DataSource; import org.springframework.boot.autoconfigure.sql.init.SqlDataSourceScriptDatabaseInitializer; import org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.DatabaseDriver; +import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; import org.springframework.boot.sql.init.DatabaseInitializationSettings; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.SimpleDriverDataSource; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -public class ApolloAssemblyDataSourceScriptDatabaseInitializer extends - SqlDataSourceScriptDatabaseInitializer { +public class ApolloDataSourceScriptDatabaseInitializer extends + DataSourceScriptDatabaseInitializer { - public ApolloAssemblyDataSourceScriptDatabaseInitializer(DataSource dataSource, - SqlInitializationProperties properties) { - super(dataSource, getSettings(dataSource, properties)); + public ApolloDataSourceScriptDatabaseInitializer(DataSource dataSource, + ApolloSqlInitializationProperties properties) { + super(determineDataSource(dataSource, properties), getSettings(dataSource, properties)); + } + + private static DataSource determineDataSource(DataSource dataSource, + ApolloSqlInitializationProperties properties) { + + String username = properties.getUsername(); + String password = properties.getPassword(); + if (StringUtils.hasText(username) && StringUtils.hasText(password)) { + return DataSourceBuilder.derivedFrom(dataSource) + .username(username) + .password(password) + .type(SimpleDriverDataSource.class) + .build(); + } + return dataSource; } public static DatabaseInitializationSettings getSettings(DataSource dataSource, - SqlInitializationProperties properties) { + ApolloSqlInitializationProperties properties) { PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver().withDriverPlatform( DatabaseDriver.MARIADB, "mysql"); @@ -66,7 +83,7 @@ public static DatabaseInitializationSettings getSettings(DataSource dataSource, private static List resolveLocations(Collection locations, PlatformPlaceholderDatabaseDriverResolver platformResolver, DataSource dataSource, - SqlInitializationProperties properties) { + ApolloSqlInitializationProperties properties) { if (CollectionUtils.isEmpty(locations)) { return null; @@ -114,7 +131,8 @@ private static String findSuffix(DataSource dataSource) { } private static String findRepositoryDirectory() { - CodeSource codeSource = ApolloApplication.class.getProtectionDomain().getCodeSource(); + CodeSource codeSource = ApolloDataSourceScriptDatabaseInitializer.class.getProtectionDomain() + .getCodeSource(); URL location = codeSource != null ? codeSource.getLocation() : null; if (location == null) { return null; diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloSqlInitializationProperties.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloSqlInitializationProperties.java new file mode 100644 index 00000000000..4ce80f4622b --- /dev/null +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloSqlInitializationProperties.java @@ -0,0 +1,142 @@ +/* + * Copyright 2024 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.common.datasource; + +import java.nio.charset.Charset; +import java.util.List; +import org.springframework.boot.sql.init.DatabaseInitializationMode; + +public class ApolloSqlInitializationProperties { + + /** + * Locations of the schema (DDL) scripts to apply to the database. + */ + private List schemaLocations; + + /** + * Locations of the data (DML) scripts to apply to the database. + */ + private List dataLocations; + + /** + * Platform to use in the default schema or data script locations, schema-${platform}.sql and + * data-${platform}.sql. + */ + private String platform = "all"; + + /** + * Username of the database to use when applying initialization scripts (if different). + */ + private String username; + + /** + * Password of the database to use when applying initialization scripts (if different). + */ + private String password; + + /** + * Whether initialization should continue when an error occurs. + */ + private boolean continueOnError = false; + + /** + * Statement separator in the schema and data scripts. + */ + private String separator = ";"; + + /** + * Encoding of the schema and data scripts. + */ + private Charset encoding; + + /** + * Mode to apply when determining whether initialization should be performed. + */ + private DatabaseInitializationMode mode = DatabaseInitializationMode.EMBEDDED; + + public List getSchemaLocations() { + return this.schemaLocations; + } + + public void setSchemaLocations(List schemaLocations) { + this.schemaLocations = schemaLocations; + } + + public List getDataLocations() { + return this.dataLocations; + } + + public void setDataLocations(List dataLocations) { + this.dataLocations = dataLocations; + } + + public String getPlatform() { + return this.platform; + } + + public void setPlatform(String platform) { + this.platform = platform; + } + + public String getUsername() { + return this.username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return this.password; + } + + public void setPassword(String password) { + this.password = password; + } + + public boolean isContinueOnError() { + return this.continueOnError; + } + + public void setContinueOnError(boolean continueOnError) { + this.continueOnError = continueOnError; + } + + public String getSeparator() { + return this.separator; + } + + public void setSeparator(String separator) { + this.separator = separator; + } + + public Charset getEncoding() { + return this.encoding; + } + + public void setEncoding(Charset encoding) { + this.encoding = encoding; + } + + public DatabaseInitializationMode getMode() { + return this.mode; + } + + public void setMode(DatabaseInitializationMode mode) { + this.mode = mode; + } +} diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAssemblyConfiguration.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAssemblyConfiguration.java new file mode 100644 index 00000000000..b4612aa0bb3 --- /dev/null +++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAssemblyConfiguration.java @@ -0,0 +1,43 @@ +/* + * Copyright 2024 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.configservice; + +import com.ctrip.framework.apollo.common.datasource.ApolloDataSourceScriptDatabaseInitializer; +import com.ctrip.framework.apollo.common.datasource.ApolloSqlInitializationProperties; +import javax.sql.DataSource; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Profile("assembly") +@Configuration +public class ConfigServiceAssemblyConfiguration { + + @ConfigurationProperties(prefix = "apollo.sql.config-init") + @Bean + public static ApolloSqlInitializationProperties apolloSqlInitializationProperties() { + return new ApolloSqlInitializationProperties(); + } + + @Bean + public static ApolloDataSourceScriptDatabaseInitializer apolloDataSourceScriptDatabaseInitializer( + DataSource dataSource, + ApolloSqlInitializationProperties properties) { + return new ApolloDataSourceScriptDatabaseInitializer(dataSource, properties); + } +} diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalAssemblyConfiguration.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalAssemblyConfiguration.java new file mode 100644 index 00000000000..94e9e619b0c --- /dev/null +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalAssemblyConfiguration.java @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.portal; + +import com.ctrip.framework.apollo.common.datasource.ApolloDataSourceScriptDatabaseInitializer; +import com.ctrip.framework.apollo.common.datasource.ApolloSqlInitializationProperties; +import javax.sql.DataSource; +import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.context.annotation.Profile; + +@Profile("assembly") +@Configuration +public class PortalAssemblyConfiguration { + + @Primary + @ConfigurationProperties(prefix = "spring.portal-datasource") + @Bean + public static DataSourceProperties dataSourceProperties() { + return new DataSourceProperties(); + } + + @ConfigurationProperties(prefix = "apollo.sql.portal-init") + @Bean + public static ApolloSqlInitializationProperties apolloSqlInitializationProperties() { + return new ApolloSqlInitializationProperties(); + } + + @Bean + public static ApolloDataSourceScriptDatabaseInitializer apolloDataSourceScriptDatabaseInitializer( + DataSource dataSource, + ApolloSqlInitializationProperties properties) { + return new ApolloDataSourceScriptDatabaseInitializer(dataSource, properties); + } +} From f3054892428ffdd60d9f95f55ecd53bd744ced7f Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 12 Jan 2024 22:03:18 +0800 Subject: [PATCH 36/59] remove table prefix --- .../apollo/assembly/ApolloApplication.java | 5 -- ...ApolloAssemblySqlInitializationConfig.java | 51 ------------------- .../resources/application-github.properties | 26 ++++++---- .../src/main/resources/logback.xml | 4 +- .../src/test/resources/application.properties | 23 ++++++--- ...ot.autoconfigure.AutoConfiguration.imports | 0 .../apollo/common/ApolloCommonConfig.java | 3 -- ...loDataSourceScriptDatabaseInitializer.java | 2 - .../common/jpa/TablePrefixNamingStrategy.java | 46 ----------------- .../common/jpa/TablePrefixProperties.java | 49 ------------------ .../ConfigServiceAssemblyConfiguration.java | 2 +- .../portal/PortalAssemblyConfiguration.java | 2 +- .../spi/configuration/AuthConfiguration.java | 28 +++++----- scripts/sql/profiles/h2/apolloconfigdb.sql | 44 ++++++++-------- scripts/sql/profiles/h2/apolloportaldb.sql | 48 ++++++++--------- .../v220-v230/apolloconfigdb-v220-v230.sql | 4 +- .../v220-v230/apolloportaldb-v220-v230.sql | 4 +- .../apolloconfigdb.sql | 4 +- .../apolloportaldb.sql | 4 +- .../v220-v230/apolloconfigdb-v220-v230.sql | 4 +- .../v220-v230/apolloportaldb-v220-v230.sql | 4 +- .../profiles/mysql-default/apolloconfigdb.sql | 4 +- .../profiles/mysql-default/apolloportaldb.sql | 4 +- .../v220-v230/apolloconfigdb-v220-v230.sql | 4 +- .../v220-v230/apolloportaldb-v220-v230.sql | 4 +- .../sql/src/gist/autoGeneratedDeclaration.sql | 2 +- 26 files changed, 113 insertions(+), 262 deletions(-) delete mode 100644 apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java delete mode 100644 apollo-biz/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports delete mode 100644 apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixNamingStrategy.java delete mode 100644 apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixProperties.java diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java index ee5cb564823..bdd6a1c1e51 100644 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java +++ b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/ApolloApplication.java @@ -17,7 +17,6 @@ package com.ctrip.framework.apollo.assembly; import com.ctrip.framework.apollo.adminservice.AdminServiceApplication; -import com.ctrip.framework.apollo.assembly.datasource.ApolloAssemblySqlInitializationConfig; import com.ctrip.framework.apollo.audit.configuration.ApolloAuditAutoConfiguration; import com.ctrip.framework.apollo.configservice.ConfigServiceApplication; import com.ctrip.framework.apollo.portal.PortalApplication; @@ -33,11 +32,7 @@ import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.context.scope.refresh.RefreshScope; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.annotation.Import; -@Import({ - ApolloAssemblySqlInitializationConfig.class, -}) @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, diff --git a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java b/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java deleted file mode 100644 index cf60bbee908..00000000000 --- a/apollo-assembly/src/main/java/com/ctrip/framework/apollo/assembly/datasource/ApolloAssemblySqlInitializationConfig.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2024 Apollo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.ctrip.framework.apollo.assembly.datasource; - -import javax.sql.DataSource; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.jdbc.DataSourceBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.jdbc.datasource.SimpleDriverDataSource; -import org.springframework.util.StringUtils; - -@EnableConfigurationProperties(SqlInitializationProperties.class) -@ConditionalOnProperty(prefix = "spring.sql.init", name = "enabled", matchIfMissing = true) -@Configuration -public class ApolloAssemblySqlInitializationConfig { -/* - @Bean - ApolloAssemblyDataSourceScriptDatabaseInitializer dataSourceScriptDatabaseInitializer(DataSource dataSource, - SqlInitializationProperties properties) { - return new ApolloAssemblyDataSourceScriptDatabaseInitializer( - determineDataSource(dataSource, properties.getUsername(), properties.getPassword()), properties); - } - - private static DataSource determineDataSource(DataSource dataSource, String username, String password) { - if (StringUtils.hasText(username) && StringUtils.hasText(password)) { - return DataSourceBuilder.derivedFrom(dataSource) - .username(username) - .password(password) - .type(SimpleDriverDataSource.class) - .build(); - } - return dataSource; - }*/ -} diff --git a/apollo-assembly/src/main/resources/application-github.properties b/apollo-assembly/src/main/resources/application-github.properties index 0ce8e1ecafb..fbdcfe0c70c 100644 --- a/apollo-assembly/src/main/resources/application-github.properties +++ b/apollo-assembly/src/main/resources/application-github.properties @@ -13,21 +13,25 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# DataSource -#spring.datasource.url=jdbc:h2:mem:~/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE -#spring.datasource.username= -#spring.datasource.password= +# Config DataSource +spring.config-datasource.url=jdbc:h2:mem:~/apollo-config-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE +#spring.config-datasource.username= +#spring.config-datasource.password= +spring.sql.config-init.schema-locations=@@repository@@/profiles/@@platform@@@@suffix@@/apolloconfigdb.sql +spring.sql.config-init.mode=embedded +# Portal DataSource +spring.portal-datasource.url=jdbc:h2:mem:~/apollo-portal-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE +#spring.portal-datasource.username= +#spring.portal-datasource.password= +spring.sql.portal-init.schema-locations=@@repository@@/profiles/@@platform@@@@suffix@@/apolloportaldb.sql +spring.sql.portal-init.mode=embedded -# Table prefix -#spring.jpa.hibernate.naming.physical-strategy=com.ctrip.framework.apollo.common.jpa.TablePrefixNamingStrategy -#spring.jpa.table-prefix.config-prefix=C_0_ -#spring.jpa.table-prefix.portal-prefix=P_0_ -#spring.session.jdbc.table-name=P_0_SPRING_SESSION +# Resolve Multi DataSource JMX name conflict +spring.jmx.unique-names=true # H2 datasource -#spring.sql.init.schema-locations=@@repository@@/profiles/@@platform@@@@suffix@@/apolloconfigdb.sql, @@repository@@/profiles/@@platform@@@@suffix@@/apolloportaldb.sql -#spring.sql.init.mode=embedded spring.jpa.hibernate.ddl-auto=none +spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl spring.jpa.properties.hibernate.show_sql=false spring.jpa.properties.hibernate.metadata_builder_contributor=com.ctrip.framework.apollo.common.jpa.SqlFunctionsMetadataBuilderContributor spring.h2.console.enabled=true diff --git a/apollo-assembly/src/main/resources/logback.xml b/apollo-assembly/src/main/resources/logback.xml index 8fe5a5232c3..cc4c4146525 100644 --- a/apollo-assembly/src/main/resources/logback.xml +++ b/apollo-assembly/src/main/resources/logback.xml @@ -45,7 +45,5 @@ - + diff --git a/apollo-assembly/src/test/resources/application.properties b/apollo-assembly/src/test/resources/application.properties index e982a313eb5..56c1e7ae868 100644 --- a/apollo-assembly/src/test/resources/application.properties +++ b/apollo-assembly/src/test/resources/application.properties @@ -13,16 +13,25 @@ # See the License for the specific language governing permissions and # limitations under the License. # -spring.datasource.url = jdbc:h2:mem:~/apolloconfigdb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE +# Config DataSource +spring.config-datasource.url=jdbc:h2:mem:~/apollo-config-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE +#spring.config-datasource.username= +#spring.config-datasource.password= +spring.sql.config-init.schema-locations=@@repository@@/profiles/@@platform@@@@suffix@@/apolloconfigdb.sql +spring.sql.config-init.mode=embedded +# Portal DataSource +spring.portal-datasource.url=jdbc:h2:mem:~/apollo-portal-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE +#spring.portal-datasource.username= +#spring.portal-datasource.password= +spring.sql.portal-init.schema-locations=@@repository@@/profiles/@@platform@@@@suffix@@/apolloportaldb.sql +spring.sql.portal-init.mode=embedded -# Table prefix -spring.jpa.hibernate.naming.physical-strategy=com.ctrip.framework.apollo.common.jpa.TablePrefixNamingStrategy -spring.jpa.table-prefix.config-prefix=C_0_ -spring.jpa.table-prefix.portal-prefix=P_0_ +# Resolve Multi DataSource JMX name conflict +spring.jmx.unique-names=true # H2 datasource -spring.sql.init.schema-locations=classpath:jpa/@@platform@@/apolloconfigdb.sql, classpath:jpa/@@platform@@/apolloportaldb.sql -spring.sql.init.mode=embedded +spring.jpa.hibernate.ddl-auto=none +spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl spring.jpa.properties.hibernate.show_sql=false spring.jpa.properties.hibernate.metadata_builder_contributor=com.ctrip.framework.apollo.common.jpa.SqlFunctionsMetadataBuilderContributor spring.h2.console.enabled=true diff --git a/apollo-biz/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/apollo-biz/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/ApolloCommonConfig.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/ApolloCommonConfig.java index 827ad6b5fd9..508488361bf 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/ApolloCommonConfig.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/ApolloCommonConfig.java @@ -16,9 +16,7 @@ */ package com.ctrip.framework.apollo.common; -import com.ctrip.framework.apollo.common.jpa.TablePrefixProperties; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -26,7 +24,6 @@ import org.springframework.security.web.firewall.HttpStatusRequestRejectedHandler; import org.springframework.security.web.firewall.RequestRejectedHandler; -@EnableConfigurationProperties(TablePrefixProperties.class) @EnableAutoConfiguration @Configuration @ComponentScan(basePackageClasses = ApolloCommonConfig.class) diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java index d678f7e8cb5..7efe1c8a1e3 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java @@ -22,8 +22,6 @@ import java.util.Collection; import java.util.List; import javax.sql.DataSource; -import org.springframework.boot.autoconfigure.sql.init.SqlDataSourceScriptDatabaseInitializer; -import org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties; import org.springframework.boot.jdbc.DataSourceBuilder; import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixNamingStrategy.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixNamingStrategy.java deleted file mode 100644 index 05ebbbf7b2d..00000000000 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixNamingStrategy.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2024 Apollo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.ctrip.framework.apollo.common.jpa; - -import org.apache.commons.lang3.StringUtils; -import org.hibernate.boot.model.naming.Identifier; -import org.hibernate.boot.model.naming.PhysicalNamingStrategy; -import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; - -public class TablePrefixNamingStrategy extends PhysicalNamingStrategyStandardImpl implements - PhysicalNamingStrategy { - - private static final long serialVersionUID = -5268252502936563292L; - - private final String tablePrefix; - - public TablePrefixNamingStrategy(String tablePrefix) { - this.tablePrefix = tablePrefix; - } - - @Override - public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) { - String tablePrefix = this.tablePrefix; - if (StringUtils.isEmpty(tablePrefix)) { - return name; - } - String entityTableName = name.getText(); - String physicalTableName = tablePrefix + entityTableName; - return new Identifier(physicalTableName, name.isQuoted()); - } -} diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixProperties.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixProperties.java deleted file mode 100644 index c854c8d0ea5..00000000000 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/jpa/TablePrefixProperties.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2024 Apollo Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package com.ctrip.framework.apollo.common.jpa; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix = "spring.jpa.table-prefix") -public class TablePrefixProperties { - - /** - * The table name prefix of config module - */ - private String configPrefix = ""; - - /** - * The table name prefix of portal module - */ - private String portalPrefix = ""; - - public String getConfigPrefix() { - return this.configPrefix; - } - - public void setConfigPrefix(String configPrefix) { - this.configPrefix = configPrefix; - } - - public String getPortalPrefix() { - return this.portalPrefix; - } - - public void setPortalPrefix(String portalPrefix) { - this.portalPrefix = portalPrefix; - } -} diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAssemblyConfiguration.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAssemblyConfiguration.java index b4612aa0bb3..6d38a0b9dc4 100644 --- a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAssemblyConfiguration.java +++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAssemblyConfiguration.java @@ -28,7 +28,7 @@ @Configuration public class ConfigServiceAssemblyConfiguration { - @ConfigurationProperties(prefix = "apollo.sql.config-init") + @ConfigurationProperties(prefix = "spring.sql.config-init") @Bean public static ApolloSqlInitializationProperties apolloSqlInitializationProperties() { return new ApolloSqlInitializationProperties(); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalAssemblyConfiguration.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalAssemblyConfiguration.java index 94e9e619b0c..1959b6df14c 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalAssemblyConfiguration.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalAssemblyConfiguration.java @@ -37,7 +37,7 @@ public static DataSourceProperties dataSourceProperties() { return new DataSourceProperties(); } - @ConfigurationProperties(prefix = "apollo.sql.portal-init") + @ConfigurationProperties(prefix = "spring.sql.portal-init") @Bean public static ApolloSqlInitializationProperties apolloSqlInitializationProperties() { return new ApolloSqlInitializationProperties(); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java index 9d5afc50888..9ba1f6eef06 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/spi/configuration/AuthConfiguration.java @@ -18,7 +18,6 @@ package com.ctrip.framework.apollo.portal.spi.configuration; import com.ctrip.framework.apollo.common.condition.ConditionalOnMissingProfile; -import com.ctrip.framework.apollo.common.jpa.TablePrefixProperties; import com.ctrip.framework.apollo.core.utils.StringUtils; import com.ctrip.framework.apollo.portal.repository.AuthorityRepository; import com.ctrip.framework.apollo.portal.repository.UserRepository; @@ -122,8 +121,7 @@ public static JdbcUserDetailsManager jdbcUserDetailsManager( PasswordEncoder passwordEncoder, AuthenticationManagerBuilder auth, DataSource datasource, - EntityManagerFactory entityManagerFactory, - TablePrefixProperties tablePrefixProperties) throws Exception { + EntityManagerFactory entityManagerFactory) throws Exception { char openQuote = '`'; char closeQuote = '`'; try { @@ -135,20 +133,19 @@ public static JdbcUserDetailsManager jdbcUserDetailsManager( } catch (Throwable ex) { //ignore } - String portalPrefix = tablePrefixProperties.getPortalPrefix(); JdbcUserDetailsManager jdbcUserDetailsManager = auth.jdbcAuthentication() .passwordEncoder(passwordEncoder).dataSource(datasource) - .usersByUsernameQuery(MessageFormat.format("SELECT {0}Username{1}, {0}Password{1}, {0}Enabled{1} FROM {0}{2}Users{1} WHERE {0}Username{1} = ?", openQuote, closeQuote, portalPrefix)) - .authoritiesByUsernameQuery(MessageFormat.format("SELECT {0}Username{1}, {0}Authority{1} FROM {0}{2}Authorities{1} WHERE {0}Username{1} = ?", openQuote, closeQuote, portalPrefix)) + .usersByUsernameQuery(MessageFormat.format("SELECT {0}Username{1}, {0}Password{1}, {0}Enabled{1} FROM {0}Users{1} WHERE {0}Username{1} = ?", openQuote, closeQuote)) + .authoritiesByUsernameQuery(MessageFormat.format("SELECT {0}Username{1}, {0}Authority{1} FROM {0}Authorities{1} WHERE {0}Username{1} = ?", openQuote, closeQuote)) .getUserDetailsService(); - jdbcUserDetailsManager.setUserExistsSql(MessageFormat.format("SELECT {0}Username{1} FROM {0}{2}Users{1} WHERE {0}Username{1} = ?", openQuote, closeQuote, portalPrefix)); - jdbcUserDetailsManager.setCreateUserSql(MessageFormat.format("INSERT INTO {0}{2}Users{1} ({0}Username{1}, {0}Password{1}, {0}Enabled{1}) values (?,?,?)", openQuote, closeQuote, portalPrefix)); - jdbcUserDetailsManager.setUpdateUserSql(MessageFormat.format("UPDATE {0}{2}Users{1} SET {0}Password{1} = ?, {0}Enabled{1} = ? WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}{2}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote, portalPrefix)); - jdbcUserDetailsManager.setDeleteUserSql(MessageFormat.format("DELETE FROM {0}{2}Users{1} WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}{2}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote, portalPrefix)); - jdbcUserDetailsManager.setCreateAuthoritySql(MessageFormat.format("INSERT INTO {0}{2}Authorities{1} ({0}Username{1}, {0}Authority{1}) values (?,?)", openQuote, closeQuote, portalPrefix)); - jdbcUserDetailsManager.setDeleteUserAuthoritiesSql(MessageFormat.format("DELETE FROM {0}{2}Authorities{1} WHERE {0}Id{1} in (SELECT a.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}{2}Authorities{1} WHERE {0}Username{1} = ?) AS a)", openQuote, closeQuote, portalPrefix)); - jdbcUserDetailsManager.setChangePasswordSql(MessageFormat.format("UPDATE {0}{2}Users{1} SET {0}Password{1} = ? WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}{2}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote, portalPrefix)); + jdbcUserDetailsManager.setUserExistsSql(MessageFormat.format("SELECT {0}Username{1} FROM {0}Users{1} WHERE {0}Username{1} = ?", openQuote, closeQuote)); + jdbcUserDetailsManager.setCreateUserSql(MessageFormat.format("INSERT INTO {0}Users{1} ({0}Username{1}, {0}Password{1}, {0}Enabled{1}) values (?,?,?)", openQuote, closeQuote)); + jdbcUserDetailsManager.setUpdateUserSql(MessageFormat.format("UPDATE {0}Users{1} SET {0}Password{1} = ?, {0}Enabled{1} = ? WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote)); + jdbcUserDetailsManager.setDeleteUserSql(MessageFormat.format("DELETE FROM {0}Users{1} WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote)); + jdbcUserDetailsManager.setCreateAuthoritySql(MessageFormat.format("INSERT INTO {0}Authorities{1} ({0}Username{1}, {0}Authority{1}) values (?,?)", openQuote, closeQuote)); + jdbcUserDetailsManager.setDeleteUserAuthoritiesSql(MessageFormat.format("DELETE FROM {0}Authorities{1} WHERE {0}Id{1} in (SELECT a.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}Authorities{1} WHERE {0}Username{1} = ?) AS a)", openQuote, closeQuote)); + jdbcUserDetailsManager.setChangePasswordSql(MessageFormat.format("UPDATE {0}Users{1} SET {0}Password{1} = ? WHERE {0}Id{1} = (SELECT u.{0}Id{1} FROM (SELECT {0}Id{1} FROM {0}Users{1} WHERE {0}Username{1} = ?) AS u)", openQuote, closeQuote)); return jdbcUserDetailsManager; } @@ -364,10 +361,9 @@ public JdbcUserDetailsManager jdbcUserDetailsManager( PasswordEncoder passwordEncoder, AuthenticationManagerBuilder auth, DataSource datasource, - EntityManagerFactory entityManagerFactory, - TablePrefixProperties tablePrefixProperties) throws Exception { + EntityManagerFactory entityManagerFactory) throws Exception { return SpringSecurityAuthAutoConfiguration - .jdbcUserDetailsManager(passwordEncoder, auth, datasource, entityManagerFactory, tablePrefixProperties); + .jdbcUserDetailsManager(passwordEncoder, auth, datasource, entityManagerFactory); } @Bean diff --git a/scripts/sql/profiles/h2/apolloconfigdb.sql b/scripts/sql/profiles/h2/apolloconfigdb.sql index 66f834a347c..3da2b561f07 100644 --- a/scripts/sql/profiles/h2/apolloconfigdb.sql +++ b/scripts/sql/profiles/h2/apolloconfigdb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -42,7 +42,7 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common -CREATE TABLE `C_0_App` ( +CREATE TABLE `App` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , `Name` varchar(500) NOT NULL DEFAULT 'default' , @@ -69,7 +69,7 @@ CREATE TABLE `C_0_App` ( -CREATE TABLE `C_0_AppNamespace` ( +CREATE TABLE `AppNamespace` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Name` varchar(32) NOT NULL DEFAULT '' , `AppId` varchar(64) NOT NULL DEFAULT '' , @@ -95,7 +95,7 @@ CREATE TABLE `C_0_AppNamespace` ( -CREATE TABLE `C_0_Audit` ( +CREATE TABLE `Audit` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `EntityName` varchar(50) NOT NULL DEFAULT 'default' , `EntityId` int(10) unsigned DEFAULT NULL , @@ -118,7 +118,7 @@ CREATE TABLE `C_0_Audit` ( -CREATE TABLE `C_0_Cluster` ( +CREATE TABLE `Cluster` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Name` varchar(32) NOT NULL DEFAULT '' , `AppId` varchar(64) NOT NULL DEFAULT '' , @@ -142,7 +142,7 @@ CREATE TABLE `C_0_Cluster` ( -CREATE TABLE `C_0_Commit` ( +CREATE TABLE `Commit` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `ChangeSets` longtext NOT NULL , `AppId` varchar(64) NOT NULL DEFAULT 'default' , @@ -167,7 +167,7 @@ CREATE TABLE `C_0_Commit` ( -CREATE TABLE `C_0_GrayReleaseRule` ( +CREATE TABLE `GrayReleaseRule` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , `ClusterName` varchar(32) NOT NULL DEFAULT 'default' , @@ -193,7 +193,7 @@ CREATE TABLE `C_0_GrayReleaseRule` ( -CREATE TABLE `C_0_Instance` ( +CREATE TABLE `Instance` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , `ClusterName` varchar(32) NOT NULL DEFAULT 'default' , @@ -214,7 +214,7 @@ CREATE TABLE `C_0_Instance` ( -CREATE TABLE `C_0_InstanceConfig` ( +CREATE TABLE `InstanceConfig` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `InstanceId` int(11) unsigned DEFAULT NULL , `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' , @@ -238,7 +238,7 @@ CREATE TABLE `C_0_InstanceConfig` ( -CREATE TABLE `C_0_Item` ( +CREATE TABLE `Item` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' , `Key` varchar(128) NOT NULL DEFAULT 'default' , @@ -264,7 +264,7 @@ CREATE TABLE `C_0_Item` ( -CREATE TABLE `C_0_Namespace` ( +CREATE TABLE `Namespace` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , `ClusterName` varchar(500) NOT NULL DEFAULT 'default' , @@ -288,7 +288,7 @@ CREATE TABLE `C_0_Namespace` ( -CREATE TABLE `C_0_NamespaceLock` ( +CREATE TABLE `NamespaceLock` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' , `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , @@ -309,7 +309,7 @@ CREATE TABLE `C_0_NamespaceLock` ( -CREATE TABLE `C_0_Release` ( +CREATE TABLE `Release` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `ReleaseKey` varchar(64) NOT NULL DEFAULT '' , `Name` varchar(64) NOT NULL DEFAULT 'default' , @@ -337,7 +337,7 @@ CREATE TABLE `C_0_Release` ( -CREATE TABLE `C_0_ReleaseHistory` ( +CREATE TABLE `ReleaseHistory` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , `ClusterName` varchar(32) NOT NULL DEFAULT 'default' , @@ -366,7 +366,7 @@ CREATE TABLE `C_0_ReleaseHistory` ( -CREATE TABLE `C_0_ReleaseMessage` ( +CREATE TABLE `ReleaseMessage` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `Message` varchar(1024) NOT NULL DEFAULT '' , `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , @@ -382,7 +382,7 @@ CREATE TABLE `C_0_ReleaseMessage` ( -CREATE TABLE `C_0_ServerConfig` ( +CREATE TABLE `ServerConfig` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Key` varchar(64) NOT NULL DEFAULT 'default' , `Cluster` varchar(32) NOT NULL DEFAULT 'default' , @@ -404,7 +404,7 @@ CREATE TABLE `C_0_ServerConfig` ( -CREATE TABLE `C_0_AccessKey` ( +CREATE TABLE `AccessKey` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , `Secret` varchar(128) NOT NULL DEFAULT '' , @@ -426,7 +426,7 @@ CREATE TABLE `C_0_AccessKey` ( -CREATE TABLE `C_0_ServiceRegistry` ( +CREATE TABLE `ServiceRegistry` ( `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT , `ServiceName` VARCHAR(64) NOT NULL , `Uri` VARCHAR(64) NOT NULL , @@ -444,7 +444,7 @@ CREATE TABLE `C_0_ServiceRegistry` ( -CREATE TABLE `C_0_AuditLog` ( +CREATE TABLE `AuditLog` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `TraceId` varchar(32) NOT NULL DEFAULT '' , `SpanId` varchar(32) NOT NULL DEFAULT '' , @@ -472,7 +472,7 @@ CREATE TABLE `C_0_AuditLog` ( -CREATE TABLE `C_0_AuditLogDataInfluence` ( +CREATE TABLE `AuditLogDataInfluence` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `SpanId` char(32) NOT NULL DEFAULT '' , `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' , @@ -494,7 +494,7 @@ CREATE TABLE `C_0_AuditLogDataInfluence` ( -- Config -- ------------------------------------------------------------ -INSERT INTO `C_0_ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) VALUES ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), @@ -506,7 +506,7 @@ VALUES -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/profiles/h2/apolloportaldb.sql b/scripts/sql/profiles/h2/apolloportaldb.sql index bb2e12cc378..6a409beb963 100644 --- a/scripts/sql/profiles/h2/apolloportaldb.sql +++ b/scripts/sql/profiles/h2/apolloportaldb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -42,7 +42,7 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common -CREATE TABLE `P_0_App` ( +CREATE TABLE `App` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , `Name` varchar(500) NOT NULL DEFAULT 'default' , @@ -69,7 +69,7 @@ CREATE TABLE `P_0_App` ( -CREATE TABLE `P_0_AppNamespace` ( +CREATE TABLE `AppNamespace` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Name` varchar(32) NOT NULL DEFAULT '' , `AppId` varchar(64) NOT NULL DEFAULT '' , @@ -95,7 +95,7 @@ CREATE TABLE `P_0_AppNamespace` ( -CREATE TABLE `P_0_Consumer` ( +CREATE TABLE `Consumer` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , `Name` varchar(500) NOT NULL DEFAULT 'default' , @@ -121,7 +121,7 @@ CREATE TABLE `P_0_Consumer` ( -CREATE TABLE `P_0_ConsumerAudit` ( +CREATE TABLE `ConsumerAudit` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `ConsumerId` int(11) unsigned DEFAULT NULL , `Uri` varchar(1024) NOT NULL DEFAULT '' , @@ -140,7 +140,7 @@ CREATE TABLE `P_0_ConsumerAudit` ( -CREATE TABLE `P_0_ConsumerRole` ( +CREATE TABLE `ConsumerRole` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `ConsumerId` int(11) unsigned DEFAULT NULL , `RoleId` int(10) unsigned DEFAULT NULL , @@ -163,7 +163,7 @@ CREATE TABLE `P_0_ConsumerRole` ( -CREATE TABLE `P_0_ConsumerToken` ( +CREATE TABLE `ConsumerToken` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `ConsumerId` int(11) unsigned DEFAULT NULL , `Token` varchar(128) NOT NULL DEFAULT '' , @@ -184,7 +184,7 @@ CREATE TABLE `P_0_ConsumerToken` ( -CREATE TABLE `P_0_Favorite` ( +CREATE TABLE `Favorite` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `UserId` varchar(32) NOT NULL DEFAULT 'default' , `AppId` varchar(64) NOT NULL DEFAULT 'default' , @@ -206,7 +206,7 @@ CREATE TABLE `P_0_Favorite` ( -CREATE TABLE `P_0_Permission` ( +CREATE TABLE `Permission` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `PermissionType` varchar(32) NOT NULL DEFAULT '' , `TargetId` varchar(256) NOT NULL DEFAULT '' , @@ -228,7 +228,7 @@ CREATE TABLE `P_0_Permission` ( -CREATE TABLE `P_0_Role` ( +CREATE TABLE `Role` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `RoleName` varchar(256) NOT NULL DEFAULT '' , `IsDeleted` boolean NOT NULL DEFAULT FALSE , @@ -249,7 +249,7 @@ CREATE TABLE `P_0_Role` ( -CREATE TABLE `P_0_RolePermission` ( +CREATE TABLE `RolePermission` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `RoleId` int(10) unsigned DEFAULT NULL , `PermissionId` int(10) unsigned DEFAULT NULL , @@ -272,7 +272,7 @@ CREATE TABLE `P_0_RolePermission` ( -CREATE TABLE `P_0_ServerConfig` ( +CREATE TABLE `ServerConfig` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Key` varchar(64) NOT NULL DEFAULT 'default' , `Value` varchar(2048) NOT NULL DEFAULT 'default' , @@ -295,7 +295,7 @@ CREATE TABLE `P_0_ServerConfig` ( -CREATE TABLE `P_0_UserRole` ( +CREATE TABLE `UserRole` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `UserId` varchar(128) DEFAULT '' , `RoleId` int(10) unsigned DEFAULT NULL , @@ -316,7 +316,7 @@ CREATE TABLE `P_0_UserRole` ( -CREATE TABLE `P_0_Users` ( +CREATE TABLE `Users` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Username` varchar(64) NOT NULL DEFAULT 'default' , `Password` varchar(512) NOT NULL DEFAULT 'default' , @@ -333,7 +333,7 @@ CREATE TABLE `P_0_Users` ( -CREATE TABLE `P_0_Authorities` ( +CREATE TABLE `Authorities` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `Username` varchar(64) NOT NULL, `Authority` varchar(50) NOT NULL, @@ -346,7 +346,7 @@ CREATE TABLE `P_0_Authorities` ( -CREATE TABLE `P_0_SPRING_SESSION` ( +CREATE TABLE `SPRING_SESSION` ( `PRIMARY_ID` char(36) NOT NULL, `SESSION_ID` char(36) NOT NULL, `CREATION_TIME` bigint NOT NULL, @@ -365,12 +365,12 @@ CREATE TABLE `P_0_SPRING_SESSION` ( -CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( +CREATE TABLE `SPRING_SESSION_ATTRIBUTES` ( `SESSION_PRIMARY_ID` char(36) NOT NULL, `ATTRIBUTE_NAME` varchar(200) NOT NULL, `ATTRIBUTE_BYTES` blob NOT NULL, PRIMARY KEY (`SESSION_PRIMARY_ID`,`ATTRIBUTE_NAME`), - CONSTRAINT `SPRING_SESSION_ATTRIBUTES_FK` FOREIGN KEY (`SESSION_PRIMARY_ID`) REFERENCES `P_0_SPRING_SESSION` (`PRIMARY_ID`) ON DELETE CASCADE + CONSTRAINT `SPRING_SESSION_ATTRIBUTES_FK` FOREIGN KEY (`SESSION_PRIMARY_ID`) REFERENCES `SPRING_SESSION` (`PRIMARY_ID`) ON DELETE CASCADE ) ; -- Dump of table AuditLog @@ -378,7 +378,7 @@ CREATE TABLE `P_0_SPRING_SESSION_ATTRIBUTES` ( -CREATE TABLE `P_0_AuditLog` ( +CREATE TABLE `AuditLog` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `TraceId` varchar(32) NOT NULL DEFAULT '' , `SpanId` varchar(32) NOT NULL DEFAULT '' , @@ -406,7 +406,7 @@ CREATE TABLE `P_0_AuditLog` ( -CREATE TABLE `P_0_AuditLogDataInfluence` ( +CREATE TABLE `AuditLogDataInfluence` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `SpanId` char(32) NOT NULL DEFAULT '' , `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' , @@ -428,7 +428,7 @@ CREATE TABLE `P_0_AuditLogDataInfluence` ( -- Config -- ------------------------------------------------------------ -INSERT INTO `P_0_ServerConfig` (`Key`, `Value`, `Comment`) +INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`) VALUES ('apollo.portal.envs', 'dev', '可支持的环境列表'), ('organizations', '[{"orgId":"TEST1","orgName":"样例部门1"},{"orgId":"TEST2","orgName":"样例部门2"}]', '部门列表'), @@ -440,17 +440,17 @@ VALUES ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); -INSERT INTO `P_0_Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) +INSERT INTO `Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) VALUES ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); -INSERT INTO `P_0_Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); +INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); -- -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/profiles/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/profiles/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql index ffb86b84bed..0b7668b730b 100644 --- a/scripts/sql/profiles/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/profiles/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -36,7 +36,7 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/profiles/h2/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/profiles/h2/delta/v220-v230/apolloportaldb-v220-v230.sql index 8372d9a34f9..80971e7e15c 100644 --- a/scripts/sql/profiles/h2/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/profiles/h2/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -36,7 +36,7 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/profiles/mysql-database-not-specified/apolloconfigdb.sql b/scripts/sql/profiles/mysql-database-not-specified/apolloconfigdb.sql index 6df2f064aff..c999b8c6df3 100644 --- a/scripts/sql/profiles/mysql-database-not-specified/apolloconfigdb.sql +++ b/scripts/sql/profiles/mysql-database-not-specified/apolloconfigdb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -501,7 +501,7 @@ VALUES -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/profiles/mysql-database-not-specified/apolloportaldb.sql b/scripts/sql/profiles/mysql-database-not-specified/apolloportaldb.sql index 41dea9a35f4..e6de5a1a4a9 100644 --- a/scripts/sql/profiles/mysql-database-not-specified/apolloportaldb.sql +++ b/scripts/sql/profiles/mysql-database-not-specified/apolloportaldb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -445,7 +445,7 @@ INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql index 3566bebbca1..96c79c3c365 100644 --- a/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -31,7 +31,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql index 94f468e12a8..9f8443856a1 100644 --- a/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -31,7 +31,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/profiles/mysql-default/apolloconfigdb.sql b/scripts/sql/profiles/mysql-default/apolloconfigdb.sql index 278c1812c56..c2b3f030a04 100644 --- a/scripts/sql/profiles/mysql-default/apolloconfigdb.sql +++ b/scripts/sql/profiles/mysql-default/apolloconfigdb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -506,7 +506,7 @@ VALUES -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/profiles/mysql-default/apolloportaldb.sql b/scripts/sql/profiles/mysql-default/apolloportaldb.sql index 895ae406b89..264f948a53b 100644 --- a/scripts/sql/profiles/mysql-default/apolloportaldb.sql +++ b/scripts/sql/profiles/mysql-default/apolloportaldb.sql @@ -25,7 +25,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -450,7 +450,7 @@ INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloconfigdb-v220-v230.sql index 29630d0fa67..e76bafa8af7 100644 --- a/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -33,7 +33,7 @@ Use ApolloConfigDB; -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloportaldb-v220-v230.sql index fb013b08039..0ff6f7efb75 100644 --- a/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloportaldb-v220-v230.sql +++ b/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloportaldb-v220-v230.sql @@ -19,7 +19,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== @@ -33,7 +33,7 @@ Use ApolloPortalDB; -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== diff --git a/scripts/sql/src/gist/autoGeneratedDeclaration.sql b/scripts/sql/src/gist/autoGeneratedDeclaration.sql index 6bc89bd2585..d3a2fe50f5c 100644 --- a/scripts/sql/src/gist/autoGeneratedDeclaration.sql +++ b/scripts/sql/src/gist/autoGeneratedDeclaration.sql @@ -17,7 +17,7 @@ -- =============================================================================== -- == == -- == Generated from 'scripts/sql/src/' == --- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == +-- == by running 'mvn compile -pl apollo-build-sql-converter -Psql-converter'. == -- == DO NOT EDIT !!! == -- == == -- =============================================================================== From 34c259646baecce72e8a5e3fb1d91a10bf806776 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 12 Jan 2024 22:30:07 +0800 Subject: [PATCH 37/59] update doc --- .../ApolloApplication-Mysql-VM-Options.png | Bin 123005 -> 182066 bytes .../distributed-deployment-guide.md | 8 +- docs/en/deployment/quick-start.md | 83 ++++++++++++------ .../development/apollo-development-guide.md | 17 ++-- ...al-how-to-implement-user-login-function.md | 2 +- .../distributed-deployment-guide.md | 8 +- docs/zh/deployment/quick-start.md | 83 ++++++++++++------ .../development/apollo-development-guide.md | 16 +++- ...al-how-to-implement-user-login-function.md | 2 +- 9 files changed, 146 insertions(+), 73 deletions(-) diff --git a/doc/images/local-development/ApolloApplication-Mysql-VM-Options.png b/doc/images/local-development/ApolloApplication-Mysql-VM-Options.png index 77abd0887ee60c2a2c9f2f54e567807aa7b48b3d..051158ea44befe4ba6e98c2afb38873afa99bca5 100644 GIT binary patch literal 182066 zcmeFYc|4n2*EimCIyg0TR7G(*Dyn8`ZmXzyj3F_!6eWfhF-7P|%{9+LjY&jmOodQY z)I3B4L24d?n1>K~o%^|;`|f?7-+%A>`|ru;W4KnXYh8PliyiK$o9xLs>vT$^9!uf&zgJZ|aV%ZL! zo;9QO8%bo|2IKi_TE45`L8Gby0(GkyveUQc8n>f z{pf+2zwOc(OD3O1?)HS=4R^w}?HCk$K?xuC@FB%+qdFVs_^6E(1h6xo-T9Gz7-wN5_1Y(l2@K5Ja;8p2Gf06)Eq7Q*Ia-7 zWZJW?muFG0YsK6nU6*867r?Ur`t{NOPfnch{Ovz!uO!aa{hiUb`>U7!^R8om9B%~u zjr1q`|5Iiy5dg40RvBH8pI>wHZ?Ecn6dk?g;SzZJM~81|>=lJc>)7uS?3({`;F1pi zlXxxs-2a&L?LYn5{`QV{uYZdDjdb?Z8|>dm_b>l3{`=o(Pyd(Mza{d&GW)kIjvf2I zG7Zge7aeU4s?SOQRaTxz9sirfzDjGiEOSLKBs-swW?aE7=s4jr$xl=C0U9Q}uvnw+$s8@ZgT_E|6^ zpppEEx;X{6E>d{v>r=>MG&LSVC8_Nt38)S&j`P_RzD)Kw?3jZ*eMnJ0CC7NoWHhr3 z40_gc<2MXo%*Ee}+|mJbl8|R_7WCHOYa#qBADs{l&MbHFT||H=Ii6}tWiH)5B^Q1f z`zwUQE$jTfIXmP~uUORz4$!L80-p-EIgsqi$e0)($tw>FE^5)flISTju0ZSicGJ7W zB!$V9(y0m3pq?*_AX2XiA-4rhezBo&$cvxY#qu-U0C1%*r88^I@ z=*w7|Lb84g;lY%-v1DfI5fatBtIHD}I#y5*tH2n^ zThIptKMnMxkj-Ic0Q6LBWJ|tPN2a}a1zLlsB}!C`rjLhT2CoiIB^v@mCjg867F2c0 zep-F-*24hwsSB_{@QJZc9UjFAxfLj~SS}0o#4l5S!rClmG8^BK*sz&2IOEl&G_@7M z3U1W;ZLgMC3@#=1ehAlmV=@O_ya3TJ&!o&ub0$|xmz?iZKZO?%VAKmBB*PhsScx6Y=AJ!!hjXkhNlzv}bID?p(L z|6|g03D#1x;GS1i4%2DS=yj7ZK566ClK}owi(VPWbTK4lCkhwZezDm)|4p-kfy96t zr9?d>xGH;(NDQ1vNm;C65iojj-s`b+T+Po8MH<6UF(pZqFa`}fyW;y*yCWenci_Hb1Z&9G?>NC`MBzmJ z!7Uq>TXW908cXj&v;y{=cn44aqT#QbPyH|54k5bmQhDz^8f0h*hb&7}+x@B8GbRt0Wam#x= z{|gf-ef74qh4n3}F8g(Zg*0KQYa{jSJhriQs&*3bsvh?sa7k72d#+W_Mi9SE!Mm33IM@7nu%5BOZ_d;AV`VhdCHPv?ZC{X3Hz*H z=5S0;bWN91TvEn)EX}82eeTv5d8fPTTdpeG`HM)`XPn&6B6UrAo@6dZYmJ`2CS0=o zDj`8gpGP>C^Y)N6BE8zEz9%ESG(VwE?R7Lmhb=9vhH>aqx3XTM~-nVdQg$G4$bx*@0NKZZ+J~Qsx zTj4iaxF5r*qThqVE}}?xygjv9R_Zkx0?P<^uJhfSm;R?)3bo@TY>GI~+zgy)o_jtP z|Io3ZS+v(Ecj{(qC2hEN3o8^s#BGOcwqk6a%5pXZ1{Y=Hwm9h96-|cHR|<)JcT{)I z+XNm4inU{TjRVV-`8kjnRBvvV;R1yjtWygPjjiUi=GO9|kV25$b!C|gvdpi!MKgRc+d{07+!Ku4iWh;yk{*h$w*S5?Si-je}ibQzYHNzbJ z9>!`QY;NJzM#=mj>PM;WFIsu^T!Jv3$KeUX#?xn@dKK!#*m?scKVt1pRCmZW+@~dU zZv}mp5M*AH+bZ@I{Z|D+#$!W*-Tai2&MK?QG6D4wJ9K~z%zFegDYT|1(x>YyS z`tV%#>064`Tdx*nU`IamAL(RdWMmdNkD|!e8N8JE$M~%Eh7DtVSvRYkQOMYIx1fT0 z?#V-=Z=RsyciHH3t=(Rp+8In5FKn$*ZpZxbJpx|`IQ_J)&z6>2A+_hO*}>TkSNRY0 z<&a(rnhw#q;Xu*Rswe!>s+`NPEPcAmldv${#Qgq)UB-omr;yNUA-1yWOW)ZoyT7v0 z7v{F92ZnZ-Bp3A_3$0-`dPi(f8{?{E2p3UXdG34ja^Cl^kilmx# zk(oR9Y}$l}Bi5>m(TByr4naU$3zXRJ9>rUyZ}~Fv(%tqlohoGTy0-|5O~vDu9ikw` zy3}$%G^Aciijein!g<+TR(6LYf^@L11=)QZCd=@dshgy>>sHXvMl*TX;!iHq5SLrl zg&HY#H=Rd+7KT+Z;~K)M4#TASwnnf5F~|c77K!Zo7#H+9LaxqW!Kz}~u=-L-p1FG! z$gGwI7a42NdVO`4DAUthhZ-+^w%_uZiq-@e2HDPR!9vtVeJ|_er&N^_i-rzJ#V@vI zbg+fof`WM~g?X-sG1LgU!6X3SFn>nt$r;PbApayMF*WtW%7=TVQZvgX=3vt_VC)zw z-rcac3mF^t*=Y+S&r2CpB~16~1LT7cmjJxj2UJ*5ScYapg^McOesYFE*)6x+)pgbU*N@u$ooTim#hKpER$&79i4|of2 zLqvkRj5Lu|D+X&nm$lUnF)l4G&G9uWVxY7buAU>;x)q8wq2ZRPfg}YD^;3H8N2vsT z5xb~M0|^E?Wd2DQ;YoumIBzyk{P#cPf-)xb2jfX026nJk*5=eaG+85%;2d@)Vq|i? zX8=_HqM~%3X9)6#X_>*PKS~E=1(hXzlxnV3-2HXGc`K4XT})+QGBJ9TB&wDO;Z5>u z1hhj~tlh{A=l4pMd2v4Bmu&X^&>_oVvd#-UI$d{6>eOu3TsD#v_ocd2nS8*ICeO+j zYi>Mw)3$XdX}w4+;{i$>XB$wFEFvjuTBco*1oX*XCxvJiH85I5+M`~=Rg?`!L>#+q zF;Q0F#GmYiKy->9VV`_0Rpr&f8Y+%c^q87)nUgPTAN=#!%2W}4$c%|cGMRULBsxoz|I zF!ZYKy6uGa$5&i~r4#S92X>@Z=^Q@Da2i^ccs!jV3qUwC%=k+8GH36OJ<-P)y$n~- z=>%aiXGq|-s*u4&?{0p{Fvk{;-ceCzVa52ac9(5%TsiBdHh5z0m#AhPxOXmV&wjOB z-Be0C=;!x1p``{&5Wc(N=QaEeUS7CQ?Zq_V#ZZU?6RpAl1)7T7GF|XcVU-(1UVYAm zTQn0~On!C)6dQXbh3~!LX>DO0Z394rS}9hQetvYnMAyqCezN7`=;qwr!O5E)CAzus znq6}oT}wz~fO_$i%t2Z^yR^}qewTSV*;f%PLcABP$qm;Lf~*d5#yZ)oULAYklnIS3 z@XDx8#Le)0HTVjL61s4K5A5{ij|@0@g;*#=BOQ-bEy~hz9XQ7>TRiaX_nR>r9A#>h zcJEgGmV&GyTVkw0%(Av+;WvwM1efR>5F@);cUgf( z7$G&-SqbO9bName(RKSk_a^8N5s_C*92~zH8}fG6Zco86>g?ndWAa_VGR~qviDtY| zHih5lH{LcnvQ85_%JQfucx;Pi^rAPua-MZh%QB@ftzfhnl?i#89%fbsF53Sw^vDap zE#WneA*R^op71mp>taDKj5(mmwE$m#>`3i0ZW7>jSOwf`5f_p6SgnjfcqDF_S5qZr zIhEIZEI*Z%)bGiIXLwLt7fOr?WkLYlGDc)PG3a+fD#{9j z2W-q<`T_1SB?kkRcM~|(_8s`gH_reP0ks>II^MR-<6H%`A@_a*RlE6?Zm_X#X79kB z=uLq3YqlvvAz*6Spjmi_UJAwK_;0dAqSAFTuO^mQ%BxQ9erysr>(5t)R@bj0A`u7^ zeN&JpY~HQ(^q8}aE0{XaPm0o-3D-Az_{MJSWf^bCts&s}A}<8E;c)qM`wxTDd9*DN zG0`!Ev(slQB5{gudH0#j##?OoNg&<{ZH}=eK&`w-tOA?4JO^skm=28T1a6Uz3#>xv zjX;&X4T{SSyN(Ss#jeQDCUs)GJo%~-!r7DgaeO;Fc2Sp7Z-WhCf^mDtX}$UsnBGnP z>+9)~SETLe3%dBfo_bCD_t!>ESzNEYQ)^NjD| zR=M(+UM(`@$~hW#zHkR-jSbpoZW7=@hIad#(e$4rfq}C76sa5V{XiSVN3CjH)MvN1 zB_>!_nAxg6O&s)}LJc_}j~Xk%U>ay^S?Jq=HsFMwkIk>hlwS3dHambVpGfQ78lV-U zWq{9wP87M#%29J!IS|{PkvaK6Pg+BPJLu7{c5W)rc>z;7lVagYW!MeAE@~(`9viF! z3f@q34+xG_d|SwFh?DAJrmkmhG@W^t{$8YR6|GZkSmkkQAb59wWV1uwWnbNn@VcnJ zbj**EGe@hlt=&m}9FFOaC#2MbD9CAcOer4BTU7Pnmd2_TAx^C9{QM>T(#;LjdG-N3jEES<&5~ zr#VBZq@J;GA*iV$V1_}U{X@o8_rqmSl|$=q&VN2?dJO2^6Euo=X}{fuomNk`yUg2G zU9rm&xWG+vnRB2J;!=Xq*Ly~hHX$`S;wo!y&$I0qX8YzM0fci4imJrDC0uj z8)Y}NzK^!Pg$a5f$o#1UAr4o}_^D%Gx4>{rkUVw22j}px=U5>R%G(ZF<`vy5HI#>2 zq0baS$j7w?mdBl?qh7Vc53*IEbC)1`pA*;-1k(n3eK3r&p=e1Gt~hjItVTBUc5EF# zUf?TKwtQyCB?U@0zvp>a%nz9xSEJT83>71PeswGknsBCXO+i*vs(wDsHhRw)F4~h* z67D&{BBLaJ@nBgoC_`>+gQe=kDgBN+=6i2x11m7d`tImPx#90k#ilbW(H@rGFb$z_g_VQS!tDeQXD*618>D@&*Zfrs+dmD;bR|qM-RRszoH8*LTipRqlwxd)Mf_ z6rmEF_FnF&iMD?W;4!4@@slrOo^c{7%!-I23`UG@yq#!&u? z{H?D7inUHXrZ}pQ9WiX&7eBsHM&8ovkf5RwKv@sg@!7T?<`m0Hb*0sTCJ{b+9`-!b z46NWh-viQPKx2tn(I_}#u+b0spvHNKems;{bd_8FDK=4jqZ5ua*Vv@cpsV6W;|w`wEiLYUXJf;^8*i zs$8Mv$()4Df^Qrtw+FM$SBrJv%p#o3XyqcHX6>#lOPE#i?S=6WICAWPCxZ=R)PI)R zFB6$q@d6eg4N|FEU*W@5)q<=>|twhrMZ=0+)}c?4jX3d(_B)~~4x8s-&Ywz0T!;7U zp~K5h+z(!mzdr_;hbmnOaIQi^AGW>7Jl_av`apV9VTZ}6-wL5Gae3cT_Sw!)!&~dp z8H#yRGtOHqdo&)*TaxfGFo|Cfrgb;{R^5N3 zM};~hb&)X;pGZ-I!QT7h$3s=@ldaK9yGHYvmn0ik-dmfBuV{A)W@`v2dRUBrpDChA zqEfxpZ^g$}J^Q9kM%JvVeKyg<-cS?_#Js71I-#TZn5sc{!b?HB{0WT|f~gaY1)JY<$ywqmy29hVa-JxJ z3HZb}vQPq#V4dulLtQ)OH}1`X-%`XEsgxRlbL1Jjb8M}k+n&P5a2`EVi#~&n*;TtmwXvJp)`8(wSGFI+ zyO1LrKX$u$1=_YoV)>WAXqD-4-Um+_fKYSyk>5EIxTB(Oi=oU=F`>q%&bfh?x(@v9 z&ySkGTf{=lVHUSjsdn33S$o@dM{B^-w0r4h#2U^p;#1s_hU9#}YlVeM4@^K7uxMZ? z>srPZ68s_oE6LM7?{bjvRiNwM%_5_{03lnc3!{4y=M%H-WWIZ|Ch~HRD^^QC(+8NV z_|PNoIX)|ByIcv=lh))(b2;*oZbth0GNX~op;|Y$iqS08Je0lu7SAoIX7G-4qjlHo?==$mrF%C?j@9sIH)^9TSbjWZK zWX>}<#}Gdy3v7@u6n;s_!RbvX{<`VCe*!RGP#)2{&;esBHShiz^>kady@zcEfID+& z!-Y0@>2qk-{G~Z&Rw4}UejAVh+H5Y`IeBu*lqh}46KWa`;pDnLLU5T;EKR1M3W?4M7 zp86y&_6Z)|KLfz|SxzRS`_|jo@?!0@YDXVr@rSnwd${*+HlxpE z7hR!*i?*+@*8*JuzAuVwgC>LB6;;EtrY@p?J?A<0DEVn3!fl_;;D`P=A*sPDX8%K$ z;hKp17I@n4jTaF)wD#rA(9e*^ zWP9CXp^7!^?#9ja4!L~c+`>i0c6aW~0or{HCC6%*!Nl5OqGaS>3NUSycmvzM-PU-& zXTW|se0ILn7&I7Ok?~-zkzBdABiL7;A_#yvWF*Xa32YSpfQP(}=-$T}gzQr)y%>RD zeGMV9tl6%wVyFjyJ$pgXyXp`8#rhdlkJwV~@X<}?V>Vsa3Y|7%;-ONKQFn=hGNE+a z>l$f1FITQ_`zFPgOJ!F4%y0@@MDl*4K@G3=xl#xbeP!xB?vRlFr;+fyy^7KGkL*Qn zd1KVdn5ih^f!_RJZ**tL6|78MX2~6_%x`ORi*!B%Q=EL|`6bTJYpWIX)}Dqu@sM>* z{6+(&pGd0LpzW=8;bzD?^G|w|TArmMA?ME#@@;>$dc6xaP-Y?0SLqL@+m3s(I*X@I zw^)Dr*36UZwcKC^lnTAdP0k23BnqaO%qMHc#iO!+yMCM>A_aXYz$i*Gn@-kD{-_+7 zeUmrcS1tb%K>#7GJ{;Mz$d8Z?SP&gO=8X{Xt)DNUz6?JS`Jbk1ZF#LjdeR+%wmr8? z^%oa;Y~^@ARhPs$$f*_e7pdi?gh0}=84Tw0xhX&7vmQ-ZY-p&gOi)0(@_rc5d$7DX zdPMPF5IDm(7o@8fSlA-#lP3h=ad{i|Hab}|X=NPAPsV1xP_X7^-NFB=uI{m0j9(VmXq?C;&Ak3X0@G9FD|h9R+d_Or4pYRFe4M zc!8Yk4%6{rxd|bRwtK02c^{&0#;;g>oe}&rzV2C#Q|y-q8&%J3reA zN-6WRXF~KFzU;rmf7vfa0&(>5%XQweN8nTDMbj#S78l^4=r7UW)xx!-?LAGHEy)yP z)HrJNQ`C2l*d9?qe7-j!8Ivt3NY03R(VEP zz7ghiar4YSawV4*5tZxO0;n^RUFO6qDmjx)dDbz+;wIp!qxdAOVpFeeDWG(WkNwoe zKQjGKpMuiWOkc08m0$lJmY-pDSA$;uaPM@W&L^n{O%&q&UIM`fiuvGj05VLvI5 zF*0#svz`k>nqeE|yAT&wn7wlwv=(VtoR3}OoCZ}}M+OEzmf|UN&59yamRS6vfMbMr zSqrYC+v2h(mp_8iz0C1Cw%(AycUDa9ii=G&S8k)3f|GO{-|M$nQxCoev^cL zL-{56a;ELL4BvodIR*CJ1gjst@&nnjq^p&cJbBlAumqtXkN?Y~?U#gNn zHOceRNpfj>U$pI6U`Ginim=miTUJzEK-xSlO}N{Ebr6LtopWZnyp(@tJpJWK#r-Te z31q$vRY%<`Iga)i=2ABQ#ENwj_1}VSwkRBj>PZL3*lw(yp~f$r_Gx!`av2b~8|S|0 zrF0#7dDo(jb}K6@V3L~A2HuL<0earO5a7LJOv!P=KJQ4A_53kV&r@sZ38iqw1$0U1 z4=eH%Em&fHRY74AJ!IZrd){nueAv_IFdm!;Ul=u;8*f11oag&K<4gMa_tk$JNUe|s zciqmbF0es;3dns_WaWp^(WTEllS3>TxfjptfrE>cquv2Xq8%!_`)2c_`#Fo5gw~?l z;I@HB^X?I_vBNxTvSY`iM{ z0ERh7?RlX)bq?>C^@p@ajh6xQb8_7w30NPP45fv$=jqxkdw7|hUT@Y^OL@lPQDiee zIN76T@y68ijVl6WY;oC2s_D4}%;xr!=l=1D*^{YAj2_L`3{|M$Lk}?YN|x%c zNSX*utUWp)xY%V};QS>`u&zrDRl3U0*a-g1cR~TL0wgWAE3*GnK zLj4LZ*}g6Ccm#TYj93|I&g@vQC;xQS-QB;QF>nYN0E&eyHlgwRZo zq+mP{pbRTY@2V#q;T^8narC9RO2&3&eL*wZx?yTEOxmftwbH(+y!SEQw17cD-aF5F zxH}v2D3aSr!LefcHvsPXml%s1BY~JG^wf6o9-uV!~rX`aCdHB0`B7Q<~rpKmqX-i(XgEp@AVWGiHgKg}oN7r%J zyMmO!)P<$E4+O$!po1JLnEm>fYT_V*I5vKoCoM1LhjMVg{0q-^Gx)Qmk{N4MBz9 z5?`xh<=yw*2e0m&-!T_#T6}W28`)|`z9 z@}|^7ssnDhsDS`qp;rV$_OV;dXBa64J>gZn!_$7JOv{gA7Vd8`>&A;!8gf1)!YR@! z7^}0-(JgmL^F`hfuxxg_lPYR5?&#;*)l3o<^~{}QSVb7x<#iI_y^G)m2|XRhCe!_xSq8=A}`$LXI)TR zjSIQA$DRiuLbEwfF4%7*etZ%(KZ4#DF!DR`(C3^D<}RVcwClCIl&Lte98Bw-ZuB3=rrGZ{goG>ymp<)!R>}7e>x=}Ko$0f4;~#$Ibom`tb=yB zj~v`;GN0d}zJsWg^uuHg`X1vfJ1~23v*K!?aBZG-dcXQc`zkF`w{SnzsnV3M|gZ^;LV;!dt1AS zxo`S;dUUsP((fEeNH&gp;~j1YbN3ABarN}Su%Nc1lV=Kp(pOY}V93wGIkr|^zbiU+ zhCqdEc_qyCMv*$ULoLCMBLLhssLlM|oZzg2hJk9972b83&25)`KKR}TUz&md zDd@x{3iCm?~%!^>e zvAxxF#cwZ|b#amFdwEqJ%u)`E5N&Vn?qm|@*eR;n#&lTK&J+B; zpO91(H)OXDI^fikaZa2$%IrVbP(x}sH`vwWHiop`Snp7j-2S7W$}s2=i_Syp*96}} zCp&t>$Z9tWI-R8D`v?K{f3`Ci7me0D^| zs0HTvx{c=MKq-l*Rg2ac#1#$%^(zC(@kRdHpYhbH6su3``;?-rjBHctX@wllsuZ=H zw;>G%O4t?tt<4>qFi*l@2*Zqv7>y^lNw6j!taUT>OJuGmAbX)M%-NJ0vg3nZlHu6>`z z@x?Cw%$-7lmsczVr)CU&=ET^?#Hx^Jgt5E3soC#k{IW#YTb)yjW&rtZ2m~oo~*d{ft1R9@^s7V)N{*YpP+>IheqN&D#LjoYZ_ zF|*xew$f!Fh~rH~-}xM!^lQ5@$`6i8M{e2w&DkcT#eKftrcl9^^6>_Qh{y}ZrXx{W z99~DTpkzdsEo!>*%HBZnHtww}LZ$SpO#7=F*&E#MmTIJQl55hzvaF&dFaE=jKM6cp z6G8|jI9qL4<~oD~pg95WvORap6F=4%9aicgDm0e?KYYv@c?RC0y2R!{&#nhLP zMI_h2_iE$(MWg)GP`j5d-dyl_%&tEMmk|T(2za!NMw`kRUQXx#u)RBZQIMMS#%A$3 zEj@X-+7$4>w%Xgq+Iq>Fthwm@w_@zC+TUabUHUlG0LBqlD-L5vHZy350Nzsvp={&7 ze|^UHSIwmD@n5X)*fFOsLyn#nwqDQQbtS7X)01;S$5Pw=&X(OV-IhlR4OXvz}ROYokEcY2ry{;(#(xB$4wi7eX{uByCn{*;7le8TxG zDxDrUHzL=6hC7N2HJI+f^B+u)9lPgvaoSOd)ZEj80`xndqW%h5u9{YdXOYm3WXCX*c`1`JXQd|;Z*S{f16%G~u#|x!({rs>a zWDo#klUKT8urvPSXNB~?hH~p#dTaSD(7#;|d(#VDAw`5{oxZj*(ouwQny3##|KiY5$eOu}3=j zv5xvlWv4vVUrzDd?Sl_NfA+GUA{tq={`Z_nBmJLZwtb7-LRPBOm@(Y&tbbvBXSL&$ zlVuY!FE*0D_&0#c<(`32zc;>u{$n<;($EDpv_xgb(L-FnKI9Uo_+Jl!Fj!AXMa72; zF8`2|!KudJ--Zw2A*~TT-T#u@hswwN9qHNzxB~VQm&;iGqQ6*|7^6O({6$IEuJX2) z7uK3yxBYwDliu0?znho-FFK*fl2TnK#2OY8=-Y-N2s_547JV_A8~N1%7yCEo@bj5t ziDi{?E#G$W^VAn0Yzli4PjzXtb{T37bGoba&nKR<=S>3!wb&QL8u{s0m~z$H4fM72 zQNj5|EK#kN`*RbW({w#1H@{Q=6|{|U&OMYts(x6NqZR_!VvPOvAcR#fdnwa;4p)|I z3jj>*k1D0XvtA1n&MCtd{b;0-a}-hDt$8$!B<>e=XnSs9;kT)$>3o}UlweEemZAOi z49Gr&(pNDxMERup&$Qv5)uTzvK{JuRI??`7I-DW-%?}&puVfx-aonOv%N7HAWR~WF z+AQn|*2M;Iis2@s97WpOj7%~O%T5cox5JBMF<&%k`;*wM=pDP_Z>eoP2^r&$X6{<$ zCF#zh{*(qBez~`&Y#RVu(|N21@SS)lW`#H3@VelbI+dXoO9GDHYdCLO0jPZP-W+XH zIy(IWa9?RC6ZBDlbu9gXY?6SI_Cu`XQLQPkV|G?lTKIvaD(!SG8R19_%K=rUPL&8A zli28G{%idnJN7E={m*5~B;_2+7+$|XpMTK}MVy!mE>Ke=%&2~NF6qF%h%*c}^R!I5 zin+ilOEk7azOD6hnXA8!^k6ISWpBa^bJtnG>(|^04DJ0}Wu_AGFVbe6Zfthj#|G>&S1#Il`hN0CByI!XC0bGhPh4mEV8h0(*u;N0f;rgVd0#QKf z^k}App=O*H!{g7YTA*W6R_;1GcS4nscmGu8XSBh0&t3gL*qF0b+4PRh7snSi4eSN+N@o)8YC)d08Iu^yqN6+D} z^%IU4p5OZK9LVX~Ke_`BLDmK-0qdf;S##J1(yDv4%c=FH3Zqt#>SuVxTvy`ad0B^w z%ELvzt#Oi=aruQ(w?SzNGbi|`Dt=|N z&sxI1!CwdRkC&SgZG>WQiX({DWg|=v9R2D2MpDMS_X?YDqDxP*x_XQO-wL8rU)uI0 zYS7g@zBM2^*+Cp^;ZnOl-+7dc&fKBo1R%D(P7VaQWo%#ZOj7u+m@48MqX-=yPKRGg zFB*&&8!_%*Oq7&@?$4IqQ};GqqN}W#rfCHRetrCH8Qu!MHQ-Edn3qVHeZCy=d-L%A zm4B|BTYIqB!;2s49%p8U^>n8i=t&!64k!5osZ#rR`^lpI*v-vXajCPXVAEK^!8A!< z7`cRu*^kMNp08K_Z$WW^fVg2`?)v$$ z0M3Ep%1>fu*=v(r@ZJis5i^i1{vlQl>ied#9@mZ-{4G;tp82n6a}>n&)K@PN>?Yl~ z3TtPo^#gaqfjcetL;G^kXAZSm$9iKhpC6wz5FR-{Lpxn^iVCoj-Mn3PRHTB82s~M` zSJ6~)I{fhT$*8FNZ*_F|xO@udOanu!;#(9{2vMd6#?|&Ed*yS8s)N+U;{?%6#bDcj zK<=9oKNDvO+D!dc#NcbwI2VSJY#&qO?N;zg^3lM~x-SL%bH#o|v>dhlEk`kZ@AVgT z$Z*$LsU5U~6ZvP0Q$fMLZ|k=nVWHq>PI}4acK(RFL!TeAInCTwk$j+9VJa3~B_cYW zhwf4S6ecfV9I3Dg&Ja#nWWzStbYu}s1PM0q-NZvPrz_s_r(*Q`h>jQDC-#~=iALlXqhU!s`U586;}(e zX_l)c3MsE_vsMMR@dWx%|QXN2$Fw4aKWEX4OR+uTgF7E1Qm0~Ku zMz~NkP@?SUR4CFWSY&zRSpg5g3`jA)Kzj?|h(x;c-{al*Q=OQ?YgpI6;cP{|sS#dQ zwx0SM#J9S*3};>7D7(mBq4uGBJ9-Jxd0hej{Ep`hjZgKPpO5d?f4?&`?IbEDYkXQ# za^0U@h|YZ!G%N5L991*Ol41b#^0Ih8p(4#(C0e(`*uWs!B;mrvxve&dTH@F+Vz5O7 zU}26ZZFco*x`P=biC5F7q@-BgY{T)LvaeMZ_o9?f{Y z2J13$hX0=u(K*h^FUk;N) zm2Q6a^$axGQQLhJgEc(dJW8ibyVG?ykrpMSi1!-pmDOPwvMUxMt5`j!p|bJ)Lg2*x zrq6I2y`BL20BsyoH8>^9Jd9BFF{~TkT%r0*#NR;#Vg;B}JzFU$)MxZ^$Sj1`m(gui z95rN~YLpF|>T2t%Z5HdX3=h|ih>Z1XM~jJdZ@qg~(vPw&vkZS4+-O~Y)M;RpfN&VkSA*YXZX@_0hH~|T^nV!%3x$R9e-E}`*8hK@`p}486T&GN)pDR zUd0W81%hZ$W5*_b<#rH8R2+o72qhm?K4?-2l1ue`+LlFUOmt9^^}rlaAZTKK2zHWO%$;=L@u(X|~^AfSwuCuN<6N8&Vdhn2oV>KVfTq?0F z93DpKRE~H=k!(UjTY({E5xS2}beyuwP4r}mvPkd{M54Gp(f2m2S){ASz`Txs#S0rQ ze##?#%|9-cn!@cFE;@!A#bxETHbQz>JE$}WU^<@LnL7e185=K0Z(l-H z15x<*{PkJ)VVu=%dYu-9lyS-jW4F%+TpUd-_REau%}*!W4cNCF#2i`72Cuwm&r5sG zt^8AMU=(@J>4$5*vTmF zSI1qd>6v`5NJUndO$TiY6C!ua7fQr~v}wvAuf0spm+Xjx(p4%W0lUDi2B4jd>-kU_N`YZtwKK#;KS;A=XM+tUkRG1an`Ggzj3Lo`QwzjSY zh?+;<4aypPM(&~YPB2GNDWXEZUYs(*tlj}E zG1O4*mT-=x>bS(Xq5yMPKy$#xK>3sgzw4D?JF&ll)Jt!lJ!X(G{L8kRm~i>{#@O;i zRpE@Gw#DH=(#VUx_rNUcf-JIbC?_9Z1!SB^O>*wiA~)Ks*DoH&IceYsXTF2>Kk3Td zv3RjTSgbqPpm%~ViQH6eNhh5s;J!;rLrqm~gfAmio(k64LD`b$_gGvZE8HHZtFQyX z%VJ_AS5If^r!5}EdY1|vEf-JNEhD&6jOaZYYnIhz2lUP}M;{NuTXLu>G_mV2ZYWf~ z9yHezt!h zsMsX%X<)JP2iPlTBG(+U7rDA!m+Uc8+<#6aWLgGMAhhq6e_KerF`H*6=C(9FD}B_p zYYI4$Xw|OE$tW1MDe7OJJ*O1?Tq63!jF?T~u*=K!FJ$rF;ZKDvfwD4H#d%6Te|8@g z=yifVHG7+)HQ@OWW$oV?1{e=S28d)-)U!v_6s8C;D zQ(yxmdf<~cqSC}fmbt%HIx{6Cyc@m5eyl6GQ!Z6f_%irP>MN|=v&Qi7Fqn1#u+lBp z1U6B{c)Uc`1j?vI_5?RUw?a>@u~wTShSJB!)eDddJCOxnzOg~3!t9EE?^z{CtGvgp zUy!FZm|MY0$lQJdf~3Z=+DdQAIRF+%OB#fZk9Hht!2`)U%{@Qs{c+-+`BdF+3$$J> zN~JZzz>=J9>zvmfvEx#-F-G#>S9XHGyt=s~nO3y0EZ?9DzHrMkurRKmLv@`8&xpD* z$8vw$IVFa!!%uDi?Q^Ce2GKp+^&@XOm|F1QR^Xl%SwMq(aWa5ku|A|BX5f82Sjv8G zfoM^0g$dMno!-Iu+^$R(zTy+4f$6VGd8f%LX#Qt$4QceA7gRLxy$8J)oG5>q5&6`| zWh#M>IDc1t+iDIxd?b8Hs?Y35FL%4s>gQ}I{fp^;pC+)!p7RWQQhAYDz*Np-M!j%J z-QdlV7P?q|+5I~RI{ks@xtCvRlm2tmLyca%QnyUTO&RV``--v$6Jpgqv8;sXfvEje zZe4e7LfM+KrDdLM0yDbp#}m{LTCvh(tAmOK&VoafRuy|Z|?TI&vU=uuW$aqb)9qO%*@H` znb~XYwSy70w#WzM7vMo#L&~UuyzInz+sM*>1#5J>oKc3$5$t&TxVjLh6fnj&xXI>B zJ^2o%QHR_+FzSr@_+qsa*$E#nBWMso8p)Nql>vKPDmh%%QUX5a^YFHJoJ2`*CYKlWJWsL5T(*36ec9d z?w0tHv^2l02oFm-{Z<=Nv2fL~D3z;pEdJ({;NzvgZyyOf1Im z8Fx4bFTTnXxc4k`;ek|5AT@Mvgw5do>vET}(PE{2#-fG_00>7tKgt)=ssIz>EdRJ+ zUS=^R?Gtjjh^$bxEHmrwlk9JM%hEbS*?#ht1ONNrwjr$N6R_W^(X+rj7t%a3-^|D= zzcb8ZcWCe`5T#aT{hAi0%wsD#{8YD(HNNtR)&>id%uFgYSXsc>=SZQ0vbKE$UZxtP=0Vbv7__;d;CBsVvzaE8?x=$7+U#)xcl-r$c70^k~QW zb~^gQIvL40E{~k_&Wl{?ArKU_O5xulLBb9mBW1A z$|~p7kE^EO=ba_tavVw?a zm*L22q6*fWwV2F>xy{cJ4gWTEU3V${RwIz>S={m6$&jBGs?Hom!r<9(S|oRH9+(G} zzdhPqcZ@0U`6^hFxfk3< z=i}$$G*ursGPQ*$3({?DT)Ut|4%((9@PKz7DOI4gy>SSAs|Msf7Du6id1s~awV&M8 zw6C5-{gm#rS?s9bE}>UxaC|U^+9D{d4!+Yh4cQ!3ty`OHLl#I`UP`(u)Uxt6Y9(o|dcKCO=x&mJOzMU_78L8+XRi zezh)%jJ3cA@7jFUBs9*Ebt$euOXa+4xrL;GfpLqCxDaB?;7p?`Nuqr3dWoBHuNs?6 z=+s{Nj$0~S_%WlH-ys)eb@NjO1U-$}_i2OdW0hZ-{q2x>E+arJFDd#Nff~|}OX^;S zmuC;uUB@Y@?0z`%t_u8K^gjAkJfk8gd^Mo(me2T89DXQSVV-4JxlB8JLaa+E(igv{ zm&e`NAb}I=fyy6t8@XsSVX`W+|u|>q4$n4OO|V2VMK+ z*v?CgQ(EcvvAfM$bfblv@}U1~MTI(eP97x?>D(%$fLi=7a;O>{`M`OY` z^t9$ra^Gc&e(20zuBpou{a)z`SP7iY)WzTh>LRpK40_; zDZo>qM_pXYdtVCAxPqj?2}2d{_+2=vQ~bQ!!MD z(lE|cFgN?A<^c9Ds;X9XJf4@T!@dlD2#zE|nV&N>E31WsA$h{4crtrAjihT}&{PDx z#Ek}pom|I%k_UjtRXUwS#7z45)L&+(b8g~(n~@PW8>mT{anjv;k$0Q%=di2oNI#|a zb{$?vB`(db=l-Xdse<;=SR|7m-cWx?`m1tr zz1p??ZTJMJl%){bl!FZp^+X?a7W*ui0hUF9wU3V8>y2|=+6R&vkp(uomuAY}ec-4~ zU2UiN?kwso_BGF;WjG%pN3OaaH^DJ+W0l?s@|`HIxKUJe!xDs5CQ6b2`avz`aK8t> zvLb_ih^U@CR64X?+q&Y5=O_-pet$x8)2E|Fi$ESIMKq$dRYFz@@q35ghnGqRk{Tfv zDnYpqe8xcplb3alUvSp;+Q;+JK9JOcTJOgUZIVpH$*d#odLrGq$7D!m(rKn80e^S> zca%Eq=$=mD43+Nln{m)g=Y^%&F5LUzm)x?Y`xyW9qq_2-?@S+}UcK`pgw%T+68r$~ z&6}SNjU{Im)i76UxKSLHszkRwlnt1b&}B_7Cd?OM^V_V9Bc&i<-npgIx-Pm)%z=ZI zl3TUOkE7lP?fQogO@8s&OLY}+ux>fOik<6A{LpEvH0n9&yunbL36Vb}A$ytnpA##m zR{@zXEE|3QhW}oHXh6*{Ux2~|`nkf@y&ut_<7n#q=3ZM|cH{SIrW>o{kgwZ5enoP% zsyuhaqd-dAgOA4OZZR|$=M^A$Hv;p`zB0IOOn9NCfh0M5alPC{F>`ajLsjeJtr1Ea zo2EUJJ!`UY;n^-@Cz`BAr{*_ZHuGZ3ZHRT&5vgzMrGqRi{7DQg%F}DggWGj!Nr_z4 zmi+Zsl;X7>3-~o+Z@;r^lB=H;+*U&#ZJofO9>$spDeaXdX7oGw+5p81DpykA^3d5| z8+pQVlCNT~78*J9^fw=jRgM|H$Ts#r-1}nS`(s@Ft9CR41&-2vHU)Op2jAF|@zX0p zW*^&~7K@G-ha2T`sHb=OHRLACj3v7Z1G!5N&D{&jYqy7&?q67k@sKK+q)n1X7-c_? zH>X;;TLMF-pFKBpB2_)QRSN;Ub;dNrm5K3u$k}JDR3-C8Js7h@npk9vK%QAJ;liwb zong+*L@MdiHu4roxOtd)*yrA~i{j0N^)C+Lsi~|7D9{ZP8hIIfii;P? z?P-nKBYy3s_;eZP6e{akL}H@LYEgmnm?p1F-#~ilmZ5*wS)!4F1jc$un=1~Fp&jWJ zKWdW3emlZkTvcbLn=-z6s=>gn=OT^w&;F=#9bsIQ7mzU-X{5N@?fv)>TzV)&ox+3i zKX~Q}b{sOtU=`pMC4tjS^n1&2grU1`I2pOu-k-W1ek~3%em-&m@Or3Zz?-RY`u%yj z$^z7Otv1}RfLQ^Yxd9!#(IJAY=@&&|a>KJYL8c}Oxiy>F1xB+vVy~AU^t{%T=$5pe zY#(9EvIPapT`e>WOtj#6JZCpG65UIjEM%H2f8FkPb$yw?ba2DWV|U3LMC$L~SFTPg z$QoossXR6P7VwKaFgUzFCu9Mo)C%OPX)|~X;3mK3XF^o6`poNQndWZHC&hoCv@i|}j5s5yk^*>7Qq5EADY`~8LIkpcy| z7Gwofu5@aDF+pz~mejbwS4Xa9TE<=yaP8e=4|Pmj#phVk#TM7qqGi50O3=sJ9xT%+ z-;axp#f%pO={^XgD_ya+Q;k=Gtt!O}N?T>eJ6hl^u=4tjbqHJs8m5#yOQ;eZEc$j{u1*!x$KP8d@_@w0UPema z^UNFlMWvZ`yHsk*mQrpx5*5dIpkWBkgQri(&-dsVFMO10iqAxBWlp%O8d;xTF=Sgl zy3sl^!dPFjC;nqg-eP=M%Kp3KxzrbAHUSvjTBFH0%H6xuZuf`nZ?^bgQ~- zHqyvVmy6L9ve@5f<|zf=m_ErZ|IIp_DXB1ccsuJnXAXLR?z ze*mQg4=nbLocv&3>yo=E@t*I;P*<_?U&SYf^DWL9I(MQv8^!QxydQ+Xu zDfHXs?1pGrs%bm zFE>L5%<7IRv#>^&?uaH0cZr{JK`6sj6{KA^7Z7;xQbeZ>33~8Bo+klDQD`(b~r5=6i+7!^4Ix zA6|c!^P=SStZ0FB;&{s@T3oA~JhHvKD-x2v6z;IQX15NPJqZBaKRne;b3it@?Ox~_ z^ERt+D;)&0j()42TVlBVqZK!KCsHZLLfhyam@_0+zp~<7Mh;GrArFvG3sqK@a!0uo zyM%G4{!U<7Kl(m2!ni*Yo}B_iPtuFS@M1dZekT5XjYs$M#qNgf<^0H0Z}iywb*%_; zEw*4y>(d)KTWiNgLe+>#Q5_yLT!;i$wep5S#s$lXPk*UI`WM;dPF?e(?8jj}VS#t< zY(?Li9Lw&v!h6aO4{VBjWGAlONt?;I_`=*uw^b2gg#-oyP@x9YU|hQbmr8Ko>I_pxiyvCb^>@9v*!-n7osg;0kC?gIMeC9=>u zL=fvJOL5Ij5g*BD1p32zoail*grm~#u-_t`Sr{`6yO>#=8w}LU=YTN)5XKpmVpI9r z$AOQyNnL+aE+pO_8u8Nb2;9^AyiYzacMPV=1kpgx-h!>tVzCjmMUQ?wR`t4@Spqp| zMv1ez5Vz^EfnyXvC_|79r!k7U*wlg^|1NEO!|Q^>CyP|QTS_6!iGk&lzK5K7qjaZE zVL?=C-?E5Gqjfr?adDnRVJQ`qND6oyva_(b)w3TfTVNnLySN;^hBmKk^Z6`T(OqgR zWymv9eyC98K6HmHZN4(sj)o-?BW;u> zUxG{%SNqe$#9k~1dP@S1Y(=dwtstPh7O_uOwb-Pr|84CDP2Jz-YtNdu!Eu?H2*8D? zl%FigufOxFy^d#hfTKW5QO=&n?%Z}rWSele62S|QsNIW($PI{j$YNl z4sGFM!22`7Hcf2T*vp&`&4MOQ+Q%L$M5F@#YRlnoOvsUru1UDxR@D1bP`?hYtp)$d z!q{MH*B&)?b+{}zFg$ptM{H?s4Wqf(t$ooqsySk7YY#}z=T80DB|Ba5)C{dU4{KZi zWDT;)sI6KCm-hD2CvvX?mP(9Pdm)>5lqv&%+O+<2tdh9im1cehC=lv=$B9s{Tzp&` z6#C^B`$a);aC}T1Qss5eImD8Ry?W<4gvB(*c+(O6&2A?fk|Pxor@!?{3wcXf(ptOk z*jOdRV`*TE9;RJ?N}*85iFn{hX>>@&s6sIMOxIxO@I{J;{cs>Gdt@^aJAl!!ME5iTwu#vcMAw0JT$ zL`!lU;_5b{x;S5-fiL>@`4bYK4_PJfY^*^qm}?=420cE?-42E4>j0ivlX@o$IzOBgXlBybB<1kYtdGd#|u0BI1jj%pTr0MHF?hT;5 zn94@^)w-ZJR{3->Bbi0m;sB7Dmq;`GGc5(kJbzQGzo9>gv$UDU*fjp^)!ks&WZ;V! zFy{heqWeK5W?Ec9?8 zhq#M81Ye{#p8v*lSJYZ@TomO@+)UR{Btva@uo7ZPVV&v~tYYcJgo4P`IzD0G>ya!0 zvksdK^#^J6e1&+sJeSwa?$komZjsL=3C#_+p04QRHs{8ZNbFVDHJmnn>xYEE8E&i5 z*9|f|(FTT9D_Veeo!h{nBsS~*E(?@%-y}p>**vG>lM7a+x)3(b-GqxU>MY?;lfp0I zY15>ogaH2WfYCp2{R08ccqMq*rjaadXcDfTfbzKQ2v9hAL7^R*l!~uE*0UVC40>?c zrpo%c)IQm>M(plR&MB7rP?bo#y^qF_3&S2mD#1H}kZI`JK)5o+0YVH3$)7r$w+1bB zMB}Ts3th$u5FoH3>3Af3tJ)W$@`F<|w*Vj^bNK7M!}V3KL(0@J3zT$e>s#Y?;BL{P zp(~aSY#n@5OXC0vk58eXuNO31G0C~AV1n27tLKr`4OQBq z%oxR3+<}@pT;G6@vtno|x2Fe6lrr+@*dr!Ps>E;(i6bH*?o;fwCJ&-KkdhzN86>0F zTUsc*`2p8U*vJG;9Gt@>Yt%TuqE6^K1*bec$J*AatoMsm*QO&i6R^!sPt|vZ!P{Tr}Mp*Ocbx%0YgIUhnMf zN|1><8}oC^(N-!grn^Dd|uDm^tamCJGP(@R@9lceJj=kB$v$Q^S|Ey)*Y@~t!rTwpwBdM2sqq} zImWtM(-30Nu>fUgv3LTqMi1TYtW3PDt|2qCJdmvZ+;fBlls|!f;ZuF@TL>((<`Do9 zb%9{A+mMNGzW664l@?6!VBgi4w)ejG7WKk0{MDxS(1e#BI18eQT@C$mGqAx9FW8nD z@+{B8wf!Z^%A4#pArHm;Sez)px#Mdbc4jWeq1Jz>$FA@n5Ir^K@oI zCm*6fu1kfKET|c@piXv#ZW~sC9yW%2!wx4@e?QZVu z@i3hsP3=9IigIa`H5$cw{{GYI*)+Yf=ADyLC#91h={3X89URA!>31P8!~t#Rtgg4E z5;?B2jewhC3=EKPD;Fw4)17|D&AsB& zWrs7*pF_hYTSe*xb??Vxhx~ltm5X_^ha0iOB4)8|+t)9xxS51oDEbDLkmp%Nn_g6> zirvGky|Ol)O%&H3Rg#`udGs>0H=Bt^9YRCHGIcybLv_lul_dpp+u_$Q!EucJ?U?IP z#1%aa-Q-2`HY_ywmXZ<}P4!?Z4$--815ODWfe)^KLW#Xr=7`7AQ8_KZm(~b;6Pm~F?FTti5{=*gNV+RGYaLWFW zg%Sm=G9~xg%0{O&jV;oU#^b+#MJH0$Ws{@=)jyrMaVyQplI4>wdzkJelQQE8apdS$ z&k*sR_56F&9}evNAP?`Qpx0sdwTgAS`VZ!{5|)AjCrd@eFeTq3h9XxF)P7LeWQsbV z1wXnbb0RCDv!B1Y@(+hmzHJfktR|tFxy> znq``n)gXZaw=PonJ&LR#%?zOZ@u^a-$wN-Wb)lt98Iwv7hUnzZRR^K%FGa_Z#1so1 zdDSwALkxO@pm0tzq=jy)2N-NHwTDA(^=xMrGh>oIe!7oD@r7eI_jlveY9Pakhywq* zP%=$9ytY2H`*h#R@^8oUe_6Zl^fnK&sz_)4HvtP zaeVw9;!%qnkJFjYN-R2!eQB6{S8HjM=S7#w&7$BlO943dR`7R5U()U(mFPQI zuE_?>4Vl9S_xkDOV3WO_(1aI22AHMMJi|rPG6&v=-6{1iD<$X<1iFRN6I^l{Htm)n!D96y9(|-(!w>eijomSu zOm+^os%SW!G*J#NMv?&_t41$YF{9w;;dOfim8<*wE1kvI zWo0pGKpZPue&+~H!F0%?=J|&Us|ROjF{<2?0Vozkh(yuh?6AEI_rBIeOku>`MY_;y zNE$@4&Aq;>RaMgt0&Z;q_o;y5TJx$KU7$XC zaBp1R9Yo^OCh5dp7qHzOiDz=Z1qH45>}qRQnxx}~VpTsUmU1oTB|WF(>A()HR)9v!gjzye!!%*N^6 z&+VvKW2MbsT`vAOK+eHYKV~Qsa12{{W@Y{NF)OF<=u?WF*}z{BJ!N1AGSzT7;# z^WvgBUZ-(=ac^fg`?U98lr2IkQ3_PB z43Au%1Q>4NwGsfl;-kkJkl&Hpg&qlF-?hCl9y?QIOP{V2f#zJ;tMMfX?5f;c$GU6# zN0qQJn;fN(xappdJmtegl(U-c5|Z@pG}Jdw-gw|EW32U5-&^9ho1#CMh<&z~FlAl_7 z7I4=nX+-(_U{O+75@slalV^AKO2TEfAq7x0hue$gQiS{@X+p8-`!aTAdb8e0p<7yl z{?xHyY0vwee|^n=h`9!Y;oy%b^+UzNf~iLG=2^Gw7Gu`h-mD$dxT6R z5BKs#tMXju>6SE*^gp~fZ|?p>lFRU5kkRO@`f+{g56MH}muOA3! zkSmt05rTIwzJp6L?y&w`a0a|D&5cXq&RgNEVx${Rewe5!5^tE2_4TV%4-ThuR*A-f z)YZ$VS8@woXvUYL4Y`}K#eyEz=^XK}JXbbBY#Jb4f{bJI&HBBH%T80JGa8cH@DY$l zJBh75p~2;&wwuN-*y{@Pi=}0&j7Su!xLCnSG#(3R`Dx~RN9X=(>@CtOo0iq&aIyt$ zx25nr9&I1JP(Wd*y|z@n2dG!(Qf@In^zNg6JDV2kwAgzEnSMGMOXJz^(6qt*acwuz z4X_fK34r50Txui@_;4O5Pev6^AXxHK^LGJv4XO#5=CLm0IJ?vMj_IS?oQblAgPpi> z3xje$lB}{DnCtE=x%nx!VJKOoVDa#tX<2i+KO7XXU732Db9{t#`RMzWgHzKAf2Ws5 zEQ5BLwmUcVC`|Xl$KV$Bli1{u_N-)HYH_k?hoopsb;>dG8`q5`lYwsu zWE?=G{`ea{I0Gqmd5+ATszT~BX2#R3$WxjX>0#Jw2db1vko%Om`<5pKSXX?L0V4hS zMX)wFmLom?F7fc@(3Fe|C|nBBNAQZ(3}05z*3GoqtSws-?Yg3hLTqRDhRw+vv+mu^ zw1cqr`E848OMD%q0}d^Q)Jq&d5~H-XcGobfA``rc=h8Zjf=cv71rAE9)cYm^3o=W2 z0_#|yR#nOVw{q4A+LNxp0e7I)D3>i$^+-`k)nke%4)ew~AtlLyoaHD~?mty#9y>vO zedyBGKNYG50_6*6B@+&$(B8fk;8Wj5yjG=v!LV+z$4J9xaaWj>s8XK8PhC zbSDqk5~&v9r}62#w8LIN(mk*PPLNF2H3sjGd?UMmi$F2avRX{HWexAHrlxeSLibv< ztw-#%XL|nGu}0ngn-#t!dGL31xZNB?BU#*IL2$r<&$Og5c#ZL}K+?zjp~Z9Cq>F5K zhd#|mN(u-(v+^xID9WPwiNn;-ab0Sb&0Ul+3hz9+DnJt$Tv2luTOmG{3|n$Sp{Yx1(cLT8%j`HY`AFKZHObMu9Tl&i%)<6aco z)%zFbIwxqdm*VsjYny+|!zNj^afK*u;i-BpjTQL}-{H!mFHlPIuvo%yUQ&e;9_;4z z_>)Aal8g2-<}}=msIaj>;cw4MfDaE}Eynz8*V7|o>3nkc-ow0M;=}r0dU*)KhUw6A z&1XiM`m^6(J$C)TxXLA$a+zk+e2iB5vt5vMs=ip3ITL-CM!z{LeS`RGY_0W^PYPt9 zL~qFzt#Bkgort+Z>|2-3o!Q4jl_T*4!0z1s zb#ZhfDtT%&DrB9jul>{uDc=v(04ESmTDuzm)GMdN@}Vz|doV6-Cgd_M%jS%sf4d8> z6d4V(*{)&&gV5RIufknoNrOlC-+Q>zrZYfq|LkSCumQx%Y2)!S4>CDj5fi|V-#=|U zm2jCzWFYvV5{TbdvsGy+Z@Mw=x78?>HP~?8gDxoOw`q98N4YeVPi<1S7(4qZ#iQKd zjb^Y0{YlOyFTyqfxU6g83dM{D^G0Y9_wP<}J!Yt0>2D1AY7wGReHs2@zi@SDcN5N7 za~R~6$$Hlsfh|5~WsG>4a}cm7#Fw_Tm4j|zVUFI@_nTtcnrkC%>!J`X1;w66`Up?l z&;!wwL;~9va_PXr6vU))T=}5an&zfEQ%w224a5SiN=S!6m*e%np6yC<9m|nJXIp@+ z;UJ>557Av9%tIi&2yF}o*W`L9P^E*~A%bxpyepG%fR&pk&~!hV78131XQmDJ_u}vQ zU}NFe0%0}@Q1bKV?Ut5sjE#r8^XpPr$5Cm>(eB7n)Z^IA`J8NeHNGa-_ zES7r=)bim{Mw}+M<+#swU*=%Brv^2O#^ieZb-7Sl>FB*Qud87{TY+rZP2J~F$dVp- zu`sqNIcvBv_*mj_V>Q|6erE(^;1w<6sXFH|12>^UBcBqW^neuN_|VeQ-Nm`Y$f4sA z_q|fX@d&!NR}x;N@HcY#EsL>}jQvgO@##b(-v-l`aIKP&OWgF=t&W$GMWwms?#+r* z%851>#kw4|9iPfG?S9_rbP}$#YKA<%IyRHGu;OKe^6S_N_=UXJ>y=7aS#dKk&`#B4 zB99Efjn5(|oEX`>Yrh0LINZxrDS3%5N@I`ZPP*0`V+)bvE-aY-y2`oJp%26HoUVq! zTW=V7frdBkXxG*X^;R1J(48XbR~57GZ54~D7q7(dn5g+ejR25OAJ^rEs!`7X7V$1! zOvL`|IhP9pPk3l3;1#!GBib!55Xw!9m!jX`SlX9{^721H>D$Q@hx@jt9BUK;%H*Io?V1?K30rxPcwPSMVA#F=*a;2YtINw{G+0{SUAuCO zXRKGGjG&@0&i9H^gmCdF)Zb+;4!KvZ>#o#YMc??~k_43b4b}{Rh+V)?X8H_Y0fdbQkp!v{|x04%dO{Lzu*6yHIddm+Ja7U(>F3g*D+)T88?#Lv|P=(5e#tUV7>5| z;UbB9+JSN%8**I|LHkG!+*I{&f(5xbQ>7kK1AB_!1R#-nEBf3DHP#LcP+Yu5R%6qx zfh?Vx!&3qm_PxsxFqkC*@kikGSQfOcYdPIT#E>xRL9wQt3-pd{VmpB$JT8?g7IF}) z50$zS4NEj1pWzdgNVb)d;$Ho@&9Q>#Vn@5yb=%9yCHfVEU*Z!}F7v_0&6)D{k;^kG zD^!J}BD77EkFyWfr7whM$Xmk#aoEP*($*$~Ta2$8A2#)V36@bRst*aQ58ezYM`}n= zDI*{^SSH@MnBA2po`nU<9F6WhdJ&?H-)~pNkIC+B{k2zn|7540OO-4=H?A)1jzZ&%5sIuP<&6IZ9vX%k<=-kd3eA#`AMN9M~$4OJEao;JH{ryuzm3@O! zfUD*o&XM=FVfdjziRd8cZkV@Z7vn{l)q!TFHN&Adf!xEBM?R<{2PEnu-!o?_(>F4& zR16Hwz&b{aEAcI>)pV^SuStv}mw_rnA)2jwr!D`sJM8ASY0l}qU%CBbzgLJvsB5~n z8;Jdn#H*^!ce-E2L+YLnWfY(er;9;GrQGsG!|1Hzh@*f2l6B_k?>-X0hqt9@@r0Q- zb)Q|F9=31&<-A)Ls7W=2Jn>JY0`Uc)A2BDyg>JnDWp*5q6tOx;$T%$_#8fUVI=D2` z!J6kyS9cH+Lw!fA`o79ykvX&tJczSOBk}$dbtdbq_P?R^<4>C`z@HVOUJRO*4b;l5 zMlTTX1E|uI)3*m@It5RR&Q^Lu`w@uxe0|?X1?NwEr}u=D$14PwUVVLgsn_>0syaV8 z6PJIFcImIePWKjN_bTlIO<>-AuN&N}|H&ry28&?_-!abbvA~HF)3*U@bPf)?1g~(o zE2sK_FB|Q-H_J_ukv;=*-ZUnd)lQ#u>VI(Q?={Q~+;5jH^ITOng&=iP^WN4w6`0NV zaSDP7qrZ8WEtankxi-*uWabttM4F)S-esNn7X>AnME!Av)lELYKU$U28^zDILOQjr z-g9ZMk5QfZucn@O^YKQ2!c}1YLfOkaY_ajSmGNDR!XH(#0DBp5?)aYNaX$*P%f?N* z?L!mV(DBF@%5!uOo;)mn0rt%^-%fk$-ab#d~&fO9v8z z&>ZKarCI?d1&6;Y`@X|LOGgY{U%b%U+iRrhl4ei}FYzq>6UUV`vtRrrKl0Dk-bz{F zZ~W@Si5r}^XdDyaYyS}&>S3QD*+l*SOw9YHOHv!m|Xvy7DQAlKqP;BB<8jbh4KUNFt*&|)|>HND(C%P4>sKpcc zr|YHmSmHChG}?A(5-ESoobsAKcZRiOj8CUrx&z*wMT>>-SV(eoar@s92@svqL zo-&IsZ=2S`9rlmi-AGRVSNSBRcMtHr#&hNhx@&2Vw`(P9UNIF)lTL}D8l&uEr{|JU zQ(^QR7HWT1^r~)Y_ro^?4BaCdZF$_tz4u>gC;isPr1}2cuAjL_Z54YJ83GdjbbV!I zMPE}hO_3*7q6+BtGQ-!p;BC{JeHtq=r|p+NH*MfG|B!?Ey$|)GQEB0D;f##{AM>nu z-2>7@-n7t0m)+lk5Rq@wtIl{rKni>!^$-0O&5maudwn4gv^SwyIbZtfA5sYdYA@R- z-_+Lbo@O0ZeltqI3dKLU`p5Gb4^D-Ck5Z0~J}j5MbH{l7=uBW#|3?>6A98*^&&A!@ z&m%VZa7<3D?9G4aycqmcrm4cvsh2ZJ?1srE8NGNRJwprG%KMLu061fdCZ(*Y34c)O z6=rGrXG0x1_ai^8&|FK>j0Ydc0b{U9M~BU^e}cYFoL~X)cEO9PV;!Vww!0PW7$!k~ zX=zDVX=sF-r=`tP0)MRsK!*T-%B_gAj1|l|ySp2!nWf_K<`ZCnQra5Uqpght0QS8l z{_mGOA?~NtRw3Ngg~j1kCKV+31^DGhD3sH5Kjiq;8_2N+_WzP^c{24}d3@GXqd}=C z3|Zb>t@MX=`S0>%swiP9W4&qIz}fC^62w23p92KIrQWUQfEUL9RqJzW0Xv+x`dJ`Y z`b6lzQgpvbow4r>?v0ohwfTRpknP*w=@6$y|DR{#yPo%k>x}<@T^V^!Kdnz>pGHzRT`qF=pHaE>;kV3* zZbP4G+1lrhJASQafdJ#BB*RN@+HVT}jmZ9atGen9p6|n{dyGyGPSr@<2~a?WS`2zf zoNapYPfdURm6c<@o8_GE_)bkBNP+JyDxSBF`-pPh?_WKlm-L$S^-`@Fpr4A73UH-K z@<`_l3>B=T5&k^{O{_|JM7oNXPwPHJwf&rbX zIlcL9fZUibAEfoax!k|M`91uU?YT5K&wIwJ!pif3+&X0T*F@_dy8ymAdtIzleV+1S z0e@ZI(+fQtzZ&DRG7?WnTvGVULyeokBG(cJn=$I?vSR)>XuT%mte{IxOLOZ{bze`+l$mAB7< zr1R2bF1`0DNpaaQ1l;MjztJI<1fQ+xs?lOIh z;)&Jh=n(3pEnrq2p@V~i^V;Ml{*%X-M!yYaP=GzXBJ6~@gTX4*jvMK1e0)I|SC@#w1p;7PtRpE(S zt-VfR57KvgDW+jh7|uF^?@2_K+hXw%y%YoA9$J5Poj-aAy@XU=^;nWtR-WV-!_BSN zZEsyT^LAx*#n8k*xvs7x($}3S@PDMQGCqZM?!5e*`HLnYvNX32f-(ciUl9;;5eQLuX_27@xc=08w|`kd z+Auld{}}2qJk8{C*#hLrZh)G-jhuM4OlU;JIiNriJCF5}bW_&S1 z(O&=R*_)1mfyo7X+5OmHSAZh91R#6PQKP_r$1m*+Q1ue$>PBl@n}RCy_BWXXXo_RP zzb$Xah{T@z@oxl_QYDc!lOn|2A8{7g#tY)!pUR_f1&{Ki)fAOCq5os#{%ZA`qQT+O zC3^+%R$ovUa4+Appd$h`Baj#$Z$MkT2p0Nw27G*ke_5*Mr}H@s?F^>g!2K2^`Q;Dc!_npjUv=cYwQR!)%P%YWLTdZ?k=A&iYrEeSD7VBziMr(Q8eplUkFiYNvk`i|nrp-f9 zt>_+xG{)@la&f%>a(Mxhuu~7p=BM+_C!>w-Zw@E&v)EgH)~NXwMc!4Ieo(Ls4F2ya z;wk)1BGV67sS)(}EhQx2V-m(`e&>q#aTa?2O)RWt|J>2I0%bDYp~GbrEkoa$kJ5X7 zKkWTvSN!GkH!q(L{PJ1x7ys7#+i#W$uR!-((c@phaiSexN+#=l@c!E#y8iM6s7{^S zuKgi~H%rQ-3J*<%LZOFKB?5C=gtT?st|U-x~e%+k4Y9bZ5V7c&KUF zNeO?7x#i!cJ6c_TSyU&7CP6ag0lBU&s>oC+KvTEy5e%Xibt+MeX;315^Pu<{`qi+K zMZ1n7xI^R}b+}@OXFi_4#P|kNd98;sFW564i{>)ES@4y|i#MkY9oTB2>sD5;_yV)B z!?oV-J2VZ$4WYZ%e-YECxn#I6^~!U@hQeeKW8vT9iPVpA2_?YuUZ^2HU54!@$H5=7#Dxn#AY)xc6$5(lUzKyxA?9wZu7o3 z&OSHq_ASNR=j*8IlEWsj11D)epjqr;8?j&R4W%#bs^lqyKE+Ect+{;n6iv-!@?s3H zx6No<+ZE;F6 zGGi5ZYEHaf0d!%SxW4t+)?JyWc$vi-n0u%1P4Cm=E$~y+3QZ z@!ihUZ`mwG{K2&sHjjR94?J4qikObLog0%L`=N`cl^bOlk?=Ch?|V^OYDlYX zzazEs`CiKW-d&V%yP0&ja`NT3R~Pkdo0+E<0;ks-qS(|x2z?LD|nW$mi? zmBk5)>j7y?h@FSa5k7QuGvYZ8kP0_oa#y@m-d}pK1ph7~ z_kK!HFG3UiwZyuRx_#T`0S} z6OMclL=xYKWrM-X8K9jNx1WXgM_uy7`WEm_v{ZbwuA<)zr~BUj@*~U2#zif?5w{EW z)adkgT1n7oc7a4A9RExe*XmD>)S3R`O1e&{Q?b~inSpohT_R6>E1fmsav$FAt-a87 zkK?oo+ejZ5Lq7T13k-qZwrL)4a}s4x^zLkXpVHge4VNnR=Z$5!ricq8(;E`ukG#J1 zOlF4k%!kK;of>=Q#D&vzbvW=}n4>wmR+|G^Y@b(N7TF!a>xEVv@CgduRYMqKzT9JP zULd?721_%ZjOo0!t3R&rcyMld5pA;e~=55G<;!BXbHB}}wK}YMrOr=dxfE=1t7d#?r>@xZtktGld zTxH*&e2Dnp(ym%!rwj?|zR%|p^nQ0H@Rpr*-fNaS^;ME4$4mIM(%qN!8LZ4Dd4@^z zvevo$OUBn&ST2PepRlXT&Ys-)%}Vv)N4Gh;*ht6)-1G<_UCb?P^7eII--`#rzAsc( z+`T#XNyTRD?od@OqJ{W-zCO!l?c-jlMSIuzrf+5@(}P((538&W>lsFOv%=SRZ)!bE zG~1?#sQNmb=cL|kE10r}nb)_}+*P~fJ%g>8E?JKdzgKnvJQZ|?cg;fz0~GO@Jf6;s zl+b?k2GKHFK5G<&LSJ?_7c4I^NcQKxC+B+gu}^+u{d#TNIwX7Dz2M1Ynl-;|VCICC ze_&3~{JP9+95Fw&8r5($F;r@FlS(x8uc<3$T)EX|+mtwB_eecuy>_DJ?3(hfFrz=U z+v3G;!MW&3aG&iH7h=DO!_+aeScpZ5lDAG0pZM|WaZ8S&F9iN=w?*T(d+^k8X~Z6z z;-=07WLI`aWZb<_DS{yj9f_3VU+Uj@l=S1X^s!flf3MHay`qo;Rt2kFZj7vLfzlFy zN8WWjr#I-le`fqC=tkzmi%%K4N6}@~g7d`?_v<=ZV2NC3oBDJKz|Yb3oG|4lb}VX4 zB6Fk)5f^R7vXXA89=_~yY}j0Km7RSB`8B%vy6rUE4V^=`F`0l}popHw=9mX@#QYN+ zrzg3(gjO1bl}riv;dCWu+GLt`0bS!Omze*n#65L|b5$j@yluZMs`liGs+o_^U0Yi_ z&tJc9&P5?tFJ8DHrEG|B7cCSNlgT&A*P~xtXHW8E7@3pKh;y4&`EtcJT4i%%BTB`6 zEEqGw0aWYra>ZHDphKutS>78e)lbwHuK8H=3uAONrIU}BYbxYYy%uNP+b@P!IQ6QQ zeS@l-3{Ub4oiUqx5bX@OEyNi7VQrcqcK4B~@Uzm^I9{t(0b)-}Rwf@U#o zTW02$^CsT%iDWgijYrnK6*ST>sAyQT{?V2$tlgK`s1Uds5H67es%)x4-|9q#r<}No zK7N3^UbJjXr%=328wTap>^trpk6>}Bj+*9NE)+FMvzV4DIXmr>fl&U@E&S%rYky~x zeuU;1;%5}qsG)Y_gn6Q3e6D9ymc%s-b)&47{%knYXzB~x?%dMMsXXlRvn1I4;09J7 z5iY$Qa^z08@RBjV%)HGU*YOYPg1Fs@xgx%ENBnDZ(7wBm5`>Fj*TKplW)*G;?&9G? zQSX5@i~mXgk)L1HKY=@`0efFWjpVc?tVzMtoL@3@ZR+yAiVU}mq{zdp~kPO?^l$eA_QF z0(@>8X7%M;d4?TC&zbFny98VgYQgkhCR4kAH=Sax;=}O1W~l5j1kdgI7Q%FKf;O(= zprkZAof}=}X+>cjc&*9VyH`EbWLFl4eqz=`q3#0%I68yc>1g)usMBIzS~+fzgCedu zTQFk#39Z!pGm*M=ZL;I|-$Vc@4Jnjf9p=Ae53U2Y)d24^UM!29)+gQ09(F`m=T&_n z@ZGWs%!TM7K?6vkRlZ_;OJ+=bQT~w#^g%!9Sz?5w-}EwOI;rSd z9yIlxsy`Y!y_PB-HGUHYO8ME4klQ}^zbuZ1{M1x^>(*#VwvbyGG%mPB2H-S*9}|Z) zLleJhLv!gsgT0))-HN3;oU*vcAaK(n^|Td*+RrKXDRVw2{R;|)p{qNk$x+$g$}yj` zFGsm-`Ac(~QOP*Fa2Hl)`B?mxBGanEOBgG2U}DpFm4-Qiyk33Ou;;n70US$-p)c>7 z7?(lmOrkU4HRj&IPwv5-f5veCIZ?~$Ej5F3 z>k&08V^{9tMmM(?6!qeaLr79@7pYS+Z}(rTJ}AFZmH>TnP3D)o4K zWrw;Rxjl#wkVmIiO-Z;Nua7ZEu%W$Lrf+v}Q;g31TuT?!{KF(H?0g~BdVX@6<_A3L zW*hWpRO&x;Ej=N**D-A^cBjNH3b;>}u!>3BEZT^};q_QZOf2Tibnfta8=<$+msFGa zuue`$WNqWHaM#2;R#7qYKdGxt{Ke|3eM4lDM$_F-t{Gm_jN8|DNOK95x9CgX#tF_I z#oN!{l5OBixj8W!J8G@hltjGyLQ-7MLNj<^i`+?`_ayzwg(XOlr%FX>^aA(wn-Q|hs&lN zrnv4K1;w08Etbbc1J#$cs#}C&YO2e`#1ZZsv84+94kNB_Dz%(y8hK)4d`T%@P$iRl za#U8I652cGH@FwVKj(~H-az9R3xedSbZ_@DPv@nW=zjO)e~BaM%4~T%ANi73Qh7vS zmyj5XPE3)Z;+$9<_QyoR^>`h$JrZpSr0tMNRn!hzx$6$;`corsyq zOOY2i8pn8MLQh20+(aWYGQu5M{Vb}TlHbu`sIyw)d;l_@cB}Xw?}?Y=rW(MK``qWr z$V0IQuoLHi5wl?>ykDeaYKh@X_0wj7(pwHDDF^d`pg+9O_fR# z3Arq#@15YaF-)EvAto&3s0GWtdXvCP#et!vRaAn)Yzg%8WYO_$IEf&S-U?yRY^zsgkfxYjLI*QZX)1P+T)Z=q{t$hT`qj>-L-9jhbEpyX4{N{*Qs*q?5FSGz^R|rItS@g=kdoAg9ke-H;0S|C`CL$ zqmiw96HeTng(S^*^TEAMfM4P=T+bp1e=uq01yN550d67L?#sd*F5OjBQA>@A6re!w zmc^~k2yT0L97C`Zep2yt_Q%AKWw75)1=;zcnb|sM-a&1$SfhViaLC7zaQ zle@2}N7srw*Z8=VQ%CDvW}Y^&h3cn1OYtA+5)O4Fy002lo|k`VHAU0v+|trH!F#e? zH+g#DTtUbB=FR-H=#R;c=ST>YTQP@k*8U;*g|Zw{rm`<4iRET{z*H~_5UTQp;?XT^ zWBS(NdDDaxD{Aaa?XQM-V6XmdM1!+*$OIlgp4Nka3!Fe|_p9p)mvTrA=HmZ=!2&uFFj?Q@BXW8JB^>yM7q9?hc{od`Ck9FczG%Pg%JhMc{yCvg{H3* z@l2nKHj$tbp^v3DSmoq4v?5n64uVRq(cv}zSM4b!B<$^vPk(D(O_@Fw{q|GqyhCb-cd`43#i`0iE?i|KD@B)Sqam7dl=?hYc=-1XB@CPw{hdJ$Ictv zH-CZ+Z5v3EMF0N~n(W;GpSmsimCeuiDK2L+@7R(6uQhnN>>*M*g{f#sXvp!mk zYuzLXI$v@3Fb`6@wiBw(d%z18z@?!f-mh$@&akbJP6qhkHAbOHSLFHNGWa5|`Oe24wjncjjNH zoyv<%`|{;S$!shRcKTx=P(E9hDIhtk?z3)8Y_*a~jKIV1$w{GyCZ?qUcbrrTHw=7b zthar`Ji~uz4=KJX#o?Y}$??se3?@GYpjS2-TY(rx&~6~jyTh!2ARsdfmPbEd3etLg zK6rUxAw35LoXcyZK{3e=8A*b>sB=_|3h@(U-YqNrz|%Y+{XA#df|=iaT|M)XU72$b zxM14*6J?Hj_(<)$=uPx%dJ!v6 zYA&l30>}Fp9oGdZUCU#t$KHj&H-8F)#eOjh)Amm*TF4#M)f5;To=StmGW_7{C{$jR zsYc0`<7~;>CHiZ?Bk!C#w@Fv(#pb6uJ)!t+64&HwAG}GbMNQ6{C;E3^DUT1ELhzt- z*+qFw!B6^#-=%yPEdp5?s8Fj}Y~?X4<1Rj~UEYXytO)ZpjlSzv&MeS=E07cfp_X*# zu_rl@+gxz7RCUO?gl>#?w_vcw!~=r5-#o^s$^hPIQm>0=g{~Qz{fA!}b63>dJapot z!GuRuS~5%+{2{1s+o(O~;kQp^dwt11drd96fvu(2@2PbiQ~ig?$VjKju&Ag2j$IBS z9#@F&z)=ADg%_pKA6@;}(IS*#Lj;dr$Q2r%-W&f}<3F0JJWw}KQmP)^4F>A3^>wm< zUH#>pO6|O?2(TH)P+28jk%%+D?f9s4L3`&i%3>4Kf<|xA+}((c@XfW*Vk-ki#>eO3 zZ^H=>&M>_Ai@Q%)@LX?5@`KJ_Bne$NgkX(mMcmUI*VUF&q}FoX-y=4+x2-AIq70VD-;gD;t#s+q)6JnKl?&21zio^2i%pM4wuQ}h&#Dpc0g>TJx{*FSG< z?cq}T7O4I!Tv@sFo^=xV&6(_!VI6yN*Nk5wmxn4AxMW@FZhfsl;(N6T>j$#Hwb~u% zj`%2Ebo2~#Pp^e8Anx>|`%IkbI|>L>lk-zUp91gGM2)9D=)@Jh1=a1UmYCf5kU8QY zmPldB@0g8#CNVsk3qoz&`qx%PhR4Shz2kjqAIdSag*ebcj(qgNgLf|e2X*5SPg(FQ z-aDB2Qp=^8vB-wMCEO^B?pB1G#G$OayfsX|u5&%3305Hf9!cS;NN*6_!$SrVq?S&L zm{j?QqOnsoxOR`;yI|%34$OC>knbKbTJvvnWuWIr_#Sn#fs-#}ligl#UDPtWRdM~BQ%1k?XWDbRRUZZX zn-rN+iZD|57BDjUrfq1Lgv4c<(us(4{8^bD!jv%~AhP_bUE5tlTI#>mKBQnE%k+In z%?rQ6{lQTGb5!=JoT+hTRTfPP-Rst8U)8iOF<96oC}KJ>LzJNAkHzQe`SP!pj}8CE@lu08n*f zkVD-c^)_65GYP_gk`SNMK$Oq`Zxm5OeGD2AC)SYQOL0_I8)ho#_T^Ci;DlZ#!@tIZ zQ|67O?J}x{>@he~?~sGHWMVWZ+Ka=&Zt`0?N8=&`-=RohhvEgU| zNajtDK`PI|eEA7EmXVtBe?}-ph33-F+~6YqoP>nA&#XnB#5UFr`RnvI?+XZb!m@eP zBQz~#!!w^zVkZ@(KAruyWkP=7|D@rg_VX|AqNDO9%o9mk;&)_?zulBE8l{+7Kfblg zAWIMJPt|GKmsVD;&!pG?KL>+>^^iK~VncPYU%EmEeJrapY}v=|docdq4@WM0#^9H- zR>TA^j@AW0E;C^O$mC;{yu|Tg0mB%NFyevP9mw6>#j|k^@9FCRftq|{|5XLqa~tZc z7L>4)%0=0;BF9@#M3mY@qNQt4u(o0{B@r@Aq%j-#LEB6cl=I`W!S>|+ebBb1ajN?F znNPp{RORH#L@_P;6&b8{vR#v}5(r~(vANM#M?W%CCI?5t)@}cQ3z$k?a%!j+KaXsy zHv0CjP5*T-7oQaSYd|^8Bp`uO0zIJ16s~^3Sc}yuu{85YM3`dGP>52U_?|_i;RTgs z5G7a7Jq4B#xtExM@?sc1T^n|&-?@hP?H{wcnkXCP|CsI_R_wpZfUh+?4taus&epbx zvmu`Dl{OMNP0f6Ud^cw)Hb^9xgZWmK zI$$Fk>_RK2h{i7Ef3?#qt2tqS|L8R`CyayQ78`>O__4ETP-p(?DxeFBh2jRUtPKN* zg6)J5xa}_{jprl&b0(3W4|W>y+6BmQmMbH)C&{&SZhra>B`xD33y6Pnomo^*JI$bg3Oi3%)6j|kYiU zXGt`Vx>Ab2Lo)xSkHe}SrN(DlXkmcwlYjgF`3mIvE*2|@Y;*ig8!1`H_;W4xZ>9~| zebXOYGJpo>Z*TSBGPJ;6{s+zPvYq4NAQaaM)WnJzv-iYSouM=B--k9uh>W!0FgtV z{ohZFInYfD+#zUjS^a$0eH$kOFpcB;`-eUCE(JwkK#Ln1J_JT~;{JUHV?J!GA{Pik z_cz@k%%xALFO1-qPXGHB2-`mW{dCH4o*(ssWJKe+|L&_~kc#Fn3-ZtDu`d`7;d8$(?&)O-RTeR010wfg z9MH5$g}ScCn$i-cl+|_p&w>`|O#Q1I62@ly#A$~s*`*>~$kbFBW* zukv4qd4U5xj-}pykU`pv8;GAq#2_w*3(^YDNrOQ{$QM04^7Cg$)`FTEJyi$KIirVT zApca=rDQr={-L_PQXRz3rP`*eYH7lcEis3?P4Rc_i30ig@;3zz8y+cfCDkQfL~dTF zhX1dtTGfvq<1(N9rR~yvzwELaTy35j}{<_xZs5gg&jSlCd-H!~W z4=pfg#Py_{M%OdgdKMi8>acjjt8i`^J0PaQeMex`e0)vNRVcj>Sh#qV%2z|sw-FdLh@pnhW!kLYjVgS41PQ$>ob_2Tgoy>8+{iy}_0htiv z1=atJU(ZUM#lyDKUQ_2YIyI2QCivS~?fsZiic6OJl>C&#dyZui6lvn5Z{@2!39=5P zoJ>BjZded2e0S%9=)4?uYV2m8`y3;mV++r?5KL2NyHN#ZomQ=s2U&;H&dYL zvCU|O@ct$SkJ!(%v6aUO8kMhN4-x{>Vy^epYF~NL4*M+$h$ykvCtmMT|G?TE^07Lb z$6d_TUp<2m=~q>p`s0`oP!#3^BOxPPJs1Efce1^*`m|{_Ww%B)B?)v$>~Cv1tD{Le zpf?$p^!zzF>Mgug-^}2#GwQnsZpigN(Fa>oATs)M>v4QdxwS|z|CBNzpGzsvf!bV% zJGKw(e!?a{#*}tS+WfI8^vA}OLC_GLJE$R^+eH@Lk|BKatT;M3lt8vvCq?Ai`GemO zaqIQZrI_h!2~8UW3;TyEwAImS;X8zi1v2{cU9LR1Nwk zxToEL6dE~_c>PGk%1&+c8uJqw3rytcvy`NqaE{Y%1pN>6TqBnOEt*h5iEcJ!(E~&{ z0Z~T6m9pK|_neSqP-qDHR`8vv8Dp1Jc;7aGlqHd^SrCtXpNh)}ATlp>2_C zSv-nFd4NQeac$4DMrK=jPSIyFAptk&pXtQ~Uwq}`8W{9_z!NeNAgd2(u|R4n-K(=~ zU*2{&v&1=6mtoACMWl(YZF$??l{1cwa;h++MsvWAy>mB&T?HZ_$&8^A+AFkvrYLVk zwQTI)T*u&Ll%{^xhC8jub2u@as-duB>6g zF`ZiSPjTXJ2`_@(#0cw+C@?=RX<6SxY0566THg1n5@UDkAs>J(#M8mQOzR<+bvSmE$LC6!pS8|Bj5J71&or+KkSF-RRt_W2 z`)V8H@`q@(8>a}Wk{io%IUVS6cw%i;02uval-SVOFPs@jV&h#s`cRPBi1&(OfBT4v zQ(9Ike57kmi{c;4>^r~pdG2CX(bSaCv13_^PA;(rOEqgkp?n5fOWZu<0?lAh)Y3JI z(5rqmk7j3n%0=6YW~BxgES5>w?~*gI7QxY}ZA0@+Rrg&;{|iWjtyR!eGN+Ed?UX7> z^mTtd3Y*!$)lh{$y_~ONp2Xmq@Vj^t?S%Xbd{&f*q06*lWWgN|C>ZC&-iRxdN!tYf zS{#k7RT~VXHFT9;+RW?OKhQQRLlogIG2_O&b<$k&F*JErX*3C?7aWv}n!fw|t>!ZF zC8JsgscLOr*cZv9EM#>r#ZDO+RGxZxWv&XF*H#~jfQRngXGYwS`w9V?tjWM=yV2Li zNT9b777ObkLeB=J0$@B+4kAw%$B3^n2(RdWmQd@hSN)4hvnwKKsX1Oi&N`nx+I$`y z`m2pXlxa1r&n>U-f)2~V9U{vjvWE-!sMC}3&|7^;SXI+Mg?}E(RV~XmmO0E|E%Lna z?1pMWSs%`~=FPSqwxb#0#_KNN`8xK17IBNX5CNc1TRlpe{zlK482XA2*nXXV!CnK zGe8zfP)ZVo`mDGGl4FX~gHK3LHUev%08(l}&Z ztGFUAp1pf1RA>(tyV*H*DWA7B(2JznnibMYcoJEh;c|mehG`~Dn7#!!s&BgG0 zc1`efAUYI51{KPu+}-9(0dSUv?c#2y6?t?vp6x7Rd+ej^ztS7$Ya_*w3c<^Fek0p) z_aXn2vi@pP{OiGQ;hCd7{cNEKawe4YGHSXD*Rs2Z*JIt;A!B^4=0A)cg(bI?%eElH zAROIL4#Y)Sopa`)D&>%#_$MJjeu|l{lwIBLm*)}LG$p5Q@cIkDq-EBxE>VKO`7?LW zmYhrH57Z?#vwq*4%c&IsQ=-HvI|MZu$8YH`cNDwSUa*UG%Ry5ltLJ|pIZA7TUt?m# z8D70oR(%>7iDraV%3!{**$nrX_bNYo_$HAWAN)-5pAekO%S0puhclmV4eyD-WKO)G z<*w9YqRCvTyCv&KQd8JVzUF*%CO!Qk-+EtImOygamH^ceofv1&4aanj(E zAK6hOjB0tC>!>u2c0B{<#p2^Fw!v4IZ~w zvK^1%EkOpaBKfnM$i8F*T{%_F{-e*ROJ`lNxdOm4>EF5ubT!B?#dM~#+nF!3Bgf|| zb2@65xXrYO{E2n>Kv-?w&`?gL+GNSggj@mQkg|bWCZzAoN7uDhj6eAr%L;1huIQRuW(ZJ*0n`{>X4$8 zBE=d-gL*xpXnU?y$jgB|Wx~hpoFZyg_mZQgvd(T5uSvKZ|Jrzd%RC;+sK9!rV_Ebv zsiz$27plDDgI0s0C|xKXVk@|t9fO%iUIj)5QFhdjZc(LCDjFBuaxO0EwYBlZ&Je0m zV=&iS8#jc{@iw>Prhm4CKR;2?+f6Hb8LM579k5}vcO{^B+OY*MaOa<>!(WQ4N&o*4 za)>M6@*-u(W?HL7*tUhubvSU3jP4iUc49%*#y2oy;`qnlzSZ&~&VW4nTQ_^bz4dwt zr+SNVPTlK|*PH6G# z=^x*gqPA}85`TETZ~vPel3B5?^MjEKt&t0*4_7zA*_2hB|ATi2Z@XN{%}Y70nVNaM z`kGzuM+i(*d+Yq!2v5CS2fBok)6@5@8qNN_TSWkjeum?{Nvn5KRkAGb_Y9B2iV}`$ zjJ&(nlb{{FCVsu*q63zXzW1M9I>81<%27 z9b{&4Jcyj;ACeqwYT|ME_- zUiZg~l2%yWpb6ja>%H@6*k&$A&1&j;l-VY(1!kkrqFKaAk1&KB6+3V zrL1F&_-iPAQqTNnx^+~j+3%HcDNX2^d}eeEw08!f!>4)DbHuT!XaZql|4L!kx$7Eu zNZAS75))pYG){u~`d@s`Iq$I1N$iH>q8}bz z94%Pf(yhsMM@&LXK@E?N z0rE=onpr*x-~VEMt!VUZk|Y^G%8zg>W72!CJGsp4p630mJ28o2@@nXNG$<4a zfL`2l?lfkCkM|=Xj`H8`mgYJ9V7|3mb@8C%p8|7&5jSyYDP;pfO0hBJbm9_hE^5x5 zna{AWv76GT6{kYJ5v?YBm%cSS8|pcY9$u4jV^bCZXd^-X$gEStgJro29a;W)YbNOy zFf;Ed{v+-Il9{yL*Vorf^5>6vJ0cUNG|)PzLs+T92Oz=d2JO{Zq56{p^CjmOwIhR` zVa%U4Q~9xtg^;(LyROt-saZ1(y;75~m^)5DE0?^Ie0YwN{MK?$SMBS!@V&PkS}O+! zA<=@zfOewo)0-EZ*_lx>1U7A=G+vS+&z~pC$VN4EVosGW=0srG@#zozquvGt(G`eO zQ8|@uMv2w*E?Q_mzkr2l7?viRy$ml--Q@k^ zW9|p9#=51oX7B8e3kU;oNs7&14<;Zga?;A3buTqay4Z_gk@6Fpx&^yM*$;sWCh+A_z&-5@sQn+}_TpKk?3FB5$!b@P@;_3L}7KTMdzEU#RI4H=ao8 ztQ`h#(vgIf|4>W#CPHWUYFGH zGNJDD1ifU%$2Mb}6sG!`a%2Z`w}kr&e*ll3`714w|KA!l|T;QTp= z`r!=N#5fTX@QAg~hNv8NMN}FvT5I(0V5YEu8mW*6;MR)040z<$aT}Dd9f=Tj3nIA> zzEY9El=YkT8vr;f_{eZ!r=;>&Kp5rN{Qm^pb9-HeCh?_1mnVlXLSA_&ef@&jzczl5 z{U~J+aQ7S)e#_!w@ltkM(elJziW<~O=RFTM31k&bo9JEiGb>rekx?27aTc-eX13Nm zYEPDg8>y-AuU2+=tr{D6R_$jY#HS?TiNgAoT(Le!W7G+W?7;3Kdo=-M-b2LHC}wqi z<;}Wj`K{=~iW83vE7$wmJ3#%i;J0@C0d`HbhuGt@Z!v43@=&vOPoYQgnI1Aj+M;C? zO{nI$c>Uu~P=3H#mjSQT2>FIX`Es15X$Wz2pdp#!ieaAS5%qV;3I3S*FCCP|cng#> zP;dH>X_4W$cUhqDEslvxO{sfJ_BMNx@O1A~5Z-q5f_}lD-OJ&%wpG(Zpw&dl48eYJ zm5zyE$ek^|BPGL^ibPDbgE#d~mljQL9EQZX^NI;p9}HtoH3N(TYp-G_1ha-PPvAhv zO}=Qn!>>Iq$c(R<`8cf7qiPKj5N|A%)YB^TV3`)`ntTSd`2CfSptj{{u1fH&1;!g{ zj!7w8ok{ZO=huk4h{c8wDN5?#79pC^brXIxo+F z#5gfL8kR(s6GNMS1%$jx{-^r3yjOYEB>qk1&)0@0#g;*zV*Cy~7w7?{f#xoD#we6W z#|g=qcwl+v0We*j$OD!H-Bqt&(ZS_=!rjf0OQFJRLwo;&6n^lBgao~H;;BcdS}?83 zUrO62B05R2g?=b6GIrzv=rtbZmg2e6JR+WsLcpt;6TKsSeWttd2R}!9OT(;)gVIoi zCP{BhUq5yw-=}a|+axhB!QYcl9c279qL~V>y|b&Py|83IGF~4=eH((zPFD(wa;rp zY)&a`NO!LNPj=~$Q$ms~{o+CMyWs12TSDR*Br6M#Z^G4F)AQD1=O<_$>|r3%_R*V$ zT21=)r^q6XryKxe0D{RIp@sG{`bI86AX2UUB!@$W& z9&B$#iP(SxB9Ejqf*LPa>&GF-AO9Xxu;f3 zi(GoNebI6L!a~-DL+edD_7|e6X0D^VxvXNjYUE#UrI>FmIQt0@j|!5Vb3=oVp!eid zE}~C$+=`cV4HGPzgGEdeegXx-qzR&*Z9jaftP!Kx^f^*h1Y?ry?R$r&&-=`ow3QGI zwwyU77lq5tiaxg`ZVs_60@-Pvx^1FG}0{7_)O@7$eTSo7w<-ojvr^$%xK}iYP;3J;|03c-ChDA82R|D?sPqHA= zqvWLO1z#96m;NW848bOKedDugSppO_Z8$&_cd#%HcuSosrP6xDDlhYqG5zkF-2|5p zPs+#6pR06NWOp6#{{HqNIWtb2goG7b(2{r8%2)56w2STa<{D}M2iO#A!_{_vEGc

&i;Xs&ezcQ>x=LB7fr!>5sgB3wRf6k9^FT;9cFcXA1=eGIAStu!q`BdxMr}oz zkST^;XBU{lv+7oqwV+v)+|!rr77pjiW84W+b@z{P#225F0&AQ+RH9!1bA2#sK4e=~ z#phlJLU!3|EkdPwdQOnwPmIF5zNKq6@BEyQUk*TQUB}=GgGZhgu?IZG$5xPONrGIQ zPvTE?5m(C4j?L#-l?hx=mA@)s|C#0_;>qJ{ose4D2ZN4BuD5UEF^0_2c@K=Nn72D> zF4QNb!!unu#G`mQR=F$)pYtT&0QigKRq;?a5fB-#ZZ6AE;_lFx)BLzosd(Ca5(6{2 zBsUzj(CH3fv~Cg1OxdxwMpK`@=e-EV^q@H~mF>&X!lMgh=O+HkB|~x^J{I}exaAp?J2GHHIDm$UagtD2t;&K6tg*f>39r(iA%Yet7^Uw zO1)8V?PB8$gzOHPuCedE&W7muG#1ZfQMkb`$~3-GxFM#w2gMm=ot`!-5 zSofe%N)ldBVCfu;c--uo?C!4t=cHd7M<$A0d_op?5-)`EsG}Is3;e*Gx=U>V^SbHP z&ROj)nTiuolyf@3^FzX;eK;If+9vRAzgE|_H~S+jXB6tH0G)4MZ1Q1y6QM|NWl#>0 zGo;Il`$R0YDcyzuCrTn-f8dvtUBWBT0U_yj$@zm+XF*9Wpt)VdXLTxAp@7e`*U1Sw zqx4Tg9J_Hga7rJDYX_U{N+=#{Rt%$&M6p5R+U`Ve$J;lcj@z<1VXedHfh)r2muUsq zlu4UU73;i1BUeFHpU1l>^e5u@GHX|i5@_foq5*3ru`VFBTY&$#LPn>3Go96s+{H{# zBZ9#Av9qU}k+U0ZKZ$o$LEiQEU@5+7U&mQ+6bESbuBc|+v}r)2uj#kF7b=<<0=+gM zupj~ZtWOpk=ivkqt-6QB-<%wu)tQ*AWeTVujH6fXp8rTvk^S-xKd4Bdw{}C3`sYaq zfxTEtVy^LmZ{P__eE)9;)>82|H_sk}AnMMm?S(`8KCY{=shN5H%pVcDTOhk%@SHL` zgBO3+;$3THZPz|kYEs!ci{Uh5)IUU!K~CXp^)|<^Pu?ZD<%Ad|hiAGomN30qRE+*) zQB05xpp33WH#fH$MqprYMscCmL7znd8HXh)cJU1x3wiUAs1dBl>S!NN$eSs!b?E|g zZ+8Jyaza^URD#51iSH)@NycxF1HVG%G5Sk$>^i+Ax6>c9**pfnR+N6UUrx$6I|*Np zsaK*&NhmiD-3ANh%vMY|Lu<`;62h+jZ6Y<_oY>?S{691ubsdI-N!r5jy{gqZB^;MV;1V>{OI z*b~Tl#i3Sv_3BOC^|o&Ycwy}%x{e~te5#zqDz`5-_hw3aT^AVvGv95?PQoJd^W)F( zW7niQ13L{yWD589!;j;8A-MnJqnY22GHiQ~`wQ!dQ4<3P`=$I)c`e84#X6pYlji3z z>*3Lh&|Zf9h-b&~%=4PM{(g?3#HRU?NoN5cfyO*TfI=T}qCjynGg?{rWOyxx-%dar z%^Gr(0Y>kFs&bUWnW2{}LuA@ttqAmdNzewH541*&nU0IOFRF~)55ujuX<|ex=Pd?1 zjS@T_fk-G$gRR7NwWv-tOD_7`9=p!>ZM;*8u;i-;f8*~EXgW7FW^8GA>TZy8 z(4!{_zn7GZ&RG5J&6}V*uq!|Rd~rnu;UPbd(wUDuvo#>4n>mH54xHh-dOP^CTo2uuDtwp-6w42ecO~8-GxNQ(> zfPjqM*C%F>XWe6*r`;jrw~JSMV~dV4^47J-S)bDxX(%&%%ImdVYS;QsQ=?p6!ak#u zxCGGTyKn=zUJX-bIj9BZ9b6NGBm;dyFP{j30wLh{?4{!rPB=bkVybnA&HIq;(`i=} z>C_L=oz1md;~5wUeC{gmgn^S^vDRf4yRSA}hRn!p%bQ`s0j<(Y*bjFsk#|-KIY{AUj&ddynJ-V6NrFPmb9W)8LA5|nrB}+?QbX)X)5p)&Y zL!9`mK>yTw%r7co-0pok*kzqH^dcr(3G2x7L&ry)KK(AR3}xB;&dzLk+Qvs%1omvU z2{X7kmfFfRcKx-hzaCTRiV$!OyqRo0ZaL-_<7k>ZF8c`RO5J_(qXd6u+J+Dm~<0H2IgaG^qj>OKpG=Kzw);w7cXOwBrj zf{HP?sOT;R9@uX2`wwO~2g9dA?B}<_Wr1c9Y!gaHo^)%C+g$X^DERsK?IvaeHTh*j z{VThW?J3sKU~hYxWN}qF|L3Pt_$}KdWT|7Jy&bh7NmkzIN+HVG4Ld@uk5lX0K+tKw zx9s*hgbXb_dG7^To7 zacJn)EAeXa2gpN`E3++h_~Q$x^I{aKSbiEK1=^BG`Ml_M2Xnsf7tl2N&p$$c9IwEU+_PdM}xmNrNj2OS-pWQw_0NbH_9 zSz8^G!ePhAY7ez>52nrDJyi*Np@%B^cXqD?-9&y$c&eqw)!m8cP+eUS|APqLUe>}D+2#)nV}7sX zB_7njlT^$Xmn2ou70@8}|1F-1#~`RQYUKWJQEUDu!9QtS$Pz2jhZ0aaB#Yfs!S z*s~cjtN17(iGX?fRZb>zrR*2bK4)r0G}@k+Rr}V5W(ZUB0Mj{s!J}#3Atdk5*QK@| zB?9R30=9TMA2wg>dO>;4a;PjGW`5oQ6*%TTlO7Y!%!~4W0|q{&lRy$Rn~9BE3gkNG zoO`nk$z9IgN)q$1V!Dv{*!Oo&cC1bHr(wU75xL~LxspGM`ZhF+-b$a#)rKk13&}_Yq zV#-dX{yecqy!bfh>4&&{8=Tjs9fkjlKFVtL-swC(utp}+C&!u}tbJEe`l&4J)y<7q z`2-9tK?-|+cYCmCauRKUtd?%QZr5eO4mC^B94LQt>qZOAAj^%cNE>>Iq%|17Qhur= z0wZNtSpedE*c*Y6!6uW%LnIGug9&>=^62nAvd_Bnzj3e@hOD+|`tdIP=sXj~GVC5`X#5 zgXO@GN=Q)<;am=^pL+yKJwni-A~_U!NI}(zbJc%soh7RVsr3~T9lh0%&39NCKqKqP{j)E=l2g{Vi(n5-P!fL5QFVXdwDZl%rb=F({&!Hfj&{-aY)6N{Q59_q(K8JC zqK*4mnO#%=MX}hx%ZwMpE_0Fv?4ke1*~eopekk%Q?|$x78y-=xHU}#2rWDw_Xe{pD zLH&k0zdr#)_p*uZk-8IQJaVY1&fkD86(g%-t)Rbr@*)PpwfFf>>_c3CQT?50Td`y7 zcHriFNYn(^&Jq7s(R_< zE!CSb?d*`dof>1qpN&Mhix5^xzX#Y2$nEUcqvRd3{v~y0c{xS7Ew89d7h8qxHrQtM zfpYa=%O@~{mx$G9?wDN|>vD6V{GK~0r>8149TUvi#YymIo&4YAWm%b`)-z?rC@vyr z-h8OW3fQ68s`3}QQ{wtr$m40_SPt@tjTij(W8-|4Pp zdL}S1>bhH-Le?Z{_YR@Ex;@>Zv;UL;jg*H*AuYR$q%q2fgp@9+C`A$1+_{dfK{b;& zW7>N<_PlKS?{KwiZBlI@BCz_vq{$^GE*2GWf}o zL0bc3JrrnZN1Ng?4?3UY1Jh zzN!skKekXuzTnT5-f=VlzdgX4Vd{Jx}J!Z9rljtd8V7BW%v(WaR2^x)~PNe9x zcMo^bOu~)+Ki1wlD6VZ=`%Xd#!8O6@APH{4JrD>%f?KdggS%@JAh-mA1r6>ljdudU zgS$2EG~SIg@^$v!=iGhXyYDMi-}-A6)m6+|YpyxR9AiAc2lxo%z0!|7xdJP$iSG?T z^B(Rki6+2s!%RJC07$Iv&fDj%KM#D{rU{x>y)*O#^?unJ4~lJ0t52}+oUTM2?tW=g z2Nf7^)^Vvf#|E@{B={*o!t)8IdhYUXP3N+O8kCW8BRRswRfGMrArDV zcK_&taX@zcqkN3%<-O#r4p|YF(PA1?SJjl9iH|EBNiAUrmKUtV#&d@Wo78ne{?xA} z+qL4{Q0*B9yEW)hTR07;_#R$JgtzOB;O$s+JY*)1nv4RVV?^)063re`41h_9#Q~^ zG-zt}BUQHy!wBbaz|MNi2;bWWx0hSM)mTV7U|>3t3}Ts&ofQ~ap%-OY%Ks(_jcc`I zX=SC*kZb7Za>QVZUbV9AaP*k;{+297Yz97731`RD@O)3F=wkch1(10Y8Xx*1k`h5v zv9t;Ner#8S3gF~ldEw;To~nFn$Q`Y9=;EwM4b3xh`!FwzDn1b$iXoY95mi@RtD(nZ z5NO90+7tQrZy$$cMbswnTS_`l8=}-?(uPKFF`(Y8aH_qFa{yh-+(cLM10pWxAuk=@ zonfcRa!5Bd#E$}Uxpub#1>O>A8~W39<6?hY-~3j__&3r9&i5$Nb(;JK!s3G-Z-nCZ zmN>_rG4ADXBjPcf4$;n+18bj}?5@l8QkXMx3Gz|2GiJw!=}WA@PMI4ZxV}CPeG<$J z#TH-Pee!6>rm=YjgFLVEe|)o={y;TVLAyO(U>fMQkaR~9MOlnnD6nC4ZaC2ONUvkw zB9OxmuRGNNJl%*bgt0(rPueC5#tB@j1fN$16Y10J+SuZI$Is!d72?Xi`&bkY^_-XT z2y8)BcNoYWO$HTEtLOPzvBWLz62K8wQ^{h#@KD+ceaYPsU8_vQ_*^TW$h!J2NT6z5 zbVKrrUv(XfYhZsU6^g&PyDgBnymUPmD;zI467glewg(VoN| z{_Q0M^m9vubwucUqV$c6Nh~DkCTI(3_zp)vKqXY-QbgRa zmNb8oU7m6}#5C)UQeq>m8}oYHKjb;7*$-JOZL{~WKRp6Y$lXKp{Nj`~s}H=#7gvgB)zH)khGZcr$M0%wM1 zW?JR*lADdjQW#UCPp;bNz+N;PhKaN;D&yU?Ql2)lzP?*L;YB9mo*HQQoSCecysx{C zM{17s#xf6YdaBeQV{s~>PAkiYL{m2-l8PJ4Sd@kk7e%g!ILQDQU8e1+l-Hrfb37pC zXnNe|M~%(76vzqn!H_7MjXBYR)qe@-0n#1vTK0s}eIYPy7x5V9u$`T{d2y#^!9CRu z=fD$4ZGZgKXD+(YQA&{R!$OqJ(BP{8ir$Gv0Pyadoyv+rbW4*F>01T9>NuVJ*mZ1> zqprPBhW>W^gPTMDEdgt7>9cwAwa!Y@ps)Akf+U>$RQ2V+5tcYFZ_vE6GkIE=@aXPHX&LK_0&3t`K;6U-hjyN)T$9KZoq5yg}))gsn5eW^(aSoqAx(d7#`F ztyMqOPbRDPh@O=2+-RQMUS~dporsag^61lf3&}HLZYTXBZsvg}GcB+xh0DXw+Z!3H zt!*Gaohq@a+$M4Zmrx`|2UX9=@5)LkQ*h|l`55N}Qn)y=ot0I%la`^TqjcVJp*r1M zX#yLA4RM2lzk1bradH$`u)+WOw!OCb!-0(2i!sqGFX_U}cB;FCo53_6n(|Qbo+;6B z#M?M^F7d?_ssvG|>y1ls6eH@Y;~3Xzfd&8Wo@+h96La~)O2%S$9&s-V>Jpr}WYP*> z60p8FVYcvwen~mO9`KH|K^v#yC3(pjEa-l$EblhvfyAljENC~GOl_RF-jye2f9@0B zDcMJAqKGP=SgTEacw`qdhi~<7k=mn2Xbu>uZnE{`%W6~&6SIMHWBOFHZTHi(%fC+_ zLIS~t*YufQ*K%dO6%+O_vX9}X7S2iclr0@(r#D1_5|+f3v!rB}O@n@d8>k5pvssn}-f;cN7?rB_nh`J>TLBr-xyP_ZPQQ!x@ev2Q4>)kdH5a z_S19WF~84+EqoZf{0k*yX}K%fOyk2^$9O!>B}XlQlM>BmM`cHn4*E%1h6nJ2O33y`lZ(gm z;+{$t+B2+zd8mt|-H}IKqiJ%Sim<7L0Q_rT#`qYjW;0pkhvv4g2iaaBe>_039??Z2( z*gAFx&I<< zAMzga&UjAIQkx41YAF1cL@@!j*?IOnHWvj4lC!cpIvhafC!CurQ%dk%$$busGY9;P zN{ER8;`?K4r(FlH*dx4b_b>R*Br{~}V2R+tDW@K|; zV449nZP2NvBg6@r^}_~`7(5?jUbO@vY6IcW#cPCRh+x%69y*cn$Owrmr9=^Wk0Uo` z(;THnj>k5BN2PDQw|YXwr%4YBh8nr-=LAgwGGhLjGfkKq_Uov5fJu9G!RmMiN8BdL zrsti;-exHKWT__K(wvK3%Pt_(7@byr8d?Wo-{7KFb4#mFl6$$A7%B9+)R-X~^wE~~ z6Y&PtBPx~83Bw&3w{$-cjuy-|YQXC?yR%}#EGs9>^YYWItWft`TL#PS{{dcVEKpCXWI5?P9V~ObuNAQena$ zRoc8jrT7hMV`3_x53jF%Y&a7ea$TQ5{SeI8dVZ}a9G~A}`xn>txyoZA!YyP7e_a}Q zn)9LLTvLbvZT2?HM+Es zJsuRpQ2agT7@X!p8IC(%z9h)b7b#&K`IcYa_mQ5<|6nI2Tl@tI|1=w}Z^~yq*wzi60rBn_kU+A+#)1%sXn*5u{i0;SVTN zPIy2}=sftPNh!y~hrf3BFugKq(frbex~P%>>fjjLfq|q9#%+JkNsi z3=L_-n7mfsG`#(kwcHenir;+rEMge}-sC=yObC=MkroPn<_vl@Y-fX|?2P!Ff4Tmm zzTsuAyoXluFCe`ltKuRUS!y;>?#d!r% z^^}x}eA-$3Tct0fya?%r&NnFF2_w=GlCEV*4V@Ak6{VobSrw1?q2a}K*xyoX1WHF2 ziA5)twr?Vnq|JDn@k;qo@+aboR-D{xcCX4|LHw8S_OcA8Dx?@%Wp#;h+K z4B;=3vEAgSFTbe^fBB1hW>slQ&P7zq*+jH;v(J*=vTmCvgzPs|BwGCil(e@xaO=J= z7twLyr4GaMF9~Wb{=!HnrB~QM{E2G`?!lzad9Y!-6sg5NELFG=0Mz&3c*7|BLzz($ zKoGs6&heAa!!T$CH@{yFINS=0-p`7dRRDDODT@Y$()f@}r;9wL<>1`nirKQsN_=Cq z+rbvfc=m&MlXl>`yea7c$?RS-nCjKXOK-Df>0c@KcZxbUh@G&@T7tsK+|@$o+?$-=G%c32U&Q=Kak`HJtDa{2{) z=Wy~YEy6=g^;Rt7pJ}5q72#=@jHu|r`Hni^HW5|5%^Bzn+8Tdj4_Ah{SlqD-r_Q?_ z5DLMlqTIOlzLY6zUdg|o^9&wa5_JD=|NDD$)Mo~seyY6~ckDKk-Pntqs3oO0X!*S8 zWF~Q<*k>POw-~}=cSHBVFy^vzpS0>K?r2Bb#IR)QUj6%ype@UutiTF_7}HnpIl9Xd17p0zDx&OE7u&0(a{0&#R7w8P2a)wk`xm7C*QBpMl7Fdj`jdowvb-^ zh}6vmb+E^nZ$7@cgHK#olgk_O0d399tVle8f%EmFlRq+cXk6k92^d#j4hR=$!dPOj z9wemF7k6}&Ah|I8d|B@Zf*Z8)@73B;?u)wNf`ORa-NX1E9yq(EjZWJk6KxIuZBksVDl zS&MEW&rs(>;Xc=s0FPAfEkB!e8oo%h_zx?A^A6n!OzJ(#70|%)7HXUvEozy#Cdj$~ zW@M#dfTswl(HWts)6}E|z2u%EMa)(<`11Sulv-T@FtT(wEtsnm+pC5oyi5kXHYUVf zu;omQXMU(^2=JxWRJNQ$(E9iD;G!wS156kV16dDm=>1QVNsoE~nLlx-(_^E;9_=rB z^e`o95v zT0r4}Dw|I6Dbi@hy~q}Z;>SLSln}Cs6KcQXMM0kkwRWwZ2h3dPJe6&@JVARSmhfiw z`o>sl!4bE38h$rs4xr$hV$&%%{KtO>2%34hCnkNH^R@Z_t2dr***P-L70hlS!z;$Kn(>7%U~N=*E9ue1B&3x}hbUkfa zcxx$0VXKgKMEEX`fI$iJXn=zP4QTH57Z7l+PeRX{zj<2R$HQwztv0WyNJnAsv-lw$ z15$6wt%`W|b~b*4!nL4j2GT!kdfw5xebbrb&29awOTYxW%@F*E2`(h~h?%FN3;k5T zQThBHm;IgA`1eW%blPVluC$d#(;v3L?7XNgoz(cya9lBT_bLi<&B2!Wc?1?1-_-u= zh*{PRup5cW;=d^IH5a1zQjll$kpU*yV5+d>pl2&{cJf=@aohuRLRMZS6(Y3{P#!5A z!xEyN;&$tA?j~qF&Vik`Syc*q!f$_kaU5lzHp!{^F}0T$OBMM^U@>OaN!P!A|3^dl zWI-J&b_{C8*K0_~8P{pgCaYcd*XQLyzdyB68vBDO9{@Hp44g9LHMuJ&x2)D~?*aY1 z3esK91+pkXHpESlwtk|?`H%BBTX9iqT#nNly80WT>PX}){%*6axx)+6U@8Fqwt^kMTWTrA9CVGQj>U+$30 zlq4&`cFY#<@UkRSbvw&N;=t#`OY|z);&>0Z^pRZ7uavlBSX+$CknY467%yA}njflI z4jDnQDdUCsd+4)tq9A9FevLI~^RFA9BZ#}tjMo0#)MchgV~H2CT$8sEuk^jBe%!Vd z2(dgjVEdr&Mqj|Fx7nNIW-Oo4LaZ<>CqUyOvR89_3Aqcwhlp8U%}bg(BKR!myLS&u zM8$4b@!-l{zO9S6nK}}&$)Rb;`ENGB)?X?jG`NqTemBmR@M&SZvJQlrI@)ve*dLc3 z(D3m$G9K9cTJy>4Lenc-1Dns(Eao<^G9&_=P?R257D`(&4y*kOxd+qlyXR6f1!~g( z_DE`}S2-RKgOL{ON4+{i0mfvm(vzNyY9@WC$$r|? z?t^{^NQ-H)mss?4W&+&YyE`9a;T6%z{K_V4bh~&LDO0>Cp$$I1TluPtXEU6xp3J>- z73z3=QB~n^L9Sb>;*>))_*h!Um969Tb#uFcZP7w7ex@IFXez8SjjhXc2$gQ0B`@&P z#`U%OPqw8Na6&RT!fkj}B8yroEyE73;g#~=<#ujW28gf<(1*+tPP*P7>ecJX0>-vQ zI}Ts_!91@ME-pB+w$OXMW{}68x3#G1#wqeAT z);wAlVVVCeJr#8ToOo8eRQkYy<-Z`4?)4bd(fLg5<*G@f)@(}zz;O-3U75>V*36E1 z%KiknW0mMfSev}3&nL@YjXMH@poES2?Iakkq>dt0PGHNy$B?POL{C^3r|O&)$ZP6n z-7wUEreS>qz411?^z)|06*8pzW&V<8coGd-hUU!8Xj*Uaffzu{YGP7(t)#dBvGS*) zF9xZ_k_`ib*XC(#7gK`2y7=q>nFp?hv6Zg01JChoYEWz2-KpTy8U4==Pz2pA;+6*X z)vv~$Kk4>T*sS<6?wtGfw!_1K6n~u=ymCIRsFnl_n^eBxoYJzY93Xa@y@Q5e${WNh zwEt94u9W`tj%F@C->LDeT7+9wsDLty5^r@tLNo}*K{NdcJp5zaaRW`jB+AP#3Z5?| z6f%)hU)o-`vK*U6SnGJ-Wa8TC_@aQQ3DTtAKDFK$>9|!nBvaPRUOs!V-IrXgEM$mC z-rjhRQg-|VfVyCi%mZNYLZ5{4*`Z8w=r-beYRiqf9vxySpsdvCG`f(s#KvcCM8z(%wW;anOMtZTD(Q3 zeo6-;(~z$-iWYAMPbC6HhWQuOYOG;P zN7wzP-F07OyIme0Iy6Y1GqzQ>;s5M?j=$DVKAOb8I0M!G*7r@;@fX+6;7bo`Y~5H; z_y%X$PfUz00Nr%#8s|YY#C2HWyvM`*{m#62@tGZ3!iL*a&iY&KGTFiBZ4y!@@dV`) zq%H>W^D(9{iMx==o(y00SG2MjL3)5@vT&{Wk<=T&HGI$xZ{Ea5I;#@vFcw>UDS6|q zV%rY5(X!6Ut6)u*xjzc2$CX3$r7TAFQNrCBj^X8M*dn=@%%MZ(j6|zftIqS2YyFMB zW7<*aGsdpiX-pajsz~PiQ1$3&WqJ0W0T3Q&yVql$74x z4Kwruf5C3#*<*dnt_FZr?a8OJ&}|c?p89kBaNd0Tq9}M}`@@Y5__oTfi;g}~PM{+E z{iJF$mV@~DeXNJkmAZQBi>LhT*mOQqA5er>3g5G&HDwffDaje=qsOY0kU;l>-_Qr0 ziS3v6?V-Od5A_@jaG2g!xC>=>ycYTwcwiE~D_67Qp;ICKnP8XQmgr54WC-HzaIdtQ zt)q6&q)IKR#O)q=*_i#}+S{&O(At+l#^!dRl2d$HTjv*JlN%q*jdi5z%s-E*eClKc zc6i99bB@1d%--JHn9&%+@-xDTAA3XR<|ze^EBT|;VhR&H+&0iP}i-;;6Ek*j7W zNnR)A)L*P83Z&!7zjbEjZ$~`PqAm)Ne4lysPUCJwn!zGU3MI@=`Z6{2B31R#Z6teA}cmP3ihVzFjuqQ0l z@MzHTp4gM^?drD9=0{@DXt5Ytt1!^{MovT+VzyZ&!jQ_t(#JTjPuIh?cAE#d1XlUhRGj&HN=KzpBjeR zdS}%O#Z*uBN1pBpZDcnXxqhu70-E1X_DQLMuJMh`l`d{o5A>zM+FD zA8>@#>-U$Ug2Xr;oJIeyt7mI@8>s;ejYyVOBg*om@8$-4IpX8FHkhTdP&Sy5bNbry z`f*e*Rd_-klfq|PA995MHJi9A5kn~|YgG(m^1ql?nE5QC(vgp>a~0uusXl7G@85q zoIcvlRo^p!``fEFqdCugo7OvE&u>0&a;P@B^crVQx5prZfgn+Nl7;Sv=IZtoBt}Mb zlg`~0cH5)H)UySO*%4&2tZleB@Cg(^>f6pKH#u`W6{+LasFfCOAm*QP4mK-YQ)TT3 zw}*JN@9GhR>WNl?JdvK&+ovwWG5F!n+a-3yM`0g}PCi>tt*r^POJ+A^Zr>16q(w~B z5gJH>sogNDuOP$ZK`7M6*y;Q=R8}zOI)>r$nehs)PCE3a;4YIIxvBU@(G`EUM3bmeGT2R}(pW!0#G+-zq>uBh7pgOl#0}=)2Wb12e zqffZ9#cS4_Pu}%oJ=#0vv`=8M0>Pyd+!^&3&CHRaUu8IGOY29 z#*_4sXe8`iGY~rwd0oF{z&EymCDL8D1jMFw!q$cnQhVTdrzFS{kFtE-Erhu;gMBz; zqJ$09BguRDiH<>#Ny=yDu@{TzI&#p6xGtv3> zH;cJ#E9+}>U&ovUCkMXXzZuc_Sp+0S3DMBA^Jc48Kf1F%Pj7pRhZV$(zj)V1X1Y50 zJp?ad|AGoR;0*+zG|Pj>u+qvZf26$zeeVneYg_qFo)#rg{=)Fy>J)2*GApWgr%}gVlX>RZ`PLSF{@vRDxTdyAEDY^mL+A&$J zrSR(HBk&4WgPq2$Qmkm*lfXFaA=wWJRt4W*FR}F;)IfuhexdZo9urhj2n4<5F|O3B zZ*G1<0gI*3pNznRH?M=$fFG>=!o{hUG;$CE;C^j-dg4O%_rb=yWw!ES3pZV9g4@eV z9Tfy^qCTi(Lo5|Y1_q%)g{fCrpv;}6NH%=sI*h4>gDhP_lpGn9Q}4^^Za*8j>yDE1 z-yWU9KN=SE!pd=r)MI2qJ+1>Bpnk+@&NeNB2=mzO4f1-;XC8aHRBSe(dFLOq#sFii z$nb@!fU6QBk^_TCK2~T4I4wr1`2HNH(5PX!>HM^@gCwqS0{m3<1X!3*KapJqG{=lU zRQ}kFOs@PZF#iKEKHQUV2 z1e*fFzk9|=xuU8buAnjG9P&j1OfPi5bCRnF)>b15tiNT3`6>84myh{i+5>hl=_1ur z9X;qc2`&fp02e4h)kBbjD}i>(P;QH%SFN!(!@VJRb$rv=%@+iCwpUcFOE-^w`t_r( z99X2Hl^>~npTz+b+e@r0`1d*^S#R39RP1rENY7g*dL!nd;B(!$5oW)!fLG<2Ofb1iZmOB0x~xOrV817ekh*8}PgivYxfIhs-;*$S z9A87{XtKwl@tzutl0(x7-bRQ6NDP3Yj_oYXZ8a}euisfB>FPw!-ln>9ym@neBH-gV z;ek*DIrmb#_amu%p1ydI*8W-5Wm#{X$^(vVOV}%FM-v|{IZ-dzU{4(b zZp>oLkYBo8p28LM%`p^$oCQ@C+o?0?fSaL znzE)`IO*UozQ?YRCo=rv{zvBf)Zd1VRdUmuDQVih=_VX3{$hd$*^ts&y*2TprQ4N& zPbpbQoITt8S#*I>}Ucjfv*|8%WjNk76YL#<$N{uoMp*PZ=^7gfjTW!7H4 zZF!3D-cxrd9MFxpYx2r;3NWnD3!1*Wz{9$7lCpk*!fi=st`5SU^tgomT)z0jnk;T_ z21J9>OA1&rN213iePcp}=eoXU1@EUdnVFe&`~6^c<$|he5h*jCuqWTDxPX@sABoP3 zUy@6mXEkg7a_2yo{|M0g_>ZQDaui<&PsCcwRG_Nfc^3H;%2FEjiTR?Kw4pjE6MzL` zUMIpAZ)}uP@z#ni`ao6zU5Z&&IL(@Tu*G2df|h&U5cTCFl(&T0yDXE`C$Cl8Y`*A8 zTKq;Nse&A@|8TABb=#Nt4PtdB*!Pn3gW+W2#w&iuz7a6b?~Eg=v!|L>tuz z_1pF@+)iaX9M5a?1I6?f_mfdH%s(-_!ud}B@t;Tgj1Q$CSE=V1_uiWJC=)d%y+rY( ztgKLM^MXjSr!`}$JIz<&>2nZ~B`< zOZPG%4~9kW2EU0EU?@V+?rP0MeG}maZ2IA(x5v**7H1xf4$#w`kT^J03TD2Z5Q%~O z;ZfEUb7N6s@y;zMsYd5deyL^A@#tPX$>;d^ocx7p=u`yp^Zc;z=xM|ISlFla3HcCX zMK>`R6rbBop&9a_+y~rsyhZgF2wb2t*)JXuO6Do@@JK3}tcK0F|K0G~>S)ZVQifY4 z^C6}0(XIuPr7;b@`ETt1K^*+FYF}9)Zspr>PD3`XEaXRzLxr?|E`knMzWWDs;4av_ zmOg5j6?Bblcv12_g$76I({B*=i4xT??JjlCpY{{_J-0lwoxlHHgTiD_qdB;B-?hn{ zhw0@=O7gpYtFOj-F56(z8LGUtk?chz6;qA!%7JHP^C4-4@7=pQlarRz$VHE?XZ#GY zVAoim@`(PkbA`BsA3IW4)i}KX`D7W19u*jZ>=1mdk$6{ z7X0s+?>MqQn9^llT~S~b(;Ot}$A9?IZ$xw4Ju${WINLu{xc@g;Yoq0VLW>jP>eiG! ze{}DEB5Z&EXP`J8X?g_sx3=% z{10P_!w!A~ZGQQ#QdGs|@}FSiqs-qYXViy#icrGM-_QHMU8Gz`|HN5G0lFWcIT(D+ zoW8V}@DP*eID_6_QP*AU|BwAqA3Qb#p_ zp;skqy^HmPE$#=eHT8yvRXv>dFB{iBViPcaJ&{imaa>*mt_EdLcW+5Im<7|hK`&DT z+^9mjWS)Ij#?R0K{rbNEa-&2M&;OOp6%vB>Ig2&i?MeE6okw!3o}K({a!c#}-8h26 z+V{+x9X&5E&yxAP9$ddFEyrwPvR1Dh(6M&;YWn%u!L)qzFdK^P+>CO3bwd@P>)JqC zi3tQY*I%xT}xnSYNFi`@&zWr~Z3BU{UT~HnS^usvc%(KL3-}&$_n} zoX4K>2VAxCZ*Wzkzu>CqEB}J4K8yS}T=j25LEZN9p!U>&yd*!JdVbQ38XS~A-DV@^ z$ZXbwlra5GY#@+5+`SHLE$0kKWBhMxW{!Pc^%`Rnq3$H=?U4N+-wuk6iSb`AN3ZLz zhz5hlzF#hRITJbbCgG&r_nPN=ZMITnYrD4J9pm|MN14}n94gN_YD{}{Iw`3J-L|xO z<>z((1YzI337=Pi?s|qO`|N@B0HLbb!=3wmxp4&4Sb*2q6s)oI4#UD_dTrE+)I%0H zi9JhUvK48M0B$0PKg`(z9Tr^K1ovE{lmH<|&wymQyDEC|k+1b2T_MyxqpN0fn=7Q^ z;gnCMZHB$$H&|@_j|qL#4t?7++`$6R$iF@+J2PXJc5aPlonIux97xku0?~a9Cg?sUpkEFedMAh$pu4naLt@f>jw!l7? zrA6n1+VS4^yH8cziDVjVgz_Zo$H-a5y&5Fk*SX~P7uJbZGQjCJ^kg4OPYvPnBksqy z`(E+{xNJGx!tb^g4WCU7Lrf5(sFZ}TV)plV9s44;AueN+@bVr6NGy!g1(|h6m%J4Y z`!9!>oNVKFZo`pJvFTpdp$u?v`TjSbu?`2b2PDbL_rql+<+%B9X61a1J`L=qw&V|| zpw?E=HRZk^aLv=btC_~&o@i!Cdt19{wWq)NhcPJda0h)Iihrn5ncpfy*Ug?8p_7qX zoG*B^$e$q8T*Z#xc`@EYfd+e)_5EYL59|@NzXlM(-byLJCPw_e&*`x`8pWBg>5pRk zwpfV=ook;{gr2Au6nwiJ;UE!kw}#jae7MolHd&yCbfAxq5fJ9EX%_|!_2A#n=6>6& zk|aP&@x;ePWyN-Lq>)*Niy2ecZE>Ksy4sz>zHtpJiu&oNXCT0Kg89`2I-MX3W@pb} zXJar0)sPdFKC$?TqM{rhhUNTtR8D#6XA~gpyruU4h(LTU*!O=%AcoxI1D2c{cQ%-A zSE;vWKHDSa^6Il!;ci0A_oG@_1wgd;P`KJ6kn?K40ldc6BY@#Vmuj~;}m{| z@nQ9h5)?l0R7uL&mp2gYTG6ZU{1Zs!VNU!@ZtG27vrh?Yy+4R8-Dci;6^OFsaPLOV zzCBZy0Dht`707AC|JZ^mO$`5>--}!dJFVW2+2dxXmn>%8bXJ*r;&#(L)HPE?JOd>7 z*jGD7SX7}7yKg%eAIXogxAmp!Uh$=me1G-V)xrJ70|KKZXe&ou_AFjB`0*1qKz7u)oJJq6C5w#w|A|1v z*>p?8=ZRyEo8C;4EHet>NU~oSYti1iqzGdtug5 z<-sGod552rDgNMxzqtJDLpol6hVB?dXZ0Xbb?X_RtwG%8XMG{fb{5M|IMDWz&Z~R2 zH%dcdDTH_)(z#;oabo!EL=@ciJGB4v;w3@Zv=!vD8RDLeqb$sLCyJ)e20J=C>l2W| zxQ}>wc~O?-CmS)%&AO#2GY8Y$f5u8!`P-X{LuRr52AN`dRHa zw+=^&ufx8tF`LWb8zI6NB_UYsQqA_o(8zA4u*B3t_e;KWE}(m(+aCD(rV14U1G#n=3DhBTHNeXq!JBv94uXD#F3RhrKeei{2Pz zp%t82(!keaNfg!z(cL?*m-Vy5JaLCf%SCQY4J+Cr%dXpdZwA*sf)BvwD0+K7Zp!f~ zhU0BxSjDxCO__9}S{5s1f_S*IFSd$BP~tU#un1C zsm#_5^kwBpPkab+qfCG;wq1jDs=*e8YERryk;iE|iMq;bS!QSPOM&(|wV5ZuOz6?y z%UJEZcbJ7;gF`6M3fKSTb_?UlTo+h*vCv{$!u?9^pzJji-(l@kQ)`12NpHU^)409* z=`9|An^x^Hx#-=oWDB?$FXLRIacfmk{j%YyX-|aq@uIuAPkqSSsbctsu)gyYQ}Fi0 zHEU=07ERCjr*3cy;d`3yXE{Dk>1(pQbP+dz;}dX2J>aGs#De0UU~ZudVn|<*jXRri z@RxgHNWfTX%78{JA2^!OvDfBD$%rj}IS7H!GrevpC+5qt*c5sjSCw`62VAS{*bPHD zmu_%;lqWnU*~w|i`1i2%uWHG|_!~HJXD+isk1uJ1j{Pjwqil{)rxIj_Y|gZ@E3%BJ z8M3owJe!q7_u4>f;6v-_wvFKGGsybPsZ$Rc=`*Dp+gSn6O9xgJ`>ooXd7n|3=Fu+^ zr}K@qD7(;X#4~*zZ%)tCNSo7=xdCQ1mB%?^;+W6N+f;Tw1h`E2fp&e z@6V*BJxn|^(iY!r(U$Gz)U8*|zp|~IY_?J?nlqM{b?-}Hm&XmoX~+&OrLbz-Dez+0 zXVx;1bCq;4Hf>mrXEWM(iSlBgl+yd*s|dE(TN)l}xOo@2a1~idH?OX@dn#s)d4gbIDBq*6~Rp)V3g zRw}1>#7qc4xpdd6rxGpCKEAnDdb9&>86DAyEhu;s+!GrxWb9ZQ&d~Lv@`$<>`RRF) zG3%CIL_c7&@Hu->@7sUGjDh7bRd&C8WzNlFzY?K zYRP(msIBiBa0W{CA+_A`UZ3-`7ekpQSSDXYRI3lNJdt{7CyBbM?WeC>kt_TYHuGfS zRva(c?aWEv$Ml@N*ChyD2&8At>Li_yYz`FEP(#t>+Ci8AhZ0^f?cK@srZw0m(BmK( zMOC=Hda3wcVq8)Y*Juv1itd|iu;6!-dRo0Rm|Q(cuqX9hi%2cr)ly?FyZcRjn>Tig z0!4E@IuV6R-Hw}Y!;gjb;Ab}a1>7(%)D*Qv?$6!~qAl1Sc7e64Q}`{)n3rp6AEp`l z&`2C`!1$4c4AZm@uu@N#jr(;h17GqSqq2COv547wOVrd6eHiHGT) z@i^&lUd#hqsQ<5&kcvkb0_Kzuwr6tGOa@>~^a77>*pUIS&xuDTmK?8ttf2LZ)j^bF zQFc8E`c*wHu(q(5N4qsRcioM9ZlA)!qr2H>T26?08jmyxaJ?WbX!>gR*6QusiLs2(Di>37GoOJk z*i~MoPi=X=)o_Vw>H#jv+$+R)kDhi!`|!Vt#8u-LM3*agb%UxP8+)cF+4pr%u@~&r z+R3Sj#FQ@uzjV2c?hV`!!Hj8qPvagGcA_$Gd`11_|01x+&WMv0P50KAMz#-uAq( zv{EL5_y^8g#2z@%EW7(~Hnw3=1!=GoJo!&D(--@z{Jc)yty3fV##=ApyI=(Vf<&fI zS(~+eF#LvQmy)txgIKqWUPlkrhaZ8j1$prp$UZCM==C;n?|282)v4#_?;9@Ka=G7x zFnoLGT2)_oKw&-qpMIR{GLN{98j`UO=7vA6^X!`F`<#k#h*tEhZ-3P9#G074mNQ@( zdwEmGNSBbaFbgwhWmPSFPDo-aK`^N`i+a4xACMEc&;&P_sf+@dOUuPg&ec1*+ zo(**{-jD^-Pg7Bvv9k~vZ#E`J5G4rBr`M=yq^uSMgfU55%JnR;;`>NSJG9q4Xfp6f z7yk%z5S@ql?e&m~q)QivuV!D-m9=5vNd+|d?v<*Va!82mDky!EGx9sIwSA@Seu1Qa zrQnS{J*Di3+#mh@E!iE)fVD^C9v_wr^Chh%i&3MrezLM5(mE%8DunuXq8Y!xng=mk zevWE$rRqiE=VEsc&y+Fre0D3c8~zrC{|?3@KH?3!n7tkLERB3C)7{J6_6P7~&HkZm z7RlPO+d$hn9{6E$pec50v7HHQ^XxlsEy277L9 z#NHz0Wv%;$A5UA&uaA=vT8tlKEm6=HU+4It-OW}lUtjji5i7^cQyuYym6V(6) z*K2$4!S|~64-ri8KCer?A`CuA%4mxF6p?=88Na@Z`tY}9b5f-mtfcryb-rEy3(M$1 z*@?pi9b4N5lxD-)pRHx%rP!a^474G{dJG*TBka0-$S&1>^v5wSQo^ zv(cFLbL;bj`Ix!%;i}cPjqaY3^!q7J2@AOz-%+h0J5g@QAvEtvqpOoe!+ZdZ7^La- z1nP{+Qd3MKAAb~&9*JQlO0QpGI%FwV-`FkB`zYMX(aMPp)Xmf5#2t%>_!V!0t2P7FCAiw-EpL??iz zwRXDa3%*#yAvOjAt9~LqD3P;0U~=}d$l*|kF(1lFMu_>9Ol*%%-~HUQ(Oy;fx|R2$ zp_~CjXkLIE5GtSkPFq$w#?!{<`M~|&=6!K}e$FS7!iSOT$3L$!YpE*tPe5WUaa8TvKo5VBiVY*n9;}4Ps^bx5NGYpN#{u^$WZ57p;HQz|`e8aaVgn zaaQQ~Rc!dc*tb1O@!vegX~pV?DQbVlCivYt05wJX1Dv`iA8+kPub0gd$}>dd-fXlA zwPWR1E0scE348Cc+;OdCsQNMo#MFxVyXn&cx0ZSk_7b1}HGiA8UBg88LxcBuV1Vn! znLQW#r7F`%QXRZxDjI*kayN<2>b&%e-OOuNw|=C0_nsoBgY3pj?H6zJu>oDzqxj1 zQ-;+3AD#SyzbdS}Zkk4RA+uL)o9#S~>%w+tLwZ6OE@rkpMf_nCHPg+vP1vu zIIkt{Tl36u>5agvVLZXqcek&uUtQhUbII&0Dn?tmh4{0)@o$x+bYIPC&;BjXgA5KL zAJ|sL^HZqtj?y_sw3n7k|~4=3c5D5X)S(< z1?-i#_@KX=%{Fxml~E127nh=tN6D#!DYJ6;#^*n6LWu@VhF7DM7X60Lojj1Scbcc_ zxW@Pk-y|F9TgTx>T)1kM*I{eNuDyk==aKO)Zcnx4x!IhqYR@TEuW`xo-d?h0)d+TJ zGZmC*I|BoQRNX1NrSwT@ac)Z((QQohLmQ(HUS&}3dHtm=Gf&dQ9m%*SXlTJf_bY|& zFQrdcpF^nRdUE7^GPKrgDM>WN(17vT$<1zCtpMir_PJm#)xIx%fX+ zJj6pfHyJM2b8WpX48g4eFSWa8cM0M<&*;(K{^rE3NHGEqkp7J^LXYIG4<#UhjNdm? zVBIH{e4%!+1&;(|{SWl$A1?!uab%i#98>oEiaPNy8KlBkD~>d7IP&+fbx$#U&o|6H zDL8u3Y)k?uc;f|?;fms=W{7R~^>57wF$1OL4cKSSjfhlcDQto2fh8-m+OAl0`;&)M z@MD8(^>9R1sX?QSZx;+bVf(42x;3eVAzbWuyo1eQz6xYw^6;+GY4Vy$#{uDRQ0S{oS%8JC@WSQF*!~gge)JN zzpjwrQBO#ww0|cynY*4&^?CCFa(Yg}y*|b@2xgX_s;}wSal4^xlSo2o`bQUI3N$i7E0Y*y) z-10oef2;wpU1XAleA3;0_Lk`7kWf3h7hCb(N1c?^185l3I!L&okZ}5i9ncL2(@z{h z%-#`v-cNk1-baLwzbepr+ko0T&y&s1C}KeO7~`Uf)xEi=t)<(UJfGt$upGg%hj-Ka zz)6QfXRVgbvByQj-<^y8b?|;&CH{W0nb{JN4p=G+Z3|DA1c%)?+@EooO6EDu=$5WT zGPW#_ZFyV8War7CfE0UZH5o+GJAkXff?ni`ZQJae&=GR(g*6 z?19InmJEm(g9fgAOnT^L{5ZOfEanZj&F>#97MkzGp4GFFb>Bl9_R0&8B&~s@o`Dq; zTMaP+(FEoENZMOti#0phPiz5XNinx<_Fa}UGw9fxNFAHdk=h~RRJRuKYa6Um!c#7`>Ebz299%r!ocCL@ z!^FDpmz4!I)<>5ZNZ($Xx ze5;_iT~m@n=#rQZ+}Stj3RDh(ngU)A-dpMkSp!-T{4qdWc9OYfS?2mN^on>fMrl9; zcCZIg z8u5TZ&s;^pF9bK+y98G&*5)Y>GOIVd#6GsU!12v6l?aEfAhs!=4~|gXs{N$A!io!u zvp9P{>o?*7l33tN!ufsOh8j2T-R(FygUXsO)uNF+NN%e>_3qd#Ro4Wqj}LoAPPf_} z@(fM)ROvs6*5i_}bE@7xZL~!`+?el_uPCvjVPnR4`TDe0zPCl)u0ii}U}y&^X(i5s zoTCW9Xi5MlX~2Fu;Xv&Paj$!v*ccn#NF-5R5mSi>!8>&P4*``%8<|T7ksJh9T{9J1 zMrkj$m_ghOjdz;djB+V|Gn?bLtDQ88hC! z>&8SU!h0jI>}WLixi_;GH&$``L=FpzlKKM6t6uchDgoH0147U;8VoZVYW~ zB&+|Z(DGGy=U!|CC_FnhpyAVmy>tzNA=$~A04%UQYNR_7c>Cdh$a;=xUi0Th(l4yzMZkGC49(g{+j)3JP+-m3rf$uz@^7!NNbm{VM z{=lz&02vE2x&m&goKDgQPVBrg*A4$|g$0+DTYnb&EJqI95TGW{nd-`JSkF>WP|y%N zKRG@X)^>-K{mc#m2%)eqBB$2zg#D z!?PFQA^)EDK2W(gCc~HEE;fY&HjGt70O}(0&hv6dPRTgG`L>o~t^^#Q#F=n6%205F zBqo22`(^m*t2qU&;4p7dzgC18y+Nm2NXCF=0jBcx-N~ZX`dff7`+K&2az@Jbh3w$+ z;i$*kGJ7Iat4Td!2GyE@hrE=#SX<&-nmBWmDCrYWdwly6CdS2bZ-5;pZ?w@Jr0q5m zb4QehHJ8c7x&C5@vj8XHm3ZA_8>6-98lLxCGg+RFz%V_78ZO0N z*MB62l0r?^f&gAMHLqy2!1ul6&yU9^gJsq8LcyKVy#8pPzyYSHvWd))NiTk8M0n2WOAw>>ZjPW<{b z5lF)Z-A6|2oX+Fp3G0r3;_w(@e(4t{l9`$94hX`xao;g~^l;;72A$cfPLN8doJ#h9 zKYRxX1>ofsNxYOoA}|9mf2#L--^^VCb}Nq%?rLBSvuEhD2(c~;= z5+Rw38S||eK0IlT$3oJgt}#e|<+-R6d{Lh>t+Fbzlw9M$;J^EzdtK@B;$6$Tget=F zv#lOC2+paJ%bfoHbXdZ`fb4jAuI`ee&}gbu{c+fF_PndP4Cav7sAH65jMn#yy@q;2iIa4L5|d8 zQvUAsjXHz|b#L?6pa28G`+F0^n0pfR{lK2VHCJ@oU}0!znC^)MI8itHV>vXVhZy^v zIA*6wbWVhugD;(i>jl9O?FY{U*f--|^>n2fWseB<@k!3{=}DOQVPWobNU^`34d~d# ztNHrPvgm-EWk!BpUCkp9oj32Xfke2(9^OAdbn~Jlq}>p3l4oPt3Rs?>Ks<})3ThG@ z)DI8{8uN|Gs@<4>Otp^qk=24vzX3ogxu5IiR`$}Ff1o=%DUl>xYl3YF*CECA%D=tg zx~MQZ7S;v8$fDZy?K9_lfnBMOqo4}2f?7vXA;HI9i1~09paBY}U+tbEO zo&R0AmaQ#U0v*$A_^m>rOv1>l;Ng-I`FP~FK1@gEpa}iUHrsq$i<+1L{TmcH&_J*Z zQrf(h^+l?YL&unMlqswk-@(VmE(l&V|Aaray6WFadQy5E6@@Z97?HV>+;(Bk3z+CS zxu?k@dUPi18Xm5_ySv-(01VZv>I@niZ|_=)5l>s&f4qPMKonoFLw?BxK7bm5{FBXbLdSu52|B4kB@#hRUusK0-{_yoc!PV)NgE}3fk;9Cn`!q!Yma~ zD_bGI%AyZU`!952s;Z&6TpLB3F{~0b9KuJQ>dS5@mrYGgEe>8?m|OCzzD5)u=>1jk zrmrt(9B$$MS!w=20Ip&s*UNQtg7Wt^v43!o_PUH(n{Y?;-I^$e-{K`?cv_mYQ906r zMtlk{1F9fD{(m1)^4+~dGr`>Hn&Md^tzWGPbmo4{ZCAdz*#Kv08vX#^ z#uPtz($ZQEJIlDc|H3ENyfql+!pY*leCO)?bxb5~#D3oL!N{+UCKUnrCa|}c;!|&h z`Tg|#i~Y{Vt9}4g!A()$wWzrGE-t9>-xj%n_2cHR9AD}_l53$rDoz%rlP7cNKmOxA z8y+qaXbAJ%V0Hy&1}vO8-qnO%vF>*~Jq_=M`DcI@5*Kzm#L}-m6Jg1*7sJCV;Kh_y zVR{IBf^bMMkL`)YX~U^%cYT5$HugznP29=;wZs489q)a5jQfYPG0~NfGxK0>2$`8d z+?0z~$4bTfJJP(*<3|IpD>ke;XLQP?f!|m1zYcaM1Walrg6`Y8Va-#NYyFkU;^0#3 z5SZlG``6Y#$C>)?aaL8n0Ko%_gZ~N0{m-jK<>v*C60#CXj4mt4A0-I_3@UM`A>HT1ryFxG6R)Tz;#ES=l{wF zet#tv>GweS4~H~)__+CuKroa&k?mqt8u;&3v44CactyECo;dBQ;7=XG|NSq6Foge& zua5eg-td19r?+tH|0?MI+eJ0`{^w_T*hn63C2act`8-`eAlbjAw83dKi0|v9M_pgL^RQ>5eeCI+0RsMf`&RL9lxd6W- zIX&bQqCS=rho8pI2$Eo%X2@!GB$IL$f6nA}+el_3oE%*(zR4*BsH7B;A z7n)tiD-*-G5w)4Hf4kCEBH{_DUG2;vIXNPm&pmp%fIULBS`NmcxkE*3<+D2q>xu01 zb=bk>;6~;^PXn`rZ>}K#GGbz>c2izw6x#{7UP~XcSAL@V_wU5>k@S>lW(8=+RihK( zLkk5E!*&P<_UBP}-luTCW=c8E1l6GT&%yj{rdR|*CU;br3B@qlxmYHU`;VlM>0|6~ zB>{cNTX9vliCL!F#W7D1rv24#raeiqF7MQwN=$Y7L#2~>A&^SNzU!vE`v|iq8wdIb z_f%ZXo%q@|T5Ke@v04A6|BV(HaxzJ3HKJj(vx|k0LB8*AG#JHjaf@BNh^dY-SwX3W zJE?3`q~aCG%^WH6`yBz4z^_~JE9bpAw?;Q;$>LLi(fz7~V|>2;-Ky*^bXSO?Z{B0C zhFUXcZa>0t7U0J(DGUh4Z0q29ZlfDtw|}Ji_eq_zmok~wb{c~$-=vm-9Uzpl8K6lZaaruN}G2i(cOc1R%`nx zaw#Kh>+3!zCeTAG4!cm#J3$E+rt9ygXbw>BZY(Im{UEgM4M&fH)eZaZ`Xu7cBzG|- z=dzs{eGV_bF9V#D%>;X6J!3!~0 zCVC0K{n$WojKP3X)83)#NbzBk?=J|jRmJm9v4H?lG{Y zm3&CwXC}In*>DLwIZ-h;Pr?1yty3-iN7CLH&ISo9%>H{=VI^%4v3f0}{R;9NW|Wkw z7y)*e$J9(v_e!MwmA4N=pWt}J8bY>~9%04T`ae*#t}b4U%ricvYlS91*(TpSnqQ+O3Xc1*Rs>Sb0+>IS4+Y3zk->Z8vRNX26KkxJ7q9o)+{uNV3MxnCkUlrPgG65$ zT0(L2f$-39bOGv7D4vzqeL_1gb1;X5$1y3@RHR~fP)JpW)TM&61^h>1=&4oKdy=!i z4#b0Rt8h;*zDkIj0O#Dcc9G2z5~6dMuf|J+vcu^k{SuTdHzG+_QYjHVTWjL?u0A?dNM!S4fdGiXOB-gq5)ecxdEhYQ)^3+1;yl8r%Qnf zC-phSJy%g?o+}M>_LEVf}=Yubt_G~5u({R3d^BE1;M zT)29)CfLH{Bal-Rz}R7nL&rXZGWDduAHH#L7-`VzXu~~I{F*MybKtmI`B4@ypT(~> zUvS_PVULtypEP<722z_Y)0!L4_cHWKLW|hjuoW7D&pEU@JgBYU77dZeScuq^1V5-z zeIe&$fNy59Bq@n-wAj(qYA8c5vrN)S@)m?0*&Z1I!WJ@jwnFq8v6=p%Ka3uaTBfF! zeV3;x1}C(m##U~owzq|$Rc^&bcQIMr=D+0SeA0J#mZEoQ>=Y)z3@U_t!Z{!~r~o3_W>Oc%cYMH$Oi_ zO|!Q6%xG%0<--&G!r57GNg@-4bTmx-gmV`=nCeMhpnxBd_lOG(1MDGn&2Gy_ouicc z(eOfTv*t2utdH(^9ng4yY^^VZo1+!Y@#=+DLdV|#sIM)~vbA(-J;K>ah0wnlcqW#) zwlYEt`;6hTa7@R$i5{||w4Q1bHa7b@n57ajCam-~bS(@G@z8l(S@(yp@~KD}xRrVL zbtYHULy9SQ7VF%J?muvK?~)4ecVV7Y1aT#qyY1AJEkv~#^cWg!EXLV8HKhP+3LUq; zn7K!U+mrNkbTlw|GKY6*IV@muGwS(v#bUn@I;ztRV#RV9ZzGX(f+MOz2YMGc%V_tASz!;PJUZ$uwld zohZ^V>G^%qcvO(Vaz}ai-1mzoH-|4j03!dhhUH9Ixnxw+rIh_!M$m-AET=$p8qX8$ z;^LZJ+WKya)$y2K*wOJPzQ2=s(*d^Ot0!O>bbs-dj(Nprf>`QzR>1knNJGQ&nt*`% zs_^zNAZdcb(Nro4zZ#fjIPooB3>zD}JlJ=CpNeCb@jc5?d`jrl5Q4tn%Z9B)et>vL za^MiPB0E}bfL8E}_5C8zclz*lX&nzPyT;=$U#JJj)rlvw7gE^9(j8%ipac8JjYs82 zlT*U$1Nc;yO;kJ9G_%fhH3DSZp5L2K3=4m+#Hvt)%jm)ZlTC$A{IQ+(KImAWsmPVn z+2RzLAtez$qxDRKXK|7RiEGsnfr?6kd~)JV23BDg*Bg=8FzJ+9__*y8N1BBzqqxc{ zYEwy_Y~W}nXS|JeSSu`O~JKdWz)W<7m z6_S{vBru_7MhAL|jN|^N9n&B88s@$+hUlWXaj~547+)2UrOtk?71aw}X`!(iAuB>U zPd8c|v40$pARFA!l;LYbdw$o0k-`nTv(F^y>hJ-Tghni+2XU0`$@s%xAXCNj(_bJ{ z0B$4wO#L%$Yg_AMK~|9Uc_V5~^>%)>$q?KxgV+Z9ZBhA1hMx8u2l=d|us7~$`1hte z`}`qn8+hAEo7;T$1Jx;}7&srI-~3wVl6GfG!ZCbB4;&~U2OOKok4*pkHX*{kIF#!f z*_X`Kud{%r$QI7|9O#cdVVf0He^(<~v!jp{{%fQl*=N=7{QW7|k=lxA7tg<%)qG0} zdg!8I*Z2hZVo~>?9R)G9-M>q)|Fm!L0wHGi+vN32$sHBOTeii-7g1>DH@fQX{0rO|a%{oW!M?h7Hr@fVl6Qe@$A~y$QB~kbd*KHi=C;*>cW&-?kV0GH!D1Dx49G@AHSq*vQnFT4t9#IxgrU= zUnvkeP2&9S68zVZ1GclcP#61L0bL}Q3dw$oC^mNL;gOKk#Ln69Ag%lDM2vpi4G=-_ zDl2Is*cIoriq{vxJpkz8Z9>u+B;d%M2!WX{mZre-VqKsD5c-=Vu^BiRG zdKsdBgU@oJWD?{V;$O)Su+<3pL4BcHF+ir?(A10)-3Q^E@AnU}jnCzjZjvG*M(4Em z@D2_z+hH)ZEyseE;tkv;yhn|$GyS-hw<^z`rYB54~p}VqnHJ&`YxiEsqtYs;?Zb+T=~kBw;H@EwB3Y zgRLH^-=i9!aaI39pIRBQ?2aehv6o@^6Hz zHJ~lu$qnh=UME6C&asCgiBzMVXT1@&LIBJe4)pqL;Nd!M>(irc8qYUb=5Dz8($Frh zQlk(q-PJi8=eTu;V=N!4=wT;%l@zl%mt{4lq; z$RUKI%ek{QVAw?#XU%oH*QFhC0me+sA6nS~s=mHFa6#LG)_+SVYR)UjVB;oQJ{*k7 zv2TiU011dO4&QkOh;pGQf z6SW$cNl~1c+hF8&nkU~AoqVHpc3*lZl>{7Vd@IP z85N0d^0w@ceiaOyK+}O!=OO>99|p45=igp`h%ggUYA<5;&j*9 zJZotJ$xW~NxNmNkLa!2LD&DRbf{EI>`5m5|lji@LK08Q!M{if%J~!WjjlFIT;}%zo z&kd(x8V}ahFjTy7gRV?}6pVC9b-Zxh7uVoM$Q;OBWCg>|n$93~bTz;XpJ3|{+kYyH zK~p$6AgfP_239X837vrobq*>Ro4h7Eb}qOD)W8Oq^=-Fr+D8fWmY1i=1(nV#${yMB zoZPEbnMVGZ&stL+$8T(w&-^jA6%DBsyc%c=Z6c57*b$dM-?-q?pCy%+R6$EcM5uUJ zP&?J{WiRg~VE$`@NjA*6ylC?1zBkT@g7_Ir;{102_y@RRb%E`*V}Y@K{Q*>Z@!+jr zu&Q(V+RS$UwOZk?i0?;(To<0bR615KHBAatc+lb{_@E88Y;c#~mfj#tsbei@Kar}o zzMhnUiHO%-JOa}n9cd%?VsnkTGywmLzg9?(P;02tyaw$=knk6!41Oc8uTx+e_g9Hh zLA?!Y<@jHA%-&u*ri3;cJMe@tta!2xkK#QQ&k(os6qg@`@`vT!=P{WBN>BR3&Xzs{ z^27CfP#H9m#@An5(DN;Nr|h!^%sB&S%uKA`a<*Q*udfTD8>vU5P(kjTePW9jvB^Q0 zvwn?g=s1h(5QQst^$K+pS`DXiA?Yb#?8UX#UlPOGVe!o54HdH)*!nQB8DUE)5WxM# zUxto(qr*3bYo2Bz--!dT^(BPuQM)ON1Y&hQBKJovK$e0E&1kvdnFnG!v+N04My$FT z!>Q`S-Rbr%6VIbMo+O_WV`Ov!++n*Wa6J?wL9^$6*|C1KY0LLUki5@h-LE{bZ2Mh) z%M@7W?;HaffPi$cHQ4g%u%~ImRabN7S3Bk5nIa9JL~O*nQZ+C4!(R@6K-PB_c>@+q z!Jc&Q<=T#Q{mi<^iuRnw<`IKlkq? zT4AZ5ZsY{`y<3|AUKV;n4H`Lzliqx6&3rzDJnA14$UXTrH>@4KA{&9T3IikHaNv~| z3$qNu2&l?-#W%oi3>xZ|ljH_LL9{>bN$XqJS>suk;nr*z2E`}Czu~eLUm!4A#V%Zc z2uiAzinY%l;x&m15aV7F0J@TFj89uf+rlQC=WYt0Tg67WD_<5SG=>CEQ<0jzDyX0O z!C-wUwm)OBeWEM1k}<6c6l#{TqTJgXlHAi%hzFXt6)jnNDeIXZ19>E}qlGF8XYyHmzS!tyur9jG4)sW*O;JjnT(4O^qb4S zAIa3~ARMDthMRudrQ*m^WUMsp4Pr0P67Xns_g%Sb>%Y_JgwFc~C7{v_qZ{K&Z_J0^ zU?=X!dsJX=MHSyf5E28~+ZP~v`%Xzw;Psudc<*DfSoPxL_nSX}cXOaABSAeAj0~f* zaY=EhG>E(KFTw;sL~&sZms<>4*~vkw%j2!k#Aca@P`kL_n$vL;&>#+cBweDk=0bQ{ zK?5Y;S*2&uPeH~v*|REjW=V4tGQlhkM|7;Md?OVRuA;pXZs$UB*Oij&bH?mA-n%7u z@vl%760qh>nV>`2XKb*L5HjxI^Y%2}INXgrG+s8M&g2F=r0N^gkq2e&l%f z4m}&zGq#?m(?}!Otp#W3~DSV&wveHiI^lR!yFEcgi9p!D8 zM>1haK$)24=66uds_)6k%ztdFkoq=JL6k?1Q6}$0|5;{lgs^(+XlHC~X9stFLWjT$ zP|7IpcO5MjSKnzhvp!#Yg&wt&v&X;AHi_=C`vx{J{dFxzIA({1Q;9HWErKQk% zKJpngS;tLZGnqx{QQ(qT<94@ml|vVQBte{C^5vVu5dQB?NczK8;CnoUL%f5ZGjgxd zNW6SgW)N*j1k(`!sSWGk@>n<|&M)ThRCwY!)PEdY<{c2jK_oAEK)W$#8D-!22<-mU zm7U%+4hFc-*A%~;R65r@FGg;EoxS!?1>T` z6Z<)<**fsTzB5_QVJ?3LgB-2-10W{+FsKOTlqPNljzM^;|7)Fubd%^C@C$WC; zB+T-)BG-__+t%wtQK@S1S5UANg)}%_>AeX>9*+EnBDy$pK$&pMZL=WNTa|sKelk6T z?B*PCghk%|ft9OClIvq2828|!lAsGzqQv__Q?CK53f6tH3?ZszqYJcw-C5KXjF1s> zIRm6%k#Py&r*L(e=f3Im`rDx8CFX8^;9B(bKi?1|oMT&ewex`e%}n==86fe(-5?=a z=bIJPW%|tjO89vXE9aM7M%_^GIv4!bl_`t&dQ;=!xfH}5SN_rCNMUdMT5s2G#loAA z!Hsi`7K3NI>@I-@NCCO% zQgNove6IAE**E#fb$dSHZX3&?{bZ;V^@UAE%Hc{|n8abE9P8B3oeGc1iQSV5f7APdulyb0)ua z7Rv-gMib&*1! z6woVB@i3w$_4|Ip@Kag=F#!gE;zuzWf#JsqIkv_kJEU|wJDne_ww>ww1Ivl-M*NYp7EX+SO*JkhtD3PyH{C6P(Rs4mL`m!8^YB&=_95r;PCFM*s5&Cjo5F<#~ zGer2#P!a>`gr7eX$m5TMMqqp+#$B`J!_B6BlJ^7s1jtKB#AZC-elCix+GAtq|E%p;@GFPH${*8 z;>$$0%+G=|wpUckwN-X&k6hLoIeE`Wiv4S8CzivtJDWIV=@@OD3rZ5maK5^f%GeDN^{amG~;H4wyd*zB6Y(zD#NGk_* z>k28gBz)BPX>N$@AvQVot&ofIaOKfyE#Bb~Q~-Xh6c$P-F&~MV`B03uG;+0?U+v21 z`>zhfB%91W;!|tEuGqL2%*_2vCyr%o-1g9U*Sn?7=n{sINF=05#uyXP%|+@y_?Ai5A&Az=k+-{hdz<3;FVXo~k5bzjpyLS_h zH^*rrG<4^&8q>xPx*UAd+ZUAf&{mK$`dm*sn^Rn@1}qW#X7jGwG{^YIOkOc^!oJe& z*4bHF@LkP3zag0YFe|zqJOaOLs3P6#PhdCD{c-O=vcI|P@pi8vcH!8A7SC<#!f`{) zr?;)coA5xMXw!2b2k9K1b?YB_k^-Q5;TYD9^R275;Mu z%15jJt^vBIiX;F;XV+>CL5WEBpUxCebSh@T8zWVHQ!EAA;4Y!wB1;RWe`4zQV;JqY z*3ol#a^Zfhc4ir0k9XyO#1N+jwOCm-RVb{Eq4l%mD5~1(0l8^ONlE*kYjruP+23O* z>iGS5gofrN(1I~M5he~jJpU&6#{e@Ggijb?{PX4B(m=@CyLIm8&@{vwlGN;{nBUOQ z@M-pYQ&Rz**-9x(14Ef3BZ%z_dmbGo?K0)DKL$n;4Q1|aD5{_FBHU5)3fKc;%<}wr z$Rrk}J_#cdb9pEe8Xk-G17BTJ3lT$EL)#2YfRPrMTx8+gm|u--dwJwd=06Cgv^Ffj^k}s)ac^X>meMfnYnZto_x2Nk#_>pLTZ zhqg$8Q3Em&)uSUHBTV>E_s&(5WY2qi81}P#@Wxv=ozfkTEC(GpgEYR8n=q>3*EgVW z=f;tWn_TClxWe^><`7%X6q4($6^vKs7IB71a*0?-p4ST;D$g){=|^bl?b! zpHsHn!x6g8NGiq#sror25n(fDXi@KjK8|L@{StJ}!$Y|n9^`R1(wlBXxOA)(%3*?u zz)|#FH^?}U*QE9cUW9?}QuWf`@jIJ=)TN%k)5jk}jR+1H43vkNvRFGpsukGfn}%bmD0>vcUQWJc{n?#jN;T>8@UlY;4`j9SEnmIT}HP zC7;h5Iw-RFt=D~MB@_~>V}7dapp%gh7dWZYVXmjneOAxbm4(xnN1X0Xc&DbXZ3142 zX=t!dg~YNqHh>D5*V&z?mEii!*eMZs6gS?&Mx@n9d+6H*aaQytob>?bLUEb{AzSyy zs}5#U-MW|R9r>Zy*35Q|-qIP?sda|K_bORbbudfEPl>bbdlw`H_fdaa6IVYyu7nQ6 zBSF~@>0b+&y!N_tgYMH$)B4PHF?=E;{oq{Dj^Z4EKV@>`Vd&&~aIvw$hEDZu zU!(E+5%jOfr9=TzQb$z9mKVEGG#lZ#xX06C8mSB!l!386e}tc?aG&q@V$Wt8z2|}7 zF`+5$?N=iuM+7IDi8a$d5qELkwW0qAcGuj94njD7;CnCu?dwpU8fO+&)Y~pvkDH2I ziY;qDYk>MiLRP=HjDEh`=WzpcPB)1STx=vRx^Wd%h%Cc=*0S_y+weef~ zczw$$)=9x;qoE}-cB-f=C)D6H>ryxH)F`l;rp z#Ov(L6TJ_l-={jt$&aQ(y^o-#_834DK^6o$SGkp#{^ho{{p83Z{hGPxj&))PKs}Ky zW&4a4?6{${_={6Rbdo*Yb7U@=PJ^W$@D2b$fZL8-M`JV|Dga#dcB~8Ne~Z|}Q{Pi5 zW^#5C8Kk8(Fs&jPtW5e`ElB*VM}jYjmG%Kj9UKZ^(9+IRN{oyoq|L62VwrDFcdSN+ z!MY18QP80#+%j0w9YXvMQhgT>g>MwhQ!E(zfH;|*XcE!({8InaO8xlp|5q!O+wvc@ zQnXyt53SJyhATzwY~M|0$@LtzQz6h-RYH6Gb$xjJJEx2{DK}GK|0U0Fv=O4*1|2zHZ6b zI93|oTj+xs_%#e_Nnyu&^E(<5Fva41f_2EUoneh7~>vPu{!);@aiY2!K zf<~@pYc{ffU9`jh(z?F^RdILm)|t6kGg?_&O-<91lJdWuihVnoO9c1XR^n790^{go zd%HO6o0;-g3Z~?|T8f-1q9~0I7RQGx{)GL-=0e@E#*2cCC*~=M18MSD0jyichC6>) z4kHItpC=-!tIx_^1ts5bElNGDMe&E84PH}U-UDSV`3QRpjRDLvt?i;%`>VIs=^W#{ zd_^uk0T}p15rf&89M@ASweKnfUn%M2?{{kU>|RP;KzxwQX8sC>p&6}%*N3q8oax&M z%H)|RrVqdjFoB$y!$Oes`UD#}v3L(eYuxjG9zq-n7h#27vKgUL!<{~Q7@~t z-%~zUb{G~SftNHl_X(6B=<>@{*nY9uI{8^3eWf#rp#*Z6vzwmrfrB5-gNKcF``JJZjtA1Ls6m0wt? zs*kuDd#v%=MV&V6@fCaKDTs{99r@GV_nMkmED|%KT9eYgpC6bvTYAQK*k=%Eo`5bk z3>UtFr1)WYrm>0dA&|M4=ANV%aJ~T*j>CfK&wRpjdK5UwiRKYMR1++jcLy+(-8c;k zC3)@*5F`Ia*ma!r>WgFGO;9p#*So&fQt5NxVFLsUwBGenKwA1>d^`LmCSB(duc=i4 zuRaJRP$J8C0*5A#ejIyqKl5lJ1;ab{Dfb~lT+f4ZdL|A7Z+n3)w5;t5ilF-wN=U#W z1mpKZsSpfF0G$}IPvjK@7)rnUqo$vXLZFW~v}ZQF+U2z?jb4wWcH4zt9n7z3uu5HP zGhlA-6`g~fUrO^t5b(XJHII^f@D2N!H_65+;dkFiQtYh(O+zWWggP)Qv?MvF8SL!shq#2+-?HEprCiJsbAqCNJ@`?N-6VZ`rKRE~MH1A=3$$L*hZ+sG`zmxo?26I+=Q2BFOUmZHwR?wjC_K0BvY4>}9ml`eyMQJL3-xW^M=Y?a21S8Gf@ZM}R;c{} z_VZbVvyRNvn1kBx|T{;-RTC|bXxy#KuDy}&6%SNYmfR`d8>t&4qi{vZFIsN`qph%Pz0k5=wP+IF9cz1y4 zT`v%|5Omn|tSoN4DsvNSl*w3*9inL~Z22I(QT5aPspeYTeJZ>P%;MBQB%Vfw{#L~A zw^h#MS~zeTYVl=f<#9KHkUdbL`)jFekQA(e9#J z&%Q2bdtx5sI*`__N3vVqmD&BZb3kd?-r8%dPGWFEKPus(Jy-)|<%woeD>VW%$Oi!C zLUZ{Rj5Jk{paUx6y}|o0ALNNFN-Bhhy2=)x^W!Hr&c)jtH*afxxGl8-m!Qrnl9J5F zVq&6kBl#S2KGl?1bWbson7IAY2}!MkxF;h=HZU+6Hp6V#^Y}BFuN3WF?fdPB%|P~( z)I=dPLX!7oCo}E5!)~Mx!cgBtrd?rSrS~8;CLiW8n&nGOM8eTln~}9g_7y{Yx&o#& zlg#|@lc|5|$J#(PU8byVBAo9+&<$U}_OZIFuj#7M#kp2!t~Tod%}hk!V1*umxY0Aa-!K9q^?$w*gz z+A{>Swdx~wbqPp4x%}3YK_RcywU;Rx?9cusD+{8N3#6Zw&J%jct!ZBb{SFn6tZ-?V zng1VYZyne4+xPveNGMXG(jcG$(jgrpEg&t;2$62-n1pnQbcdvLHY

JXiH00a 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 literal 123005 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 ZACj^b;N!+3CdcN^+xKH(+06xws#wV66NazPp5^ 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 Qe=RBsn(wOLeEjnN0JUtf6aWAK diff --git a/docs/en/deployment/distributed-deployment-guide.md b/docs/en/deployment/distributed-deployment-guide.md index 87592367e94..6ef7cc8cfcc 100644 --- a/docs/en/deployment/distributed-deployment-guide.md +++ b/docs/en/deployment/distributed-deployment-guide.md @@ -217,12 +217,12 @@ You can choose to create it by manually importing SQL or by automatically import #### 2.1.1.1 Manual SQL Import -You can import [apolloportaldb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/apolloportaldb.sql) through various MySQL clients. +You can import [apolloportaldb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/apolloportaldb.sql) through various MySQL clients. Using the native MySQL client as an example. ```sql -source /your_local_path/scripts/sql/apolloportaldb.sql +source /your_local_path/scripts/sql/profiles/mysql-default/apolloportaldb.sql ``` #### 2.1.1.2 Created via Flyway import SQL @@ -252,12 +252,12 @@ You can choose to create it by manually importing SQL or automatically importing #### 2.1.2.1 Importing SQL Manually -You can import [apolloconfigdb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/apolloconfigdb.sql) through various MySQL clients. +You can import [apolloconfigdb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/apolloconfigdb.sql) through various MySQL clients. Using the native MySQL client as an example. ```sql -source /your_local_path/scripts/sql/apolloconfigdb.sql +source /your_local_path/scripts/sql/profiles/mysql-default/apolloconfigdb.sql ``` #### 2.1.2.2 SQL import via Flyway diff --git a/docs/en/deployment/quick-start.md b/docs/en/deployment/quick-start.md index 030593126cf..41a436617e8 100644 --- a/docs/en/deployment/quick-start.md +++ b/docs/en/deployment/quick-start.md @@ -75,79 +75,108 @@ No configuration is required, just use the following command to start > Note: When using the in-memory database, any operation will be lost after the Apollo process restarts ```bash export SPRING_PROFILES_ACTIVE="github,auth" -unset SPRING_SQL_INIT_MODE +unset SPRING_SQL_CONFIG_INIT_MODE +unset SPRING_SQL_PORTAL_INIT_MODE java -jar apollo-all-in-one.jar ``` ## 2.2 Use H2 file database, automatic initialization #### Precautions -1. The path `~/apollo/apolloassemblydb` in the SPRING_DATASOURCE_URL environment variable in the script can be replaced with other custom paths, you need to ensure that this path has read and write permissions +1. The path `~/apollo/apollo-config-db` and `~/apollo/apollo-portal-db` in the environment variable in the script can be replaced with other custom paths, you need to ensure that this path has read and write permissions ### 2.2.1 First startup -Use the SPRING_SQL_INIT_MODE="always" environment variable for initialization at the first startup +Use the SPRING_SQL_CONFIG_INIT_MODE="always" and SPRING_SQL_PORTAL_INIT_MODE="always" environment variable for initialization at the first startup ```bash export SPRING_PROFILES_ACTIVE="github,auth" -export SPRING_SQL_INIT_MODE="always" -export SPRING_DATASOURCE_URL="jdbc:h2:file:~/apollo/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +# config db +export SPRING_SQL_CONFIG_INIT_MODE="always" +export SPRING_CONFIG_DATASOURCE_URL="jdbc:h2:file:~/apollo/apollo-config-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +# portal db +export SPRING_SQL_PORTAL_INIT_MODE="always" +export SPRING_PORTAL_DATASOURCE_URL="jdbc:h2:file:~/apollo/apollo-portal-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" java -jar apollo-all-in-one.jar ``` ### 2.2.2 Subsequent startup -Remove the SPRING_SQL_INIT_MODE environment variable to avoid repeated initialization at subsequent startup +Remove the SPRING_SQL_CONFIG_INIT_MODE and SPRING_SQL_PORTAL_INIT_MODE environment variable to avoid repeated initialization at subsequent startup ```bash export SPRING_PROFILES_ACTIVE="github,auth" -unset SPRING_SQL_INIT_MODE -export SPRING_DATASOURCE_URL="jdbc:h2:file:~/apollo/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +# config db +unset SPRING_SQL_CONFIG_INIT_MODE +export SPRING_CONFIG_DATASOURCE_URL="jdbc:h2:file:~/apollo/apollo-config-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +# portal db +unset SPRING_SQL_PORTAL_INIT_MODE +export SPRING_PORTAL_DATASOURCE_URL="jdbc:h2:file:~/apollo/apollo-portal-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" java -jar apollo-all-in-one.jar ``` ## 2.3 Use mysql database, automatic initialization #### Precautions -1. The your-mysql-server:3306 in the SPRING_DATASOURCE_URL environment variable in the script needs to be replaced with the actual mysql server address and port, ApolloAssemblyDB needs to be replaced with the actual database name -2. The SPRING_DATASOURCE_USERNAME and SPRING_DATASOURCE_PASSWORD environment variables in the script need to fill in the actual username and password +1. The your-mysql-server:3306 in the environment variable in the script needs to be replaced with the actual mysql server address and port, ApolloConfigDB and ApolloPortalDB needs to be replaced with the actual database name +2. The "apollo-username" and "apollo-password" in the environment variables in the script need to fill in the actual username and password ### 2.3.1 First startup Use the SPRING_SQL_INIT_MODE="always" environment variable for initialization at the first startup ```bash export SPRING_PROFILES_ACTIVE="github,auth" -export SPRING_SQL_INIT_MODE="always" -export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" -export SPRING_DATASOURCE_USERNAME="apollo-username" -export SPRING_DATASOURCE_PASSWORD="apollo-password" +# config db +export SPRING_SQL_CONFIG_INIT_MODE="always" +export SPRING_CONFIG_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloConfigDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_CONFIG_DATASOURCE_USERNAME="apollo-username" +export SPRING_CONFIG_DATASOURCE_PASSWORD="apollo-password" +# portal db +export SPRING_SQL_PORTAL_INIT_MODE="always" +export SPRING_PORTAL_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloPortalDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_PORTAL_DATASOURCE_USERNAME="apollo-username" +export SPRING_PORTAL_DATASOURCE_PASSWORD="apollo-password" java -jar apollo-all-in-one.jar ``` ### 2.3.2 Subsequent startup -Remove the SPRING_SQL_INIT_MODE environment variable to avoid repeated initialization at subsequent startup +Remove the SPRING_SQL_CONFIG_INIT_MODE and SPRING_SQL_PORTAL_INIT_MODE environment variable to avoid repeated initialization at subsequent startup ```bash export SPRING_PROFILES_ACTIVE="github,auth" -unset SPRING_SQL_INIT_MODE -export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" -export SPRING_DATASOURCE_USERNAME="apollo-username" -export SPRING_DATASOURCE_PASSWORD="apollo-password" +# config db +unset SPRING_SQL_CONFIG_INIT_MODE +export SPRING_CONFIG_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloConfigDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_CONFIG_DATASOURCE_USERNAME="apollo-username" +export SPRING_CONFIG_DATASOURCE_PASSWORD="apollo-password" +# portal db +unset SPRING_SQL_PORTAL_INIT_MODE +export SPRING_PORTAL_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloPortalDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_PORTAL_DATASOURCE_USERNAME="apollo-username" +export SPRING_PORTAL_DATASOURCE_PASSWORD="apollo-password" java -jar apollo-all-in-one.jar ``` ## 2.4 Use mysql database, manual initialization -### 2.4.1 Manually initialize ApolloAssemblyDB -Import [sql/assembly](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/assembly) through various MySQL clients +### 2.4.1 Manually initialize ApolloConfigDB and ApolloPortalDB +You can import [apolloconfigdb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/apolloconfigdb.sql) to ApolloConfigDB through various MySQL clients. +You can import [apolloportaldb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/apolloportaldb.sql) to ApolloPortalDB through various MySQL clients. ### 2.4.2 Run #### Precautions -1. The your-mysql-server:3306 in the SPRING_DATASOURCE_URL environment variable in the script needs to be replaced with the actual mysql server address and port, ApolloAssemblyDB needs to be replaced with the actual database name -2. The SPRING_DATASOURCE_USERNAME and SPRING_DATASOURCE_PASSWORD environment variables in the script need to fill in the actual username and password +1. The your-mysql-server:3306 in the environment variable in the script needs to be replaced with the actual mysql server address and port, ApolloConfigDB and ApolloPortalDB needs to be replaced with the actual database name +2. The "apollo-username" and "apollo-password" in the environment variables in the script need to fill in the actual username and password + ```bash export SPRING_PROFILES_ACTIVE="github,auth" -unset SPRING_SQL_INIT_MODE -export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" -export SPRING_DATASOURCE_USERNAME="apollo-username" -export SPRING_DATASOURCE_PASSWORD="apollo-password" +# config db +unset SPRING_SQL_CONFIG_INIT_MODE +export SPRING_CONFIG_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloConfigDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_CONFIG_DATASOURCE_USERNAME="apollo-username" +export SPRING_CONFIG_DATASOURCE_PASSWORD="apollo-password" +# portal db +unset SPRING_SQL_PORTAL_INIT_MODE +export SPRING_PORTAL_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloPortalDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_PORTAL_DATASOURCE_USERNAME="apollo-username" +export SPRING_PORTAL_DATASOURCE_PASSWORD="apollo-password" java -jar apollo-all-in-one.jar ``` diff --git a/docs/en/development/apollo-development-guide.md b/docs/en/development/apollo-development-guide.md index 7b4fbfa59d3..a9202e54e2f 100644 --- a/docs/en/development/apollo-development-guide.md +++ b/docs/en/development/apollo-development-guide.md @@ -54,14 +54,21 @@ The following is an example of how to start `apollo-assembly` locally with Intel ``` >Note 1: apollo_profile is specified here as `github` and `auth`, where `github` is a profile required by Apollo for database configuration, and `auth` is added from 0.9.0 to support simple authentication using Spring Security provided by apollo. For more information you can refer to [Portal-implement-user-login-function](en/development/portal-how-to-implement-user-login-function) > ->Note 2: If you plan to use a MySQL database, you need to add `spring.datasource.*` related configuration, replace the database connection information with your own, note that the database is `ApolloAssemblyDB` -> +>Note 2: If you plan to use a MySQL database, you need to add `spring.config-datasource.*` related configuration, +> the your-mysql-server:3306 needs to be replaced with the actual mysql server address and port, +> ApolloConfigDB and ApolloPortalDB needs to be replaced with the actual database name, +> apollo-username and apollo-password need to be replaced with the actual username and password + ![ApolloApplication-Mysql-VM-Options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ApolloApplication-Mysql-VM-Options.png) ``` --Dspring.datasource.url=jdbc:mysql://localhost:3306/ApolloAssemblyDB?characterEncoding=utf8 --Dspring.datasource.username=root --Dspring.datasource.password= +-Dspring.config-datasource.url=jdbc:mysql://your-mysql-server:3306/ApolloConfigDB?useUnicode=true&characterEncoding=UTF8 +-Dspring.config-datasource.username=apollo-username +-Dspring.config-datasource.password=apollo-password + +-Dspring.portal-datasource.url=jdbc:mysql://your-mysql-server:3306/ApolloPortalDB?useUnicode=true&characterEncoding=UTF8 +-Dspring.portal-datasource.username=apollo-username +-Dspring.portal-datasource.password=apollo-password ``` The initialization script for the MySQL database can be found in the scripts/sql/profiles/mysql-default directory of this project. diff --git a/docs/en/development/portal-how-to-implement-user-login-function.md b/docs/en/development/portal-how-to-implement-user-login-function.md index 80686150e96..13610b4ea9b 100644 --- a/docs/en/development/portal-how-to-implement-user-login-function.md +++ b/docs/en/development/portal-how-to-implement-user-login-function.md @@ -10,7 +10,7 @@ Use the following steps. ### 1. Install 0.9.0 or above -> If the previous version is 0.8.0, you need to import [apolloportaldb-v080-v090.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/delta/v080-v090/apolloportaldb-v080-v090.sql) +> If the previous version is 0.8.0, you need to import [apolloportaldb-v080-v090.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/delta/v080-v090/apolloportaldb-v080-v090.sql) Checking ApolloPortalDB, the `Users` table should already exist and have an initial record. The initial user name is apollo and the password is admin. diff --git a/docs/zh/deployment/distributed-deployment-guide.md b/docs/zh/deployment/distributed-deployment-guide.md index f26ffed58d0..6b5c1fd933d 100644 --- a/docs/zh/deployment/distributed-deployment-guide.md +++ b/docs/zh/deployment/distributed-deployment-guide.md @@ -215,11 +215,11 @@ Apollo服务端共需要两个数据库:`ApolloPortalDB`和`ApolloConfigDB`, #### 2.1.1.1 手动导入SQL创建 -通过各种MySQL客户端导入[apolloportaldb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/apolloportaldb.sql)即可。 +通过各种MySQL客户端导入[apolloportaldb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/apolloportaldb.sql)即可。 以MySQL原生客户端为例: ```sql -source /your_local_path/scripts/sql/apolloportaldb.sql +source /your_local_path/scripts/sql/profiles/mysql-default/apolloportaldb.sql ``` #### 2.1.1.2 通过Flyway导入SQL创建 @@ -248,11 +248,11 @@ select `Id`, `Key`, `Value`, `Comment` from `ApolloPortalDB`.`ServerConfig` limi #### 2.1.2.1 手动导入SQL -通过各种MySQL客户端导入[apolloconfigdb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/apolloconfigdb.sql)即可。 +通过各种MySQL客户端导入[apolloconfigdb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/apolloconfigdb.sql)即可。 以MySQL原生客户端为例: ```sql -source /your_local_path/scripts/sql/apolloconfigdb.sql +source /your_local_path/scripts/sql/profiles/mysql-default/apolloconfigdb.sql ``` #### 2.1.2.2 通过Flyway导入SQL diff --git a/docs/zh/deployment/quick-start.md b/docs/zh/deployment/quick-start.md index f968970061b..d02012744b4 100644 --- a/docs/zh/deployment/quick-start.md +++ b/docs/zh/deployment/quick-start.md @@ -76,79 +76,108 @@ Quick Start只针对本地测试使用,所以一般用户不需要自己下载 > 注:使用内存数据库时,任何操作都会在 apollo 进程重启后丢失 ```bash export SPRING_PROFILES_ACTIVE="github,auth" -unset SPRING_SQL_INIT_MODE +unset SPRING_SQL_CONFIG_INIT_MODE +unset SPRING_SQL_PORTAL_INIT_MODE java -jar apollo-all-in-one.jar ``` ## 2.2 使用 H2 文件数据库,自动初始化 #### 注意事项 -1. 脚本中的 SPRING_DATASOURCE_URL 环境变量中的路径 `~/apollo/apolloassemblydb` 可以替换为其它自定义路径,需要保证该路径有读写权限 +1. 脚本中环境变量中的路径 `~/apollo/apollo-config-db` 和 `~/apollo/apollo-portal-db` 可以替换为其它自定义路径,需要保证该路径有读写权限 ### 2.2.1 首次启动 -首次启动使用 SPRING_SQL_INIT_MODE="always" 环境变量来进行初始化 +首次启动使用 SPRING_SQL_CONFIG_INIT_MODE="always" 和 SPRING_SQL_PORTAL_INIT_MODE="always" 环境变量来进行初始化 ```bash export SPRING_PROFILES_ACTIVE="github,auth" -export SPRING_SQL_INIT_MODE="always" -export SPRING_DATASOURCE_URL="jdbc:h2:file:~/apollo/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +# config db +export SPRING_SQL_CONFIG_INIT_MODE="always" +export SPRING_CONFIG_DATASOURCE_URL="jdbc:h2:file:~/apollo/apollo-config-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +# portal db +export SPRING_SQL_PORTAL_INIT_MODE="always" +export SPRING_PORTAL_DATASOURCE_URL="jdbc:h2:file:~/apollo/apollo-portal-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" java -jar apollo-all-in-one.jar ``` ### 2.2.2 后续启动 -后续启动去掉 SPRING_SQL_INIT_MODE 环境变量来避免重复初始化 +后续启动去掉 SPRING_SQL_CONFIG_INIT_MODE 和 SPRING_SQL_PORTAL_INIT_MODE 环境变量来避免重复初始化 ```bash export SPRING_PROFILES_ACTIVE="github,auth" -unset SPRING_SQL_INIT_MODE -export SPRING_DATASOURCE_URL="jdbc:h2:file:~/apollo/apolloassemblydb;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +# config db +unset SPRING_SQL_CONFIG_INIT_MODE +export SPRING_CONFIG_DATASOURCE_URL="jdbc:h2:file:~/apollo/apollo-config-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" +# portal db +unset SPRING_SQL_PORTAL_INIT_MODE +export SPRING_PORTAL_DATASOURCE_URL="jdbc:h2:file:~/apollo/apollo-portal-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE" java -jar apollo-all-in-one.jar ``` ## 2.3 使用 mysql 数据库,自动初始化 #### 注意事项 -1. 脚本中的 SPRING_DATASOURCE_URL 环境变量中的 your-mysql-server:3306 需要替换为实际的 mysql 服务器地址和端口,ApolloAssemblyDB 需要替换为实际的数据库名称 -2. 脚本中的 SPRING_DATASOURCE_USERNAME 和 SPRING_DATASOURCE_PASSWORD 环境变量需要填写实际的用户名和密码 +1. 脚本环境变量中的 your-mysql-server:3306 需要替换为实际的 mysql 服务器地址和端口,ApolloConfigDB 和 ApolloPortalDB 需要替换为实际的数据库名称 +2. 脚本环境变量中的 "apollo-username" 和 "apollo-password" 需要填写实际的用户名和密码 ### 2.3.1 首次启动 首次启动使用 SPRING_SQL_INIT_MODE="always" 环境变量来进行初始化 ```bash export SPRING_PROFILES_ACTIVE="github,auth" -export SPRING_SQL_INIT_MODE="always" -export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" -export SPRING_DATASOURCE_USERNAME="apollo-username" -export SPRING_DATASOURCE_PASSWORD="apollo-password" +# config db +export SPRING_SQL_CONFIG_INIT_MODE="always" +export SPRING_CONFIG_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloConfigDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_CONFIG_DATASOURCE_USERNAME="apollo-username" +export SPRING_CONFIG_DATASOURCE_PASSWORD="apollo-password" +# portal db +export SPRING_SQL_PORTAL_INIT_MODE="always" +export SPRING_PORTAL_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloPortalDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_PORTAL_DATASOURCE_USERNAME="apollo-username" +export SPRING_PORTAL_DATASOURCE_PASSWORD="apollo-password" java -jar apollo-all-in-one.jar ``` ### 2.3.2 后续启动 -后续启动去掉 SPRING_SQL_INIT_MODE 环境变量来避免重复初始化 +后续启动去掉 SPRING_SQL_CONFIG_INIT_MODE 和 SPRING_SQL_PORTAL_INIT_MODE 环境变量来避免重复初始化 ```bash export SPRING_PROFILES_ACTIVE="github,auth" -unset SPRING_SQL_INIT_MODE -export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" -export SPRING_DATASOURCE_USERNAME="apollo-username" -export SPRING_DATASOURCE_PASSWORD="apollo-password" +# config db +unset SPRING_SQL_CONFIG_INIT_MODE +export SPRING_CONFIG_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloConfigDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_CONFIG_DATASOURCE_USERNAME="apollo-username" +export SPRING_CONFIG_DATASOURCE_PASSWORD="apollo-password" +# portal db +unset SPRING_SQL_PORTAL_INIT_MODE +export SPRING_PORTAL_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloPortalDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_PORTAL_DATASOURCE_USERNAME="apollo-username" +export SPRING_PORTAL_DATASOURCE_PASSWORD="apollo-password" java -jar apollo-all-in-one.jar ``` ## 2.4 使用 mysql 数据库,手动初始化 -### 2.4.1 手动初始化 ApolloAssemblyDB -通过各种MySQL客户端导入 [sql/assembly](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/assembly) +### 2.4.1 手动初始化 ApolloConfigDB 和 ApolloPortalDB +ApolloConfigDB 通过各种MySQL客户端导入[apolloconfigdb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/apolloconfigdb.sql)即可。 +ApolloPortalDB 通过各种MySQL客户端导入[apolloportaldb.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/apolloportaldb.sql)即可。 ### 2.4.2 运行 #### 注意事项 -1. 脚本中的 SPRING_DATASOURCE_URL 环境变量中的 your-mysql-server:3306 需要替换为实际的 mysql 服务器地址和端口,ApolloAssemblyDB 需要替换为实际的数据库名称 -2. 脚本中的 SPRING_DATASOURCE_USERNAME 和 SPRING_DATASOURCE_PASSWORD 环境变量需要填写实际的用户名和密码 +1. 脚本环境变量中的 your-mysql-server:3306 需要替换为实际的 mysql 服务器地址和端口,ApolloConfigDB 和 ApolloPortalDB 需要替换为实际的数据库名称 +2. 脚本环境变量中的 "apollo-username" 和 "apollo-password" 需要填写实际的用户名和密码 + ```bash export SPRING_PROFILES_ACTIVE="github,auth" -unset SPRING_SQL_INIT_MODE -export SPRING_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloAssemblyDB?useUnicode=true&characterEncoding=UTF8" -export SPRING_DATASOURCE_USERNAME="apollo-username" -export SPRING_DATASOURCE_PASSWORD="apollo-password" +# config db +unset SPRING_SQL_CONFIG_INIT_MODE +export SPRING_CONFIG_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloConfigDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_CONFIG_DATASOURCE_USERNAME="apollo-username" +export SPRING_CONFIG_DATASOURCE_PASSWORD="apollo-password" +# portal db +unset SPRING_SQL_PORTAL_INIT_MODE +export SPRING_PORTAL_DATASOURCE_URL="jdbc:mysql://your-mysql-server:3306/ApolloPortalDB?useUnicode=true&characterEncoding=UTF8" +export SPRING_PORTAL_DATASOURCE_USERNAME="apollo-username" +export SPRING_PORTAL_DATASOURCE_PASSWORD="apollo-password" java -jar apollo-all-in-one.jar ``` diff --git a/docs/zh/development/apollo-development-guide.md b/docs/zh/development/apollo-development-guide.md index aab07e85617..427cccfae19 100644 --- a/docs/zh/development/apollo-development-guide.md +++ b/docs/zh/development/apollo-development-guide.md @@ -45,13 +45,21 @@ Apollo本地开发需要以下组件: ``` >注1:这里指定了apollo_profile是`github`和`auth`,其中`github`是Apollo必须的一个profile,用于数据库的配置,`auth`是从0.9.0新增的,用来支持使用apollo提供的Spring Security简单认证,更多信息可以参考[Portal-实现用户登录功能](zh/development/portal-how-to-implement-user-login-function) > ->注2:如果需要使用 mysql 数据库,添加`spring.datasource.*`相关配置,数据库连接信息替换成你自己的,注意数据库是`ApolloAssemblyDB` +>注2:如果需要使用 mysql 数据库,添加`spring.config-datasource.*` 和 `spring.portal-datasource.*` 相关配置, +> your-mysql-server:3306 需要替换为实际的 mysql 服务器地址和端口, +> ApolloConfigDB 和 ApolloPortalDB 需要替换为实际的数据库名称, +> apollo-username 和 apollo-password 需要替换为实际的用户名和密码 + ![ApolloApplication-Mysql-VM-Options](https://cdn.jsdelivr.net/gh/apolloconfig/apollo@master/doc/images/local-development/ApolloApplication-Mysql-VM-Options.png) ``` --Dspring.datasource.url=jdbc:mysql://localhost:3306/ApolloAssemblyDB?characterEncoding=utf8 --Dspring.datasource.username=root --Dspring.datasource.password= +-Dspring.config-datasource.url=jdbc:mysql://your-mysql-server:3306/ApolloConfigDB?useUnicode=true&characterEncoding=UTF8 +-Dspring.config-datasource.username=apollo-username +-Dspring.config-datasource.password=apollo-password + +-Dspring.portal-datasource.url=jdbc:mysql://your-mysql-server:3306/ApolloPortalDB?useUnicode=true&characterEncoding=UTF8 +-Dspring.portal-datasource.username=apollo-username +-Dspring.portal-datasource.password=apollo-password ``` mysql 数据库初始化脚本见 本项目 scripts/sql/profiles/mysql-default 目录下的文件 diff --git a/docs/zh/development/portal-how-to-implement-user-login-function.md b/docs/zh/development/portal-how-to-implement-user-login-function.md index cb406e616e3..ae8d996517b 100644 --- a/docs/zh/development/portal-how-to-implement-user-login-function.md +++ b/docs/zh/development/portal-how-to-implement-user-login-function.md @@ -8,7 +8,7 @@ Apollo是配置管理系统,会提供权限管理(Authorization),理论 使用步骤如下: ### 1. 安装0.9.0以上版本 ->如果之前是0.8.0版本,需要导入[apolloportaldb-v080-v090.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/delta/v080-v090/apolloportaldb-v080-v090.sql) +>如果之前是0.8.0版本,需要导入[apolloportaldb-v080-v090.sql](https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/delta/v080-v090/apolloportaldb-v080-v090.sql) 查看ApolloPortalDB,应该已经存在`Users`表,并有一条初始记录。初始用户名是apollo,密码是admin。 From 224bd7aa2760cd6b77f23eafca2e3f81162f41a0 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 12 Jan 2024 22:59:01 +0800 Subject: [PATCH 38/59] fix init --- .../ApolloDataSourceScriptDatabaseInitializer.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java index 7efe1c8a1e3..12727c5b5f8 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java @@ -142,7 +142,11 @@ private static String findRepositoryDirectory() { if ("file".equals(location.getProtocol())) { // running with ide String locationText = location.toString(); - return locationText.replace("/apollo-assembly/target/classes/", "/scripts/sql"); + if (!locationText.endsWith("/apollo-common/target/classes/")) { + throw new IllegalStateException( + "can not determine repository directory from classpath: " + locationText); + } + return locationText.replace("/apollo-common/target/classes/", "/scripts/sql"); } return null; } From 435348a35dc97607f82b3b72682bfe299369e6b7 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 12 Jan 2024 23:56:20 +0800 Subject: [PATCH 39/59] log apollo datasource initialize --- ...loDataSourceScriptDatabaseInitializer.java | 171 ++++------------- ...ourceScriptDatabaseInitializerFactory.java | 176 ++++++++++++++++++ .../ConfigServiceAssemblyConfiguration.java | 3 +- .../portal/PortalAssemblyConfiguration.java | 3 +- 4 files changed, 214 insertions(+), 139 deletions(-) create mode 100644 apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java index 12727c5b5f8..e6d3af94857 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializer.java @@ -16,161 +16,58 @@ */ package com.ctrip.framework.apollo.common.datasource; -import java.net.URL; -import java.security.CodeSource; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; import javax.sql.DataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.boot.jdbc.DataSourceBuilder; -import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.init.DataSourceScriptDatabaseInitializer; -import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; +import org.springframework.boot.sql.init.DatabaseInitializationMode; import org.springframework.boot.sql.init.DatabaseInitializationSettings; -import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.AbstractDriverBasedDataSource; import org.springframework.jdbc.datasource.SimpleDriverDataSource; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; public class ApolloDataSourceScriptDatabaseInitializer extends DataSourceScriptDatabaseInitializer { - public ApolloDataSourceScriptDatabaseInitializer(DataSource dataSource, - ApolloSqlInitializationProperties properties) { - super(determineDataSource(dataSource, properties), getSettings(dataSource, properties)); - } - - private static DataSource determineDataSource(DataSource dataSource, - ApolloSqlInitializationProperties properties) { - - String username = properties.getUsername(); - String password = properties.getPassword(); - if (StringUtils.hasText(username) && StringUtils.hasText(password)) { - return DataSourceBuilder.derivedFrom(dataSource) - .username(username) - .password(password) - .type(SimpleDriverDataSource.class) - .build(); - } - return dataSource; - } - - public static DatabaseInitializationSettings getSettings(DataSource dataSource, - ApolloSqlInitializationProperties properties) { - - PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver().withDriverPlatform( - DatabaseDriver.MARIADB, "mysql"); - - List schemaLocations = resolveLocations(properties.getSchemaLocations(), - platformResolver, - dataSource, properties); - List dataLocations = resolveLocations(properties.getDataLocations(), platformResolver, - dataSource, properties); - - DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); - settings.setSchemaLocations( - scriptLocations(schemaLocations, "schema", properties.getPlatform())); - settings.setDataLocations(scriptLocations(dataLocations, "data", properties.getPlatform())); - settings.setContinueOnError(properties.isContinueOnError()); - settings.setSeparator(properties.getSeparator()); - settings.setEncoding(properties.getEncoding()); - settings.setMode(properties.getMode()); - return settings; - } - - - private static List resolveLocations(Collection locations, - PlatformPlaceholderDatabaseDriverResolver platformResolver, DataSource dataSource, - ApolloSqlInitializationProperties properties) { - - if (CollectionUtils.isEmpty(locations)) { - return null; - } - - Collection convertedLocations = convertRepositoryLocations(locations, dataSource); - if (CollectionUtils.isEmpty(convertedLocations)) { - return null; - } + private static final Logger log = LoggerFactory.getLogger( + ApolloDataSourceScriptDatabaseInitializer.class); - String platform = properties.getPlatform(); - if (StringUtils.hasText(platform) && !"all".equals(platform)) { - return platformResolver.resolveAll(platform, convertedLocations.toArray(new String[0])); - } - return platformResolver.resolveAll(dataSource, convertedLocations.toArray(new String[0])); - } - - private static Collection convertRepositoryLocations(Collection locations, - DataSource dataSource) { - if (CollectionUtils.isEmpty(locations)) { - return null; - } - String repositoryDir = findRepositoryDirectory(); - String suffix = findSuffix(dataSource); - List convertedLocations = new ArrayList<>(locations.size()); - for (String location : locations) { - String convertedLocation = convertRepositoryLocation(location, repositoryDir, suffix); - if (StringUtils.hasText(convertedLocation)) { - convertedLocations.add(convertedLocation); - } - } - return convertedLocations; - } - - private static String findSuffix(DataSource dataSource) { - DatabaseDriver databaseDriver = DatabaseDriver.fromDataSource(dataSource); - if (DatabaseDriver.MYSQL.equals(databaseDriver)) { - JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); - String database = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class); - if (database != null) { - return "-database-not-specified"; - } - } - return ""; - } - - private static String findRepositoryDirectory() { - CodeSource codeSource = ApolloDataSourceScriptDatabaseInitializer.class.getProtectionDomain() - .getCodeSource(); - URL location = codeSource != null ? codeSource.getLocation() : null; - if (location == null) { - return null; - } - if ("jar".equals(location.getProtocol())) { - // running with jar - return "classpath:META-INF/sql"; - } - if ("file".equals(location.getProtocol())) { - // running with ide - String locationText = location.toString(); - if (!locationText.endsWith("/apollo-common/target/classes/")) { - throw new IllegalStateException( - "can not determine repository directory from classpath: " + locationText); + public ApolloDataSourceScriptDatabaseInitializer(DataSource dataSource, + DatabaseInitializationSettings settings) { + super(dataSource, settings); + if (this.isEnabled(settings)) { + log.info("Apollo DataSource Initialize is enabled"); + if (log.isDebugEnabled()) { + String jdbcUrl = this.getJdbcUrl(dataSource); + log.debug("Initialize jdbc url: {}", jdbcUrl); + List schemaLocations = settings.getSchemaLocations(); + if (!schemaLocations.isEmpty()) { + for (String schemaLocation : schemaLocations) { + log.debug("Initialize Schema Location: {}", schemaLocation); + } + } } - return locationText.replace("/apollo-common/target/classes/", "/scripts/sql"); + } else { + log.info("Apollo DataSource Initialize is disabled"); } - return null; } - private static String convertRepositoryLocation(String location, String repositoryDir, - String suffix) { - if (!StringUtils.hasText(location)) { - return location; - } - if (!StringUtils.hasText(repositoryDir)) { - // repository dir not found - return null; + private String getJdbcUrl(DataSource dataSource) { + if (dataSource instanceof AbstractDriverBasedDataSource) { + AbstractDriverBasedDataSource driverBasedDataSource = (AbstractDriverBasedDataSource) dataSource; + return driverBasedDataSource.getUrl(); } - return location.replace("@@repository@@", repositoryDir).replace("@@suffix@@", suffix); + SimpleDriverDataSource simpleDriverDataSource = DataSourceBuilder.derivedFrom(dataSource) + .type(SimpleDriverDataSource.class) + .build(); + return simpleDriverDataSource.getUrl(); } - private static List scriptLocations(List locations, String fallback, - String platform) { - if (locations != null) { - return locations; + private boolean isEnabled(DatabaseInitializationSettings settings) { + if (settings.getMode() == DatabaseInitializationMode.NEVER) { + return false; } - List fallbackLocations = new ArrayList<>(); - fallbackLocations.add("optional:classpath*:" + fallback + "-" + platform + ".sql"); - fallbackLocations.add("optional:classpath*:" + fallback + ".sql"); - return fallbackLocations; + return settings.getMode() == DatabaseInitializationMode.ALWAYS || this.isEmbeddedDatabase(); } } diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java new file mode 100644 index 00000000000..c5f85582af7 --- /dev/null +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java @@ -0,0 +1,176 @@ +/* + * Copyright 2024 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.common.datasource; + +import java.net.URL; +import java.security.CodeSource; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.sql.DataSource; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.boot.jdbc.DatabaseDriver; +import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; +import org.springframework.boot.sql.init.DatabaseInitializationSettings; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.SimpleDriverDataSource; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +public class ApolloDataSourceScriptDatabaseInitializerFactory { + + public static ApolloDataSourceScriptDatabaseInitializer create(DataSource dataSource, + ApolloSqlInitializationProperties properties) { + DataSource determinedDataSource = determineDataSource(dataSource, properties); + DatabaseInitializationSettings settings = getSettings(dataSource, properties); + return new ApolloDataSourceScriptDatabaseInitializer(determinedDataSource, settings); + } + + private static DataSource determineDataSource(DataSource dataSource, + ApolloSqlInitializationProperties properties) { + + String username = properties.getUsername(); + String password = properties.getPassword(); + if (StringUtils.hasText(username) && StringUtils.hasText(password)) { + return DataSourceBuilder.derivedFrom(dataSource) + .username(username) + .password(password) + .type(SimpleDriverDataSource.class) + .build(); + } + return dataSource; + } + + private static DatabaseInitializationSettings getSettings(DataSource dataSource, + ApolloSqlInitializationProperties properties) { + + PlatformPlaceholderDatabaseDriverResolver platformResolver = new PlatformPlaceholderDatabaseDriverResolver().withDriverPlatform( + DatabaseDriver.MARIADB, "mysql"); + + List schemaLocations = resolveLocations(properties.getSchemaLocations(), + platformResolver, + dataSource, properties); + List dataLocations = resolveLocations(properties.getDataLocations(), platformResolver, + dataSource, properties); + + DatabaseInitializationSettings settings = new DatabaseInitializationSettings(); + settings.setSchemaLocations( + scriptLocations(schemaLocations, "schema", properties.getPlatform())); + settings.setDataLocations(scriptLocations(dataLocations, "data", properties.getPlatform())); + settings.setContinueOnError(properties.isContinueOnError()); + settings.setSeparator(properties.getSeparator()); + settings.setEncoding(properties.getEncoding()); + settings.setMode(properties.getMode()); + return settings; + } + + + private static List resolveLocations(Collection locations, + PlatformPlaceholderDatabaseDriverResolver platformResolver, DataSource dataSource, + ApolloSqlInitializationProperties properties) { + + if (CollectionUtils.isEmpty(locations)) { + return null; + } + + Collection convertedLocations = convertRepositoryLocations(locations, dataSource); + if (CollectionUtils.isEmpty(convertedLocations)) { + return null; + } + + String platform = properties.getPlatform(); + if (StringUtils.hasText(platform) && !"all".equals(platform)) { + return platformResolver.resolveAll(platform, convertedLocations.toArray(new String[0])); + } + return platformResolver.resolveAll(dataSource, convertedLocations.toArray(new String[0])); + } + + private static Collection convertRepositoryLocations(Collection locations, + DataSource dataSource) { + if (CollectionUtils.isEmpty(locations)) { + return null; + } + String repositoryDir = findRepositoryDirectory(); + String suffix = findSuffix(dataSource); + List convertedLocations = new ArrayList<>(locations.size()); + for (String location : locations) { + String convertedLocation = convertRepositoryLocation(location, repositoryDir, suffix); + if (StringUtils.hasText(convertedLocation)) { + convertedLocations.add(convertedLocation); + } + } + return convertedLocations; + } + + private static String findSuffix(DataSource dataSource) { + DatabaseDriver databaseDriver = DatabaseDriver.fromDataSource(dataSource); + if (DatabaseDriver.MYSQL.equals(databaseDriver)) { + JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); + String database = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class); + if (database != null) { + return "-database-not-specified"; + } + } + return ""; + } + + private static String findRepositoryDirectory() { + CodeSource codeSource = ApolloDataSourceScriptDatabaseInitializer.class.getProtectionDomain() + .getCodeSource(); + URL location = codeSource != null ? codeSource.getLocation() : null; + if (location == null) { + return null; + } + if ("jar".equals(location.getProtocol())) { + // running with jar + return "classpath:META-INF/sql"; + } + if ("file".equals(location.getProtocol())) { + // running with ide + String locationText = location.toString(); + if (!locationText.endsWith("/apollo-common/target/classes/")) { + throw new IllegalStateException( + "can not determine repository directory from classpath: " + locationText); + } + return locationText.replace("/apollo-common/target/classes/", "/scripts/sql"); + } + return null; + } + + private static String convertRepositoryLocation(String location, String repositoryDir, + String suffix) { + if (!StringUtils.hasText(location)) { + return location; + } + if (!StringUtils.hasText(repositoryDir)) { + // repository dir not found + return null; + } + return location.replace("@@repository@@", repositoryDir).replace("@@suffix@@", suffix); + } + + private static List scriptLocations(List locations, String fallback, + String platform) { + if (locations != null) { + return locations; + } + List fallbackLocations = new ArrayList<>(); + fallbackLocations.add("optional:classpath*:" + fallback + "-" + platform + ".sql"); + fallbackLocations.add("optional:classpath*:" + fallback + ".sql"); + return fallbackLocations; + } +} diff --git a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAssemblyConfiguration.java b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAssemblyConfiguration.java index 6d38a0b9dc4..3321019eb1b 100644 --- a/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAssemblyConfiguration.java +++ b/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/ConfigServiceAssemblyConfiguration.java @@ -17,6 +17,7 @@ package com.ctrip.framework.apollo.configservice; import com.ctrip.framework.apollo.common.datasource.ApolloDataSourceScriptDatabaseInitializer; +import com.ctrip.framework.apollo.common.datasource.ApolloDataSourceScriptDatabaseInitializerFactory; import com.ctrip.framework.apollo.common.datasource.ApolloSqlInitializationProperties; import javax.sql.DataSource; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -38,6 +39,6 @@ public static ApolloSqlInitializationProperties apolloSqlInitializationPropertie public static ApolloDataSourceScriptDatabaseInitializer apolloDataSourceScriptDatabaseInitializer( DataSource dataSource, ApolloSqlInitializationProperties properties) { - return new ApolloDataSourceScriptDatabaseInitializer(dataSource, properties); + return ApolloDataSourceScriptDatabaseInitializerFactory.create(dataSource, properties); } } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalAssemblyConfiguration.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalAssemblyConfiguration.java index 1959b6df14c..08b9909b09d 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalAssemblyConfiguration.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/PortalAssemblyConfiguration.java @@ -17,6 +17,7 @@ package com.ctrip.framework.apollo.portal; import com.ctrip.framework.apollo.common.datasource.ApolloDataSourceScriptDatabaseInitializer; +import com.ctrip.framework.apollo.common.datasource.ApolloDataSourceScriptDatabaseInitializerFactory; import com.ctrip.framework.apollo.common.datasource.ApolloSqlInitializationProperties; import javax.sql.DataSource; import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties; @@ -47,6 +48,6 @@ public static ApolloSqlInitializationProperties apolloSqlInitializationPropertie public static ApolloDataSourceScriptDatabaseInitializer apolloDataSourceScriptDatabaseInitializer( DataSource dataSource, ApolloSqlInitializationProperties properties) { - return new ApolloDataSourceScriptDatabaseInitializer(dataSource, properties); + return ApolloDataSourceScriptDatabaseInitializerFactory.create(dataSource, properties); } } From 0397d900f8840980a7c55537d750267e9ece725f Mon Sep 17 00:00:00 2001 From: vdisk Date: Sat, 13 Jan 2024 00:09:02 +0800 Subject: [PATCH 40/59] fix apollo datasource initialize --- .../ApolloDataSourceScriptDatabaseInitializerFactory.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java index c5f85582af7..443592644d2 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java @@ -118,11 +118,16 @@ private static Collection convertRepositoryLocations(Collection private static String findSuffix(DataSource dataSource) { DatabaseDriver databaseDriver = DatabaseDriver.fromDataSource(dataSource); + if (DatabaseDriver.H2.equals(databaseDriver)) { + return ""; + } if (DatabaseDriver.MYSQL.equals(databaseDriver)) { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); String database = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class); if (database != null) { return "-database-not-specified"; + } else { + return "-default"; } } return ""; From ee487c8b706bfbc97a538ad416e9a72907ecd0cf Mon Sep 17 00:00:00 2001 From: vdisk Date: Sat, 13 Jan 2024 00:16:40 +0800 Subject: [PATCH 41/59] mv h2 sql --- apollo-assembly/pom.xml | 4 ++-- .../apollo/build/sql/converter/ApolloSqlConverter.java | 8 ++++---- .../build/sql/converter/ApolloSqlConverterTest.java | 10 +++++----- ...olloDataSourceScriptDatabaseInitializerFactory.java | 2 +- .../sql/profiles/{h2 => h2-default}/apolloconfigdb.sql | 0 .../sql/profiles/{h2 => h2-default}/apolloportaldb.sql | 0 .../delta/v220-v230/apolloconfigdb-v220-v230.sql | 0 .../delta/v220-v230/apolloportaldb-v220-v230.sql | 0 8 files changed, 12 insertions(+), 12 deletions(-) rename scripts/sql/profiles/{h2 => h2-default}/apolloconfigdb.sql (100%) rename scripts/sql/profiles/{h2 => h2-default}/apolloportaldb.sql (100%) rename scripts/sql/profiles/{h2 => h2-default}/delta/v220-v230/apolloconfigdb-v220-v230.sql (100%) rename scripts/sql/profiles/{h2 => h2-default}/delta/v220-v230/apolloportaldb-v220-v230.sql (100%) diff --git a/apollo-assembly/pom.xml b/apollo-assembly/pom.xml index e93c67c38ae..5e006314f14 100644 --- a/apollo-assembly/pom.xml +++ b/apollo-assembly/pom.xml @@ -63,8 +63,8 @@ ${project.parent.basedir}/scripts/sql/profiles - h2/apolloconfigdb.sql - h2/apolloportaldb.sql + h2-default/apolloconfigdb.sql + h2-default/apolloportaldb.sql mysql-database-not-specified/apolloconfigdb.sql mysql-database-not-specified/apolloportaldb.sql mysql-default/apolloconfigdb.sql diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverter.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverter.java index 7085578b62b..e340571176f 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverter.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverter.java @@ -54,8 +54,8 @@ public static List convert(String targetParentDir) { // 'scripts/sql/src' -> 'scripts/sql/profiles/mysql-database-not-specified' convertMysqlDatabaseNotSpecifiedList(templateList, srcDir, targetParentDir, gists); - // 'scripts/sql/src' -> 'scripts/sql/profiles/h2' - convertH2List(templateList, srcDir, targetParentDir, gists); + // 'scripts/sql/src' -> 'scripts/sql/profiles/h2-default' + convertH2DefaultList(templateList, srcDir, targetParentDir, gists); return srcSqlList; } @@ -111,9 +111,9 @@ private static void convertMysqlDatabaseNotSpecifiedList(List templ } } - private static void convertH2List(List templateList, String srcDir, + private static void convertH2DefaultList(List templateList, String srcDir, String targetParentDir, SqlTemplateGist gists) { - String targetDir = targetParentDir + "/sql/profiles/h2"; + String targetDir = targetParentDir + "/sql/profiles/h2-default"; SqlTemplateGist mainMysqlGists = SqlTemplateGist.builder() .autoGeneratedDeclaration(gists.getAutoGeneratedDeclaration()) diff --git a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java index f0e7bb075cf..eb13c44d81f 100644 --- a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java +++ b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java @@ -60,8 +60,8 @@ private void checkSqlList(List srcSqlList, String srcDir, String checker this.checkMysqlDatabaseNotSpecifiedList(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); - // '/scripts/sql/profiles/h2' - this.checkH2List(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); + // '/scripts/sql/profiles/h2-default' + this.checkH2DefaultList(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); } private void checkMysqlDefaultList(List srcSqlList, String srcDir, @@ -188,10 +188,10 @@ private void checkMysqlDatabaseNotSpecifiedList(List srcSqlList, String } } - private void checkH2List(List srcSqlList, String srcDir, + private void checkH2DefaultList(List srcSqlList, String srcDir, String checkerParentDir, String repositoryParentDir) { - String checkerTargetDir = checkerParentDir + "/sql/profiles/h2"; - String repositoryTargetDir = repositoryParentDir + "/sql/profiles/h2"; + String checkerTargetDir = checkerParentDir + "/sql/profiles/h2-default"; + String repositoryTargetDir = repositoryParentDir + "/sql/profiles/h2-default"; for (String srcSql : srcSqlList) { String checkerTargetSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, checkerTargetDir); diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java index 443592644d2..c9ca40cbb8c 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java @@ -119,7 +119,7 @@ private static Collection convertRepositoryLocations(Collection private static String findSuffix(DataSource dataSource) { DatabaseDriver databaseDriver = DatabaseDriver.fromDataSource(dataSource); if (DatabaseDriver.H2.equals(databaseDriver)) { - return ""; + return "-default"; } if (DatabaseDriver.MYSQL.equals(databaseDriver)) { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); diff --git a/scripts/sql/profiles/h2/apolloconfigdb.sql b/scripts/sql/profiles/h2-default/apolloconfigdb.sql similarity index 100% rename from scripts/sql/profiles/h2/apolloconfigdb.sql rename to scripts/sql/profiles/h2-default/apolloconfigdb.sql diff --git a/scripts/sql/profiles/h2/apolloportaldb.sql b/scripts/sql/profiles/h2-default/apolloportaldb.sql similarity index 100% rename from scripts/sql/profiles/h2/apolloportaldb.sql rename to scripts/sql/profiles/h2-default/apolloportaldb.sql diff --git a/scripts/sql/profiles/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql similarity index 100% rename from scripts/sql/profiles/h2/delta/v220-v230/apolloconfigdb-v220-v230.sql rename to scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql diff --git a/scripts/sql/profiles/h2/delta/v220-v230/apolloportaldb-v220-v230.sql b/scripts/sql/profiles/h2-default/delta/v220-v230/apolloportaldb-v220-v230.sql similarity index 100% rename from scripts/sql/profiles/h2/delta/v220-v230/apolloportaldb-v220-v230.sql rename to scripts/sql/profiles/h2-default/delta/v220-v230/apolloportaldb-v220-v230.sql From e24336aa2d9dd9a6a9293eb4e17610b9c8d8c9a6 Mon Sep 17 00:00:00 2001 From: vdisk Date: Sat, 13 Jan 2024 00:27:18 +0800 Subject: [PATCH 42/59] fix apollo datasource initialize v0.2 --- apollo-assembly/pom.xml | 2 -- .../ApolloDataSourceScriptDatabaseInitializerFactory.java | 8 +------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/apollo-assembly/pom.xml b/apollo-assembly/pom.xml index 5e006314f14..adea3607fea 100644 --- a/apollo-assembly/pom.xml +++ b/apollo-assembly/pom.xml @@ -67,8 +67,6 @@ h2-default/apolloportaldb.sql mysql-database-not-specified/apolloconfigdb.sql mysql-database-not-specified/apolloportaldb.sql - mysql-default/apolloconfigdb.sql - mysql-default/apolloportaldb.sql diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java index c9ca40cbb8c..f41e8c4e979 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java @@ -122,13 +122,7 @@ private static String findSuffix(DataSource dataSource) { return "-default"; } if (DatabaseDriver.MYSQL.equals(databaseDriver)) { - JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); - String database = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class); - if (database != null) { - return "-database-not-specified"; - } else { - return "-default"; - } + return "-database-not-specified"; } return ""; } From bbe2163350c7752109b82b63a20c707742bd506a Mon Sep 17 00:00:00 2001 From: vdisk Date: Sat, 13 Jan 2024 00:43:15 +0800 Subject: [PATCH 43/59] clean import --- .../ApolloDataSourceScriptDatabaseInitializerFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java index f41e8c4e979..74106334df7 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/datasource/ApolloDataSourceScriptDatabaseInitializerFactory.java @@ -26,7 +26,6 @@ import org.springframework.boot.jdbc.DatabaseDriver; import org.springframework.boot.jdbc.init.PlatformPlaceholderDatabaseDriverResolver; import org.springframework.boot.sql.init.DatabaseInitializationSettings; -import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.SimpleDriverDataSource; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; From d0aa029bf7271a87cebedef4e053a18a1dffd3e4 Mon Sep 17 00:00:00 2001 From: vdisk Date: Sat, 13 Jan 2024 00:53:00 +0800 Subject: [PATCH 44/59] fix sql check --- .../apollo/build/sql/converter/ApolloSqlConverterTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java index eb13c44d81f..c666c30da48 100644 --- a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java +++ b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java @@ -172,6 +172,9 @@ private void doCheck(String checkerTargetSql, String repositoryTargetSql) { "invalid sql file content, please run '" + GENERATE_TIPS + "' to regenerated\npath: " + repositoryTargetSql + "(line: " + lineNumber + ")"); } + Assertions.assertEquals(checkerLines.size(), repositoryLines.size(), + "invalid sql file content, please run '" + GENERATE_TIPS + "' to regenerated\npath: " + + repositoryTargetSql); } private void checkMysqlDatabaseNotSpecifiedList(List srcSqlList, String srcDir, From 5d212c32130f5cfa01365006332db1c9e9abfce2 Mon Sep 17 00:00:00 2001 From: vdisk Date: Sat, 13 Jan 2024 00:55:27 +0800 Subject: [PATCH 45/59] fix sql check v0.2 --- .../apollo/build/sql/converter/ApolloSqlConverterTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java index c666c30da48..4d4bfdce8f9 100644 --- a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java +++ b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java @@ -79,7 +79,8 @@ private void checkMysqlDefaultList(List srcSqlList, String srcDir, repositoryTargetDir, repositorySqlList); Assertions.assertEquals(0, redundantSqlList.size(), "redundant sql files, please add sql files in 'scripts/sql/src' and then run '" - + GENERATE_TIPS + "' to generated. Do not edit 'scripts/sql' manually !!!\npath: " + + GENERATE_TIPS + + "' to generated. Do not edit 'scripts/sql/profiles' manually !!!\npath: " + redundantSqlList); List missingSqlList = this.findMissingSqlList(checkerTargetDir, checkerSqlList, From 1080e41f1ec08f81bc90580aec0728b35750c86f Mon Sep 17 00:00:00 2001 From: vdisk Date: Mon, 15 Jan 2024 18:10:52 +0800 Subject: [PATCH 46/59] merge sql --- .../v220-v230/apolloconfigdb-v220-v230.sql | 21 ------------------- .../v220-v230/apolloconfigdb-v220-v230.sql | 2 ++ 2 files changed, 2 insertions(+), 21 deletions(-) delete mode 100644 scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql diff --git a/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql deleted file mode 100644 index 412b67f5fd2..00000000000 --- a/scripts/sql/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ /dev/null @@ -1,21 +0,0 @@ --- --- Copyright 2024 Apollo Authors --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. --- -# delta schema to upgrade apollo config db from v2.2.0 to v2.3.0 - -Use ApolloConfigDB; - -ALTER TABLE `Cluster` - ADD COLUMN `Comment` varchar(64) DEFAULT NULL COMMENT '备注'; \ No newline at end of file diff --git a/scripts/sql/src/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/src/delta/v220-v230/apolloconfigdb-v220-v230.sql index 7d021227974..b072cf9f311 100644 --- a/scripts/sql/src/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/src/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -19,5 +19,7 @@ -- ${gists.h2Function} -- ${gists.useDatabase} +ALTER TABLE `Cluster` + ADD COLUMN `Comment` varchar(64) DEFAULT NULL COMMENT '备注'; -- ${gists.autoGeneratedDeclaration} From bce70ef0b794c509c9438ace271f1f72922c26a1 Mon Sep 17 00:00:00 2001 From: vdisk Date: Mon, 15 Jan 2024 18:13:31 +0800 Subject: [PATCH 47/59] merge sql generated --- scripts/sql/profiles/h2-default/apolloconfigdb.sql | 1 + .../h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql | 2 ++ .../profiles/mysql-database-not-specified/apolloconfigdb.sql | 1 + .../delta/v220-v230/apolloconfigdb-v220-v230.sql | 2 ++ scripts/sql/profiles/mysql-default/apolloconfigdb.sql | 1 + .../mysql-default/delta/v220-v230/apolloconfigdb-v220-v230.sql | 2 ++ 6 files changed, 9 insertions(+) diff --git a/scripts/sql/profiles/h2-default/apolloconfigdb.sql b/scripts/sql/profiles/h2-default/apolloconfigdb.sql index 3da2b561f07..01971cc488f 100644 --- a/scripts/sql/profiles/h2-default/apolloconfigdb.sql +++ b/scripts/sql/profiles/h2-default/apolloconfigdb.sql @@ -123,6 +123,7 @@ CREATE TABLE `Cluster` ( `Name` varchar(32) NOT NULL DEFAULT '' , `AppId` varchar(64) NOT NULL DEFAULT '' , `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' , + `Comment` varchar(64) DEFAULT NULL , `IsDeleted` boolean NOT NULL DEFAULT FALSE , `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , diff --git a/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql index 0b7668b730b..346494053fb 100644 --- a/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -31,6 +31,8 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common -- +ALTER TABLE `Cluster` + ADD COLUMN `Comment` varchar(64) DEFAULT NULL ; -- -- =============================================================================== diff --git a/scripts/sql/profiles/mysql-database-not-specified/apolloconfigdb.sql b/scripts/sql/profiles/mysql-database-not-specified/apolloconfigdb.sql index c999b8c6df3..4d2e0c19118 100644 --- a/scripts/sql/profiles/mysql-database-not-specified/apolloconfigdb.sql +++ b/scripts/sql/profiles/mysql-database-not-specified/apolloconfigdb.sql @@ -118,6 +118,7 @@ CREATE TABLE `Cluster` ( `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id', `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', + `Comment` varchar(64) DEFAULT NULL COMMENT '备注', `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', diff --git a/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql index 96c79c3c365..3f659cea710 100644 --- a/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/profiles/mysql-database-not-specified/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -26,6 +26,8 @@ -- -- +ALTER TABLE `Cluster` + ADD COLUMN `Comment` varchar(64) DEFAULT NULL COMMENT '备注'; -- -- =============================================================================== diff --git a/scripts/sql/profiles/mysql-default/apolloconfigdb.sql b/scripts/sql/profiles/mysql-default/apolloconfigdb.sql index c2b3f030a04..3736ea599f3 100644 --- a/scripts/sql/profiles/mysql-default/apolloconfigdb.sql +++ b/scripts/sql/profiles/mysql-default/apolloconfigdb.sql @@ -123,6 +123,7 @@ CREATE TABLE `Cluster` ( `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id', `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', + `Comment` varchar(64) DEFAULT NULL COMMENT '备注', `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', diff --git a/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloconfigdb-v220-v230.sql index e76bafa8af7..a1defac266c 100644 --- a/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/profiles/mysql-default/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -28,6 +28,8 @@ -- Use Database Use ApolloConfigDB; +ALTER TABLE `Cluster` + ADD COLUMN `Comment` varchar(64) DEFAULT NULL COMMENT '备注'; -- -- =============================================================================== From d0e409e108ea469d68917d097e936e065dfcaf0d Mon Sep 17 00:00:00 2001 From: vdisk Date: Wed, 24 Jan 2024 00:04:29 +0800 Subject: [PATCH 48/59] add sql test temp --- apollo-build-sql-converter/pom.xml | 10 + .../sql/converter/ApolloH2ConverterUtil.java | 81 +++- .../ApolloMysqlDefaultConverterUtil.java | 15 +- .../sql/converter/ApolloSqlConverter.java | 28 +- .../sql/converter/ApolloSqlConverterUtil.java | 211 ++++++++- .../build/sql/converter/SqlStatement.java | 99 +++++ ... ApolloSqlConverterAutoGeneratedTest.java} | 14 +- .../converter/ApolloSqlConverterH2Test.java | 145 ++++++ .../build/sql/converter/TestH2Function.java | 24 + .../apolloconfigdb-v040-v050-after.sql | 14 + .../apolloconfigdb-v040-v050-base.sql | 414 ++++++++++++++++++ .../apolloconfigdb-v040-v050-before.sql | 14 + .../v040-v050/apolloconfigdb-v040-v050.sql | 30 ++ .../apolloportaldb-v040-v050-base.sql | 308 +++++++++++++ .../v040-v050/apolloportaldb-v040-v050.sql | 24 + .../v060-v062/apolloconfigdb-v060-v062.sql | 23 + .../v060-v062/apolloportaldb-v060-v062.sql | 23 + .../v080-v090/apolloportaldb-v080-v090.sql | 42 ++ .../v151-v160/apolloconfigdb-v151-v160.sql | 35 ++ .../v170-v180/apolloconfigdb-v170-v180.sql | 27 ++ .../v170-v180/apolloportaldb-v170-v180.sql | 22 + .../v180-v190/apolloconfigdb-v180-v190.sql | 72 +++ .../v180-v190/apolloportaldb-v180-v190.sql | 100 +++++ .../apolloconfigdb-v190-v200-after.sql | 86 ++++ .../v190-v200/apolloconfigdb-v190-v200.sql | 60 +++ .../apolloportaldb-v190-v200-after.sql | 81 ++++ .../v190-v200/apolloportaldb-v190-v200.sql | 53 +++ .../v200-v210/apolloconfigdb-v200-v210.sql | 39 ++ .../v210-v220/apolloconfigdb-v210-v220.sql | 95 ++++ .../v210-v220/apolloportaldb-v210-v220.sql | 81 ++++ .../profiles/h2-default/apolloconfigdb.sql | 119 +++-- .../profiles/h2-default/apolloportaldb.sql | 100 ++--- 32 files changed, 2310 insertions(+), 179 deletions(-) create mode 100644 apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlStatement.java rename apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/{ApolloSqlConverterTest.java => ApolloSqlConverterAutoGeneratedTest.java} (94%) create mode 100644 apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java create mode 100644 apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/TestH2Function.java create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-after.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-base.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-before.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050-base.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloconfigdb-v060-v062.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloportaldb-v060-v062.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v080-v090/apolloportaldb-v080-v090.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v151-v160/apolloconfigdb-v151-v160.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloconfigdb-v170-v180.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloportaldb-v170-v180.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloconfigdb-v180-v190.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloportaldb-v180-v190.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200-after.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200-after.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v200-v210/apolloconfigdb-v200-v210.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloconfigdb-v210-v220.sql create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloportaldb-v210-v220.sql diff --git a/apollo-build-sql-converter/pom.xml b/apollo-build-sql-converter/pom.xml index 4490f8ce96e..82d91068ec2 100644 --- a/apollo-build-sql-converter/pom.xml +++ b/apollo-build-sql-converter/pom.xml @@ -32,6 +32,16 @@ org.freemarker freemarker + + com.h2database + h2 + test + + + org.springframework.boot + spring-boot-starter-jdbc + test + diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java index a9c6070c1d2..ff4ae0ec1ca 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java @@ -16,22 +16,25 @@ */ package com.ctrip.framework.apollo.build.sql.converter; -import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; -import java.io.StringReader; import java.io.UncheckedIOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ApolloH2ConverterUtil { + private static final Pattern CREATE_TABLE_PATTERN = Pattern.compile("CREATE\\s+TABLE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?"); + private static final Pattern ALTER_TABLE_PATTERN = Pattern.compile("ALTER\\s+TABLE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?"); private static final Pattern TABLE_COMMENT_PATTERN = Pattern.compile("COMMENT='[^']*'"); - private static final Pattern INDEX_NAME_PATTERN = Pattern.compile("KEY *`[a-zA-Z0-9\\-_]+` *"); + private static final Pattern INDEX_NAME_PATTERN = Pattern.compile("KEY\\s*(`)?(?[a-zA-Z0-9\\-_]+)(`)?"); + private static final Pattern DROP_INDEX_PATTERN = Pattern.compile("DROP\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?"); + private static final Pattern CREATE_INDEX_PATTERN = Pattern.compile("CREATE\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?"); private static final Pattern PREFIX_INDEX_PATTERN = Pattern.compile( "(`[a-zA-Z0-9\\-_]+`)\\([0-9]+\\)"); private static final Pattern COLUMN_COMMENT_PATTERN = Pattern.compile("COMMENT *'[^']*'"); @@ -43,41 +46,54 @@ public static void convert(SqlTemplate sqlTemplate, String targetSql, String rawText = ApolloSqlConverterUtil.process(sqlTemplate, context); - try (BufferedReader bufferedReader = new BufferedReader(new StringReader(rawText)); - BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), + List sqlStatements = ApolloSqlConverterUtil.toStatements(rawText); + try (BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { - for (String line = bufferedReader.readLine(); line != null; - line = bufferedReader.readLine()) { - String convertedLine = convertAssemblyH2Line(line); + for (SqlStatement sqlStatement : sqlStatements) { + String convertedLine = convertAssemblyH2Line(sqlStatement); bufferedWriter.write(convertedLine); bufferedWriter.write('\n'); } + } catch (IOException e) { throw new UncheckedIOException(e); } } - private static String convertAssemblyH2Line(String line) { - String convertedLine = line; + private static String convertAssemblyH2Line(SqlStatement sqlStatement) { + String convertedLine = sqlStatement.getRawText(); // remove drop table if (convertedLine.contains("DROP TABLE")) { return ""; } - // table config - convertedLine = convertTableConfig(convertedLine); + String tableName = null; + Matcher createTableMatcher = CREATE_TABLE_PATTERN.matcher(convertedLine); + if (createTableMatcher.find()) { + tableName = createTableMatcher.group("tableName"); + // table config + convertedLine = convertTableConfig(convertedLine, sqlStatement); + } else { + Matcher alterTableMatcher = ALTER_TABLE_PATTERN.matcher(convertedLine); + if (alterTableMatcher.find()) { + tableName = alterTableMatcher.group("tableName"); + } + } - // index - convertedLine = convertIndex(convertedLine); + // index with table + convertedLine = convertIndexWithTable(convertedLine, tableName, sqlStatement); + + // index with alter + convertedLine = convertIndexWithAlter(convertedLine, tableName, sqlStatement); // column - convertedLine = convertColumn(convertedLine); + convertedLine = convertColumn(convertedLine, sqlStatement); return convertedLine; } - private static String convertTableConfig(String convertedLine) { + private static String convertTableConfig(String convertedLine, SqlStatement sqlStatement) { if (convertedLine.contains("ENGINE=InnoDB")) { convertedLine = convertedLine.replace("ENGINE=InnoDB", ""); } @@ -97,15 +113,15 @@ private static String convertTableConfig(String convertedLine) { return convertedLine; } - private static String convertIndex(String convertedLine) { + private static String convertIndexWithTable(String convertedLine,String tableName, SqlStatement sqlStatement) { if (convertedLine.contains("KEY")) { - // remove index name + // replace index name // KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) // -> - // KEY (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + // KEY `tableName_AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) Matcher indexNameMatcher = INDEX_NAME_PATTERN.matcher(convertedLine); if (indexNameMatcher.find()) { - convertedLine = indexNameMatcher.replaceAll("KEY "); + convertedLine = indexNameMatcher.replaceAll("KEY `" + tableName + "_${indexName}`"); } // convert prefix index @@ -121,7 +137,30 @@ private static String convertIndex(String convertedLine) { return convertedLine; } - private static String convertColumn(String convertedLine) { + private static String convertIndexWithAlter(String convertedLine, String tableName, + SqlStatement sqlStatement) { + Matcher dropIndexMatcher = DROP_INDEX_PATTERN.matcher(convertedLine); + if (dropIndexMatcher.find()) { + convertedLine = dropIndexMatcher.replaceAll("DROP INDEX `" + tableName + "_${indexName}`"); + } + Matcher createIndexMatcher = CREATE_INDEX_PATTERN.matcher(convertedLine); + if (createIndexMatcher.find()) { + convertedLine = createIndexMatcher.replaceAll("CREATE INDEX `" + tableName + "_${indexName}`"); + + // convert prefix index + // CREATE INDEX `IX_NAME` ON App (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + // -> + // CREATE INDEX `IX_NAME` ON App (`AppId`,`ClusterName`,`NamespaceName`) + for (Matcher prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedLine); + prefixIndexMatcher.find(); + prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedLine)) { + convertedLine = prefixIndexMatcher.replaceAll("$1"); + } + } + return convertedLine; + } + + private static String convertColumn(String convertedLine, SqlStatement sqlStatement) { // convert bit(1) to boolean // `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal' // -> diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloMysqlDefaultConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloMysqlDefaultConverterUtil.java index e7148aaf0f5..d41f9563523 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloMysqlDefaultConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloMysqlDefaultConverterUtil.java @@ -24,6 +24,8 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; public class ApolloMysqlDefaultConverterUtil { @@ -43,13 +45,12 @@ public static void convert(SqlTemplate sqlTemplate, String targetSql, String rawText = ApolloSqlConverterUtil.process(sqlTemplate, context); - try (BufferedReader bufferedReader = new BufferedReader(new StringReader(rawText)); - BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), + List sqlStatements = ApolloSqlConverterUtil.toStatements(rawText); + try (BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { - for (String line = bufferedReader.readLine(); line != null; - line = bufferedReader.readLine()) { - String convertedLine = convertMainMysqlLine(line, databaseName); + for (SqlStatement sqlStatement : sqlStatements) { + String convertedLine = convertMainMysqlLine(sqlStatement, databaseName); bufferedWriter.write(convertedLine); bufferedWriter.write('\n'); } @@ -58,8 +59,8 @@ public static void convert(SqlTemplate sqlTemplate, String targetSql, } } - private static String convertMainMysqlLine(String line, String databaseName) { - String convertedLine = line; + private static String convertMainMysqlLine(SqlStatement sqlStatement, String databaseName) { + String convertedLine = sqlStatement.getRawText(); convertedLine = convertedLine.replace("ApolloAssemblyDB", databaseName); diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverter.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverter.java index e340571176f..fac0e5a5d14 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverter.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverter.java @@ -27,19 +27,18 @@ public class ApolloSqlConverter { public static void main(String[] args) { String repositoryDir = ApolloSqlConverterUtil.getRepositoryDir(); + String srcDir = repositoryDir + "/scripts/sql/src"; String targetParentDir = repositoryDir + "/scripts"; - convert(targetParentDir); - } - - public static List convert(String targetParentDir) { + SqlTemplateGist gists = ApolloSqlConverterUtil.getGists(repositoryDir); - String repositoryDir = ApolloSqlConverterUtil.getRepositoryDir(); - String srcDir = repositoryDir + "/scripts/sql/src"; + convert(repositoryDir, srcDir, targetParentDir, gists); + } - Configuration configuration = createConfiguration(repositoryDir); + public static List convert(String repositoryDir, String srcDir, String targetParentDir, + SqlTemplateGist gists) { - SqlTemplateGist gists = ApolloSqlConverterUtil.getGists(repositoryDir); + Configuration configuration = createConfiguration(srcDir); // 'scripts/sql/src/apolloconfigdb.sql' // 'scripts/sql/src/apolloportaldb.sql' @@ -60,10 +59,10 @@ public static List convert(String targetParentDir) { return srcSqlList; } - private static Configuration createConfiguration(String repositoryDir) { + private static Configuration createConfiguration(String srcDir) { Configuration configuration = new Configuration(Configuration.VERSION_2_3_32); try { - configuration.setDirectoryForTemplateLoading(new File(repositoryDir + "/scripts/sql/src")); + configuration.setDirectoryForTemplateLoading(new File(srcDir)); } catch (IOException e) { throw new UncheckedIOException(e); } @@ -86,7 +85,8 @@ private static void convertMysqlDefaultList(List templateList, .build(); for (SqlTemplate sqlTemplate : templateList) { - String targetSql = ApolloSqlConverterUtil.replacePath(sqlTemplate.getSrcPath(), srcDir, targetDir); + String targetSql = ApolloSqlConverterUtil.replacePath(sqlTemplate.getSrcPath(), srcDir, + targetDir); ApolloMysqlDefaultConverterUtil.convert(sqlTemplate, targetSql, context); } } @@ -106,7 +106,8 @@ private static void convertMysqlDatabaseNotSpecifiedList(List templ .gists(mainMysqlGists) .build(); for (SqlTemplate sqlTemplate : templateList) { - String targetSql = ApolloSqlConverterUtil.replacePath(sqlTemplate.getSrcPath(), srcDir, targetDir); + String targetSql = ApolloSqlConverterUtil.replacePath(sqlTemplate.getSrcPath(), srcDir, + targetDir); ApolloMysqlDefaultConverterUtil.convert(sqlTemplate, targetSql, context); } } @@ -125,7 +126,8 @@ private static void convertH2DefaultList(List templateList, String .gists(mainMysqlGists) .build(); for (SqlTemplate sqlTemplate : templateList) { - String targetSql = ApolloSqlConverterUtil.replacePath(sqlTemplate.getSrcPath(), srcDir, targetDir); + String targetSql = ApolloSqlConverterUtil.replacePath(sqlTemplate.getSrcPath(), srcDir, + targetDir); ApolloH2ConverterUtil.convert(sqlTemplate, targetSql, context); } } diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterUtil.java index b2ce096d1b5..3c16d5df60c 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterUtil.java @@ -20,6 +20,7 @@ import freemarker.template.Template; import java.io.BufferedReader; import java.io.IOException; +import java.io.StringReader; import java.io.StringWriter; import java.io.UncheckedIOException; import java.net.URI; @@ -34,12 +35,27 @@ import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Set; import java.util.StringJoiner; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Pattern; public class ApolloSqlConverterUtil { + private static final Pattern BASE_PATTERN = Pattern.compile( + "(apolloconfigdb|apolloportaldb)-v[0-9]{3,}-v[0-9]{3,}-base.sql"); + + private static final Pattern BEFORE_PATTERN = Pattern.compile( + "(apolloconfigdb|apolloportaldb)-v[0-9]{3,}-v[0-9]{3,}-before.sql"); + + private static final Pattern DELTA_PATTERN = Pattern.compile( + "(apolloconfigdb|apolloportaldb)-v[0-9]{3,}-v[0-9]{3,}.sql"); + + private static final Pattern AFTER_PATTERN = Pattern.compile( + "(apolloconfigdb|apolloportaldb)-v[0-9]{3,}-v[0-9]{3,}-after.sql"); public static String getRepositoryDir() { ProtectionDomain protectionDomain = ApolloSqlConverter.class.getProtectionDomain(); @@ -49,7 +65,7 @@ public static String getRepositoryDir() { try { uri = location.toURI(); } catch (URISyntaxException e) { - throw new IllegalArgumentException(e.getLocalizedMessage(),e); + throw new IllegalArgumentException(e.getLocalizedMessage(), e); } Path path = Paths.get(uri); String unixClassPath = path.toString().replace("\\", "/"); @@ -164,13 +180,75 @@ public static List list(Path dir) { return subPathList; } + public static List listSorted(Path dir, Comparator comparator) { + List subPathList = list(dir); + List sortedSubPathList = new ArrayList<>(subPathList); + sortedSubPathList.sort(comparator); + return sortedSubPathList; + } + + public static List listSorted(Path dir) { + return listSorted(dir, Comparator.comparing(Path::toString)); + } + + public static void deleteDir(Path dir) { + try { + ApolloSqlConverterUtil.deleteDirInternal(dir); + } catch (IOException e) { + throw new UncheckedIOException("failed to delete dir " + e.getLocalizedMessage(), e); + } + } + + private static void deleteDirInternal(Path dir) throws IOException { + if (!Files.exists(dir)) { + return; + } + List files = ApolloSqlConverterUtil.list(dir); + for (Path file : files) { + if (!Files.exists(file)) { + continue; + } + if (Files.isDirectory(file)) { + ApolloSqlConverterUtil.deleteDirInternal(file); + Files.delete(file); + } else { + Files.delete(file); + } + } + } + + public static Comparator deltaSqlComparator() { + return Comparator.comparing(path -> { + String unixPath = path.replace("\\", "/"); + int lastIndex = unixPath.lastIndexOf("/"); + String fileName; + if (lastIndex > 0) { + fileName = unixPath.substring(lastIndex + 1); + } else { + fileName = unixPath; + } + // sort: base < before < delta < after + if (BASE_PATTERN.matcher(fileName).matches()) { + return "00" + path; + } else if (BEFORE_PATTERN.matcher(fileName).matches()) { + return "30" + path; + } else if (DELTA_PATTERN.matcher(fileName).matches()) { + return "50" + path; + } else if (AFTER_PATTERN.matcher(fileName).matches()) { + return "90" + path; + } else { + throw new IllegalArgumentException("illegal file name: " + fileName); + } + }); + } + private static List getDeltaSqlList(String dir, Set ignoreDirs) { Path dirPath = Paths.get(dir + "/delta"); if (!Files.exists(dirPath)) { return Collections.emptyList(); } - List deltaDirList = list(dirPath); - List deltaSqlList = new ArrayList<>(); + List deltaDirList = listSorted(dirPath); + List allDeltaSqlList = new ArrayList<>(); for (Path deltaDir : deltaDirList) { if (!Files.isDirectory(deltaDir)) { continue; @@ -178,16 +256,17 @@ private static List getDeltaSqlList(String dir, Set ignoreDirs) if (ignoreDirs.contains(deltaDir.toString().replace("\\", "/"))) { continue; } - List deltaFiles = list(deltaDir); + List deltaFiles = listSorted(deltaDir, + Comparator.comparing(Path::toString, deltaSqlComparator())); for (Path path : deltaFiles) { String fileName = path.toString(); if (fileName.endsWith(".sql")) { - deltaSqlList.add(fileName.replace("\\", "/")); + allDeltaSqlList.add(fileName.replace("\\", "/")); } } } - return deltaSqlList; + return allDeltaSqlList; } @@ -206,4 +285,124 @@ public static List toTemplates(List srcSqlList, String srcD } return templateList; } + + public static List toStatements(String rawText) { + List sqlStatementList = new ArrayList<>(); + try (BufferedReader bufferedReader = new BufferedReader(new StringReader(rawText))) { + AtomicReferencerawTextJoinerRef = new AtomicReference<>(new StringJoiner("\n")); + StringBuilder singleLineTextBuilder = new StringBuilder(); + List textLines = new ArrayList<>(); + AtomicBoolean comment = new AtomicBoolean(false); + for (String line = bufferedReader.readLine(); line != null; + line = bufferedReader.readLine()) { + if (line.startsWith("--")) { + commentLine(line, rawTextJoinerRef, singleLineTextBuilder, textLines, comment, + sqlStatementList); + } else { + noCommentLine(line, rawTextJoinerRef, singleLineTextBuilder, textLines, comment, + sqlStatementList); + } + } + if (!textLines.isEmpty()) { + StringJoiner sqlStatementRawTextJoiner = rawTextJoinerRef.get(); + SqlStatement sqlStatement = createStatement( + sqlStatementRawTextJoiner, singleLineTextBuilder, textLines); + sqlStatementList.add(sqlStatement); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return sqlStatementList; + } + + private static void commentLine(String line,AtomicReference rawTextJoinerRef, + StringBuilder singleLineTextBuilder, List textLines, AtomicBoolean comment, + List sqlStatementList) { + + if (!comment.get()) { + comment.set(true); + if (!textLines.isEmpty()) { + StringJoiner sqlStatementRawTextJoiner = rawTextJoinerRef.get(); + SqlStatement sqlStatement = createStatement( + sqlStatementRawTextJoiner, singleLineTextBuilder, textLines); + + resetStatementBuffer(rawTextJoinerRef, singleLineTextBuilder, + textLines); + sqlStatementList.add(sqlStatement); + } + } + StringJoiner sqlStatementRawTextJoiner = rawTextJoinerRef.get(); + // raw text + sqlStatementRawTextJoiner.add(line); + // single line text + singleLineTextBuilder.append(line); + // text lines + textLines.add(line); + } + + private static void noCommentLine(String line, AtomicReferencerawTextJoinerRef , + StringBuilder singleLineTextBuilder, List textLines, + AtomicBoolean comment, List sqlStatementList) { + + if (comment.get()) { + comment.set(false); + if (!textLines.isEmpty()) { + StringJoiner sqlStatementRawTextJoiner = rawTextJoinerRef.get(); + SqlStatement sqlStatement = createStatement( + sqlStatementRawTextJoiner, singleLineTextBuilder, textLines); + + resetStatementBuffer(rawTextJoinerRef, singleLineTextBuilder, + textLines); + sqlStatementList.add(sqlStatement); + } + } + + StringJoiner sqlStatementRawTextJoiner = rawTextJoinerRef.get(); + // ; is the end of a statement + int indexOfSemicolon = line.indexOf(';'); + if (indexOfSemicolon == -1) { + // raw text + sqlStatementRawTextJoiner.add(line); + // single line text + singleLineTextBuilder.append(line); + // text lines + textLines.add(line); + } else { + String lineBeforeSemicolon = line.substring(0, indexOfSemicolon + 1); + // raw text + sqlStatementRawTextJoiner.add(lineBeforeSemicolon); + // single line text + singleLineTextBuilder.append(lineBeforeSemicolon); + // text lines + textLines.add(lineBeforeSemicolon); + + SqlStatement sqlStatement = createStatement( + sqlStatementRawTextJoiner, singleLineTextBuilder, textLines); + + resetStatementBuffer(rawTextJoinerRef, singleLineTextBuilder, + textLines); + + sqlStatementList.add(sqlStatement); + } + } + + private static SqlStatement createStatement(StringJoiner sqlStatementRawTextJoiner, + StringBuilder singleLineTextBuilder, List textLines) { + return SqlStatement.builder() + .rawText(sqlStatementRawTextJoiner.toString()) + .singleLineText(singleLineTextBuilder.toString()) + .textLines(new ArrayList<>(textLines)) + .build(); + } + + private static void resetStatementBuffer( + AtomicReference rawTextJoinerRef, + StringBuilder singleLineTextBuilder, List textLines) { + // raw text + rawTextJoinerRef.set(new StringJoiner("\n")); + // single line text + singleLineTextBuilder.setLength(0); + // text lines + textLines.clear(); + } } diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlStatement.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlStatement.java new file mode 100644 index 00000000000..d6f40da1915 --- /dev/null +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/SqlStatement.java @@ -0,0 +1,99 @@ +/* + * Copyright 2024 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.build.sql.converter; + +import java.util.Collections; +import java.util.List; +import java.util.StringJoiner; + +public class SqlStatement { + + private final String rawText; + + private final String singleLineText; + + private final List textLines; + + SqlStatement(Builder builder) { + this.rawText = builder.rawText; + this.singleLineText = builder.singleLineText; + this.textLines = builder.textLines; + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + Builder builder = new Builder(); + builder.rawText = this.rawText; + builder.singleLineText = this.singleLineText; + builder.textLines = this.textLines; + return builder; + } + + public String getRawText() { + return this.rawText; + } + + public String getSingleLineText() { + return this.singleLineText; + } + + public List getTextLines() { + return this.textLines; + } + + @Override + public String toString() { + return new StringJoiner(", ", SqlStatement.class.getSimpleName() + "[", "]") + // fields + .add("rawText='" + this.rawText + "'") + .toString(); + } + + public static final class Builder { + + private String rawText; + private String singleLineText; + private List textLines; + + Builder() { + } + + public Builder rawText(String rawText) { + this.rawText = rawText; + return this; + } + + public Builder singleLineText(String singleLineText) { + this.singleLineText = singleLineText; + return this; + } + + public Builder textLines(List textLines) { + this.textLines = textLines == null ? null : + // nonnull + (textLines.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(textLines)); + return this; + } + + public SqlStatement build() { + return new SqlStatement(this); + } + } +} diff --git a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterAutoGeneratedTest.java similarity index 94% rename from apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java rename to apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterAutoGeneratedTest.java index 4d4bfdce8f9..1fc956544aa 100644 --- a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterTest.java +++ b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterAutoGeneratedTest.java @@ -31,20 +31,26 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -class ApolloSqlConverterTest { +class ApolloSqlConverterAutoGeneratedTest { private static final String GENERATE_TIPS = "mvn compile -pl apollo-build-sql-converter -Psql-converter"; + /** + * Check sql files in 'scripts/sql/profiles' are auto generated. + */ @Test - void checkSql() { + void checkAutoGenerated() { String repositoryDir = ApolloSqlConverterUtil.getRepositoryDir(); String srcDir = repositoryDir + "/scripts/sql/src"; - String checkerParentDir = repositoryDir + "/apollo-build-sql-converter/target/scripts"; + String checkerParentDir = repositoryDir + "/apollo-build-sql-converter/target/scripts/sql/checker-auto-generated"; String repositoryParentDir = repositoryDir + "/scripts"; // generate checker sql files - List srcSqlList = ApolloSqlConverter.convert(checkerParentDir); + ApolloSqlConverterUtil.deleteDir(Paths.get(checkerParentDir)); + SqlTemplateGist gists = ApolloSqlConverterUtil.getGists(repositoryDir); + List srcSqlList = ApolloSqlConverter.convert(repositoryDir, srcDir, checkerParentDir, + gists); // compare checker sql files with repository sql files this.checkSqlList(srcSqlList, srcDir, checkerParentDir, repositoryParentDir); diff --git a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java new file mode 100644 index 00000000000..1f0529c2698 --- /dev/null +++ b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java @@ -0,0 +1,145 @@ +/* + * Copyright 2024 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.build.sql.converter; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.core.io.PathResource; +import org.springframework.jdbc.datasource.SimpleDriverDataSource; +import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; + +class ApolloSqlConverterH2Test { + + @Test + void checkH2() { + String repositoryDir = ApolloSqlConverterUtil.getRepositoryDir(); + + String srcDir = repositoryDir + "/scripts/sql/src"; + String checkerParentDir = + repositoryDir + "/apollo-build-sql-converter/target/scripts/sql/checker-h2"; + String testSrcDir = + repositoryDir + "/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test"; + String testCheckerParentDir = + repositoryDir + "/apollo-build-sql-converter/target/scripts/sql/checker-h2-test"; + + // generate checker sql files + ApolloSqlConverterUtil.deleteDir(Paths.get(checkerParentDir)); + SqlTemplateGist gists = ApolloSqlConverterUtil.getGists(repositoryDir); + SqlTemplateGist h2TestGist = gists.toBuilder() + .h2Function("\n" + + "\n" + + "-- H2 Function\n" + + "-- ------------------------------------------------------------\n" + + "CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR \"com.ctrip.framework.apollo.build.sql.converter.TestH2Function.unixTimestamp\";\n") + .build(); + List srcSqlList = ApolloSqlConverter.convert(repositoryDir, srcDir, checkerParentDir, + h2TestGist); + List checkerSqlList = new ArrayList<>(srcSqlList.size()); + for (String srcSql : srcSqlList) { + String checkerSql = ApolloSqlConverterUtil.replacePath(srcSql, srcDir, + checkerParentDir + "/sql/profiles/h2-default"); + checkerSqlList.add(checkerSql); + } + + // generate test checker sql files + ApolloSqlConverterUtil.deleteDir(Paths.get(testCheckerParentDir)); + List testSrcSqlList = ApolloSqlConverter.convert(repositoryDir, testSrcDir, + testCheckerParentDir, h2TestGist); + List testCheckerSqlList = new ArrayList<>(testSrcSqlList.size()); + for (String testSrcSql : testSrcSqlList) { + String testCheckerSql = ApolloSqlConverterUtil.replacePath(testSrcSql, testSrcDir, + testCheckerParentDir + "/sql/profiles/h2-default"); + testCheckerSqlList.add(testCheckerSql); + } + + this.checkSort(testSrcSqlList); + + String h2Path = "test-h2"; + this.checkConfigDatabase(h2Path, checkerSqlList, testCheckerSqlList); + + this.checkPortalDatabase(h2Path, testSrcSqlList, srcSqlList, testCheckerParentDir, + checkerParentDir); + + } + + private void checkSort(List testSrcSqlList) { + int baseIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v040-v050-base.sql"); + Assertions.assertTrue(baseIndex >= 0); + int beforeIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v040-v050-before.sql"); + Assertions.assertTrue(beforeIndex >= 0); + int deltaIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v040-v050.sql"); + Assertions.assertTrue(deltaIndex >= 0); + int afterIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v040-v050-after.sql"); + Assertions.assertTrue(afterIndex >= 0); + + Assertions.assertTrue(baseIndex < beforeIndex); + Assertions.assertTrue(beforeIndex < deltaIndex); + Assertions.assertTrue(deltaIndex < afterIndex); + } + + private int getIndex(List srcSqlList, String fileName) { + for (int i = 0; i < srcSqlList.size(); i++) { + String sqlFile = srcSqlList.get(i); + if (sqlFile.endsWith(fileName)) { + return i; + } + } + return -1; + } + + private void checkConfigDatabase(String h2Path, List checkerSqlList, + List testCheckerSqlList) { + SimpleDriverDataSource configDataSource = new SimpleDriverDataSource(); + configDataSource.setUrl("jdbc:h2:mem:~/" + h2Path + + "/apollo-config-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE"); + configDataSource.setDriverClass(org.h2.Driver.class); + + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); + populator.setContinueOnError(false); + populator.setSeparator(";"); + populator.setSqlScriptEncoding(StandardCharsets.UTF_8.name()); + + for (String sqlFile : testCheckerSqlList) { + if (sqlFile.contains("apolloconfigdb-")) { + populator.addScript(new PathResource(Paths.get(sqlFile))); + } + } + + for (String sqlFile : checkerSqlList) { + if (sqlFile.contains("apolloconfigdb-")) { + populator.addScript(new PathResource(Paths.get(sqlFile))); + } + } + + DatabasePopulatorUtils.execute(populator, configDataSource); + } + + private void checkPortalDatabase(String h2Path, List testSrcSqlList, + List srcSqlList, + String testCheckerParentDir, String checkerParentDir) { + SimpleDriverDataSource portalDataSource = new SimpleDriverDataSource(); + portalDataSource.setUrl("jdbc:h2:mem:~/" + h2Path + + "/apollo-portal-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE"); + portalDataSource.setDriverClass(org.h2.Driver.class); + } + +} \ No newline at end of file diff --git a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/TestH2Function.java b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/TestH2Function.java new file mode 100644 index 00000000000..e88984ad0f7 --- /dev/null +++ b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/TestH2Function.java @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Apollo Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package com.ctrip.framework.apollo.build.sql.converter; + +public class TestH2Function { + + public static long unixTimestamp(java.sql.Timestamp timestamp) { + return timestamp.getTime() / 1000L; + } +} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-after.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-after.sql new file mode 100644 index 00000000000..4dda942796c --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-after.sql @@ -0,0 +1,14 @@ +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.setupDatabase} + + +-- ${gists.autoGeneratedDeclaration} \ No newline at end of file diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-base.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-base.sql new file mode 100644 index 00000000000..9448f7851be --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-base.sql @@ -0,0 +1,414 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.setupDatabase} + +-- Dump of table app +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `App`; + +CREATE TABLE `App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `AppId` (`AppId`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `Name` (`Name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +-- Dump of table appnamespace +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `AppNamespace`; + +CREATE TABLE `AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +-- Dump of table audit +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Audit`; + +CREATE TABLE `Audit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID', + `OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表'; + + + +-- Dump of table cluster +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Cluster`; + +CREATE TABLE `Cluster` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', + `AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'App id', + `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_AppId_Name` (`AppId`,`Name`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群'; + + + +-- Dump of table commit +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Commit`; + +CREATE TABLE `Commit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `ChangeSets` longtext NOT NULL COMMENT '修改变更集', + `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `AppId` (`AppId`(191)), + KEY `ClusterName` (`ClusterName`(191)), + KEY `NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表'; + +-- Dump of table grayreleaserule +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `GrayReleaseRule`; + +CREATE TABLE `GrayReleaseRule` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name', + `Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release', + `BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表'; + + +-- Dump of table instance +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Instance`; + +CREATE TABLE `Instance` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name', + `Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`), + KEY `IX_IP` (`Ip`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例'; + + + +-- Dump of table instanceconfig +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `InstanceConfig`; + +CREATE TABLE `InstanceConfig` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id', + `ConfigAppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config App Id', + `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name', + `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), + KEY `IX_ReleaseKey` (`ReleaseKey`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息'; + + + +-- Dump of table item +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Item`; + +CREATE TABLE `Item` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Value` longtext NOT NULL COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_GroupId` (`NamespaceId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目'; + + + +-- Dump of table namespace +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Namespace`; + +CREATE TABLE `Namespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `AppId_ClusterName_NamespaceName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间'; + + + +-- Dump of table namespacelock +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `NamespaceLock`; + +CREATE TABLE `NamespaceLock` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT 'default' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_NamespaceId` (`NamespaceId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁'; + + + +-- Dump of table privilege +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Privilege`; + +CREATE TABLE `Privilege` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Name', + `PrivilType` varchar(50) NOT NULL DEFAULT 'default' COMMENT 'PrivilType', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'NamespaceId', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`id`), + KEY `Name_PrivilType_NamespaceId` (`Name`(191),`PrivilType`,`NamespaceId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限'; + + + +-- Dump of table release +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Release`; + +CREATE TABLE `Release` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字', + `Comment` varchar(256) DEFAULT NULL COMMENT '发布说明', + `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Configurations` longtext NOT NULL COMMENT '发布配置', + `IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃', + `Status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '发布的状态,0:废弃 1:正常 2:灰度', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `AppId_ClusterName_GroupName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_ReleaseKey` (`ReleaseKey`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布'; + + +-- Dump of table releasehistory +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ReleaseHistory`; + +CREATE TABLE `ReleaseHistory` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id', + `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId', + `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度', + `OperationContext` longtext NOT NULL COMMENT '发布上下文信息', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), + KEY `IX_ReleaseId` (`ReleaseId`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史'; + + +-- Dump of table releasemessage +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ReleaseMessage`; + +CREATE TABLE `ReleaseMessage` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Message` (`Message`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息'; + + + +-- Dump of table serverconfig +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ServerConfig`; + +CREATE TABLE `ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_Key` (`Key`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + +-- Config +-- ------------------------------------------------------------ +INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +VALUES + ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url'), + ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), + ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), + ('appnamespace.private.enable', 'default', 'false', '是否开启private namespace'), + ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'); + +-- ${gists.autoGeneratedDeclaration} + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-before.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-before.sql new file mode 100644 index 00000000000..c804ef63fb9 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-before.sql @@ -0,0 +1,14 @@ +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.setupDatabase} + + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050.sql new file mode 100644 index 00000000000..ed7992de6f9 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050.sql @@ -0,0 +1,30 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v0.4.0 to v0.5.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +DROP TABLE `Privilege`; +ALTER TABLE `Release` DROP `Status`; +ALTER TABLE `Namespace` ADD KEY `IX_NamespaceName` (`NamespaceName`(191)); +ALTER TABLE `Cluster` ADD KEY `IX_ParentClusterId` (`ParentClusterId`); +ALTER TABLE `AppNamespace` ADD KEY `IX_AppId` (`AppId`); +ALTER TABLE `App` DROP INDEX `Name`; +ALTER TABLE `App` ADD KEY `Name` (`Name`); + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050-base.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050-base.sql new file mode 100644 index 00000000000..bc3f0ec2021 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050-base.sql @@ -0,0 +1,308 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.setupDatabase} + +-- Dump of table app +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `App`; + +CREATE TABLE `App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `AppId` (`AppId`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `Name` (`Name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +-- Dump of table appnamespace +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `AppNamespace`; + +CREATE TABLE `AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(32) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +-- Dump of table consumer +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Consumer`; + +CREATE TABLE `Consumer` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `AppId` (`AppId`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者'; + + + +-- Dump of table consumeraudit +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ConsumerAudit`; + +CREATE TABLE `ConsumerAudit` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri', + `Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_ConsumerId` (`ConsumerId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表'; + + + +-- Dump of table consumerrole +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ConsumerRole`; + +CREATE TABLE `ConsumerRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) DEFAULT '' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`), + KEY `IX_ConsumerId_RoleId` (`ConsumerId`,`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表'; + + + +-- Dump of table consumertoken +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ConsumerToken`; + +CREATE TABLE `ConsumerToken` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId', + `Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token', + `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_Token` (`Token`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表'; + +-- Dump of table favorite +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Favorite`; + +CREATE TABLE `Favorite` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户', + `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `AppId` (`AppId`(191)), + KEY `IX_UserId` (`UserId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表'; + +-- Dump of table permission +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Permission`; + +CREATE TABLE `Permission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型', + `TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TargetId_PermissionType` (`TargetId`(191),`PermissionType`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表'; + + + +-- Dump of table role +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Role`; + +CREATE TABLE `Role` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_RoleName` (`RoleName`(191)), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; + + + +-- Dump of table rolepermission +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `RolePermission`; + +CREATE TABLE `RolePermission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) DEFAULT '' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`), + KEY `IX_PermissionId` (`PermissionId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表'; + + + +-- Dump of table serverconfig +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ServerConfig`; + +CREATE TABLE `ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_Key` (`Key`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + + + +-- Dump of table userrole +-- ------------------------------------------------------------ + +DROP TABLE IF EXISTS `UserRole`; + +CREATE TABLE `UserRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) DEFAULT '' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`), + KEY `IX_UserId_RoleId` (`UserId`,`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表'; + +-- Config +-- ------------------------------------------------------------ +INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`) +VALUES + ('apollo.portal.envs', 'dev', '可支持的环境列表'), + ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), + ('superAdmin', 'apollo', 'Portal超级管理员'), + ('api.readTimeout', '10000', 'http接口read timeout'), + ('consumer.token.salt', 'someSalt', 'consumer token salt'); + +-- ${gists.autoGeneratedDeclaration} + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050.sql new file mode 100644 index 00000000000..b7c4d91e900 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050.sql @@ -0,0 +1,24 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +# delta schema to upgrade apollo portal db from v0.4.0 to v0.5.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +ALTER TABLE `AppNamespace` ADD KEY `IX_AppId` (`AppId`); +ALTER TABLE `App` DROP INDEX `Name`; +ALTER TABLE `App` ADD KEY `Name` (`Name`); \ No newline at end of file diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloconfigdb-v060-v062.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloconfigdb-v060-v062.sql new file mode 100644 index 00000000000..afb82ad42e4 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloconfigdb-v060-v062.sql @@ -0,0 +1,23 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v0.6.0 to v0.6.2 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +ALTER TABLE `App` DROP INDEX `Name`; +CREATE INDEX `IX_NAME` ON App (`Name`(191)); diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloportaldb-v060-v062.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloportaldb-v060-v062.sql new file mode 100644 index 00000000000..048fd52acaf --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloportaldb-v060-v062.sql @@ -0,0 +1,23 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v0.6.0 to v0.6.2 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +ALTER TABLE `App` DROP INDEX `Name`; +CREATE INDEX `IX_NAME` ON App (`Name`(191)); diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v080-v090/apolloportaldb-v080-v090.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v080-v090/apolloportaldb-v080-v090.sql new file mode 100644 index 00000000000..6bf091ce7ee --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v080-v090/apolloportaldb-v080-v090.sql @@ -0,0 +1,42 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v0.8.0 to v0.9.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +CREATE TABLE `Users` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户名', + `Password` varchar(64) NOT NULL DEFAULT 'default' COMMENT '密码', + `Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址', + `Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效', + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + +CREATE TABLE `Authorities` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(50) NOT NULL, + `Authority` varchar(50) NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +INSERT INTO `Users` (`Username`, `Password`, `Email`, `Enabled`) +VALUES + ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo@acme.com', 1); + +INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v151-v160/apolloconfigdb-v151-v160.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v151-v160/apolloconfigdb-v151-v160.sql new file mode 100644 index 00000000000..1bc7803d692 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v151-v160/apolloconfigdb-v151-v160.sql @@ -0,0 +1,35 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v1.5.1 to v1.6.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +CREATE TABLE `AccessKey` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret', + `IsEnabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: enabled, 0: disabled', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DataChange_CreatedBy` varchar(32) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(32) NOT NULL DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `AppId` (`AppId`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; \ No newline at end of file diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloconfigdb-v170-v180.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloconfigdb-v170-v180.sql new file mode 100644 index 00000000000..584530298ca --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloconfigdb-v170-v180.sql @@ -0,0 +1,27 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v1.7.0 to v1.8.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +alter table `AppNamespace` change AppId AppId varchar(64) NOT NULL DEFAULT 'default' COMMENT 'app id'; +alter table `Cluster` change AppId AppId varchar(64) NOT NULL DEFAULT 'default' COMMENT 'app id'; +alter table `GrayReleaseRule` change AppId AppId varchar(64) NOT NULL DEFAULT 'default' COMMENT 'app id'; +alter table `Instance` change AppId AppId varchar(64) NOT NULL DEFAULT 'default' COMMENT 'app id'; +alter table `InstanceConfig` change ConfigAppId ConfigAppId varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id'; +alter table `ReleaseHistory` change AppId AppId varchar(64) NOT NULL DEFAULT 'default' COMMENT 'app id'; diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloportaldb-v170-v180.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloportaldb-v170-v180.sql new file mode 100644 index 00000000000..c3bd8d1a5dc --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloportaldb-v170-v180.sql @@ -0,0 +1,22 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v1.7.0 to v1.8.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +alter table `AppNamespace` change AppId AppId varchar(64) NOT NULL DEFAULT 'default' COMMENT 'app id'; diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloconfigdb-v180-v190.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloconfigdb-v180-v190.sql new file mode 100644 index 00000000000..9a5272ce951 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloconfigdb-v180-v190.sql @@ -0,0 +1,72 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v1.8.0 to v1.9.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +ALTER TABLE `App` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `AppNamespace` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `Audit` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `Cluster` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `Commit` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `GrayReleaseRule` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `Item` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `Namespace` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `NamespaceLock` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `Release` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `ReleaseHistory` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `ServerConfig` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `AccessKey` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloportaldb-v180-v190.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloportaldb-v180-v190.sql new file mode 100644 index 00000000000..bc6be1f0bf9 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloportaldb-v180-v190.sql @@ -0,0 +1,100 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v1.8.0 to v1.9.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +ALTER TABLE `App` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `AppNamespace` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `Consumer` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `ConsumerRole` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `ConsumerToken` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `Favorite` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `Permission` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `Role` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `RolePermission` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `ServerConfig` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `UserRole` + MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +ALTER TABLE `Users` + MODIFY COLUMN `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户', + ADD COLUMN `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称' AFTER `Password`; +UPDATE `Users` SET `UserDisplayName`=`Username` WHERE `UserDisplayName` = 'default'; + +ALTER TABLE `Users` + MODIFY COLUMN `Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码'; +UPDATE `Users` SET `Password` = REPLACE(`Password`, '{nonsensical}', '{placeholder}') WHERE `Password` LIKE '{nonsensical}%'; +-- note: add the {bcrypt} prefix for `Users`.`Password` is not mandatory, and it may break the old version of apollo-portal while upgrading. +-- 注意: 向 `Users`.`Password` 添加 {bcrypt} 是非必须操作, 并且这个操作会导致升级 apollo-portal 集群的过程中旧版的 apollo-portal 无法使用. +-- UPDATE `Users` SET `Password` = CONCAT('{bcrypt}', `Password`) WHERE `Password` NOT LIKE '{%}%'; + +-- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) +CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, + SESSION_ID CHAR(36) NOT NULL, + CREATION_TIME BIGINT NOT NULL, + LAST_ACCESS_TIME BIGINT NOT NULL, + MAX_INACTIVE_INTERVAL INT NOT NULL, + EXPIRY_TIME BIGINT NOT NULL, + PRINCIPAL_NAME VARCHAR(100), + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME); +CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME); + +CREATE TABLE SPRING_SESSION_ATTRIBUTES ( + SESSION_PRIMARY_ID CHAR(36) NOT NULL, + ATTRIBUTE_NAME VARCHAR(200) NOT NULL, + ATTRIBUTE_BYTES BLOB NOT NULL, + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200-after.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200-after.sql new file mode 100644 index 00000000000..2ef8fae247a --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200-after.sql @@ -0,0 +1,86 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v1.9.0 to v2.0.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +-- Begin:Create indexes to solve the problem of updating large tables +ALTER TABLE `Commit` ADD INDEX `idx_IsDeleted_DeletedAt` (`IsDeleted`, `DeletedAt`); +ALTER TABLE `Release` ADD INDEX `idx_IsDeleted_DeletedAt` (`IsDeleted`, `DeletedAt`); + +-- the follow DML won't change the `DataChange_LastTime` field +UPDATE `AccessKey` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `App` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `AppNamespace` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `Audit` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `Cluster` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `Commit` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `GrayReleaseRule` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `Item` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `Namespace` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `NamespaceLock` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `Release` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `ReleaseHistory` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `ServerConfig` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; + +-- add UNIQUE CONSTRAINT INDEX for each table +ALTER TABLE `AccessKey` + ADD UNIQUE INDEX `UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`), + DROP INDEX `AppId`; + +ALTER TABLE `App` + ADD UNIQUE INDEX `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + DROP INDEX `AppId`; + +ALTER TABLE `AppNamespace` + ADD UNIQUE INDEX `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + DROP INDEX `IX_AppId`; + +-- Ignore TABLE `Audit` + +ALTER TABLE `Cluster` + ADD UNIQUE INDEX `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + DROP INDEX `IX_AppId_Name`; + +-- Ignore TABLE `Commit` + +-- Ignore TABLE `GrayReleaseRule`, add unique index in future + +-- Ignore TABLE `Item`, add unique index in future + +ALTER TABLE `Namespace` + ADD UNIQUE INDEX `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191),`DeletedAt`), + DROP INDEX `AppId_ClusterName_NamespaceName`; + +ALTER TABLE `NamespaceLock` + ADD UNIQUE INDEX `UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`), + DROP INDEX `IX_NamespaceId`; + +ALTER TABLE `Release` + ADD UNIQUE INDEX `UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`), + DROP INDEX `IX_ReleaseKey`; + +-- Ignore TABLE `ReleaseHistory` + +ALTER TABLE `ServerConfig` + ADD UNIQUE INDEX `UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`), + DROP INDEX `IX_Key`; + +-- End:Delete temporarily created indexes +ALTER TABLE `Commit` DROP INDEX `idx_IsDeleted_DeletedAt`; +ALTER TABLE `Release` DROP INDEX `idx_IsDeleted_DeletedAt`; diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200.sql new file mode 100644 index 00000000000..f9a21a7b99f --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200.sql @@ -0,0 +1,60 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v1.9.0 to v2.0.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +ALTER TABLE `App` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `AppNamespace` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `Audit` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `Cluster` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `Commit` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `GrayReleaseRule` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `Item` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`, + ADD INDEX IX_key (`Key`); + +ALTER TABLE `Namespace` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `NamespaceLock` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `Release` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `ReleaseHistory` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `ServerConfig` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `AccessKey` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200-after.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200-after.sql new file mode 100644 index 00000000000..c31ef4ed444 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200-after.sql @@ -0,0 +1,81 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v1.9.0 to v2.0.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +-- the follow DML won't change the `DataChange_LastTime` field +UPDATE `App` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `AppNamespace` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `Consumer` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `ConsumerRole` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `ConsumerToken` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `Favorite` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `Permission` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `Role` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `RolePermission` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `ServerConfig` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; +UPDATE `UserRole` SET `DeletedAt` = -Id, `DataChange_LastTime` = `DataChange_LastTime` WHERE `IsDeleted` = 1 and `DeletedAt` = 0; + +-- add UNIQUE CONSTRAINT INDEX for each table +ALTER TABLE `App` + ADD UNIQUE INDEX `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + DROP INDEX `AppId`; + +ALTER TABLE `AppNamespace` + ADD UNIQUE INDEX `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + DROP INDEX `IX_AppId`; + +ALTER TABLE `Consumer` + ADD UNIQUE INDEX `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + DROP INDEX `AppId`; + +ALTER TABLE `ConsumerRole` + ADD UNIQUE INDEX `UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`), + DROP INDEX `IX_ConsumerId_RoleId`; + +ALTER TABLE `ConsumerToken` + ADD UNIQUE INDEX `UK_Token_DeletedAt` (`Token`,`DeletedAt`), + DROP INDEX `IX_Token`; + +ALTER TABLE `Favorite` + ADD UNIQUE INDEX `UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`), + DROP INDEX `IX_UserId`; + +ALTER TABLE `Permission` + ADD UNIQUE INDEX `UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`), + DROP INDEX `IX_TargetId_PermissionType`; + +ALTER TABLE `Role` + ADD UNIQUE INDEX `UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`), + DROP INDEX `IX_RoleName`; + +ALTER TABLE `RolePermission` + ADD UNIQUE INDEX `UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`), + DROP INDEX `IX_RoleId`; + +ALTER TABLE `ServerConfig` + ADD UNIQUE INDEX `UK_Key_DeletedAt` (`Key`,`DeletedAt`), + DROP INDEX `IX_Key`; + +ALTER TABLE `UserRole` + ADD UNIQUE INDEX `UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`), + DROP INDEX `IX_UserId_RoleId`; + +ALTER TABLE `Users` + ADD UNIQUE INDEX `UK_Username` (`Username`); diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200.sql new file mode 100644 index 00000000000..c6e6ab23d40 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200.sql @@ -0,0 +1,53 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v1.9.0 to v2.0.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +ALTER TABLE `App` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `AppNamespace` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `Consumer` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `ConsumerRole` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `ConsumerToken` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `Favorite` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `Permission` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `Role` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `RolePermission` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `ServerConfig` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +ALTER TABLE `UserRole` + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; \ No newline at end of file diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v200-v210/apolloconfigdb-v200-v210.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v200-v210/apolloconfigdb-v200-v210.sql new file mode 100644 index 00000000000..4140930fc1d --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v200-v210/apolloconfigdb-v200-v210.sql @@ -0,0 +1,39 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v2.0.0 to v2.1.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +-- add INDEX for ReleaseHistory table +CREATE INDEX IX_PreviousReleaseId ON ReleaseHistory(PreviousReleaseId); + +ALTER TABLE `Item` + ADD COLUMN `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '配置项类型,0: String,1: Number,2: Boolean,3: JSON' AFTER `Key`; + +CREATE TABLE `ServiceRegistry` ( + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', + `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), + INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; \ No newline at end of file diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloconfigdb-v210-v220.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloconfigdb-v210-v220.sql new file mode 100644 index 00000000000..c71be2bf0e7 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloconfigdb-v210-v220.sql @@ -0,0 +1,95 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v2.1.0 to v2.2.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +ALTER TABLE `App` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `Commit` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `Namespace` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `Release` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `AccessKey` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `Commit` + DROP INDEX `AppId`, + ADD INDEX `AppId` (`AppId`); + +ALTER TABLE `Namespace` + DROP INDEX `UK_AppId_ClusterName_NamespaceName_DeletedAt`, + ADD UNIQUE INDEX `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`); + +ALTER TABLE `Release` + DROP INDEX `AppId_ClusterName_GroupName`, + ADD INDEX `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`); + +DROP TABLE IF EXISTS `AuditLog`; + +CREATE TABLE `AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + + +DROP TABLE IF EXISTS `AuditLogDataInfluence`; + +CREATE TABLE `AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloportaldb-v210-v220.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloportaldb-v210-v220.sql new file mode 100644 index 00000000000..ff613cc5849 --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloportaldb-v210-v220.sql @@ -0,0 +1,81 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v2.1.0 to v2.2.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +ALTER TABLE `App` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `Consumer` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `Favorite` + MODIFY COLUMN `AppId` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT 'AppID'; + +ALTER TABLE `Favorite` + DROP INDEX `AppId`, + ADD INDEX `AppId` (`AppId`); + +DROP TABLE IF EXISTS `AuditLog`; + +CREATE TABLE `AuditLog` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_TraceId` (`TraceId`), + KEY `IX_OpName` (`OpName`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_Operator` (`Operator`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志表'; + + +DROP TABLE IF EXISTS `AuditLogDataInfluence`; + +CREATE TABLE `AuditLogDataInfluence` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_SpanId` (`SpanId`), + KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `IX_EntityId` (`InfluenceEntityId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; diff --git a/scripts/sql/profiles/h2-default/apolloconfigdb.sql b/scripts/sql/profiles/h2-default/apolloconfigdb.sql index 01971cc488f..7cf19950ab4 100644 --- a/scripts/sql/profiles/h2-default/apolloconfigdb.sql +++ b/scripts/sql/profiles/h2-default/apolloconfigdb.sql @@ -41,7 +41,6 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common -- ------------------------------------------------------------ - CREATE TABLE `App` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , @@ -57,9 +56,9 @@ CREATE TABLE `App` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`AppId`,`DeletedAt`), - KEY (`DataChange_LastTime`), - KEY (`Name`) + UNIQUE KEY `App_UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `App_DataChange_LastTime` (`DataChange_LastTime`), + KEY `App_IX_Name` (`Name`) ) ; @@ -68,7 +67,6 @@ CREATE TABLE `App` ( -- ------------------------------------------------------------ - CREATE TABLE `AppNamespace` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Name` varchar(32) NOT NULL DEFAULT '' , @@ -83,9 +81,9 @@ CREATE TABLE `AppNamespace` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`AppId`,`Name`,`DeletedAt`), - KEY (`Name`,`AppId`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `AppNamespace_UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `AppNamespace_Name_AppId` (`Name`,`AppId`), + KEY `AppNamespace_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -94,7 +92,6 @@ CREATE TABLE `AppNamespace` ( -- ------------------------------------------------------------ - CREATE TABLE `Audit` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `EntityName` varchar(50) NOT NULL DEFAULT 'default' , @@ -108,7 +105,7 @@ CREATE TABLE `Audit` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY (`DataChange_LastTime`) + KEY `Audit_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -117,7 +114,6 @@ CREATE TABLE `Audit` ( -- ------------------------------------------------------------ - CREATE TABLE `Cluster` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Name` varchar(32) NOT NULL DEFAULT '' , @@ -131,9 +127,9 @@ CREATE TABLE `Cluster` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`AppId`,`Name`,`DeletedAt`), - KEY (`ParentClusterId`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `Cluster_UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Cluster_IX_ParentClusterId` (`ParentClusterId`), + KEY `Cluster_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -142,7 +138,6 @@ CREATE TABLE `Cluster` ( -- ------------------------------------------------------------ - CREATE TABLE `Commit` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `ChangeSets` longtext NOT NULL , @@ -157,17 +152,16 @@ CREATE TABLE `Commit` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY (`DataChange_LastTime`), - KEY (`AppId`), - KEY (`ClusterName`), - KEY (`NamespaceName`) + KEY `Commit_DataChange_LastTime` (`DataChange_LastTime`), + KEY `Commit_AppId` (`AppId`), + KEY `Commit_ClusterName` (`ClusterName`), + KEY `Commit_NamespaceName` (`NamespaceName`) ) ; -- Dump of table grayreleaserule -- ------------------------------------------------------------ - CREATE TABLE `GrayReleaseRule` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , @@ -184,8 +178,8 @@ CREATE TABLE `GrayReleaseRule` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY (`DataChange_LastTime`), - KEY (`AppId`,`ClusterName`,`NamespaceName`) + KEY `GrayReleaseRule_DataChange_LastTime` (`DataChange_LastTime`), + KEY `GrayReleaseRule_IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`) ) ; @@ -193,7 +187,6 @@ CREATE TABLE `GrayReleaseRule` ( -- ------------------------------------------------------------ - CREATE TABLE `Instance` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , @@ -203,9 +196,9 @@ CREATE TABLE `Instance` ( `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`AppId`,`ClusterName`,`Ip`,`DataCenter`), - KEY (`Ip`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `Instance_IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`), + KEY `Instance_IX_IP` (`Ip`), + KEY `Instance_IX_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -214,7 +207,6 @@ CREATE TABLE `Instance` ( -- ------------------------------------------------------------ - CREATE TABLE `InstanceConfig` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `InstanceId` int(11) unsigned DEFAULT NULL , @@ -226,10 +218,10 @@ CREATE TABLE `InstanceConfig` ( `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), - KEY (`ReleaseKey`), - KEY (`DataChange_LastTime`), - KEY (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) + UNIQUE KEY `InstanceConfig_IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), + KEY `InstanceConfig_IX_ReleaseKey` (`ReleaseKey`), + KEY `InstanceConfig_IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `InstanceConfig_IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) ) ; @@ -238,7 +230,6 @@ CREATE TABLE `InstanceConfig` ( -- ------------------------------------------------------------ - CREATE TABLE `Item` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' , @@ -254,8 +245,8 @@ CREATE TABLE `Item` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY (`NamespaceId`), - KEY (`DataChange_LastTime`) + KEY `Item_IX_GroupId` (`NamespaceId`), + KEY `Item_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -264,7 +255,6 @@ CREATE TABLE `Item` ( -- ------------------------------------------------------------ - CREATE TABLE `Namespace` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , @@ -277,9 +267,9 @@ CREATE TABLE `Namespace` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`AppId`,`ClusterName`,`NamespaceName`,`DeletedAt`), - KEY (`DataChange_LastTime`), - KEY (`NamespaceName`) + UNIQUE KEY `Namespace_UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`,`NamespaceName`,`DeletedAt`), + KEY `Namespace_DataChange_LastTime` (`DataChange_LastTime`), + KEY `Namespace_IX_NamespaceName` (`NamespaceName`) ) ; @@ -288,7 +278,6 @@ CREATE TABLE `Namespace` ( -- ------------------------------------------------------------ - CREATE TABLE `NamespaceLock` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' , @@ -299,8 +288,8 @@ CREATE TABLE `NamespaceLock` ( `IsDeleted` boolean DEFAULT FALSE , `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , PRIMARY KEY (`Id`), - UNIQUE KEY (`NamespaceId`,`DeletedAt`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `NamespaceLock_UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`), + KEY `NamespaceLock_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -309,7 +298,6 @@ CREATE TABLE `NamespaceLock` ( -- ------------------------------------------------------------ - CREATE TABLE `Release` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `ReleaseKey` varchar(64) NOT NULL DEFAULT '' , @@ -327,9 +315,9 @@ CREATE TABLE `Release` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`ReleaseKey`,`DeletedAt`), - KEY (`AppId`,`ClusterName`,`NamespaceName`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `Release_UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`), + KEY `Release_AppId_ClusterName_GroupName` (`AppId`,`ClusterName`,`NamespaceName`), + KEY `Release_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -337,7 +325,6 @@ CREATE TABLE `Release` ( -- ------------------------------------------------------------ - CREATE TABLE `ReleaseHistory` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , @@ -355,10 +342,10 @@ CREATE TABLE `ReleaseHistory` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), - KEY (`ReleaseId`), - KEY (`DataChange_LastTime`), - KEY (`PreviousReleaseId`) + KEY `ReleaseHistory_IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), + KEY `ReleaseHistory_IX_ReleaseId` (`ReleaseId`), + KEY `ReleaseHistory_IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `ReleaseHistory_IX_PreviousReleaseId` (`PreviousReleaseId`) ) ; @@ -366,14 +353,13 @@ CREATE TABLE `ReleaseHistory` ( -- ------------------------------------------------------------ - CREATE TABLE `ReleaseMessage` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `Message` varchar(1024) NOT NULL DEFAULT '' , `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY (`DataChange_LastTime`), - KEY (`Message`) + KEY `ReleaseMessage_DataChange_LastTime` (`DataChange_LastTime`), + KEY `ReleaseMessage_IX_Message` (`Message`) ) ; @@ -382,7 +368,6 @@ CREATE TABLE `ReleaseMessage` ( -- ------------------------------------------------------------ - CREATE TABLE `ServerConfig` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Key` varchar(64) NOT NULL DEFAULT 'default' , @@ -396,15 +381,14 @@ CREATE TABLE `ServerConfig` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`Key`,`Cluster`,`DeletedAt`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `ServerConfig_UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`), + KEY `ServerConfig_DataChange_LastTime` (`DataChange_LastTime`) ) ; -- Dump of table accesskey -- ------------------------------------------------------------ - CREATE TABLE `AccessKey` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , @@ -417,8 +401,8 @@ CREATE TABLE `AccessKey` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`AppId`,`Secret`,`DeletedAt`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `AccessKey_UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`), + KEY `AccessKey_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -426,7 +410,6 @@ CREATE TABLE `AccessKey` ( -- ------------------------------------------------------------ - CREATE TABLE `ServiceRegistry` ( `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT , `ServiceName` VARCHAR(64) NOT NULL , @@ -444,7 +427,6 @@ CREATE TABLE `ServiceRegistry` ( -- ------------------------------------------------------------ - CREATE TABLE `AuditLog` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `TraceId` varchar(32) NOT NULL DEFAULT '' , @@ -462,17 +444,16 @@ CREATE TABLE `AuditLog` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY (`TraceId`), - KEY (`OpName`), - KEY (`DataChange_CreatedTime`), - KEY (`Operator`) + KEY `AuditLog_IX_TraceId` (`TraceId`), + KEY `AuditLog_IX_OpName` (`OpName`), + KEY `AuditLog_IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `AuditLog_IX_Operator` (`Operator`) ) ; -- Dump of table AuditLogDataInfluence -- ------------------------------------------------------------ - CREATE TABLE `AuditLogDataInfluence` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `SpanId` char(32) NOT NULL DEFAULT '' , @@ -488,9 +469,9 @@ CREATE TABLE `AuditLogDataInfluence` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY (`SpanId`), - KEY (`DataChange_CreatedTime`), - KEY (`InfluenceEntityId`) + KEY `AuditLogDataInfluence_IX_SpanId` (`SpanId`), + KEY `AuditLogDataInfluence_IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `AuditLogDataInfluence_IX_EntityId` (`InfluenceEntityId`) ) ; -- Config diff --git a/scripts/sql/profiles/h2-default/apolloportaldb.sql b/scripts/sql/profiles/h2-default/apolloportaldb.sql index 6a409beb963..fc94a65cbf7 100644 --- a/scripts/sql/profiles/h2-default/apolloportaldb.sql +++ b/scripts/sql/profiles/h2-default/apolloportaldb.sql @@ -41,7 +41,6 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common -- ------------------------------------------------------------ - CREATE TABLE `App` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , @@ -57,9 +56,9 @@ CREATE TABLE `App` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`AppId`,`DeletedAt`), - KEY (`DataChange_LastTime`), - KEY (`Name`) + UNIQUE KEY `App_UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `App_DataChange_LastTime` (`DataChange_LastTime`), + KEY `App_IX_Name` (`Name`) ) ; @@ -68,7 +67,6 @@ CREATE TABLE `App` ( -- ------------------------------------------------------------ - CREATE TABLE `AppNamespace` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Name` varchar(32) NOT NULL DEFAULT '' , @@ -83,9 +81,9 @@ CREATE TABLE `AppNamespace` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`AppId`,`Name`,`DeletedAt`), - KEY (`Name`,`AppId`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `AppNamespace_UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `AppNamespace_Name_AppId` (`Name`,`AppId`), + KEY `AppNamespace_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -94,7 +92,6 @@ CREATE TABLE `AppNamespace` ( -- ------------------------------------------------------------ - CREATE TABLE `Consumer` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `AppId` varchar(64) NOT NULL DEFAULT 'default' , @@ -110,8 +107,8 @@ CREATE TABLE `Consumer` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`AppId`,`DeletedAt`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `Consumer_UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `Consumer_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -120,7 +117,6 @@ CREATE TABLE `Consumer` ( -- ------------------------------------------------------------ - CREATE TABLE `ConsumerAudit` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `ConsumerId` int(11) unsigned DEFAULT NULL , @@ -129,8 +125,8 @@ CREATE TABLE `ConsumerAudit` ( `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY (`DataChange_LastTime`), - KEY (`ConsumerId`) + KEY `ConsumerAudit_IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `ConsumerAudit_IX_ConsumerId` (`ConsumerId`) ) ; @@ -139,7 +135,6 @@ CREATE TABLE `ConsumerAudit` ( -- ------------------------------------------------------------ - CREATE TABLE `ConsumerRole` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `ConsumerId` int(11) unsigned DEFAULT NULL , @@ -151,9 +146,9 @@ CREATE TABLE `ConsumerRole` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`ConsumerId`,`RoleId`,`DeletedAt`), - KEY (`DataChange_LastTime`), - KEY (`RoleId`) + UNIQUE KEY `ConsumerRole_UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`), + KEY `ConsumerRole_IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `ConsumerRole_IX_RoleId` (`RoleId`) ) ; @@ -162,7 +157,6 @@ CREATE TABLE `ConsumerRole` ( -- ------------------------------------------------------------ - CREATE TABLE `ConsumerToken` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `ConsumerId` int(11) unsigned DEFAULT NULL , @@ -175,15 +169,14 @@ CREATE TABLE `ConsumerToken` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`Token`,`DeletedAt`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `ConsumerToken_UK_Token_DeletedAt` (`Token`,`DeletedAt`), + KEY `ConsumerToken_DataChange_LastTime` (`DataChange_LastTime`) ) ; -- Dump of table favorite -- ------------------------------------------------------------ - CREATE TABLE `Favorite` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `UserId` varchar(32) NOT NULL DEFAULT 'default' , @@ -196,16 +189,15 @@ CREATE TABLE `Favorite` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`UserId`,`AppId`,`DeletedAt`), - KEY (`AppId`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `Favorite_UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`), + KEY `Favorite_AppId` (`AppId`), + KEY `Favorite_DataChange_LastTime` (`DataChange_LastTime`) ) AUTO_INCREMENT=23 ; -- Dump of table permission -- ------------------------------------------------------------ - CREATE TABLE `Permission` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `PermissionType` varchar(32) NOT NULL DEFAULT '' , @@ -217,8 +209,8 @@ CREATE TABLE `Permission` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`TargetId`,`PermissionType`,`DeletedAt`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `Permission_UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`), + KEY `Permission_IX_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -227,7 +219,6 @@ CREATE TABLE `Permission` ( -- ------------------------------------------------------------ - CREATE TABLE `Role` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `RoleName` varchar(256) NOT NULL DEFAULT '' , @@ -238,8 +229,8 @@ CREATE TABLE `Role` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`RoleName`,`DeletedAt`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `Role_UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`), + KEY `Role_IX_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -248,7 +239,6 @@ CREATE TABLE `Role` ( -- ------------------------------------------------------------ - CREATE TABLE `RolePermission` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `RoleId` int(10) unsigned DEFAULT NULL , @@ -260,9 +250,9 @@ CREATE TABLE `RolePermission` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`RoleId`,`PermissionId`,`DeletedAt`), - KEY (`DataChange_LastTime`), - KEY (`PermissionId`) + UNIQUE KEY `RolePermission_UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`), + KEY `RolePermission_IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `RolePermission_IX_PermissionId` (`PermissionId`) ) ; @@ -271,7 +261,6 @@ CREATE TABLE `RolePermission` ( -- ------------------------------------------------------------ - CREATE TABLE `ServerConfig` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Key` varchar(64) NOT NULL DEFAULT 'default' , @@ -284,8 +273,8 @@ CREATE TABLE `ServerConfig` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`Key`,`DeletedAt`), - KEY (`DataChange_LastTime`) + UNIQUE KEY `ServerConfig_UK_Key_DeletedAt` (`Key`,`DeletedAt`), + KEY `ServerConfig_DataChange_LastTime` (`DataChange_LastTime`) ) ; @@ -294,7 +283,6 @@ CREATE TABLE `ServerConfig` ( -- ------------------------------------------------------------ - CREATE TABLE `UserRole` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `UserId` varchar(128) DEFAULT '' , @@ -306,16 +294,15 @@ CREATE TABLE `UserRole` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - UNIQUE KEY (`UserId`,`RoleId`,`DeletedAt`), - KEY (`DataChange_LastTime`), - KEY (`RoleId`) + UNIQUE KEY `UserRole_UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`), + KEY `UserRole_IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `UserRole_IX_RoleId` (`RoleId`) ) ; -- Dump of table Users -- ------------------------------------------------------------ - CREATE TABLE `Users` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `Username` varchar(64) NOT NULL DEFAULT 'default' , @@ -324,7 +311,7 @@ CREATE TABLE `Users` ( `Email` varchar(64) NOT NULL DEFAULT 'default' , `Enabled` tinyint(4) DEFAULT NULL , PRIMARY KEY (`Id`), - UNIQUE KEY (`Username`) + UNIQUE KEY `Users_UK_Username` (`Username`) ) ; @@ -332,7 +319,6 @@ CREATE TABLE `Users` ( -- ------------------------------------------------------------ - CREATE TABLE `Authorities` ( `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , `Username` varchar(64) NOT NULL, @@ -345,7 +331,6 @@ CREATE TABLE `Authorities` ( -- ------------------------------------------------------------ - CREATE TABLE `SPRING_SESSION` ( `PRIMARY_ID` char(36) NOT NULL, `SESSION_ID` char(36) NOT NULL, @@ -355,16 +340,15 @@ CREATE TABLE `SPRING_SESSION` ( `EXPIRY_TIME` bigint NOT NULL, `PRINCIPAL_NAME` varchar(100) DEFAULT NULL, PRIMARY KEY (`PRIMARY_ID`), - UNIQUE KEY (`SESSION_ID`), - KEY (`EXPIRY_TIME`), - KEY (`PRINCIPAL_NAME`) + UNIQUE KEY `SPRING_SESSION_SPRING_SESSION_IX1` (`SESSION_ID`), + KEY `SPRING_SESSION_SPRING_SESSION_IX2` (`EXPIRY_TIME`), + KEY `SPRING_SESSION_SPRING_SESSION_IX3` (`PRINCIPAL_NAME`) ) ; -- Dump of table SPRING_SESSION_ATTRIBUTES -- ------------------------------------------------------------ - CREATE TABLE `SPRING_SESSION_ATTRIBUTES` ( `SESSION_PRIMARY_ID` char(36) NOT NULL, `ATTRIBUTE_NAME` varchar(200) NOT NULL, @@ -377,7 +361,6 @@ CREATE TABLE `SPRING_SESSION_ATTRIBUTES` ( -- ------------------------------------------------------------ - CREATE TABLE `AuditLog` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `TraceId` varchar(32) NOT NULL DEFAULT '' , @@ -395,17 +378,16 @@ CREATE TABLE `AuditLog` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY (`TraceId`), - KEY (`OpName`), - KEY (`DataChange_CreatedTime`), - KEY (`Operator`) + KEY `AuditLog_IX_TraceId` (`TraceId`), + KEY `AuditLog_IX_OpName` (`OpName`), + KEY `AuditLog_IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `AuditLog_IX_Operator` (`Operator`) ) ; -- Dump of table AuditLogDataInfluence -- ------------------------------------------------------------ - CREATE TABLE `AuditLogDataInfluence` ( `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , `SpanId` char(32) NOT NULL DEFAULT '' , @@ -421,9 +403,9 @@ CREATE TABLE `AuditLogDataInfluence` ( `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , PRIMARY KEY (`Id`), - KEY (`SpanId`), - KEY (`DataChange_CreatedTime`), - KEY (`InfluenceEntityId`) + KEY `AuditLogDataInfluence_IX_SpanId` (`SpanId`), + KEY `AuditLogDataInfluence_IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), + KEY `AuditLogDataInfluence_IX_EntityId` (`InfluenceEntityId`) ) ; -- Config From 1313fc3ec1dc58bdaa7ae6052523a9ed439a3407 Mon Sep 17 00:00:00 2001 From: vdisk Date: Thu, 25 Jan 2024 00:07:17 +0800 Subject: [PATCH 49/59] add sql test temp 2 --- .../sql/converter/ApolloH2ConverterUtil.java | 326 +++++++++++++----- .../ApolloMysqlDefaultConverterUtil.java | 10 +- 2 files changed, 242 insertions(+), 94 deletions(-) diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java index ff4ae0ec1ca..7885195e25c 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java @@ -24,20 +24,53 @@ import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.List; +import java.util.StringJoiner; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ApolloH2ConverterUtil { - private static final Pattern CREATE_TABLE_PATTERN = Pattern.compile("CREATE\\s+TABLE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?"); - private static final Pattern ALTER_TABLE_PATTERN = Pattern.compile("ALTER\\s+TABLE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?"); - private static final Pattern TABLE_COMMENT_PATTERN = Pattern.compile("COMMENT='[^']*'"); - private static final Pattern INDEX_NAME_PATTERN = Pattern.compile("KEY\\s*(`)?(?[a-zA-Z0-9\\-_]+)(`)?"); - private static final Pattern DROP_INDEX_PATTERN = Pattern.compile("DROP\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?"); - private static final Pattern CREATE_INDEX_PATTERN = Pattern.compile("CREATE\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?"); + private static final Pattern CREATE_TABLE_PATTERN = Pattern.compile( + "CREATE\\s+TABLE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", Pattern.CASE_INSENSITIVE); + + private static final Pattern ALTER_TABLE_PATTERN = Pattern.compile( + "ALTER\\s+TABLE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", Pattern.CASE_INSENSITIVE); + private static final Pattern ADD_COLUMN_PATTERN = Pattern.compile( + "ADD\\s+COLUMN\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + Pattern.CASE_INSENSITIVE); + private static final Pattern MODIFY_COLUMN_PATTERN = Pattern.compile( + "MODIFY\\s+COLUMN\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + Pattern.CASE_INSENSITIVE); + private static final Pattern CHANGE_PATTERN = Pattern.compile( + "CHANGE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + Pattern.CASE_INSENSITIVE); + private static final Pattern DROP_COLUMN_PATTERN = Pattern.compile( + "DROP\\s+(COLUMN\\s+)?(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", + Pattern.CASE_INSENSITIVE); + private static final Pattern ADD_KEY_PATTERN = Pattern.compile( + "ADD\\s+(?(UNIQUE\\s+)?KEY)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + Pattern.CASE_INSENSITIVE); + private static final Pattern ADD_INDEX_PATTERN = Pattern.compile( + "ADD\\s+(?(UNIQUE\\s+)?INDEX)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + Pattern.CASE_INSENSITIVE); + + private static final Pattern CREATE_INDEX_ON_PATTERN = Pattern.compile( + "CREATE\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s+ON\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", + Pattern.CASE_INSENSITIVE); + + private static final Pattern INDEX_NAME_PATTERN = Pattern.compile( + "KEY\\s*(`)?(?[a-zA-Z0-9\\-_]+)(`)?", Pattern.CASE_INSENSITIVE); + private static final Pattern DROP_INDEX_PATTERN = Pattern.compile( + "DROP\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", Pattern.CASE_INSENSITIVE); + private static final Pattern CREATE_INDEX_PATTERN = Pattern.compile( + "CREATE\\s+(?(UNIQUE\\s+)?INDEX)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", + Pattern.CASE_INSENSITIVE); private static final Pattern PREFIX_INDEX_PATTERN = Pattern.compile( - "(`[a-zA-Z0-9\\-_]+`)\\([0-9]+\\)"); - private static final Pattern COLUMN_COMMENT_PATTERN = Pattern.compile("COMMENT *'[^']*'"); + "(?\\(" + + "((`)?[a-zA-Z0-9\\-_]+(`)?\\s*(\\([0-9]+\\))?,)*)" + + "(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*\\([0-9]+\\)" + + "(?(,(`)?[a-zA-Z0-9\\-_]+(`)?\\s*(\\([0-9]+\\))?)*" + + "\\))"); public static void convert(SqlTemplate sqlTemplate, String targetSql, SqlTemplateContext context) { @@ -48,11 +81,11 @@ public static void convert(SqlTemplate sqlTemplate, String targetSql, List sqlStatements = ApolloSqlConverterUtil.toStatements(rawText); try (BufferedWriter bufferedWriter = Files.newBufferedWriter(Paths.get(targetSql), - StandardCharsets.UTF_8, StandardOpenOption.CREATE, - StandardOpenOption.TRUNCATE_EXISTING)) { + StandardCharsets.UTF_8, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING)) { for (SqlStatement sqlStatement : sqlStatements) { - String convertedLine = convertAssemblyH2Line(sqlStatement); - bufferedWriter.write(convertedLine); + String convertedText = convertAssemblyH2Line(sqlStatement); + bufferedWriter.write(convertedText); bufferedWriter.write('\n'); } @@ -62,122 +95,237 @@ public static void convert(SqlTemplate sqlTemplate, String targetSql, } private static String convertAssemblyH2Line(SqlStatement sqlStatement) { - String convertedLine = sqlStatement.getRawText(); + String convertedText = sqlStatement.getRawText(); // remove drop table - if (convertedLine.contains("DROP TABLE")) { + if (convertedText.contains("DROP TABLE")) { return ""; } - String tableName = null; - Matcher createTableMatcher = CREATE_TABLE_PATTERN.matcher(convertedLine); + Matcher createTableMatcher = CREATE_TABLE_PATTERN.matcher(convertedText); + Matcher alterTableMatcher = ALTER_TABLE_PATTERN.matcher(convertedText); + Matcher createIndexOnMatcher = CREATE_INDEX_ON_PATTERN.matcher(convertedText); if (createTableMatcher.find()) { - tableName = createTableMatcher.group("tableName"); + String createTableName = createTableMatcher.group("tableName"); // table config - convertedLine = convertTableConfig(convertedLine, sqlStatement); - } else { - Matcher alterTableMatcher = ALTER_TABLE_PATTERN.matcher(convertedLine); - if (alterTableMatcher.find()) { - tableName = alterTableMatcher.group("tableName"); - } + convertedText = convertTableConfig(convertedText, sqlStatement); + // index with table + convertedText = convertIndexWithTable(convertedText, createTableName, sqlStatement); + } else if (alterTableMatcher.find()) { + String alterTableName = alterTableMatcher.group("tableName"); + // alter table + convertedText = convertTableAlter(convertedText, sqlStatement, alterTableMatcher, + alterTableName); + } else if (createIndexOnMatcher.find()) { + String createIndexOnTableName = createIndexOnMatcher.group("tableName"); + // index with table + convertedText = convertIndexOnTable(convertedText, createIndexOnTableName, sqlStatement); } - // index with table - convertedLine = convertIndexWithTable(convertedLine, tableName, sqlStatement); + // column + convertedText = convertColumn(convertedText, sqlStatement); + return convertedText; + } - // index with alter - convertedLine = convertIndexWithAlter(convertedLine, tableName, sqlStatement); + private static String convertTableConfig(String convertedText, SqlStatement sqlStatement) { + if (convertedText.contains("ENGINE=InnoDB")) { + convertedText = convertedText.replace("ENGINE=InnoDB", ""); + } + if (convertedText.contains("DEFAULT CHARSET=utf8mb4")) { + convertedText = convertedText.replace("DEFAULT CHARSET=utf8mb4", ""); + } + if (convertedText.contains("ROW_FORMAT=DYNAMIC")) { + convertedText = convertedText.replace("ROW_FORMAT=DYNAMIC", ""); + } - // column - convertedLine = convertColumn(convertedLine, sqlStatement); - return convertedLine; + return convertedText; + } + + private static String convertTableAlter(String convertedText, SqlStatement sqlStatement, + Matcher alterTableMatcher, String tableName) { + int foundCount = getSubStatementCount(convertedText, sqlStatement, tableName); + if (foundCount == 0) { + throw new IllegalStateException("Unsupported alter table statement: " + convertedText); + } else if (foundCount == 1) { + // index with alter + convertedText = convertIndexNameWithAlter(convertedText, tableName, sqlStatement); + return convertedText; + } else if (foundCount > 1) { + convertedText = alterTableMatcher.replaceAll(""); + convertedText = convertTableAlterMulti(convertedText, sqlStatement, tableName); + } + + return convertedText; } - private static String convertTableConfig(String convertedLine, SqlStatement sqlStatement) { - if (convertedLine.contains("ENGINE=InnoDB")) { - convertedLine = convertedLine.replace("ENGINE=InnoDB", ""); + private static int getSubStatementCount(String convertedText, SqlStatement sqlStatement, + String tableName) { + int foundCount = 0; + Matcher addColumnMatcher = ADD_COLUMN_PATTERN.matcher(convertedText); + while (addColumnMatcher.find()) { + foundCount++; + } + Matcher modifyColumnMatcher = MODIFY_COLUMN_PATTERN.matcher(convertedText); + while (modifyColumnMatcher.find()) { + foundCount++; + } + Matcher changeMatcher = CHANGE_PATTERN.matcher(convertedText); + while (changeMatcher.find()) { + foundCount++; + } + Matcher dropColumnMatcher = DROP_COLUMN_PATTERN.matcher(convertedText); + while (dropColumnMatcher.find()) { + foundCount++; } - if (convertedLine.contains("DEFAULT CHARSET=utf8mb4")) { - convertedLine = convertedLine.replace("DEFAULT CHARSET=utf8mb4", ""); + Matcher addKeyMatcher = ADD_KEY_PATTERN.matcher(convertedText); + while (addKeyMatcher.find()) { + foundCount++; } - if (convertedLine.contains("ROW_FORMAT=DYNAMIC")) { - convertedLine = convertedLine.replace("ROW_FORMAT=DYNAMIC", ""); + Matcher addIndexMatcher = ADD_INDEX_PATTERN.matcher(convertedText); + while (addIndexMatcher.find()) { + foundCount++; } + Matcher dropIndexMatcher = DROP_INDEX_PATTERN.matcher(convertedText); + while (dropIndexMatcher.find()) { + foundCount++; + } + return foundCount; + } - // remove table comment - Matcher tableCommentMatcher = TABLE_COMMENT_PATTERN.matcher(convertedLine); - if (tableCommentMatcher.find()) { - convertedLine = tableCommentMatcher.replaceAll(""); + private static String convertTableAlterMulti(String convertedText, SqlStatement sqlStatement, + String tableName) { + Matcher addColumnMatcher = ADD_COLUMN_PATTERN.matcher(convertedText); + if (addColumnMatcher.find()) { + convertedText = addColumnMatcher.replaceAll( + "ALTER TABLE `" + tableName + "` ADD COLUMN `${columnName}`${subStatement};"); + } + Matcher modifyColumnMatcher = MODIFY_COLUMN_PATTERN.matcher(convertedText); + if (modifyColumnMatcher.find()) { + convertedText = modifyColumnMatcher.replaceAll( + "ALTER TABLE `" + tableName + "` MODIFY COLUMN `${columnName}`${subStatement};"); + } + Matcher changeMatcher = CHANGE_PATTERN.matcher(convertedText); + if (changeMatcher.find()) { + convertedText = changeMatcher.replaceAll("ALTER TABLE `" + tableName + + "` CHANGE `${oldColumnName` `${newColumnName}` ${subStatement};"); } - return convertedLine; + Matcher dropColumnMatcher = DROP_COLUMN_PATTERN.matcher(convertedText); + if (dropColumnMatcher.find()) { + convertedText = dropColumnMatcher.replaceAll( + "ALTER TABLE `" + tableName + "` DROP `${columnName}`;"); + } + Matcher addKeyMatcher = ADD_KEY_PATTERN.matcher(convertedText); + if (addKeyMatcher.find()) { + convertedText = addKeyMatcher.replaceAll( + "ALTER TABLE `" + tableName + "` ADD ${indexType} `" + tableName + + "_${indexName}` ${subStatement};"); + convertedText = removePrefixIndex(convertedText); + } + Matcher addIndexMatcher = ADD_INDEX_PATTERN.matcher(convertedText); + if (addIndexMatcher.find()) { + convertedText = addIndexMatcher.replaceAll( + "ALTER TABLE `" + tableName + "` ADD ${indexType} `" + tableName + + "_${indexName}` ${subStatement};"); + convertedText = removePrefixIndex(convertedText); + } + Matcher dropIndexMatcher = DROP_INDEX_PATTERN.matcher(convertedText); + if (dropIndexMatcher.find()) { + convertedText = dropIndexMatcher.replaceAll( + "ALTER TABLE `" + tableName + "` DROP INDEX `" + tableName + "_${indexName}`;"); + } + return convertedText; } - private static String convertIndexWithTable(String convertedLine,String tableName, SqlStatement sqlStatement) { - if (convertedLine.contains("KEY")) { - // replace index name - // KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) - // -> - // KEY `tableName_AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) - Matcher indexNameMatcher = INDEX_NAME_PATTERN.matcher(convertedLine); - if (indexNameMatcher.find()) { - convertedLine = indexNameMatcher.replaceAll("KEY `" + tableName + "_${indexName}`"); - } + private static String convertIndexOnTable(String convertedText, String tableName, + SqlStatement sqlStatement) { + Matcher createIndexMatcher = CREATE_INDEX_PATTERN.matcher(convertedText); + if (createIndexMatcher.find()) { + convertedText = createIndexMatcher.replaceAll( + "CREATE ${indexType} `" + tableName + "_${indexName}`"); + convertedText = removePrefixIndex(convertedText); + } + return convertedText; + } + + private static String convertIndexWithTable(String convertedText, String tableName, + SqlStatement sqlStatement) { + String[] lines = convertedText.split("\n"); + StringJoiner joiner = new StringJoiner("\n"); + for (String line : lines) { + String convertedLine = line; + if (convertedLine.contains("KEY")) { + // replace index name + // KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + // -> + // KEY `tableName_AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + Matcher indexNameMatcher = INDEX_NAME_PATTERN.matcher(convertedLine); + if (indexNameMatcher.find()) { + convertedLine = indexNameMatcher.replaceAll("KEY `" + tableName + "_${indexName}`"); + } - // convert prefix index - // KEY (`AppId`,`ClusterName`(191),`NamespaceName`(191)) - // -> - // KEY (`AppId`,`ClusterName`,`NamespaceName`) - for (Matcher prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedLine); - prefixIndexMatcher.find(); - prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedLine)) { - convertedLine = prefixIndexMatcher.replaceAll("$1"); + convertedLine = removePrefixIndex(convertedLine); } + joiner.add(convertedLine); } - return convertedLine; + return joiner.toString(); } - private static String convertIndexWithAlter(String convertedLine, String tableName, + private static String convertIndexNameWithAlter(String convertedText, String tableName, SqlStatement sqlStatement) { - Matcher dropIndexMatcher = DROP_INDEX_PATTERN.matcher(convertedLine); - if (dropIndexMatcher.find()) { - convertedLine = dropIndexMatcher.replaceAll("DROP INDEX `" + tableName + "_${indexName}`"); + Matcher addKeyMatcher = ADD_KEY_PATTERN.matcher(convertedText); + if (addKeyMatcher.find()) { + convertedText = addKeyMatcher.replaceAll( + "ADD ${indexType} `" + tableName + "_${indexName}` ${subStatement};"); + convertedText = removePrefixIndex(convertedText); + } + Matcher addIndexMatcher = ADD_INDEX_PATTERN.matcher(convertedText); + if (addIndexMatcher.find()) { + convertedText = addIndexMatcher.replaceAll( + "ADD ${indexType} `" + tableName + "_${indexName}` ${subStatement};"); + convertedText = removePrefixIndex(convertedText); } - Matcher createIndexMatcher = CREATE_INDEX_PATTERN.matcher(convertedLine); + Matcher createIndexMatcher = CREATE_INDEX_PATTERN.matcher(convertedText); if (createIndexMatcher.find()) { - convertedLine = createIndexMatcher.replaceAll("CREATE INDEX `" + tableName + "_${indexName}`"); - - // convert prefix index - // CREATE INDEX `IX_NAME` ON App (`AppId`,`ClusterName`(191),`NamespaceName`(191)) - // -> - // CREATE INDEX `IX_NAME` ON App (`AppId`,`ClusterName`,`NamespaceName`) - for (Matcher prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedLine); - prefixIndexMatcher.find(); - prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedLine)) { - convertedLine = prefixIndexMatcher.replaceAll("$1"); - } + convertedText = createIndexMatcher.replaceAll( + "CREATE ${indexType} `" + tableName + "_${indexName}`"); + convertedText = removePrefixIndex(convertedText); + } + Matcher dropIndexMatcher = DROP_INDEX_PATTERN.matcher(convertedText); + if (dropIndexMatcher.find()) { + convertedText = dropIndexMatcher.replaceAll("DROP INDEX `" + tableName + "_${indexName}`;"); } - return convertedLine; + return convertedText; } - private static String convertColumn(String convertedLine, SqlStatement sqlStatement) { + private static String removePrefixIndex(String convertedText) { + // convert prefix index + // CREATE INDEX `IX_NAME` ON App (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + // -> + // CREATE INDEX `IX_NAME` ON App (`AppId`,`ClusterName`,`NamespaceName`) + for (Matcher prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedText); + prefixIndexMatcher.find(); + prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedText)) { + convertedText = prefixIndexMatcher.replaceAll("${prefix}`${columnName}`${suffix}"); + } + return convertedText; + } + + private static String convertColumn(String convertedText, SqlStatement sqlStatement) { // convert bit(1) to boolean // `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal' // -> // `IsDeleted` boolean NOT NULL DEFAULT FALSE - if (convertedLine.contains("bit(1)")) { - convertedLine = convertedLine.replace("bit(1)", "boolean"); + if (convertedText.contains("bit(1)")) { + convertedText = convertedText.replace("bit(1)", "boolean"); } - if (convertedLine.contains("b'0'")) { - convertedLine = convertedLine.replace("b'0'", "FALSE"); + if (convertedText.contains("b'0'")) { + convertedText = convertedText.replace("b'0'", "FALSE"); } - - // remove column comment - Matcher columnCommentMatcher = COLUMN_COMMENT_PATTERN.matcher(convertedLine); - if (columnCommentMatcher.find()) { - convertedLine = columnCommentMatcher.replaceAll(""); + if (convertedText.contains("b'1'")) { + convertedText = convertedText.replace("b'1'", "TRUE"); } - return convertedLine; + return convertedText; } } diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloMysqlDefaultConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloMysqlDefaultConverterUtil.java index d41f9563523..3450cd016bb 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloMysqlDefaultConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloMysqlDefaultConverterUtil.java @@ -50,8 +50,8 @@ public static void convert(SqlTemplate sqlTemplate, String targetSql, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { for (SqlStatement sqlStatement : sqlStatements) { - String convertedLine = convertMainMysqlLine(sqlStatement, databaseName); - bufferedWriter.write(convertedLine); + String convertedText = convertMainMysqlLine(sqlStatement, databaseName); + bufferedWriter.write(convertedText); bufferedWriter.write('\n'); } } catch (IOException e) { @@ -60,10 +60,10 @@ public static void convert(SqlTemplate sqlTemplate, String targetSql, } private static String convertMainMysqlLine(SqlStatement sqlStatement, String databaseName) { - String convertedLine = sqlStatement.getRawText(); + String convertedText = sqlStatement.getRawText(); - convertedLine = convertedLine.replace("ApolloAssemblyDB", databaseName); + convertedText = convertedText.replace("ApolloAssemblyDB", databaseName); - return convertedLine; + return convertedText; } } From db9a48a7b0c98c00e6584bc302d63052af5d2807 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 26 Jan 2024 22:49:18 +0800 Subject: [PATCH 50/59] add sql test --- .../sql/converter/ApolloH2ConverterUtil.java | 323 ++++++++---------- .../sql/converter/ApolloSqlConverterUtil.java | 4 + .../ApolloSqlConverterAutoGeneratedTest.java | 8 +- .../converter/ApolloSqlConverterH2Test.java | 36 +- .../apolloconfigdb-v000-v010-after.sql} | 0 .../apolloconfigdb-v000-v010-base.sql} | 0 .../apolloconfigdb-v000-v010-before.sql} | 2 +- .../v000-v010/apolloconfigdb-v000-v010.sql | 22 ++ .../apolloportaldb-v000-v010-base.sql} | 0 .../v000-v010/apolloportaldb-v000-v010.sql | 22 ++ .../v040-v050/apolloportaldb-v040-v050.sql | 6 +- .../v060-v062/apolloconfigdb-v060-v062.sql | 2 + .../v060-v062/apolloportaldb-v060-v062.sql | 2 + .../v080-v090/apolloportaldb-v080-v090.sql | 2 + .../v151-v160/apolloconfigdb-v151-v160.sql | 4 +- .../v170-v180/apolloconfigdb-v170-v180.sql | 2 + .../v170-v180/apolloportaldb-v170-v180.sql | 2 + .../v180-v190/apolloconfigdb-v180-v190.sql | 2 + .../v180-v190/apolloportaldb-v180-v190.sql | 2 + .../apolloconfigdb-v190-v200-after.sql | 2 + .../v190-v200/apolloconfigdb-v190-v200.sql | 2 + .../apolloportaldb-v190-v200-after.sql | 2 + .../v190-v200/apolloportaldb-v190-v200.sql | 4 +- .../v200-v210/apolloconfigdb-v200-v210.sql | 4 +- .../v210-v220/apolloconfigdb-v210-v220.sql | 2 + .../v210-v220/apolloportaldb-v210-v220.sql | 2 + 26 files changed, 260 insertions(+), 199 deletions(-) rename apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/{v040-v050/apolloconfigdb-v040-v050-before.sql => v000-v010/apolloconfigdb-v000-v010-after.sql} (100%) rename apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/{v040-v050/apolloconfigdb-v040-v050-base.sql => v000-v010/apolloconfigdb-v000-v010-base.sql} (100%) rename apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/{v040-v050/apolloconfigdb-v040-v050-after.sql => v000-v010/apolloconfigdb-v000-v010-before.sql} (93%) create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010.sql rename apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/{v040-v050/apolloportaldb-v040-v050-base.sql => v000-v010/apolloportaldb-v000-v010-base.sql} (100%) create mode 100644 apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloportaldb-v000-v010.sql diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java index 7885195e25c..59ba0dd1b30 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java @@ -30,48 +30,6 @@ public class ApolloH2ConverterUtil { - private static final Pattern CREATE_TABLE_PATTERN = Pattern.compile( - "CREATE\\s+TABLE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", Pattern.CASE_INSENSITIVE); - - private static final Pattern ALTER_TABLE_PATTERN = Pattern.compile( - "ALTER\\s+TABLE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", Pattern.CASE_INSENSITIVE); - private static final Pattern ADD_COLUMN_PATTERN = Pattern.compile( - "ADD\\s+COLUMN\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", - Pattern.CASE_INSENSITIVE); - private static final Pattern MODIFY_COLUMN_PATTERN = Pattern.compile( - "MODIFY\\s+COLUMN\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", - Pattern.CASE_INSENSITIVE); - private static final Pattern CHANGE_PATTERN = Pattern.compile( - "CHANGE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", - Pattern.CASE_INSENSITIVE); - private static final Pattern DROP_COLUMN_PATTERN = Pattern.compile( - "DROP\\s+(COLUMN\\s+)?(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", - Pattern.CASE_INSENSITIVE); - private static final Pattern ADD_KEY_PATTERN = Pattern.compile( - "ADD\\s+(?(UNIQUE\\s+)?KEY)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", - Pattern.CASE_INSENSITIVE); - private static final Pattern ADD_INDEX_PATTERN = Pattern.compile( - "ADD\\s+(?(UNIQUE\\s+)?INDEX)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", - Pattern.CASE_INSENSITIVE); - - private static final Pattern CREATE_INDEX_ON_PATTERN = Pattern.compile( - "CREATE\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s+ON\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", - Pattern.CASE_INSENSITIVE); - - private static final Pattern INDEX_NAME_PATTERN = Pattern.compile( - "KEY\\s*(`)?(?[a-zA-Z0-9\\-_]+)(`)?", Pattern.CASE_INSENSITIVE); - private static final Pattern DROP_INDEX_PATTERN = Pattern.compile( - "DROP\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", Pattern.CASE_INSENSITIVE); - private static final Pattern CREATE_INDEX_PATTERN = Pattern.compile( - "CREATE\\s+(?(UNIQUE\\s+)?INDEX)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", - Pattern.CASE_INSENSITIVE); - private static final Pattern PREFIX_INDEX_PATTERN = Pattern.compile( - "(?\\(" - + "((`)?[a-zA-Z0-9\\-_]+(`)?\\s*(\\([0-9]+\\))?,)*)" - + "(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*\\([0-9]+\\)" - + "(?(,(`)?[a-zA-Z0-9\\-_]+(`)?\\s*(\\([0-9]+\\))?)*" - + "\\))"); - public static void convert(SqlTemplate sqlTemplate, String targetSql, SqlTemplateContext context) { @@ -84,7 +42,12 @@ public static void convert(SqlTemplate sqlTemplate, String targetSql, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { for (SqlStatement sqlStatement : sqlStatements) { - String convertedText = convertAssemblyH2Line(sqlStatement); + String convertedText; + try { + convertedText = convertAssemblyH2Line(sqlStatement); + } catch (Throwable e) { + throw new RuntimeException("convert error: " + sqlStatement.getRawText(), e); + } bufferedWriter.write(convertedText); bufferedWriter.write('\n'); } @@ -94,105 +57,155 @@ public static void convert(SqlTemplate sqlTemplate, String targetSql, } } + + private static final Pattern OPERATION_TABLE_PATTERN = Pattern.compile( + "(?DROP|CREATE|ALTER)\\s+TABLE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", + Pattern.CASE_INSENSITIVE); + + private static final Pattern CREATE_INDEX_ON_PATTERN = Pattern.compile( + "CREATE\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s+ON\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", + Pattern.CASE_INSENSITIVE); + private static String convertAssemblyH2Line(SqlStatement sqlStatement) { String convertedText = sqlStatement.getRawText(); - // remove drop table - if (convertedText.contains("DROP TABLE")) { - return ""; + // TABLE `` + Matcher opTableMatcher = OPERATION_TABLE_PATTERN.matcher(convertedText); + if (opTableMatcher.find()) { + String operation = opTableMatcher.group("operation"); + if ("DROP".equalsIgnoreCase(operation)) { + return ""; + } else if ("CREATE".equalsIgnoreCase(operation)) { + return convertCreateTable(convertedText, sqlStatement, opTableMatcher); + } else if ("ALTER".equalsIgnoreCase(operation)) { + return convertAlterTable(convertedText, sqlStatement, opTableMatcher); + } } - Matcher createTableMatcher = CREATE_TABLE_PATTERN.matcher(convertedText); - Matcher alterTableMatcher = ALTER_TABLE_PATTERN.matcher(convertedText); + // CREATE INDEX `` ON `` Matcher createIndexOnMatcher = CREATE_INDEX_ON_PATTERN.matcher(convertedText); - if (createTableMatcher.find()) { - String createTableName = createTableMatcher.group("tableName"); - // table config - convertedText = convertTableConfig(convertedText, sqlStatement); - // index with table - convertedText = convertIndexWithTable(convertedText, createTableName, sqlStatement); - } else if (alterTableMatcher.find()) { - String alterTableName = alterTableMatcher.group("tableName"); - // alter table - convertedText = convertTableAlter(convertedText, sqlStatement, alterTableMatcher, - alterTableName); - } else if (createIndexOnMatcher.find()) { + if (createIndexOnMatcher.find()) { String createIndexOnTableName = createIndexOnMatcher.group("tableName"); // index with table - convertedText = convertIndexOnTable(convertedText, createIndexOnTableName, sqlStatement); + return convertIndexOnTable(convertedText, createIndexOnTableName, sqlStatement); } + // others + return convertedText; + } + + private static String convertCreateTable(String convertedText, SqlStatement sqlStatement, + Matcher opTableMatcher) { + String tableName = opTableMatcher.group("tableName"); + // table config + convertedText = convertTableConfig(convertedText, sqlStatement); + // index with table + convertedText = convertIndexWithTable(convertedText, tableName, sqlStatement); // column convertedText = convertColumn(convertedText, sqlStatement); return convertedText; } + private static final Pattern ENGINE_PATTERN = Pattern.compile( + "ENGINE\\s*=\\s*InnoDB", Pattern.CASE_INSENSITIVE); + + private static final Pattern DEFAULT_CHARSET_PATTERN = Pattern.compile( + "DEFAULT\\s+CHARSET\\s*=\\s*utf8mb4", Pattern.CASE_INSENSITIVE); + + private static final Pattern ROW_FORMAT_PATTERN = Pattern.compile( + "ROW_FORMAT\\s*=\\s*DYNAMIC", Pattern.CASE_INSENSITIVE); + private static String convertTableConfig(String convertedText, SqlStatement sqlStatement) { - if (convertedText.contains("ENGINE=InnoDB")) { - convertedText = convertedText.replace("ENGINE=InnoDB", ""); + Matcher engineMatcher = ENGINE_PATTERN.matcher(convertedText); + if (engineMatcher.find()) { + convertedText = engineMatcher.replaceAll(""); } - if (convertedText.contains("DEFAULT CHARSET=utf8mb4")) { - convertedText = convertedText.replace("DEFAULT CHARSET=utf8mb4", ""); + Matcher defaultCharsetMatcher = DEFAULT_CHARSET_PATTERN.matcher(convertedText); + if (defaultCharsetMatcher.find()) { + convertedText = defaultCharsetMatcher.replaceAll(""); } - if (convertedText.contains("ROW_FORMAT=DYNAMIC")) { - convertedText = convertedText.replace("ROW_FORMAT=DYNAMIC", ""); + Matcher rowFormatMatcher = ROW_FORMAT_PATTERN.matcher(convertedText); + if (rowFormatMatcher.find()) { + convertedText = rowFormatMatcher.replaceAll(""); } - return convertedText; } - private static String convertTableAlter(String convertedText, SqlStatement sqlStatement, - Matcher alterTableMatcher, String tableName) { - int foundCount = getSubStatementCount(convertedText, sqlStatement, tableName); - if (foundCount == 0) { - throw new IllegalStateException("Unsupported alter table statement: " + convertedText); - } else if (foundCount == 1) { - // index with alter - convertedText = convertIndexNameWithAlter(convertedText, tableName, sqlStatement); - return convertedText; - } else if (foundCount > 1) { - convertedText = alterTableMatcher.replaceAll(""); - convertedText = convertTableAlterMulti(convertedText, sqlStatement, tableName); - } + private static final Pattern INDEX_NAME_PATTERN = Pattern.compile( + "KEY\\s*(`)?(?[a-zA-Z0-9\\-_]+)(`)?", Pattern.CASE_INSENSITIVE); - return convertedText; + private static String convertIndexWithTable(String convertedText, String tableName, + SqlStatement sqlStatement) { + String[] lines = convertedText.split("\n"); + StringJoiner joiner = new StringJoiner("\n"); + for (String line : lines) { + String convertedLine = line; + if (convertedLine.contains("KEY")) { + // replace index name + // KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + // -> + // KEY `tableName_AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + Matcher indexNameMatcher = INDEX_NAME_PATTERN.matcher(convertedLine); + if (indexNameMatcher.find()) { + convertedLine = indexNameMatcher.replaceAll("KEY `" + tableName + "_${indexName}`"); + } + convertedLine = removePrefixIndex(convertedLine); + } + joiner.add(convertedLine); + } + return joiner.toString(); } - private static int getSubStatementCount(String convertedText, SqlStatement sqlStatement, - String tableName) { - int foundCount = 0; - Matcher addColumnMatcher = ADD_COLUMN_PATTERN.matcher(convertedText); - while (addColumnMatcher.find()) { - foundCount++; - } - Matcher modifyColumnMatcher = MODIFY_COLUMN_PATTERN.matcher(convertedText); - while (modifyColumnMatcher.find()) { - foundCount++; - } - Matcher changeMatcher = CHANGE_PATTERN.matcher(convertedText); - while (changeMatcher.find()) { - foundCount++; - } - Matcher dropColumnMatcher = DROP_COLUMN_PATTERN.matcher(convertedText); - while (dropColumnMatcher.find()) { - foundCount++; - } - Matcher addKeyMatcher = ADD_KEY_PATTERN.matcher(convertedText); - while (addKeyMatcher.find()) { - foundCount++; + private static String convertColumn(String convertedText, SqlStatement sqlStatement) { + // convert bit(1) to boolean + // `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal' + // -> + // `IsDeleted` boolean NOT NULL DEFAULT FALSE + if (convertedText.contains("bit(1)")) { + convertedText = convertedText.replace("bit(1)", "boolean"); } - Matcher addIndexMatcher = ADD_INDEX_PATTERN.matcher(convertedText); - while (addIndexMatcher.find()) { - foundCount++; + if (convertedText.contains("b'0'")) { + convertedText = convertedText.replace("b'0'", "FALSE"); } - Matcher dropIndexMatcher = DROP_INDEX_PATTERN.matcher(convertedText); - while (dropIndexMatcher.find()) { - foundCount++; + if (convertedText.contains("b'1'")) { + convertedText = convertedText.replace("b'1'", "TRUE"); } - return foundCount; + + return convertedText; + } + + private static String convertAlterTable(String convertedText, SqlStatement sqlStatement, + Matcher opTableMatcher) { + String tableName = opTableMatcher.group("tableName"); + // remove first table name + convertedText = opTableMatcher.replaceAll(""); + convertedText = convertAlterTableMulti(convertedText, sqlStatement, tableName); + + return convertedText; } - private static String convertTableAlterMulti(String convertedText, SqlStatement sqlStatement, + private static final Pattern ADD_COLUMN_PATTERN = Pattern.compile( + "ADD\\s+COLUMN\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + Pattern.CASE_INSENSITIVE); + private static final Pattern MODIFY_COLUMN_PATTERN = Pattern.compile( + "MODIFY\\s+COLUMN\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + Pattern.CASE_INSENSITIVE); + private static final Pattern CHANGE_PATTERN = Pattern.compile( + "CHANGE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + Pattern.CASE_INSENSITIVE); + private static final Pattern DROP_COLUMN_PATTERN = Pattern.compile( + "DROP\\s+(COLUMN\\s+)?(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", + Pattern.CASE_INSENSITIVE); + private static final Pattern ADD_KEY_PATTERN = Pattern.compile( + "ADD\\s+(?(UNIQUE\\s+)?KEY)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + Pattern.CASE_INSENSITIVE); + private static final Pattern ADD_INDEX_PATTERN = Pattern.compile( + "ADD\\s+(?(UNIQUE\\s+)?INDEX)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + Pattern.CASE_INSENSITIVE); + private static final Pattern DROP_INDEX_PATTERN = Pattern.compile( + "DROP\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", Pattern.CASE_INSENSITIVE); + + private static String convertAlterTableMulti(String convertedText, SqlStatement sqlStatement, String tableName) { Matcher addColumnMatcher = ADD_COLUMN_PATTERN.matcher(convertedText); if (addColumnMatcher.find()) { @@ -207,7 +220,7 @@ private static String convertTableAlterMulti(String convertedText, SqlStatement Matcher changeMatcher = CHANGE_PATTERN.matcher(convertedText); if (changeMatcher.find()) { convertedText = changeMatcher.replaceAll("ALTER TABLE `" + tableName - + "` CHANGE `${oldColumnName` `${newColumnName}` ${subStatement};"); + + "` CHANGE `${oldColumnName}` `${newColumnName}` ${subStatement};"); } Matcher dropColumnMatcher = DROP_COLUMN_PATTERN.matcher(convertedText); @@ -237,6 +250,10 @@ private static String convertTableAlterMulti(String convertedText, SqlStatement return convertedText; } + private static final Pattern CREATE_INDEX_PATTERN = Pattern.compile( + "CREATE\\s+(?(UNIQUE\\s+)?INDEX)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", + Pattern.CASE_INSENSITIVE); + private static String convertIndexOnTable(String convertedText, String tableName, SqlStatement sqlStatement) { Matcher createIndexMatcher = CREATE_INDEX_PATTERN.matcher(convertedText); @@ -248,61 +265,21 @@ private static String convertIndexOnTable(String convertedText, String tableName return convertedText; } - private static String convertIndexWithTable(String convertedText, String tableName, - SqlStatement sqlStatement) { - String[] lines = convertedText.split("\n"); - StringJoiner joiner = new StringJoiner("\n"); - for (String line : lines) { - String convertedLine = line; - if (convertedLine.contains("KEY")) { - // replace index name - // KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) - // -> - // KEY `tableName_AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) - Matcher indexNameMatcher = INDEX_NAME_PATTERN.matcher(convertedLine); - if (indexNameMatcher.find()) { - convertedLine = indexNameMatcher.replaceAll("KEY `" + tableName + "_${indexName}`"); - } - - convertedLine = removePrefixIndex(convertedLine); - } - joiner.add(convertedLine); - } - return joiner.toString(); - } - - private static String convertIndexNameWithAlter(String convertedText, String tableName, - SqlStatement sqlStatement) { - Matcher addKeyMatcher = ADD_KEY_PATTERN.matcher(convertedText); - if (addKeyMatcher.find()) { - convertedText = addKeyMatcher.replaceAll( - "ADD ${indexType} `" + tableName + "_${indexName}` ${subStatement};"); - convertedText = removePrefixIndex(convertedText); - } - Matcher addIndexMatcher = ADD_INDEX_PATTERN.matcher(convertedText); - if (addIndexMatcher.find()) { - convertedText = addIndexMatcher.replaceAll( - "ADD ${indexType} `" + tableName + "_${indexName}` ${subStatement};"); - convertedText = removePrefixIndex(convertedText); - } - Matcher createIndexMatcher = CREATE_INDEX_PATTERN.matcher(convertedText); - if (createIndexMatcher.find()) { - convertedText = createIndexMatcher.replaceAll( - "CREATE ${indexType} `" + tableName + "_${indexName}`"); - convertedText = removePrefixIndex(convertedText); - } - Matcher dropIndexMatcher = DROP_INDEX_PATTERN.matcher(convertedText); - if (dropIndexMatcher.find()) { - convertedText = dropIndexMatcher.replaceAll("DROP INDEX `" + tableName + "_${indexName}`;"); - } - return convertedText; - } + private static final Pattern PREFIX_INDEX_PATTERN = Pattern.compile( + "(?\\(" + // other columns + + "((`)?[a-zA-Z0-9\\-_]+(`)?\\s*(\\([0-9]+\\))?,)*)" + // ``(191) + + "(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*\\([0-9]+\\)" + // other columns + + "(?(,(`)?[a-zA-Z0-9\\-_]+(`)?\\s*(\\([0-9]+\\))?)*" + + "\\))"); private static String removePrefixIndex(String convertedText) { // convert prefix index - // CREATE INDEX `IX_NAME` ON App (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + // (`AppId`,`ClusterName`(191),`NamespaceName`(191)) // -> - // CREATE INDEX `IX_NAME` ON App (`AppId`,`ClusterName`,`NamespaceName`) + // (`AppId`,`ClusterName`,`NamespaceName`) for (Matcher prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedText); prefixIndexMatcher.find(); prefixIndexMatcher = PREFIX_INDEX_PATTERN.matcher(convertedText)) { @@ -310,22 +287,4 @@ private static String removePrefixIndex(String convertedText) { } return convertedText; } - - private static String convertColumn(String convertedText, SqlStatement sqlStatement) { - // convert bit(1) to boolean - // `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal' - // -> - // `IsDeleted` boolean NOT NULL DEFAULT FALSE - if (convertedText.contains("bit(1)")) { - convertedText = convertedText.replace("bit(1)", "boolean"); - } - if (convertedText.contains("b'0'")) { - convertedText = convertedText.replace("b'0'", "FALSE"); - } - if (convertedText.contains("b'1'")) { - convertedText = convertedText.replace("b'1'", "TRUE"); - } - - return convertedText; - } } diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterUtil.java index 3c16d5df60c..af49f64655e 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterUtil.java @@ -227,6 +227,10 @@ public static Comparator deltaSqlComparator() { } else { fileName = unixPath; } + if (!fileName.endsWith(".sql")) { + // not sql file + return path; + } // sort: base < before < delta < after if (BASE_PATTERN.matcher(fileName).matches()) { return "00" + path; diff --git a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterAutoGeneratedTest.java b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterAutoGeneratedTest.java index 1fc956544aa..d43454504ca 100644 --- a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterAutoGeneratedTest.java +++ b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterAutoGeneratedTest.java @@ -173,15 +173,19 @@ private void doCheck(String checkerTargetSql, String repositoryTargetSql) { for (int i = 0; i < checkerLines.size(); i++) { String checkerLine = checkerLines.get(i); - String repositoryLine = repositoryLines.get(i); int lineNumber = i + 1; + if (i >= repositoryLines.size()) { + Assertions.fail("invalid sql file content, please run '" + GENERATE_TIPS + + "' to regenerated\npath: " + repositoryTargetSql + "(line: " + lineNumber + ")"); + } + String repositoryLine = repositoryLines.get(i); Assertions.assertEquals(checkerLine, repositoryLine, "invalid sql file content, please run '" + GENERATE_TIPS + "' to regenerated\npath: " + repositoryTargetSql + "(line: " + lineNumber + ")"); } Assertions.assertEquals(checkerLines.size(), repositoryLines.size(), "invalid sql file content, please run '" + GENERATE_TIPS + "' to regenerated\npath: " - + repositoryTargetSql); + + repositoryTargetSql+ "(line: " + checkerLines.size() + ")"); } private void checkMysqlDatabaseNotSpecifiedList(List srcSqlList, String srcDir, diff --git a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java index 1f0529c2698..0dc1102ce2f 100644 --- a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java +++ b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java @@ -76,21 +76,21 @@ void checkH2() { String h2Path = "test-h2"; this.checkConfigDatabase(h2Path, checkerSqlList, testCheckerSqlList); - this.checkPortalDatabase(h2Path, testSrcSqlList, srcSqlList, testCheckerParentDir, - checkerParentDir); + this.checkPortalDatabase(h2Path, checkerSqlList, testCheckerSqlList); } private void checkSort(List testSrcSqlList) { - int baseIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v040-v050-base.sql"); + int baseIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v000-v010-base.sql"); Assertions.assertTrue(baseIndex >= 0); - int beforeIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v040-v050-before.sql"); + int beforeIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v000-v010-before.sql"); Assertions.assertTrue(beforeIndex >= 0); - int deltaIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v040-v050.sql"); + int deltaIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v000-v010.sql"); Assertions.assertTrue(deltaIndex >= 0); - int afterIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v040-v050-after.sql"); + int afterIndex = this.getIndex(testSrcSqlList, "apolloconfigdb-v000-v010-after.sql"); Assertions.assertTrue(afterIndex >= 0); + // base < before < delta < after Assertions.assertTrue(baseIndex < beforeIndex); Assertions.assertTrue(beforeIndex < deltaIndex); Assertions.assertTrue(deltaIndex < afterIndex); @@ -133,13 +133,31 @@ private void checkConfigDatabase(String h2Path, List checkerSqlList, DatabasePopulatorUtils.execute(populator, configDataSource); } - private void checkPortalDatabase(String h2Path, List testSrcSqlList, - List srcSqlList, - String testCheckerParentDir, String checkerParentDir) { + private void checkPortalDatabase(String h2Path, List checkerSqlList, + List testCheckerSqlList) { SimpleDriverDataSource portalDataSource = new SimpleDriverDataSource(); portalDataSource.setUrl("jdbc:h2:mem:~/" + h2Path + "/apollo-portal-db;mode=mysql;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1;BUILTIN_ALIAS_OVERRIDE=TRUE;DATABASE_TO_UPPER=FALSE"); portalDataSource.setDriverClass(org.h2.Driver.class); + + ResourceDatabasePopulator populator = new ResourceDatabasePopulator(); + populator.setContinueOnError(false); + populator.setSeparator(";"); + populator.setSqlScriptEncoding(StandardCharsets.UTF_8.name()); + + for (String sqlFile : testCheckerSqlList) { + if (sqlFile.contains("apolloportaldb-")) { + populator.addScript(new PathResource(Paths.get(sqlFile))); + } + } + + for (String sqlFile : checkerSqlList) { + if (sqlFile.contains("apolloportaldb-")) { + populator.addScript(new PathResource(Paths.get(sqlFile))); + } + } + + DatabasePopulatorUtils.execute(populator, portalDataSource); } } \ No newline at end of file diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-before.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-after.sql similarity index 100% rename from apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-before.sql rename to apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-after.sql diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-base.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-base.sql similarity index 100% rename from apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-base.sql rename to apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-base.sql diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-after.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-before.sql similarity index 93% rename from apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-after.sql rename to apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-before.sql index 4dda942796c..c804ef63fb9 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloconfigdb-v040-v050-after.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-before.sql @@ -11,4 +11,4 @@ -- ${gists.setupDatabase} --- ${gists.autoGeneratedDeclaration} \ No newline at end of file +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010.sql new file mode 100644 index 00000000000..88193c89edf --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010.sql @@ -0,0 +1,22 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo config db from v0.0.0 to v0.1.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050-base.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloportaldb-v000-v010-base.sql similarity index 100% rename from apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050-base.sql rename to apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloportaldb-v000-v010-base.sql diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloportaldb-v000-v010.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloportaldb-v000-v010.sql new file mode 100644 index 00000000000..df9f7b68deb --- /dev/null +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloportaldb-v000-v010.sql @@ -0,0 +1,22 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- delta schema to upgrade apollo portal db from v0.4.0 to v0.5.0 + +-- ${gists.autoGeneratedDeclaration} +-- ${gists.h2Function} +-- ${gists.useDatabase} + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050.sql index b7c4d91e900..a2a6108bd4d 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v040-v050/apolloportaldb-v040-v050.sql @@ -13,7 +13,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- -# delta schema to upgrade apollo portal db from v0.4.0 to v0.5.0 +-- delta schema to upgrade apollo portal db from v0.4.0 to v0.5.0 -- ${gists.autoGeneratedDeclaration} -- ${gists.h2Function} @@ -21,4 +21,6 @@ ALTER TABLE `AppNamespace` ADD KEY `IX_AppId` (`AppId`); ALTER TABLE `App` DROP INDEX `Name`; -ALTER TABLE `App` ADD KEY `Name` (`Name`); \ No newline at end of file +ALTER TABLE `App` ADD KEY `Name` (`Name`); + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloconfigdb-v060-v062.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloconfigdb-v060-v062.sql index afb82ad42e4..ce5d7ab8b4b 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloconfigdb-v060-v062.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloconfigdb-v060-v062.sql @@ -21,3 +21,5 @@ ALTER TABLE `App` DROP INDEX `Name`; CREATE INDEX `IX_NAME` ON App (`Name`(191)); + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloportaldb-v060-v062.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloportaldb-v060-v062.sql index 048fd52acaf..5d4a1dc7091 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloportaldb-v060-v062.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v060-v062/apolloportaldb-v060-v062.sql @@ -21,3 +21,5 @@ ALTER TABLE `App` DROP INDEX `Name`; CREATE INDEX `IX_NAME` ON App (`Name`(191)); + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v080-v090/apolloportaldb-v080-v090.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v080-v090/apolloportaldb-v080-v090.sql index 6bf091ce7ee..15c56f0d085 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v080-v090/apolloportaldb-v080-v090.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v080-v090/apolloportaldb-v080-v090.sql @@ -40,3 +40,5 @@ VALUES ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo@acme.com', 1); INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v151-v160/apolloconfigdb-v151-v160.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v151-v160/apolloconfigdb-v151-v160.sql index 1bc7803d692..315920637ef 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v151-v160/apolloconfigdb-v151-v160.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v151-v160/apolloconfigdb-v151-v160.sql @@ -32,4 +32,6 @@ CREATE TABLE `AccessKey` ( PRIMARY KEY (`Id`), KEY `AppId` (`AppId`(191)), KEY `DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloconfigdb-v170-v180.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloconfigdb-v170-v180.sql index 584530298ca..cc085536d50 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloconfigdb-v170-v180.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloconfigdb-v170-v180.sql @@ -25,3 +25,5 @@ alter table `GrayReleaseRule` change AppId AppId varchar(64) NOT NULL DEFAULT ' alter table `Instance` change AppId AppId varchar(64) NOT NULL DEFAULT 'default' COMMENT 'app id'; alter table `InstanceConfig` change ConfigAppId ConfigAppId varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id'; alter table `ReleaseHistory` change AppId AppId varchar(64) NOT NULL DEFAULT 'default' COMMENT 'app id'; + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloportaldb-v170-v180.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloportaldb-v170-v180.sql index c3bd8d1a5dc..ffa769906b3 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloportaldb-v170-v180.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v170-v180/apolloportaldb-v170-v180.sql @@ -20,3 +20,5 @@ -- ${gists.useDatabase} alter table `AppNamespace` change AppId AppId varchar(64) NOT NULL DEFAULT 'default' COMMENT 'app id'; + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloconfigdb-v180-v190.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloconfigdb-v180-v190.sql index 9a5272ce951..ec6abbc0220 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloconfigdb-v180-v190.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloconfigdb-v180-v190.sql @@ -70,3 +70,5 @@ ALTER TABLE `ServerConfig` ALTER TABLE `AccessKey` MODIFY COLUMN `DataChange_CreatedBy` VARCHAR(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', MODIFY COLUMN `DataChange_LastModifiedBy` VARCHAR(64) DEFAULT '' COMMENT '最后修改人邮箱前缀'; + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloportaldb-v180-v190.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloportaldb-v180-v190.sql index bc6be1f0bf9..95dd8a21f9e 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloportaldb-v180-v190.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v180-v190/apolloportaldb-v180-v190.sql @@ -98,3 +98,5 @@ CREATE TABLE SPRING_SESSION_ATTRIBUTES ( CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200-after.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200-after.sql index 2ef8fae247a..9ae64ef85bb 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200-after.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200-after.sql @@ -84,3 +84,5 @@ ALTER TABLE `ServerConfig` -- End:Delete temporarily created indexes ALTER TABLE `Commit` DROP INDEX `idx_IsDeleted_DeletedAt`; ALTER TABLE `Release` DROP INDEX `idx_IsDeleted_DeletedAt`; + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200.sql index f9a21a7b99f..323afe7486a 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloconfigdb-v190-v200.sql @@ -58,3 +58,5 @@ ALTER TABLE `ServerConfig` ALTER TABLE `AccessKey` ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200-after.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200-after.sql index c31ef4ed444..7b05e5e115b 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200-after.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200-after.sql @@ -79,3 +79,5 @@ ALTER TABLE `UserRole` ALTER TABLE `Users` ADD UNIQUE INDEX `UK_Username` (`Username`); + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200.sql index c6e6ab23d40..d521cf25a53 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v190-v200/apolloportaldb-v190-v200.sql @@ -50,4 +50,6 @@ ALTER TABLE `ServerConfig` ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; ALTER TABLE `UserRole` - ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; \ No newline at end of file + ADD COLUMN `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds' AFTER `IsDeleted`; + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v200-v210/apolloconfigdb-v200-v210.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v200-v210/apolloconfigdb-v200-v210.sql index 4140930fc1d..47bfa07ce82 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v200-v210/apolloconfigdb-v200-v210.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v200-v210/apolloconfigdb-v200-v210.sql @@ -36,4 +36,6 @@ CREATE TABLE `ServiceRegistry` ( PRIMARY KEY (`Id`), UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; \ No newline at end of file +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloconfigdb-v210-v220.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloconfigdb-v210-v220.sql index c71be2bf0e7..78cc43b4cae 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloconfigdb-v210-v220.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloconfigdb-v210-v220.sql @@ -93,3 +93,5 @@ CREATE TABLE `AuditLogDataInfluence` ( KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), KEY `IX_EntityId` (`InfluenceEntityId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + +-- ${gists.autoGeneratedDeclaration} diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloportaldb-v210-v220.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloportaldb-v210-v220.sql index ff613cc5849..0175694efe1 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloportaldb-v210-v220.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v210-v220/apolloportaldb-v210-v220.sql @@ -79,3 +79,5 @@ CREATE TABLE `AuditLogDataInfluence` ( KEY `IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), KEY `IX_EntityId` (`InfluenceEntityId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='审计日志数据变动表'; + +-- ${gists.autoGeneratedDeclaration} From c8b376504721f0614cd4f5a99b16ac6fd28b9955 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 26 Jan 2024 22:55:44 +0800 Subject: [PATCH 51/59] sql convert --- .../sql/converter/ApolloH2ConverterUtil.java | 16 +- .../profiles/h2-default/apolloconfigdb.sql | 456 +++++++++--------- .../profiles/h2-default/apolloportaldb.sql | 336 ++++++------- .../v220-v230/apolloconfigdb-v220-v230.sql | 4 +- 4 files changed, 405 insertions(+), 407 deletions(-) diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java index 59ba0dd1b30..cb79aed09d9 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java @@ -59,7 +59,7 @@ public static void convert(SqlTemplate sqlTemplate, String targetSql, private static final Pattern OPERATION_TABLE_PATTERN = Pattern.compile( - "(?DROP|CREATE|ALTER)\\s+TABLE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?", + "(?DROP|CREATE|ALTER)\\s+TABLE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*", Pattern.CASE_INSENSITIVE); private static final Pattern CREATE_INDEX_ON_PATTERN = Pattern.compile( @@ -185,25 +185,25 @@ private static String convertAlterTable(String convertedText, SqlStatement sqlSt } private static final Pattern ADD_COLUMN_PATTERN = Pattern.compile( - "ADD\\s+COLUMN\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + "\\s*ADD\\s+COLUMN\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", Pattern.CASE_INSENSITIVE); private static final Pattern MODIFY_COLUMN_PATTERN = Pattern.compile( - "MODIFY\\s+COLUMN\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + "\\s*MODIFY\\s+COLUMN\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", Pattern.CASE_INSENSITIVE); private static final Pattern CHANGE_PATTERN = Pattern.compile( - "CHANGE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + "\\s*CHANGE\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", Pattern.CASE_INSENSITIVE); private static final Pattern DROP_COLUMN_PATTERN = Pattern.compile( - "DROP\\s+(COLUMN\\s+)?(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", + "\\s*DROP\\s+(COLUMN\\s+)?(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", Pattern.CASE_INSENSITIVE); private static final Pattern ADD_KEY_PATTERN = Pattern.compile( - "ADD\\s+(?(UNIQUE\\s+)?KEY)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + "\\s*ADD\\s+(?(UNIQUE\\s+)?KEY)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", Pattern.CASE_INSENSITIVE); private static final Pattern ADD_INDEX_PATTERN = Pattern.compile( - "ADD\\s+(?(UNIQUE\\s+)?INDEX)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", + "\\s*ADD\\s+(?(UNIQUE\\s+)?INDEX)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", Pattern.CASE_INSENSITIVE); private static final Pattern DROP_INDEX_PATTERN = Pattern.compile( - "DROP\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", Pattern.CASE_INSENSITIVE); + "\\s*DROP\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", Pattern.CASE_INSENSITIVE); private static String convertAlterTableMulti(String convertedText, SqlStatement sqlStatement, String tableName) { diff --git a/scripts/sql/profiles/h2-default/apolloconfigdb.sql b/scripts/sql/profiles/h2-default/apolloconfigdb.sql index 7cf19950ab4..8a24f1c82c9 100644 --- a/scripts/sql/profiles/h2-default/apolloconfigdb.sql +++ b/scripts/sql/profiles/h2-default/apolloconfigdb.sql @@ -42,24 +42,24 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common CREATE TABLE `App` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `AppId` varchar(64) NOT NULL DEFAULT 'default' , - `Name` varchar(500) NOT NULL DEFAULT 'default' , - `OrgId` varchar(32) NOT NULL DEFAULT 'default' , - `OrgName` varchar(64) NOT NULL DEFAULT 'default' , - `OwnerName` varchar(500) NOT NULL DEFAULT 'default' , - `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `App_UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), KEY `App_DataChange_LastTime` (`DataChange_LastTime`), KEY `App_IX_Name` (`Name`) -) ; +) COMMENT='应用表'; @@ -68,23 +68,23 @@ CREATE TABLE `App` ( CREATE TABLE `AppNamespace` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `Name` varchar(32) NOT NULL DEFAULT '' , - `AppId` varchar(64) NOT NULL DEFAULT '' , - `Format` varchar(32) NOT NULL DEFAULT 'properties' , - `IsPublic` boolean NOT NULL DEFAULT FALSE , - `Comment` varchar(64) NOT NULL DEFAULT '' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` boolean NOT NULL DEFAULT FALSE COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `AppNamespace_UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), KEY `AppNamespace_Name_AppId` (`Name`,`AppId`), KEY `AppNamespace_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='应用namespace定义'; @@ -93,20 +93,20 @@ CREATE TABLE `AppNamespace` ( CREATE TABLE `Audit` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `EntityName` varchar(50) NOT NULL DEFAULT 'default' , - `EntityId` int(10) unsigned DEFAULT NULL , - `OpName` varchar(50) NOT NULL DEFAULT 'default' , - `Comment` varchar(500) DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID', + `OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), KEY `Audit_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='日志审计表'; @@ -115,22 +115,22 @@ CREATE TABLE `Audit` ( CREATE TABLE `Cluster` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `Name` varchar(32) NOT NULL DEFAULT '' , - `AppId` varchar(64) NOT NULL DEFAULT '' , - `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' , - `Comment` varchar(64) DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id', + `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', + `Comment` varchar(64) DEFAULT NULL COMMENT '备注', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `Cluster_UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), KEY `Cluster_IX_ParentClusterId` (`ParentClusterId`), KEY `Cluster_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='集群'; @@ -139,48 +139,48 @@ CREATE TABLE `Cluster` ( CREATE TABLE `Commit` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `ChangeSets` longtext NOT NULL , - `AppId` varchar(64) NOT NULL DEFAULT 'default' , - `ClusterName` varchar(500) NOT NULL DEFAULT 'default' , - `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' , - `Comment` varchar(500) DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `ChangeSets` longtext NOT NULL COMMENT '修改变更集', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), KEY `Commit_DataChange_LastTime` (`DataChange_LastTime`), KEY `Commit_AppId` (`AppId`), KEY `Commit_ClusterName` (`ClusterName`), KEY `Commit_NamespaceName` (`NamespaceName`) -) ; +) COMMENT='commit 历史表'; -- Dump of table grayreleaserule -- ------------------------------------------------------------ CREATE TABLE `GrayReleaseRule` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `AppId` varchar(64) NOT NULL DEFAULT 'default' , - `ClusterName` varchar(32) NOT NULL DEFAULT 'default' , - `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' , - `BranchName` varchar(32) NOT NULL DEFAULT 'default' , - `Rules` varchar(16000) DEFAULT '[]' , - `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' , - `BranchStatus` tinyint(2) DEFAULT '1' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name', + `Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release', + `BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), KEY `GrayReleaseRule_DataChange_LastTime` (`DataChange_LastTime`), KEY `GrayReleaseRule_IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`) -) ; +) COMMENT='灰度规则表'; -- Dump of table instance @@ -188,18 +188,18 @@ CREATE TABLE `GrayReleaseRule` ( CREATE TABLE `Instance` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `AppId` varchar(64) NOT NULL DEFAULT 'default' , - `ClusterName` varchar(32) NOT NULL DEFAULT 'default' , - `DataCenter` varchar(64) NOT NULL DEFAULT 'default' , - `Ip` varchar(32) NOT NULL DEFAULT '' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name', + `Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `Instance_IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`), KEY `Instance_IX_IP` (`Ip`), KEY `Instance_IX_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='使用配置的应用实例'; @@ -208,21 +208,21 @@ CREATE TABLE `Instance` ( CREATE TABLE `InstanceConfig` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `InstanceId` int(11) unsigned DEFAULT NULL , - `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' , - `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' , - `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' , - `ReleaseKey` varchar(64) NOT NULL DEFAULT '' , - `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id', + `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id', + `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name', + `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `InstanceConfig_IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), KEY `InstanceConfig_IX_ReleaseKey` (`ReleaseKey`), KEY `InstanceConfig_IX_DataChange_LastTime` (`DataChange_LastTime`), KEY `InstanceConfig_IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) -) ; +) COMMENT='应用实例的配置信息'; @@ -231,23 +231,23 @@ CREATE TABLE `InstanceConfig` ( CREATE TABLE `Item` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' , - `Key` varchar(128) NOT NULL DEFAULT 'default' , - `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' , - `Value` longtext NOT NULL , - `Comment` varchar(1024) DEFAULT '' , - `LineNum` int(10) unsigned DEFAULT '0' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '配置项类型,0: String,1: Number,2: Boolean,3: JSON', + `Value` longtext NOT NULL COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), KEY `Item_IX_GroupId` (`NamespaceId`), KEY `Item_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='配置项目'; @@ -256,21 +256,21 @@ CREATE TABLE `Item` ( CREATE TABLE `Namespace` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `AppId` varchar(64) NOT NULL DEFAULT 'default' , - `ClusterName` varchar(500) NOT NULL DEFAULT 'default' , - `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `Namespace_UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`,`NamespaceName`,`DeletedAt`), KEY `Namespace_DataChange_LastTime` (`DataChange_LastTime`), KEY `Namespace_IX_NamespaceName` (`NamespaceName`) -) ; +) COMMENT='命名空间'; @@ -279,18 +279,18 @@ CREATE TABLE `Namespace` ( CREATE TABLE `NamespaceLock` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , - `IsDeleted` boolean DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `IsDeleted` boolean DEFAULT FALSE COMMENT '软删除', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', PRIMARY KEY (`Id`), UNIQUE KEY `NamespaceLock_UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`), KEY `NamespaceLock_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='namespace的编辑锁'; @@ -299,26 +299,26 @@ CREATE TABLE `NamespaceLock` ( CREATE TABLE `Release` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `ReleaseKey` varchar(64) NOT NULL DEFAULT '' , - `Name` varchar(64) NOT NULL DEFAULT 'default' , - `Comment` varchar(256) DEFAULT NULL , - `AppId` varchar(64) NOT NULL DEFAULT 'default' , - `ClusterName` varchar(500) NOT NULL DEFAULT 'default' , - `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' , - `Configurations` longtext NOT NULL , - `IsAbandoned` boolean NOT NULL DEFAULT FALSE , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字', + `Comment` varchar(256) DEFAULT NULL COMMENT '发布说明', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Configurations` longtext NOT NULL COMMENT '发布配置', + `IsAbandoned` boolean NOT NULL DEFAULT FALSE COMMENT '是否废弃', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `Release_UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`), KEY `Release_AppId_ClusterName_GroupName` (`AppId`,`ClusterName`,`NamespaceName`), KEY `Release_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='发布'; -- Dump of table releasehistory @@ -326,27 +326,27 @@ CREATE TABLE `Release` ( CREATE TABLE `ReleaseHistory` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `AppId` varchar(64) NOT NULL DEFAULT 'default' , - `ClusterName` varchar(32) NOT NULL DEFAULT 'default' , - `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' , - `BranchName` varchar(32) NOT NULL DEFAULT 'default' , - `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' , - `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' , - `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' , - `OperationContext` longtext NOT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id', + `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId', + `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度', + `OperationContext` longtext NOT NULL COMMENT '发布上下文信息', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), KEY `ReleaseHistory_IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), KEY `ReleaseHistory_IX_ReleaseId` (`ReleaseId`), KEY `ReleaseHistory_IX_DataChange_LastTime` (`DataChange_LastTime`), KEY `ReleaseHistory_IX_PreviousReleaseId` (`PreviousReleaseId`) -) ; +) COMMENT='发布历史'; -- Dump of table releasemessage @@ -354,13 +354,13 @@ CREATE TABLE `ReleaseHistory` ( CREATE TABLE `ReleaseMessage` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `Message` varchar(1024) NOT NULL DEFAULT '' , - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), KEY `ReleaseMessage_DataChange_LastTime` (`DataChange_LastTime`), KEY `ReleaseMessage_IX_Message` (`Message`) -) ; +) COMMENT='发布消息'; @@ -369,41 +369,41 @@ CREATE TABLE `ReleaseMessage` ( CREATE TABLE `ServerConfig` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `Key` varchar(64) NOT NULL DEFAULT 'default' , - `Cluster` varchar(32) NOT NULL DEFAULT 'default' , - `Value` varchar(2048) NOT NULL DEFAULT 'default' , - `Comment` varchar(1024) DEFAULT '' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `ServerConfig_UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`), KEY `ServerConfig_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='配置服务自身配置'; -- Dump of table accesskey -- ------------------------------------------------------------ CREATE TABLE `AccessKey` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `AppId` varchar(64) NOT NULL DEFAULT 'default' , - `Secret` varchar(128) NOT NULL DEFAULT '' , - `IsEnabled` boolean NOT NULL DEFAULT FALSE , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret', + `IsEnabled` boolean NOT NULL DEFAULT FALSE COMMENT '1: enabled, 0: disabled', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `AccessKey_UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`), KEY `AccessKey_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='访问密钥'; -- Dump of table serviceregistry @@ -411,68 +411,68 @@ CREATE TABLE `AccessKey` ( CREATE TABLE `ServiceRegistry` ( - `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT , - `ServiceName` VARCHAR(64) NOT NULL , - `Uri` VARCHAR(64) NOT NULL , - `Cluster` VARCHAR(64) NOT NULL , - `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' , - `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', + `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='注册中心'; -- Dump of table AuditLog -- ------------------------------------------------------------ CREATE TABLE `AuditLog` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `TraceId` varchar(32) NOT NULL DEFAULT '' , - `SpanId` varchar(32) NOT NULL DEFAULT '' , - `ParentSpanId` varchar(32) DEFAULT NULL , - `FollowsFromSpanId` varchar(32) DEFAULT NULL , - `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' , - `OpType` varchar(50) NOT NULL DEFAULT 'default' , - `OpName` varchar(150) NOT NULL DEFAULT 'default' , - `Description` varchar(200) DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) DEFAULT NULL , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), KEY `AuditLog_IX_TraceId` (`TraceId`), KEY `AuditLog_IX_OpName` (`OpName`), KEY `AuditLog_IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), KEY `AuditLog_IX_Operator` (`Operator`) -) ; +) COMMENT='审计日志表'; -- Dump of table AuditLogDataInfluence -- ------------------------------------------------------------ CREATE TABLE `AuditLogDataInfluence` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `SpanId` char(32) NOT NULL DEFAULT '' , - `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' , - `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' , - `FieldName` varchar(50) DEFAULT NULL , - `FieldOldValue` varchar(500) DEFAULT NULL , - `FieldNewValue` varchar(500) DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) DEFAULT NULL , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), KEY `AuditLogDataInfluence_IX_SpanId` (`SpanId`), KEY `AuditLogDataInfluence_IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), KEY `AuditLogDataInfluence_IX_EntityId` (`InfluenceEntityId`) -) ; +) COMMENT='审计日志数据变动表'; -- Config -- ------------------------------------------------------------ diff --git a/scripts/sql/profiles/h2-default/apolloportaldb.sql b/scripts/sql/profiles/h2-default/apolloportaldb.sql index fc94a65cbf7..e1be67d3d6e 100644 --- a/scripts/sql/profiles/h2-default/apolloportaldb.sql +++ b/scripts/sql/profiles/h2-default/apolloportaldb.sql @@ -42,24 +42,24 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common CREATE TABLE `App` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `AppId` varchar(64) NOT NULL DEFAULT 'default' , - `Name` varchar(500) NOT NULL DEFAULT 'default' , - `OrgId` varchar(32) NOT NULL DEFAULT 'default' , - `OrgName` varchar(64) NOT NULL DEFAULT 'default' , - `OwnerName` varchar(500) NOT NULL DEFAULT 'default' , - `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `App_UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), KEY `App_DataChange_LastTime` (`DataChange_LastTime`), KEY `App_IX_Name` (`Name`) -) ; +) COMMENT='应用表'; @@ -68,23 +68,23 @@ CREATE TABLE `App` ( CREATE TABLE `AppNamespace` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `Name` varchar(32) NOT NULL DEFAULT '' , - `AppId` varchar(64) NOT NULL DEFAULT '' , - `Format` varchar(32) NOT NULL DEFAULT 'properties' , - `IsPublic` boolean NOT NULL DEFAULT FALSE , - `Comment` varchar(64) NOT NULL DEFAULT '' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` boolean NOT NULL DEFAULT FALSE COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `AppNamespace_UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), KEY `AppNamespace_Name_AppId` (`Name`,`AppId`), KEY `AppNamespace_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='应用namespace定义'; @@ -93,23 +93,23 @@ CREATE TABLE `AppNamespace` ( CREATE TABLE `Consumer` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `AppId` varchar(64) NOT NULL DEFAULT 'default' , - `Name` varchar(500) NOT NULL DEFAULT 'default' , - `OrgId` varchar(32) NOT NULL DEFAULT 'default' , - `OrgName` varchar(64) NOT NULL DEFAULT 'default' , - `OwnerName` varchar(500) NOT NULL DEFAULT 'default' , - `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `Consumer_UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), KEY `Consumer_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='开放API消费者'; @@ -118,16 +118,16 @@ CREATE TABLE `Consumer` ( CREATE TABLE `ConsumerAudit` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `ConsumerId` int(11) unsigned DEFAULT NULL , - `Uri` varchar(1024) NOT NULL DEFAULT '' , - `Method` varchar(16) NOT NULL DEFAULT '' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri', + `Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), KEY `ConsumerAudit_IX_DataChange_LastTime` (`DataChange_LastTime`), KEY `ConsumerAudit_IX_ConsumerId` (`ConsumerId`) -) ; +) COMMENT='consumer审计表'; @@ -136,20 +136,20 @@ CREATE TABLE `ConsumerAudit` ( CREATE TABLE `ConsumerRole` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `ConsumerId` int(11) unsigned DEFAULT NULL , - `RoleId` int(10) unsigned DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `ConsumerRole_UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`), KEY `ConsumerRole_IX_DataChange_LastTime` (`DataChange_LastTime`), KEY `ConsumerRole_IX_RoleId` (`RoleId`) -) ; +) COMMENT='consumer和role的绑定表'; @@ -158,60 +158,60 @@ CREATE TABLE `ConsumerRole` ( CREATE TABLE `ConsumerToken` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `ConsumerId` int(11) unsigned DEFAULT NULL , - `Token` varchar(128) NOT NULL DEFAULT '' , - `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId', + `Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token', + `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `ConsumerToken_UK_Token_DeletedAt` (`Token`,`DeletedAt`), KEY `ConsumerToken_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='consumer token表'; -- Dump of table favorite -- ------------------------------------------------------------ CREATE TABLE `Favorite` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `UserId` varchar(32) NOT NULL DEFAULT 'default' , - `AppId` varchar(64) NOT NULL DEFAULT 'default' , - `Position` int(32) NOT NULL DEFAULT '10000' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `Favorite_UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`), KEY `Favorite_AppId` (`AppId`), KEY `Favorite_DataChange_LastTime` (`DataChange_LastTime`) -) AUTO_INCREMENT=23 ; +) AUTO_INCREMENT=23 COMMENT='应用收藏表'; -- Dump of table permission -- ------------------------------------------------------------ CREATE TABLE `Permission` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `PermissionType` varchar(32) NOT NULL DEFAULT '' , - `TargetId` varchar(256) NOT NULL DEFAULT '' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型', + `TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `Permission_UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`), KEY `Permission_IX_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='permission表'; @@ -220,18 +220,18 @@ CREATE TABLE `Permission` ( CREATE TABLE `Role` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `RoleName` varchar(256) NOT NULL DEFAULT '' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `Role_UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`), KEY `Role_IX_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='角色表'; @@ -240,20 +240,20 @@ CREATE TABLE `Role` ( CREATE TABLE `RolePermission` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `RoleId` int(10) unsigned DEFAULT NULL , - `PermissionId` int(10) unsigned DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `RolePermission_UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`), KEY `RolePermission_IX_DataChange_LastTime` (`DataChange_LastTime`), KEY `RolePermission_IX_PermissionId` (`PermissionId`) -) ; +) COMMENT='角色和权限的绑定表'; @@ -262,20 +262,20 @@ CREATE TABLE `RolePermission` ( CREATE TABLE `ServerConfig` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `Key` varchar(64) NOT NULL DEFAULT 'default' , - `Value` varchar(2048) NOT NULL DEFAULT 'default' , - `Comment` varchar(1024) DEFAULT '' , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `ServerConfig_UK_Key_DeletedAt` (`Key`,`DeletedAt`), KEY `ServerConfig_DataChange_LastTime` (`DataChange_LastTime`) -) ; +) COMMENT='配置服务自身配置'; @@ -284,35 +284,35 @@ CREATE TABLE `ServerConfig` ( CREATE TABLE `UserRole` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , - `UserId` varchar(128) DEFAULT '' , - `RoleId` int(10) unsigned DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), UNIQUE KEY `UserRole_UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`), KEY `UserRole_IX_DataChange_LastTime` (`DataChange_LastTime`), KEY `UserRole_IX_RoleId` (`RoleId`) -) ; +) COMMENT='用户和role的绑定表'; -- Dump of table Users -- ------------------------------------------------------------ CREATE TABLE `Users` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `Username` varchar(64) NOT NULL DEFAULT 'default' , - `Password` varchar(512) NOT NULL DEFAULT 'default' , - `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' , - `Email` varchar(64) NOT NULL DEFAULT 'default' , - `Enabled` tinyint(4) DEFAULT NULL , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户', + `Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码', + `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称', + `Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址', + `Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效', PRIMARY KEY (`Id`), UNIQUE KEY `Users_UK_Username` (`Username`) -) ; +) COMMENT='用户表'; -- Dump of table Authorities @@ -320,7 +320,7 @@ CREATE TABLE `Users` ( CREATE TABLE `Authorities` ( - `Id` int(11) unsigned NOT NULL AUTO_INCREMENT , + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', `Username` varchar(64) NOT NULL, `Authority` varchar(50) NOT NULL, PRIMARY KEY (`Id`) @@ -362,51 +362,51 @@ CREATE TABLE `SPRING_SESSION_ATTRIBUTES` ( CREATE TABLE `AuditLog` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `TraceId` varchar(32) NOT NULL DEFAULT '' , - `SpanId` varchar(32) NOT NULL DEFAULT '' , - `ParentSpanId` varchar(32) DEFAULT NULL , - `FollowsFromSpanId` varchar(32) DEFAULT NULL , - `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' , - `OpType` varchar(50) NOT NULL DEFAULT 'default' , - `OpName` varchar(150) NOT NULL DEFAULT 'default' , - `Description` varchar(200) DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) DEFAULT NULL , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `TraceId` varchar(32) NOT NULL DEFAULT '' COMMENT '链路全局唯一ID', + `SpanId` varchar(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `ParentSpanId` varchar(32) DEFAULT NULL COMMENT '父跨度ID', + `FollowsFromSpanId` varchar(32) DEFAULT NULL COMMENT '上一个兄弟跨度ID', + `Operator` varchar(64) NOT NULL DEFAULT 'anonymous' COMMENT '操作人', + `OpType` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `OpName` varchar(150) NOT NULL DEFAULT 'default' COMMENT '操作名称', + `Description` varchar(200) DEFAULT NULL COMMENT '备注', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), KEY `AuditLog_IX_TraceId` (`TraceId`), KEY `AuditLog_IX_OpName` (`OpName`), KEY `AuditLog_IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), KEY `AuditLog_IX_Operator` (`Operator`) -) ; +) COMMENT='审计日志表'; -- Dump of table AuditLogDataInfluence -- ------------------------------------------------------------ CREATE TABLE `AuditLogDataInfluence` ( - `Id` int(10) unsigned NOT NULL AUTO_INCREMENT , - `SpanId` char(32) NOT NULL DEFAULT '' , - `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' , - `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' , - `FieldName` varchar(50) DEFAULT NULL , - `FieldOldValue` varchar(500) DEFAULT NULL , - `FieldNewValue` varchar(500) DEFAULT NULL , - `IsDeleted` boolean NOT NULL DEFAULT FALSE , - `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' , - `DataChange_CreatedBy` varchar(64) DEFAULT NULL , - `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , - `DataChange_LastModifiedBy` varchar(64) DEFAULT '' , - `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `SpanId` char(32) NOT NULL DEFAULT '' COMMENT '跨度ID', + `InfluenceEntityId` varchar(50) NOT NULL DEFAULT '0' COMMENT '记录ID', + `InfluenceEntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `FieldName` varchar(50) DEFAULT NULL COMMENT '字段名称', + `FieldOldValue` varchar(500) DEFAULT NULL COMMENT '字段旧值', + `FieldNewValue` varchar(500) DEFAULT NULL COMMENT '字段新值', + `IsDeleted` boolean NOT NULL DEFAULT FALSE COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) DEFAULT NULL COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', PRIMARY KEY (`Id`), KEY `AuditLogDataInfluence_IX_SpanId` (`SpanId`), KEY `AuditLogDataInfluence_IX_DataChange_CreatedTime` (`DataChange_CreatedTime`), KEY `AuditLogDataInfluence_IX_EntityId` (`InfluenceEntityId`) -) ; +) COMMENT='审计日志数据变动表'; -- Config -- ------------------------------------------------------------ diff --git a/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql index 346494053fb..1af54d15863 100644 --- a/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -30,9 +30,7 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; -- - -ALTER TABLE `Cluster` - ADD COLUMN `Comment` varchar(64) DEFAULT NULL ; +ALTER TABLE `Cluster` ADD COLUMN `Comment` varchar(64) DEFAULT NULL COMMENT '备注'; -- -- =============================================================================== From 08ffbb7c1850d400308fbeb60ee1d00d7ada319a Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 26 Jan 2024 23:18:20 +0800 Subject: [PATCH 52/59] fix sql-convert --- .../build/sql/converter/ApolloH2ConverterUtil.java | 14 +++++++------- .../sql/converter/ApolloSqlConverterH2Test.java | 1 + .../delta/v220-v230/apolloconfigdb-v220-v230.sql | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java index cb79aed09d9..e00a5c465b1 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java @@ -210,42 +210,42 @@ private static String convertAlterTableMulti(String convertedText, SqlStatement Matcher addColumnMatcher = ADD_COLUMN_PATTERN.matcher(convertedText); if (addColumnMatcher.find()) { convertedText = addColumnMatcher.replaceAll( - "ALTER TABLE `" + tableName + "` ADD COLUMN `${columnName}`${subStatement};"); + "\nALTER TABLE `" + tableName + "` ADD COLUMN `${columnName}`${subStatement};"); } Matcher modifyColumnMatcher = MODIFY_COLUMN_PATTERN.matcher(convertedText); if (modifyColumnMatcher.find()) { convertedText = modifyColumnMatcher.replaceAll( - "ALTER TABLE `" + tableName + "` MODIFY COLUMN `${columnName}`${subStatement};"); + "\nALTER TABLE `" + tableName + "` MODIFY COLUMN `${columnName}`${subStatement};"); } Matcher changeMatcher = CHANGE_PATTERN.matcher(convertedText); if (changeMatcher.find()) { - convertedText = changeMatcher.replaceAll("ALTER TABLE `" + tableName + convertedText = changeMatcher.replaceAll("\nALTER TABLE `" + tableName + "` CHANGE `${oldColumnName}` `${newColumnName}` ${subStatement};"); } Matcher dropColumnMatcher = DROP_COLUMN_PATTERN.matcher(convertedText); if (dropColumnMatcher.find()) { convertedText = dropColumnMatcher.replaceAll( - "ALTER TABLE `" + tableName + "` DROP `${columnName}`;"); + "\nALTER TABLE `" + tableName + "` DROP `${columnName}`;"); } Matcher addKeyMatcher = ADD_KEY_PATTERN.matcher(convertedText); if (addKeyMatcher.find()) { convertedText = addKeyMatcher.replaceAll( - "ALTER TABLE `" + tableName + "` ADD ${indexType} `" + tableName + "\nALTER TABLE `" + tableName + "` ADD ${indexType} `" + tableName + "_${indexName}` ${subStatement};"); convertedText = removePrefixIndex(convertedText); } Matcher addIndexMatcher = ADD_INDEX_PATTERN.matcher(convertedText); if (addIndexMatcher.find()) { convertedText = addIndexMatcher.replaceAll( - "ALTER TABLE `" + tableName + "` ADD ${indexType} `" + tableName + "\nALTER TABLE `" + tableName + "` ADD ${indexType} `" + tableName + "_${indexName}` ${subStatement};"); convertedText = removePrefixIndex(convertedText); } Matcher dropIndexMatcher = DROP_INDEX_PATTERN.matcher(convertedText); if (dropIndexMatcher.find()) { convertedText = dropIndexMatcher.replaceAll( - "ALTER TABLE `" + tableName + "` DROP INDEX `" + tableName + "_${indexName}`;"); + "\nALTER TABLE `" + tableName + "` DROP INDEX `" + tableName + "_${indexName}`;"); } return convertedText; } diff --git a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java index 0dc1102ce2f..85276a0f4f0 100644 --- a/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java +++ b/apollo-build-sql-converter/src/test/java/com/ctrip/framework/apollo/build/sql/converter/ApolloSqlConverterH2Test.java @@ -36,6 +36,7 @@ void checkH2() { String srcDir = repositoryDir + "/scripts/sql/src"; String checkerParentDir = repositoryDir + "/apollo-build-sql-converter/target/scripts/sql/checker-h2"; + String testSrcDir = repositoryDir + "/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test"; String testCheckerParentDir = diff --git a/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql b/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql index 1af54d15863..ec703d5aa80 100644 --- a/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql +++ b/scripts/sql/profiles/h2-default/delta/v220-v230/apolloconfigdb-v220-v230.sql @@ -30,6 +30,7 @@ CREATE ALIAS IF NOT EXISTS UNIX_TIMESTAMP FOR "com.ctrip.framework.apollo.common.jpa.H2Function.unixTimestamp"; -- + ALTER TABLE `Cluster` ADD COLUMN `Comment` varchar(64) DEFAULT NULL COMMENT '备注'; -- From b1e370af4b0e96a7733c3523b60f12a192cf4348 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 26 Jan 2024 23:40:55 +0800 Subject: [PATCH 53/59] CHANGES.md --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index cccd30b1b50..3029a1fa0c4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,7 @@ Apollo 2.3.0 * [Fix circular references on LdapAutoConfiguration](https://github.com/apolloconfig/apollo/pull/5055) * [Add comment for clusters and UI display](https://github.com/apolloconfig/apollo/pull/5072) * [Fix the issue that the length of private namespaces are mis-calculated](https://github.com/apolloconfig/apollo/pull/5078) +* [apollo assembly optimization](https://github.com/apolloconfig/apollo/pull/5035) ------------------ From 768c250793505ec7c3b9a202a9e3fb187a777827 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 26 Jan 2024 23:50:40 +0800 Subject: [PATCH 54/59] fix copyright --- .../v000-v010/apolloconfigdb-v000-v010-after.sql | 16 ++++++++++++++++ .../apolloconfigdb-v000-v010-before.sql | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-after.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-after.sql index c804ef63fb9..000eaf8db3f 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-after.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-after.sql @@ -1,3 +1,19 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; diff --git a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-before.sql b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-before.sql index c804ef63fb9..000eaf8db3f 100644 --- a/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-before.sql +++ b/apollo-build-sql-converter/src/test/resources/META-INF/sql/h2-test/delta/v000-v010/apolloconfigdb-v000-v010-before.sql @@ -1,3 +1,19 @@ +-- +-- Copyright 2024 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; From 4d72047391015e91e6055124f2807d3cf6359957 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 2 Feb 2024 19:49:47 +0800 Subject: [PATCH 55/59] clean logger --- apollo-assembly/src/main/resources/logback.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/apollo-assembly/src/main/resources/logback.xml b/apollo-assembly/src/main/resources/logback.xml index cc4c4146525..e724e3c8f46 100644 --- a/apollo-assembly/src/main/resources/logback.xml +++ b/apollo-assembly/src/main/resources/logback.xml @@ -45,5 +45,4 @@ - From 4941f4fb93fe8750dc2d00de2c11930a55142a9e Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 2 Feb 2024 20:01:17 +0800 Subject: [PATCH 56/59] fix order --- .../apollo/adminservice/AdminServiceAssemblyConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyConfiguration.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyConfiguration.java index cc1ccdf897a..7fae4f487b6 100644 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyConfiguration.java +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyConfiguration.java @@ -26,7 +26,7 @@ @Configuration public class AdminServiceAssemblyConfiguration { - @Order(99) + @Order(100) @Configuration static class AdminServiceSecurityConfigurer extends WebSecurityConfigurerAdapter { From 06afabb3fc90741f61afcfc0073e604b498dca67 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 2 Feb 2024 20:09:53 +0800 Subject: [PATCH 57/59] fix h2 converter --- .../apollo/build/sql/converter/ApolloH2ConverterUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java index e00a5c465b1..3397b26bd8b 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java @@ -132,7 +132,7 @@ private static String convertTableConfig(String convertedText, SqlStatement sqlS } private static final Pattern INDEX_NAME_PATTERN = Pattern.compile( - "KEY\\s*(`)?(?[a-zA-Z0-9\\-_]+)(`)?", Pattern.CASE_INSENSITIVE); + "(KEY\\s*`|KEY\\s+)(?[a-zA-Z0-9\\-_]+)(`)?", Pattern.CASE_INSENSITIVE); private static String convertIndexWithTable(String convertedText, String tableName, SqlStatement sqlStatement) { @@ -140,7 +140,7 @@ private static String convertIndexWithTable(String convertedText, String tableNa StringJoiner joiner = new StringJoiner("\n"); for (String line : lines) { String convertedLine = line; - if (convertedLine.contains("KEY")) { + if (convertedLine.contains("KEY") || convertedLine.contains("key")) { // replace index name // KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) // -> From d68ed97e74f4cedc41d9c4d9003e6de313efe828 Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 2 Feb 2024 20:20:11 +0800 Subject: [PATCH 58/59] fix h2 converter v0.2 --- .../sql/converter/ApolloH2ConverterUtil.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java index 3397b26bd8b..dd4bbb8b47a 100644 --- a/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java +++ b/apollo-build-sql-converter/src/main/java/com/ctrip/framework/apollo/build/sql/converter/ApolloH2ConverterUtil.java @@ -132,7 +132,16 @@ private static String convertTableConfig(String convertedText, SqlStatement sqlS } private static final Pattern INDEX_NAME_PATTERN = Pattern.compile( - "(KEY\\s*`|KEY\\s+)(?[a-zA-Z0-9\\-_]+)(`)?", Pattern.CASE_INSENSITIVE); + // KEY `AppId_ClusterName_GroupName` + "(KEY\\s*`|KEY\\s+)(?[a-zA-Z0-9\\-_]+)(`)?\\s*" + // (`AppId`,`ClusterName`(191),`NamespaceName`(191)) + + "\\((?" + + "(`)?[a-zA-Z0-9\\-_]+(`)?\\s*(\\([0-9]+\\))?" + + "(," + + "(`)?[a-zA-Z0-9\\-_]+(`)?\\s*(\\([0-9]+\\))?" + + ")*" + + ")\\)", + Pattern.CASE_INSENSITIVE); private static String convertIndexWithTable(String convertedText, String tableName, SqlStatement sqlStatement) { @@ -147,7 +156,8 @@ private static String convertIndexWithTable(String convertedText, String tableNa // KEY `tableName_AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)) Matcher indexNameMatcher = INDEX_NAME_PATTERN.matcher(convertedLine); if (indexNameMatcher.find()) { - convertedLine = indexNameMatcher.replaceAll("KEY `" + tableName + "_${indexName}`"); + convertedLine = indexNameMatcher.replaceAll( + "KEY `" + tableName + "_${indexName}` (${indexColumns})"); } convertedLine = removePrefixIndex(convertedLine); } @@ -203,7 +213,8 @@ private static String convertAlterTable(String convertedText, SqlStatement sqlSt "\\s*ADD\\s+(?(UNIQUE\\s+)?INDEX)\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?(?.*)[,;]", Pattern.CASE_INSENSITIVE); private static final Pattern DROP_INDEX_PATTERN = Pattern.compile( - "\\s*DROP\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", Pattern.CASE_INSENSITIVE); + "\\s*DROP\\s+INDEX\\s+(`)?(?[a-zA-Z0-9\\-_]+)(`)?\\s*[,;]", + Pattern.CASE_INSENSITIVE); private static String convertAlterTableMulti(String convertedText, SqlStatement sqlStatement, String tableName) { From e8b44ee59f3cb9453d4b5f94da9cb0ef952b3b9c Mon Sep 17 00:00:00 2001 From: vdisk Date: Fri, 2 Feb 2024 21:56:21 +0800 Subject: [PATCH 59/59] fix order v0.2 --- .../apollo/adminservice/AdminServiceAssemblyConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyConfiguration.java b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyConfiguration.java index 7fae4f487b6..0c517375183 100644 --- a/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyConfiguration.java +++ b/apollo-adminservice/src/main/java/com/ctrip/framework/apollo/adminservice/AdminServiceAssemblyConfiguration.java @@ -26,7 +26,7 @@ @Configuration public class AdminServiceAssemblyConfiguration { - @Order(100) + @Order(101) @Configuration static class AdminServiceSecurityConfigurer extends WebSecurityConfigurerAdapter {