<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Semernitskaya</title>
    <description>The latest articles on DEV Community by Semernitskaya (@semernitskaya).</description>
    <link>https://dev.to/semernitskaya</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F732341%2F545a80cb-2c18-463a-9d6c-51ae476aec81.jpg</url>
      <title>DEV Community: Semernitskaya</title>
      <link>https://dev.to/semernitskaya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/semernitskaya"/>
    <language>en</language>
    <item>
      <title>7 myths about Software Engineer work in 2022</title>
      <dc:creator>Semernitskaya</dc:creator>
      <pubDate>Tue, 31 May 2022 19:16:04 +0000</pubDate>
      <link>https://dev.to/semernitskaya/7-myths-about-software-engineer-work-in-2022-4mac</link>
      <guid>https://dev.to/semernitskaya/7-myths-about-software-engineer-work-in-2022-4mac</guid>
      <description>&lt;p&gt;In my article, I would like to discuss some myths about software engineer work that are considered to be true and can affect the confidence and self-esteem of people who are just starting their careers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disclaimer
&lt;/h3&gt;

&lt;p&gt;This list of myths is only my opinion and is based mainly on my experience and stories of engineers I know. Of course, we all have different backgrounds and career paths, so it's normal if my opinion is different from yours.&lt;br&gt;
The main goal of this article is to show people who are at the begging of their career in IT that some of their concerns/insecurities about themself are not true. Because the target audience for my article is beginners - some of my sentences can be pretty obvious to more experienced developers.&lt;br&gt;
The article's header contains the year (2022) to emphasize that some of my ideas do not apply to the past and probably won't be valid in the future (who knows?)&lt;/p&gt;

&lt;h2&gt;
  
  
  1. You don't need communication skills
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhd7t3mmsprrjd8edl8au.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhd7t3mmsprrjd8edl8au.jpg" alt="Image description" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's a common myth popularized by many movies about hackers: a software engineer is a recluse, who works alone, hates people, and is definitely a tech genius (we'll talk about it later). But the truth is that for many roles in IT companies nowadays you have to communicate with other human beings: discuss tasks and possible solutions with your team, collect business requirements, negotiate terms and priorities.&lt;br&gt;
The good news is that there are various roles and ways of working in different companies and even in different teams inside the same company, so you will be able to find a position that matches your level of sociability.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. It's a fancy job
&lt;/h2&gt;

&lt;p&gt;We all have seen inspiring photos of IT specialists working with their MacBooks in cozy cafes. We all have heard about big salaries, flexible hours and other perks. Is this all true? Yes, but it's challenging to get all these preferences when you are just starting your career and don't have significant experience and many projects in your CV. Sometimes you can get only some of these perks but not the others. &lt;br&gt;
If you are just at the beginning of your career journey, it's important to remember that it's completely normal to change companies and look for a perfect fit for you (money-wise, culture-wise, etc).     &lt;/p&gt;

&lt;h2&gt;
  
  
  3. You must love math
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fub63j29o77phjhoifhcm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fub63j29o77phjhoifhcm.jpg" alt="Image description" width="748" height="484"&gt;&lt;/a&gt;&lt;br&gt;
I love math, you probably love it too, or probably you hate math. In both cases, you can be a good software developer. &lt;br&gt;
Let me explain: it's well known that Computer Science is closely connected with math, but let's be honest, most software engineers don't use math in their day to day work; in addition, some companies can have separate departments that create and improve different math models and algorithms used in the company. So if you are good at math - that will be your strength for sure, but if you are not - there are many positions where you can work successfully without it.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. You must know algorithms (very well)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqohaz6sl75s3k3phmkd6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqohaz6sl75s3k3phmkd6.jpg" alt="Image description" width="800" height="463"&gt;&lt;/a&gt;&lt;br&gt;
Algorithm interview questions are a super controversial topic that causes a lot of debates among engineers. Some people argue that you can't be a good software developer without knowing all algorithms from &lt;a href="https://en.wikipedia.org/wiki/Introduction_to_Algorithms" rel="noopener noreferrer"&gt;Cormen's book&lt;/a&gt;, other think that algorithms are useless in day-to-day engineering work most of the time and how dare someone asks to rotate a binary tree during the interview.&lt;br&gt;
The truth, as usual, lies somewhere in the middle: there are some positions where a good knowledge of algorithms and their optimization are essential, and there are other job roles where you need entirely different skills to succeed. Usually, it's enough to have a basic understanding of different data structures and the complexity of some common algorithms.&lt;br&gt;
It is also important to remember that most of the algorithms are already implemented in libraries for many programming languages. So if, for example, you need to find the shortest path in a graph - you should start by searching for a library that allows you to represent your data in the form of a graph and has all the algorithms you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Your work has to be your hobby
&lt;/h2&gt;

&lt;p&gt;There are many posts from people who are writing their own mobile apps or other pet-projects in their free time as a hobby. Sometimes such side projects can become successful businesses and primary income sources for the developers. However, even if you can't earn money from your pet-projects - they are always an excellent way to study something and try technologies you want to try. &lt;br&gt;
But your pet-projects or other studying activities should not necessarily be your hobby and things you do to relax and have a rest. If you need to spend time with your family or walk with your dog in the park or binge watch some crazy anime series on Netflix (guilty) to feel rested - just do it. You can always have dedicated time that you spend on self-development, reading tech articles and learning new frameworks. &lt;br&gt;
Do not try to convince yourself that this is your hobby if it is not, otherwise you may soon face burnout or even depression.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. You have to be a young prodigy
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8uymgj6yayhm539mdih.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8uymgj6yayhm539mdih.gif" alt="Image description" width="400" height="225"&gt;&lt;/a&gt;&lt;br&gt;
You've probably heard career stories from people who started their career at 13 as a software developer, wrote their first compiler at 16 and became CTO of a successful startup in their 20s. I genuinely believe that they are super talented people passionate about their job. &lt;br&gt;
However, if you have a longer career path or if you realised what you would like to do in your life much later - this is also completely normal and doesn't make you a bad specialist. We all have different life experiences. So it's okay if as a teenager you wanted to be a rock star instead of trying to hack your school website or writing your first computer game - you still can become a great professional.   &lt;/p&gt;

&lt;h2&gt;
  
  
  7. You should be an engineer to work in IT
&lt;/h2&gt;

&lt;p&gt;Despite all I mentioned above: you don't have to be a young genius, you may not be as great at math to be a successful engineer, etc. - this profession is still not for everyone. Sometimes, as a developer you, have to spend hours looking for some complicated bug in your code (or even in someone else's code) - for someone it will be exciting and rewarding, for someone it will be boring and exhausting. &lt;br&gt;
If you are a backend engineer - you probably won't be able to see the results of your work in some visual form, e.g. mobile app or website. For me personally, this is completely okay - I enjoy seeing my services working well, having great performance and matching all the business requirements - but again, it depends on your type of personality.&lt;br&gt;
It's important to remember that there are many other professions in IT, not only engineering positions, and you can make a career in any of them (QA, designers, managers, scientists, tech writers, developer advocates etc.). So you can always find something that will suit your skills, interests and character.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In my article, I tried to dispel some myths about the work of software engineers and working in IT in general. Unfortunately, there are many more myths, some of them are almost harmless, others are more harmful. Regardless of our expertise level and job title, we all need to exercise our critical thinking, stay open-minded and be ready to learn to be less affected by various cognitive biases and stereotypes.&lt;/p&gt;




&lt;p&gt;Images:&lt;br&gt;
Hackers (1995)&lt;br&gt;
Confused Math Lady meme&lt;br&gt;
Twitter&lt;br&gt;
Silicon Valley (2014)&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>motivation</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Details of how Snowflake Streams work</title>
      <dc:creator>Semernitskaya</dc:creator>
      <pubDate>Mon, 28 Feb 2022 18:10:05 +0000</pubDate>
      <link>https://dev.to/semernitskaya/details-of-snowflake-streams-work-2ejm</link>
      <guid>https://dev.to/semernitskaya/details-of-snowflake-streams-work-2ejm</guid>
      <description>&lt;p&gt;&lt;a href="https://www.snowflake.com/" rel="noopener noreferrer"&gt;Snowflake&lt;/a&gt; is a multicloud Data Warehouse that can be used for building cloud data platform in your company. To keep track of data changes in a table, Snowflake has introduced the Table Streams feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Snowflake Table Streams&lt;/strong&gt; (or Snowflake Streams for short) can be used for implementing Change Data Capture (CDC) architecture design pattern. See &lt;a href="https://www.avenga.com/magazine/change-data-capture/" rel="noopener noreferrer"&gt;this article&lt;/a&gt; for more details about CDC pattern. &lt;br&gt;
In my post I'm going to explain some details about Snowflake Streams and show how they can be created and used.  &lt;/p&gt;
&lt;h2&gt;
  
  
  Snowflake Streams definition and types
&lt;/h2&gt;

&lt;p&gt;Definition from &lt;a href="https://docs.snowflake.com/en/user-guide/streams.html" rel="noopener noreferrer"&gt;the Snowflake documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A stream object records data manipulation language (DML) changes made to tables, including inserts, updates, and deletes, as well as metadata about each change, so that actions can be taken using the changed data. ... A table stream ... makes a “change table” available of what changed, at the row level, between two transactional points of time in a table. This allows querying and consuming a sequence of change records in a transactional fashion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A stream itself &lt;strong&gt;does not contain any table data&lt;/strong&gt; (this can be important if you have GDPR or similar requirements for you system). A stream stores only an offset for the source table and not any actual table columns or data.&lt;br&gt;&lt;br&gt;
When queried, a stream accesses and returns the historic data in the same shape as the source table (i.e. the same column names and ordering) with the following additional columns:  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;METADATA$ACTION&lt;/strong&gt; - DML operation type: &lt;code&gt;INSERTED&lt;/code&gt; or &lt;code&gt;DELETED&lt;/code&gt; &lt;br&gt;
&lt;strong&gt;METADATA$ISUPDATE&lt;/strong&gt; - Shows if the operation was part of an UPDATE statement. &lt;code&gt;UPDATE&lt;/code&gt; operation is represented as a combination of &lt;code&gt;DELETE&lt;/code&gt; and &lt;code&gt;INSERT&lt;/code&gt; records in the stream with &lt;code&gt;METADATA$ISUPDATE = TRUE&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;METADATA$ROW_ID&lt;/strong&gt; - Unique and immutable row ID from the source table&lt;/p&gt;
&lt;h3&gt;
  
  
  Snowflake Streams types
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stream type&lt;/th&gt;
&lt;th&gt;Supporting tables&lt;/th&gt;
&lt;th&gt;Is insert only&lt;/th&gt;
&lt;th&gt;Comment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;Standard tables, &lt;a href="https://docs.snowflake.com/en/user-guide/data-load-dirtables.html" rel="noopener noreferrer"&gt;directory tables&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;NO&lt;/td&gt;
&lt;td&gt;Tracks all DML changes to the source table, including inserts, updates, and deletes (including table truncates)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Append-only&lt;/td&gt;
&lt;td&gt;Standard tables&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;Tracks row inserts only. Update and delete operations (including table truncates) are not recorded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Insert-only&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.snowflake.com/en/user-guide/tables-external.html" rel="noopener noreferrer"&gt;External tables&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;YES&lt;/td&gt;
&lt;td&gt;Tracks row inserts only. They do not record delete operations that remove rows from an inserted set&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  Snowflake Streams creation
&lt;/h2&gt;

&lt;p&gt;Stream can be created using &lt;code&gt;CREATE&lt;/code&gt; statement, by default Standard stream will be created. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;APPEND_ONLY = TRUE&lt;/code&gt; to create Append-only stream, use &lt;code&gt;INSERT_ONLY = TRUE&lt;/code&gt; to create Insert-only stream&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;SHOW_INITIAL_ROWS = TRUE&lt;/code&gt; if you need new stream to include records presented in the table before it was created&lt;/li&gt;
&lt;li&gt;You can create several streams for the same table and then read from them and advance offsets independently (see the next section for more details about stream offset). Because stream doesn't store actual data - you can create as many streams as you need for a table without significant cost rise. 
Example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- create a table&lt;/span&gt;
&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;fee&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- create a Standard stream &lt;/span&gt;
&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;member_check&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- create an Append-only stream&lt;/span&gt;
&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;member_check_append&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="n"&gt;append_only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;SHOW STREAMS&lt;/code&gt; command to show streams you have an access to. Example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SHOW&lt;/span&gt; &lt;span class="n"&gt;STREAMS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;STREAM_HAS_DATA&lt;/code&gt; option to check if stream has data or not. Example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;SYSTEM&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;STREAM_HAS_DATA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'member_check'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Insert-only stream is only supported for external tables. It can be created for a regular table but in this case this stream will act like a standard stream. Example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- for the members table&lt;/span&gt;

&lt;span class="c1"&gt;-- this stream will act like Standard stream&lt;/span&gt;
&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;member_check_insert&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="n"&gt;insert_only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Snowflake Streams querying. Stream offset
&lt;/h2&gt;

&lt;p&gt;We can query a stream the same way we query a view or a table. All the changes in the source table are visible in the stream only after they are committed. The stream returns all of the columns from the table and its metadata columns. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- for the members table&lt;/span&gt;

&lt;span class="c1"&gt;-- insert values&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;values&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'Joe'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'Jane'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'George'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'Betty'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'Sally'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- check streams&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  NAME    FEE METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
1   Joe 0   INSERT  FALSE   e585f6fd43b0c68492d11c3e9af24198134c011d
2   Jane    0   INSERT  FALSE   878c5702cfe33d390310ec55f0003f320210f721
3   George  0   INSERT  FALSE   b8f4e37b5f8ba669656e8b7e961c473f872d10e9
4   Betty   0   INSERT  FALSE   116dff9927a916f986f4701ead7d73f30b9d2ff7
5   Sally   0   INSERT  FALSE   f739b6f1785779f728a52dfd1db7b2036c44ce96
**/&lt;/span&gt;

&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check_append&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  NAME    FEE METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
1   Joe 0   INSERT  FALSE   e585f6fd43b0c68492d11c3e9af24198134c011d
2   Jane    0   INSERT  FALSE   878c5702cfe33d390310ec55f0003f320210f721
3   George  0   INSERT  FALSE   b8f4e37b5f8ba669656e8b7e961c473f872d10e9
4   Betty   0   INSERT  FALSE   116dff9927a916f986f4701ead7d73f30b9d2ff7
5   Sally   0   INSERT  FALSE   f739b6f1785779f728a52dfd1db7b2036c44ce96
**/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As it was mentioned above the stream only stores the offset for the source table, then it uses the versioning history for the source table to show changed records. &lt;br&gt;
 &lt;br&gt;
Just querying the data from the stream will not change the offset. If we run the same &lt;code&gt;SELECT&lt;/code&gt; statements from the code snippet above - the same 5 records will be returned.&lt;br&gt;
 &lt;br&gt;
A stream advances its offset &lt;strong&gt;only&lt;/strong&gt; when it is used in a DML transaction (advancing offset for the stream can be compared to committing offset for Kafka topic for example). The standard approach here is to read changed records from the stream and insert them into some other table in a DML transaction. Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- for the members table&lt;/span&gt;

&lt;span class="c1"&gt;-- create history table&lt;/span&gt;
&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;members_history&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="nb"&gt;varchar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- advance the offset of the stream member_check_append&lt;/span&gt;
&lt;span class="k"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;members_history&lt;/span&gt; 
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check_append&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- check streams again&lt;/span&gt;
&lt;span class="c1"&gt;-- member_check remains the same, because we haven't advanced its offset yet&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  NAME    FEE METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
1   Joe 0   INSERT  FALSE   e585f6fd43b0c68492d11c3e9af24198134c011d
2   Jane    0   INSERT  FALSE   878c5702cfe33d390310ec55f0003f320210f721
3   George  0   INSERT  FALSE   b8f4e37b5f8ba669656e8b7e961c473f872d10e9
4   Betty   0   INSERT  FALSE   116dff9927a916f986f4701ead7d73f30b9d2ff7
5   Sally   0   INSERT  FALSE   f739b6f1785779f728a52dfd1db7b2036c44ce96
**/&lt;/span&gt;

&lt;span class="c1"&gt;-- member_check_append is empty because we've advanced the offset for this stream&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check_append&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  NAME    FEE METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
**/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; &lt;br&gt;
Just putting &lt;code&gt;SELECT&lt;/code&gt; from the stream between &lt;code&gt;BEGIN&lt;/code&gt; and &lt;code&gt;COMMIT&lt;/code&gt; statements won't change the offset of the stream. Example:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- for the members table&lt;/span&gt;

&lt;span class="k"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- won't advance the offset&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need to advance stream offset to the current table version but don't want to consume the stream data in a DML transaction - you can use one of two approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recreate the stream (using the &lt;code&gt;CREATE OR REPLACE&lt;/code&gt; command)&lt;/li&gt;
&lt;li&gt;Insert the current change data into a dummy table. In the &lt;code&gt;INSERT&lt;/code&gt; statement, query the stream but include a &lt;code&gt;WHERE&lt;/code&gt; clause that filters out all of the change data. Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- for the members table&lt;/span&gt;

&lt;span class="c1"&gt;-- create utility table&lt;/span&gt;
&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;utility&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- advance the offset of the stream member_check&lt;/span&gt;
&lt;span class="k"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;utility&lt;/span&gt; &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- check member_check stream again &lt;/span&gt;
&lt;span class="c1"&gt;-- member_check is empty because we've advanced offset for this stream&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  NAME    FEE METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
**/&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A stream becomes &lt;strong&gt;stale&lt;/strong&gt; when its offset is outside of the data retention period for its source table. When a stream becomes stale, the historical data for the source table is no longer accessible, including any unconsumed change records. To track new change records for the table, recreate the stream. To prevent a stream from becoming stale, consume the stream records within a transaction during the retention period for the table. See more details and related settings in &lt;a href="https://docs.snowflake.com/en/user-guide/streams-intro.html#data-retention-period-and-staleness" rel="noopener noreferrer"&gt;the Snowflake documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional details of Snowflake Streams
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;On &lt;strong&gt;DDL&lt;/strong&gt; changes (e.g. &lt;code&gt;ADD COLUMN&lt;/code&gt;, &lt;code&gt;DROP COLUMN&lt;/code&gt;) we won’t get any new records in the stream, even adding a new column with a default value won’t cause any &lt;code&gt;UPDATE&lt;/code&gt;-s. Existing / new records in the stream will include changes in columns. Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- create a table&lt;/span&gt;
&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- create a Standard stream &lt;/span&gt;
&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;or&lt;/span&gt; &lt;span class="k"&gt;replace&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;test_stream&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- insert values&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;values&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- check the stream&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;test_stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
1   INSERT  FALSE   71e6b8e0f43b2c14330ce1a3142d2e8001a93c61
2   INSERT  FALSE   c97db7c45da5efeb895cbd811f210a506600f620
**/&lt;/span&gt;

&lt;span class="c1"&gt;-- add a new column with a default value&lt;/span&gt;
&lt;span class="k"&gt;alter&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt; &lt;span class="n"&gt;test&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="k"&gt;column&lt;/span&gt; &lt;span class="n"&gt;fee&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- check the stream again =&amp;gt; no new updates in the stream, a new column is visible&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;test_stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  FEE METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
1   10  INSERT  FALSE   71e6b8e0f43b2c14330ce1a3142d2e8001a93c61
2   10  INSERT  FALSE   c97db7c45da5efeb895cbd811f210a506600f620
**/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;For the Standard stream type if a record was &lt;strong&gt;inserted and then deleted&lt;/strong&gt; between two stream reads - it won’t be visible at all. Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- for the members table&lt;/span&gt;

&lt;span class="c1"&gt;-- insert a new record and then delete it&lt;/span&gt;
&lt;span class="k"&gt;insert&lt;/span&gt; &lt;span class="k"&gt;into&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fee&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;values&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Mike'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- check streams&lt;/span&gt;
&lt;span class="c1"&gt;-- member_check is empty because it's Standard stream&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  NAME    FEE METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
**/&lt;/span&gt;

&lt;span class="c1"&gt;-- member_check_append contains a new record because it's Append-only stream&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check_append&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  NAME    FEE METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
6   Mike    0   INSERT  FALSE   d98b3586efc9e5b17ff13956bdb304094894a4ec
**/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Updates are not visible in the stream if there is no actual data change. Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- for the members table&lt;/span&gt;

&lt;span class="c1"&gt;-- update fee column with the same value&lt;/span&gt;
&lt;span class="k"&gt;update&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="n"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- check the stream =&amp;gt; no new values&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  NAME    FEE METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
**/&lt;/span&gt;

&lt;span class="c1"&gt;-- update fee column with the new value&lt;/span&gt;
&lt;span class="k"&gt;update&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="n"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- check the stream =&amp;gt; update is visible&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  NAME    FEE METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
3   George  10  INSERT  TRUE    640590445de028a556d79d6361a8aa59fc3301d3
3   George  0   DELETE  TRUE    640590445de028a556d79d6361a8aa59fc3301d3
**/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MERGE&lt;/code&gt; operations are visible in the stream similar to simple &lt;code&gt;CREATE&lt;/code&gt; / &lt;code&gt;UPDATE&lt;/code&gt; operations&lt;/li&gt;
&lt;li&gt;If the row was &lt;strong&gt;updated multiple times&lt;/strong&gt; before we could read it - in this case, the stream will return only the net changes, i.e. only the last value is returned. Example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- for the members table&lt;/span&gt;

&lt;span class="c1"&gt;-- update fee column several times, update name column&lt;/span&gt;
&lt;span class="k"&gt;update&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="n"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;update&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="n"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;update&lt;/span&gt; &lt;span class="n"&gt;members&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Anna'&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- check the stream =&amp;gt; the last version of the record is visible&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;member_check&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="cm"&gt;/**
ID  NAME    FEE METADATA$ACTION METADATA$ISUPDATE   METADATA$ROW_ID
3   Anna    30  INSERT  TRUE    640590445de028a556d79d6361a8aa59fc3301d3
3   George  0   DELETE  TRUE    640590445de028a556d79d6361a8aa59fc3301d3
**/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Snowflake Streams is a tool that lets you implement CDC pattern in your Data Warehouse without using external ELT tools, or simply allow consumers to track changes in some of your tables without incurring significant cost. At the same time, you need to be aware of the limitations of streams, some of which I described in my article, for example how DDL changes can affect your stream, or the possibility to get a stale stream, or the way changes are accumulated in the stream between two reads.  &lt;/p&gt;




&lt;p&gt;Cover image: Shutterstock/Mariia Tagirova&lt;/p&gt;

</description>
      <category>cdc</category>
      <category>snowflake</category>
      <category>cloud</category>
      <category>datawarehouse</category>
    </item>
    <item>
      <title>Moving reflection-based code from Java 8 to 11 and 17</title>
      <dc:creator>Semernitskaya</dc:creator>
      <pubDate>Fri, 18 Feb 2022 10:18:43 +0000</pubDate>
      <link>https://dev.to/semernitskaya/moving-reflection-based-code-from-java-8-to-11-and-17-1n8e</link>
      <guid>https://dev.to/semernitskaya/moving-reflection-based-code-from-java-8-to-11-and-17-1n8e</guid>
      <description>&lt;p&gt;During the migration of one of the libraries from Java 8 to Java 11 and then to Java 17 I ran into a number of problems with the reflection functionality that was used in this library. In my article I'm going to describe these problems and how they can be solved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Java 8
&lt;/h2&gt;

&lt;p&gt;In the library reflection mechanism was used to access private fields, methods and constructors of JDK internal classes, for example, to manipulate annotations in runtime. Here are some examples of reflection usages without actual manipulation code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.lang.reflect.Constructor&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.lang.reflect.Field&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.lang.reflect.Method&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Map&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReflectionUsage&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;throws&lt;/span&gt; &lt;span class="nc"&gt;NoSuchMethodException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;NoSuchFieldException&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ClassNotFoundException&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;declaredAnnotationsMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"declaredAnnotations"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;declaredAnnotationsMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAccessible&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Field&lt;/span&gt; &lt;span class="n"&gt;declaredAnnotationsField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"declaredAnnotations"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;declaredAnnotationsField&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAccessible&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;annotationDataClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java.lang.Class$AnnotationData"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Constructor&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;?&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;annotationDataConstructor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;annotationDataClass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredConstructor&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;annotationDataConstructor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAccessible&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="nc"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;annotationDataMethod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"annotationData"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;annotationDataMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAccessible&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Java 11
&lt;/h2&gt;

&lt;p&gt;After I migrated the library to Java 11, I started getting warnings like the followings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by ...ReflectionUsage ... to method java.lang.reflect.Field.declaredAnnotations()
WARNING: Please consider reporting this to the maintainers of ...ReflectionUsage
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These warnings are caused by the modular structure introduced in Java 9: reflective access to internal JDK modules is considered to be &lt;code&gt;Illegal&lt;/code&gt;, but in Java 9-11 such access is still allowed - it only produces warnings.&lt;br&gt;&lt;br&gt;
To see all warnings produced due to &lt;code&gt;Illegal&lt;/code&gt; access of the code, you can use the option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--illegal-access=warn
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Java 17
&lt;/h2&gt;

&lt;h3&gt;
  
  
  InaccessibleObjectException
&lt;/h3&gt;

&lt;p&gt;After I migrated the library to Java 17, I started seeing runtime errors &lt;code&gt;InaccessibleObjectException&lt;/code&gt; instead of &lt;code&gt;Illegal&lt;/code&gt; access warnings. An example of &lt;code&gt;InaccessibleObjectException&lt;/code&gt; stack trace:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make private java.util.Map java.lang.reflect.Field.declaredAnnotations() accessible: module java.base does not "opens java.lang.reflect" to unnamed module @...
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
    at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
    at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
    at ...ReflectionUsage.main(ReflectionUsage.java:13)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To resolve these exceptions it's required to use the option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--add-opens
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the Oracle &lt;a href="https://docs.oracle.com/javase/9/migrate/toc.htm#JSMIG-GUID-12F945EB-71D6-46AF-8C3D-D354FD0B1781" rel="noopener noreferrer"&gt;article&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have to allow code on the class path to do deep reflection to access nonpublic members, then use the --add-opens runtime option. &lt;br&gt;
Some libraries do deep reflection, meaning setAccessible(true), so they can access all members, including private ones. You can grant this access using the --add-opens option on the java command line. No warning messages are generated as a result of using this option.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I used the following options for the library:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
In Java 16 and prior it's also possible to fix this error by using the option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--illegal-access=permit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;but its support has been removed in Java 17&lt;/p&gt;

&lt;h3&gt;
  
  
  NoSuchFieldException
&lt;/h3&gt;

