📄 umysqlclient.pas
字号:
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: string; 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 = 1) 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) or (_len=0) then
begin
TPPCA(row)[field]:=nil; //empty value
TPCA(lengths)[field]:=0;
end
else
begin
TPPCA(row)[field]:=StrAlloc(_len+1);
//copy field content
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 = 1)) 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 = 0)or(len1 = NULL_LENGTH) then //if it is an empty field
TPPCA(cur.data)[field]:=nil
else
begin
//let's grab some memory
TPPCA(cur.data)[field]:=StrAlloc(len1+1);
//copy field content
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
begin //we can check max_length
if TPFDA(mysql_fields)[field].Max_Length < cardinal(len1) then
TPFDA(mysql_fields)[field].Max_Length := cardinal(len1);
end;
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;
////////////////////////////////////////////////////////////////////////////////
// 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
//table
aFieldVal:=TPPCA(row.data)[0];
field.Table:=StrNew(aFieldVal);
//name
aFieldVal:=TPPCA(row.data)[1];
field.Name:=strnew(aFieldVal);
//length
aFieldVal:=TPPCA(row.data)[2];
if aFieldVal<>nil then
field.length:= (byte(pchar(aFieldVal)[0]))+
(byte(pchar(aFieldVal)[1]))shl 8+
(byte(pchar(aFieldVal)[2]))shl 16;
//field type
aFieldVal:=TPPCA(row.data)[3];
if aFieldVal<>nil then
field.FieldType:= byte(pchar(aFieldVal)[0]);
//NUM_FLAG is not send from server so it needs to be set
if (field.FieldType<=FIELD_TYPE_INT24) AND ((field.FieldType<>FIELD_TYPE_TIMESTAMP) OR (field.Length=14) OR (field.Length=8)) OR (field.FieldType=FIELD_TYPE_YEAR) then
field.flags:=field.flags or NUM_FLAG;
//flags and decimals
aFieldVal:=TPPCA(row.data)[4];
if aFieldVal<>nil then
begin
if (long_flag_protocol) then
begin
field.flags:= (byte(pchar(aFieldVal)[0]))+
(byte(pchar(aFieldVal)[1]))shl 8;
field.decimals:=byte(pchar(aFieldVal)[2]);
end
else
begin
field.flags:= byte(pchar(aFieldVal)[0]);
field.decimals:=byte(pchar(aFieldVal)[1]);
end;
end;
//default value
//field.def:=nil; //*** removed
//aFieldVal:=TPPCA(row.data)[5];
//if (aFieldVal<>nil)and(data.fields=6) then //if there are 6 fields on PMysql_Data
//field.def:=strnew(aFieldVal);
field.Max_Length:= 0; //for the moment we don't know the max_length
row := row.next; //next field def
field:=@TPFDA(field)[1];
end;
free_rows(data); //we can now free data since all values are in fields
end;
////////////////////////////////////////////////////////////////////////////////
// closes the connection to mysql server
procedure TMysqlClient.close;
var rec:boolean;
begin
//init internal variables
fscramble_buff:='';
fthread_id:=0;
faffected_rows:=0;
finsert_id:=0;
fstatus:=MYSQL_STATUS_READY;
fserver_version:='';
fserver_capabilities:=0;
fserver_status:=SERVER_STATUS_AUTOCOMMIT;
fserver_language:=0;
fextra_info:=0;
finfo:='';
if fnet.net_connected then //are we connected?
begin
free_old_query; //if we have anything in buffer
fstatus:=MYSQL_STATUS_READY;
rec:=freconnect; //preserve reconnect state
freconnect:=false;
simple_command(COM_QUIT,'',0,true,freconnect); //tell the server we go
fnet.net_close;
freconnect:=rec;
//should init all server variables
end;
if assigned(fusedresult) then
begin
fusedresult.fhandle:=nil; //break the link
fusedresult:=nil;
end;
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -