2017-12-17 9 views
1

데이터베이스에 연결하기 위해 pyodbc를 사용하는 응용 프로그램이 있습니다. 다른 db 엔진으로 실행할 수 있습니다. 이제 저는 그것을 Firebird에 적용하려고합니다. 내가 바인딩 parametres 처리하기 위해 기본 pyodbc 방법을 사용할 수 있습니다 (SQLite는 테스트, 사이베이스) 일부 DB 엔진파이어 버드에 연결하여 pyodbc를 사용하는 바인딩 매개 변수

:

cnxn = pyodbc.connect(connect_string, autocommit=True) 
cur = cnxn.cursor() 
sql = """DECLARE v_file_type_id INT; v_path varchar2(1024); v_md5 varchar2(32); 
     BEGIN 
     v_file_type_id := %d; 
     v_path := '%s'; 
     v_md5 := '%s'; 
     insert into files (file_type_id, path, md5) values (v_file_type_id, v_path, v_md5); 
     END;""" % (file_type_id, path, md5) 
cur.execute(sql) 
: Oracle의

cnxn = pyodbc.connect(connect_string, autocommit=True) 
cur = cnxn.cursor() 
cur.execute("insert into files (file_type_id, path, md5) values (?, ?, ?)", file_type_id, path, md5) 

나는 실행하는 특별한 SQL을 준비했다

첫 번째 방법은 Firebird에서 작동하지 않습니다. 오류 : pyodbc.IntegrityError: ('23000', '[23000] [ODBC Firebird Driver][Firebird]validation error for column FILE_TYPE_ID, value "*** null ***" (-625) (SQLExecDirectW)')가 표시됩니다.

오라클과 마찬가지로 전용 SQL을 준비하려고했지만 몇 가지 문제가 있습니다.

cnxn = pyodbc.connect(connect_string, autocommit=True) 
cur = cnxn.cursor() 
sql = """set term^; 
     execute block 
     as 
     declare v_file_type_id int = %d; 
     declare v_path varchar(1024) = '%s'; 
     declare v_md5 varchar(32) = '%s'; 
     begin 
     insert into files (file_type_id, path, md5) values (:v_file_type_id, :v_path, :v_md5); 
     end 
     ^
     set term ; ^""" % (file_type_id, path, md5) 
cur.execute(sql) 

작동하지 않습니다. 이번 오류는 pyodbc.Error: ('HY000', '[HY000] [ODBC Firebird Driver][Firebird]Dynamic SQL Error\nSQL error code = -104\nToken unknown - line 1, column 5\nterm (-104) (SQLExecDirectW)')입니다.

나는 어떤 해결책을 찾고있어, 그 두 가지 방법 중 하나로 그것을 실행할 수 있습니다. 성능 측면 또한 매우 중요합니다. 응용 프로그램이 자주 실행되지는 않지만 코드의 일부분이 약 15 만 개를 삽입 할 때마다 files 테이블에 삽입됩니다.

+1

파이어 버드가 실행하려고하는 실제 SQL을 보면 여기서 도움이 될 것입니다. SQL과 매개 변수를 전달할 때'pyodbc'에서 실행되는 실제 SQL을 볼 수있는 방법이 없습니다. Firebird에서 쿼리 로깅을 설정하고 오류의 원인이되는 SQL을 포함시킬 수 있습니까? – FlipperPA

답변

1

첫 번째 오류는 당신의 변수 file_type_id가 null 즉, 사실 당신이 FILE_TYPE_ID라는 not null 열로 null 값을 삽입하는에 의해 발생하고, 이것은 컬럼의 제약 조건에 의해 허용되지 않습니다, 또는 뭔가 다른입니다 잘못되어가는. 내가 파이썬 또는 DB-API와 아무것도 않았기 때문에

그것은 잠시왔다,하지만 지금까지 내가 기억으로, 당신이 실행하는 방식은 잘못된 것입니다 :

cur.execute("insert into files (file_type_id, path, md5) values (?, ?, ?)", file_type_id, path, md5) 

될 (의 사용을주의해야 튜플)

cur.execute("insert into files (file_type_id, path, md5) values (?, ?, ?)", (file_type_id, path, md5)) 

두 번째 오류가 set term가 유효한 파이어 버드 SQL 문이 아닌 사실에 의해 발생, 그것은 문 터미네이터를 전환하는 클라이언트 도구에 대한 진술이다, 또한 firebird procedural query throwing "token unknown" error at "SET TERM #;"

참조

Execute 블록은 익명의 'stored'프로 시저이며 일반적으로 이런 식으로 준비된 명령문을 실행하는 데 사용되지 않습니다. 실행 블록을 사용하면 문자열 형식을 사용하기 때문에 SQL 삽입 작업을 수행 할 때 특히 안전하지 않습니다. 실행 블록으로 인해이 양식은 '정상'구문을 실행하는 것보다 위험합니다.

파이썬 용 Firebird 데이터베이스 드라이버가 여러 개 있는데, FDBpyfirebirdsql이므로 ODBC를 사용할 필요가 없습니다.

+0

사실, pyodbc는 튜플로 전달되는 매개 변수 값을 필요로하지 않습니다 (ref : [here] (https://github.com/mkleehammer/pyodbc/wiki/Features-beyond-the-DB-API#passing-parameters)). –

+0

예, 첫 번째 오류는 'null'값을 허용하지 않는 열에 넣으려는 시도에 대해 말합니다. 하지만'file_type_id'는'null'이 아니므로,'cur.execute (...)'바로 전에 값을 출력 할 수 있습니다. 또한'connect_string'을 sqlite 또는 Sybase 데이터베이스로 변경하면 같은 코드가 작동합니다.나는 매개 변수를 전달하는 두 가지 방법을 시도했다. (위에서 쓴 것처럼) 직접적으로. 이 경우 둘 다 작동하지 않습니다. 나는 처음부터 끝까지'set term' 부분을 제거했고, 이제 작동합니다. 나는 잠재적 인 위험을 이해합니다. 당신의 도움을 주셔서 감사합니다. – Yama

+0

@Yama 흠, ODBC 드라이버의 버그를 제안합니다. Firebird ODBC 드라이버 2.0.5를 사용하고 있습니까? –

관련 문제