&lt;p&gt;Fix with &lt;code&gt;--add-opens&lt;/code&gt; option helped me with &lt;code&gt;InaccessibleObjectException&lt;/code&gt; but then I started getting &lt;code&gt;NoSuchFieldException&lt;/code&gt; when trying to access private field &lt;code&gt;declaredAnnotations&lt;/code&gt; from &lt;code&gt;java.lang.reflect.Field&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Exception in thread "main" java.lang.NoSuchFieldException: declaredAnnotations
    at java.base/java.lang.Class.getDeclaredField(Class.java:2610)
    at ...ReflectionUsage.main(ReflectionUsage.java:15)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for the sentence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Field&lt;/span&gt; &lt;span class="n"&gt;declaredAnnotationsField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredField&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"declaredAnnotations"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;NoSuchFieldException&lt;/code&gt; was caused by the feature "Filtering for classes with security sensitive fields" introduced in Java 12 &lt;a href="https://bugs.openjdk.java.net/browse/JDK-8210522" rel="noopener noreferrer"&gt;JDK-8210522&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Core reflection has a filtering mechanism to hide security and integrity sensitive fields and methods from Class getXXXField(s) and getXXXMethod(s). &lt;br&gt;
The filtering mechanism has been used for several releases to hide security sensitive fields such as System.security and Class.classLoader.&lt;br&gt;
This CSR proposes to extend the filters to hide fields from a number of highly security sensitive classes in java.lang.reflect and java.lang.invoke.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I found two possible workarounds to access private fields of &lt;code&gt;java.lang.reflect.Field&lt;/code&gt; class (in my case I needed access to &lt;code&gt;declaredAnnotations&lt;/code&gt; field, but the same approach can be used to access other fields that are not available because of &lt;a href="https://bugs.openjdk.java.net/browse/JDK-8210522" rel="noopener noreferrer"&gt;JDK-8210522&lt;/a&gt;) &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Workaround #1:&lt;/strong&gt; use &lt;a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/invoke/VarHandle.html" rel="noopener noreferrer"&gt;VarHandle&lt;/a&gt; (&lt;a href="https://stackoverflow.com/a/56043252/5516086" rel="noopener noreferrer"&gt;source&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;lookup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MethodHandles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;privateLookupIn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;MethodHandles&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;lookup&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="nc"&gt;VarHandle&lt;/span&gt; &lt;span class="n"&gt;declaredAnnotationsField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lookup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findVarHandle&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"declaredAnnotations"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Workaround #2:&lt;/strong&gt; invoke &lt;code&gt;getDeclaredFields0&lt;/code&gt; method for &lt;code&gt;java.lang.reflect.Field&lt;/code&gt; class using reflection (&lt;a href="https://stackoverflow.com/a/69418150/5516086" rel="noopener noreferrer"&gt;source&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;Method&lt;/span&gt; &lt;span class="n"&gt;getDeclaredFields0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getDeclaredMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"getDeclaredFields0"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;getDeclaredFields0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAccessible&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;[])&lt;/span&gt; &lt;span class="n"&gt;getDeclaredFields0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invoke&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;Field&lt;/span&gt; &lt;span class="n"&gt;declaredAnnotationsField&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Field&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"declaredAnnotations"&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;equals&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;declaredAnnotationsField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;declaredAnnotationsField&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setAccessible&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;&lt;br&gt;
Main goal of &lt;a href="https://bugs.openjdk.java.net/browse/JDK-8210522" rel="noopener noreferrer"&gt;JDK-8210522&lt;/a&gt; feature is to prevent reflective access to several internal fields, so workarounds described above can stop working with any new JDK release so if you have the same problem - probably you need to think about re-writing your code to use a different approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article I've covered only reflection related aspects of migration Java applications to the newest LTS releases of Java (JDK 11, JDK 17), but there are certainly many more potential issues and problems during this upgrade.&lt;/p&gt;




&lt;p&gt;Cover image: Photo by &lt;a href="https://unsplash.com/@nineteen?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Andrew Ly&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/mountain-reflection?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>jdk17</category>
      <category>jdk11</category>
    </item>
  </channel>
</rss>
