10.5 Çalışma kipi ve dil çevirisi

<< İçindekileri Görüntülemek İçin Tıklayın >>

Yer:  Teknik Kılavuzlar > IVEDI SQL Kullanıcı Kılavuzu > 10. Önişlemci >

10.5 Çalışma kipi ve dil çevirisi

#MODE PRECOMPILE
#MODE EXECUTE
#MODE CONVERT TO {STANDARDSQL | FIREBIRD | POSTGRESQL | CSHARPORM} [STRICT]
KipAnlamı
PRECOMPILEYalnız metin üretir, hiçbir şey çalıştırmaz
EXECUTENormal motor
CONVERT TO <hedef>Deyimleri o lehçenin metni olarak yeniden üretir
CONVERT TO <hedef> STRICTAynısı, ama yoruma indirilen her yapı hata verir

STRICT yalnız o yönergenin parçasıdır: yazılmayan bir #MODE CONVERT TO <hedef> onu kaldırır; #MODE EXECUTE ve #MODE PRECOMPILE de kaldırır.

Kip kilidi

Bağlantının kipini onu kuran katman belirlemişse (dil sunucusu bağlantısı gibi) istemciden gelen metin kipi değiştiremez: kipi değiştiren bir #MODE hata verir, bağlantının zaten içinde olduğu kipi isteyen yönerge ise etkisiz kalır. #MODE PRECOMPILE kilitli bağlantıda her zaman reddedilir.

CONVERT TO kipi, aynı SQL'i başka bir motora taşımanın yoludur. Örnek:

#mode convert to postgresql

execute block
as
  i integer;
begin
  i = 5;
  i = i + 1;
end;

çıktısı:

do
$execute_block$
<<v_>>
declare
  i integer;
begin
  v_.i = 5;
  v_.i = v_.i + 1;
end
$execute_block$
;
Hedeflerin durumu

POSTGRESQL ve FIREBIRD üretilen ve doğrulanan hedeflerdir: ikisinin de çıktısı gerçek bir sunucuda koşturularak sınanır. STANDARDSQL metin üretir ama bir sunucuda sınanmaz. CSHARPORM ayrıştırıcı tarafından kabul edilir ama koşucuları yoktur.

Firebird'e özgü: şema yoktur (Firebird 5), bu yüzden adlar şemasız üretilir ve CREATE SCHEMA çevrilemez; LOCAL TEMPORARY tablo GLOBAL TEMPORARY olarak üretilir; ON COMMIT DROP karşılıksızdır ve hata verir.

Çevrilemeyen işlevsel kod

Hedef lehçede karşılığı olmayan bir işlevsel deyim sessizce geçilmez. Ham metin geçişinde bir uyumsuzluğu hedef veritabanının kendisi yakalar; çevrimde araya motor girer ve işleyen bir komutu yoruma çevirmek, o uyumsuzluğu ikisinin de yakalayamayacağı tek yer hâline getirir. Hedefe göre değişen kod NATIVE_SQL(POSTGRESQL '…', FIREBIRD '…') ile, yalnız IVEDI'de anlamlı olan nesne ATTRIBUTES (IVEDI_ONLY = TRUE) ile yazılır.

Deyimin hangi sınıfa girdiği çıktıyı belirler:

  • Karşılığı hiç olmayan yapılar her zaman hata verir: Firebird'de CREATE/ALTER/DROP SCHEMA ve ON COMMIT DROP, üretilmeyen hedeflerde CREATE COLLATION.
  • Yoruma indirilen işlevsel yapılar (örneğin PostgreSQL'de CREATE EXCEPTION, CREATE PACKAGE, IN AUTONOMOUS TRANSACTION, ALTER USER … PASSWORD, SET CATALOG, CONNECT) öntanımlı olarak yorum olarak geçer; STRICT ile hata verir ve hiçbir metin üretmez. Hata SQLSTATE 0A000 ile gelir ve neyin kaybolduğunu söyler.
  • IVEDI'ye özgü deyimler sessizce atlanır, STRICT olsun olmasın: yorum yazılmaz, hata verilmez. Bunlar IVEDI'ye özgü meta veri (SET ATTRIBUTES, COMMENT … FOR LOCALE, BEGIN/END LEVEL, CREATE SYNONYM) ve nesnesi IVEDI_ONLY olan her deyimdir.
  • Çevrim anında bulunamayan bir nesnenin DROP … IF EXISTS'i yorum olarak geçer; STRICT ile hata verir.

NET.HttpServerRequest / NET.HttpServerResponse — uç yordamının imzası

Bir ENDPOINT (bkz. ENDPOINT — HTTP uçları) CONTENT RAW kipinde function f(request NET.HttpServerRequest) returns NET.HttpServerResponse ya da procedure p(request NET.HttpServerRequest) returns (response NET.HttpServerResponse) imzalı bir yordamı çağırır.

ÜyeAnlamı
HttpServerRequest.method, path, hostİstek yöntemi, işlemci kökünden sonraki yol (ENDPOINT PATH ile aynı), Host başlığı.
query, headers (json)Sorgu parametreleri ve başlıklar {"ad": "değer"}; başlık adları küçük harf. Param(ad) ve Header(ad) (harf duyarsız) tek değeri verir.
remoteIp, contentType, userNameİstemcinin IP'si, istek gövdesinin türü, LOGIN / ROLE uçlarında doğrulanan login (anonimde NULL).
body, bodyBlob, BodyJson(), BodyJsonOrEmpty()Metin gövde (JSON, XML, form), ikili gövde (application/octet-stream gibi türler), gövdenin JSON olarak okunmuş hali (OrEmpty: boş ya da bozuk gövdede {}).
Field(ad)JSON gövde alanı, yoksa form alanı, yoksa sorgu parametresi (harf duyarsız).
HttpServerResponse.status (200), contentType, headers, body, bodyBlobYanıt oldugu gibi yazılır: durum kodu, Content-Type, ek başlıklar, metin ya da ikili gövde.
Json(gövde, durum), Text(metin, tür, durum), FromBlob(blob, tür, durum), Error(durum, ileti)Statik kurucular; Error {"result": false, "message": …} gövdesini kurar.
SetHeader(ad, değer)Yanıt başlığı yazar / değiştirir; NULL değer siler (NET.http_set_header).
Unauthorized([şema])401 ve WWW-Authenticate: Bearer (ya da verilen şema) başlıklı yanıt. NET.Http.BearerToken(request) başlıktaki belirteci, BearerClaims(request, anahtar) doğrulanmış JWT gövdesini verir (yoksa NULL).

NET.Cache — bitiş zamanlı anahtar / değer önbelleği

Dış servis köprülerinin süreç belleğinde tuttuğu şeylerin motor karşılığı (ajanın işçileri ayrı süreçlerdir, istekler arası paylaşılan bellek yoktur): oturum anahtarı önbelleği, tek kullanımlık değer (OAuth state → kod), iş anahtarına göre sayaç. Sistem tablosu ivd$net_cache; yazımlar otonomdur (çağıranın işlemi geri alınsa da kalır), süresi dolan satırlar yazımda silinir. Değer metindir (JSON dâhil).

ÜyeAnlamı
NET.Cache.Get(anahtar)Değer; anahtar yoksa ya da süresi dolmuşsa NULL.
NET.Cache.Put(anahtar, değer, ttlSaniye)Yazar ya da değiştirir; ttlSaniye <= 0 siler.
NET.Cache.Remove(anahtar)Siler.
NET.Cache.Increment(anahtar, ttlSaniye)Sayaç: penceredeki ilk çağrı 1 yazar (bitiş = şimdi + ttl), sonrakiler 1 artırır; artırılmış değeri döndürür.
NET.Cache.Allow(anahtar, sınır, pencereSaniye)Increment sonucu sınırı aşmıyorsa TRUE (istek sınırı); anahtar ya da sınır NULL ise her zaman TRUE.

Depo tek bağlantılı olan veritabanında (sqlite) otonom yazım, oturumun kendi işlemi geri alınırsa onunla birlikte gider: depodaki iç işlemin bir sahibi vardır, öteki işlemler onun içinde kayıt noktasıdır. Yordamdan Put çağıran bir msql oturumu sonunda COMMIT verir; uç yordamları zaten işlemci tarafından commit edilir.

tok = NET.Cache.Get('GibAuthToken_' || kullanici);
if (tok is null) then
begin
  tok = json_value(NET.Http.PostJson(url, json_object('username', kullanici, 'password', parola)).body, '$.token');
  NET.Cache.Put('GibAuthToken_' || kullanici, tok, 19800);          --// 5,5 saat
end
if (NET.Cache.Increment('RateLimit_' || vkn || '_' || saat, kalanSaniye) > 8) then
  return NET.HttpServerResponse.Json(json_object('isSuccess', false, 'errorMessage', 'saatlik sınır'), 429);

NET servis ve işlem tanımları — ivd$net_service / ivd$net_operation ve NET.Http.Invoke

Bir dış HTTP servisi kodla değil satırla tanımlanır: sys.ivd$net_service servisi (taban URL ya da credential'ın BASEURL etiketi, giriş biçimi, giriş şablonları, belirteç yolu ve süresi, varsayılan başlıklar, zaman aşımı), sys.ivd$net_operation her işlemi (yöntem, yol ve sorgu şablonu, gövde kipi ve şablonu, yanıt kipi, Accept) tutar. Şablonlardaki {ad} yer tutucuları çağrı parametrelerinden (JSON nesnesi) doldurulur: yol ve sorgu değerleri yüzde kodlanır, JSON şablonunda dizge kaçışlanır, sayı ve mantıksal olduğu gibi yazılır, eksik ya da NULL alan boş kalır.

Kolon / üyeAnlamı
ivd$auth_kindNONE (başlık yok), CALLER_BEARER (çağrı parametresi token), JSON_LOGIN (POST JSON gövde), FORM_CLIENT_CREDENTIALS (POST form), QUERY_CLIENT_CREDENTIALS (POST, parametreler sorgu dizisinde).
ivd$auth_path, ivd$auth_headers, ivd$auth_bodyGiriş isteğinin yolu, başlık ve gövde şablonları (JSON).
ivd$auth_ok_path / ivd$auth_ok_value, ivd$token_path, ivd$token_ttl_secGiriş yanıtında başarı denetimi (JSON yolu ve beklenen değer), belirtecin JSON yolu, NET.Cache'te tutulma süresi (0 = tutulmaz).
ivd$body_kindNONE, PARAM (çağrı parametresi body, türü contentType), TEMPLATE (ivd$body_template doldurulur), FORM (şablon form alanları).
ivd$response_kindTEXT (body) ya da BINARY (bodyBlob).
NET.Http.Invoke(servis, işlem, parametreler [, belirteç])İşlemi çağırır, ham NET.HttpResponse döner. Belirteç: argüman, yoksa parametre token, yoksa ServiceToken.
NET.Http.ServiceToken(servis, parametreler)Servisin oturum belirteci: önbellekten ya da girişle (ServiceLogin); önbellek anahtarı servis + parametre cacheKey ya da username. InvalidateServiceToken düşürür (401 sonrası).
NET.Http.ServiceLogin(servis, parametreler), ServiceBaseUrl(servis, parametreler)Giriş isteğinin ham yanıtı; doldurulmuş taban URL.
NET.url_encode(s), NET.fill_template(şablon, parametreler, kip), NET.build_url(taban, yol, sorguŞablonu, parametreler)Yüzde kodlama (RFC 3986); şablon doldurma (kip raw | json | url); taban + yol + sorgu dizisi (taban ham, yol ve sorgu yüzde kodlu; sorgu şablonu metindir, sırası korunur).
NET.credential_info(ad)Credential'ın sır olmayan alanları: {"name", "type", "subType", "identity", "tags": {...}}; parola hiç dönmez.
NET.Http.MaskSecrets(jsonMetni [, alanlar])Günlüğe yazmadan önce JSON'daki parola alanlarını (PASSWORD; virgülle başka adlar, harf duyarsız, iç içe) *** yapar; anahtar yazıldığı gibi kalır.
insert into sys.ivd$net_service (ivd$service_name, ivd$credential_name, ivd$auth_kind, ivd$auth_path, ivd$auth_headers,
  ivd$auth_body, ivd$auth_ok_path, ivd$auth_ok_value, ivd$token_path, ivd$token_ttl_sec)
  values ('GIB_EBELGE', 'gib_ebelge', 'JSON_LOGIN', 'auth/login', '{"username": "{credential:gib_ebelge.identity}"}',
          '{"username": "{username}", "password": "{password}"}', '$.authenticationStatus', 'AUTHENTICATED', '$.token', 19800);
insert into sys.ivd$net_operation (ivd$service_name, ivd$operation_name, ivd$http_method, ivd$path, ivd$body_kind, ivd$accept)
  values ('GIB_EBELGE', 'invoice_list', 'POST', 'other/earsiv/adimaDuzenlenen', 'PARAM', 'application/json');

resp = NET.Http.Invoke('GIB_EBELGE', 'invoice_list', json_object('username', kullanici, 'password', parola, 'body', istekGovdesi));
if (resp.status = 401) then NET.Http.InvalidateServiceToken('GIB_EBELGE', json_object('username', kullanici));

10.5.1 ENDPOINT — HTTP uçları (REST işlemcisi)

ENDPOINT bir HTTP yöntemi ve yolunu bir PSQL yordamına bağlayan katalog nesnesidir. Ajanın (ve dağıtım sunucusunun) REST işlemcisi, conf'ta verilen veritabanının uçlarını kataloğundan okur ve istek geldiğinde yordamı çağırır; uç COMMIT anında yayındadır, hizmet yeniden başlatılmaz. Nesne her zaman IVEDI_ONLY'dir, hedef yordam bağımlılık olarak yazılır (DROP PROCEDURE RESTRICT'te reddedilir, CASCADE ucu da düşürür).

create or alter endpoint app.turmob_values
  method POST path '/turmob/values'               --// aynı yol için yöntem başına bir nesne
  host '*'                                        --// sanal konak süzgeci (öndeğer '*')
  anonymous                                       --// | login (Basic, MASTER login'i + EXECUTE hakkı) | role <rol> (MASTER rolü)
  allow from ('212.133.164.87', '10.0.0.0/8')     --// IPv4, IPv4/CIDR, IPv6; uymayan 403
  rate limit 120 per minute by ip                 --// aşan 429 + Retry-After; RATE LIMIT NONE kaldırır
  content raw                                     --// raw: HttpServerRequest -> HttpServerResponse | dataset: FASTAPI biçimi
  as call app.nws_turmob.values_endpoint
  attributes ("doc.summary" = 'TÜRMOB mükellef bilgisi');
commit;

grant execute on app.turmob_values to app_role;   --// LOGIN kipi için
  • CONTENT RAW: yordam NET.HttpServerRequest alır, NET.HttpServerResponse döndürür; yanıt olduğu gibi yazılır (eski istemci sözleşmeleri — ham JSON dizisi, HTML, base64 PDF, SOAP — böyle korunur).
  • CONTENT DATASET: yordamın skaler parametreleri istek gövdesindeki JSON nesnesinden ve sorgu parametrelerinden adla bağlanır; sonuç kümesi (yordam) ya da tek değer (işlev, kolon VALUE) {"result": true, "metadata": {…}, "dataset": [[…]]} biçiminde döner (/crud/fastapi ile aynı; gövdede "metadata": false / "dataValueOnly": false seçenekleri).
  • Kimlik: ANONYMOUS kimliksiz koşar; LOGIN HTTP Basic ister, login motora itilir ve ucun EXECUTE hakkı aranır (sahip, SYSDBA, SYSADMIN ya da GRANT EXECUTE); ROLE rol Basic ve MASTER'daki rol üyeliğini ister. Kimliksiz / yanlış parola 401, haksız 403. Authorization: Basic değeri işlemcide kalır, yordama ulaşmaz; başka bir şema (Bearer <jwt>) ANONYMOUS uçta yordama gelir (request.Header('Authorization')), yordam onu NET.Http.JwtVerify ile kendisi doğrular.
  • Hata: yordamın yakalanmayan istisnası 500 ve genel bir ileti verir, ayrıntı ajanın günlüğündedir; bilinmeyen yol 404, yolu bilinen ama yöntemi başka istek 405 (Allow başlığıyla).
  • Katalog: IVD$V_ENDPOINTS görünümü (yöntem, yol, konak, kimlik kipi, rol, izinli adresler, sınır, içerik kipi, hedef, TARGET_ID, kaynak metin, doc.summary); seviye 4 paketiyle taşınır (UPGRADE LEVEL kod nesnesi gibi kaynağından kurar; hedef ad veritabanı adsız saklanır, paket başka adlı veritabanına da kurulur). Seviye 4 paketi, ürün domain'leriyle (ft*) tanımlı seviye 4 tablosunun domain satırlarını ad çözümlemesi için taşır; EKLENTI şemasındaki paket derlendiği andaki arama yoluyla (NETSIM görünümleri) yeniden derlenir.
  • Yönetim: ajanın "WS Uç Noktaları" sayfasının "Motor uçları" sekmesi listeler ve test isteği gönderir.

10.5.2 IVEDI_ONLY nesneler

ATTRIBUTES (IVEDI_ONLY = TRUE) ile yaratılan yordam, işlev, tetikleyici, görünüm, paket ve nesne tipi yalnız IVEDI kataloğunda yaşar ve yalnız IVEDI motoru tarafından kullanılır:

  • depoya DDL'i inmez: Firebird / PostgreSQL / ODBC veritabanında fiziksel karşılığı yoktur;
  • metin çevriminde (#MODE CONVERT TO …, STRICT dâhil) onu yaratan, değiştiren, düşüren, yorumlayan ya da ona hak veren deyimler ve ona başvuran üst düzey deyimler (EXECUTE PROCEDURE, SELECT, INSERT …) hiç yazılmaz;
  • EXECUTION STORAGE veritabanında da motor çalıştırır: çağrı depoya devredilmez; IVEDI_ONLY tetikleyici, satırı IVEDI yazdığında tetiklenir (depoya doğrudan bağlanan istemcide tetiklenmez);
  • VERIFY LEVEL onu doğrulamaz, sayısını bir NOT satırında bildirir.
create function kdv_orani(tarih date) returns numeric(5,2) attributes (ivedi_only = true) as
begin
  return 20;
end;

create procedure fiyat_hesapla(tutar numeric(18,2)) returns (sonuc numeric(18,2))
  attributes (ivedi_only = true) as
begin
  sonuc = tutar * (1 + kdv_orani(current_date) / 100);
  suspend;
end;

create view v_ozet (id, toplam) attributes (ivedi_only = true) as select id, tutar from siparis;

create trigger siparis_iz for siparis after insert attributes (ivedi_only = true) as
begin
  insert into siparis_log (id) values (new.id);
end;

create package yardimci attributes (ivedi_only = true) as
  function kisalt(s varchar(100)) returns varchar(20);
end;

Yazım yeri: yordam ve işlevde parametre ve RETURNS'ten sonra, görünümde AS'tan önce, tetikleyicide olaydan sonra, paket ve nesne tipinde addan sonra. Nitelik öznitelik tablosunda değil, nesnenin tip bayrağında (IVD$TYPE_FLAGS, 0x00200000) tutulur. Bir paketin ya da tipin üyeleri ve bir görünümün tetikleyicileri sahibinin niteliğini taşır.

Kurallar (derlemede denetlenir, reddedilen nesne kataloğa girmez):

  • Tablo, domain, istisna, dizi, harmanlama, kolon ve parametre IVEDI_ONLY olamaz; bunlar her zaman depoya gider (IVEDI_ONLY_NOT_ALLOWED, SQLSTATE 0A000).
  • IVEDI_ONLY olmayan bir nesne IVEDI_ONLY bir nesneye başvuramaz, çünkü depoda ve çevrilmiş metinde o nesne yoktur (IVEDI_ONLY_REFERENCE, SQLSTATE 0A000). Ona başvuran nesne de IVEDI_ONLY yapılır.
  • Nitelik SET ATTRIBUTES ile açılıp kapatılamaz; yeniden tanımda (CREATE OR ALTER, ALTER … AS) ATTRIBUTES (IVEDI_ONLY = TRUE) yeniden yazılır. Nesnenin nerede yaşadığını değiştirmek için nesne düşürülüp yeniden yaratılır.
Firebird ve SET TERM

Bir PSQL gövdesi ; içerir; bu yüzden isql'e verilecek bir dosyada deyim sonlandırıcısı değiştirilir. SET TERM IVEDI'nin tanıdığı bir deyimdir: kaynakta yazılır, Firebird hedefinde karşılığı üretilir. Üretilen metin de onu izler: SET TERM ^ ; yazıldıktan sonraki deyimler ^ ile biter. Kural isql'inkiyle aynıdır: SET TERM deyiminin kendisi eski sonlandırıcıyla biter.

set term ^ ;
create procedure p1(x integer) returns (n integer) as begin n = x + 1; suspend; end^
set term ; ^
Adlar tırnaksız üretilir

Üretilen metinde nesne adları tırnaksız yazılır: PostgreSQL hedefinde küçültülerek, Firebird hedefinde olduğu gibi. Böylece üretilen metin, aynı ada tırnaksız atıfta bulunan elle yazılmış metinle yan yana durabilir; katlama her iki tarafta da aynı yönde çalışır. Tırnak yalnız ad tanımlayıcı olarak yazılamıyorsa (örneğin tire içeren tr-x-icu) ya da ayrılmış bir sözcükse konur.

10.5.3 Karşılığı olmayan deyimler

Bir deyimin hedef lehçede karşılığı yoksa sessizce düşmez: yerine, nedenini söyleyen bir yorum üretilir (STRICT ile hata). Böylece çevrilmiş betiği okuyan kişi neyin taşınmadığını görür. Aşağıdaki tablo, PostgreSQL hedefinin ne yaptığını özetler.

DeyimPostgreSQL çıktısı
ALTER SEQUENCEALTER SEQUENCE; bütün yan tümceler birebir
ALTER DOMAINALTER DOMAIN … SET/DROP DEFAULT | RENAME TO; SET ATTRIBUTES atlanır
ALTER VIEW … ASCREATE OR REPLACE VIEW (PostgreSQL'de gövdeyi ALTER VIEW değiştirmez); RENAME TO birebir; SET ATTRIBUTES atlanır
ATTRIBUTES ( … ) (her bildirimde), ALTER … SET ATTRIBUTESBildirimdeki öznitelikler üretilmez (IVEDI'ye özel, katalogda durur); yalnız SET ATTRIBUTES içeren ALTER atlanır
ALTER ROLE, ALTER SCHEMARENAME TO; AUTHORIZATION → OWNER TO
ALTER TRIGGER … ACTIVE|INACTIVEALTER TABLE … ENABLE|DISABLE TRIGGER (olay tetikleyicisinde ALTER EVENT TRIGGER)
ALTER TRIGGER … POSITION nALTER TRIGGER … RENAME TO: PostgreSQL'de konum özniteliği yoktur, aynı olayın tetikleyicileri ada göre alfabetik koşar; üretilen ad bu yüzden konumu beş basamakla içerir (<ad>_00010) ve konumu değiştirmek adı değiştirmektir
ALTER TRIGGER … RENAME TOİki deyim: tetikleyici ve gövdesini taşıyan fonksiyon ayrı ayrı yeniden adlandırılır
POST_EVENT '<ad>'NOTIFY "<ad>"; iki motorda da olay COMMIT'te teslim edilir. Parametreli biçim çevrilmez
CREATE TYPEYalnız üye değişkenlerden oluşan tip CREATE TYPE … AS (…) bileşik tipine çevrilir; metodu, kurucusu, iç içe tipi ya da INHERIT FROM'u olan tip yoruma çevrilir
ALTER USER … PASSWORDYorum: katalogda yalnız tuzlu SHA-256 özeti durur (SHA256:<tuz>:<hex>), düz metin parola üretilemez ve basılmaz
ALTER INDEX … ACTIVE|INACTIVEYorum: PostgreSQL'de bir dizin devre dışı bırakılamaz
CREATE PACKAGEYorum: PostgreSQL'de paket yoktur
CREATE DIRECTORY, CREATE CREDENTIALYorum: karşılığı yok
CREATE DATABASE LINKYorum: en yakın yapı postgres_fdw'dir ve tek deyimle kurulmaz
CREATE SYNONYMAtlanır: başvurular zaten derleyicide hedefe çözülür
SET CATALOG, SET NAMES, SET AUTODDL, SET SQL DIALECT, SET TERM, CONNECT, DISCONNECTYorum