com.aoindustries.aoserv.client.MySQLDatabase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aoserv-client Show documentation
Show all versions of aoserv-client Show documentation
Java client for the AOServ Platform.
/*
* aoserv-client - Java client for the AOServ platform.
* Copyright (C) 2000-2013, 2014, 2015, 2016 AO Industries, Inc.
* [email protected]
* 7262 Bull Pen Cir
* Mobile, AL 36695
*
* This file is part of aoserv-client.
*
* aoserv-client is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* aoserv-client is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with aoserv-client. If not, see .
*/
package com.aoindustries.aoserv.client;
import com.aoindustries.io.CompressedDataInputStream;
import com.aoindustries.io.CompressedDataOutputStream;
import com.aoindustries.io.IoUtils;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.List;
/**
* A MySQLDatabase
corresponds to a unique MySQL table
* space on one server. The database name must be unique per server
* and, to aid in account portability, will typically be unique
* across the entire system.
*
* @see MySQLDBUser
*
* @author AO Industries, Inc.
*/
final public class MySQLDatabase extends CachedObjectIntegerKey implements Removable, Dumpable, JdbcProvider {
static final int
COLUMN_PKEY=0,
COLUMN_MYSQL_SERVER=2,
COLUMN_PACKAGE=3
;
static final String COLUMN_NAME_name = "name";
static final String COLUMN_MYSQL_SERVER_name = "mysql_server";
/**
* The classname of the JDBC driver used for the MySQLDatabase
.
*/
public static final String
REDHAT_JDBC_DRIVER="com.mysql.jdbc.Driver",
MANDRAKE_JDBC_DRIVER="com.mysql.jdbc.Driver",
CENTOS_JDBC_DRIVER="com.mysql.jdbc.Driver"
;
/**
* The URL for MySQL JDBC documentation.
*/
public static final String
REDHAT_JDBC_DOCUMENTATION_URL="https://dev.mysql.com/doc/connector-j/5.1/en/",
MANDRAKE_JDBC_DOCUMENTATION_URL="https://dev.mysql.com/doc/connector-j/5.1/en/",
CENTOS_JDBC_DOCUMENTATION_URL="https://dev.mysql.com/doc/connector-j/5.1/en/"
;
/**
* The longest name allowed for a MySQL database.
*/
public static final int MAX_DATABASE_NAME_LENGTH=64;
/**
* The root database for a mysql installation.
*/
public static final String MYSQL="mysql";
/**
* Special databases that are never removed.
*/
public static final String
INFORMATION_SCHEMA="information_schema",
PERFORMANCE_SCHEMA="performance_schema"
;
String name;
int mysql_server;
String packageName;
private AlertLevel maxCheckTableAlertLevel;
public int addMySQLServerUser(
MySQLServerUser msu,
boolean canSelect,
boolean canInsert,
boolean canUpdate,
boolean canDelete,
boolean canCreate,
boolean canDrop,
boolean canIndex,
boolean canAlter,
boolean canCreateTempTable,
boolean canLockTables,
boolean canCreateView,
boolean canShowView,
boolean canCreateRoutine,
boolean canAlterRoutine,
boolean canExecute,
boolean canEvent,
boolean canTrigger
) throws IOException, SQLException {
return table.connector.getMysqlDBUsers().addMySQLDBUser(
this,
msu,
canSelect,
canInsert,
canUpdate,
canDelete,
canCreate,
canDrop,
canIndex,
canAlter,
canCreateTempTable,
canLockTables,
canCreateView,
canShowView,
canCreateRoutine,
canAlterRoutine,
canExecute,
canEvent,
canTrigger
);
}
@Override
public void dump(PrintWriter out) throws IOException, SQLException {
dump((Writer)out);
}
public void dump(final Writer out) throws IOException, SQLException {
table.connector.requestUpdate(
false,
new AOServConnector.UpdateRequest() {
@Override
public void writeRequest(CompressedDataOutputStream masterOut) throws IOException {
masterOut.writeCompressedInt(AOServProtocol.CommandID.DUMP_MYSQL_DATABASE.ordinal());
masterOut.writeCompressedInt(pkey);
}
@Override
public void readResponse(CompressedDataInputStream masterIn) throws IOException, SQLException {
/*int code;
byte[] buff=BufferManager.getBytes();
try {
char[] chars=BufferManager.getChars();
try {
while((code=masterIn.readByte())==AOServProtocol.NEXT) {
int len=masterIn.readShort();
masterIn.readFully(buff, 0, len);
for(int c=0;c getMySQLDBUsers() throws IOException, SQLException {
return table.connector.getMysqlDBUsers().getMySQLDBUsers(this);
}
public List getMySQLServerUsers() throws IOException, SQLException {
return table.connector.getMysqlDBUsers().getMySQLServerUsers(this);
}
public String getName() {
return name;
}
public Package getPackage() throws SQLException, IOException {
Package obj=table.connector.getPackages().get(packageName);
if(obj==null) throw new SQLException("Unable to find Package: "+packageName);
return obj;
}
public MySQLServer getMySQLServer() throws SQLException, IOException {
MySQLServer obj=table.connector.getMysqlServers().get(mysql_server);
if(obj==null) throw new SQLException("Unable to find MySQLServer: "+mysql_server);
return obj;
}
public AlertLevel getMaxCheckTableAlertLevel() {
return maxCheckTableAlertLevel;
}
@Override
public SchemaTable.TableID getTableID() {
return SchemaTable.TableID.MYSQL_DATABASES;
}
@Override
public void init(ResultSet result) throws SQLException {
pkey=result.getInt(1);
name=result.getString(2);
mysql_server=result.getInt(3);
packageName=result.getString(4);
maxCheckTableAlertLevel = AlertLevel.valueOf(result.getString(5));
}
@Override
public void read(CompressedDataInputStream in) throws IOException {
pkey=in.readCompressedInt();
name=in.readUTF();
mysql_server=in.readCompressedInt();
packageName=in.readUTF().intern();
maxCheckTableAlertLevel = AlertLevel.valueOf(in.readCompressedUTF());
}
@Override
public List getCannotRemoveReasons() throws SQLException, IOException {
List reasons=new ArrayList<>();
if(name.equals(MYSQL)) reasons.add(new CannotRemoveReason<>("Not allowed to remove the MySQL database named "+MYSQL, this));
if(name.equals(INFORMATION_SCHEMA)) {
String version = getMySQLServer().getVersion().getVersion();
if(
version.startsWith(MySQLServer.VERSION_5_0_PREFIX)
|| version.startsWith(MySQLServer.VERSION_5_1_PREFIX)
|| version.startsWith(MySQLServer.VERSION_5_6_PREFIX)
) reasons.add(new CannotRemoveReason<>("Not allowed to remove the MySQL database named "+INFORMATION_SCHEMA, this));
}
if(name.equals(PERFORMANCE_SCHEMA)) {
String version = getMySQLServer().getVersion().getVersion();
if(
version.startsWith(MySQLServer.VERSION_5_6_PREFIX)
) reasons.add(new CannotRemoveReason<>("Not allowed to remove the MySQL database named "+PERFORMANCE_SCHEMA, this));
}
return reasons;
}
@Override
public void remove() throws IOException, SQLException {
table.connector.requestUpdateIL(
true,
AOServProtocol.CommandID.REMOVE,
SchemaTable.TableID.MYSQL_DATABASES,
pkey
);
}
@Override
String toStringImpl() {
return name;
}
@Override
public void write(CompressedDataOutputStream out, AOServProtocol.Version version) throws IOException {
out.writeCompressedInt(pkey);
out.writeUTF(name);
if(version.compareTo(AOServProtocol.Version.VERSION_1_4)<0) out.writeCompressedInt(-1);
else out.writeCompressedInt(mysql_server);
out.writeUTF(packageName);
if(version.compareTo(AOServProtocol.Version.VERSION_1_30)<=0) {
out.writeShort(0);
out.writeShort(7);
}
if(version.compareTo(AOServProtocol.Version.VERSION_1_74) >= 0) {
out.writeCompressedUTF(maxCheckTableAlertLevel.name());
}
}
public enum Engine {
CSV,
MyISAM,
InnoDB,
HEAP,
MEMORY,
PERFORMANCE_SCHEMA
}
public static class TableStatus {
public enum RowFormat {
Compact,
Dynamic,
Fixed
}
public enum Collation {
binary,
latin1_swedish_ci,
utf8_bin,
utf8_general_ci,
utf8_unicode_ci,
utf8mb4_unicode_ci,
utf8mb4_unicode_520_ci
}
private final String name;
private final Engine engine;
private final Integer version;
private final RowFormat rowFormat;
private final Long rows;
private final Long avgRowLength;
private final Long dataLength;
private final Long maxDataLength;
private final Long indexLength;
private final Long dataFree;
private final Long autoIncrement;
private final String createTime;
private final String updateTime;
private final String checkTime;
private final Collation collation;
private final String checksum;
private final String createOptions;
private final String comment;
public TableStatus(
String name,
Engine engine,
Integer version,
RowFormat rowFormat,
Long rows,
Long avgRowLength,
Long dataLength,
Long maxDataLength,
Long indexLength,
Long dataFree,
Long autoIncrement,
String createTime,
String updateTime,
String checkTime,
Collation collation,
String checksum,
String createOptions,
String comment
) {
this.name = name;
this.engine = engine;
this.version = version;
this.rowFormat = rowFormat;
this.rows = rows;
this.avgRowLength = avgRowLength;
this.dataLength = dataLength;
this.maxDataLength = maxDataLength;
this.indexLength = indexLength;
this.dataFree = dataFree;
this.autoIncrement = autoIncrement;
this.createTime = createTime;
this.updateTime = updateTime;
this.checkTime = checkTime;
this.collation = collation;
this.checksum = checksum;
this.createOptions = createOptions;
this.comment = comment;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @return the engine
*/
public Engine getEngine() {
return engine;
}
/**
* @return the version
*/
public Integer getVersion() {
return version;
}
/**
* @return the rowFormat
*/
public RowFormat getRowFormat() {
return rowFormat;
}
/**
* @return the rows
*/
public Long getRows() {
return rows;
}
/**
* @return the avgRowLength
*/
public Long getAvgRowLength() {
return avgRowLength;
}
/**
* @return the dataLength
*/
public Long getDataLength() {
return dataLength;
}
/**
* @return the maxDataLength
*/
public Long getMaxDataLength() {
return maxDataLength;
}
/**
* @return the indexLength
*/
public Long getIndexLength() {
return indexLength;
}
/**
* @return the dataFree
*/
public Long getDataFree() {
return dataFree;
}
/**
* @return the autoIncrement
*/
public Long getAutoIncrement() {
return autoIncrement;
}
/**
* @return the createTime
*/
public String getCreateTime() {
return createTime;
}
/**
* @return the updateTime
*/
public String getUpdateTime() {
return updateTime;
}
/**
* @return the checkTime
*/
public String getCheckTime() {
return checkTime;
}
/**
* @return the collation
*/
public Collation getCollation() {
return collation;
}
/**
* @return the checksum
*/
public String getChecksum() {
return checksum;
}
/**
* @return the createOptions
*/
public String getCreateOptions() {
return createOptions;
}
/**
* @return the comment
*/
public String getComment() {
return comment;
}
}
/**
* Gets the table status on the master server.
*/
public List getTableStatus() throws IOException, SQLException {
return getTableStatus(null);
}
/**
* Gets the table status on the master server or provided slave server.
*/
public List getTableStatus(final FailoverMySQLReplication mysqlSlave) throws IOException, SQLException {
return table.connector.requestResult(
true,
new AOServConnector.ResultRequest>() {
private List result;
@Override
public void writeRequest(CompressedDataOutputStream out) throws IOException {
out.writeCompressedInt(AOServProtocol.CommandID.GET_MYSQL_TABLE_STATUS.ordinal());
out.writeCompressedInt(pkey);
out.writeCompressedInt(mysqlSlave==null ? -1 : mysqlSlave.pkey);
}
@Override
public void readResponse(CompressedDataInputStream in) throws IOException, SQLException {
int code=in.readByte();
if(code==AOServProtocol.NEXT) {
int size = in.readCompressedInt();
List tableStatuses = new ArrayList<>(size);
for(int c=0;c afterRelease() {
return result;
}
}
);
}
public static class CheckTableResult {
public enum MsgType {
status,
error,
info,
warning,
// From MySQL 5.1
note,
Error
}
private final String table;
private final long duration;
private final MsgType msgType;
private final String msgText;
public CheckTableResult(
String table,
long duration,
MsgType msgType,
String msgText
) {
this.table = table;
this.duration = duration;
this.msgType = msgType;
this.msgText = msgText;
}
/**
* @return the table
*/
public String getTable() {
return table;
}
/**
* @return the duration
*/
public long getDuration() {
return duration;
}
/**
* @return the msgType
*/
public MsgType getMsgType() {
return msgType;
}
/**
* @return the msgText
*/
public String getMsgText() {
return msgText;
}
}
/**
* Gets the table status on the master server.
*/
public List checkTables(final Collection tableNames) throws IOException, SQLException {
return checkTables(null, tableNames);
}
/**
* Gets the table status on the master server or provided slave server.
*/
public List checkTables(final FailoverMySQLReplication mysqlSlave, final Collection tableNames) throws IOException, SQLException {
if(tableNames.isEmpty()) return Collections.emptyList();
return table.connector.requestResult(
true,
new AOServConnector.ResultRequest>() {
private List result;
@Override
public void writeRequest(CompressedDataOutputStream out) throws IOException {
out.writeCompressedInt(AOServProtocol.CommandID.CHECK_MYSQL_TABLES.ordinal());
out.writeCompressedInt(pkey);
out.writeCompressedInt(mysqlSlave==null ? -1 : mysqlSlave.pkey);
int size = tableNames.size();
out.writeCompressedInt(size);
int count = 0;
Iterator iter = tableNames.iterator();
while(count checkTableResults = new ArrayList<>(size);
for(int c=0;c afterRelease() {
return result;
}
}
);
}
/**
* Determines if a name is safe for use as a table/column name, the name identifier
* should be enclosed with backticks (`).
*/
public static boolean isSafeName(String name) {
// Must be a-z first, then a-z or 0-9 or _ or -
int len = name.length();
if (len == 0) return false;
// The first character must be [a-z] or [A-Z] or _
char ch = name.charAt(0);
if ((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && ch != '_') return false;
// The rest may have additional characters
for (int c = 1; c < len; c++) {
ch = name.charAt(c);
if ((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') && ch != '_' && ch != '-') return false;
}
// Also must not be a reserved word
/*int size=reservedWords.size();
for(int c=0;c
© 2015 - 2025 Weber Informatics LLC | Privacy Policy