📄 umysqlclient.pas
字号:
result:=''//fnet.last_error //there was an error
else //no error
begin
if pchar(fnet.read_pos)[0]=#0 then //did we got an empty string?
begin
fnet.last_errno:=CR_WRONG_HOST_INFO;
fnet.last_error:= client_errors[(fnet.last_errno)-CR_MIN_ERROR];
result:='';//fnet.last_error;
end
else
result:=pchar(fnet.read_pos); //return stats
end;
finally
if FThreaded then
FCriticalSection.Leave;
end;
end;
////////////////////////////////////////////////////////////////////////////////
// reconnects to the server
// returns true if success
function TMysqlClient.reconnect: boolean;
begin
if (not freconnect) or
(fserver_status and SERVER_STATUS_IN_TRANS =SERVER_STATUS_IN_TRANS) then
begin
fserver_status:=fserver_status and not SERVER_STATUS_IN_TRANS;
result:=false;
exit;
end;
//fnet.net_close;
if not connect then
result:=false
else
result:=true;
end;
////////////////////////////////////////////////////////////////////////////////
// internal send file to server for use with load data infile on client machine
function TMysqlClient.send_file_to_server(const filename: string): longint;
var
readcount:longint;
buf:array[0..IO_SIZE*15-1] of char;
f:file;
tmp:byte;
begin
//todo fn_format(buf,filename,"","",4);
assignfile(f,filename);
tmp:=filemode; //old filemode
filemode:=0; //read only
{$I-}
reset(f,1); //try to open the file
{$I+}
if (IOResult<> 0) then
begin
fnet.last_errno:=0;// EE_FILENOTFOUND
fnet.last_error:=copy(format('File ''%s'' not found (Errcode: %d)',[filename,IOResult]),1,length(fnet.last_error));
fnet.my_net_write('',0); //send empty packet to server
fnet.net_flush;
result:=-1;
filemode:=tmp;
exit;
end;
blockread(f,buf,sizeof(buf),readcount); //let's send the file
while (readcount > 0) do //while we still have things in file
begin
if (fnet.my_net_write(buf,readcount)<>0) then //maybe we have errors?
begin
fnet.last_errno:=CR_SERVER_LOST;
fnet.last_error:=client_errors[(fnet.last_errno)-CR_MIN_ERROR];
closefile(f);
result:=-1;
filemode:=tmp;
exit;
end;
blockread(f,buf,sizeof(buf),readcount); //read next chunk
end;
closefile(f); //close the file
if (fnet.my_net_write('',0)<>0) or (fnet.net_flush<>0) then //send empty packet to mark eof
begin
fnet.last_errno:=CR_SERVER_LOST;
fnet.last_error:=client_errors[(fnet.last_errno)-CR_MIN_ERROR];
result:=-1;
filemode:=tmp;
exit;
end;
if (readcount < 0) then //did by any chance we had an error while reading?
begin
fnet.last_errno:=2;//EE_READ
fnet.last_error:=copy(format('Error reading file ''%s'' (Errcode: %d)',[filename,IOResult]),1,sizeof(fnet.last_error)-1);
result:=-1;
filemode:=tmp;
exit;
end;
filemode:=tmp; //restore filemode
result:=0;
end;
////////////////////////////////////////////////////////////////////////////////
//returns client version
function TMysqlClient.GetClientInfo: string;
begin
result:=MYSQL_SERVER_VERSION;
end;
////////////////////////////////////////////////////////////////////////////////
// returns protocol version - one should read this only after connecting
// or else will be 0
function TMysqlClient.Getprotocol_version: cardinal;
begin
result:=fnet.protocol_version;
end;
////////////////////////////////////////////////////////////////////////////////
//internal function to send a command to the server
function TMysqlClient.simple_command(command: TEnumServerCommand;
arg: pchar; lengt: Integer; skipp_check: boolean; retry:boolean): longint;
var
pl:longint;
begin
result:= -1; //mark error unless ok
if not fnet.net_connected then //are we connected?
begin
if not(reconnect) then //attempt to reconnect
begin
//preserve the error on connect
//fnet.last_errno:=CR_SERVER_GONE_ERROR;
//fnet.last_error:=client_errors[(fnet.last_errno)-CR_MIN_ERROR];
exit;
end
end;
if (fstatus <> MYSQL_STATUS_READY) then //can we execute this command?
begin
fnet.last_errno:=CR_COMMANDS_OUT_OF_SYNC;
fnet.last_error:=client_errors[(fnet.last_errno)-CR_MIN_ERROR];
exit;
end;
fnet.last_error:=''; //init for command
fnet.last_errno:=0;
finfo:='';
faffected_rows:= 0;
finsert_id:=0;
fnet.net_clear;
if (fnet.net_write_command(chr(ord(command)),pchar(arg),lengt )<>0) then //let's try to send
begin
fnet.net_close;//end_server
free_old_query;
if reconnect or (fnet.net_write_command(chr(ord(command)),pchar(arg),lengt)<>0)then //another attempt to reconnect end send
begin
//failed
fnet.last_errno:=CR_SERVER_GONE_ERROR;
fnet.last_error:=client_errors[(fnet.last_errno)-CR_MIN_ERROR];
exit;
end;
end;
result:=0; //no error
if (not skipp_check) then //if we need to check if server got it
begin
pl:=fnet.net_safe_read; //read length of next packet
if pl = packet_error then //if there is something
begin
if fnet.last_errno=CR_SERVER_LOST then
close;
if retry then //one more time, but in order to not make it infinite loop this time will not retry
result:=simple_command(command,arg,lengt,skipp_check,false) //this time we do not retry
else
result:=-1;
end
else
result:=0; //ok
end;
end;
////////////////////////////////////////////////////////////////////////////////
// returns last error string (mapped on NET, actually down to VIO)
function TMysqlClient.GetLastError: string;
begin
result:=fnet.last_error;
end;
////////////////////////////////////////////////////////////////////////////////
// reads one row from the server
// returns 0 if no error
// returns 1 if there arent anymore rows
function TMysqlClient.read_one_row(fields:longint;row:TMysql_Row;lengths:PCardinal): longint;
var
field:longint;
pkt_len, _len:longint;
_pos, prev_pos:PChar;
begin
// is there anything to read?
pkt_len:=fnet.net_safe_read;
if (pkt_len=packet_error) then
begin
result:=-1;
exit;
end;
// is it the last row?
if (pkt_len < 8) and(pchar(fnet.read_pos)[0] = #254) then
begin
result:=1;
exit;
end;
//free row content
for field:=0 to fields -1 do
strdispose(TPPCA(row)[field]);
//read next row
prev_pos:= nil;
_pos:=pchar(fnet.read_pos);
// for each field value
for field:=0 to fields-1 do
begin
//get field value size
_len:=net_field_length(longint(_pos));
if (_len=NULL_LENGTH) then
begin
TPPCA(row)[field] := nil;
TPCA(lengths)[field]:= FNullLength;
end
else
begin
TPPCA(row)[field]:=StrAlloc(_len+1);
//copy field content
if _len>0 then
move(_pos[0],TPPCA(row)[field]^,_len);
TPPCA(row)[field][_len]:=#0;// if one uses pchar
_pos:=_pos+_len;
TPCA(lengths)[field]:=_len;
end;
if (prev_pos<>nil)and(prev_pos[0]<>#0)then //if previous field value didnt ended by #0
prev_pos[0]:=#0;
prev_pos:=_pos; //move to next
end;
prev_pos[0]:=#0; //set the last #0
result:=0;
end;
////////////////////////////////////////////////////////////////////////////////
// reads rows from the server
// returns data if no error
// returns nil if there were any errors
function TMysqlClient.read_rows(mysql_fields: PMysql_FieldDef; fields: Integer; var hadErrors:boolean): PMYSQL_DATA;
var
pkt_len, field, len1:longint;
cp:pchar;
prev_ptr:PMysql_Rows;
cur:PMysql_Rows;
begin
result:=nil;
hadErrors:=true;
pkt_len:=fnet.net_safe_read; //is there any data?
if (pkt_len= packet_error) then
exit;
new(result);
if (result=nil) then //out of memory?
begin
fnet.last_errno:=CR_OUT_OF_MEMORY;
fnet.last_error:=client_errors[(fnet.last_errno)-CR_MIN_ERROR];
exit;
end;
result.data:=nil;
prev_ptr:= nil;
result.rows:=0;
result.fields:=fields;
cp:=pchar(fnet.read_pos);
while not (( byte(cp[0]) = 254) and (pkt_len < 8)) do //do this until we get last row
begin
//here you could add a progress or something
//like an event onNewRow <-disadvantage you can't tell how many left
inc(result.rows); //we have new row
//let's grab some memory for the new row
new(cur);
if cur<>nil then
cur.data:=allocmem((fields)*sizeof(pchar));
if (cur=nil) or (cur.data=nil) then
begin //mmm.. we are running out of memory
free_rows(result);
fnet.last_errno:=CR_OUT_OF_MEMORY;
fnet.last_error:=client_errors[(fnet.last_errno)-CR_MIN_ERROR];
result:=nil;
exit;
end;
cur.Next:=nil; //so far we assume no more rows
cur.prior:=prev_ptr; //double link
if prev_ptr<>nil then
prev_ptr.Next:= cur //preserve next link
else
result.data:=cur;//it is the first / head
prev_ptr:=cur;
for field:=0 to fields-1 do //for each field
begin
len1:=net_field_length(longint(cp));
if (len1 = NULL_LENGTH) then //if it is an empty field
TPPCA(cur.data)[field]:= nil
else
if len1>0 then begin
//let's grab some memory
TPPCA(cur.data)[field]:=StrAlloc(len1+1);
//copy field content
if len1>0 then
move(cp[0],TPPCA(cur.data)[field]^,len1);
TPPCA(cur.data)[field][len1]:=#0;// if one uses pchar
cp:=pchar(longint(cp)+len1); //we can move to next field
if (mysql_fields<>nil) then //if we passed fields structure
if TPFDA(mysql_fields)[field].Max_Length < cardinal(len1) then
TPFDA(mysql_fields)[field].Max_Length := cardinal(len1);
end;
end;
pkt_len:=fnet.net_safe_read; //let's try to read next row /if any
if ( pkt_len= packet_error) then
begin //maybe we got an error
free_rows(result); //we can free the rows
result:=nil;
exit;
end;
cp:=pchar(fnet.read_pos); //here we go again .. next row
end;
hadErrors:=false;
end;
function TMySQLClient.protocol41: boolean;
begin
Result := fserver_capabilities and CLIENT_PROTOCOL_41=CLIENT_PROTOCOL_41;
end;
////////////////////////////////////////////////////////////////////////////////
// internal decode of PMysql_Data into fields structure
function TMysqlClient.unpack_fields(data: PMYSQL_DATA; fields: Integer; long_flag_protocol: boolean): PMysql_FieldDef;
var
field:PMysql_FieldDef;
row:PMysql_Rows;
aFieldVal:pchar;
begin
//let's grab some memory
getmem(result,sizeof(TMysql_FieldDef)*fields);
field:=result;
if (result=nil) then //out of memory?
exit;
row:=data.data; //first row=first field def
while row<>nil do
begin
with field^ do begin
name := nil;
org_name := nil;
table := nil;
org_table := nil;
db := nil;
catalog := nil;
def := nil;
end;
if {False and }((fserver_capabilities {fclient_flag }and CLIENT_PROTOCOL_41)=CLIENT_PROTOCOL_41) then begin
//catalog
field.catalog := StrNew(TPPCA(row.data)[0]);
field.db := StrNew(TPPCA(row.data)[1]);
field.table := StrNew(TPPCA(row.data)[2]);
field.org_table := StrNew(TPPCA(row.data)[3]);
field.name := StrNew(TPPCA(row.data)[4]);
field.org_name := StrNew(TPPCA(row.data)[5]);
aFieldVal:=TPPCA(row.data)[6];
field.charsetnr:= (byte(pchar(aFieldVal)[0]))+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -