Fast MySQL client for Node.js with support for prepared statements, SSL, compression, and promise-based APIs
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
MySQL server implementation for creating custom MySQL protocol servers, handling client connections, and building MySQL-compatible database services.
Creates a MySQL protocol server that can accept client connections and handle MySQL commands.
/**
* Create MySQL protocol server
* @param handler - Optional connection handler function
* @returns Server instance
*/
function createServer(handler?: (connection: Connection) => void): Server;Usage Examples:
const mysql = require('mysql2');
// Create basic server
const server = mysql.createServer();
// Handle new connections
server.on('connection', (conn) => {
console.log('New connection from:', conn.remoteAddress);
// Handle queries from client
conn.on('query', (sql) => {
console.log('Received query:', sql);
// Send mock response
if (sql === 'SELECT 1') {
conn.writeTextResult([{ '1': 1 }], [{ name: '1', type: 'LONG' }]);
} else {
conn.writeError({ message: 'Unknown query', code: 1064 });
}
});
});
// Start server
server.listen(3307, () => {
console.log('MySQL server listening on port 3307');
});
// Create server with connection handler
const server2 = mysql.createServer((conn) => {
console.log('Connection established');
// Set connection attributes
conn.serverHandshake({
protocolVersion: 10,
serverVersion: '5.7.0-mock',
connectionId: Math.floor(Math.random() * 1000000),
statusFlags: 2,
characterSet: 8,
capabilityFlags: 0xffffff
});
});MySQL protocol server class extending Node.js net.Server.
interface Server extends EventEmitter {
/** Start listening for connections */
listen(port: number, callback?: () => void): void;
listen(port: number, hostname: string, callback?: () => void): void;
listen(options: { port: number; host?: string; backlog?: number }, callback?: () => void): void;
/** Close server and stop accepting connections */
close(callback?: (err?: Error) => void): void;
/** Get server address information */
address(): { port: number; family: string; address: string } | string | null;
/** Maximum number of concurrent connections */
maxConnections: number;
/** Current number of connections */
connections: number;
/** Whether server is listening */
listening: boolean;
}MySQL servers emit events for connection management and error handling.
// Event: 'connection' - New client connection
server.on('connection', (connection) => {
console.log('Client connected:', connection.connectionId);
});
// Event: 'listening' - Server started listening
server.on('listening', () => {
console.log('Server is listening');
});
// Event: 'close' - Server closed
server.on('close', () => {
console.log('Server closed');
});
// Event: 'error' - Server error
server.on('error', (error) => {
console.error('Server error:', error);
});Server connections provide methods for handling MySQL protocol communications.
interface ServerConnection extends EventEmitter {
/** Connection ID */
connectionId: number;
/** Client remote address */
remoteAddress: string;
/** Client remote port */
remotePort: number;
/** Connection state */
state: string;
/** Send handshake to client */
serverHandshake(options: HandshakeOptions): void;
/** Write OK packet to client */
writeOk(options?: OkPacketOptions): void;
/** Write error packet to client */
writeError(options: ErrorPacketOptions): void;
/** Write result set to client */
writeTextResult(rows: any[], fields: FieldDefinition[]): void;
/** Write prepared statement response */
writePreparedStatement(id: number, fields: FieldDefinition[], params: FieldDefinition[]): void;
/** Write binary result set */
writeBinaryResult(rows: any[], fields: FieldDefinition[]): void;
/** Write EOF packet */
writeEof(options?: EofPacketOptions): void;
/** Close connection */
close(): void;
/** Destroy connection */
destroy(): void;
}Server connections emit events for handling MySQL protocol commands.
// Event: 'query' - Text query received
connection.on('query', (sql) => {
console.log('Query:', sql);
// Process query and send response
if (sql.toUpperCase().startsWith('SELECT')) {
// Handle SELECT
connection.writeTextResult(rows, fields);
} else if (sql.toUpperCase().startsWith('INSERT')) {
// Handle INSERT
connection.writeOk({ affectedRows: 1, insertId: 123 });
} else {
connection.writeError({ message: 'Unsupported query', code: 1064 });
}
});
// Event: 'prepare' - Prepared statement creation
connection.on('prepare', (sql) => {
console.log('Prepare:', sql);
// Create prepared statement
const statementId = Math.floor(Math.random() * 1000000);
connection.writePreparedStatement(statementId, fields, params);
});
// Event: 'execute' - Prepared statement execution
connection.on('execute', (statementId, parameters) => {
console.log('Execute statement:', statementId, 'with params:', parameters);
// Execute prepared statement
connection.writeBinaryResult(rows, fields);
});
// Event: 'close' - Connection closed
connection.on('close', () => {
console.log('Connection closed');
});
// Event: 'error' - Connection error
connection.on('error', (error) => {
console.error('Connection error:', error);
});Configuration for MySQL server handshake.
interface HandshakeOptions {
/** Protocol version */
protocolVersion?: number;
/** Server version string */
serverVersion?: string;
/** Connection ID */
connectionId?: number;
/** Authentication plugin name */
authPluginName?: string;
/** Server capabilities */
capabilityFlags?: number;
/** Character set */
characterSet?: number;
/** Server status flags */
statusFlags?: number;
/** Authentication plugin data */
authPluginData?: Buffer;
}Options for various MySQL protocol packets.
interface OkPacketOptions {
/** Number of affected rows */
affectedRows?: number;
/** Last insert ID */
insertId?: number;
/** Server status flags */
serverStatus?: number;
/** Warning count */
warningCount?: number;
/** Status message */
message?: string;
}
interface ErrorPacketOptions {
/** Error message */
message: string;
/** Error code */
code?: number;
/** SQL state */
sqlState?: string;
}
interface EofPacketOptions {
/** Warning count */
warningCount?: number;
/** Server status flags */
statusFlags?: number;
}MySQL field metadata for result sets.
interface FieldDefinition {
/** Field name */
name: string;
/** Field type */
type: number;
/** Field length */
length?: number;
/** Field flags */
flags?: number;
/** Decimal places */
decimals?: number;
/** Database name */
db?: string;
/** Table name */
table?: string;
/** Original table name */
orgTable?: string;
/** Original field name */
orgName?: string;
/** Character set */
charsetNr?: number;
}const mysql = require('mysql2');
const backendPool = mysql.createPool({
host: 'backend-db.example.com',
user: 'proxy_user',
password: 'proxy_password',
database: 'production'
});
const proxyServer = mysql.createServer((conn) => {
console.log(`Proxy connection ${conn.connectionId} from ${conn.remoteAddress}`);
// Handle queries by forwarding to backend
conn.on('query', async (sql) => {
try {
const [rows, fields] = await backendPool.execute(sql);
if (Array.isArray(rows)) {
// SELECT result
conn.writeTextResult(rows, fields);
} else {
// INSERT/UPDATE/DELETE result
conn.writeOk({
affectedRows: rows.affectedRows,
insertId: rows.insertId,
message: rows.message
});
}
} catch (error) {
conn.writeError({
message: error.message,
code: error.errno || 1064,
sqlState: error.sqlState || 'HY000'
});
}
});
// Send initial handshake
conn.serverHandshake({
protocolVersion: 10,
serverVersion: '5.7.0-proxy',
connectionId: conn.connectionId,
characterSet: 8,
capabilityFlags: 0xffffff
});
});
proxyServer.listen(3308, () => {
console.log('Database proxy server listening on port 3308');
});const mockData = {
users: [
{ id: 1, name: 'John Doe', email: 'john@example.com', active: 1 },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', active: 1 },
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', active: 0 }
]
};
const mockServer = mysql.createServer((conn) => {
console.log(`Mock connection ${conn.connectionId}`);
conn.on('query', (sql) => {
console.log('Mock query:', sql);
const upperSql = sql.toUpperCase().trim();
if (upperSql === 'SELECT * FROM users') {
// Return all users
conn.writeTextResult(mockData.users, [
{ name: 'id', type: mysql.Types.LONG },
{ name: 'name', type: mysql.Types.VAR_STRING },
{ name: 'email', type: mysql.Types.VAR_STRING },
{ name: 'active', type: mysql.Types.TINY }
]);
} else if (upperSql.startsWith('SELECT * FROM users WHERE')) {
// Simple WHERE clause parsing
const activeMatch = sql.match(/active\s*=\s*(\d+)/i);
if (activeMatch) {
const active = parseInt(activeMatch[1]);
const filteredUsers = mockData.users.filter(user => user.active === active);
conn.writeTextResult(filteredUsers, [
{ name: 'id', type: mysql.Types.LONG },
{ name: 'name', type: mysql.Types.VAR_STRING },
{ name: 'email', type: mysql.Types.VAR_STRING },
{ name: 'active', type: mysql.Types.TINY }
]);
} else {
conn.writeError({ message: 'Unsupported WHERE clause', code: 1064 });
}
} else if (upperSql === 'SELECT 1') {
// Ping query
conn.writeTextResult([{ '1': 1 }], [{ name: '1', type: mysql.Types.LONG }]);
} else {
conn.writeError({ message: 'Unsupported query', code: 1064 });
}
});
// Initial handshake
conn.serverHandshake({
protocolVersion: 10,
serverVersion: '5.7.0-mock',
connectionId: conn.connectionId,
characterSet: 33, // UTF8_GENERAL_CI
capabilityFlags: 0xffffff
});
});
mockServer.listen(3309, () => {
console.log('Mock database server listening on port 3309');
});const authenticatedServer = mysql.createServer((conn) => {
let authenticated = false;
conn.on('authenticate', (user, password, database) => {
console.log(`Authentication attempt: ${user}@${database}`);
// Simple authentication logic
if (user === 'testuser' && password === 'testpass') {
authenticated = true;
conn.writeOk({ message: 'Authentication successful' });
} else {
conn.writeError({
message: 'Access denied',
code: 1045,
sqlState: '28000'
});
conn.close();
}
});
conn.on('query', (sql) => {
if (!authenticated) {
conn.writeError({
message: 'Not authenticated',
code: 1045,
sqlState: '28000'
});
return;
}
// Handle authenticated queries...
conn.writeOk({ message: 'Query executed' });
});
// Custom handshake with authentication
conn.serverHandshake({
protocolVersion: 10,
serverVersion: '5.7.0-auth',
connectionId: conn.connectionId,
authPluginName: 'mysql_native_password',
characterSet: 33,
capabilityFlags: 0xffffff
});
});
authenticatedServer.listen(3310, () => {
console.log('Authenticated server listening on port 3310');
});const server = mysql.createServer();
const connections = new Set();
server.on('connection', (conn) => {
connections.add(conn);
conn.on('close', () => {
connections.delete(conn);
});
});
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('Shutting down server...');
server.close(() => {
console.log('Server closed');
// Close all connections
connections.forEach(conn => conn.close());
process.exit(0);
});
});
server.listen(3307);const server = mysql.createServer();
server.on('error', (error) => {
if (error.code === 'EADDRINUSE') {
console.error('Port already in use');
} else if (error.code === 'EACCES') {
console.error('Permission denied');
} else {
console.error('Server error:', error);
}
});
server.on('connection', (conn) => {
conn.on('error', (error) => {
console.error(`Connection ${conn.connectionId} error:`, error);
});
});