Kako gonilnik prevaja stavke
graph TD
A["Stavek SQL aplikacije (Access, ADO.NET, VBA)"] --> B{"Ali ga je mogoče izraziti kot zahtevo OData?"}
B -->|da| C["Zahteva OData storitvi: $select, $filter, $orderby, $top, $skip, $count, $apply, POST/PATCH/DELETE"]
B -->|ne| D{"Ali povezava ali storitev navaja naslov za lastne stavke?"}
D -->|da| E["Nespremenjeno podatkovni zbirki (prepustna pot, z vezanimi vrednostmi)"]
D -->|ne| F["Zavrnjeno s SQLSTATE 42000 in sporočilom, ki navaja razlog"]Gonilnik sam ničesar ne izračuna. Vsak stavek se prevede v zahtevo OData, posreduje podatkovni zbirki ali zavrne – nikoli ne naloži cele tabele, da bi lokalno filtriral, združeval v skupine ali združeval tabele. To pojasnjuje, zakaj poizvedba v Accessu z eno storitvijo deluje, z drugo pa se konča z „ODBC–call failed“.
Ključne funkcije
- Branje, filtriranje, razvrščanje in štetje na storitvi. Pogoji, razvrščanje, izbira stolpcev in
COUNT(*)se storitvi pošljejo kot poizvedbene možnosti; prenesejo se samo ustrezne vrstice. - Urejanje kot pri tabeli SQL Serverja.
INSERT,UPDATEinDELETEiz podatkovnega lista in obrazca postanejoPOST,PATCHinDELETE, z zaznavanjem konfliktov pri pisanju prekIf-Match. - Vsote in skupine brez prepustne poti, če storitev podpira združevanje v skupine.
- Listanje z
OFFSET … FETCHkot v SQL Serverju. - Dolgi pogoji v telesu namesto v naslovu.
- Vse drugo se pošlje nespremenjeno podatkovni zbirki, če je to mogoče – sicer jasna zavrnitev namesto napačnega rezultata.
Osnovni pojmi
Prevedeno
| Aplikacija pošlje | Gonilnik vpraša storitev |
|---|---|
SELECT a, b FROM t WHERE x = ? ORDER BY a | GET t?$select=a,b&$filter=x eq …&$orderby=a |
… WHERE x LIKE '%Keller%' | $filter=contains(x,'Keller') (prav tako x% → startswith, %x → endswith) |
… WHERE Nr IN (?, ?, …) | veriga pogojev or: Nr eq … or Nr eq … |
SELECT COUNT(*) FROM t WHERE … | GET t/$count?$filter=… – brez nalaganja vrstic |
… ORDER BY a OFFSET 500 ROWS FETCH NEXT 200 ROWS ONLY | $orderby=a&$skip=500&$top=200 |
SELECT g, SUM(x) FROM t GROUP BY g HAVING … | $apply=groupby((g),aggregate(x with sum as …))&$filter=…, samo če storitev podpira $apply |
SELECT … WHERE Ključ = ? | $filter=Ključ eq … – branje vedno poteka prek množice, nikoli prek naslova ključa |
INSERT INTO t … | POST t |
UPDATE t SET … WHERE Ključ = ? AND RazličicaVrstice = ? | PATCH t(…) z If-Match |
DELETE FROM t WHERE Ključ = ? AND RazličicaVrstice = ? | DELETE t(…) z If-Match |
UPDATE/DELETE tabele brez ključa prek vseh starih vrednosti | vezani dejanji UpdateByOriginal/DeleteByOriginal, če ju storitev podpira |
Naslov, ki bi postal daljši od MAXURLLENGTH, se pošlje kot POST …/$query z možnostmi v telesu. Popolna
pravila so v
Podprti SQL: združevanje v skupine in povzemanje
in Podprti SQL: branje po straneh z OFFSET/FETCH.
Posredovano
Kar ni mogoče prevesti – spoj dveh tabel, podpoizvedba, sprememba mnogih vrstic, stavek sheme,
računanje med agregati –, gonilnik nespremenjeno pošlje na naslov za lastne stavke. Vezane vrednosti
ostanejo vrednosti: iz označb mesta ? nastanejo poimenovani parametri. Stolpce rezultata opiše
storitev, gonilnik tipov ne ugiba.
Naslov navede bodisi povezava (PASSTHROUGH) bodisi storitev v svojem dokumentu metapodatkov.
Ali se stavek sme izvesti, odloči storitev, ne gonilnik; gonilnik ga ne preverja in ne razvršča.
Zakaj, je pojasnjeno v
Varnostni model in meje zaupanja;
nastavitev pa v Nastavitev prepustnih poizvedb.
Izjema: stavke nad tabelami s predpono MSys – sistemskimi tabelami aplikacije, na primer poizvedba
Accessa po MSysConf ob vsaki povezavi – gonilnik zavrne sam. V storitvi jih ni, Access pa pričakuje
natanko ta odgovor.
Zavrnjeno
Brez naslova za lastne stavke gonilnik vse, česar ni mogoče prevesti, zavrne s SQLSTATE 42000.
Access to prikaže kot napako 3146 „ODBC–call failed“ in poizvedbe nato ne izračuna
sam – tudi ne vsot in spojev, ki bi jih pri lokalni tabeli zmogel sam. Glejte
"ODBC--call failed" pri vsotah ali spojih.
Namesto približnega prevoda se zavrnejo – oziroma z naslovom za lastne stavke posredujejo – tudi:
LIKE z _ ali
razredom znakov ([a-c]), funkcije zunaj SUM, MIN, MAX, AVG, COUNT v združevanju v
skupine, spreminjanje ali brisanje tabele brez različice vrstice prek starih vrednosti vseh
stolpcev, če storitev zanjo ne deklarira ne lastnosti sočasnosti ne dejanj za tabele brez ključa.
Razlog je vedno isti: tiho poenostavljen stavek bi vrnil drugačen rezultat, ki bi bil videti kot
pravilen odgovor.
Transakcije
Vsak stavek je svoja zahteva storitvi. V transakcijo jih gonilnik združi samo, če storitev podpira
transakcije:
v tem primeru v $metadata navede naslov Store.Transactions (podatkovni prehod Wkl.Data.Gateway to
stori).
| Storitev | SQL_TXN_CAPABLE | Samodejna potrditev izklopljena (BeginTrans, BeginTransaction) |
|---|---|---|
s Store.Transactions | SQL_TC_ALL, izolacija READ COMMITTED | Ob prvi zahtevi gonilnik odpre transakcijo na storitvi; vsaka nadaljnja zahteva povezave – branje, pisanje, lastni stavki – se izvede v njej in vidi njene lastne, še neshranjene spremembe. SQLEndTran jih shrani ali zavrže; prekinitev povezave jih zavrže |
| brez | SQL_TC_NONE | HYC00 namesto navidezno odprte transakcije |
Access in DAO se samo po SQL_TXN_CAPABLE odločita, ali BeginTrans posredujeta gonilniku. Če storitev
transakcij ne podpira, transakcijo obdržita zase: vsaka sprememba je takoj shranjena na storitvi,
Rollback pa tam ničesar ne razveljavi – brez napake. Z njimi se koda VBA z
BeginTrans/Rollback vede kot prek gonilnika SQL Serverja: Rollback razveljavi spremembe,
nove zapise in poizvedbe za posodobitev, CommitTrans jih shrani, napaka enega stavka pa
transakcijo pusti odprto.
Razlike od gonilnika SQL Serverja: transakcija na storitvi uporablja lastno povezavo; če je aplikacija
nekaj časa ne uporablja, jo storitev razveljavi, CommitTrans pa v tem primeru javi 40001 – nič od tega
ni shranjeno. Kako dolgo storitev čaka, določi sama; pri podatkovnem prehodu Wkl.Data.Gateway sta
to privzeto dve minuti.
Pred uporabo preverite, ali transakcije delujejo
Če se aplikacija zanaša na Rollback – na primer postopek, ki skupaj ustvari glavo in postavke –,
to preverite s storitvijo, na kateri naj bi se izvajala:
- Poizvedite po zmožnosti: v DAO
CurrentDb.OpenRecordset("<povezana tabela>").Transactions(mora bitiTrue), v ODBCSQLGetInfo(SQL_TXN_CAPABLE)(mora bitiSQL_TC_ALL). - Preizkusite na preizkusni vrstici:
BeginTrans, spremenite vrstico,Rollback, znova preberite vrstico. Imeti mora staro vrednost.
Če je v 1. koraku False, Rollback na storitvi ničesar ne razveljavi, brez napake. Postopek, ki
sme več zapisov shraniti samo skupaj, v tem primeru spada v proceduro podatkovne zbirke, ki jo aplikacija
kliče prek prepustne poti, ali pa potrebuje storitev s transakcijami.
Kaj se zgodi pri napakah
| Primer | Rezultat | Kaj mora storiti aplikacija |
|---|---|---|
| Stavek v transakciji ne uspe (na primer kršen ključ) | Stavek javi napako; transakcija ostane odprta, druge spremembe v njej ostanejo – kot prek gonilnika SQL Serverja | sama odloči: Rollback ali shranjevanje drugih s CommitTrans |
| Storitev je transakcijo razveljavila (nedejavnost, neuporabna transakcija) | CommitTrans javi 40001; nič ni shranjeno | postopek začne znova |
Povezava se prekine med CommitTrans | 08S01. Gonilnik zaključka ne ponovi: ni znano, ali je bilo shranjeno | znova prebere zadevne zapise; če zaključek ni prispel do storitve, storitev transakcijo razveljavi po svojem času nedejavnosti |
Povezava se prekine med Rollback | 08S01; nič se ne shrani, ker storitev odprto transakcijo razveljavi najpozneje po svojem času nedejavnosti | nič; zapisi so po izteku časa nedejavnosti spet prosti |
| Storitev ne podpira transakcij | ADO.NET: HYC00 pri BeginTransaction; DAO/Access: vsaka sprememba je takoj shranjena, Rollback ostane brez učinka | glejte preverjanje zgoraj |
Sporočila podatkovne zbirke
Če podatkovna zbirka stavek zavrne in storitev pošlje njena sporočila (error.details s številko
sporočila kot code, tako podatkovni prehod Wkl.Data.Gateway), jih gonilnik javi kot gonilnik SQL
Serverja: en diagnostični zapis na sporočilo, številka sporočila kot izvorna številka napake in
SQLSTATE, ki ga storitev navede zraven (23000 za kršen ključ, sklic ali obvezno vrednost, 22001
za predolgo vrednost, 01000 za spremljajoče opozorilo).
| Aplikacija | vidi |
|---|---|
| Access, okno s sporočilom | besedilo prvega sporočila, za njim njegovo številko: … (#547) |
| VBA/DAO | DBEngine.Errors(0).Number = številka sporočila, .Description = besedilo; zadnji vnos je kot vedno napaka Accessa (3146) |
| ADO.NET | OdbcException.Errors[i].NativeError in .SQLState |
Koda, ki pri neposredni povezavi ravna glede na številko (If DBEngine.Errors(0).Number = 2627 Then),
tako deluje nespremenjena. Besedilo storitev posreduje samo, če ne navaja ničesar, česar klicatelj ne
sme videti; sicer je tam besedilo storitve, številka in SQLSTATE pa se kljub temu ujemata. Brez
details gonilnik javi en sam zapis s statusom HTTP kot številko.
Zakaj tako: preučene alternative
Razdelitev na prevajanje, posredovanje in zavračanje je odločitev pri zasnovi. Tri alternative bi pravilnost, stroške ali varnost porazdelile bistveno drugače:
| Alternativa | Kaj bi prinesla | Zakaj je zavržena |
|---|---|---|
| Lokalno računanje: gonilnik naloži vrstice in sam filtrira, združuje v skupine ali združuje tabele | Vsaka poizvedba bi delovala, tudi s storitvijo brez združevanja v skupine in brez prepustne poti | Stroški rastejo s tabelo, ne z rezultatom, in ostanejo nevidni, dokler tabela ni velika. Poleg tega bi gonilnik računal po svojih pravilih za vrstni red razvrščanja, NULL in zaokroževanje, ne po pravilih podatkovne zbirke – rezultat bi brez opozorila odstopal |
| Samo posredovanje: vsak stavek se pošlje nespremenjen podatkovni zbirki | Polni jezik SQL podatkovne zbirke, brez pravil prevajanja | Gonilnik bi bil vezan na storitev, ki ponuja tak naslov, in na njeno narečje SQL; vsak klicatelj bi potreboval pravico za izvajanje lastnih stavkov. Posredovan stavek se poleg tega prebere v celoti, brez naslednjih strani |
| Samo prevajanje, vse drugo zavrniti | Nobene poti mimo pravil storitve | Access po zavrnitvi ne računa sam, tudi če SQLGetInfo zmožnost zanika. Spoji in vsote prek povezanih tabel ne bi v tem primeru nikoli uspele |
Izbrana oblika združuje zadnji dve: kar je mogoče izraziti kot zahtevo OData, deluje z vsako
storitvijo OData v4 in pod njenimi pravili za vsako tabelo; samo preostanek potrebuje naslov za lastne
stavke. Njena cena: poizvedba, ki je ni mogoče izvesti po nobeni od obeh poti, vidno ne uspe, namesto da
bi se izvajala počasi ali nenatančno. Prav tako je zavrženo približevanje posameznih sestavin, na primer
LIKE 'a_c' kot contains; razlog je opisan v razdelku Zavrnjeno.
Sorodne teme
- Varnostni model in meje zaupanja – kdo dovoli posredovan stavek