DB::MariaDBSourceDBMariaDBNativeConnection

class Connection

A native FFI connection to the MariaDB/MySQL client library.

Definitions

def self.connect(host: "localhost", username: nil, password: nil, database: nil, port: 0, unix_socket: nil, client_flags: 0, compression: false, types: DEFAULT_TYPES, **options)

Establish a connection to the MariaDB/MySQL server.

Signature

parameter host String

The hostname or IP address to connect to.

parameter username String | Nil

The username for authentication.

parameter password String | Nil

The password for authentication.

parameter database String | Nil

The database name to connect to.

parameter port Integer

The port number to connect to.

parameter unix_socket String | Nil

The Unix socket path for local connections.

parameter client_flags Integer

Client connection flags.

parameter compression Boolean

Whether to enable connection compression.

parameter types Hash

Type mapping configuration.

parameter options Hash

Additional connection options.

returns Connection

A new connected instance.

raises Error

If the connection fails.

Implementation

def self.connect(host: "localhost", username: nil, password: nil, database: nil, port: 0, unix_socket: nil, client_flags: 0, compression: false, types: DEFAULT_TYPES, **options)
	pointer = Native.mysql_init(nil)
	Native.mysql_options(pointer, MYSQL_OPT_NONBLOCK, nil)
	
	# if protocol
	# 	Native.mysql_options(pointer, MYSQL_OPT_PROTOCOL, FFI::MemoryPointer.new(:uint, protocol))
	# end
	
	client_flags |= CLIENT_MULTI_STATEMENT | CLIENT_MULTI_RESULTS
	
	if compression
		client_flags |= CLIENT_COMPRESSION
	end
	
	result = FFI::MemoryPointer.new(:pointer)
	
	status = Native.mysql_real_connect_start(result, pointer, host, username, password, database, port, unix_socket, client_flags);
	
	io = ::IO.new(Native.mysql_get_socket(pointer), "r+", autoclose: false)
	
	if status > 0
		while status > 0
			if status & MYSQL_WAIT_READ
				io.wait_readable
			elsif status & MYSQL_WAIT_WRITE
				io.wait_writable
			else
				io.wait_any
			end
			
			status = Native.mysql_real_connect_cont(result, pointer, status)
		end
	end
	
	if result.read_pointer.null?
		raise Error, "Could not connect: #{Native.mysql_error(pointer)}!"
	end
	
	return self.new(pointer, io, types, **options)
end

def initialize(address, io, types, **options)

Initialize a native connection wrapper.

Signature

parameter address FFI::Pointer

The pointer to the native connection.

parameter io IO

The IO object for the socket.

parameter types Hash

Type mapping configuration.

parameter options Hash

Additional options.

Implementation

def initialize(address, io, types, **options)
	super(address)
	
	@io = io
	@result = nil
	
	@types = types
end

attr :types

Signature

attribute Hash

The type mapping configuration.

def wait_for(status)

Wait for the specified IO condition.

Signature

parameter status Integer

The status flags indicating which IO condition to wait for.

Implementation

def wait_for(status)
	if status & MYSQL_WAIT_READ
		@io.wait_readable
	elsif status & MYSQL_WAIT_WRITE
		@io.wait_writable
	end
end

def check_error!(message)

Check for errors and raise an exception if one occurred.

Signature

parameter message String

The error message prefix.

raises Error

If an error occurred.

Implementation

def check_error!(message)
	if Native.mysql_errno(self) != 0
		raise Error, "#{message}: #{Native.mysql_error(self)}!"
	end
end

def status

Get the current connection status.

Signature

returns String

The status string from the server.

Implementation

def status
	Native.mysql_stat(self)
end

def free_result

Free the current result set.

Implementation

def free_result
	if @result
		Native.mysql_free_result(@result)
		
		@result = nil
	end
end

def close

Close the connection and release all resources.

Implementation

def close
	self.free_result
	
	Native.mysql_close(self)
	
	@io.close
end

def escape(value)

Escape a string value for safe inclusion in SQL queries.

Signature

parameter value String

The value to escape.

returns String

The escaped string.

Implementation

def escape(value)
	value = value.to_s
	
	maximum_length = value.bytesize * 2 + 1
	out = FFI::MemoryPointer.new(:char, maximum_length)
	
	Native.mysql_real_escape_string(self, out, value, value.bytesize)
	
	return out.read_string
end

def send_query(statement)

Send a query to the server for execution.

Signature

parameter statement String

The SQL statement to execute.

raises Error

If the query fails.

Implementation

def send_query(statement)
	self.free_result
	
	error = FFI::MemoryPointer.new(:int)
	
	status = Native.mysql_real_query_start(error, self, statement, statement.bytesize)
	
	while status != 0
		self.wait_for(status)
		
		status = Native.mysql_real_query_cont(error, self, status)
	end
	
	if error.read_int != 0
		raise Error, "Could not send query: #{Native.mysql_error(self)}!"
	end
end

def more_results?

Check if there are more result sets available.

Signature

returns Boolean

True if there are more results.

Implementation

def more_results?
	Native.mysql_more_results(self) == 1
end

def next_result(types: @types)

Get the next result set from a multi-result query.

Signature

parameter types Hash

Type mapping to use for this result.

returns Result | Nil

The next result set, or nil if no more results.

Implementation

def next_result(types: @types)
	if result = self.get_result
		return Result.new(self, types, result)
	end
end

def discard_results

Silently discard any results that the application did not read.

Signature

returns Nil

Implementation

def discard_results
	while result = self.get_result
	end
	
	return nil
end

def affected_rows

Get the number of rows affected by the last query.

Signature

returns Integer

The number of affected rows.

Implementation

def affected_rows
	Native.mysql_affected_rows(self)
end

def insert_id

Get the last auto-generated ID from an INSERT query.

Signature

returns Integer

The last insert ID.

Implementation

def insert_id
	Native.mysql_insert_id(self)
end

def info

Get information about the last query execution.

Signature

returns String | Nil

Information string about the query.

Implementation

def info
	Native.mysql_info(self)
end