Page 1 of 1
LOAD DATA LOCAL INFILE with named pipes
Posted: Tue 04 Oct 2016 15:31
by zeltron73
Hello,
I would like to execute a command like this :
Code: Select all
LOAD DATA LOCAL INFILE "//localhost/pipe/pipename" INTO TABLE test FIELDS TERMINATED BY ";" ENCLOSED BY '"' LINES TERMINATED BY "\r\n";
Unfortunately, this does not work with MyDAC, because the code will ask the file size and the operating system will return 0 for a pipe... So the file is immediately closed and the server will return an error code.
This command works like a charm with the "mysql.exe" console program.
Could you modify the code so that MyDAC components could execute "LOAD DATA LOCAL INFILE" with pipes ?
Info: in the file MySqlSession.pas we can find the method TMySqlSession.ReadQueryResult
and the following code:
Code: Select all
c := f.Size; // will return 0 for named pipes
while c > 0 do begin
r := Min(c, Length(buf));
f.ReadBuffer(buf[0], r);
net.WriteBytes(buf, 0, r);
net.Send;
Dec(c, r);
end;
I think this could be replaced by :
Code: Select all
c := f.ReadBuffer(buf[0], Length(buf));
while c > 0 do begin
net.WriteBytes(buf, 0, c);
net.Send;
c := f.ReadBuffer(buf[0], Length(buf));
end;
Regards.
Re: LOAD DATA LOCAL INFILE with named pipes
Posted: Thu 06 Oct 2016 08:02
by zeltron73
Sorry,
In my previous post, the last piece of code should be replaced by:
Code: Select all
c := f.Read(buf[0], Length(buf)); // Read and not ReadBuffer !!!
while c > 0 do begin
net.WriteBytes(buf, 0, c);
net.Send;
c := f.Read(buf[0], Length(buf));
end;
Regard.
Re: LOAD DATA LOCAL INFILE with named pipes
Posted: Thu 06 Oct 2016 13:25
by ViktorV
Thank you for the information and your help on issue investigation. The issue investigation is in progress. We will inform you when we have any results.
Re: LOAD DATA LOCAL INFILE with named pipes
Posted: Fri 14 Oct 2016 10:08
by zeltron73
Here is a little test to reproduce the problem...
Code: Select all
CREATE TABLE `table1` (
`Field1` int(10) unsigned NOT NULL,
`Field2` varchar(45) NOT NULL DEFAULT '""',
PRIMARY KEY (`Field1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Code: Select all
procedure TForm1.Button1Click(Sender: TObject);
const
BUF_SIZE = $10000;
LOAD_DATA_QUERY = 'LOAD DATA LOCAL INFILE "%0:s" IGNORE INTO TABLE `%1:s`.`%2:s` ' +
'FIELDS TERMINATED BY ";" OPTIONALLY ENCLOSED BY "\"" LINES TERMINATED BY "\r\n";';
var
pipeName: string;
outputStream: TFileStream;
mysqlThread: TThread;
pipeConnectionEvent: TSimpleEvent;
overlapped: TOverlapped;
line: AnsiString;
begin
outputStream := nil;
mysqlThread := nil;
FillChar(overlapped, SizeOf(overlapped), 0);
pipeConnectionEvent := nil;
try
pipeName := '\\.\pipe\mysqlTest';
outputStream := TFileStream.Create(CreateNamedPipe(PChar(pipeName),
PIPE_ACCESS_OUTBOUND or FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, BUF_SIZE, 0, 100, nil));
pipeName := StringReplace(pipeName, '\', '/', [rfReplaceAll]);
pipeName := StringReplace(pipeName, '/./', '/localhost/', [rfIgnoreCase]);
mysqlThread := TThread.CreateAnonymousThread(
procedure
var
connection: TMyConnection;
query: TMyQuery;
begin
try
connection := nil;
query := nil;
try
connection := TMyConnection.Create(nil);
connection.Server := 'localhost';
connection.Port := 3306;
connection.Username := 'user';
connection.Password := 'password';
connection.Database := 'test';
query := TMyQuery.Create(nil);
query.Connection := connection;
query.SQL.Text := string.Format(LOAD_DATA_QUERY, [pipeName, connection.Database, 'table1']);
query.ExecSQL;
finally
query.Free;
connection.Free;
end;
except
on E: Exception do OutputDebugString(PChar(E.Message));
end;
end);
pipeConnectionEvent := TSimpleEvent.Create;
overlapped.hEvent := pipeConnectionEvent.Handle;
if ConnectNamedPipe(outputStream.Handle, @overlapped) or
(GetLastError = ERROR_IO_PENDING) or (GetLastError = ERROR_PIPE_CONNECTED) then
begin
mysqlThread.FreeOnTerminate := False;
mysqlThread.Start;
if (pipeConnectionEvent.WaitFor(5000) <> wrSignaled) then Exit;
line := '"1";"String1"'#13#10;
outputStream.Write(Pointer(line)^, Length(line));
TThread.Sleep(5000);
line := '"2";"String2"'#13#10;
outputStream.Write(Pointer(line)^, Length(line));
line := '"3";"String3"'#13#10;
outputStream.Write(Pointer(line)^, Length(line));
line := '"4";"String4"'#13#10;
outputStream.Write(Pointer(line)^, Length(line));
line := '"5";"String5"'#13#10;
outputStream.Write(Pointer(line)^, Length(line));
end;
finally
pipeConnectionEvent.Free;
outputStream.Free; // close the pipe
mysqlThread.Free; // wait for the thread
end;
end;
When you execute the test, the first line only is inserted because when the sql command is executed only that line was written... The others are ignored because MyDAC has still closed the pipe !
I hope that it will help you.
Regards.
Re: LOAD DATA LOCAL INFILE with named pipes
Posted: Mon 17 Oct 2016 11:45
by ViktorV
Thank you for being interested in our products and your help on issue investigation.
We will investigate the behavior of MyDAC according to your description and inform you about the results.