Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Got "request synchronization error" when calling isc_dsql_sql_info with isc_info_sql_records parameter after last record fetched [CORE1310] #1729

Closed
firebird-automations opened this issue Jun 9, 2007 · 14 comments

Comments

@firebird-automations
Copy link
Collaborator

Submitted by: Vitaly (v6y)

Relate to CORE1651

Attachments:
syncerr.tgz

I getting this error always when a table contains the fields with double precision data type and has at least a few hudreds records. Everything is ok if a table does not have double precision data type fields, or there are a few records in it, or double precision fileds are not used in a query.

Last problem bulid tested: LI-T2.1.0.15947 Firebird 2.1 Beta 1
Last good build I have: LI-T2.1.0.15853 Firebird 2.1 Beta 1

Test:
/*meta-test.sql*/
SET SQL DIALECT 3;

create database 'localhost:/tmp/testdb.fdb' page_size=16384;

CREATE TABLE "TEST"
(
"ID" INTEGER NOT NULL PRIMARY KEY,
"TEXTFLD" VARCHAR(64),
"DOUBLEFLD" double precision
);
/*=== end of meta-test.sql =======================*/
/* test-sql.sql */
set term ^;
execute block
as
declare variable i integer;
begin
i=0;
while (i<1000) do
begin
insert into test
(id,textfld,doublefld)
values
(:i,'NAME ' || :i, :i*0.245);
i=i+1;
end
end
^
/*== end of test-sql.sql */

/*testit.cpp*/
#⁠include <ibase.h>
#⁠include <stdio.h>
#⁠include<stdlib.h>

#⁠define ERREXIT(status, rc) {isc_print_status(status); return rc;}
#⁠define IS_ISC_ERROR(status) (status[0] == 1 && status[1])

isc_db_handle db = NULL;
isc_tr_handle trans = NULL;
isc_stmt_handle stmt = NULL;
ISC_STATUS_ARRAY status;
int fetch_stat=0;
XSQLDA * sqlda;

void free_sqlda(XSQLDA *sqlda) {
int i;
for (i=0; i<sqlda->sqld; i++) {
free(sqlda->sqlvar[i].sqldata);
free(sqlda->sqlvar[i].sqlind);
}
sqlda->sqld=0;
}

void set_sqlda(XSQLDA *sqlda) {
int i;
for (i=0; i<sqlda->sqld; i++) {
if ((sqlda->sqlvar[i].sqltype & ~1)==SQL_VARYING)
sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen + sizeof(short));
else
sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen);

sqlda->sqlvar[i].sqlind = (short*)calloc(sizeof(short),1);
}
}

int affectedRows(int * sCnt=0,int * uCnt=0, int * iCnt=0, int *dCnt=0) {
static char count_info[] = {isc_info_sql_records};
char info_buffer[128];
char *p ;
int affected_rows=-1;
int selectCount,insertCount,updateCount,deleteCount;

selectCount=insertCount=updateCount=deleteCount=0;

isc_dsql_sql_info(status, &stmt,
sizeof (count_info), count_info,sizeof (info_buffer), info_buffer);
if (IS_ISC_ERROR(status)) return -1;

p=info_buffer+3;
affected_rows=0;
while (*p != isc_info_end) {
int count;
char item=*p++;
short len = (short)isc_vax_integer(p,2);
p+=2;
count=isc_vax_integer(p,len);
switch(item) {
case isc_info_req_select_count: selectCount+=count; break;
case isc_info_req_insert_count: insertCount+=count; break;
case isc_info_req_update_count: updateCount+=count; break;
case isc_info_req_delete_count: deleteCount+=count; break;
}

 p \+= len;

}
if (sCnt) *sCnt=selectCount;
if (uCnt) *uCnt=updateCount;
if (iCnt) *iCnt=insertCount;
if (dCnt) *dCnt=deleteCount;

affected_rows = selectCount+updateCount+insertCount+deleteCount;

return affected_rows;
}

int main (int argc, char** argv)
{

char dbname[]="localhost:/tmp/testdb.fdb";
if (isc_attach_database(status, 0, dbname, &db, 0, NULL))
{
printf("Could not open database %s\n", dbname);
ERREXIT(status, 1);
}
sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH (3));
sqlda->sqln = 3;
sqlda->version = 1;

isc\_start\_transaction\(status,&trans,1,&db,0,0\);    
if \(\!trans\) ERREXIT\(status, 1\);
isc\_dsql\_allocate\_statement\(status, &db, &stmt\);
if \(\!stmt\) ERREXIT\(status, 1\);

if \(isc\_dsql\_prepare\(status, &trans, &stmt, 0, "select \* from test", 3, sqlda\)\)
 ERREXIT\(status, 1\);
 
set\_sqlda\(sqlda\);
if \(isc\_dsql\_execute\(status, &trans, &stmt, 3,sqlda\)\)
 ERREXIT\(status, 1\);

int ar;    

while\(\!\(fetch\_stat=isc\_dsql\_fetch\(status, &stmt, 3, sqlda\)\)\);

if \(fetch\_stat\!=100L\) ERREXIT\(status, 1\);

if \(\(ar=affectedRows\(\)\)<0\) ERREXIT\(status, 1\);

printf\("Affected rows: %i\\n",ar\);

free\_sqlda\(sqlda\);
free \(sqlda\);
isc\_commit\_transaction\(status, &trans\);
isc\_detach\_database\(status, &db\);

return 0;    

}
/* end of testit.cpp*/

/*Makefile*/
GDS = fbclient

OBJS = testit.o
TARGETS = testit

.cpp.o:
g++ -g -c $&lt; -o $@

testit: $(OBJS)
g++ -o $@ $^ -l$(GDS)
clean:
rm -f $(TARGETS) $(OBJS)
cleanall: clean
rm -f /tmp/testdb.fdb
#⁠end of Makedile

/*http://runit.sh*/
#⁠!/bin/bash
prompt_pass () {
echo -n "DB User(sysdba): "
read ISC_USER
echo -n "DB Password(masterkey): "
stty -echo
read ISC_PASSWORD
echo
stty echo

if [ "${ISC_USER}" == "" ]
then
ISC_USER="sysdba"
fi

if [ "${ISC_PASSWORD}" == "" ]
then
ISC_PASSWORD="masterkey"
fi

}

clear

make || exit -1

echo
prompt_pass
export ISC_USER
export ISC_PASSWORD

if [ ! -f /tmp/testdb.fdb ]
then
echo -n "Firebird dir(/opt/firebird/): "
read FBPATH;
if [ "${FBPATH}" == "" ]
then
FBPATH="/opt/firebird/"
fi
${FBPATH}/bin/isql -i meta-test.sql || exit -1
${FBPATH}/bin/isql -i test-sql.sql localhost:/tmp/testdb.fdb || exit -1
fi

./testit
#⁠end of http://runit.sh

Commits: 0593719 a3757ab

@firebird-automations
Copy link
Collaborator Author

Commented by: Vitaly (v6y)

Just run http://runit.sh

@firebird-automations
Copy link
Collaborator Author

Modified by: Vitaly (v6y)

Attachment: syncerr.tgz [ 10414 ]

@firebird-automations
Copy link
Collaborator Author

Modified by: @hvlad

assignee: Vlad Horsun [ hvlad ]

@firebird-automations
Copy link
Collaborator Author

Commented by: @hvlad

Batch fetch code send op_fetch packet before finish processing of current packet. Therefore it often happens that this op_fetch packet received by the engine after all rows fetched. Egine responds with isc_req_sync which was hidden on old remote code and stay visible now.
Current solution is to receive all queued op_fetch packets immediately after EOF was detected.
More advanced solution is to not send op_fetch packet if current packed already contains EOF. This will remove one unneeded roundrtip

@firebird-automations
Copy link
Collaborator Author

Modified by: @hvlad

status: Open [ 1 ] => Resolved [ 5 ]

resolution: Fixed [ 1 ]

Fix Version: 2.1 Beta 1 [ 10141 ]

@firebird-automations
Copy link
Collaborator Author

Commented by: Vitaly (v6y)

Now (in my test I mean) the first next call of "isc_dsql_fetch", after this function already had returned 100 (all records were fetched), returned 0 code and status vector showed no error. Second call to this function returns 335544364 and this "request synchronization error" error, and the third "isc_dsql_fetch"' function call causes the firebird crashing. Things like that happened in QT3 IBASE SQL Driver (because QT SQL drivers supposed to be universal, this driver tryed several times to fetch records after any failure and crashed as result)

@firebird-automations
Copy link
Collaborator Author

Commented by: @hvlad

Sorry i not understand : are you said that

1000th call of isc_dsql_fetch returns 0 - is ok
1001th call of isc_dsql_fetch returns EOF (100) - is ok
1002th call of isc_dsql_fetch returns isc_req_sync (335544364L) - is ok
1003th call of isc_dsql_fetch crushed the server

?

@firebird-automations
Copy link
Collaborator Author

Commented by: Vitaly (v6y)

I said that:

1000th call of isc_dsql_fetch returns 0 - is ok
1001th call of isc_dsql_fetch returns EOF (100) - is ok
1002th call of isc_dsql_fetch returns 0 - again returns OK - I guess it is not ok
1003th call of isc_dsql_fetch returns isc_req_sync (335544364L) - I do not know is it ok
1004th call of isc_dsql_fetch crushed the server

The isc_dsql_fetch function called from QT3's QIBaseResult::gotoNext function. When fetch returned 100 this function returned false and QT3 call QIBaseResult::gotoNext to make shure that there are really no records to fetch . This time it returned true because isc_dsql_fetch returned 0 (QT supposed everything OK). On getting true it guessed that there still records remained to fetch and call gotoNext again. Now it returned false, because isc_dsql_fetch returned 335544364L and to make shure that no records it called gotNext and this time firebird with QT3 crashed.

To reproduce in Linux try use my test table an call isc_dsql_fetch 3 times more , after it already returned 100

P.S. Tested with build LI-T2.1.0.15956 Firebird 2.1 Beta 1

@firebird-automations
Copy link
Collaborator Author

Commented by: @hvlad

Additional patch is committed. Try build 15964 please

@firebird-automations
Copy link
Collaborator Author

Commented by: Vitaly (v6y)

Now it seemed to be Ok.

Thanks

@firebird-automations
Copy link
Collaborator Author

Modified by: @pcisar

status: Resolved [ 5 ] => Closed [ 6 ]

@firebird-automations
Copy link
Collaborator Author

Modified by: @hvlad

Link: This issue relate to CORE1651 [ CORE1651 ]

@firebird-automations
Copy link
Collaborator Author

Modified by: @pcisar

Workflow: jira [ 12284 ] => Firebird [ 14719 ]

@firebird-automations
Copy link
Collaborator Author

Modified by: @pavel-zotov

QA Status: No test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants